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.java;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
022    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
023    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
024    import org.jetbrains.jet.lang.resolve.name.FqName;
025    import org.jetbrains.jet.lang.types.*;
026    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
027    import org.jetbrains.jet.rt.signature.JetSignatureExceptionsAdapter;
028    import org.jetbrains.jet.rt.signature.JetSignatureVariance;
029    import org.jetbrains.jet.rt.signature.JetSignatureVisitor;
030    
031    import java.util.ArrayList;
032    import java.util.Collections;
033    import java.util.List;
034    
035    public 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    }