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                    VariableDescriptor propertyDescriptor = resolveSession.getInjector().getDescriptorResolver()
209                            .resolveObjectDeclaration(thisDescriptor, classOrObjectDeclaration, classifier, resolveSession.getTrace());
210                    result.add(propertyDescriptor);
211                }
212            }
213    
214            getNonDeclaredProperties(name, result);
215    
216            return result;
217        }
218    
219        protected abstract void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result);
220    
221        @NotNull
222        @Override
223        public Collection<ClassDescriptor> getObjectDescriptors() {
224            return allDescriptors.compute().objects;
225        }
226    
227        @Override
228        public VariableDescriptor getLocalVariable(@NotNull Name name) {
229            return null;
230        }
231    
232        @NotNull
233        @Override
234        public DeclarationDescriptor getContainingDeclaration() {
235            return thisDescriptor;
236        }
237    
238        @NotNull
239        @Override
240        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
241            // A member scope has no labels
242            return Collections.emptySet();
243        }
244    
245        @Override
246        public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) {
247            throw new UnsupportedOperationException(); // TODO
248        }
249    
250        @NotNull
251        @Override
252        public Collection<DeclarationDescriptor> getAllDescriptors() {
253            return allDescriptors.compute().all;
254        }
255    
256        @NotNull
257        private AllDescriptors computeAllDescriptors() {
258            AllDescriptors result = new AllDescriptors();
259            for (JetDeclaration declaration : declarationProvider.getAllDeclarations()) {
260                if (declaration instanceof JetEnumEntry) {
261                    JetEnumEntry jetEnumEntry = (JetEnumEntry) declaration;
262                    Name name = safeNameForLazyResolve(jetEnumEntry);
263                    if (name != null) {
264                        result.all.addAll(getProperties(name));
265                        result.objects.add(getObjectDescriptor(name));
266                    }
267                }
268                else if (declaration instanceof JetObjectDeclaration) {
269                    JetObjectDeclaration objectDeclaration = (JetObjectDeclaration) declaration;
270                    Name name = safeNameForLazyResolve(objectDeclaration.getNameAsDeclaration());
271                    if (name != null) {
272                        result.all.addAll(getProperties(name));
273                        result.objects.add(getObjectDescriptor(name));
274                    }
275                }
276                else if (declaration instanceof JetClassOrObject) {
277                    JetClassOrObject classOrObject = (JetClassOrObject) declaration;
278                    Name name = safeNameForLazyResolve(classOrObject.getNameAsName());
279                    if (name != null) {
280                        result.all.addAll(classDescriptors.fun(name));
281                    }
282                }
283                else if (declaration instanceof JetFunction) {
284                    JetFunction function = (JetFunction) declaration;
285                    result.all.addAll(getFunctions(safeNameForLazyResolve(function)));
286                }
287                else if (declaration instanceof JetProperty) {
288                    JetProperty property = (JetProperty) declaration;
289                    result.all.addAll(getProperties(safeNameForLazyResolve(property)));
290                }
291                else if (declaration instanceof JetParameter) {
292                    JetParameter parameter = (JetParameter) declaration;
293                    Name name = safeNameForLazyResolve(parameter);
294                    result.all.addAll(getProperties(name));
295                }
296                else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
297                    // Do nothing for typedefs as they are not supported.
298                    // MultiDeclarations are not supported on global level too.
299                }
300                else {
301                    throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
302                }
303            }
304            addExtraDescriptors(result.all);
305            return result;
306        }
307    
308        protected abstract void addExtraDescriptors(@NotNull Collection<DeclarationDescriptor> result);
309    
310        @NotNull
311        @Override
312        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
313            ReceiverParameterDescriptor receiver = getImplicitReceiver();
314            if (receiver != null) {
315                return Collections.singletonList(receiver);
316            }
317            return Collections.emptyList();
318        }
319    
320        @Nullable
321        protected abstract ReceiverParameterDescriptor getImplicitReceiver();
322    
323        // Do not change this, override in concrete subclasses:
324        // it is very easy to compromise laziness of this class, and fail all the debugging
325        // a generic implementation can't do this properly
326        @Override
327        public abstract String toString();
328    
329        @NotNull
330        @Override
331        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
332            return getAllDescriptors();
333        }
334    }