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.intellij.psi.PsiElement;
020 import com.intellij.psi.PsiNameIdentifierOwner;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
025 import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
026 import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
027 import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder;
028 import org.jetbrains.jet.lang.psi.*;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
031 import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
032 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
033 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
034 import org.jetbrains.jet.lang.resolve.scopes.WriteThroughScope;
035 import org.jetbrains.jet.lang.types.JetType;
036 import org.jetbrains.jet.utils.DFS;
037
038 import javax.inject.Inject;
039 import java.util.*;
040
041 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
042 import static org.jetbrains.jet.lang.resolve.BindingContext.FQNAME_TO_CLASS_DESCRIPTOR;
043 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
044 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry;
045 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isObject;
046 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.getDefaultClassVisibility;
047 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
048 import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
049 import static org.jetbrains.jet.lang.resolve.source.SourcePackage.toSourceElement;
050
051 public class TypeHierarchyResolver {
052 private static final DFS.Neighbors<ClassDescriptor> CLASS_INHERITANCE_EDGES = new DFS.Neighbors<ClassDescriptor>() {
053 @NotNull
054 @Override
055 public Iterable<ClassDescriptor> getNeighbors(ClassDescriptor current) {
056 List<ClassDescriptor> result = new ArrayList<ClassDescriptor>();
057 for (JetType supertype : current.getDefaultType().getConstructor().getSupertypes()) {
058 DeclarationDescriptor descriptor = supertype.getConstructor().getDeclarationDescriptor();
059 if (descriptor instanceof ClassDescriptor) {
060 result.add((ClassDescriptor) descriptor);
061 }
062 }
063 DeclarationDescriptor container = current.getContainingDeclaration();
064 if (container instanceof ClassDescriptor) {
065 result.add((ClassDescriptor) container);
066 }
067 return result;
068 }
069 };
070
071 @NotNull
072 private ImportsResolver importsResolver;
073 @NotNull
074 private DescriptorResolver descriptorResolver;
075 @NotNull
076 private ScriptHeaderResolver scriptHeaderResolver;
077 @NotNull
078 private MutablePackageFragmentProvider packageFragmentProvider;
079 @NotNull
080 private BindingTrace trace;
081
082 @Inject
083 public void setImportsResolver(@NotNull ImportsResolver importsResolver) {
084 this.importsResolver = importsResolver;
085 }
086
087 @Inject
088 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
089 this.descriptorResolver = descriptorResolver;
090 }
091
092 // SCRIPT: inject script header resolver
093 @Inject
094 public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
095 this.scriptHeaderResolver = scriptHeaderResolver;
096 }
097
098 @Inject
099 public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
100 this.packageFragmentProvider = packageFragmentProvider;
101 }
102
103 @Inject
104 public void setTrace(@NotNull BindingTrace trace) {
105 this.trace = trace;
106 }
107
108 public void process(
109 @NotNull TopDownAnalysisContext c,
110 @NotNull JetScope outerScope,
111 @NotNull PackageLikeBuilder owner,
112 @NotNull Collection<? extends PsiElement> declarations
113 ) {
114
115 {
116 // TODO: Very temp code - main goal is to remove recursion from collectPackageFragmentsAndClassifiers
117 Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>();
118 forDeferredResolve.addAll(collectPackageFragmentsAndClassifiers(c, outerScope, owner, declarations));
119
120 while (!forDeferredResolve.isEmpty()) {
121 JetDeclarationContainer declarationContainer = forDeferredResolve.poll();
122 assert declarationContainer != null;
123
124 DeclarationDescriptor descriptorForDeferredResolve = c.forDeferredResolver.get(declarationContainer);
125 JetScope scope = c.normalScope.get(declarationContainer);
126
127 // Even more temp code
128 if (descriptorForDeferredResolve instanceof MutableClassDescriptor) {
129 forDeferredResolve.addAll(
130 collectPackageFragmentsAndClassifiers(
131 c,
132 scope,
133 ((MutableClassDescriptor) descriptorForDeferredResolve).getBuilder(),
134 declarationContainer.getDeclarations()));
135 }
136 else if (descriptorForDeferredResolve instanceof MutablePackageFragmentDescriptor) {
137 forDeferredResolve.addAll(
138 collectPackageFragmentsAndClassifiers(
139 c,
140 scope,
141 ((MutablePackageFragmentDescriptor) descriptorForDeferredResolve).getBuilder(),
142 declarationContainer.getDeclarations()));
143 }
144 else {
145 assert false;
146 }
147 }
148 }
149
150 importsResolver.processTypeImports(c);
151
152 createTypeConstructors(c); // create type constructors for classes and generic parameters, supertypes are not filled in
153 resolveTypesInClassHeaders(c); // Generic bounds and types in supertype lists (no expressions or constructor resolution)
154
155 c.setClassesTopologicalOrder(topologicallySortClassesAndObjects(c));
156
157 // Detect and disconnect all loops in the hierarchy
158 detectAndDisconnectLoops(c);
159 }
160
161 @NotNull
162 private Collection<JetDeclarationContainer> collectPackageFragmentsAndClassifiers(
163 @NotNull TopDownAnalysisContext c,
164 @NotNull JetScope outerScope,
165 @NotNull PackageLikeBuilder owner,
166 @NotNull Iterable<? extends PsiElement> declarations
167 ) {
168 Collection<JetDeclarationContainer> forDeferredResolve = new ArrayList<JetDeclarationContainer>();
169
170 ClassifierCollector collector = new ClassifierCollector(c, outerScope, owner, forDeferredResolve);
171
172 for (PsiElement declaration : declarations) {
173 declaration.accept(collector);
174 }
175
176 return forDeferredResolve;
177 }
178
179
180 @NotNull
181 private static ClassKind getClassKind(@NotNull JetClass jetClass) {
182 if (jetClass.isTrait()) return ClassKind.TRAIT;
183 if (jetClass.isAnnotation()) return ClassKind.ANNOTATION_CLASS;
184 if (jetClass.isEnum()) return ClassKind.ENUM_CLASS;
185 return ClassKind.CLASS;
186 }
187
188 private void createTypeConstructors(@NotNull TopDownAnalysisContext c) {
189 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
190 JetClassOrObject classOrObject = entry.getKey();
191 MutableClassDescriptor descriptor = (MutableClassDescriptor) entry.getValue();
192 if (classOrObject instanceof JetClass) {
193 descriptorResolver.resolveMutableClassDescriptor(
194 c.getTopDownAnalysisParameters(),
195 (JetClass) classOrObject, descriptor, trace);
196 }
197 else if (classOrObject instanceof JetObjectDeclaration) {
198 descriptor.setModality(Modality.FINAL);
199 descriptor.setVisibility(resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor)));
200 descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
201 }
202
203 descriptor.createTypeConstructor();
204
205 ClassKind kind = descriptor.getKind();
206 if (kind == ClassKind.ENUM_ENTRY || kind == ClassKind.OBJECT) {
207 MutableClassDescriptor classObject = descriptor.getClassObjectDescriptor();
208 assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText();
209
210 // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a synthetic class object.
211 // We make this class object inherit from the singleton here, thus allowing to use the singleton's class object where
212 // the instance of the singleton is applicable. Effectively all members of the singleton would be present in its class
213 // object as fake overrides, so you can access them via standard class object notation: ObjectName.memberName()
214 classObject.setSupertypes(Collections.singleton(descriptor.getDefaultType()));
215
216 classObject.createTypeConstructor();
217 }
218 }
219 }
220
221 private void resolveTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
222 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
223 JetClassOrObject classOrObject = entry.getKey();
224 if (classOrObject instanceof JetClass) {
225 ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
226 //noinspection unchecked
227 descriptorResolver.resolveGenericBounds((JetClass) classOrObject, descriptor, descriptor.getScopeForClassHeaderResolution(),
228 (List) descriptor.getTypeConstructor().getParameters(), trace);
229 }
230 }
231
232 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
233 descriptorResolver.resolveSupertypesForMutableClassDescriptor(entry.getKey(), (MutableClassDescriptor) entry.getValue(), trace);
234 }
235 }
236
237 @NotNull
238 @SuppressWarnings("unchecked")
239 private static List<MutableClassDescriptor> topologicallySortClassesAndObjects(@NotNull TopDownAnalysisContext c) {
240 Collection<ClassDescriptor> sourceClasses = (Collection) c.getAllClasses();
241 List<ClassDescriptor> allClassesOrdered = DFS.topologicalOrder(sourceClasses, CLASS_INHERITANCE_EDGES);
242 allClassesOrdered.retainAll(sourceClasses);
243 return (List) allClassesOrdered;
244 }
245
246 private void detectAndDisconnectLoops(@NotNull TopDownAnalysisContext c) {
247 List<Runnable> tasks = new ArrayList<Runnable>();
248 for (final MutableClassDescriptor klass : c.getClassesTopologicalOrder()) {
249 for (final JetType supertype : klass.getSupertypes()) {
250 ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
251 if (supertypeDescriptor instanceof ClassDescriptor) {
252 ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
253 if (isReachable(superclass, klass, new HashSet<ClassDescriptor>())) {
254 tasks.add(new Runnable() {
255 @Override
256 public void run() {
257 klass.getSupertypes().remove(supertype);
258 }
259 });
260 reportCyclicInheritanceHierarchyError(trace, klass, superclass);
261 }
262 }
263 }
264 }
265
266 for (Runnable task : tasks) {
267 task.run();
268 }
269 }
270
271 // TODO: use DFS and copy to LazyClassTypeConstructor.isReachable
272 private static boolean isReachable(
273 @NotNull ClassDescriptor from,
274 @NotNull MutableClassDescriptor to,
275 @NotNull Set<ClassDescriptor> visited
276 ) {
277 if (!visited.add(from)) return false;
278 for (ClassDescriptor superclass : CLASS_INHERITANCE_EDGES.getNeighbors(from)) {
279 if (superclass == to || isReachable(superclass, to, visited)) return true;
280 }
281 return false;
282 }
283
284 public static void reportCyclicInheritanceHierarchyError(
285 @NotNull BindingTrace trace,
286 @NotNull ClassDescriptor classDescriptor,
287 @NotNull ClassDescriptor superclass
288 ) {
289 PsiElement psiElement = DescriptorToSourceUtils.classDescriptorToDeclaration(classDescriptor);
290
291 PsiElement elementToMark = null;
292 if (psiElement instanceof JetClassOrObject) {
293 JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
294 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
295 JetTypeReference typeReference = delegationSpecifier.getTypeReference();
296 if (typeReference == null) continue;
297 JetType supertype = trace.get(TYPE, typeReference);
298 if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
299 elementToMark = typeReference;
300 }
301 }
302 }
303 if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
304 PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
305 PsiElement nameIdentifier = namedElement.getNameIdentifier();
306 if (nameIdentifier != null) {
307 elementToMark = nameIdentifier;
308 }
309 }
310 if (elementToMark != null) {
311 trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
312 }
313 }
314
315 private class ClassifierCollector extends JetVisitorVoid {
316 private final TopDownAnalysisContext c;
317 private final JetScope outerScope;
318 private final PackageLikeBuilder owner;
319 private final Collection<JetDeclarationContainer> forDeferredResolve;
320
321 public ClassifierCollector(
322 @NotNull TopDownAnalysisContext c,
323 @NotNull JetScope outerScope,
324 @NotNull PackageLikeBuilder owner,
325 @NotNull Collection<JetDeclarationContainer> forDeferredResolve
326 ) {
327 this.c = c;
328 this.outerScope = outerScope;
329 this.owner = owner;
330 this.forDeferredResolve = forDeferredResolve;
331 }
332
333 @Override
334 public void visitJetFile(@NotNull JetFile file) {
335 MutablePackageFragmentDescriptor packageFragment = getOrCreatePackageFragmentForFile(file);
336 c.getPackageFragments().put(file, packageFragment);
337 c.addFile(file);
338
339 PackageViewDescriptor packageView = packageFragment.getContainingDeclaration().getPackage(packageFragment.getFqName());
340 ChainedScope rootPlusPackageScope = new ChainedScope(packageView, "Root scope for " + file, packageView.getMemberScope(), outerScope);
341 WriteThroughScope packageScope = new WriteThroughScope(rootPlusPackageScope, packageFragment.getMemberScope(),
342 new TraceBasedRedeclarationHandler(trace), "package in file " + file.getName());
343 packageScope.changeLockLevel(WritableScope.LockLevel.BOTH);
344 c.getFileScopes().put(file, packageScope);
345
346 if (file.isScript()) {
347 // SCRIPT: process script hierarchy
348 scriptHeaderResolver.processScriptHierarchy(c, file.getScript(), packageScope);
349 }
350
351 prepareForDeferredCall(packageScope, packageFragment, file);
352 }
353
354 @Override
355 public void visitClass(@NotNull JetClass klass) {
356 MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
357
358 owner.addClassifierDescriptor(mutableClassDescriptor);
359 }
360
361 @Override
362 public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
363 if (declaration.isObjectLiteral()) {
364 createClassDescriptorForSingleton(declaration, SpecialNames.NO_NAME_PROVIDED, ClassKind.CLASS);
365 return;
366 }
367
368 MutableClassDescriptor descriptor =
369 createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.OBJECT);
370
371 owner.addClassifierDescriptor(descriptor);
372 trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetNamedDeclarationUtil.getUnsafeFQName(declaration), descriptor);
373
374 descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObjectForSingleton(descriptor));
375 }
376
377 @Override
378 public void visitEnumEntry(@NotNull JetEnumEntry declaration) {
379 MutableClassDescriptor descriptor =
380 createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.ENUM_ENTRY);
381
382 owner.addClassifierDescriptor(descriptor);
383
384 descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObjectForSingleton(descriptor));
385 }
386
387 @Override
388 public void visitTypedef(@NotNull JetTypedef typedef) {
389 trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
390 }
391
392 @Override
393 public void visitClassObject(@NotNull JetClassObject classObject) {
394 JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
395
396 DeclarationDescriptor container = owner.getOwnerForChildren();
397
398 MutableClassDescriptor classObjectDescriptor =
399 createClassDescriptorForSingleton(objectDeclaration, getClassObjectName(container.getName()), ClassKind.CLASS_OBJECT);
400
401 PackageLikeBuilder.ClassObjectStatus status =
402 isEnumEntry(container) || isObject(container) || c.getTopDownAnalysisParameters().isDeclaredLocally() ?
403 PackageLikeBuilder.ClassObjectStatus.NOT_ALLOWED :
404 owner.setClassObjectDescriptor(classObjectDescriptor);
405
406 switch (status) {
407 case DUPLICATE:
408 trace.report(MANY_CLASS_OBJECTS.on(classObject));
409 break;
410 case NOT_ALLOWED:
411 trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
412 break;
413 case OK:
414 // Everything is OK so no errors to trace.
415 break;
416 }
417 }
418
419 @NotNull
420 private MutablePackageFragmentDescriptor getOrCreatePackageFragmentForFile(@NotNull JetFile file) {
421 JetPackageDirective packageDirective = file.getPackageDirective();
422 assert packageDirective != null : "scripts are not supported";
423
424 MutablePackageFragmentDescriptor fragment = packageFragmentProvider.getOrCreateFragment(packageDirective.getFqName());
425
426 ModuleDescriptor module = packageFragmentProvider.getModule();
427 DescriptorResolver.resolvePackageHeader(packageDirective, module, trace);
428 DescriptorResolver.registerFileInPackage(trace, file);
429 trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file, fragment);
430
431 return fragment;
432 }
433
434
435 @NotNull
436 private MutableClassDescriptor createSyntheticClassObjectForSingleton(@NotNull ClassDescriptor classDescriptor) {
437 MutableClassDescriptor classObject =
438 new MutableClassDescriptor(classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false,
439 getClassObjectName(classDescriptor.getName()), SourceElement.NO_SOURCE);
440
441 classObject.setModality(Modality.FINAL);
442 classObject.setVisibility(DescriptorUtils.getSyntheticClassObjectVisibility());
443 classObject.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
444 createPrimaryConstructorForObject(null, classObject);
445 return classObject;
446 }
447
448 @NotNull
449 private MutableClassDescriptor createClassDescriptorForClass(
450 @NotNull JetClass klass,
451 @NotNull DeclarationDescriptor containingDeclaration
452 ) {
453 MutableClassDescriptor descriptor = new MutableClassDescriptor(
454 containingDeclaration, outerScope, getClassKind(klass), klass.isInner(), JetPsiUtil.safeName(klass.getName()),
455 toSourceElement(klass)
456 );
457 c.getDeclaredClasses().put(klass, descriptor);
458 trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetNamedDeclarationUtil.getUnsafeFQName(klass), descriptor);
459
460 prepareForDeferredCall(descriptor.getScopeForMemberDeclarationResolution(), descriptor, klass);
461
462 return descriptor;
463 }
464
465 @NotNull
466 private MutableClassDescriptor createClassDescriptorForSingleton(
467 @NotNull JetClassOrObject declaration,
468 @NotNull Name name,
469 @NotNull ClassKind kind
470 ) {
471 MutableClassDescriptor descriptor = new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name,
472 toSourceElement(declaration));
473
474 prepareForDeferredCall(descriptor.getScopeForMemberDeclarationResolution(), descriptor, declaration);
475
476 createPrimaryConstructorForObject(declaration, descriptor);
477 trace.record(BindingContext.CLASS, declaration, descriptor);
478
479 c.getDeclaredClasses().put(declaration, descriptor);
480
481 return descriptor;
482 }
483
484 @NotNull
485 private ConstructorDescriptorImpl createPrimaryConstructorForObject(
486 @Nullable JetClassOrObject object,
487 @NotNull MutableClassDescriptor mutableClassDescriptor
488 ) {
489 ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
490 .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
491 mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
492 return constructorDescriptor;
493 }
494
495 private void prepareForDeferredCall(
496 @NotNull JetScope outerScope,
497 @NotNull DeclarationDescriptor descriptorForDeferredResolve,
498 @NotNull JetDeclarationContainer container
499 ) {
500 forDeferredResolve.add(container);
501 c.normalScope.put(container, outerScope);
502 c.forDeferredResolver.put(container, descriptorForDeferredResolve);
503 }
504 }
505 }