001    /*
002     * Copyright 2010-2014 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.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 kotlin.Function0;
024    import kotlin.Function1;
025    import kotlin.Unit;
026    import kotlin.KotlinPackage;
027    import org.jetbrains.annotations.Mutable;
028    import org.jetbrains.annotations.NotNull;
029    import org.jetbrains.annotations.Nullable;
030    import org.jetbrains.jet.lang.descriptors.*;
031    import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
032    import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase;
033    import org.jetbrains.jet.lang.psi.*;
034    import org.jetbrains.jet.lang.resolve.AnnotationResolver;
035    import org.jetbrains.jet.lang.resolve.BindingContext;
036    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
037    import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver;
038    import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
039    import org.jetbrains.jet.lang.resolve.lazy.LazyEntity;
040    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
041    import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider;
042    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassInfoUtil;
043    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
044    import org.jetbrains.jet.lang.resolve.lazy.data.SyntheticClassObjectInfo;
045    import org.jetbrains.jet.lang.resolve.lazy.declarations.ClassMemberDeclarationProvider;
046    import org.jetbrains.jet.lang.resolve.name.Name;
047    import org.jetbrains.jet.lang.resolve.scopes.*;
048    import org.jetbrains.jet.lang.types.JetType;
049    import org.jetbrains.jet.lang.types.TypeConstructor;
050    import org.jetbrains.jet.lang.types.TypeUtils;
051    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
052    import org.jetbrains.jet.storage.NotNullLazyValue;
053    import org.jetbrains.jet.storage.NullableLazyValue;
054    import org.jetbrains.jet.storage.StorageManager;
055    
056    import java.util.*;
057    
058    import static org.jetbrains.jet.lang.diagnostics.Errors.CLASS_OBJECT_NOT_ALLOWED;
059    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isSyntheticClassObject;
060    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.*;
061    import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
062    
063    public class LazyClassDescriptor extends ClassDescriptorBase implements LazyEntity, ClassDescriptorWithResolutionScopes {
064        private static final Predicate<JetType> VALID_SUPERTYPE = new Predicate<JetType>() {
065            @Override
066            public boolean apply(JetType type) {
067                assert !type.isError() : "Error types must be filtered out in DescriptorResolver";
068                return TypeUtils.getClassDescriptor(type) != null;
069            }
070        };
071        private final ResolveSession resolveSession;
072        private final JetClassLikeInfo originalClassInfo;
073        private final ClassMemberDeclarationProvider declarationProvider;
074    
075        private final LazyClassTypeConstructor typeConstructor;
076        private final Modality modality;
077        private final Visibility visibility;
078        private final ClassKind kind;
079        private final boolean isInner;
080    
081        private final NotNullLazyValue<Annotations> annotations;
082        private final NullableLazyValue<ClassDescriptorWithResolutionScopes> classObjectDescriptor;
083    
084        private final LazyClassMemberScope unsubstitutedMemberScope;
085    
086        private final NotNullLazyValue<JetScope> scopeForClassHeaderResolution;
087        private final NotNullLazyValue<JetScope> scopeForMemberDeclarationResolution;
088        private final NotNullLazyValue<JetScope> scopeForPropertyInitializerResolution;
089    
090        private final NullableLazyValue<Void> forceResolveAllContents;
091    
092        public LazyClassDescriptor(
093                @NotNull ResolveSession resolveSession,
094                @NotNull DeclarationDescriptor containingDeclaration,
095                @NotNull Name name,
096                @NotNull JetClassLikeInfo classLikeInfo
097        ) {
098            super(resolveSession.getStorageManager(), containingDeclaration, name);
099            this.resolveSession = resolveSession;
100    
101            if (classLikeInfo.getCorrespondingClassOrObject() != null) {
102                this.resolveSession.getTrace().record(BindingContext.CLASS, classLikeInfo.getCorrespondingClassOrObject(), this);
103            }
104            this.resolveSession.getTrace().record(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, DescriptorUtils.getFqName(this), this);
105    
106            this.originalClassInfo = classLikeInfo;
107            this.declarationProvider = resolveSession.getDeclarationProviderFactory().getClassMemberDeclarationProvider(classLikeInfo);
108    
109            this.unsubstitutedMemberScope = new LazyClassMemberScope(resolveSession, declarationProvider, this);
110    
111            this.typeConstructor = new LazyClassTypeConstructor();
112    
113            this.kind = classLikeInfo.getClassKind();
114    
115            JetModifierList modifierList = classLikeInfo.getModifierList();
116            if (kind.isSingleton()) {
117                this.modality = Modality.FINAL;
118            }
119            else {
120                Modality defaultModality = kind == ClassKind.TRAIT ? Modality.ABSTRACT : Modality.FINAL;
121                this.modality = resolveModalityFromModifiers(modifierList, defaultModality);
122            }
123            this.visibility = isSyntheticClassObject(this)
124                              ? DescriptorUtils.getSyntheticClassObjectVisibility()
125                              : resolveVisibilityFromModifiers(modifierList, getDefaultClassVisibility(this));
126            this.isInner = isInnerClass(modifierList);
127    
128            StorageManager storageManager = resolveSession.getStorageManager();
129            this.annotations = storageManager.createLazyValue(new Function0<Annotations>() {
130                @Override
131                public Annotations invoke() {
132                    return resolveAnnotations();
133                }
134            });
135            this.classObjectDescriptor = storageManager.createNullableLazyValue(new Function0<ClassDescriptorWithResolutionScopes>() {
136                @Override
137                public ClassDescriptorWithResolutionScopes invoke() {
138                    return computeClassObjectDescriptor();
139                }
140            });
141            this.scopeForClassHeaderResolution = storageManager.createLazyValue(new Function0<JetScope>() {
142                @Override
143                public JetScope invoke() {
144                    return computeScopeForClassHeaderResolution();
145                }
146            });
147            this.scopeForMemberDeclarationResolution = storageManager.createLazyValue(new Function0<JetScope>() {
148                @Override
149                public JetScope invoke() {
150                    return computeScopeForMemberDeclarationResolution();
151                }
152            });
153            this.scopeForPropertyInitializerResolution = storageManager.createLazyValue(new Function0<JetScope>() {
154                @Override
155                public JetScope invoke() {
156                    return computeScopeForPropertyInitializerResolution();
157                }
158            });
159            this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0<Void>() {
160                @Override
161                public Void invoke() {
162                    doForceResolveAllContents();
163                    return null;
164                }
165            }, null);
166        }
167    
168        @NotNull
169        @Override
170        public JetScope getScopeForMemberLookup() {
171            return unsubstitutedMemberScope;
172        }
173    
174        @Override
175        @NotNull
176        public JetScope getScopeForClassHeaderResolution() {
177            return scopeForClassHeaderResolution.invoke();
178        }
179    
180        @NotNull
181        private JetScope computeScopeForClassHeaderResolution() {
182            WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with type parameters for " + getName());
183            for (TypeParameterDescriptor typeParameterDescriptor : getTypeConstructor().getParameters()) {
184                scope.addClassifierDescriptor(typeParameterDescriptor);
185            }
186            scope.changeLockLevel(WritableScope.LockLevel.READING);
187    
188            PsiElement scopeAnchor = declarationProvider.getOwnerInfo().getScopeAnchor();
189    
190            return new ChainedScope(this, "ScopeForClassHeaderResolution: " + getName(),
191                    scope,
192                    getScopeProvider().getResolutionScopeForDeclaration(scopeAnchor));
193        }
194    
195        @Override
196        @NotNull
197        public JetScope getScopeForMemberDeclarationResolution() {
198            return scopeForMemberDeclarationResolution.invoke();
199        }
200    
201        @NotNull
202        private JetScope computeScopeForMemberDeclarationResolution() {
203            WritableScopeImpl thisScope = new WritableScopeImpl(JetScope.EMPTY, this, RedeclarationHandler.DO_NOTHING, "Scope with 'this' for " + getName());
204            thisScope.addLabeledDeclaration(this);
205            thisScope.changeLockLevel(WritableScope.LockLevel.READING);
206    
207            ClassDescriptor classObject = getClassObjectDescriptor();
208            JetScope classObjectAdapterScope = (classObject != null) ? new ClassObjectMixinScope(classObject) : JetScope.EMPTY;
209    
210            return new ChainedScope(
211                    this,
212                    "ScopeForMemberDeclarationResolution: " + getName(),
213                    thisScope,
214                    getScopeForMemberLookup(),
215                    getScopeForClassHeaderResolution(),
216                    classObjectAdapterScope);
217        }
218    
219        @Override
220        @NotNull
221        public JetScope getScopeForInitializerResolution() {
222            return scopeForPropertyInitializerResolution.invoke();
223        }
224    
225        @NotNull
226        @Override
227        public Collection<CallableMemberDescriptor> getDeclaredCallableMembers() {
228            //noinspection unchecked
229            return (Collection) KotlinPackage.filter(
230                    unsubstitutedMemberScope.getAllDescriptors(),
231                    new Function1<DeclarationDescriptor, Boolean>() {
232                        @Override
233                        public Boolean invoke(DeclarationDescriptor descriptor) {
234                            return descriptor instanceof CallableMemberDescriptor
235                                   && ((CallableMemberDescriptor) descriptor).getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
236                        }
237                    }
238            );
239        }
240    
241        @NotNull
242        private JetScope computeScopeForPropertyInitializerResolution() {
243            ConstructorDescriptor primaryConstructor = getUnsubstitutedPrimaryConstructor();
244            if (primaryConstructor == null) return getScopeForMemberDeclarationResolution();
245    
246            WritableScopeImpl scope = new WritableScopeImpl(JetScope.EMPTY, primaryConstructor, RedeclarationHandler.DO_NOTHING, "Scope with constructor parameters in " + getName());
247            for (ValueParameterDescriptor valueParameterDescriptor : primaryConstructor.getValueParameters()) {
248                scope.addVariableDescriptor(valueParameterDescriptor);
249            }
250            scope.changeLockLevel(WritableScope.LockLevel.READING);
251    
252            return new ChainedScope(
253                    primaryConstructor,
254                    "ScopeForPropertyInitializerResolution: " + getName(),
255                    scope, getScopeForMemberDeclarationResolution());
256        }
257    
258        @NotNull
259        @Override
260        public Collection<ConstructorDescriptor> getConstructors() {
261            return unsubstitutedMemberScope.getConstructors();
262        }
263    
264        @Override
265        public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
266            return unsubstitutedMemberScope.getPrimaryConstructor();
267        }
268    
269        @NotNull
270        @Override
271        public TypeConstructor getTypeConstructor() {
272            return typeConstructor;
273        }
274    
275        @Override
276        public ClassDescriptorWithResolutionScopes getClassObjectDescriptor() {
277            return classObjectDescriptor.invoke();
278        }
279    
280        @Nullable
281        private ClassDescriptorWithResolutionScopes computeClassObjectDescriptor() {
282            JetClassObject classObject = declarationProvider.getOwnerInfo().getClassObject();
283    
284            JetClassLikeInfo classObjectInfo = getClassObjectInfo(classObject);
285            if (classObjectInfo != null) {
286                return new LazyClassDescriptor(resolveSession, this, getClassObjectName(getName()), classObjectInfo);
287            }
288            return null;
289        }
290    
291        @Nullable
292        public JetClassLikeInfo getClassObjectInfo(JetClassObject classObject) {
293            if (classObject != null) {
294                if (getKind() != ClassKind.CLASS && getKind() != ClassKind.TRAIT && getKind() != ClassKind.ANNOTATION_CLASS || isInner()) {
295                    resolveSession.getTrace().report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
296                }
297    
298                JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
299                return JetClassInfoUtil.createClassLikeInfo(objectDeclaration);
300            }
301            else if (getKind() == ClassKind.OBJECT || getKind() == ClassKind.ENUM_ENTRY || getKind() == ClassKind.ENUM_CLASS) {
302                return new SyntheticClassObjectInfo(originalClassInfo, this);
303            }
304    
305            return null;
306        }
307    
308        @NotNull
309        @Override
310        public ClassKind getKind() {
311            return kind;
312        }
313    
314        @NotNull
315        @Override
316        public Modality getModality() {
317            return modality;
318        }
319    
320        @NotNull
321        @Override
322        public Visibility getVisibility() {
323            return visibility;
324        }
325    
326        @Override
327        public boolean isInner() {
328            return isInner;
329        }
330    
331        @NotNull
332        @Override
333        public Annotations getAnnotations() {
334            return annotations.invoke();
335        }
336    
337        @NotNull
338        private Annotations resolveAnnotations() {
339            JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
340            JetModifierList modifierList = classInfo.getModifierList();
341            if (modifierList != null) {
342                AnnotationResolver annotationResolver = resolveSession.getAnnotationResolver();
343                JetScope scopeForDeclaration = getScopeProvider().getResolutionScopeForDeclaration(classInfo.getScopeAnchor());
344                return annotationResolver.resolveAnnotationsWithArguments(scopeForDeclaration, modifierList, resolveSession.getTrace());
345            }
346            else {
347                return Annotations.EMPTY;
348            }
349        }
350    
351        @Override
352        public String toString() {
353            // not using descriptor render to preserve laziness
354            return "lazy class " + getName().toString();
355        }
356    
357        @Override
358        public void forceResolveAllContents() {
359            forceResolveAllContents.invoke();
360        }
361    
362        private void doForceResolveAllContents() {
363            ForceResolveUtil.forceResolveAllContents(getAnnotations());
364    
365            ClassDescriptor classObjectDescriptor = getClassObjectDescriptor();
366            if (classObjectDescriptor != null) {
367                ForceResolveUtil.forceResolveAllContents(classObjectDescriptor);
368            }
369    
370            getClassObjectType();
371            ForceResolveUtil.forceResolveAllContents(getConstructors());
372            getContainingDeclaration();
373            getThisAsReceiverParameter();
374            getKind();
375            getModality();
376            getName();
377            getOriginal();
378            getScopeForClassHeaderResolution();
379            getScopeForMemberDeclarationResolution();
380            ForceResolveUtil.forceResolveAllContents(getScopeForMemberLookup());
381            getScopeForInitializerResolution();
382            getUnsubstitutedInnerClassesScope();
383            ForceResolveUtil.forceResolveAllContents(getTypeConstructor());
384            getUnsubstitutedPrimaryConstructor();
385            getVisibility();
386        }
387    
388        private static class Supertypes {
389            @Mutable
390            public final Collection<JetType> trueSupertypes;
391            @Mutable
392            public final Collection<JetType> cyclicSupertypes;
393    
394            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes) {
395                this(trueSupertypes, new ArrayList<JetType>(0));
396            }
397    
398            private Supertypes(@Mutable @NotNull Collection<JetType> trueSupertypes, @Mutable @NotNull Collection<JetType> cyclicSupertypes) {
399                this.trueSupertypes = trueSupertypes;
400                this.cyclicSupertypes = cyclicSupertypes;
401            }
402    
403            @NotNull
404            public Collection<JetType> getAllSupertypes() {
405                return KotlinPackage.plus(trueSupertypes, cyclicSupertypes);
406            }
407        }
408    
409        private class LazyClassTypeConstructor implements LazyEntity, TypeConstructor {
410            private final NotNullLazyValue<Supertypes> supertypes = resolveSession.getStorageManager().createLazyValueWithPostCompute(
411                    new Function0<Supertypes>() {
412                        @Override
413                        public Supertypes invoke() {
414                            if (KotlinBuiltIns.isSpecialClassWithNoSupertypes(LazyClassDescriptor.this)) {
415                                return new Supertypes(Collections.<JetType>emptyList());
416                            }
417    
418                            JetClassLikeInfo info = declarationProvider.getOwnerInfo();
419                            if (info instanceof SyntheticClassObjectInfo) {
420                                LazyClassDescriptor descriptor = ((SyntheticClassObjectInfo) info).getClassDescriptor();
421                                if (descriptor.getKind().isSingleton()) {
422                                    return new Supertypes(Collections.singleton(descriptor.getDefaultType()));
423                                }
424                            }
425    
426                            JetClassOrObject classOrObject = info.getCorrespondingClassOrObject();
427                            if (classOrObject == null) {
428                                return new Supertypes(Collections.singleton(KotlinBuiltIns.getInstance().getAnyType()));
429                            }
430    
431                            List<JetType> allSupertypes = resolveSession.getDescriptorResolver()
432                                    .resolveSupertypes(getScopeForClassHeaderResolution(), LazyClassDescriptor.this, classOrObject,
433                                                       resolveSession.getTrace());
434    
435                            return new Supertypes(Lists.newArrayList(Collections2.filter(allSupertypes, VALID_SUPERTYPE)));
436                        }
437                    },
438                    new Function1<Boolean, Supertypes>() {
439                        @Override
440                        public Supertypes invoke(Boolean firstTime) {
441                            return new Supertypes(Collections.<JetType>emptyList());
442                        }
443                    },
444                    new Function1<Supertypes, Unit>() {
445                        @Override
446                        public Unit invoke(@NotNull Supertypes supertypes) {
447                            findAndDisconnectLoopsInTypeHierarchy(supertypes);
448                            return Unit.VALUE;
449                        }
450                    }
451            );
452    
453            private final NotNullLazyValue<List<TypeParameterDescriptor>> parameters = resolveSession.getStorageManager().createLazyValue(new Function0<List<TypeParameterDescriptor>>() {
454                @Override
455                public List<TypeParameterDescriptor> invoke() {
456                    JetClassLikeInfo classInfo = declarationProvider.getOwnerInfo();
457                    List<JetTypeParameter> typeParameters = classInfo.getTypeParameters();
458    
459                    List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>(typeParameters.size());
460                    for (int i = 0; i < typeParameters.size(); i++) {
461                        parameters.add(new LazyTypeParameterDescriptor(resolveSession, LazyClassDescriptor.this, typeParameters.get(i), i));
462                    }
463    
464                    return parameters;
465                }
466            });
467    
468            private final NullableLazyValue<Void> forceResolveAllContents =
469                    resolveSession.getStorageManager().createRecursionTolerantNullableLazyValue(new Function0<Void>() {
470                        @Override
471                        public Void invoke() {
472                            doForceResolveAllContents();
473                            return null;
474                        }
475                    }, null);
476    
477            @NotNull
478            @Override
479            public List<TypeParameterDescriptor> getParameters() {
480                return parameters.invoke();
481            }
482    
483            @NotNull
484            @Override
485            public Collection<JetType> getSupertypes() {
486                return supertypes.invoke().trueSupertypes;
487            }
488    
489            private void findAndDisconnectLoopsInTypeHierarchy(Supertypes supertypes) {
490                for (Iterator<JetType> iterator = supertypes.trueSupertypes.iterator(); iterator.hasNext(); ) {
491                    JetType supertype = iterator.next();
492                    if (isReachable(supertype.getConstructor(), this, new HashSet<TypeConstructor>())) {
493                        iterator.remove();
494                        supertypes.cyclicSupertypes.add(supertype);
495    
496                        ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
497                        if (supertypeDescriptor instanceof ClassDescriptor) {
498                            ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
499                            TypeHierarchyResolver.reportCyclicInheritanceHierarchyError(resolveSession.getTrace(), LazyClassDescriptor.this,
500                                                                                        superclass);
501                        }
502                    }
503                }
504            }
505    
506            private boolean isReachable(TypeConstructor from, TypeConstructor to, Set<TypeConstructor> visited) {
507                if (!visited.add(from)) return false;
508                Collection<JetType> supertypes = from instanceof LazyClassTypeConstructor
509                                                 ? ((LazyClassTypeConstructor) from).supertypes.invoke().getAllSupertypes()
510                                                 : from.getSupertypes();
511                for (JetType supertype : supertypes) {
512                    TypeConstructor supertypeConstructor = supertype.getConstructor();
513                    if (supertypeConstructor == to) {
514                        return true;
515                    }
516                    if (isReachable(supertypeConstructor, to, visited)) {
517                        return true;
518                    }
519                }
520                return false;
521            }
522    
523            @Override
524            public boolean isFinal() {
525                return !getModality().isOverridable();
526            }
527    
528            @Override
529            public boolean isDenotable() {
530                return true;
531            }
532    
533            @Override
534            public ClassifierDescriptor getDeclarationDescriptor() {
535                return LazyClassDescriptor.this;
536            }
537    
538            @NotNull
539            @Override
540            public Annotations getAnnotations() {
541                return Annotations.EMPTY; // TODO
542            }
543    
544            @Override
545            public String toString() {
546                return LazyClassDescriptor.this.getName().toString();
547            }
548    
549            @Override
550            public void forceResolveAllContents() {
551                forceResolveAllContents.invoke();
552            }
553    
554            private void doForceResolveAllContents() {
555                ForceResolveUtil.forceResolveAllContents(getAnnotations());
556                ForceResolveUtil.forceResolveAllContents(getSupertypes());
557                ForceResolveUtil.forceResolveAllContents(getParameters());
558            }
559        }
560    
561        @NotNull
562        private ScopeProvider getScopeProvider() {
563            return resolveSession.getScopeProvider();
564        }
565    }