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.java.scope;
018    
019    import com.google.common.collect.Lists;
020    import com.google.common.collect.Maps;
021    import com.google.common.collect.Sets;
022    import com.intellij.openapi.progress.ProgressIndicatorProvider;
023    import com.intellij.openapi.util.Condition;
024    import com.intellij.psi.PsiElement;
025    import com.intellij.util.containers.ContainerUtil;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.jet.lang.descriptors.*;
029    import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
030    import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices;
031    import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider;
032    import org.jetbrains.jet.lang.resolve.java.provider.NamedMembers;
033    import org.jetbrains.jet.lang.resolve.java.provider.PackagePsiDeclarationProvider;
034    import org.jetbrains.jet.lang.resolve.java.provider.PsiDeclarationProvider;
035    import org.jetbrains.jet.lang.resolve.name.Name;
036    import org.jetbrains.jet.lang.resolve.scopes.JetScopeImpl;
037    
038    import java.util.*;
039    
040    public abstract class JavaBaseScope extends JetScopeImpl {
041    
042        @NotNull
043        protected final JavaSemanticServices semanticServices;
044        @NotNull
045        protected final PsiDeclarationProvider declarationProvider;
046        @NotNull
047        private final Map<Name, Set<FunctionDescriptor>> functionDescriptors = Maps.newHashMap();
048        @NotNull
049        private final Map<Name, Set<VariableDescriptor>> propertyDescriptors = Maps.newHashMap();
050        @Nullable
051        private Collection<DeclarationDescriptor> allDescriptors = null;
052        @Nullable
053        private Set<ClassDescriptor> objectDescriptors = null;
054        @NotNull
055        protected final ClassOrNamespaceDescriptor descriptor;
056    
057        private Collection<ClassDescriptor> innerClasses = null;
058    
059    
060        protected JavaBaseScope(
061                @NotNull ClassOrNamespaceDescriptor descriptor,
062                @NotNull JavaSemanticServices semanticServices,
063                @NotNull PsiDeclarationProvider declarationProvider
064        ) {
065            this.semanticServices = semanticServices;
066            this.declarationProvider = declarationProvider;
067            this.descriptor = descriptor;
068        }
069    
070        @NotNull
071        @Override
072        public DeclarationDescriptor getContainingDeclaration() {
073            return descriptor;
074        }
075    
076        @NotNull
077        @Override
078        public Collection<VariableDescriptor> getProperties(@NotNull Name name) {
079            Set<VariableDescriptor> cached = propertyDescriptors.get(name);
080            if (cached != null) return cached;
081    
082            if (allDescriptorsComputed()) {
083                return Collections.emptySet();
084            }
085    
086            Set<VariableDescriptor> computedDescriptors = computePropertyDescriptors(name);
087            propertyDescriptors.put(name, computedDescriptors);
088            return computedDescriptors;
089        }
090    
091        @NotNull
092        private Set<VariableDescriptor> computePropertyDescriptors(@NotNull Name name) {
093            return getResolver().resolveFieldGroupByName(name, declarationProvider, descriptor);
094        }
095    
096        @NotNull
097        @Override
098        public Collection<FunctionDescriptor> getFunctions(@NotNull Name name) {
099            Set<FunctionDescriptor> cached = functionDescriptors.get(name);
100            if (cached != null) return cached;
101    
102            if (allDescriptorsComputed()) {
103                return Collections.emptySet();
104            }
105    
106            Set<FunctionDescriptor> computedDescriptors = computeFunctionDescriptor(name);
107            functionDescriptors.put(name, computedDescriptors);
108            return computedDescriptors;
109        }
110    
111        @NotNull
112        protected abstract Set<FunctionDescriptor> computeFunctionDescriptor(@NotNull Name name);
113    
114        @NotNull
115        @Override
116        public Collection<DeclarationDescriptor> getAllDescriptors() {
117            if (allDescriptorsComputed()) {
118                return allDescriptors;
119            }
120    
121            allDescriptors = computeAllDescriptors();
122    
123            return allDescriptors;
124        }
125    
126        private boolean allDescriptorsComputed() {
127            return allDescriptors != null;
128        }
129    
130        @NotNull
131        protected Collection<DeclarationDescriptor> computeAllDescriptors() {
132            Collection<DeclarationDescriptor> result = Sets.newHashSet();
133            result.addAll(computeFieldAndFunctionDescriptors());
134            result.addAll(filterObjects(getInnerClasses(), false));
135            return result;
136        }
137    
138        @NotNull
139        @Override
140        public Set<ClassDescriptor> getObjectDescriptors() {
141            if (objectDescriptors == null) {
142                objectDescriptors = new HashSet<ClassDescriptor>(filterObjects(getInnerClasses(), true));
143            }
144            return objectDescriptors;
145        }
146    
147        @NotNull
148        protected abstract Collection<ClassDescriptor> computeInnerClasses();
149    
150        @NotNull
151        private Collection<DeclarationDescriptor> computeFieldAndFunctionDescriptors() {
152            Collection<DeclarationDescriptor> result = Lists.newArrayList();
153            for (NamedMembers members : declarationProvider.getMembersCache().allMembers()) {
154                Name name = members.getName();
155                ProgressIndicatorProvider.checkCanceled();
156                result.addAll(getFunctions(name));
157                ProgressIndicatorProvider.checkCanceled();
158                result.addAll(getProperties(name));
159            }
160            return result;
161        }
162    
163        @NotNull
164        protected JavaDescriptorResolver getResolver() {
165            return semanticServices.getDescriptorResolver();
166        }
167    
168        //TODO: remove this method
169        @NotNull
170        public PsiElement getPsiElement() {
171            if (declarationProvider instanceof ClassPsiDeclarationProvider) {
172                return ((ClassPsiDeclarationProvider) declarationProvider).getPsiClass();
173            }
174            if (declarationProvider instanceof PackagePsiDeclarationProvider) {
175                return ((PackagePsiDeclarationProvider) declarationProvider).getPsiPackage();
176            }
177            throw new IllegalStateException();
178        }
179    
180        @NotNull
181        protected Collection<ClassDescriptor> getInnerClasses() {
182            if (innerClasses == null) {
183                innerClasses = computeInnerClasses();
184            }
185            return innerClasses;
186        }
187    
188        private static <T extends ClassDescriptor> Collection<T> filterObjects(Collection<T> classes, final boolean objects) {
189            return ContainerUtil.filter(classes, new Condition<T>() {
190                @Override
191                public boolean value(T classDescriptor) {
192                    return classDescriptor.getKind().isObject() == objects;
193                }
194            });
195        }
196    }