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.autocasts.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                result.add(propertyDescriptor);
186                AnnotationResolver.resolveAnnotationsArguments(propertyDescriptor, trace);
187            }
188    
189            getNonDeclaredProperties(name, result);
190    
191            return result;
192        }
193    
194        protected abstract void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result);
195    
196        @Override
197        public VariableDescriptor getLocalVariable(@NotNull Name name) {
198            return null;
199        }
200    
201        @NotNull
202        @Override
203        public DeclarationDescriptor getContainingDeclaration() {
204            return thisDescriptor;
205        }
206    
207        @NotNull
208        @Override
209        public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull Name labelName) {
210            // A member scope has no labels
211            return Collections.emptySet();
212        }
213    
214        @NotNull
215        @Override
216        public Collection<DeclarationDescriptor> getAllDescriptors() {
217            Collection<DeclarationDescriptor> result = new LinkedHashSet<DeclarationDescriptor>(descriptorsFromDeclaredElements.invoke());
218            result.addAll(extraDescriptors.invoke());
219            return result;
220        }
221    
222        @NotNull
223        private Collection<DeclarationDescriptor> computeDescriptorsFromDeclaredElements() {
224            List<JetDeclaration> declarations = declarationProvider.getAllDeclarations();
225            ArrayList<DeclarationDescriptor> result = new ArrayList<DeclarationDescriptor>(declarations.size());
226            for (JetDeclaration declaration : declarations) {
227                if (declaration instanceof JetClassOrObject) {
228                    JetClassOrObject classOrObject = (JetClassOrObject) declaration;
229                    result.addAll(classDescriptors.invoke(classOrObject.getNameAsSafeName()));
230                }
231                else if (declaration instanceof JetFunction) {
232                    JetFunction function = (JetFunction) declaration;
233                    result.addAll(getFunctions(function.getNameAsSafeName()));
234                }
235                else if (declaration instanceof JetProperty) {
236                    JetProperty property = (JetProperty) declaration;
237                    result.addAll(getProperties(property.getNameAsSafeName()));
238                }
239                else if (declaration instanceof JetParameter) {
240                    JetParameter parameter = (JetParameter) declaration;
241                    result.addAll(getProperties(parameter.getNameAsSafeName()));
242                }
243                else if (declaration instanceof JetScript) {
244                    result.addAll(classDescriptors.invoke(ScriptNameUtil.classNameForScript((JetScript) declaration).shortName()));
245                }
246                else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
247                    // Do nothing for typedefs as they are not supported.
248                    // MultiDeclarations are not supported on global level too.
249                }
250                else {
251                    throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
252                }
253            }
254            result.trimToSize();
255            return result;
256        }
257    
258        @NotNull
259        protected abstract Collection<DeclarationDescriptor> computeExtraDescriptors();
260    
261        @NotNull
262        @Override
263        public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
264            ReceiverParameterDescriptor receiver = getImplicitReceiver();
265            if (receiver != null) {
266                return Collections.singletonList(receiver);
267            }
268            return Collections.emptyList();
269        }
270    
271        @Nullable
272        protected abstract ReceiverParameterDescriptor getImplicitReceiver();
273    
274        // Do not change this, override in concrete subclasses:
275        // it is very easy to compromise laziness of this class, and fail all the debugging
276        // a generic implementation can't do this properly
277        @Override
278        public abstract String toString();
279    
280        @NotNull
281        @Override
282        public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
283            return getAllDescriptors();
284        }
285    
286        @Override
287        public void printScopeStructure(@NotNull Printer p) {
288            p.println(getClass().getSimpleName(), " {");
289            p.pushIndent();
290    
291            p.println("thisDescriptor = ", thisDescriptor);
292    
293            p.popIndent();
294            p.println("}");
295        }
296    }