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.lang.types.lang.KotlinBuiltIns;
037 import org.jetbrains.jet.utils.DFS;
038
039 import javax.inject.Inject;
040 import java.util.*;
041
042 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
043 import static org.jetbrains.jet.lang.resolve.BindingContext.FQNAME_TO_CLASS_DESCRIPTOR;
044 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
045 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry;
046 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isObject;
047 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.getDefaultClassVisibility;
048 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
049 import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
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 || kind == ClassKind.ENUM_CLASS) {
207 MutableClassDescriptor classObject = descriptor.getClassObjectDescriptor();
208 assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText();
209
210 JetType supertype;
211 if (kind == ClassKind.ENUM_CLASS) {
212 supertype = KotlinBuiltIns.getInstance().getAnyType();
213 }
214 else {
215 // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a synthetic class object.
216 // We make this class object inherit from the singleton here, thus allowing to use the singleton's class object where
217 // the instance of the singleton is applicable. Effectively all members of the singleton would be present in its class
218 // object as fake overrides, so you can access them via standard class object notation: ObjectName.memberName()
219 supertype = descriptor.getDefaultType();
220 }
221 classObject.setSupertypes(Collections.singleton(supertype));
222 classObject.createTypeConstructor();
223 }
224 }
225 }
226
227 private void resolveTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
228 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
229 JetClassOrObject classOrObject = entry.getKey();
230 if (classOrObject instanceof JetClass) {
231 ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
232 //noinspection unchecked
233 descriptorResolver.resolveGenericBounds((JetClass) classOrObject, descriptor, descriptor.getScopeForClassHeaderResolution(),
234 (List) descriptor.getTypeConstructor().getParameters(), trace);
235 }
236 }
237
238 for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
239 descriptorResolver.resolveSupertypesForMutableClassDescriptor(entry.getKey(), (MutableClassDescriptor) entry.getValue(), trace);
240 }
241 }
242
243 @NotNull
244 @SuppressWarnings("unchecked")
245 private static List<MutableClassDescriptor> topologicallySortClassesAndObjects(@NotNull TopDownAnalysisContext c) {
246 Collection<ClassDescriptor> sourceClasses = (Collection) c.getAllClasses();
247 List<ClassDescriptor> allClassesOrdered = DFS.topologicalOrder(sourceClasses, CLASS_INHERITANCE_EDGES);
248 allClassesOrdered.retainAll(sourceClasses);
249 return (List) allClassesOrdered;
250 }
251
252 private void detectAndDisconnectLoops(@NotNull TopDownAnalysisContext c) {
253 List<Runnable> tasks = new ArrayList<Runnable>();
254 for (final MutableClassDescriptor klass : c.getClassesTopologicalOrder()) {
255 for (final JetType supertype : klass.getSupertypes()) {
256 ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
257 if (supertypeDescriptor instanceof ClassDescriptor) {
258 ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
259 if (isReachable(superclass, klass, new HashSet<ClassDescriptor>())) {
260 tasks.add(new Runnable() {
261 @Override
262 public void run() {
263 klass.getSupertypes().remove(supertype);
264 }
265 });
266 reportCyclicInheritanceHierarchyError(trace, klass, superclass);
267 }
268 }
269 }
270 }
271
272 for (Runnable task : tasks) {
273 task.run();
274 }
275 }
276
277 // TODO: use DFS and copy to LazyClassTypeConstructor.isReachable
278 private static boolean isReachable(
279 @NotNull ClassDescriptor from,
280 @NotNull MutableClassDescriptor to,
281 @NotNull Set<ClassDescriptor> visited
282 ) {
283 if (!visited.add(from)) return false;
284 for (ClassDescriptor superclass : CLASS_INHERITANCE_EDGES.getNeighbors(from)) {
285 if (superclass == to || isReachable(superclass, to, visited)) return true;
286 }
287 return false;
288 }
289
290 public static void reportCyclicInheritanceHierarchyError(
291 @NotNull BindingTrace trace,
292 @NotNull ClassDescriptor classDescriptor,
293 @NotNull ClassDescriptor superclass
294 ) {
295 PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
296
297 PsiElement elementToMark = null;
298 if (psiElement instanceof JetClassOrObject) {
299 JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
300 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
301 JetTypeReference typeReference = delegationSpecifier.getTypeReference();
302 if (typeReference == null) continue;
303 JetType supertype = trace.get(TYPE, typeReference);
304 if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
305 elementToMark = typeReference;
306 }
307 }
308 }
309 if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
310 PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
311 PsiElement nameIdentifier = namedElement.getNameIdentifier();
312 if (nameIdentifier != null) {
313 elementToMark = nameIdentifier;
314 }
315 }
316 if (elementToMark != null) {
317 trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
318 }
319 }
320
321 private class ClassifierCollector extends JetVisitorVoid {
322 private final TopDownAnalysisContext c;
323 private final JetScope outerScope;
324 private final PackageLikeBuilder owner;
325 private final Collection<JetDeclarationContainer> forDeferredResolve;
326
327 public ClassifierCollector(
328 @NotNull TopDownAnalysisContext c,
329 @NotNull JetScope outerScope,
330 @NotNull PackageLikeBuilder owner,
331 @NotNull Collection<JetDeclarationContainer> forDeferredResolve
332 ) {
333 this.c = c;
334 this.outerScope = outerScope;
335 this.owner = owner;
336 this.forDeferredResolve = forDeferredResolve;
337 }
338
339 @Override
340 public void visitJetFile(@NotNull JetFile file) {
341 MutablePackageFragmentDescriptor packageFragment = getOrCreatePackageFragmentForFile(file);
342 c.getPackageFragments().put(file, packageFragment);
343 c.addFile(file);
344
345 PackageViewDescriptor packageView = packageFragment.getContainingDeclaration().getPackage(packageFragment.getFqName());
346 ChainedScope rootPlusPackageScope = new ChainedScope(packageView, "Root scope for " + file, packageView.getMemberScope(), outerScope);
347 WriteThroughScope packageScope = new WriteThroughScope(rootPlusPackageScope, packageFragment.getMemberScope(),
348 new TraceBasedRedeclarationHandler(trace), "package in file " + file.getName());
349 packageScope.changeLockLevel(WritableScope.LockLevel.BOTH);
350 c.getFileScopes().put(file, packageScope);
351
352 if (file.isScript()) {
353 // SCRIPT: process script hierarchy
354 scriptHeaderResolver.processScriptHierarchy(c, file.getScript(), packageScope);
355 }
356
357 prepareForDeferredCall(packageScope, packageFragment, file);
358 }
359
360 @Override
361 public void visitClass(@NotNull JetClass klass) {
362 MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
363
364 owner.addClassifierDescriptor(mutableClassDescriptor);
365 }
366
367 @Override
368 public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
369 if (declaration.isObjectLiteral()) {
370 createClassDescriptorForSingleton(declaration, SpecialNames.NO_NAME_PROVIDED, ClassKind.CLASS);
371 return;
372 }
373
374 MutableClassDescriptor descriptor =
375 createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.OBJECT);
376
377 owner.addClassifierDescriptor(descriptor);
378 trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetNamedDeclarationUtil.getUnsafeFQName(declaration), descriptor);
379
380 descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObject(descriptor));
381 }
382
383 @Override
384 public void visitEnumEntry(@NotNull JetEnumEntry declaration) {
385 MutableClassDescriptor descriptor =
386 createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.ENUM_ENTRY);
387
388 owner.addClassifierDescriptor(descriptor);
389
390 descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObject(descriptor));
391 }
392
393 @Override
394 public void visitTypedef(@NotNull JetTypedef typedef) {
395 trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
396 }
397
398 @Override
399 public void visitClassObject(@NotNull JetClassObject classObject) {
400 JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
401
402 DeclarationDescriptor container = owner.getOwnerForChildren();
403
404 MutableClassDescriptor classObjectDescriptor =
405 createClassDescriptorForSingleton(objectDeclaration, getClassObjectName(container.getName()), ClassKind.CLASS_OBJECT);
406
407 PackageLikeBuilder.ClassObjectStatus status =
408 isEnumEntry(container) || isObject(container) || c.getTopDownAnalysisParameters().isDeclaredLocally() ?
409 PackageLikeBuilder.ClassObjectStatus.NOT_ALLOWED :
410 owner.setClassObjectDescriptor(classObjectDescriptor);
411
412 switch (status) {
413 case DUPLICATE:
414 trace.report(MANY_CLASS_OBJECTS.on(classObject));
415 break;
416 case NOT_ALLOWED:
417 trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
418 break;
419 case OK:
420 // Everything is OK so no errors to trace.
421 break;
422 }
423 }
424
425 @NotNull
426 private MutablePackageFragmentDescriptor getOrCreatePackageFragmentForFile(@NotNull JetFile file) {
427 JetPackageDirective packageDirective = file.getPackageDirective();
428 assert packageDirective != null : "scripts are not supported";
429
430 MutablePackageFragmentDescriptor fragment = packageFragmentProvider.getOrCreateFragment(packageDirective.getFqName());
431
432 ModuleDescriptor module = packageFragmentProvider.getModule();
433 DescriptorResolver.resolvePackageHeader(packageDirective, module, trace);
434 DescriptorResolver.registerFileInPackage(trace, file);
435 trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file, fragment);
436
437 return fragment;
438 }
439
440
441 private void createClassObjectForEnumClass(@NotNull MutableClassDescriptor mutableClassDescriptor) {
442 if (mutableClassDescriptor.getKind() == ClassKind.ENUM_CLASS) {
443 MutableClassDescriptor classObject = createSyntheticClassObject(mutableClassDescriptor);
444 mutableClassDescriptor.getBuilder().setClassObjectDescriptor(classObject);
445 classObject.getBuilder().addFunctionDescriptor(DescriptorResolver.createEnumClassObjectValuesMethod(classObject, trace));
446 classObject.getBuilder().addFunctionDescriptor(DescriptorResolver.createEnumClassObjectValueOfMethod(classObject, trace));
447 }
448 }
449
450 @NotNull
451 private MutableClassDescriptor createSyntheticClassObject(@NotNull ClassDescriptor classDescriptor) {
452 MutableClassDescriptor classObject = new MutableClassDescriptor(classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false,
453 getClassObjectName(classDescriptor.getName()));
454
455 classObject.setModality(Modality.FINAL);
456 classObject.setVisibility(DescriptorUtils.getSyntheticClassObjectVisibility());
457 classObject.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
458 createPrimaryConstructorForObject(null, classObject);
459 return classObject;
460 }
461
462 @NotNull
463 private MutableClassDescriptor createClassDescriptorForClass(
464 @NotNull JetClass klass,
465 @NotNull DeclarationDescriptor containingDeclaration
466 ) {
467 ClassKind kind = getClassKind(klass);
468 // Kind check is needed in order to not consider enums as inner in any case
469 // (otherwise it would be impossible to create a class object in the enum)
470 boolean isInner = kind == ClassKind.CLASS && klass.isInner();
471 MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
472 containingDeclaration, outerScope, kind, isInner, JetPsiUtil.safeName(klass.getName()));
473 c.getDeclaredClasses().put(klass, mutableClassDescriptor);
474 trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetNamedDeclarationUtil.getUnsafeFQName(klass), mutableClassDescriptor);
475
476 createClassObjectForEnumClass(mutableClassDescriptor);
477
478 JetScope classScope = mutableClassDescriptor.getScopeForMemberDeclarationResolution();
479
480 prepareForDeferredCall(classScope, mutableClassDescriptor, klass);
481
482 return mutableClassDescriptor;
483 }
484
485 @NotNull
486 private MutableClassDescriptor createClassDescriptorForSingleton(
487 @NotNull JetClassOrObject declaration,
488 @NotNull Name name,
489 @NotNull ClassKind kind
490 ) {
491 MutableClassDescriptor descriptor = new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name);
492
493 prepareForDeferredCall(descriptor.getScopeForMemberDeclarationResolution(), descriptor, declaration);
494
495 createPrimaryConstructorForObject(declaration, descriptor);
496 trace.record(BindingContext.CLASS, declaration, descriptor);
497
498 c.getDeclaredClasses().put(declaration, descriptor);
499
500 return descriptor;
501 }
502
503 @NotNull
504 private ConstructorDescriptorImpl createPrimaryConstructorForObject(
505 @Nullable PsiElement object,
506 @NotNull MutableClassDescriptor mutableClassDescriptor
507 ) {
508 ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
509 .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
510 mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
511 return constructorDescriptor;
512 }
513
514 private void prepareForDeferredCall(
515 @NotNull JetScope outerScope,
516 @NotNull DeclarationDescriptor descriptorForDeferredResolve,
517 @NotNull JetDeclarationContainer container
518 ) {
519 forDeferredResolve.add(container);
520 c.normalScope.put(container, outerScope);
521 c.forDeferredResolver.put(container, descriptorForDeferredResolve);
522 }
523 }
524 }