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.intellij.psi.PsiEllipsisType;
020    import com.intellij.psi.PsiType;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
024    import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
025    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
026    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
027    import org.jetbrains.jet.lang.resolve.java.*;
028    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiParameterWrapper;
029    import org.jetbrains.jet.lang.resolve.name.Name;
030    import org.jetbrains.jet.lang.types.JetType;
031    import org.jetbrains.jet.lang.types.TypeUtils;
032    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033    
034    import javax.inject.Inject;
035    import java.util.ArrayList;
036    import java.util.Collections;
037    import java.util.List;
038    
039    public 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    }