001    /*
002     * Copyright 2010-2013 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 jet.Function0;
023    import jet.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.calls.autocasts.DataFlowInfo;
029    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
030    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
031    import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProvider;
032    import org.jetbrains.jet.lang.resolve.name.LabelName;
033    import org.jetbrains.jet.lang.resolve.name.Name;
034    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
036    import org.jetbrains.jet.storage.NotNullLazyValue;
037    import org.jetbrains.jet.storage.StorageManager;
038    import org.jetbrains.jet.utils.Printer;
039    
040    import java.util.Collection;
041    import java.util.Collections;
042    import java.util.List;
043    import java.util.Set;
044    
045    import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
046    
047    public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, DP extends DeclarationProvider> implements JetScope {
048        protected final ResolveSession resolveSession;
049        protected final DP declarationProvider;
050        protected final D thisDescriptor;
051    
052        private final MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> classDescriptors;
053        private final MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> objectDescriptors;
054    
055        private final MemoizedFunctionToNotNull<Name, Set<FunctionDescriptor>> functionDescriptors;
056        private final MemoizedFunctionToNotNull<Name, Set<VariableDescriptor>> propertyDescriptors;
057    
058        private static class AllDescriptors {
059            private final Collection<DeclarationDescriptor> all = Sets.newLinkedHashSet();
060            private final Collection<ClassDescriptor> objects = Sets.newLinkedHashSet();
061        }
062    
063        private final NotNullLazyValue<AllDescriptors> allDescriptors;
064    
065        protected AbstractLazyMemberScope(
066                @NotNull ResolveSession resolveSession,
067                @NotNull DP declarationProvider,
068                @NotNull D thisDescriptor
069        ) {
070            this.resolveSession = resolveSession;
071            this.declarationProvider = declarationProvider;
072            this.thisDescriptor = thisDescriptor;
073    
074            StorageManager storageManager = resolveSession.getStorageManager();
075            this.classDescriptors = storageManager.createMemoizedFunction(new Function1<Name, List<ClassDescriptor>>() {
076                @Override
077                public List<ClassDescriptor> invoke(Name name) {
078                    return resolveClassOrObjectDescriptor(name, false);
079                }
080            });
081            this.objectDescriptors = storageManager.createMemoizedFunction(new Function1<Name, List<ClassDescriptor>>() {
082                @Override
083                public List<ClassDescriptor> invoke(Name name) {
084                    return resolveClassOrObjectDescriptor(name, true);
085                }
086            });
087    
088            this.functionDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<FunctionDescriptor>>() {
089                @Override
090                public Set<FunctionDescriptor> invoke(Name name) {
091                    return doGetFunctions(name);
092                }
093            });
094            this.propertyDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<VariableDescriptor>>() {
095                @Override
096                public Set<VariableDescriptor> invoke(Name name) {
097                    return doGetProperties(name);
098                }
099            });
100    
101            this.allDescriptors = storageManager.createLazyValue(new Function0<AllDescriptors>() {
102                @Override
103                public AllDescriptors invoke() {
104                    return computeAllDescriptors();
105                }
106            });
107        }
108    
109        @Nullable
110        private List<ClassDescriptor> resolveClassOrObjectDescriptor(@NotNull final Name name, final boolean object) {
111            Collection<JetClassOrObject> classOrObjectDeclarations = declarationProvider.getClassOrObjectDeclarations(name);
112    
113            return ContainerUtil.mapNotNull(classOrObjectDeclarations, new Function<JetClassOrObject, ClassDescriptor>() {
114                @Override
115                public ClassDescriptor fun(JetClassOrObject classOrObject) {
116                    if (object != declaresObjectOrEnumConstant(classOrObject)) return null;
117    
118                    return new LazyClassDescriptor(resolveSession, thisDescriptor, name,
119                                                   JetClassInfoUtil.createClassLikeInfo(classOrObject));
120                }
121            });
122        }
123    
124        private static boolean declaresObjectOrEnumConstant(JetClassOrObject declaration) {
125            return declaration instanceof JetObjectDeclaration || declaration instanceof JetEnumEntry;
126        }
127    
128        @Override
129        public ClassifierDescriptor getClassifier(@NotNull Name name) {
130            return first(classDescriptors.invoke(name));
131        }
132    
133        @Override
134        public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
135            return first(objectDescriptors.invoke(name));
136        }
137    
138        private static <T> T first(@NotNull List<T> list) {
139            if (list.isEmpty()) return null;
140            return list.get(0);
141        }
142    
143        @NotNull
144        @Override
145        public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
146            return functionDescriptors.invoke(name);
147        }
148    
149        @NotNull
150        private Set<FunctionDescriptor> doGetFunctions(@NotNull Name name) {
151            Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
152    
153            Collection<JetNamedFunction> declarations = declarationProvider.getFunctionDeclarations(name);
154            for (JetNamedFunction functionDeclaration : declarations) {
155                JetScope resolutionScope = getScopeForMemberDeclarationResolution(functionDeclaration);
156                result.add(resolveSession.getInjector().getDescriptorResolver().resolveFunctionDescriptorWithAnnotationArguments(
157                      thisDescriptor, resolutionScope,
158                      functionDeclaration,
159                      resolveSession.getTrace(),
160                      // this relies on the assumption that a lazily resolved declaration is not a local one,
161                      // thus doesn't have a surrounding data flow
162                      DataFlowInfo.EMPTY)
163                );
164            }
165    
166            getNonDeclaredFunctions(name, result);
167    
168            return result;
169        }
170    
171        @NotNull
172        protected abstract JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration);
173    
174        protected abstract void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result);
175    
176        @NotNull
177        @Override
178        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
179            return propertyDescriptors.invoke(name);
180        }
181    
182        @NotNull
183        public Set<VariableDescriptor> doGetProperties(@NotNull Name name) {
184            Set<VariableDescriptor> result = Sets.newLinkedHashSet();
185    
186            Collection<JetProperty> declarations = declarationProvider.getPropertyDeclarations(name);
187            for (JetProperty propertyDeclaration : declarations) {
188                JetScope resolutionScope = getScopeForMemberDeclarationResolution(propertyDeclaration);
189                PropertyDescriptor propertyDescriptor =
190                        resolveSession.getInjector().getDescriptorResolver().resolvePropertyDescriptor(
191                               thisDescriptor, resolutionScope,
192                               propertyDeclaration,
193                               resolveSession.getTrace(),
194                               // this relies on the assumption that a lazily resolved declaration is not a local one,
195                               // thus doesn't have a surrounding data flow
196                               DataFlowInfo.EMPTY);
197                result.add(propertyDescriptor);
198                resolveSession.getInjector().getAnnotationResolver().resolveAnnotationsArguments(propertyDescriptor, resolveSession.getTrace(), resolutionScope);
199            }
200    
201            // Objects are also properties
202            Collection<JetClassOrObject> classOrObjectDeclarations = declarationProvider.getClassOrObjectDeclarations(name);
203            for (JetClassOrObject classOrObjectDeclaration : classOrObjectDeclarations) {
204                if (declaresObjectOrEnumConstant(classOrObjectDeclaration)) {
205                    ClassDescriptor classifier = getObjectDescriptor(name);
206                    if (classifier == null) {
207                        throw new IllegalStateException("Object declaration " + name + " found in the DeclarationProvider " + declarationProvider + " but not in the scope " + this);
208                    }
209    
210                    JetScope scope = getScopeForMemberDeclarationResolution(classOrObjectDeclaration);
211    
212                    VariableDescriptor propertyDescriptor = resolveSession.getInjector().getDescriptorResolver()
213                            .resolveObjectDeclaration(scope, thisDescriptor, classOrObjectDeclaration, classifier, resolveSession.getTrace());
214                    result.add(propertyDescriptor);
215                }
216            }
217    
218            getNonDeclaredProperties(name, result);
219    
220            return result;
221        }
222    
223        protected abstract void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result);
224    
225        @NotNull
226        @Override
227        public Collection<ClassDescriptor> getObjectDescriptors() {
228            return allDescriptors.invoke().objects;
229        }
230    
231        @Override
232        public VariableDescriptor getLocalVariable(@NotNull Name name) {
233            return null;
234        }
235    
236        @NotNull
237        @Override
238        public DeclarationDescriptor getContainingDeclaration() {
239            return thisDescriptor;
240        }
241    
242        @NotNull
243        @Override
244        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
245            // A member scope has no labels
246            return Collections.emptySet();
247        }
248    
249        @NotNull
250        @Override
251        public Collection<DeclarationDescriptor> getAllDescriptors() {
252            return allDescriptors.invoke().all;
253        }
254    
255        @NotNull
256        private AllDescriptors computeAllDescriptors() {
257            AllDescriptors result = new AllDescriptors();
258            for (JetDeclaration declaration : declarationProvider.getAllDeclarations()) {
259                if (declaration instanceof JetEnumEntry) {
260                    JetEnumEntry jetEnumEntry = (JetEnumEntry) declaration;
261                    Name name = safeNameForLazyResolve(jetEnumEntry);
262                    if (name != null) {
263                        result.all.addAll(getProperties(name));
264                        result.objects.add(getObjectDescriptor(name));
265                    }
266                }
267                else if (declaration instanceof JetObjectDeclaration) {
268                    JetObjectDeclaration objectDeclaration = (JetObjectDeclaration) declaration;
269                    Name name = safeNameForLazyResolve(objectDeclaration.getNameAsDeclaration());
270                    if (name != null) {
271                        result.all.addAll(getProperties(name));
272                        result.objects.add(getObjectDescriptor(name));
273                    }
274                }
275                else if (declaration instanceof JetClassOrObject) {
276                    JetClassOrObject classOrObject = (JetClassOrObject) declaration;
277                    Name name = safeNameForLazyResolve(classOrObject.getNameAsName());
278                    if (name != null) {
279                        result.all.addAll(classDescriptors.invoke(name));
280                    }
281                }
282                else if (declaration instanceof JetFunction) {
283                    JetFunction function = (JetFunction) declaration;
284                    result.all.addAll(getFunctions(safeNameForLazyResolve(function)));
285                }
286                else if (declaration instanceof JetProperty) {
287                    JetProperty property = (JetProperty) declaration;
288                    result.all.addAll(getProperties(safeNameForLazyResolve(property)));
289                }
290                else if (declaration instanceof JetParameter) {
291                    JetParameter parameter = (JetParameter) declaration;
292                    Name name = safeNameForLazyResolve(parameter);
293                    result.all.addAll(getProperties(name));
294                }
295                else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
296                    // Do nothing for typedefs as they are not supported.
297                    // MultiDeclarations are not supported on global level too.
298                }
299                else {
300                    throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
301                }
302            }
303            addExtraDescriptors(result.all);
304            return result;
305        }
306    
307        protected abstract void addExtraDescriptors(@NotNull Collection<DeclarationDescriptor> result);
308    
309        @NotNull
310        @Override
311        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
312            ReceiverParameterDescriptor receiver = getImplicitReceiver();
313            if (receiver != null) {
314                return Collections.singletonList(receiver);
315            }
316            return Collections.emptyList();
317        }
318    
319        @Nullable
320        protected abstract ReceiverParameterDescriptor getImplicitReceiver();
321    
322        // Do not change this, override in concrete subclasses:
323        // it is very easy to compromise laziness of this class, and fail all the debugging
324        // a generic implementation can't do this properly
325        @Override
326        public abstract String toString();
327    
328        @NotNull
329        @Override
330        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
331            return getAllDescriptors();
332        }
333    
334        @Override
335        public void printScopeStructure(@NotNull Printer p) {
336            p.println(getClass().getSimpleName(), " {");
337            p.pushIndent();
338    
339            p.println("thisDescriptor = ", thisDescriptor);
340    
341            p.popIndent();
342            p.println("}");
343        }
344    }