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