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