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
017package org.jetbrains.jet.lang.resolve.java;
018
019import org.jetbrains.annotations.NotNull;
020import org.jetbrains.annotations.Nullable;
021import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
022import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
023import org.jetbrains.jet.lang.resolve.DescriptorUtils;
024import org.jetbrains.jet.lang.resolve.name.FqName;
025import org.jetbrains.jet.lang.types.*;
026import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
027import org.jetbrains.jet.rt.signature.JetSignatureExceptionsAdapter;
028import org.jetbrains.jet.rt.signature.JetSignatureVariance;
029import org.jetbrains.jet.rt.signature.JetSignatureVisitor;
030
031import java.util.ArrayList;
032import java.util.Collections;
033import java.util.List;
034
035public abstract class JetTypeJetSignatureReader extends JetSignatureExceptionsAdapter {
036    
037    private final JavaSemanticServices javaSemanticServices;
038    private final JavaDescriptorResolver javaDescriptorResolver;
039    private final KotlinBuiltIns kotlinBuiltIns;
040    private final TypeVariableResolver typeVariableResolver;
041
042    public JetTypeJetSignatureReader(JavaSemanticServices javaSemanticServices, KotlinBuiltIns kotlinBuiltIns, TypeVariableResolver typeVariableResolver) {
043        this.javaSemanticServices = javaSemanticServices;
044        this.javaDescriptorResolver = javaSemanticServices.getDescriptorResolver();
045        this.kotlinBuiltIns = kotlinBuiltIns;
046        this.typeVariableResolver = typeVariableResolver;
047    }
048    
049    
050    private JetType getPrimitiveType(char descriptor, boolean nullable) {
051        if (!nullable) {
052            for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
053                if (jvmPrimitiveType.getJvmLetter() == descriptor) {
054                    return KotlinBuiltIns.getInstance().getPrimitiveJetType(jvmPrimitiveType.getPrimitiveType());
055                }
056            }
057            if (descriptor == 'V') {
058                return KotlinBuiltIns.getInstance().getUnitType();
059            }
060        }
061        else {
062            for (JvmPrimitiveType jvmPrimitiveType : JvmPrimitiveType.values()) {
063                if (jvmPrimitiveType.getJvmLetter() == descriptor) {
064                    return KotlinBuiltIns.getInstance().getNullablePrimitiveJetType(jvmPrimitiveType.getPrimitiveType());
065                }
066            }
067            if (descriptor == 'V') {
068                throw new IllegalStateException("incorrect signature: nullable void");
069            }
070        }
071        throw new IllegalStateException("incorrect signature");
072    }
073
074    @Override
075    public void visitBaseType(char descriptor, boolean nullable) {
076        done(getPrimitiveType(descriptor, nullable));
077    }
078
079
080    private ClassDescriptor classDescriptor;
081    private JetType errorType;
082    private boolean nullable;
083    private List<TypeProjection> typeArguments;
084
085    @Override
086    public void visitClassType(String signatureName, boolean nullable, boolean forceReal) {
087        FqName fqName = JvmClassName.bySignatureName(signatureName).getFqName();
088
089        enterClass(resolveClassDescriptorByFqName(fqName, forceReal), fqName.asString(), nullable);
090    }
091
092    private void enterClass(@Nullable ClassDescriptor classDescriptor, @NotNull String className, boolean nullable) {
093        this.classDescriptor = classDescriptor;
094
095        if (this.classDescriptor == null) {
096            // TODO: report in to trace
097            this.errorType = ErrorUtils.createErrorType("class not found by name: " + className);
098        }
099        this.nullable = nullable;
100        this.typeArguments = new ArrayList<TypeProjection>();
101    }
102
103    @Nullable
104    private ClassDescriptor resolveClassDescriptorByFqName(FqName ourName, boolean forceReal) {
105        if (!forceReal) {
106            ClassDescriptor mappedDescriptor = JavaToKotlinClassMap.getInstance().
107                    mapKotlinClass(ourName, TypeUsage.MEMBER_SIGNATURE_INVARIANT);
108            if (mappedDescriptor != null) {
109                return mappedDescriptor;
110            }
111        }
112
113        return javaDescriptorResolver.resolveClass(ourName, DescriptorSearchRule.INCLUDE_KOTLIN);
114    }
115
116    @Override
117    public void visitInnerClassType(String signatureName, boolean nullable, boolean forceReal) {
118        JvmClassName jvmClassName = JvmClassName.bySignatureName(signatureName);
119        ClassDescriptor descriptor = resolveClassDescriptorByFqName(jvmClassName.getOuterClassFqName(), forceReal);
120        for (String innerClassName : jvmClassName.getInnerClassNameList()) {
121            descriptor = descriptor != null ? DescriptorUtils.getInnerClassByName(descriptor, innerClassName) : null;
122        }
123        enterClass(descriptor, signatureName, nullable);
124    }
125
126    private static Variance parseVariance(JetSignatureVariance variance) {
127        switch (variance) {
128            case INVARIANT: return Variance.INVARIANT;
129            case OUT: return Variance.OUT_VARIANCE;
130            case IN: return Variance.IN_VARIANCE;
131            default: throw new IllegalStateException();
132        }
133    }
134
135    @Override
136    public JetSignatureVisitor visitTypeArgument(final JetSignatureVariance variance) {
137        return new JetTypeJetSignatureReader(javaSemanticServices, kotlinBuiltIns, typeVariableResolver) {
138
139            @Override
140            protected void done(@NotNull JetType jetType) {
141                typeArguments.add(new TypeProjection(parseVariance(variance), jetType));
142            }
143        };
144    }
145
146    @Override
147    public JetSignatureVisitor visitArrayType(final boolean nullable, final JetSignatureVariance wildcard) {
148        return new JetTypeJetSignatureReader(javaSemanticServices, kotlinBuiltIns, typeVariableResolver) {
149            @Override
150            public void visitBaseType(char descriptor, boolean nullable) {
151                JetType primitiveType = getPrimitiveType(descriptor, nullable);
152                JetType arrayType;
153                if (!nullable) {
154                    arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(primitiveType);
155                }
156                else {
157                    arrayType = TypeUtils.makeNullableAsSpecified(KotlinBuiltIns.getInstance().getArrayType(primitiveType), nullable);
158                }
159                JetTypeJetSignatureReader.this.done(arrayType);
160            }
161
162            @Override
163            protected void done(@NotNull JetType jetType) {
164                JetType arrayType = TypeUtils.makeNullableAsSpecified(KotlinBuiltIns.getInstance().getArrayType(
165                        parseVariance(wildcard), jetType), nullable);
166                JetTypeJetSignatureReader.this.done(arrayType);
167            }
168        };
169    }
170
171    @Override
172    public void visitTypeVariable(String name, boolean nullable) {
173        JetType r = TypeUtils.makeNullableAsSpecified(typeVariableResolver.getTypeVariable(name).getDefaultType(), nullable);
174        done(r);
175    }
176
177    @Override
178    public void visitEnd() {
179        if ((errorType != null) == (classDescriptor != null)) {
180            throw new IllegalStateException("must initialize either errorType or classDescriptor");
181        }
182        JetType jetType;
183        if (errorType != null) {
184            jetType = errorType;
185        }
186        else {
187            jetType = new JetTypeImpl(
188                    Collections.<AnnotationDescriptor>emptyList(),
189                    classDescriptor.getTypeConstructor(),
190                    nullable,
191                    typeArguments,
192                    classDescriptor.getMemberScope(typeArguments));
193        }
194        done(jetType);
195    }
196    
197    protected abstract void done(@NotNull JetType jetType);
198}