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