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