001    /*
002     * Copyright 2010-2014 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.lang.resolve.lazy.descriptors;
018    
019    import com.google.common.collect.Sets;
020    import com.intellij.util.Function;
021    import com.intellij.util.containers.ContainerUtil;
022    import kotlin.Function0;
023    import kotlin.Function1;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.jet.lang.descriptors.*;
027    import org.jetbrains.jet.lang.psi.*;
028    import org.jetbrains.jet.lang.resolve.AnnotationResolver;
029    import org.jetbrains.jet.lang.resolve.BindingTrace;
030    import org.jetbrains.jet.lang.resolve.ScriptNameUtil;
031    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
032    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
033    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
034    import org.jetbrains.jet.lang.resolve.lazy.data.JetScriptInfo;
035    import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProvider;
036    import org.jetbrains.jet.lang.resolve.name.LabelName;
037    import org.jetbrains.jet.lang.resolve.name.Name;
038    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
040    import org.jetbrains.jet.storage.NotNullLazyValue;
041    import org.jetbrains.jet.storage.StorageManager;
042    import org.jetbrains.jet.utils.Printer;
043    
044    import java.util.*;
045    
046    import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
047    
048    public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, DP extends DeclarationProvider> implements JetScope {
049        protected final ResolveSession resolveSession;
050        protected final BindingTrace trace;
051        protected final DP declarationProvider;
052        protected final D thisDescriptor;
053    
054        private final MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> classDescriptors;
055    
056        private final MemoizedFunctionToNotNull<Name, Set<FunctionDescriptor>> functionDescriptors;
057        private final MemoizedFunctionToNotNull<Name, Set<VariableDescriptor>> propertyDescriptors;
058    
059        private final NotNullLazyValue<Collection<DeclarationDescriptor>> descriptorsFromDeclaredElements;
060        private final NotNullLazyValue<Collection<DeclarationDescriptor>> extraDescriptors;
061    
062        protected AbstractLazyMemberScope(
063                @NotNull ResolveSession resolveSession,
064                @NotNull DP declarationProvider,
065                @NotNull D thisDescriptor,
066                @NotNull BindingTrace trace
067        ) {
068            this.resolveSession = resolveSession;
069            this.trace = trace;
070            this.declarationProvider = declarationProvider;
071            this.thisDescriptor = thisDescriptor;
072    
073            StorageManager storageManager = resolveSession.getStorageManager();
074            this.classDescriptors = storageManager.createMemoizedFunction(new Function1<Name, List<ClassDescriptor>>() {
075                @Override
076                public List<ClassDescriptor> invoke(Name name) {
077                    return resolveClassDescriptor(name);
078                }
079            });
080    
081            this.functionDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<FunctionDescriptor>>() {
082                @Override
083                public Set<FunctionDescriptor> invoke(Name name) {
084                    return doGetFunctions(name);
085                }
086            });
087            this.propertyDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<VariableDescriptor>>() {
088                @Override
089                public Set<VariableDescriptor> invoke(Name name) {
090                    return doGetProperties(name);
091                }
092            });
093    
094            this.descriptorsFromDeclaredElements = storageManager.createLazyValue(new Function0<Collection<DeclarationDescriptor>>() {
095                @Override
096                public Collection<DeclarationDescriptor> invoke() {
097                    return computeDescriptorsFromDeclaredElements();
098                }
099            });
100            this.extraDescriptors = storageManager.createLazyValue(new Function0<Collection<DeclarationDescriptor>>() {
101                @Override
102                public Collection<DeclarationDescriptor> invoke() {
103                    return computeExtraDescriptors();
104                }
105            });
106        }
107    
108        @Nullable
109        private List<ClassDescriptor> resolveClassDescriptor(@NotNull final Name name) {
110            Collection<JetClassLikeInfo> classOrObjectDeclarations = declarationProvider.getClassOrObjectDeclarations(name);
111    
112            return ContainerUtil.mapNotNull(classOrObjectDeclarations, new Function<JetClassLikeInfo, ClassDescriptor>() {
113                @Override
114                public ClassDescriptor fun(JetClassLikeInfo classLikeInfo) {
115                    // SCRIPT: Creating a script class
116                    if (classLikeInfo instanceof JetScriptInfo) {
117                        return new LazyScriptClassDescriptor(resolveSession, thisDescriptor, name, (JetScriptInfo) classLikeInfo);
118                    }
119                    return new LazyClassDescriptor(resolveSession, thisDescriptor, name, classLikeInfo);
120                }
121            });
122        }
123    
124        @Override
125        public ClassifierDescriptor getClassifier(@NotNull Name name) {
126            return first(classDescriptors.invoke(name));
127        }
128    
129        private static <T> T first(@NotNull List<T> list) {
130            if (list.isEmpty()) return null;
131            return list.get(0);
132        }
133    
134        @NotNull
135        @Override
136        public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
137            return functionDescriptors.invoke(name);
138        }
139    
140        @NotNull
141        private Set<FunctionDescriptor> doGetFunctions(@NotNull Name name) {
142            Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
143    
144            Collection<JetNamedFunction> declarations = declarationProvider.getFunctionDeclarations(name);
145            for (JetNamedFunction functionDeclaration : declarations) {
146                JetScope resolutionScope = getScopeForMemberDeclarationResolution(functionDeclaration);
147                result.add(resolveSession.getDescriptorResolver().resolveFunctionDescriptorWithAnnotationArguments(
148                      thisDescriptor, resolutionScope,
149                      functionDeclaration,
150                      trace,
151                      // this relies on the assumption that a lazily resolved declaration is not a local one,
152                      // thus doesn't have a surrounding data flow
153                      DataFlowInfo.EMPTY)
154                );
155            }
156    
157            getNonDeclaredFunctions(name, result);
158    
159            return result;
160        }
161    
162        @NotNull
163        protected abstract JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration);
164    
165        protected abstract void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result);
166    
167        @NotNull
168        @Override
169        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
170            return propertyDescriptors.invoke(name);
171        }
172    
173        @NotNull
174        public Set<VariableDescriptor> doGetProperties(@NotNull Name name) {
175            Set<VariableDescriptor> result = Sets.newLinkedHashSet();
176    
177            Collection<JetProperty> declarations = declarationProvider.getPropertyDeclarations(name);
178            for (JetProperty propertyDeclaration : declarations) {
179                JetScope resolutionScope = getScopeForMemberDeclarationResolution(propertyDeclaration);
180                PropertyDescriptor propertyDescriptor =
181                        resolveSession.getDescriptorResolver().resolvePropertyDescriptor(
182                               thisDescriptor, resolutionScope,
183                               propertyDeclaration,
184                               trace,
185                               // this relies on the assumption that a lazily resolved declaration is not a local one,
186                               // thus doesn't have a surrounding data flow
187                               DataFlowInfo.EMPTY);
188                result.add(propertyDescriptor);
189                AnnotationResolver.resolveAnnotationsArguments(propertyDescriptor, trace);
190            }
191    
192            getNonDeclaredProperties(name, result);
193    
194            return result;
195        }
196    
197        protected abstract void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result);
198    
199        @Override
200        public VariableDescriptor getLocalVariable(@NotNull Name name) {
201            return null;
202        }
203    
204        @NotNull
205        @Override
206        public DeclarationDescriptor getContainingDeclaration() {
207            return thisDescriptor;
208        }
209    
210        @NotNull
211        @Override
212        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
213            // A member scope has no labels
214            return Collections.emptySet();
215        }
216    
217        @NotNull
218        @Override
219        public Collection<DeclarationDescriptor> getAllDescriptors() {
220            Collection<DeclarationDescriptor> result = new LinkedHashSet<DeclarationDescriptor>(descriptorsFromDeclaredElements.invoke());
221            result.addAll(extraDescriptors.invoke());
222            return result;
223        }
224    
225        @NotNull
226        private Collection<DeclarationDescriptor> computeDescriptorsFromDeclaredElements() {
227            List<JetDeclaration> declarations = declarationProvider.getAllDeclarations();
228            ArrayList<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarations.size());
229            for (JetDeclaration declaration : declarations) {
230                if (declaration instanceof JetClassOrObject) {
231                    JetClassOrObject classOrObject = (JetClassOrObject) declaration;
232                    result.addAll(classDescriptors.invoke(safeNameForLazyResolve(classOrObject.getNameAsName())));
233                }
234                else if (declaration instanceof JetFunction) {
235                    JetFunction function = (JetFunction) declaration;
236                    result.addAll(getFunctions(safeNameForLazyResolve(function)));
237                }
238                else if (declaration instanceof JetProperty) {
239                    JetProperty property = (JetProperty) declaration;
240                    result.addAll(getProperties(safeNameForLazyResolve(property)));
241                }
242                else if (declaration instanceof JetParameter) {
243                    JetParameter parameter = (JetParameter) declaration;
244                    result.addAll(getProperties(safeNameForLazyResolve(parameter)));
245                }
246                else if (declaration instanceof JetScript) {
247                    result.addAll(classDescriptors.invoke(ScriptNameUtil.classNameForScript((JetScript) declaration).shortName()));
248                }
249                else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
250                    // Do nothing for typedefs as they are not supported.
251                    // MultiDeclarations are not supported on global level too.
252                }
253                else {
254                    throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
255                }
256            }
257            result.trimToSize();
258            return result;
259        }
260    
261        @NotNull
262        protected abstract Collection<DeclarationDescriptor> computeExtraDescriptors();
263    
264        @NotNull
265        @Override
266        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
267            ReceiverParameterDescriptor receiver = getImplicitReceiver();
268            if (receiver != null) {
269                return Collections.singletonList(receiver);
270            }
271            return Collections.emptyList();
272        }
273    
274        @Nullable
275        protected abstract ReceiverParameterDescriptor getImplicitReceiver();
276    
277        // Do not change this, override in concrete subclasses:
278        // it is very easy to compromise laziness of this class, and fail all the debugging
279        // a generic implementation can't do this properly
280        @Override
281        public abstract String toString();
282    
283        @NotNull
284        @Override
285        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
286            return getAllDescriptors();
287        }
288    
289        @Override
290        public void printScopeStructure(@NotNull Printer p) {
291            p.println(getClass().getSimpleName(), " {");
292            p.pushIndent();
293    
294            p.println("thisDescriptor = ", thisDescriptor);
295    
296            p.popIndent();
297            p.println("}");
298        }
299    }