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.google.common.collect.Lists;
020import com.intellij.psi.*;
021import jet.typeinfo.TypeInfoVariance;
022import org.jetbrains.annotations.NotNull;
023import org.jetbrains.annotations.Nullable;
024import org.jetbrains.jet.lang.descriptors.*;
025import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
027import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028import org.jetbrains.jet.lang.resolve.java.*;
029import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation;
030import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
031import org.jetbrains.jet.lang.resolve.name.Name;
032import org.jetbrains.jet.lang.types.JetType;
033import org.jetbrains.jet.lang.types.Variance;
034import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
035import org.jetbrains.jet.rt.signature.JetSignatureAdapter;
036import org.jetbrains.jet.rt.signature.JetSignatureExceptionsAdapter;
037import org.jetbrains.jet.rt.signature.JetSignatureReader;
038import org.jetbrains.jet.rt.signature.JetSignatureVisitor;
039
040import javax.inject.Inject;
041import java.util.ArrayList;
042import java.util.Collections;
043import java.util.List;
044
045public final class JavaSignatureResolver {
046
047    @NotNull
048    private JavaSemanticServices semanticServices;
049
050    @Inject
051    public void setJavaSemanticServices(@NotNull JavaSemanticServices javaSemanticServices) {
052        this.semanticServices = javaSemanticServices;
053    }
054
055    private static boolean isJavaLangObject(@NotNull JetType type) {
056        ClassifierDescriptor classifierDescriptor = type.getConstructor().getDeclarationDescriptor();
057        return classifierDescriptor instanceof ClassDescriptor &&
058               DescriptorUtils.getFQName(classifierDescriptor).equalsTo(DescriptorResolverUtils.OBJECT_FQ_NAME);
059    }
060
061    private enum TypeParameterDescriptorOrigin {
062        JAVA,
063        KOTLIN,
064    }
065
066    public static class TypeParameterDescriptorInitialization {
067        @NotNull
068        private final TypeParameterDescriptorOrigin origin;
069        @NotNull
070        private final TypeParameterDescriptorImpl descriptor;
071        private final PsiTypeParameter psiTypeParameter;
072        @Nullable
073        private final List<JetType> upperBoundsForKotlin;
074
075        private TypeParameterDescriptorInitialization(@NotNull TypeParameterDescriptorImpl descriptor, @NotNull PsiTypeParameter psiTypeParameter) {
076            this.origin = TypeParameterDescriptorOrigin.JAVA;
077            this.descriptor = descriptor;
078            this.psiTypeParameter = psiTypeParameter;
079            this.upperBoundsForKotlin = null;
080        }
081
082        private TypeParameterDescriptorInitialization(
083                @NotNull TypeParameterDescriptorImpl descriptor, @NotNull PsiTypeParameter psiTypeParameter,
084                @Nullable List<JetType> upperBoundsForKotlin
085        ) {
086            this.origin = TypeParameterDescriptorOrigin.KOTLIN;
087            this.descriptor = descriptor;
088            this.psiTypeParameter = psiTypeParameter;
089            this.upperBoundsForKotlin = upperBoundsForKotlin;
090        }
091
092        @NotNull
093        public TypeParameterDescriptorImpl getDescriptor() {
094            return descriptor;
095        }
096    }
097
098
099
100    @NotNull
101    private static PsiTypeParameter getPsiTypeParameterByName(PsiTypeParameterListOwner clazz, String name) {
102        for (PsiTypeParameter typeParameter : clazz.getTypeParameters()) {
103            if (typeParameter.getName().equals(name)) {
104                return typeParameter;
105            }
106        }
107        throw new IllegalStateException("PsiTypeParameter '" + name + "' is not found");
108    }
109
110
111
112    private abstract class JetSignatureTypeParameterVisitor extends JetSignatureExceptionsAdapter {
113
114        @NotNull
115        private final PsiTypeParameterListOwner psiOwner;
116        @NotNull
117        private final String name;
118        @NotNull
119        private final TypeVariableResolver typeVariableResolver;
120        @NotNull
121        private final TypeParameterDescriptorImpl typeParameterDescriptor;
122
123        protected JetSignatureTypeParameterVisitor(
124                @NotNull PsiTypeParameterListOwner psiOwner,
125                @NotNull String name,
126                @NotNull TypeVariableResolver typeVariableResolver,
127                @NotNull TypeParameterDescriptorImpl typeParameterDescriptor)
128        {
129            if (name.isEmpty()) {
130                throw new IllegalStateException();
131            }
132
133            this.psiOwner = psiOwner;
134            this.name = name;
135            this.typeVariableResolver = typeVariableResolver;
136            this.typeParameterDescriptor = typeParameterDescriptor;
137        }
138
139        List<JetType> upperBounds = new ArrayList<JetType>();
140
141        @Override
142        public JetSignatureVisitor visitClassBound() {
143            return new JetTypeJetSignatureReader(semanticServices, KotlinBuiltIns.getInstance(), typeVariableResolver) {
144                @Override
145                protected void done(@NotNull JetType jetType) {
146                    if (isJavaLangObject(jetType)) {
147                        return;
148                    }
149                    upperBounds.add(jetType);
150                }
151            };
152        }
153
154        @Override
155        public JetSignatureVisitor visitInterfaceBound() {
156            return new JetTypeJetSignatureReader(semanticServices, KotlinBuiltIns.getInstance(), typeVariableResolver) {
157                @Override
158                protected void done(@NotNull JetType jetType) {
159                    upperBounds.add(jetType);
160                }
161            };
162        }
163
164        @Override
165        public void visitFormalTypeParameterEnd() {
166            PsiTypeParameter psiTypeParameter = getPsiTypeParameterByName(psiOwner, name);
167            TypeParameterDescriptorInitialization typeParameterDescriptorInitialization = new TypeParameterDescriptorInitialization(typeParameterDescriptor, psiTypeParameter, upperBounds);
168            done(typeParameterDescriptorInitialization);
169        }
170
171        protected abstract void done(@NotNull TypeParameterDescriptorInitialization typeParameterDescriptor);
172    }
173
174    private class JetSignatureTypeParametersVisitor extends JetSignatureExceptionsAdapter {
175        @NotNull
176        private final DeclarationDescriptor containingDeclaration;
177        @NotNull
178        private final PsiTypeParameterListOwner psiOwner;
179
180        private final List<TypeParameterDescriptor> previousTypeParameters = new ArrayList<TypeParameterDescriptor>();
181        // note changes state in this method
182        private final TypeVariableResolver typeVariableResolver;
183
184
185        private JetSignatureTypeParametersVisitor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull PsiTypeParameterListOwner psiOwner, @NotNull String context) {
186            this.containingDeclaration = containingDeclaration;
187            this.psiOwner = psiOwner;
188
189            this.typeVariableResolver = TypeVariableResolvers.typeVariableResolverFromTypeParameters(
190                    previousTypeParameters,
191                    containingDeclaration,
192                    context);
193        }
194
195        private int formalTypeParameterIndex = 0;
196
197
198        List<TypeParameterDescriptorInitialization> r = new ArrayList<TypeParameterDescriptorInitialization>();
199
200        @Override
201        public JetSignatureVisitor visitFormalTypeParameter(final String name, TypeInfoVariance variance, boolean reified) {
202            TypeParameterDescriptorImpl typeParameter = TypeParameterDescriptorImpl.createForFurtherModification(
203                    containingDeclaration,
204                    Collections.<AnnotationDescriptor>emptyList(), // TODO: wrong
205                    reified,
206                    JetSignatureUtils.translateVariance(variance),
207                    Name.identifier(name),
208                    formalTypeParameterIndex++);
209
210            previousTypeParameters.add(typeParameter);
211
212            return new JetSignatureTypeParameterVisitor(psiOwner, name, typeVariableResolver, typeParameter) {
213                @Override
214                protected void done(@NotNull TypeParameterDescriptorInitialization typeParameterDescriptor) {
215                    r.add(typeParameterDescriptor);
216                    previousTypeParameters.add(typeParameterDescriptor.descriptor);
217                }
218            };
219        }
220    }
221
222        /**
223     * @see #resolveMethodTypeParametersFromJetSignature(String, PsiMethod, DeclarationDescriptor)
224     */
225    private List<TypeParameterDescriptorInitialization> resolveClassTypeParametersFromJetSignature(String jetSignature,
226            final PsiClass clazz, final ClassDescriptor classDescriptor) {
227        String context = "class " + clazz.getQualifiedName();
228        JetSignatureTypeParametersVisitor jetSignatureTypeParametersVisitor = new JetSignatureTypeParametersVisitor(classDescriptor, clazz, context) {
229            @Override
230            public JetSignatureVisitor visitSuperclass() {
231                // TODO
232                return new JetSignatureAdapter();
233            }
234
235            @Override
236            public JetSignatureVisitor visitInterface() {
237                // TODO
238                return new JetSignatureAdapter();
239            }
240        };
241        new JetSignatureReader(jetSignature).accept(jetSignatureTypeParametersVisitor);
242        return jetSignatureTypeParametersVisitor.r;
243    }
244
245
246        private static List<TypeParameterDescriptorInitialization> makeUninitializedTypeParameters(
247                @NotNull DeclarationDescriptor containingDeclaration,
248                @NotNull PsiTypeParameter[] typeParameters
249        ) {
250        List<TypeParameterDescriptorInitialization> result = Lists.newArrayList();
251        for (PsiTypeParameter typeParameter : typeParameters) {
252            TypeParameterDescriptorInitialization typeParameterDescriptor = makeUninitializedTypeParameter(containingDeclaration, typeParameter);
253            result.add(typeParameterDescriptor);
254        }
255        return result;
256    }
257
258    @NotNull
259    private static TypeParameterDescriptorInitialization makeUninitializedTypeParameter(
260            @NotNull DeclarationDescriptor containingDeclaration,
261            @NotNull PsiTypeParameter psiTypeParameter
262    ) {
263        TypeParameterDescriptorImpl typeParameterDescriptor = TypeParameterDescriptorImpl.createForFurtherModification(
264                containingDeclaration,
265                Collections.<AnnotationDescriptor>emptyList(), // TODO
266                false,
267                Variance.INVARIANT,
268                Name.identifier(psiTypeParameter.getName()),
269                psiTypeParameter.getIndex()
270        );
271        return new TypeParameterDescriptorInitialization(typeParameterDescriptor, psiTypeParameter);
272    }
273
274    private void initializeTypeParameter(TypeParameterDescriptorInitialization typeParameter, TypeVariableResolver typeVariableByPsiResolver) {
275        TypeParameterDescriptorImpl typeParameterDescriptor = typeParameter.descriptor;
276        if (typeParameter.origin == TypeParameterDescriptorOrigin.KOTLIN) {
277            List<JetType> upperBoundsForKotlin = typeParameter.upperBoundsForKotlin;
278            assert upperBoundsForKotlin != null;
279            if (upperBoundsForKotlin.size() == 0){
280                typeParameterDescriptor.addUpperBound(KotlinBuiltIns.getInstance().getNullableAnyType());
281            }
282            else {
283                for (JetType upperBound : upperBoundsForKotlin) {
284                    typeParameterDescriptor.addUpperBound(upperBound);
285                }
286            }
287
288            // TODO: lower bounds
289        }
290        else {
291            PsiClassType[] referencedTypes = typeParameter.psiTypeParameter.getExtendsList().getReferencedTypes();
292            if (referencedTypes.length == 0){
293                typeParameterDescriptor.addUpperBound(KotlinBuiltIns.getInstance().getNullableAnyType());
294            }
295            else if (referencedTypes.length == 1) {
296                typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedTypes[0], TypeUsage.UPPER_BOUND, typeVariableByPsiResolver));
297            }
298            else {
299                for (PsiClassType referencedType : referencedTypes) {
300                    typeParameterDescriptor.addUpperBound(semanticServices.getTypeTransformer().transformToType(referencedType, TypeUsage.UPPER_BOUND, typeVariableByPsiResolver));
301                }
302            }
303        }
304        typeParameterDescriptor.setInitialized();
305    }
306
307    public void initializeTypeParameters(
308            List<TypeParameterDescriptorInitialization> typeParametersInitialization,
309            @NotNull DeclarationDescriptor typeParametersOwner,
310            @NotNull String context
311    ) {
312        List<TypeParameterDescriptor> prevTypeParameters = Lists.newArrayList();
313
314        List<TypeParameterDescriptor> typeParameters = Lists.newArrayList();
315        for (TypeParameterDescriptorInitialization typeParameterDescriptor : typeParametersInitialization) {
316            typeParameters.add(typeParameterDescriptor.descriptor);
317        }
318
319        for (TypeParameterDescriptorInitialization psiTypeParameter : typeParametersInitialization) {
320            prevTypeParameters.add(psiTypeParameter.descriptor);
321            initializeTypeParameter(psiTypeParameter,
322                    TypeVariableResolvers.typeVariableResolverFromTypeParameters(typeParameters, typeParametersOwner, context));
323        }
324    }
325
326
327    public List<TypeParameterDescriptorInitialization> createUninitializedClassTypeParameters(
328            PsiClass psiClass, ClassDescriptor classDescriptor
329    ) {
330        JetClassAnnotation jetClassAnnotation = JetClassAnnotation.get(psiClass);
331
332        if (jetClassAnnotation.signature().length() > 0) {
333            return resolveClassTypeParametersFromJetSignature(
334                    jetClassAnnotation.signature(), psiClass, classDescriptor);
335        }
336
337        return makeUninitializedTypeParameters(classDescriptor, psiClass.getTypeParameters());
338    }
339
340
341    public List<TypeParameterDescriptor> resolveMethodTypeParameters(
342            @NotNull PsiMethodWrapper method,
343            @NotNull DeclarationDescriptor functionDescriptor
344    ) {
345
346        List<TypeParameterDescriptorInitialization> typeParametersIntialization;
347        PsiMethod psiMethod = method.getPsiMethod();
348        if (method.getJetMethodAnnotation().typeParameters().length() > 0) {
349            typeParametersIntialization = resolveMethodTypeParametersFromJetSignature(
350                    method.getJetMethodAnnotation().typeParameters(), psiMethod, functionDescriptor);
351        }
352        else {
353            typeParametersIntialization = makeUninitializedTypeParameters(functionDescriptor, psiMethod.getTypeParameters());
354        }
355
356        PsiClass psiMethodContainingClass = psiMethod.getContainingClass();
357        assert psiMethodContainingClass != null;
358        String context = "method " + method.getName() + " in class " + psiMethodContainingClass.getQualifiedName();
359        initializeTypeParameters(typeParametersIntialization, functionDescriptor, context);
360
361        List<TypeParameterDescriptor> typeParameters = Lists.newArrayListWithCapacity(typeParametersIntialization.size());
362
363        for (TypeParameterDescriptorInitialization tpdi : typeParametersIntialization) {
364            typeParameters.add(tpdi.descriptor);
365        }
366
367        return typeParameters;
368    }
369
370    /**
371     * @see #resolveClassTypeParametersFromJetSignature(String, PsiClass, ClassDescriptor)
372     */
373    private List<TypeParameterDescriptorInitialization> resolveMethodTypeParametersFromJetSignature(String jetSignature,
374            PsiMethod method, DeclarationDescriptor functionDescriptor)
375    {
376        PsiClass methodContainingClass = method.getContainingClass();
377        assert methodContainingClass != null;
378        String context = "method " + method.getName() + " in class " + methodContainingClass.getQualifiedName();
379        JetSignatureTypeParametersVisitor jetSignatureTypeParametersVisitor = new JetSignatureTypeParametersVisitor(functionDescriptor, method, context);
380        new JetSignatureReader(jetSignature).acceptFormalTypeParametersOnly(jetSignatureTypeParametersVisitor);
381        return jetSignatureTypeParametersVisitor.r;
382    }
383
384}