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.resolver;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.psi.*;
021    import jet.typeinfo.TypeInfoVariance;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
027    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028    import org.jetbrains.jet.lang.resolve.java.*;
029    import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation;
030    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
031    import org.jetbrains.jet.lang.resolve.name.Name;
032    import org.jetbrains.jet.lang.types.JetType;
033    import org.jetbrains.jet.lang.types.Variance;
034    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
035    import org.jetbrains.jet.rt.signature.JetSignatureAdapter;
036    import org.jetbrains.jet.rt.signature.JetSignatureExceptionsAdapter;
037    import org.jetbrains.jet.rt.signature.JetSignatureReader;
038    import org.jetbrains.jet.rt.signature.JetSignatureVisitor;
039    
040    import javax.inject.Inject;
041    import java.util.ArrayList;
042    import java.util.Collections;
043    import java.util.List;
044    
045    public 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    }