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