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.resolver;
018
019import com.intellij.psi.PsiClass;
020import com.intellij.psi.PsiClassType;
021import jet.typeinfo.TypeInfoVariance;
022import org.jetbrains.annotations.NotNull;
023import org.jetbrains.annotations.Nullable;
024import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
025import org.jetbrains.jet.lang.descriptors.ClassKind;
026import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
027import org.jetbrains.jet.lang.resolve.BindingContext;
028import org.jetbrains.jet.lang.resolve.BindingTrace;
029import org.jetbrains.jet.lang.resolve.java.*;
030import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider;
031import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
032import org.jetbrains.jet.lang.types.ErrorUtils;
033import org.jetbrains.jet.lang.types.JetType;
034import org.jetbrains.jet.lang.types.TypeUtils;
035import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036import org.jetbrains.jet.rt.signature.JetSignatureAdapter;
037import org.jetbrains.jet.rt.signature.JetSignatureExceptionsAdapter;
038import org.jetbrains.jet.rt.signature.JetSignatureReader;
039import org.jetbrains.jet.rt.signature.JetSignatureVisitor;
040
041import javax.inject.Inject;
042import java.util.ArrayList;
043import java.util.Collection;
044import java.util.List;
045
046import static org.jetbrains.jet.lang.resolve.java.provider.DeclarationOrigin.KOTLIN;
047
048public final class JavaSupertypeResolver {
049
050    private BindingTrace trace;
051    private JavaSemanticServices semanticServices;
052    private JavaTypeTransformer typeTransformer;
053    private JavaClassResolver classResolver;
054
055    @Inject
056    public void setTrace(BindingTrace trace) {
057        this.trace = trace;
058    }
059
060    @Inject
061    public void setSemanticServices(JavaSemanticServices semanticServices) {
062        this.semanticServices = semanticServices;
063    }
064
065    @Inject
066    public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
067        this.typeTransformer = typeTransformer;
068    }
069
070    @Inject
071    public void setClassResolver(JavaClassResolver classResolver) {
072        this.classResolver = classResolver;
073    }
074
075    public Collection<JetType> getSupertypes(
076            @NotNull ClassDescriptor classDescriptor,
077            @NotNull PsiClassWrapper psiClass,
078            @NotNull ClassPsiDeclarationProvider classData,
079            @NotNull List<TypeParameterDescriptor> typeParameters
080    ) {
081
082        List<JetType> result = new ArrayList<JetType>();
083
084        String context = "class " + psiClass.getQualifiedName();
085
086        if (psiClass.getJetClass().signature().length() > 0) {
087            readSuperTypes(psiClass, typeParameters, classDescriptor, result, context);
088        }
089        else {
090            TypeVariableResolver typeVariableResolverForSupertypes =
091                    TypeVariableResolvers.typeVariableResolverFromTypeParameters(typeParameters, classDescriptor, context);
092            transformSupertypeList(result, psiClass.getPsiClass().getExtendsListTypes(), typeVariableResolverForSupertypes);
093            transformSupertypeList(result, psiClass.getPsiClass().getImplementsListTypes(), typeVariableResolverForSupertypes);
094        }
095
096        reportIncompleteHierarchyForErrorTypes(classDescriptor, result);
097
098        if (result.isEmpty()) {
099            addBaseClass(psiClass, classData, classDescriptor, result);
100        }
101        return result;
102    }
103
104    private void readSuperTypes(
105            PsiClassWrapper psiClass,
106            List<TypeParameterDescriptor> typeParameters,
107            ClassDescriptor classDescriptor,
108            final List<JetType> result,
109            String context
110    ) {
111        final TypeVariableResolver typeVariableResolver =
112                TypeVariableResolvers.typeVariableResolverFromTypeParameters(typeParameters, classDescriptor, context);
113
114        new JetSignatureReader(psiClass.getJetClass().signature()).accept(new JetSignatureExceptionsAdapter() {
115            @Override
116            public JetSignatureVisitor visitFormalTypeParameter(String name, TypeInfoVariance variance, boolean reified) {
117                // TODO: collect
118                return new JetSignatureAdapter();
119            }
120
121            @Override
122            public JetSignatureVisitor visitSuperclass() {
123                return new JetTypeJetSignatureReader(semanticServices, KotlinBuiltIns.getInstance(),
124                                                     typeVariableResolver) {
125                    @Override
126                    protected void done(@NotNull JetType jetType) {
127                        if (!jetType.equals(KotlinBuiltIns.getInstance().getAnyType())) {
128                            result.add(jetType);
129                        }
130                    }
131                };
132            }
133
134            @Override
135            public JetSignatureVisitor visitInterface() {
136                return visitSuperclass();
137            }
138        });
139    }
140
141    private void addBaseClass(
142            @NotNull PsiClassWrapper psiClass,
143            @NotNull ClassPsiDeclarationProvider classData,
144            @NotNull ClassDescriptor classDescriptor,
145            @NotNull List<JetType> result
146    ) {
147        if (classData.getDeclarationOrigin() == KOTLIN
148            || DescriptorResolverUtils.OBJECT_FQ_NAME.equalsTo(psiClass.getQualifiedName())
149            // TODO: annotations
150            || classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
151            result.add(KotlinBuiltIns.getInstance().getAnyType());
152        }
153        else {
154            ClassDescriptor object = resolveJavaLangObject();
155            if (object != null) {
156                result.add(object.getDefaultType());
157            }
158            else {
159                //TODO: hack here
160                result.add(KotlinBuiltIns.getInstance().getAnyType());
161               // throw new IllegalStateException("Could not resolve java.lang.Object");
162            }
163        }
164    }
165
166    private void reportIncompleteHierarchyForErrorTypes(ClassDescriptor classDescriptor, List<JetType> result) {
167        for (JetType supertype : result) {
168            if (ErrorUtils.isErrorType(supertype)) {
169                trace.record(BindingContext.INCOMPLETE_HIERARCHY, classDescriptor);
170            }
171        }
172    }
173
174    private void transformSupertypeList(
175            List<JetType> result,
176            PsiClassType[] extendsListTypes,
177            TypeVariableResolver typeVariableResolver
178    ) {
179        for (PsiClassType type : extendsListTypes) {
180            PsiClass resolved = type.resolve();
181            if (resolved != null) {
182                String qualifiedName = resolved.getQualifiedName();
183                assert qualifiedName != null;
184                if (JvmStdlibNames.JET_OBJECT.getFqName().equalsTo(qualifiedName)) {
185                    continue;
186                }
187            }
188
189            JetType transform = typeTransformer
190                    .transformToType(type, TypeUsage.SUPERTYPE, typeVariableResolver);
191            if (ErrorUtils.isErrorType(transform)) {
192                continue;
193            }
194
195            result.add(TypeUtils.makeNotNullable(transform));
196        }
197    }
198
199
200    @Nullable
201    private ClassDescriptor resolveJavaLangObject() {
202        ClassDescriptor clazz = classResolver.resolveClass(DescriptorResolverUtils.OBJECT_FQ_NAME,
203                                                           DescriptorSearchRule.IGNORE_IF_FOUND_IN_KOTLIN);
204        if (clazz == null) {
205            // TODO: warning
206        }
207        return clazz;
208    }
209}