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.PsiEllipsisType;
020import com.intellij.psi.PsiType;
021import org.jetbrains.annotations.NotNull;
022import org.jetbrains.annotations.Nullable;
023import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
024import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
025import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
026import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
027import org.jetbrains.jet.lang.resolve.java.*;
028import org.jetbrains.jet.lang.resolve.java.wrapper.PsiParameterWrapper;
029import org.jetbrains.jet.lang.resolve.name.Name;
030import org.jetbrains.jet.lang.types.JetType;
031import org.jetbrains.jet.lang.types.TypeUtils;
032import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033
034import javax.inject.Inject;
035import java.util.ArrayList;
036import java.util.Collections;
037import java.util.List;
038
039public final class JavaValueParameterResolver {
040
041    private JavaTypeTransformer typeTransformer;
042
043    public JavaValueParameterResolver() {
044    }
045
046    @NotNull
047    private JvmMethodParameterMeaning resolveParameterDescriptor(
048            DeclarationDescriptor containingDeclaration, int i,
049            PsiParameterWrapper parameter, TypeVariableResolver typeVariableResolver
050    ) {
051
052        if (parameter.getJetTypeParameter().isDefined()) {
053            return JvmMethodParameterMeaning.typeInfo();
054        }
055
056        PsiType psiType = parameter.getPsiParameter().getType();
057
058        // TODO: must be very slow, make it lazy?
059        Name name = Name.identifier(getParameterName(i, parameter));
060
061        if (parameter.getJetValueParameter().name().length() > 0) {
062            name = Name.identifier(parameter.getJetValueParameter().name());
063        }
064
065        String typeFromAnnotation = parameter.getJetValueParameter().type();
066        boolean receiver = parameter.getJetValueParameter().receiver();
067        boolean hasDefaultValue = parameter.getJetValueParameter().hasDefaultValue();
068
069        JetType outType;
070        if (typeFromAnnotation.length() > 0) {
071            outType = getTypeTransformer().transformToType(typeFromAnnotation, typeVariableResolver);
072        }
073        else {
074            TypeUsage typeUsage = JavaTypeTransformer.adjustTypeUsageWithMutabilityAnnotations(parameter.getPsiParameter(), TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT);
075            outType = getTypeTransformer().transformToType(psiType, typeUsage, typeVariableResolver);
076        }
077
078        JetType varargElementType;
079        if (psiType instanceof PsiEllipsisType || parameter.getJetValueParameter().vararg()) {
080            varargElementType = KotlinBuiltIns.getInstance().getArrayElementType(TypeUtils.makeNotNullable(outType));
081            outType = TypeUtils.makeNotNullable(outType);
082        }
083        else {
084            varargElementType = null;
085        }
086
087        if (receiver) {
088            return JvmMethodParameterMeaning.receiver(outType);
089        }
090        else {
091
092            JetType transformedType;
093            if (JavaAnnotationResolver.findAnnotationWithExternal(parameter.getPsiParameter(), JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION.getFqName().asString()) !=
094                null) {
095                transformedType = TypeUtils.makeNullableAsSpecified(outType, false);
096            }
097            else {
098                transformedType = outType;
099            }
100            return JvmMethodParameterMeaning.regular(new ValueParameterDescriptorImpl(
101                    containingDeclaration,
102                    i,
103                    Collections.<AnnotationDescriptor>emptyList(), // TODO
104                    name,
105                    transformedType,
106                    hasDefaultValue,
107                    varargElementType
108            ));
109        }
110    }
111
112    @NotNull
113    private JavaTypeTransformer getTypeTransformer() {
114        return typeTransformer;
115    }
116
117    @Inject
118    public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
119        this.typeTransformer = typeTransformer;
120    }
121
122    @NotNull
123    private static String getParameterName(int number, @NotNull PsiParameterWrapper parameter) {
124        String psiParameterName = parameter.getPsiParameter().getName();
125        return psiParameterName != null ? psiParameterName : "p" + number;
126    }
127
128    public JavaDescriptorResolver.ValueParameterDescriptors resolveParameterDescriptors(
129            DeclarationDescriptor containingDeclaration,
130            List<PsiParameterWrapper> parameters, TypeVariableResolver typeVariableResolver
131    ) {
132        List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
133        JetType receiverType = null;
134        int indexDelta = 0;
135        for (int i = 0, parametersLength = parameters.size(); i < parametersLength; i++) {
136            PsiParameterWrapper parameter = parameters.get(i);
137            JvmMethodParameterMeaning meaning =
138                    resolveParameterDescriptor(containingDeclaration, i + indexDelta, parameter, typeVariableResolver);
139            if (meaning.kind == JvmMethodParameterKind.TYPE_INFO) {
140                // TODO
141                --indexDelta;
142            }
143            else if (meaning.kind == JvmMethodParameterKind.REGULAR) {
144                result.add(meaning.valueParameterDescriptor);
145            }
146            else if (meaning.kind == JvmMethodParameterKind.RECEIVER) {
147                if (receiverType != null) {
148                    throw new IllegalStateException("more than one receiver");
149                }
150                --indexDelta;
151                receiverType = meaning.receiverType;
152            }
153        }
154        return new JavaDescriptorResolver.ValueParameterDescriptors(receiverType, result);
155    }
156
157    public enum JvmMethodParameterKind {
158        REGULAR,
159        RECEIVER,
160        TYPE_INFO,
161    }
162
163    public static class JvmMethodParameterMeaning {
164        public final JvmMethodParameterKind kind;
165        private final JetType receiverType;
166        private final ValueParameterDescriptor valueParameterDescriptor;
167
168        private JvmMethodParameterMeaning(
169                JvmMethodParameterKind kind,
170                @Nullable JetType receiverType,
171                @Nullable ValueParameterDescriptor valueParameterDescriptor
172        ) {
173            this.kind = kind;
174            this.receiverType = receiverType;
175            this.valueParameterDescriptor = valueParameterDescriptor;
176        }
177
178        public static JvmMethodParameterMeaning receiver(@NotNull JetType receiverType) {
179            return new JvmMethodParameterMeaning(JvmMethodParameterKind.RECEIVER, receiverType, null);
180        }
181
182        public static JvmMethodParameterMeaning regular(@NotNull ValueParameterDescriptor valueParameterDescriptor) {
183            return new JvmMethodParameterMeaning(JvmMethodParameterKind.REGULAR, null, valueParameterDescriptor);
184        }
185
186        public static JvmMethodParameterMeaning typeInfo() {
187            return new JvmMethodParameterMeaning(JvmMethodParameterKind.TYPE_INFO, null, null);
188        }
189    }
190}