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