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 }