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    
039    import java.util.Collection;
040    import java.util.Collections;
041    import java.util.List;
042    import java.util.Set;
043    
044    import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
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 Function1<Name, List<ClassDescriptor>>() {
075                @Override
076                public List<ClassDescriptor> invoke(Name name) {
077                    return resolveClassOrObjectDescriptor(name, false);
078                }
079            });
080            this.objectDescriptors = storageManager.createMemoizedFunction(new Function1<Name, List<ClassDescriptor>>() {
081                @Override
082                public List<ClassDescriptor> invoke(Name name) {
083                    return resolveClassOrObjectDescriptor(name, true);
084                }
085            });
086    
087            this.functionDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<FunctionDescriptor>>() {
088                @Override
089                public Set<FunctionDescriptor> invoke(Name name) {
090                    return doGetFunctions(name);
091                }
092            });
093            this.propertyDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<VariableDescriptor>>() {
094                @Override
095                public Set<VariableDescriptor> invoke(Name name) {
096                    return doGetProperties(name);
097                }
098            });
099    
100            this.allDescriptors = storageManager.createLazyValue(new Function0<AllDescriptors>() {
101                @Override
102                public AllDescriptors invoke() {
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.invoke(name));
130        }
131    
132        @Override
133        public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
134            return first(objectDescriptors.invoke(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.invoke(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.invoke(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.invoke().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        @NotNull
249        @Override
250        public Collection<DeclarationDescriptor> getAllDescriptors() {
251            return allDescriptors.invoke().all;
252        }
253    
254        @NotNull
255        private AllDescriptors computeAllDescriptors() {
256            AllDescriptors result = new AllDescriptors();
257            for (JetDeclaration declaration : declarationProvider.getAllDeclarations()) {
258                if (declaration instanceof JetEnumEntry) {
259                    JetEnumEntry jetEnumEntry = (JetEnumEntry) declaration;
260                    Name name = safeNameForLazyResolve(jetEnumEntry);
261                    if (name != null) {
262                        result.all.addAll(getProperties(name));
263                        result.objects.add(getObjectDescriptor(name));
264                    }
265                }
266                else if (declaration instanceof JetObjectDeclaration) {
267                    JetObjectDeclaration objectDeclaration = (JetObjectDeclaration) declaration;
268                    Name name = safeNameForLazyResolve(objectDeclaration.getNameAsDeclaration());
269                    if (name != null) {
270                        result.all.addAll(getProperties(name));
271                        result.objects.add(getObjectDescriptor(name));
272                    }
273                }
274                else if (declaration instanceof JetClassOrObject) {
275                    JetClassOrObject classOrObject = (JetClassOrObject) declaration;
276                    Name name = safeNameForLazyResolve(classOrObject.getNameAsName());
277                    if (name != null) {
278                        result.all.addAll(classDescriptors.invoke(name));
279                    }
280                }
281                else if (declaration instanceof JetFunction) {
282                    JetFunction function = (JetFunction) declaration;
283                    result.all.addAll(getFunctions(safeNameForLazyResolve(function)));
284                }
285                else if (declaration instanceof JetProperty) {
286                    JetProperty property = (JetProperty) declaration;
287                    result.all.addAll(getProperties(safeNameForLazyResolve(property)));
288                }
289                else if (declaration instanceof JetParameter) {
290                    JetParameter parameter = (JetParameter) declaration;
291                    Name name = safeNameForLazyResolve(parameter);
292                    result.all.addAll(getProperties(name));
293                }
294                else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
295                    // Do nothing for typedefs as they are not supported.
296                    // MultiDeclarations are not supported on global level too.
297                }
298                else {
299                    throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
300                }
301            }
302            addExtraDescriptors(result.all);
303            return result;
304        }
305    
306        protected abstract void addExtraDescriptors(@NotNull Collection<DeclarationDescriptor> result);
307    
308        @NotNull
309        @Override
310        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
311            ReceiverParameterDescriptor receiver = getImplicitReceiver();
312            if (receiver != null) {
313                return Collections.singletonList(receiver);
314            }
315            return Collections.emptyList();
316        }
317    
318        @Nullable
319        protected abstract ReceiverParameterDescriptor getImplicitReceiver();
320    
321        // Do not change this, override in concrete subclasses:
322        // it is very easy to compromise laziness of this class, and fail all the debugging
323        // a generic implementation can't do this properly
324        @Override
325        public abstract String toString();
326    
327        @NotNull
328        @Override
329        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
330            return getAllDescriptors();
331        }
332    }