001    /*
002     * Copyright 2010-2015 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.kotlin.resolve;
018    
019    import com.google.common.base.Function;
020    import com.google.common.base.Functions;
021    import com.google.common.collect.Maps;
022    import com.intellij.psi.PsiElement;
023    import com.intellij.psi.PsiFile;
024    import kotlin.Function1;
025    import kotlin.KotlinPackage;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.kotlin.descriptors.*;
028    import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor;
029    import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor;
030    import org.jetbrains.kotlin.psi.*;
031    import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
032    import org.jetbrains.kotlin.resolve.scopes.JetScope;
033    import org.jetbrains.kotlin.resolve.scopes.WritableScope;
034    import org.jetbrains.kotlin.storage.ExceptionTracker;
035    import org.jetbrains.kotlin.storage.StorageManager;
036    
037    import java.io.PrintStream;
038    import java.util.*;
039    
040    public class TopDownAnalysisContext implements BodiesResolveContext {
041    
042        private final DataFlowInfo outerDataFlowInfo;
043    
044        private final Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> classes = Maps.newLinkedHashMap();
045        private final Map<JetClassInitializer, ClassDescriptorWithResolutionScopes> anonymousInitializers = Maps.newLinkedHashMap();
046        protected final Map<JetFile, MutablePackageFragmentDescriptor> packageFragments = Maps.newHashMap();
047        protected final Set<JetFile> files = new LinkedHashSet<JetFile>();
048        private List<MutableClassDescriptor> classesTopologicalOrder = null;
049    
050        private final Map<JetDeclaration, JetScope> declaringScopes = Maps.newHashMap();
051        private final Map<JetNamedFunction, SimpleFunctionDescriptor> functions = Maps.newLinkedHashMap();
052        private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap();
053        private final Map<JetParameter, PropertyDescriptor> primaryConstructorParameterProperties = Maps.newHashMap();
054        private Map<JetCallableDeclaration, CallableMemberDescriptor> members = null;
055    
056        // File scopes - package scope extended with imports
057        protected final Map<JetFile, WritableScope> fileScopes = Maps.newHashMap();
058    
059        public final Map<JetDeclarationContainer, DeclarationDescriptor> forDeferredResolver = Maps.newHashMap();
060    
061        public final Map<JetDeclarationContainer, JetScope> normalScope = Maps.newHashMap();
062    
063        private final Map<JetScript, ScriptDescriptor> scripts = Maps.newLinkedHashMap();
064    
065        private final TopDownAnalysisParameters topDownAnalysisParameters;
066    
067        private StringBuilder debugOutput;
068    
069        public TopDownAnalysisContext(@NotNull TopDownAnalysisParameters topDownAnalysisParameters, @NotNull DataFlowInfo outerDataFlowInfo) {
070            this.topDownAnalysisParameters = topDownAnalysisParameters;
071            this.outerDataFlowInfo = outerDataFlowInfo;
072        }
073    
074        @Override
075        @NotNull
076        public TopDownAnalysisParameters getTopDownAnalysisParameters() {
077            return topDownAnalysisParameters;
078        }
079    
080        public void debug(Object message) {
081            if (debugOutput != null) {
082                debugOutput.append(message).append("\n");
083            }
084        }
085    
086        @SuppressWarnings("UnusedDeclaration")
087        /*package*/ void enableDebugOutput() {
088            if (debugOutput == null) {
089                debugOutput = new StringBuilder();
090            }
091        }
092        
093        /*package*/ void printDebugOutput(PrintStream out) {
094            if (debugOutput != null) {
095                out.print(debugOutput);
096            }
097        }
098    
099        @Override
100        public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
101            PsiFile containingFile = element.getContainingFile();
102            boolean result = containingFile != null && topDownAnalysisParameters.getAnalyzeCompletely().apply(containingFile);
103            if (!result) {
104                debug(containingFile);
105            }
106            return result;
107        }
108    
109        @Override
110        public Map<JetClassOrObject, ClassDescriptorWithResolutionScopes> getDeclaredClasses() {
111            return classes;
112        }
113    
114        @Override
115        public Map<JetClassInitializer, ClassDescriptorWithResolutionScopes> getAnonymousInitializers() {
116            return anonymousInitializers;
117        }
118    
119        public Map<JetFile, WritableScope> getFileScopes() {
120            return fileScopes;
121        }
122    
123        public Map<JetFile, MutablePackageFragmentDescriptor> getPackageFragments() {
124            return packageFragments;
125        }
126    
127        @NotNull
128        @Override
129        public StorageManager getStorageManager() {
130            return topDownAnalysisParameters.getStorageManager();
131        }
132    
133        @NotNull
134        @Override
135        public ExceptionTracker getExceptionTracker() {
136            return topDownAnalysisParameters.getExceptionTracker();
137        }
138    
139        @Override
140        public Collection<JetFile> getFiles() {
141            return files;
142        }
143    
144        public void addFile(@NotNull JetFile file) {
145            files.add(file);
146        }
147    
148        @Override
149        @NotNull
150        public Map<JetScript, ScriptDescriptor> getScripts() {
151            return scripts;
152        }
153    
154        public Map<JetParameter, PropertyDescriptor> getPrimaryConstructorParameterProperties() {
155            return primaryConstructorParameterProperties;
156        }
157    
158        @Override
159        public Map<JetProperty, PropertyDescriptor> getProperties() {
160            return properties;
161        }
162    
163        @Override
164        public Function<JetDeclaration, JetScope> getDeclaringScopes() {
165            return Functions.forMap(declaringScopes);
166        }
167    
168        public void registerDeclaringScope(@NotNull JetDeclaration declaration, @NotNull JetScope scope) {
169            declaringScopes.put(declaration, scope);
170        }
171    
172        @Override
173        public Map<JetNamedFunction, SimpleFunctionDescriptor> getFunctions() {
174            return functions;
175        }
176    
177        @NotNull
178        public Map<JetCallableDeclaration, CallableMemberDescriptor> getMembers() {
179            if (members == null) {
180                members = Maps.newLinkedHashMap();
181                members.putAll(functions);
182                members.putAll(properties);
183                members.putAll(primaryConstructorParameterProperties);
184            }
185            return members;
186        }
187    
188        @NotNull
189        public List<MutableClassDescriptor> getClassesTopologicalOrder() {
190            return classesTopologicalOrder;
191        }
192    
193        public void setClassesTopologicalOrder(@NotNull List<MutableClassDescriptor> classesTopologicalOrder) {
194            this.classesTopologicalOrder = classesTopologicalOrder;
195        }
196    
197        @Override
198        @NotNull
199        public DataFlowInfo getOuterDataFlowInfo() {
200            return outerDataFlowInfo;
201        }
202    
203        @NotNull
204        public Collection<ClassDescriptorWithResolutionScopes> getAllClasses() {
205            // SCRIPT: all classes are declared classes + script classes
206            Collection<ClassDescriptorWithResolutionScopes> scriptClasses = KotlinPackage.map(
207                    getScripts().values(),
208                    new Function1<ScriptDescriptor, ClassDescriptorWithResolutionScopes>() {
209                        @Override
210                        public ClassDescriptorWithResolutionScopes invoke(ScriptDescriptor scriptDescriptor) {
211                            return (ClassDescriptorWithResolutionScopes) scriptDescriptor.getClassDescriptor();
212                        }
213                    }
214            );
215            return KotlinPackage.plus(getDeclaredClasses().values(), scriptClasses);
216        }
217    }