001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.lazy.descriptors;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.collect.Collections2;
021    import com.google.common.collect.Lists;
022    import com.intellij.psi.PsiElement;
023    import com.intellij.psi.PsiNameIdentifierOwner;
024    import kotlin.KotlinPackage;
025    import kotlin.Unit;
026    import kotlin.jvm.functions.Function0;
027    import kotlin.jvm.functions.Function1;
028    import org.jetbrains.annotations.Mutable;
029    import org.jetbrains.annotations.NotNull;
030    import org.jetbrains.annotations.Nullable;
031    import org.jetbrains.annotations.ReadOnly;
032    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
033    import org.jetbrains.kotlin.descriptors.*;
034    import org.jetbrains.kotlin.descriptors.annotations.Annotations;
035    import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorBase;
036    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
037    import org.jetbrains.kotlin.name.Name;
038    import org.jetbrains.kotlin.psi.*;
039    import org.jetbrains.kotlin.resolve.*;
040    import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
041    import org.jetbrains.kotlin.resolve.lazy.LazyClassContext;
042    import org.jetbrains.kotlin.resolve.lazy.LazyEntity;
043    import org.jetbrains.kotlin.resolve.lazy.data.JetClassInfoUtil;
044    import org.jetbrains.kotlin.resolve.lazy.data.JetClassLikeInfo;
045    import org.jetbrains.kotlin.resolve.lazy.data.JetClassOrObjectInfo;
046    import org.jetbrains.kotlin.resolve.lazy.data.JetObjectInfo;
047    import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider;
048    import org.jetbrains.kotlin.resolve.scopes.JetScope;
049    import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
050    import org.jetbrains.kotlin.resolve.scopes.StaticScopeForKotlinClass;
051    import org.jetbrains.kotlin.storage.MemoizedFunctionToNotNull;
052    import org.jetbrains.kotlin.storage.NotNullLazyValue;
053    import org.jetbrains.kotlin.storage.NullableLazyValue;
054    import org.jetbrains.kotlin.storage.StorageManager;
055    import org.jetbrains.kotlin.types.AbstractClassTypeConstructor;
056    import org.jetbrains.kotlin.types.JetType;
057    import org.jetbrains.kotlin.types.TypeConstructor;
058    import org.jetbrains.kotlin.types.TypeUtils;
059    
060    import java.util.*;
061    
062    import static kotlin.KotlinPackage.firstOrNull;
063    import static org.jetbrains.kotlin.diagnostics.Errors.CYCLIC_INHERITANCE_HIERARCHY;
064    import static org.jetbrains.kotlin.diagnostics.Errors.TYPE_PARAMETERS_IN_ENUM;
065    import static org.jetbrains.kotlin.resolve.BindingContext.TYPE;
066    import static org.jetbrains.kotlin.resolve.ModifiersChecker.*;
067    import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement;
068    
069    public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDescriptorWithResolutionScopes, LazyEntity {
070        private static final Predicate<JetType> VALID_SUPERTYPE = new Predicate<JetType>() {
071            @Override
072            public boolean apply(JetType type) {
073                assert !type.isError() : "Error types must be filtered out in DescriptorResolver";
074                return TypeUtils.getClassDescriptor(type) != null;
075            }
076        };
077        private final LazyClassContext c;
078    
079        private final ClassMemberDeclarationProvider declarationProvider;
080    
081        private final LazyClassTypeConstructor typeConstructor;
082        private final Modality modality;
083        private final Visibility visibility;
084        private final NotNullLazyValue<ClassKind> kind;
085        private final NotNullLazyValue<Boolean> isInner;
086    
087        private final Annotations annotations;
088        private final Annotations danglingAnnotations;
089        private final NullableLazyValue<LazyClassDescriptor> companionObjectDescriptor;
090        private final MemoizedFunctionToNotNull<JetObjectDeclaration, ClassDescriptor> extraCompanionObjectDescriptors;
091    
092        private final LazyClassMemberScope unsubstitutedMemberScope;
093        private final JetScope staticScope;
094    
095        private final NullableLazyValue<Void> forceResolveAllContents;
096        private final boolean isCompanionObject;
097    
098        private final ClassResolutionScopesSupport resolutionScopesSupport;
099    
100        public LazyClassDescriptor(
101                @NotNull LazyClassContext c,
102                @NotNull DeclarationDescriptor containingDeclaration,
103                @NotNull Name name,
104                @NotNull JetClassLikeInfo classLikeInfo
105        ) {
106            super(c.getStorageManager(), containingDeclaration, name,
107                  toSourceElement(classLikeInfo.getCorrespondingClassOrObject())
108            );
109            this.c = c;
110    
111            JetClassOrObject classOrObject = classLikeInfo.getCorrespondingClassOrObject();
112            if (classOrObject != null) {
113                this.c.getTrace().record(BindingContext.CLASS, classOrObject, this);
114            }
115            this.c.getTrace().record(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, DescriptorUtils.getFqName(this), this);
116    
117            this.declarationProvider = c.getDeclarationProviderFactory().getClassMemberDeclarationProvider(classLikeInfo);
118    
119            this.unsubstitutedMemberScope = createMemberScope(c, this.declarationProvider);
120            this.staticScope = new StaticScopeForKotlinClass(this);
121    
122            this.typeConstructor = new LazyClassTypeConstructor();
123    
124            final ClassKind syntaxKind = classLikeInfo.getClassKind();
125            this.isCompanionObject = classLikeInfo instanceof JetObjectInfo && ((JetObjectInfo) classLikeInfo).isCompanionObject();
126    
127            final JetModifierList modifierList = classLikeInfo.getModifierList();
128            if (syntaxKind.isSingleton()) {
129                this.modality = Modality.FINAL;
130            }
131            else {
132                Modality defaultModality = syntaxKind == ClassKind.INTERFACE ? Modality.ABSTRACT : Modality.FINAL;
133                this.modality = resolveModalityFromModifiers(modifierList, defaultModality);
134            }
135    
136            boolean isLocal = classOrObject != null && JetPsiUtil.isLocal(classOrObject);
137            Visibility defaultVisibility;
138            if (syntaxKind == ClassKind.ENUM_ENTRY || (syntaxKind == ClassKind.OBJECT && isCompanionObject)) {
139                defaultVisibility = Visibilities.PUBLIC;
140            }
141            else {
142                defaultVisibility = Visibilities.DEFAULT_VISIBILITY;
143            }
144            this.visibility = isLocal ? Visibilities.LOCAL : resolveVisibilityFromModifiers(modifierList, defaultVisibility);
145    
146            StorageManager storageManager = c.getStorageManager();
147            final ClassDescriptor descriptor = this;
148    
149            this.isInner = storageManager.createLazyValue(new Function0<Boolean>() {
150                @Override
151                public Boolean invoke() {
152                    return isInnerClass(modifierList) && !ModifiersChecker.isIllegalInner(descriptor);
153                }
154            });
155    
156            this.kind = storageManager.createLazyValue(new Function0<ClassKind>() {
157                @Override
158                public ClassKind invoke() {
159                    return (syntaxKind == ClassKind.CLASS && KotlinBuiltIns.isAnnotation(descriptor)) ? ClassKind.ANNOTATION_CLASS : syntaxKind;
160                }
161            });
162    
163            if (modifierList != null) {
164                LazyAnnotations classAnnotations = new LazyAnnotations(
165                        new LazyAnnotationsContext(
166                                c.getAnnotationResolver(),
167                                storageManager,
168                                c.getTrace()
169                        ) {
170                            @NotNull
171                            @Override
172                            public LexicalScope getScope() {
173                                return getOuterScope();
174                            }
175                        },
176                        modifierList.getAnnotationEntries()
177                );
178                this.annotations = c.getAnnotationResolver().resolveAndAppendAnnotationsFromModifiers(
179                        classAnnotations, modifierList
180                );
181            }
182            else {
183                this.annotations = Annotations.EMPTY;
184            }
185    
186            List<JetAnnotationEntry> jetDanglingAnnotations = classLikeInfo.getDanglingAnnotations();
187            if (jetDanglingAnnotations.isEmpty()) {
188                this.danglingAnnotations = Annotations.EMPTY;
189            }
190            else {
191                this.danglingAnnotations = new LazyAnnotations(
192                        new LazyAnnotationsContext(
193                                c.getAnnotationResolver(),
194                                storageManager,
195                                c.getTrace()
196                        ) {
197                            @NotNull
198                            @Override
199                            public LexicalScope getScope() {
200                                return getScopeForMemberDeclarationResolution();
201                            }
202                        },
203                        jetDanglingAnnotations
204                );
205            }
206    
207            this.companionObjectDescriptor = storageManager.createNullableLazyValue(new Function0<LazyClassDescriptor>() {
208                @Override
209                public LazyClassDescriptor invoke() {
210                    return computeCompanionObjectDescriptor(getCompanionObjectIfAllowed());
211                }
212            });
213            this.extraCompanionObjectDescriptors = storageManager.createMemoizedFunction(new Function1<JetObjectDeclaration, ClassDescriptor>() {
214                @Override
215                public ClassDescriptor invoke(JetObjectDeclaration companionObject) {
216                    return computeCompanionObjectDescriptor(companionObject);
217                }
218            });
219            this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0<Void>() {
220                @Override
221                public Void invoke() {
222                    doForceResolveAllContents();
223                    return null;
224                }
225            }, null);
226    
227            this.resolutionScopesSupport = new ClassResolutionScopesSupport(this, storageManager, new Function0<LexicalScope>() {
228                @Override
229                public LexicalScope invoke() {
230                    return getOuterScope();
231                }
232            }, classLikeInfo.getPrimaryConstructorParameters());
233        }
234    
235        // NOTE: Called from constructor!
236        @NotNull
237        protected LazyClassMemberScope createMemberScope(
238                @NotNull LazyClassContext c,
239                @NotNull ClassMemberDeclarationProvider declarationProvider
240        ) {
241            return new LazyClassMemberScope(c, declarationProvider, this, c.getTrace());
242        }
243    
244        @NotNull
245        @Override
246        public JetScope getUnsubstitutedMemberScope() {
247            return unsubstitutedMemberScope;
248        }
249    
250        @NotNull
251        protected LexicalScope getOuterScope() {
252            return c.getDeclarationScopeProvider().getResolutionScopeForDeclaration(declarationProvider.getOwnerInfo().getScopeAnchor());
253        }
254    
255        @Override
256        @NotNull
257        public LexicalScope getScopeForClassHeaderResolution() {
258            return resolutionScopesSupport.getScopeForClassHeaderResolution().invoke();
259        }
260    
261        @Override
262        @NotNull
263        public LexicalScope getScopeForMemberDeclarationResolution() {
264            return resolutionScopesSupport.getScopeForMemberDeclarationResolution().invoke();
265        }
266    
267        @Override
268        @NotNull
269        public LexicalScope getScopeForStaticMemberDeclarationResolution() {
270            return resolutionScopesSupport.getScopeForStaticMemberDeclarationResolution().invoke();
271        }
272    
273        @Override
274        @NotNull
275        public LexicalScope getScopeForInitializerResolution() {
276            return resolutionScopesSupport.getScopeForInitializerResolution().invoke();
277        }
278    
279        @NotNull
280        @Override
281        public Collection<CallableMemberDescriptor> getDeclaredCallableMembers() {
282            //noinspection unchecked
283            return (Collection) KotlinPackage.filter(
284                    unsubstitutedMemberScope.getAllDescriptors(),
285                    new Function1<DeclarationDescriptor, Boolean>() {
286                        @Override
287                        public Boolean invoke(DeclarationDescriptor descriptor) {
288                            return descriptor instanceof CallableMemberDescriptor
289                                   && ((CallableMemberDescriptor) descriptor).getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
290                        }
291                    }
292            );
293        }
294    
295        @NotNull
296        @Override
297        public JetScope getStaticScope() {
298            return staticScope;
299        }
300    
301        @NotNull
302        @Override
303        public Collection<ConstructorDescriptor> getConstructors() {
304            return unsubstitutedMemberScope.getConstructors();
305        }
306    
307        @Override
308        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
309            return unsubstitutedMemberScope.getPrimaryConstructor();
310        }
311    
312        @NotNull
313        @Override
314        public TypeConstructor getTypeConstructor() {
315            return typeConstructor;
316        }
317    
318        @Override
319        public LazyClassDescriptor getCompanionObjectDescriptor() {
320            return companionObjectDescriptor.invoke();
321        }
322    
323        @NotNull
324        @ReadOnly
325        public List<ClassDescriptor> getDescriptorsForExtraCompanionObjects() {
326            final JetObjectDeclaration allowedCompanionObject = getCompanionObjectIfAllowed();
327    
328            return KotlinPackage.map(
329                    KotlinPackage.filter(
330                            declarationProvider.getOwnerInfo().getCompanionObjects(),
331                            new Function1<JetObjectDeclaration, Boolean>() {
332                                @Override
333                                public Boolean invoke(JetObjectDeclaration companionObject) {
334                                    return companionObject != allowedCompanionObject;
335                                }
336                            }
337                    ),
338                    new Function1<JetObjectDeclaration, ClassDescriptor>() {
339                        @Override
340                        public ClassDescriptor invoke(JetObjectDeclaration companionObject) {
341                            return extraCompanionObjectDescriptors.invoke(companionObject);
342                        }
343                    }
344            );
345        }
346    
347        @Nullable
348        private LazyClassDescriptor computeCompanionObjectDescriptor(@Nullable JetObjectDeclaration companionObject) {
349            JetClassLikeInfo companionObjectInfo = getCompanionObjectInfo(companionObject);
350            if (!(companionObjectInfo instanceof JetClassOrObjectInfo)) {
351                return null;
352            }
353            Name name = ((JetClassOrObjectInfo) companionObjectInfo).getName();
354            assert name != null;
355            getUnsubstitutedMemberScope().getClassifier(name, NoLookupLocation.UNSORTED);
356            ClassDescriptor companionObjectDescriptor = c.getTrace().get(BindingContext.CLASS, companionObject);
357            if (companionObjectDescriptor instanceof LazyClassDescriptor) {
358                assert DescriptorUtils.isCompanionObject(companionObjectDescriptor) : "Not a companion object: " + companionObjectDescriptor;
359                return (LazyClassDescriptor) companionObjectDescriptor;
360            }
361            else {
362                return null;
363            }
364        }
365    
366        @Nullable
367        private static JetClassLikeInfo getCompanionObjectInfo(@Nullable JetObjectDeclaration companionObject) {
368            if (companionObject != null) {
369                return JetClassInfoUtil.createClassLikeInfo(companionObject);
370            }
371    
372            return null;
373        }
374    
375        @Nullable
376        private JetObjectDeclaration getCompanionObjectIfAllowed() {
377            JetObjectDeclaration companionObject = firstOrNull(declarationProvider.getOwnerInfo().getCompanionObjects());
378            return (companionObject != null && isCompanionObjectAllowed()) ? companionObject : null;
379        }
380    
381        private boolean isCompanionObjectAllowed() {
382            return !(getKind().isSingleton() || isInner() || DescriptorUtils.isLocal(this));
383        }
384    
385        @NotNull
386        @Override
387        public ClassKind getKind() {
388            return kind.invoke();
389        }
390    
391        @NotNull
392        @Override
393        public Modality getModality() {
394            return modality;
395        }
396    
397        @NotNull
398        @Override
399        public Visibility getVisibility() {
400            return visibility;
401        }
402    
403        @Override
404        public boolean isInner() {
405            return isInner.invoke();
406        }
407    
408        @Override
409        public boolean isCompanionObject() {
410            return isCompanionObject;
411        }
412    
413        @NotNull
414        @Override
415        public Annotations getAnnotations() {
416            return annotations;
417        }
418    
419        @NotNull
420        public Annotations getDanglingAnnotations() {
421            return danglingAnnotations;
422        }
423    
424        @Override
425        public String toString() {
426            // not using descriptor render to preserve laziness
427            return "lazy class " + getName().toString();
428        }
429    
430        @Override
431        public void forceResolveAllContents() {
432            forceResolveAllContents.invoke();
433        }
434    
435        private void doForceResolveAllContents() {
436            resolveMemberHeaders();
437            ClassDescriptor companionObjectDescriptor = getCompanionObjectDescriptor();
438            if (companionObjectDescriptor != null) {
439                ForceResolveUtil.forceResolveAllContents(companionObjectDescriptor);
440            }
441    
442            ForceResolveUtil.forceResolveAllContents(getConstructors());
443            ForceResolveUtil.forceResolveAllContents(getDescriptorsForExtraCompanionObjects());
444            ForceResolveUtil.forceResolveAllContents(getUnsubstitutedMemberScope());
445            ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
446        }
447    
448        // Note: headers of member classes' members are not resolved
449        public void resolveMemberHeaders() {
450            ForceResolveUtil.forceResolveAllContents(getAnnotations());
451            ForceResolveUtil.forceResolveAllContents(getDanglingAnnotations());
452    
453            getCompanionObjectDescriptor();
454    
455            getDescriptorsForExtraCompanionObjects();
456    
457            getConstructors();
458            getContainingDeclaration();
459            getThisAsReceiverParameter();
460            getKind();
461            getModality();
462            getName();
463            getOriginal();
464            getScopeForClassHeaderResolution();
465            getScopeForMemberDeclarationResolution();
466            getUnsubstitutedMemberScope().getAllDescriptors();
467            getScopeForInitializerResolution();
468            getUnsubstitutedInnerClassesScope();
469            getTypeConstructor().getSupertypes();
470            for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
471                typeParameterDescriptor.getUpperBounds();
472                typeParameterDescriptor.getLowerBounds();
473            }
474            getUnsubstitutedPrimaryConstructor();
475            getVisibility();
476        }
477    
478        private static class Supertypes {
479            @Mutable
480            public final Collection<JetType> trueSupertypes;
481            @Mutable
482            public final Collection<JetType> cyclicSupertypes;
483    
484            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes) {
485                this(trueSupertypes, new ArrayList<JetType>(0));
486            }
487    
488            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes, @Mutable @NotNull Collection<JetType> cyclicSupertypes) {
489                this.trueSupertypes = trueSupertypes;
490                this.cyclicSupertypes = cyclicSupertypes;
491            }
492    
493            @NotNull
494            public Collection<JetType> getAllSupertypes() {
495                return KotlinPackage.plus(trueSupertypes, cyclicSupertypes);
496            }
497        }
498    
499        private class LazyClassTypeConstructor extends AbstractClassTypeConstructor implements LazyEntity {
500            private final NotNullLazyValue<Supertypes> supertypes = c.getStorageManager().createLazyValueWithPostCompute(
501                    new Function0<Supertypes>() {
502                        @Override
503                        public Supertypes invoke() {
504                            if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
505                                return new Supertypes(Collections.<JetType>emptyList());
506                            }
507    
508                            JetClassOrObject classOrObject = declarationProvider.getOwnerInfo().getCorrespondingClassOrObject();
509                            if (classOrObject == null) {
510                                return new Supertypes(Collections.singleton(c.getModuleDescriptor().getBuiltIns().getAnyType()));
511                            }
512    
513                            List<JetType> allSupertypes = c.getDescriptorResolver()
514                                    .resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
515                                                       c.getTrace());
516    
517                            return new Supertypes(Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)));
518                        }
519                    },
520                    new Function1<Boolean, Supertypes>() {
521                        @Override
522                        public Supertypes invoke(Boolean firstTime) {
523                            return new Supertypes(Collections.<JetType>emptyList());
524                        }
525                    },
526                    new Function1<Supertypes, Unit>() {
527                        @Override
528                        public Unit invoke(@NotNull Supertypes supertypes) {
529                            findAndDisconnectLoopsInTypeHierarchy(supertypes);
530                            return Unit.INSTANCE$;
531                        }
532                    }
533            );
534    
535            private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = c.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
536                @Override
537                public List<TypeParameterDescriptor> invoke() {
538                    JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
539                    JetTypeParameterList typeParameterList = classInfo.getTypeParameterList();
540                    if (typeParameterList == null) return Collections.emptyList();
541    
542                    if (classInfo.getClassKind() == ClassKind.ENUM_CLASS) {
543                        c.getTrace().report(TYPE_PARAMETERS_IN_ENUM.on(typeParameterList));
544                    }
545    
546                    List<JetTypeParameter> typeParameters = typeParameterList.getParameters();
547                    List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size());
548                    for (int i = 0; i < typeParameters.size(); i++) {
549                        parameters.add(new LazyTypeParameterDescriptor(c, LazyClassDescriptor.this, typeParameters.get(i), i));
550                    }
551    
552                    return parameters;
553                }
554            });
555    
556            private final NullableLazyValue<Void> forceResolveAllContents =
557                    c.getStorageManager().createRecursionTolerantNullableLazyValue(new Function0<Void>() {
558                        @Override
559                        public Void invoke() {
560                            doForceResolveAllContents();
561                            return null;
562                        }
563                    }, null);
564    
565            @NotNull
566            @Override
567            public List<TypeParameterDescriptor> getParameters() {
568                return parameters.invoke();
569            }
570    
571            @NotNull
572            @Override
573            public Collection<JetType> getSupertypes() {
574                return supertypes.invoke().trueSupertypes;
575            }
576    
577            private void findAndDisconnectLoopsInTypeHierarchy(Supertypes supertypes) {
578                for (Iterator<JetType> iterator = supertypes.trueSupertypes.iterator(); iterator.hasNext(); ) {
579                    JetType supertype = iterator.next();
580                    if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
581                        iterator.remove();
582                        supertypes.cyclicSupertypes.add(supertype);
583    
584                        ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
585                        if (supertypeDescriptor instanceof ClassDescriptor) {
586                            ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
587                            reportCyclicInheritanceHierarchyError(c.getTrace(), LazyClassDescriptor.this, superclass);
588                        }
589                    }
590                }
591            }
592    
593            private void reportCyclicInheritanceHierarchyError(
594                    @NotNull BindingTrace trace,
595                    @NotNull ClassDescriptor classDescriptor,
596                    @NotNull ClassDescriptor superclass
597            ) {
598                PsiElement psiElement = DescriptorToSourceUtils.getSourceFromDescriptor(classDescriptor);
599    
600                PsiElement elementToMark = null;
601                if (psiElement instanceof JetClassOrObject) {
602                    JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
603                    for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
604                        JetTypeReference typeReference = delegationSpecifier.getTypeReference();
605                        if (typeReference == null) continue;
606                        JetType supertype = trace.get(TYPE, typeReference);
607                        if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
608                            elementToMark = typeReference;
609                        }
610                    }
611                }
612                if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
613                    PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
614                    PsiElement nameIdentifier = namedElement.getNameIdentifier();
615                    if (nameIdentifier != null) {
616                        elementToMark = nameIdentifier;
617                    }
618                }
619                if (elementToMark != null) {
620                    trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
621                }
622            }
623    
624            private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
625                if (!visited.add(from)) return false;
626                for (JetType supertype : getNeighbors(from)) {
627                    TypeConstructor supertypeConstructor = supertype.getConstructor();
628                    if (supertypeConstructor == to) {
629                        return true;
630                    }
631                    if (isReachable(supertypeConstructor, to, visited)) {
632                        return true;
633                    }
634                }
635                return false;
636            }
637    
638            private Collection<JetType> getNeighbors(TypeConstructor from) {
639                // Supertypes + type for container
640                Collection<JetType> neighbours = new ArrayList<JetType>(
641                        from instanceof LazyClassTypeConstructor
642                                 ? ((LazyClassTypeConstructor) from).supertypes.invoke().getAllSupertypes()
643                                 : from.getSupertypes()
644                );
645    
646                ClassifierDescriptor fromDescriptor = from.getDeclarationDescriptor();
647                if (fromDescriptor != null) {
648                    DeclarationDescriptor container = fromDescriptor.getContainingDeclaration();
649                    if (container instanceof ClassDescriptor) {
650                        neighbours.add(((ClassDescriptor) container).getDefaultType());
651                    }
652                }
653                return neighbours;
654            }
655    
656            @Override
657            public boolean isFinal() {
658                return !getModality().isOverridable();
659            }
660    
661            @Override
662            public boolean isDenotable() {
663                return true;
664            }
665    
666            @Override
667            public ClassifierDescriptor getDeclarationDescriptor() {
668                return LazyClassDescriptor.this;
669            }
670    
671            @NotNull
672            @Override
673            public Annotations getAnnotations() {
674                return Annotations.EMPTY; // TODO
675            }
676    
677            @Override
678            public String toString() {
679                return LazyClassDescriptor.this.getName().toString();
680            }
681    
682            @Override
683            public void forceResolveAllContents() {
684                forceResolveAllContents.invoke();
685            }
686    
687            private void doForceResolveAllContents() {
688                ForceResolveUtil.forceResolveAllContents(getAnnotations());
689                ForceResolveUtil.forceResolveAllContents(getSupertypes());
690                ForceResolveUtil.forceResolveAllContents(getParameters());
691            }
692        }
693    }