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