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.Predicates;
020 import com.google.common.collect.Sets;
021 import com.intellij.openapi.project.Project;
022 import com.intellij.psi.PsiElement;
023 import kotlin.Function1;
024 import kotlin.KotlinPackage;
025 import org.jetbrains.annotations.NotNull;
026 import org.jetbrains.annotations.Nullable;
027 import org.jetbrains.jet.context.GlobalContext;
028 import org.jetbrains.jet.context.GlobalContextImpl;
029 import org.jetbrains.jet.di.InjectorForLazyResolve;
030 import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
031 import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
032 import org.jetbrains.jet.lang.descriptors.*;
033 import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
034 import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
035 import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder;
036 import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilderDummy;
037 import org.jetbrains.jet.lang.psi.JetClassOrObject;
038 import org.jetbrains.jet.lang.psi.JetFile;
039 import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
040 import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
041 import org.jetbrains.jet.lang.resolve.name.FqName;
042 import org.jetbrains.jet.lang.resolve.name.Name;
043 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
044 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
045 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
046 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
047 import org.jetbrains.jet.storage.LockBasedStorageManager;
048
049 import javax.inject.Inject;
050 import java.util.Collection;
051 import java.util.Collections;
052 import java.util.LinkedHashSet;
053 import java.util.Set;
054
055 public class TopDownAnalyzer {
056
057 @NotNull
058 private BindingTrace trace;
059 @NotNull
060 private DeclarationResolver declarationResolver;
061 @NotNull
062 private TypeHierarchyResolver typeHierarchyResolver;
063 @NotNull
064 private OverrideResolver overrideResolver;
065 @NotNull
066 private OverloadResolver overloadResolver;
067 @NotNull
068 private ModuleDescriptor moduleDescriptor;
069 @NotNull
070 private MutablePackageFragmentProvider packageFragmentProvider;
071 @NotNull
072 private BodyResolver bodyResolver;
073 @NotNull
074 private Project project;
075
076 @NotNull
077 private LazyTopDownAnalyzer lazyTopDownAnalyzer;
078
079 @Inject
080 public void setTrace(@NotNull BindingTrace trace) {
081 this.trace = trace;
082 }
083
084 @Inject
085 public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
086 this.declarationResolver = declarationResolver;
087 }
088
089 @Inject
090 public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
091 this.typeHierarchyResolver = typeHierarchyResolver;
092 }
093
094 @Inject
095 public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
096 this.overrideResolver = overrideResolver;
097 }
098
099 @Inject
100 public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
101 this.overloadResolver = overloadResolver;
102 }
103
104 @Inject
105 public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
106 this.moduleDescriptor = moduleDescriptor;
107 }
108
109 @Inject
110 public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
111 this.packageFragmentProvider = packageFragmentProvider;
112 }
113
114 @Inject
115 public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
116 this.bodyResolver = bodyResolver;
117 }
118
119 @Inject
120 public void setProject(@NotNull Project project) {
121 this.project = project;
122 }
123
124 @Inject
125 public void setLazyTopDownAnalyzer(@NotNull LazyTopDownAnalyzer lazyTopDownAnalyzer) {
126 this.lazyTopDownAnalyzer = lazyTopDownAnalyzer;
127 }
128
129 public void doProcess(
130 @NotNull TopDownAnalysisContext c,
131 @NotNull JetScope outerScope,
132 @NotNull PackageLikeBuilder owner,
133 @NotNull Collection<? extends PsiElement> declarations
134 ) {
135 // c.enableDebugOutput();
136 c.debug("Enter");
137
138 if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
139 ResolveSession resolveSession = new InjectorForLazyResolve(
140 project,
141 new GlobalContextImpl((LockBasedStorageManager) c.getStorageManager(), c.getExceptionTracker()), // TODO
142 (ModuleDescriptorImpl) moduleDescriptor, // TODO
143 new FileBasedDeclarationProviderFactory(c.getStorageManager(), getFiles(declarations)),
144 trace
145 ).getResolveSession();
146
147 lazyTopDownAnalyzer.analyzeDeclarations(
148 resolveSession,
149 c.getTopDownAnalysisParameters(),
150 declarations
151 );
152 return;
153 }
154
155 typeHierarchyResolver.process(c, outerScope, owner, declarations);
156 declarationResolver.process(c);
157 overrideResolver.process(c);
158 lockScopes(c);
159
160 overloadResolver.process(c);
161
162 if (!c.getTopDownAnalysisParameters().isAnalyzingBootstrapLibrary()) {
163 bodyResolver.resolveBodies(c);
164 }
165
166 c.debug("Exit");
167 c.printDebugOutput(System.out);
168 }
169
170 private static Collection<JetFile> getFiles(Collection<? extends PsiElement> declarations) {
171 return new LinkedHashSet<JetFile>(KotlinPackage.map(declarations, new Function1<PsiElement, JetFile>() {
172 @Nullable
173 @Override
174 public JetFile invoke(PsiElement element) {
175 return (JetFile) element.getContainingFile();
176 }
177 }));
178 }
179
180 private void lockScopes(@NotNull TopDownAnalysisContext c) {
181 for (ClassDescriptorWithResolutionScopes mutableClassDescriptor : c.getDeclaredClasses().values()) {
182 ((MutableClassDescriptor) mutableClassDescriptor).lockScopes();
183 }
184
185 // SCRIPT: extra code for scripts
186 Set<FqName> scriptFqNames = Sets.newHashSet();
187 for (JetFile file : c.getFileScopes().keySet()) {
188 if (file.isScript()) {
189 scriptFqNames.add(file.getPackageFqName());
190 }
191 }
192 for (MutablePackageFragmentDescriptor fragment : packageFragmentProvider.getAllFragments()) {
193 // todo: this is hack in favor of REPL
194 if (!scriptFqNames.contains(fragment.getFqName())) {
195 fragment.getMemberScope().changeLockLevel(WritableScope.LockLevel.READING);
196 }
197 }
198 }
199
200 public static void processClassOrObject(
201 @NotNull GlobalContext globalContext,
202 @Nullable final WritableScope scope,
203 @NotNull ExpressionTypingContext context,
204 @NotNull final DeclarationDescriptor containingDeclaration,
205 @NotNull JetClassOrObject object
206 ) {
207 ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(Name.special("<dummy for object>"),
208 Collections.<ImportPath>emptyList(),
209 PlatformToKotlinClassMap.EMPTY);
210
211 TopDownAnalysisParameters topDownAnalysisParameters =
212 TopDownAnalysisParameters.createForLocalDeclarations(
213 globalContext.getStorageManager(),
214 globalContext.getExceptionTracker(),
215 Predicates.equalTo(object.getContainingFile())
216 );
217
218 InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
219 object.getProject(), topDownAnalysisParameters, context.trace, moduleDescriptor
220 );
221
222 TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
223 c.setOuterDataFlowInfo(context.dataFlowInfo);
224
225 injector.getTopDownAnalyzer().doProcess(
226 c,
227 context.scope,
228 new PackageLikeBuilder() {
229
230 @NotNull
231 @Override
232 public DeclarationDescriptor getOwnerForChildren() {
233 return containingDeclaration;
234 }
235
236 @Override
237 public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) {
238 if (scope != null) {
239 scope.addClassifierDescriptor(classDescriptor);
240 }
241 }
242
243 @Override
244 public void addFunctionDescriptor(@NotNull SimpleFunctionDescriptor functionDescriptor) {
245 throw new UnsupportedOperationException();
246 }
247
248 @Override
249 public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) {
250
251 }
252
253 @Override
254 public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
255 return ClassObjectStatus.NOT_ALLOWED;
256 }
257 },
258 Collections.<PsiElement>singletonList(object)
259 );
260 }
261
262 @NotNull
263 public TopDownAnalysisContext analyzeFiles(
264 @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
265 @NotNull Collection<JetFile> files
266 ) {
267 ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.SOURCES, packageFragmentProvider);
268
269 // "depend on" builtins module
270 ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
271
272 // dummy builder is used because "root" is module descriptor,
273 // packages added to module explicitly in
274
275 TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
276 doProcess(c, JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor), new PackageLikeBuilderDummy(), files);
277 return c;
278 }
279
280
281 @NotNull
282 public MutablePackageFragmentProvider getPackageFragmentProvider() {
283 return packageFragmentProvider;
284 }
285
286 }
287
288