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