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.AnnotationResolver;
029    import org.jetbrains.jet.lang.resolve.BindingTrace;
030    import org.jetbrains.jet.lang.resolve.ScriptNameUtil;
031    import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo;
032    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
033    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
034    import org.jetbrains.jet.lang.resolve.lazy.data.JetScriptInfo;
035    import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProvider;
036    import org.jetbrains.jet.lang.resolve.name.Name;
037    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038    import org.jetbrains.jet.storage.MemoizedFunctionToNotNull;
039    import org.jetbrains.jet.storage.NotNullLazyValue;
040    import org.jetbrains.jet.storage.StorageManager;
041    import org.jetbrains.jet.utils.Printer;
042    
043    import java.util.*;
044    
045    public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, DP extends DeclarationProvider> implements JetScope {
046        protected final ResolveSession resolveSession;
047        protected final BindingTrace trace;
048        protected final DP declarationProvider;
049        protected final D thisDescriptor;
050    
051        private final MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> classDescriptors;
052    
053        private final MemoizedFunctionToNotNull<Name, Set<FunctionDescriptor>> functionDescriptors;
054        private final MemoizedFunctionToNotNull<Name, Set<VariableDescriptor>> propertyDescriptors;
055    
056        private final NotNullLazyValue<Collection<DeclarationDescriptor>> descriptorsFromDeclaredElements;
057        private final NotNullLazyValue<Collection<DeclarationDescriptor>> extraDescriptors;
058    
059        protected AbstractLazyMemberScope(
060                @NotNull ResolveSession resolveSession,
061                @NotNull DP declarationProvider,
062                @NotNull D thisDescriptor,
063                @NotNull BindingTrace trace
064        ) {
065            this.resolveSession = resolveSession;
066            this.trace = trace;
067            this.declarationProvider = declarationProvider;
068            this.thisDescriptor = thisDescriptor;
069    
070            StorageManager storageManager = resolveSession.getStorageManager();
071            this.classDescriptors = storageManager.createMemoizedFunction(new Function1<Name, List<ClassDescriptor>>() {
072                @Override
073                public List<ClassDescriptor> invoke(Name name) {
074                    return resolveClassDescriptor(name);
075                }
076            });
077    
078            this.functionDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<FunctionDescriptor>>() {
079                @Override
080                public Set<FunctionDescriptor> invoke(Name name) {
081                    return doGetFunctions(name);
082                }
083            });
084            this.propertyDescriptors = storageManager.createMemoizedFunction(new Function1<Name, Set<VariableDescriptor>>() {
085                @Override
086                public Set<VariableDescriptor> invoke(Name name) {
087                    return doGetProperties(name);
088                }
089            });
090    
091            this.descriptorsFromDeclaredElements = storageManager.createLazyValue(new Function0<Collection<DeclarationDescriptor>>() {
092                @Override
093                public Collection<DeclarationDescriptor> invoke() {
094                    return computeDescriptorsFromDeclaredElements();
095                }
096            });
097            this.extraDescriptors = storageManager.createLazyValue(new Function0<Collection<DeclarationDescriptor>>() {
098                @Override
099                public Collection<DeclarationDescriptor> invoke() {
100                    return computeExtraDescriptors();
101                }
102            });
103        }
104    
105        @Nullable
106        private List<ClassDescriptor> resolveClassDescriptor(@NotNull final Name name) {
107            Collection<JetClassLikeInfo> classOrObjectDeclarations = declarationProvider.getClassOrObjectDeclarations(name);
108    
109            return ContainerUtil.mapNotNull(classOrObjectDeclarations, new Function<JetClassLikeInfo, ClassDescriptor>() {
110                @Override
111                public ClassDescriptor fun(JetClassLikeInfo classLikeInfo) {
112                    // SCRIPT: Creating a script class
113                    if (classLikeInfo instanceof JetScriptInfo) {
114                        return new LazyScriptClassDescriptor(resolveSession, thisDescriptor, name, (JetScriptInfo) classLikeInfo);
115                    }
116                    return new LazyClassDescriptor(resolveSession, thisDescriptor, name, classLikeInfo);
117                }
118            });
119        }
120    
121        @Override
122        public ClassifierDescriptor getClassifier(@NotNull Name name) {
123            return first(classDescriptors.invoke(name));
124        }
125    
126        private static <T> T first(@NotNull List<T> list) {
127            if (list.isEmpty()) return null;
128            return list.get(0);
129        }
130    
131        @NotNull
132        @Override
133        public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
134            return functionDescriptors.invoke(name);
135        }
136    
137        @NotNull
138        private Set<FunctionDescriptor> doGetFunctions(@NotNull Name name) {
139            Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
140    
141            Collection<JetNamedFunction> declarations = declarationProvider.getFunctionDeclarations(name);
142            for (JetNamedFunction functionDeclaration : declarations) {
143                JetScope resolutionScope = getScopeForMemberDeclarationResolution(functionDeclaration);
144                result.add(resolveSession.getDescriptorResolver().resolveFunctionDescriptorWithAnnotationArguments(
145                      thisDescriptor, resolutionScope,
146                      functionDeclaration,
147                      trace,
148                      // this relies on the assumption that a lazily resolved declaration is not a local one,
149                      // thus doesn't have a surrounding data flow
150                      DataFlowInfo.EMPTY)
151                );
152            }
153    
154            getNonDeclaredFunctions(name, result);
155    
156            return result;
157        }
158    
159        @NotNull
160        protected abstract JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration);
161    
162        protected abstract void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result);
163    
164        @NotNull
165        @Override
166        public Set<VariableDescriptor> getProperties(@NotNull Name name) {
167            return propertyDescriptors.invoke(name);
168        }
169    
170        @NotNull
171        public Set<VariableDescriptor> doGetProperties(@NotNull Name name) {
172            Set<VariableDescriptor> result = Sets.newLinkedHashSet();
173    
174            Collection<JetProperty> declarations = declarationProvider.getPropertyDeclarations(name);
175            for (JetProperty propertyDeclaration : declarations) {
176                JetScope resolutionScope = getScopeForMemberDeclarationResolution(propertyDeclaration);
177                PropertyDescriptor propertyDescriptor =
178                        resolveSession.getDescriptorResolver().resolvePropertyDescriptor(
179                               thisDescriptor, resolutionScope,
180                               propertyDeclaration,
181                               trace,
182                               // this relies on the assumption that a lazily resolved declaration is not a local one,
183                               // thus doesn't have a surrounding data flow
184                               DataFlowInfo.EMPTY
185                        );
186                result.add(propertyDescriptor);
187                AnnotationResolver.resolveAnnotationsArguments(propertyDescriptor.getAnnotations(), trace);
188            }
189    
190            getNonDeclaredProperties(name, result);
191    
192            return result;
193        }
194    
195        protected abstract void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result);
196    
197        @Override
198        public VariableDescriptor getLocalVariable(@NotNull Name name) {
199            return null;
200        }
201    
202        @NotNull
203        @Override
204        public DeclarationDescriptor getContainingDeclaration() {
205            return thisDescriptor;
206        }
207    
208        @NotNull
209        @Override
210        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull Name labelName) {
211            // A member scope has no labels
212            return Collections.emptySet();
213        }
214    
215        @NotNull
216        @Override
217        public Collection<DeclarationDescriptor> getAllDescriptors() {
218            Collection<DeclarationDescriptor> result = new LinkedHashSet<DeclarationDescriptor>(descriptorsFromDeclaredElements.invoke());
219            result.addAll(extraDescriptors.invoke());
220            return result;
221        }
222    
223        @NotNull
224        private Collection<DeclarationDescriptor> computeDescriptorsFromDeclaredElements() {
225            List<JetDeclaration> declarations = declarationProvider.getAllDeclarations();
226            ArrayList<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarations.size());
227            for (JetDeclaration declaration : declarations) {
228                if (declaration instanceof JetClassOrObject) {
229                    JetClassOrObject classOrObject = (JetClassOrObject) declaration;
230                    result.addAll(classDescriptors.invoke(classOrObject.getNameAsSafeName()));
231                }
232                else if (declaration instanceof JetFunction) {
233                    JetFunction function = (JetFunction) declaration;
234                    result.addAll(getFunctions(function.getNameAsSafeName()));
235                }
236                else if (declaration instanceof JetProperty) {
237                    JetProperty property = (JetProperty) declaration;
238                    result.addAll(getProperties(property.getNameAsSafeName()));
239                }
240                else if (declaration instanceof JetParameter) {
241                    JetParameter parameter = (JetParameter) declaration;
242                    result.addAll(getProperties(parameter.getNameAsSafeName()));
243                }
244                else if (declaration instanceof JetScript) {
245                    result.addAll(classDescriptors.invoke(ScriptNameUtil.classNameForScript((JetScript) declaration).shortName()));
246                }
247                else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
248                    // Do nothing for typedefs as they are not supported.
249                    // MultiDeclarations are not supported on global level too.
250                }
251                else {
252                    throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
253                }
254            }
255            result.trimToSize();
256            return result;
257        }
258    
259        @NotNull
260        protected abstract Collection<DeclarationDescriptor> computeExtraDescriptors();
261    
262        @NotNull
263        @Override
264        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
265            return Collections.emptyList();
266        }
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    }