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.collect.Lists;
020 import com.google.common.collect.Multimap;
021 import com.google.common.collect.Sets;
022 import com.intellij.psi.PsiElement;
023 import com.intellij.psi.PsiNameIdentifierOwner;
024 import org.jetbrains.annotations.NotNull;
025 import org.jetbrains.annotations.Nullable;
026 import org.jetbrains.jet.lang.descriptors.*;
027 import org.jetbrains.jet.lang.descriptors.impl.*;
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.JetScope;
032 import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
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.SubstitutionUtils;
037 import org.jetbrains.jet.lang.types.TypeConstructor;
038 import org.jetbrains.jet.lang.types.TypeProjection;
039 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
040 import org.jetbrains.jet.utils.DFS;
041
042 import javax.inject.Inject;
043 import java.util.*;
044
045 import static org.jetbrains.jet.lang.diagnostics.Errors.*;
046 import static org.jetbrains.jet.lang.resolve.BindingContext.FQNAME_TO_CLASS_DESCRIPTOR;
047 import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
048 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry;
049 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isObject;
050 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.getDefaultClassVisibility;
051 import static org.jetbrains.jet.lang.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
052 import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
053
054 public class TypeHierarchyResolver {
055 @NotNull
056 private TopDownAnalysisContext context;
057 @NotNull
058 private ImportsResolver importsResolver;
059 @NotNull
060 private DescriptorResolver descriptorResolver;
061 @NotNull
062 private ScriptHeaderResolver scriptHeaderResolver;
063 @NotNull
064 private NamespaceFactoryImpl namespaceFactory;
065 @NotNull
066 private BindingTrace trace;
067
068 @Inject
069 public void setContext(@NotNull TopDownAnalysisContext context) {
070 this.context = context;
071 }
072
073 @Inject
074 public void setImportsResolver(@NotNull ImportsResolver importsResolver) {
075 this.importsResolver = importsResolver;
076 }
077
078 @Inject
079 public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
080 this.descriptorResolver = descriptorResolver;
081 }
082
083 @Inject
084 public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
085 this.scriptHeaderResolver = scriptHeaderResolver;
086 }
087
088 @Inject
089 public void setNamespaceFactory(@NotNull NamespaceFactoryImpl namespaceFactory) {
090 this.namespaceFactory = namespaceFactory;
091 }
092
093 @Inject
094 public void setTrace(@NotNull BindingTrace trace) {
095 this.trace = trace;
096 }
097
098 public void process(
099 @NotNull JetScope outerScope, @NotNull NamespaceLikeBuilder owner,
100 @NotNull Collection<? extends PsiElement> declarations
101 ) {
102
103 {
104 // TODO: Very temp code - main goal is to remove recursion from collectNamespacesAndClassifiers
105 Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>();
106 forDeferredResolve.addAll(collectNamespacesAndClassifiers(outerScope, owner, declarations));
107
108 while (!forDeferredResolve.isEmpty()) {
109 JetDeclarationContainer declarationContainer = forDeferredResolve.poll();
110 assert declarationContainer != null;
111
112 DeclarationDescriptor descriptorForDeferredResolve = context.forDeferredResolver.get(declarationContainer);
113 JetScope scope = context.normalScope.get(declarationContainer);
114
115 // Even more temp code
116 if (descriptorForDeferredResolve instanceof MutableClassDescriptorLite) {
117 forDeferredResolve.addAll(
118 collectNamespacesAndClassifiers(
119 scope,
120 ((MutableClassDescriptorLite) descriptorForDeferredResolve).getBuilder(),
121 declarationContainer.getDeclarations()));
122 }
123 else if (descriptorForDeferredResolve instanceof NamespaceDescriptorImpl) {
124 forDeferredResolve.addAll(
125 collectNamespacesAndClassifiers(
126 scope,
127 ((NamespaceDescriptorImpl) descriptorForDeferredResolve).getBuilder(),
128 declarationContainer.getDeclarations()));
129 }
130 else {
131 assert false;
132 }
133 }
134 }
135
136 importsResolver.processTypeImports(outerScope);
137
138 createTypeConstructors(); // create type constructors for classes and generic parameters, supertypes are not filled in
139 resolveTypesInClassHeaders(); // Generic bounds and types in supertype lists (no expressions or constructor resolution)
140
141 context.setClassesTopologicalOrder(topologicallySortClassesAndObjects());
142
143 // Detect and disconnect all loops in the hierarchy
144 detectAndDisconnectLoops();
145
146 // At this point, there are no loops in the type hierarchy
147
148 checkSupertypesForConsistency();
149 // computeSuperclasses();
150
151 checkTypesInClassHeaders(); // Check bounds in the types used in generic bounds and supertype lists
152 }
153
154 @NotNull
155 private Collection<JetDeclarationContainer> collectNamespacesAndClassifiers(
156 @NotNull JetScope outerScope,
157 @NotNull NamespaceLikeBuilder owner,
158 @NotNull Iterable<? extends PsiElement> declarations
159 ) {
160 Collection<JetDeclarationContainer> forDeferredResolve = new ArrayList<JetDeclarationContainer>();
161
162 ClassifierCollector collector = new ClassifierCollector(outerScope, owner, forDeferredResolve);
163
164 for (PsiElement declaration : declarations) {
165 declaration.accept(collector);
166 }
167
168 return forDeferredResolve;
169 }
170
171
172 @NotNull
173 private static ClassKind getClassKind(@NotNull JetClass jetClass) {
174 if (jetClass.isTrait()) return ClassKind.TRAIT;
175 if (jetClass.isAnnotation()) return ClassKind.ANNOTATION_CLASS;
176 if (jetClass.isEnum()) return ClassKind.ENUM_CLASS;
177 return ClassKind.CLASS;
178 }
179
180 private void createTypeConstructors() {
181 for (Map.Entry<JetClassOrObject, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
182 JetClassOrObject classOrObject = entry.getKey();
183 MutableClassDescriptor descriptor = entry.getValue();
184 if (classOrObject instanceof JetClass) {
185 descriptorResolver.resolveMutableClassDescriptor((JetClass) classOrObject, descriptor, trace);
186 }
187 else if (classOrObject instanceof JetObjectDeclaration) {
188 descriptor.setModality(Modality.FINAL);
189 descriptor.setVisibility(resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor)));
190 descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
191 }
192
193 descriptor.createTypeConstructor();
194
195 if (classOrObject instanceof JetEnumEntry ||
196 classOrObject instanceof JetObjectDeclaration && classOrObject.getNameIdentifier() != null) {
197 MutableClassDescriptorLite classObject = descriptor.getClassObjectDescriptor();
198 assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText();
199
200 // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a synthetic class object.
201 // We make this class object inherit from the singleton here, thus allowing to use the singleton's class object where
202 // the instance of the singleton is applicable. Effectively all members of the singleton would be present in its class
203 // object as fake overrides, so you can access them via standard class object notation: ObjectName.memberName()
204 classObject.addSupertype(descriptor.getDefaultType());
205 }
206 }
207 }
208
209 private void resolveTypesInClassHeaders() {
210 for (Map.Entry<JetClassOrObject, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
211 JetClassOrObject classOrObject = entry.getKey();
212 MutableClassDescriptor descriptor = entry.getValue();
213 if (classOrObject instanceof JetClass) {
214 //noinspection unchecked
215 descriptorResolver.resolveGenericBounds((JetClass) classOrObject, descriptor.getScopeForSupertypeResolution(),
216 (List) descriptor.getTypeConstructor().getParameters(), trace);
217 }
218 descriptorResolver.resolveSupertypesForMutableClassDescriptor(classOrObject, descriptor, trace);
219 }
220 }
221
222 private List<MutableClassDescriptorLite> topologicallySortClassesAndObjects() {
223 // A topsort is needed only for better diagnostics:
224 // edges that get removed to disconnect loops are more reasonable in this case
225 //noinspection unchecked
226 return DFS.topologicalOrder(
227 (Iterable) context.getClasses().values(),
228 new DFS.Neighbors<MutableClassDescriptorLite>() {
229 @NotNull
230 @Override
231 public Iterable<MutableClassDescriptorLite> getNeighbors(MutableClassDescriptorLite current) {
232 List<MutableClassDescriptorLite> result = Lists.newArrayList();
233 for (JetType supertype : current.getSupertypes()) {
234 DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
235 if (declarationDescriptor instanceof MutableClassDescriptorLite) {
236 MutableClassDescriptorLite classDescriptor = (MutableClassDescriptorLite) declarationDescriptor;
237 result.add(classDescriptor);
238 }
239 }
240 return result;
241 }
242 });
243
244 }
245
246 private void detectAndDisconnectLoops() {
247 // Loop detection and disconnection
248 Set<ClassDescriptor> visited = Sets.newHashSet();
249 Set<ClassDescriptor> beingProcessed = Sets.newHashSet();
250 List<ClassDescriptor> currentPath = Lists.newArrayList();
251 for (MutableClassDescriptorLite klass : context.getClassesTopologicalOrder()) {
252 traverseTypeHierarchy(klass, visited, beingProcessed, currentPath);
253 }
254 }
255
256 private void traverseTypeHierarchy(
257 MutableClassDescriptorLite currentClass,
258 Set<ClassDescriptor> visited,
259 Set<ClassDescriptor> beingProcessed,
260 List<ClassDescriptor> currentPath
261 ) {
262 if (!visited.add(currentClass)) {
263 if (beingProcessed.contains(currentClass)) {
264 markCycleErrors(currentPath, currentClass);
265 assert !currentPath.isEmpty() : "Cycle cannot be found on an empty currentPath";
266 ClassDescriptor subclassOfCurrent = currentPath.get(currentPath.size() - 1);
267 assert subclassOfCurrent instanceof MutableClassDescriptor;
268 // Disconnect the loop
269 for (Iterator<JetType> iterator = ((MutableClassDescriptor) subclassOfCurrent).getSupertypes().iterator();
270 iterator.hasNext(); ) {
271 JetType type = iterator.next();
272 if (type.getConstructor() == currentClass.getTypeConstructor()) {
273 iterator.remove();
274 break;
275 }
276 }
277 }
278 return;
279 }
280
281 beingProcessed.add(currentClass);
282 currentPath.add(currentClass);
283 for (JetType supertype : Lists.newArrayList(currentClass.getSupertypes())) {
284 DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
285 if (declarationDescriptor instanceof MutableClassDescriptor) {
286 MutableClassDescriptor mutableClassDescriptor = (MutableClassDescriptor) declarationDescriptor;
287 traverseTypeHierarchy(mutableClassDescriptor, visited, beingProcessed, currentPath);
288 }
289 }
290 beingProcessed.remove(currentClass);
291 currentPath.remove(currentPath.size() - 1);
292 }
293
294 private void markCycleErrors(List<ClassDescriptor> currentPath, @NotNull ClassDescriptor current) {
295 int size = currentPath.size();
296 for (int i = size - 1; i >= 0; i--) {
297 ClassDescriptor classDescriptor = currentPath.get(i);
298
299 ClassDescriptor superclass = (i < size - 1) ? currentPath.get(i + 1) : current;
300 PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
301
302 PsiElement elementToMark = null;
303 if (psiElement instanceof JetClassOrObject) {
304 JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
305 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
306 JetTypeReference typeReference = delegationSpecifier.getTypeReference();
307 if (typeReference == null) continue;
308 JetType supertype = trace.get(TYPE, typeReference);
309 if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
310 elementToMark = typeReference;
311 }
312 }
313 }
314 if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
315 PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
316 PsiElement nameIdentifier = namedElement.getNameIdentifier();
317 if (nameIdentifier != null) {
318 elementToMark = nameIdentifier;
319 }
320 }
321 if (elementToMark != null) {
322 trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
323 }
324
325 if (classDescriptor == current) {
326 // Beginning of cycle is found
327 break;
328 }
329 }
330 }
331
332 private void checkSupertypesForConsistency() {
333 for (MutableClassDescriptorLite mutableClassDescriptor : context.getClassesTopologicalOrder()) {
334 Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
335 .buildDeepSubstitutionMultimap(mutableClassDescriptor.getDefaultType());
336 for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
337 Collection<TypeProjection> projections = entry.getValue();
338 if (projections.size() > 1) {
339 TypeConstructor typeConstructor = entry.getKey();
340 DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
341 assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
342 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
343
344 // Immediate arguments of supertypes cannot be projected
345 Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
346 for (TypeProjection projection : projections) {
347 conflictingTypes.add(projection.getType());
348 }
349 switch (typeParameterDescriptor.getVariance()) {
350 case INVARIANT:
351 // Leave conflicting types as is
352 break;
353 case IN_VARIANCE:
354 // Filter out those who have supertypes in this set (common supertype)
355 Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
356 break;
357 case OUT_VARIANCE:
358 // Filter out those who have subtypes in this set (common subtype)
359 Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
360 break;
361 }
362
363 if (conflictingTypes.size() > 1) {
364 DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
365 assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
366 JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
367 .classDescriptorToDeclaration(trace.getBindingContext(), mutableClassDescriptor);
368 JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
369 assert delegationSpecifierList != null;
370 // trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
371 trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
372 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
373 conflictingTypes));
374 }
375 }
376 }
377 }
378 }
379
380 private enum Filter {
381 REMOVE_IF_SUBTYPE_IN_THE_SET {
382 @Override
383 public boolean removeNeeded(JetType subject, JetType other) {
384 return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject);
385 }
386 },
387 REMOVE_IF_SUPERTYPE_IN_THE_SET {
388 @Override
389 public boolean removeNeeded(JetType subject, JetType other) {
390 return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other);
391 }
392 };
393
394 private void proceed(Set<JetType> conflictingTypes) {
395 for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
396 JetType type = iterator.next();
397 for (JetType otherType : conflictingTypes) {
398 boolean subtypeOf = removeNeeded(type, otherType);
399 if (type != otherType && subtypeOf) {
400 iterator.remove();
401 break;
402 }
403 }
404 }
405 }
406
407 public abstract boolean removeNeeded(JetType subject, JetType other);
408 }
409
410 private void checkTypesInClassHeaders() {
411 for (JetClassOrObject classOrObject : context.getClasses().keySet()) {
412 for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
413 checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
414 }
415
416 if (!(classOrObject instanceof JetClass)) continue;
417 JetClass jetClass = (JetClass) classOrObject;
418
419 for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
420 checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
421 }
422
423 for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
424 checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
425 }
426 }
427 }
428
429 private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) {
430 if (typeReference != null) {
431 JetType type = trace.getBindingContext().get(TYPE, typeReference);
432 if (type != null) {
433 DescriptorResolver.checkBounds(typeReference, type, trace);
434 }
435 }
436 }
437
438 private class ClassifierCollector extends JetVisitorVoid {
439 private final JetScope outerScope;
440 private final NamespaceLikeBuilder owner;
441 private final Collection<JetDeclarationContainer> forDeferredResolve;
442
443 public ClassifierCollector(@NotNull JetScope outerScope,
444 @NotNull NamespaceLikeBuilder owner,
445 @NotNull Collection<JetDeclarationContainer> forDeferredResolve
446 ) {
447 this.outerScope = outerScope;
448 this.owner = owner;
449 this.forDeferredResolve = forDeferredResolve;
450 }
451
452 @Override
453 public void visitJetFile(@NotNull JetFile file) {
454 NamespaceDescriptorImpl namespaceDescriptor = namespaceFactory.createNamespaceDescriptorPathIfNeeded(
455 file, outerScope, RedeclarationHandler.DO_NOTHING);
456 context.getNamespaceDescriptors().put(file, namespaceDescriptor);
457
458 WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(),
459 new TraceBasedRedeclarationHandler(trace), "namespace in file " + file.getName());
460 namespaceScope.changeLockLevel(WritableScope.LockLevel.BOTH);
461 context.getNamespaceScopes().put(file, namespaceScope);
462
463 if (file.isScript()) {
464 scriptHeaderResolver.processScriptHierarchy(file.getScript(), namespaceScope);
465 }
466
467 prepareForDeferredCall(namespaceScope, namespaceDescriptor, file);
468 }
469
470 @Override
471 public void visitClass(@NotNull JetClass klass) {
472 MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
473
474 owner.addClassifierDescriptor(mutableClassDescriptor);
475 }
476
477 @Override
478 public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
479 if (declaration.isObjectLiteral()) {
480 createClassDescriptorForSingleton(declaration, SpecialNames.NO_NAME_PROVIDED, ClassKind.CLASS);
481 return;
482 }
483
484 MutableClassDescriptor descriptor =
485 createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.OBJECT);
486
487 owner.addClassifierDescriptor(descriptor);
488 trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(declaration), descriptor);
489
490 descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObject(descriptor));
491 }
492
493 @Override
494 public void visitEnumEntry(@NotNull JetEnumEntry declaration) {
495 MutableClassDescriptor descriptor =
496 createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.ENUM_ENTRY);
497
498 owner.addClassifierDescriptor(descriptor);
499
500 descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObject(descriptor));
501 }
502
503 @Override
504 public void visitTypedef(@NotNull JetTypedef typedef) {
505 trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
506 }
507
508 @Override
509 public void visitClassObject(@NotNull JetClassObject classObject) {
510 JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
511 if (objectDeclaration == null) return;
512
513 DeclarationDescriptor container = owner.getOwnerForChildren();
514
515 MutableClassDescriptor classObjectDescriptor =
516 createClassDescriptorForSingleton(objectDeclaration, getClassObjectName(container.getName()), ClassKind.CLASS_OBJECT);
517
518 NamespaceLikeBuilder.ClassObjectStatus status =
519 isEnumEntry(container) || isObject(container) ?
520 NamespaceLikeBuilder.ClassObjectStatus.NOT_ALLOWED :
521 owner.setClassObjectDescriptor(classObjectDescriptor);
522
523 switch (status) {
524 case DUPLICATE:
525 trace.report(MANY_CLASS_OBJECTS.on(classObject));
526 break;
527 case NOT_ALLOWED:
528 trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
529 break;
530 case OK:
531 // Everything is OK so no errors to trace.
532 break;
533 }
534 }
535
536 private void createClassObjectForEnumClass(@NotNull MutableClassDescriptor mutableClassDescriptor) {
537 if (mutableClassDescriptor.getKind() == ClassKind.ENUM_CLASS) {
538 MutableClassDescriptor classObject = createSyntheticClassObject(mutableClassDescriptor);
539 mutableClassDescriptor.getBuilder().setClassObjectDescriptor(classObject);
540 classObject.getBuilder().addFunctionDescriptor(DescriptorResolver.createEnumClassObjectValuesMethod(classObject, trace));
541 classObject.getBuilder().addFunctionDescriptor(DescriptorResolver.createEnumClassObjectValueOfMethod(classObject, trace));
542 }
543 }
544
545 @NotNull
546 private MutableClassDescriptor createSyntheticClassObject(@NotNull ClassDescriptor classDescriptor) {
547 MutableClassDescriptor classObject = new MutableClassDescriptor(classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false,
548 getClassObjectName(classDescriptor.getName()));
549 classObject.setModality(Modality.FINAL);
550 classObject.setVisibility(DescriptorUtils.getSyntheticClassObjectVisibility());
551 classObject.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
552 createPrimaryConstructorForObject(null, classObject);
553 classObject.createTypeConstructor();
554 return classObject;
555 }
556
557 @NotNull
558 private MutableClassDescriptor createClassDescriptorForClass(
559 @NotNull JetClass klass,
560 @NotNull DeclarationDescriptor containingDeclaration
561 ) {
562 ClassKind kind = getClassKind(klass);
563 // Kind check is needed in order to not consider enums as inner in any case
564 // (otherwise it would be impossible to create a class object in the enum)
565 boolean isInner = kind == ClassKind.CLASS && klass.isInner();
566 MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
567 containingDeclaration, outerScope, kind, isInner, JetPsiUtil.safeName(klass.getName()));
568 context.getClasses().put(klass, mutableClassDescriptor);
569 trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(klass), mutableClassDescriptor);
570
571 createClassObjectForEnumClass(mutableClassDescriptor);
572
573 JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
574
575 prepareForDeferredCall(classScope, mutableClassDescriptor, klass);
576
577 return mutableClassDescriptor;
578 }
579
580 @NotNull
581 private MutableClassDescriptor createClassDescriptorForSingleton(
582 @NotNull JetClassOrObject declaration,
583 @NotNull Name name,
584 @NotNull ClassKind kind
585 ) {
586 MutableClassDescriptor descriptor = new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name);
587
588 prepareForDeferredCall(descriptor.getScopeForMemberResolution(), descriptor, declaration);
589
590 createPrimaryConstructorForObject(declaration, descriptor);
591 trace.record(BindingContext.CLASS, declaration, descriptor);
592
593 context.getClasses().put(declaration, descriptor);
594
595 return descriptor;
596 }
597
598 @NotNull
599 private ConstructorDescriptorImpl createPrimaryConstructorForObject(
600 @Nullable PsiElement object,
601 @NotNull MutableClassDescriptor mutableClassDescriptor
602 ) {
603 ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
604 .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
605 mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
606 return constructorDescriptor;
607 }
608
609 private void prepareForDeferredCall(
610 @NotNull JetScope outerScope,
611 @NotNull DeclarationDescriptor descriptorForDeferredResolve,
612 @NotNull JetDeclarationContainer container
613 ) {
614 forDeferredResolve.add(container);
615 context.normalScope.put(container, outerScope);
616 context.forDeferredResolver.put(container, descriptorForDeferredResolve);
617 }
618 }
619 }