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