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.descriptors.impl;
018    
019    import jet.Function0;
020    import org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.resolve.name.Name;
024    import org.jetbrains.jet.lang.resolve.scopes.InnerClassesScopeWrapper;
025    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
026    import org.jetbrains.jet.lang.resolve.scopes.SubstitutingScope;
027    import org.jetbrains.jet.lang.types.*;
028    import org.jetbrains.jet.storage.NotNullLazyValue;
029    import org.jetbrains.jet.storage.StorageManager;
030    
031    import java.util.List;
032    import java.util.Map;
033    
034    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass;
035    
036    public abstract class AbstractClassDescriptor implements ClassDescriptor {
037        private final Name name;
038        protected final NotNullLazyValue<JetType> defaultType;
039        private final NotNullLazyValue<JetScope> unsubstitutedInnerClassesScope;
040        private final NotNullLazyValue<ReceiverParameterDescriptor> thisAsReceiverParameter;
041    
042        public AbstractClassDescriptor(@NotNull StorageManager storageManager, @NotNull Name name) {
043            this.name = name;
044            this.defaultType = storageManager.createLazyValue(new Function0<JetType>() {
045                @Override
046                public JetType invoke() {
047                    return TypeUtils.makeUnsubstitutedType(AbstractClassDescriptor.this, getScopeForMemberLookup());
048                }
049            });
050            this.unsubstitutedInnerClassesScope = storageManager.createLazyValue(new Function0<JetScope>() {
051                @Override
052                public JetScope invoke() {
053                    return new InnerClassesScopeWrapper(getScopeForMemberLookup());
054                }
055            });
056            this.thisAsReceiverParameter = storageManager.createLazyValue(new Function0<ReceiverParameterDescriptor>() {
057                @Override
058                public ReceiverParameterDescriptor invoke() {
059                    return new LazyClassReceiverParameterDescriptor(AbstractClassDescriptor.this);
060                }
061            });
062        }
063    
064        @NotNull
065        @Override
066        public Name getName() {
067            return name;
068        }
069    
070        @NotNull
071        @Override
072        public DeclarationDescriptor getOriginal() {
073            return this;
074        }
075    
076        @NotNull
077        protected abstract JetScope getScopeForMemberLookup();
078    
079        @Nullable
080        @Override
081        public JetType getClassObjectType() {
082            if (getKind() == ClassKind.OBJECT) {
083                return getDefaultType();
084            }
085    
086            if (getKind() == ClassKind.ENUM_ENTRY) {
087                DeclarationDescriptor enumClass = getContainingDeclaration();
088                assert isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + this;
089                return ((ClassDescriptor) enumClass).getDefaultType();
090            }
091    
092            ClassDescriptor classObject = getClassObjectDescriptor();
093            return classObject == null ? null : classObject.getDefaultType();
094        }
095    
096        @NotNull
097        @Override
098        public JetScope getUnsubstitutedInnerClassesScope() {
099            return unsubstitutedInnerClassesScope.invoke();
100        }
101    
102        @NotNull
103        @Override
104        public ReceiverParameterDescriptor getThisAsReceiverParameter() {
105            return thisAsReceiverParameter.invoke();
106        }
107    
108        @NotNull
109        @Override
110        public JetScope getMemberScope(List<? extends TypeProjection> typeArguments) {
111            assert typeArguments.size() == getTypeConstructor().getParameters().size() : "Illegal number of type arguments: expected "
112                                                                                         + getTypeConstructor().getParameters().size() + " but was " + typeArguments.size()
113                                                                                         + " for " + getTypeConstructor() + " " + getTypeConstructor().getParameters();
114            if (typeArguments.isEmpty()) return getScopeForMemberLookup();
115    
116            List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
117            Map<TypeConstructor, TypeProjection> substitutionContext = SubstitutionUtils.buildSubstitutionContext(typeParameters, typeArguments);
118    
119            // Unsafe substitutor is OK, because no recursion can hurt us upon a trivial substitution:
120            // all the types are written explicitly in the code already, they can not get infinite.
121            // One exception is *-projections, but they need to be handled separately anyways.
122            TypeSubstitutor substitutor = TypeSubstitutor.createUnsafe(substitutionContext);
123            return new SubstitutingScope(getScopeForMemberLookup(), substitutor);
124        }
125    
126        @NotNull
127        @Override
128        public ClassDescriptor substitute(@NotNull TypeSubstitutor substitutor) {
129            if (substitutor.isEmpty()) {
130                return this;
131            }
132            return new LazySubstitutingClassDescriptor(this, substitutor);
133        }
134    
135        @NotNull
136        @Override
137        public JetType getDefaultType() {
138            return defaultType.invoke();
139        }
140    
141        @Override
142        public void acceptVoid(DeclarationDescriptorVisitor<Void, Void> visitor) {
143            visitor.visitClassDescriptor(this, null);
144        }
145    
146        @Override
147        public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
148            return visitor.visitClassDescriptor(this, data);
149        }
150    }