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