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.descriptors.*;
032 import org.jetbrains.jet.lang.descriptors.impl.*;
033 import org.jetbrains.jet.lang.psi.JetClassOrObject;
034 import org.jetbrains.jet.lang.psi.JetFile;
035 import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
036 import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
037 import org.jetbrains.jet.lang.resolve.name.FqName;
038 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
040 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
041 import org.jetbrains.jet.storage.LockBasedStorageManager;
042
043 import javax.inject.Inject;
044 import java.util.*;
045
046 public class TopDownAnalyzer {
047
048 @NotNull
049 private BindingTrace trace;
050 @NotNull
051 private DeclarationResolver declarationResolver;
052 @NotNull
053 private TypeHierarchyResolver typeHierarchyResolver;
054 @NotNull
055 private OverrideResolver overrideResolver;
056 @NotNull
057 private OverloadResolver overloadResolver;
058 @NotNull
059 private ModuleDescriptor moduleDescriptor;
060 @NotNull
061 private MutablePackageFragmentProvider packageFragmentProvider;
062 @NotNull
063 private BodyResolver bodyResolver;
064 @NotNull
065 private AdditionalCheckerProvider additionalCheckerProvider;
066 @NotNull
067 private Project project;
068
069 @NotNull
070 private LazyTopDownAnalyzer lazyTopDownAnalyzer;
071
072 @Inject
073 public void setTrace(@NotNull BindingTrace trace) {
074 this.trace = trace;
075 }
076
077 @Inject
078 public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
079 this.declarationResolver = declarationResolver;
080 }
081
082 @Inject
083 public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
084 this.typeHierarchyResolver = typeHierarchyResolver;
085 }
086
087 @Inject
088 public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
089 this.overrideResolver = overrideResolver;
090 }
091
092 @Inject
093 public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
094 this.overloadResolver = overloadResolver;
095 }
096
097 @Inject
098 public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
099 this.moduleDescriptor = moduleDescriptor;
100 }
101
102 @Inject
103 public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
104 this.packageFragmentProvider = packageFragmentProvider;
105 }
106
107 @Inject
108 public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
109 this.bodyResolver = bodyResolver;
110 }
111
112 @Inject
113 public void setProject(@NotNull Project project) {
114 this.project = project;
115 }
116
117 @Inject
118 public void setLazyTopDownAnalyzer(@NotNull LazyTopDownAnalyzer lazyTopDownAnalyzer) {
119 this.lazyTopDownAnalyzer = lazyTopDownAnalyzer;
120 }
121
122 @Inject
123 public void setAdditionalCheckerProvider(@NotNull AdditionalCheckerProvider additionalCheckerProvider) {
124 this.additionalCheckerProvider = additionalCheckerProvider;
125 }
126
127 public void doProcess(
128 @NotNull TopDownAnalysisContext c,
129 @NotNull JetScope outerScope,
130 @NotNull PackageLikeBuilder owner,
131 @NotNull Collection<? extends PsiElement> declarations
132 ) {
133 // c.enableDebugOutput();
134 c.debug("Enter");
135
136 if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
137 ResolveSession resolveSession = new InjectorForLazyResolve(
138 project,
139 new GlobalContextImpl((LockBasedStorageManager) c.getStorageManager(), c.getExceptionTracker()), // TODO
140 (ModuleDescriptorImpl) moduleDescriptor, // TODO
141 new FileBasedDeclarationProviderFactory(c.getStorageManager(), getFiles(declarations)),
142 trace,
143 additionalCheckerProvider
144 ).getResolveSession();
145
146 lazyTopDownAnalyzer.analyzeDeclarations(
147 resolveSession,
148 c.getTopDownAnalysisParameters(),
149 declarations
150 );
151 return;
152 }
153
154 typeHierarchyResolver.process(c, outerScope, owner, declarations);
155 declarationResolver.process(c);
156 overrideResolver.process(c);
157 lockScopes(c);
158
159 overloadResolver.process(c);
160
161 if (!c.getTopDownAnalysisParameters().isAnalyzingBootstrapLibrary()) {
162 bodyResolver.resolveBodies(c);
163 }
164
165 c.debug("Exit");
166 c.printDebugOutput(System.out);
167 }
168
169 private static Collection<JetFile> getFiles(Collection<? extends PsiElement> declarations) {
170 return new LinkedHashSet<JetFile>(KotlinPackage.map(declarations, new Function1<PsiElement, JetFile>() {
171 @Nullable
172 @Override
173 public JetFile invoke(PsiElement element) {
174 return (JetFile) element.getContainingFile();
175 }
176 }));
177 }
178
179 private void lockScopes(@NotNull TopDownAnalysisContext c) {
180 for (ClassDescriptorWithResolutionScopes mutableClassDescriptor : c.getDeclaredClasses().values()) {
181 ((MutableClassDescriptor) mutableClassDescriptor).lockScopes();
182 }
183
184 // SCRIPT: extra code for scripts
185 Set<FqName> scriptFqNames = Sets.newHashSet();
186 for (JetFile file : c.getFileScopes().keySet()) {
187 if (file.isScript()) {
188 scriptFqNames.add(file.getPackageFqName());
189 }
190 }
191 for (MutablePackageFragmentDescriptor fragment : packageFragmentProvider.getAllFragments()) {
192 // todo: this is hack in favor of REPL
193 if (!scriptFqNames.contains(fragment.getFqName())) {
194 fragment.getMemberScope().changeLockLevel(WritableScope.LockLevel.READING);
195 }
196 }
197 }
198
199 public static void processClassOrObject(
200 @NotNull GlobalContext globalContext,
201 @Nullable final WritableScope scope,
202 @NotNull ExpressionTypingContext context,
203 @NotNull final DeclarationDescriptor containingDeclaration,
204 @NotNull JetClassOrObject object,
205 @NotNull AdditionalCheckerProvider additionalCheckerProvider
206 ) {
207 TopDownAnalysisParameters topDownAnalysisParameters =
208 TopDownAnalysisParameters.createForLocalDeclarations(
209 globalContext.getStorageManager(),
210 globalContext.getExceptionTracker(),
211 Predicates.equalTo(object.getContainingFile())
212 );
213
214 InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
215 object.getProject(),
216 topDownAnalysisParameters,
217 context.trace,
218 DescriptorUtils.getContainingModule(containingDeclaration),
219 additionalCheckerProvider
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 @NotNull PackageFragmentProvider... additionalProviders
267 ) {
268 return analyzeFiles(topDownAnalysisParameters, files, Arrays.asList(additionalProviders));
269 }
270
271 @NotNull
272 public TopDownAnalysisContext analyzeFiles(
273 @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
274 @NotNull Collection<JetFile> files,
275 @NotNull List<PackageFragmentProvider> additionalProviders
276 ) {
277 CompositePackageFragmentProvider provider =
278 new CompositePackageFragmentProvider(KotlinPackage.plus(Arrays.asList(packageFragmentProvider), additionalProviders));
279 ((ModuleDescriptorImpl) moduleDescriptor).initialize(provider);
280
281 // dummy builder is used because "root" is module descriptor,
282 // packages added to module explicitly in
283 TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
284 doProcess(c, JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor), new PackageLikeBuilderDummy(), files);
285 return c;
286 }
287
288
289 @NotNull
290 public MutablePackageFragmentProvider getPackageFragmentProvider() {
291 return packageFragmentProvider;
292 }
293
294 }
295
296