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
017package org.jetbrains.jet.lang.resolve.lazy.descriptors;
018
019import com.google.common.collect.Sets;
020import com.intellij.openapi.util.Computable;
021import com.intellij.util.Function;
022import com.intellij.util.containers.ContainerUtil;
023import org.jetbrains.annotations.NotNull;
024import org.jetbrains.annotations.Nullable;
025import org.jetbrains.jet.lang.descriptors.*;
026import org.jetbrains.jet.lang.psi.*;
027import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
028import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
029import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProvider;
030import org.jetbrains.jet.lang.resolve.lazy.storage.MemoizedFunctionToNotNull;
031import org.jetbrains.jet.lang.resolve.lazy.storage.NotNullLazyValue;
032import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
033import org.jetbrains.jet.lang.resolve.name.LabelName;
034import org.jetbrains.jet.lang.resolve.name.Name;
035import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036
037import java.util.Collection;
038import java.util.Collections;
039import java.util.List;
040import java.util.Set;
041
042import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
043import static org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager.ReferenceKind.STRONG;
044
045public abstract class AbstractLazyMemberScope<D extends DeclarationDescriptor, DP extends DeclarationProvider> implements JetScope {
046    protected final ResolveSession resolveSession;
047    protected final DP declarationProvider;
048    protected final D thisDescriptor;
049
050    private final MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> classDescriptors;
051    private final MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> objectDescriptors;
052
053    private final MemoizedFunctionToNotNull<Name, Set<FunctionDescriptor>> functionDescriptors;
054    private final MemoizedFunctionToNotNull<Name, Set<VariableDescriptor>> propertyDescriptors;
055
056    private static class AllDescriptors {
057        private final Collection<DeclarationDescriptor> all = Sets.newLinkedHashSet();
058        private final Collection<ClassDescriptor> objects = Sets.newLinkedHashSet();
059    }
060
061    private final NotNullLazyValue<AllDescriptors> allDescriptors;
062
063    protected AbstractLazyMemberScope(
064            @NotNull ResolveSession resolveSession,
065            @NotNull DP declarationProvider,
066            @NotNull D thisDescriptor
067    ) {
068        this.resolveSession = resolveSession;
069        this.declarationProvider = declarationProvider;
070        this.thisDescriptor = thisDescriptor;
071
072        StorageManager storageManager = resolveSession.getStorageManager();
073        this.classDescriptors = storageManager.createMemoizedFunction(new Function<Name, List<ClassDescriptor>>() {
074            @Override
075            public List<ClassDescriptor> fun(Name name) {
076                return resolveClassOrObjectDescriptor(name, false);
077            }
078        }, STRONG);
079        this.objectDescriptors = storageManager.createMemoizedFunction(new Function<Name, List<ClassDescriptor>>() {
080            @Override
081            public List<ClassDescriptor> fun(Name name) {
082                return resolveClassOrObjectDescriptor(name, true);
083            }
084        }, STRONG);
085
086        this.functionDescriptors = storageManager.createMemoizedFunction(new Function<Name, Set<FunctionDescriptor>>() {
087            @Override
088            public Set<FunctionDescriptor> fun(Name name) {
089                return doGetFunctions(name);
090            }
091        }, STRONG);
092        this.propertyDescriptors = storageManager.createMemoizedFunction(new Function<Name, Set<VariableDescriptor>>() {
093            @Override
094            public Set<VariableDescriptor> fun(Name name) {
095                return doGetProperties(name);
096            }
097        }, STRONG);
098
099        this.allDescriptors = storageManager.createLazyValue(new Computable<AllDescriptors>() {
100            @Override
101            public AllDescriptors compute() {
102                return computeAllDescriptors();
103            }
104        });
105    }
106
107    @Nullable
108    private List<ClassDescriptor> resolveClassOrObjectDescriptor(@NotNull final Name name, final boolean object) {
109        Collection<JetClassOrObject> classOrObjectDeclarations = declarationProvider.getClassOrObjectDeclarations(name);
110
111        return ContainerUtil.mapNotNull(classOrObjectDeclarations, new Function<JetClassOrObject, ClassDescriptor>() {
112            @Override
113            public ClassDescriptor fun(JetClassOrObject classOrObject) {
114                if (object != declaresObjectOrEnumConstant(classOrObject)) return null;
115
116                return new LazyClassDescriptor(resolveSession, thisDescriptor, name,
117                                               JetClassInfoUtil.createClassLikeInfo(classOrObject));
118            }
119        });
120    }
121
122    private static boolean declaresObjectOrEnumConstant(JetClassOrObject declaration) {
123        return declaration instanceof JetObjectDeclaration || declaration instanceof JetEnumEntry;
124    }
125
126    @Override
127    public ClassifierDescriptor getClassifier(@NotNull Name name) {
128        return first(classDescriptors.fun(name));
129    }
130
131    @Override
132    public ClassDescriptor getObjectDescriptor(@NotNull Name name) {
133        return first(objectDescriptors.fun(name));
134    }
135
136    private static <T> T first(@NotNull List<T> list) {
137        if (list.isEmpty()) return null;
138        return list.get(0);
139    }
140
141    @NotNull
142    @Override
143    public Set<FunctionDescriptor> getFunctions(@NotNull Name name) {
144        return functionDescriptors.fun(name);
145    }
146
147    @NotNull
148    private Set<FunctionDescriptor> doGetFunctions(@NotNull Name name) {
149        Set<FunctionDescriptor> result = Sets.newLinkedHashSet();
150
151        Collection<JetNamedFunction> declarations = declarationProvider.getFunctionDeclarations(name);
152        for (JetNamedFunction functionDeclaration : declarations) {
153            JetScope resolutionScope = getScopeForMemberDeclarationResolution(functionDeclaration);
154            result.add(resolveSession.getInjector().getDescriptorResolver().resolveFunctionDescriptorWithAnnotationArguments(thisDescriptor, resolutionScope,
155                                                                                                      functionDeclaration,
156                                                                                                      resolveSession.getTrace()));
157        }
158
159        getNonDeclaredFunctions(name, result);
160
161        return result;
162    }
163
164    @NotNull
165    protected abstract JetScope getScopeForMemberDeclarationResolution(JetDeclaration declaration);
166
167    protected abstract void getNonDeclaredFunctions(@NotNull Name name, @NotNull Set<FunctionDescriptor> result);
168
169    @NotNull
170    @Override
171    public Set<VariableDescriptor> getProperties(@NotNull Name name) {
172        return propertyDescriptors.fun(name);
173    }
174
175    @NotNull
176    public Set<VariableDescriptor> doGetProperties(@NotNull Name name) {
177        Set<VariableDescriptor> result = Sets.newLinkedHashSet();
178
179        Collection<JetProperty> declarations = declarationProvider.getPropertyDeclarations(name);
180        for (JetProperty propertyDeclaration : declarations) {
181            JetScope resolutionScope = getScopeForMemberDeclarationResolution(propertyDeclaration);
182            PropertyDescriptor propertyDescriptor =
183                    resolveSession.getInjector().getDescriptorResolver().resolvePropertyDescriptor(thisDescriptor, resolutionScope,
184                                                                                                   propertyDeclaration,
185                                                                                                   resolveSession.getTrace());
186            result.add(propertyDescriptor);
187            resolveSession.getInjector().getAnnotationResolver().resolveAnnotationsArguments(propertyDescriptor, resolveSession.getTrace(), resolutionScope);
188        }
189
190        // Objects are also properties
191        Collection<JetClassOrObject> classOrObjectDeclarations = declarationProvider.getClassOrObjectDeclarations(name);
192        for (JetClassOrObject classOrObjectDeclaration : classOrObjectDeclarations) {
193            if (declaresObjectOrEnumConstant(classOrObjectDeclaration)) {
194                ClassDescriptor classifier = getObjectDescriptor(name);
195                if (classifier == null) {
196                    throw new IllegalStateException("Object declaration " + name + " found in the DeclarationProvider " + declarationProvider + " but not in the scope " + this);
197                }
198                VariableDescriptor propertyDescriptor = resolveSession.getInjector().getDescriptorResolver()
199                        .resolveObjectDeclaration(thisDescriptor, classOrObjectDeclaration, classifier, resolveSession.getTrace());
200                result.add(propertyDescriptor);
201            }
202        }
203
204        getNonDeclaredProperties(name, result);
205
206        return result;
207    }
208
209    protected abstract void getNonDeclaredProperties(@NotNull Name name, @NotNull Set<VariableDescriptor> result);
210
211    @NotNull
212    @Override
213    public Collection<ClassDescriptor> getObjectDescriptors() {
214        return allDescriptors.compute().objects;
215    }
216
217    @Override
218    public VariableDescriptor getLocalVariable(@NotNull Name name) {
219        return null;
220    }
221
222    @NotNull
223    @Override
224    public DeclarationDescriptor getContainingDeclaration() {
225        return thisDescriptor;
226    }
227
228    @NotNull
229    @Override
230    public Collection<DeclarationDescriptor> getDeclarationsByLabel(@NotNull LabelName labelName) {
231        // A member scope has no labels
232        return Collections.emptySet();
233    }
234
235    @Override
236    public PropertyDescriptor getPropertyByFieldReference(@NotNull Name fieldName) {
237        throw new UnsupportedOperationException(); // TODO
238    }
239
240    @NotNull
241    @Override
242    public Collection<DeclarationDescriptor> getAllDescriptors() {
243        return allDescriptors.compute().all;
244    }
245
246    @NotNull
247    private AllDescriptors computeAllDescriptors() {
248        AllDescriptors result = new AllDescriptors();
249        for (JetDeclaration declaration : declarationProvider.getAllDeclarations()) {
250            if (declaration instanceof JetEnumEntry) {
251                JetEnumEntry jetEnumEntry = (JetEnumEntry) declaration;
252                Name name = safeNameForLazyResolve(jetEnumEntry);
253                if (name != null) {
254                    result.all.addAll(getProperties(name));
255                    result.objects.add(getObjectDescriptor(name));
256                }
257            }
258            else if (declaration instanceof JetObjectDeclaration) {
259                JetObjectDeclaration objectDeclaration = (JetObjectDeclaration) declaration;
260                Name name = safeNameForLazyResolve(objectDeclaration.getNameAsDeclaration());
261                if (name != null) {
262                    result.all.addAll(getProperties(name));
263                    result.objects.add(getObjectDescriptor(name));
264                }
265            }
266            else if (declaration instanceof JetClassOrObject) {
267                JetClassOrObject classOrObject = (JetClassOrObject) declaration;
268                Name name = safeNameForLazyResolve(classOrObject.getNameAsName());
269                if (name != null) {
270                    result.all.addAll(classDescriptors.fun(name));
271                }
272            }
273            else if (declaration instanceof JetFunction) {
274                JetFunction function = (JetFunction) declaration;
275                result.all.addAll(getFunctions(safeNameForLazyResolve(function)));
276            }
277            else if (declaration instanceof JetProperty) {
278                JetProperty property = (JetProperty) declaration;
279                result.all.addAll(getProperties(safeNameForLazyResolve(property)));
280            }
281            else if (declaration instanceof JetParameter) {
282                JetParameter parameter = (JetParameter) declaration;
283                Name name = safeNameForLazyResolve(parameter);
284                result.all.addAll(getProperties(name));
285            }
286            else if (declaration instanceof JetTypedef || declaration instanceof JetMultiDeclaration) {
287                // Do nothing for typedefs as they are not supported.
288                // MultiDeclarations are not supported on global level too.
289            }
290            else {
291                throw new IllegalArgumentException("Unsupported declaration kind: " + declaration);
292            }
293        }
294        addExtraDescriptors(result.all);
295        return result;
296    }
297
298    protected abstract void addExtraDescriptors(@NotNull Collection<DeclarationDescriptor> result);
299
300    @NotNull
301    @Override
302    public List<ReceiverParameterDescriptor> getImplicitReceiversHierarchy() {
303        ReceiverParameterDescriptor receiver = getImplicitReceiver();
304        if (receiver != null) {
305            return Collections.singletonList(receiver);
306        }
307        return Collections.emptyList();
308    }
309
310    @Nullable
311    protected abstract ReceiverParameterDescriptor getImplicitReceiver();
312
313    // Do not change this, override in concrete subclasses:
314    // it is very easy to compromise laziness of this class, and fail all the debugging
315    // a generic implementation can't do this properly
316    @Override
317    public abstract String toString();
318
319    @NotNull
320    @Override
321    public Collection<DeclarationDescriptor> getOwnDeclaredDescriptors() {
322        return getAllDescriptors();
323    }
324}