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 org.jetbrains.annotations.NotNull;
020    import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
021    import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
022    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
023    import org.jetbrains.jet.lang.resolve.java.structure.JavaArrayType;
024    import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
025    import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
026    import org.jetbrains.jet.lang.resolve.java.structure.JavaValueParameter;
027    import org.jetbrains.jet.lang.resolve.name.Name;
028    import org.jetbrains.jet.lang.types.JetType;
029    import org.jetbrains.jet.lang.types.TypeUtils;
030    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
031    
032    import javax.inject.Inject;
033    import java.util.ArrayList;
034    import java.util.List;
035    
036    public final class JavaValueParameterResolver {
037        private JavaAnnotationResolver annotationResolver;
038        private JavaTypeTransformer typeTransformer;
039    
040        @Inject
041        public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
042            this.annotationResolver = annotationResolver;
043        }
044    
045        @Inject
046        public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
047            this.typeTransformer = typeTransformer;
048        }
049    
050        @NotNull
051        private ValueParameterDescriptor resolveValueParameter(
052                @NotNull DeclarationDescriptor containingDeclaration,
053                int i,
054                @NotNull JavaValueParameter parameter,
055                @NotNull TypeVariableResolver typeVariableResolver
056        ) {
057            TypeUsage typeUsage = annotationResolver.hasMutableAnnotation(parameter)
058                                  ? TypeUsage.MEMBER_SIGNATURE_COVARIANT
059                                  : TypeUsage.MEMBER_SIGNATURE_CONTRAVARIANT;
060    
061            JavaType parameterType = parameter.getType();
062    
063            JetType varargElementType;
064            JetType outType;
065            if (parameter.isVararg()) {
066                // TODO: test this code
067                assert parameterType instanceof JavaArrayType : "Vararg parameter should be an array: " + parameterType;
068                JetType arrayType = typeTransformer.transformVarargType(((JavaArrayType) parameterType), typeUsage, typeVariableResolver);
069    
070                outType = TypeUtils.makeNotNullable(arrayType);
071                varargElementType = KotlinBuiltIns.getInstance().getArrayElementType(outType);
072            }
073            else {
074                JetType transformedType = typeTransformer.transformToType(parameterType, typeUsage, typeVariableResolver);
075                if (transformedType.isNullable() && annotationResolver.hasNotNullAnnotation(parameter)) {
076                    transformedType = TypeUtils.makeNotNullable(transformedType);
077                }
078    
079                outType = transformedType;
080                varargElementType = null;
081            }
082    
083            return new ValueParameterDescriptorImpl(
084                    containingDeclaration,
085                    i,
086                    annotationResolver.resolveAnnotations(parameter),
087                    getParameterName(i, parameter), // TODO: must be very slow, make it lazy?
088                    outType,
089                    false,
090                    varargElementType
091            );
092        }
093    
094        @NotNull
095        private static Name getParameterName(int number, @NotNull JavaValueParameter parameter) {
096            Name psiParameterName = parameter.getName();
097            return psiParameterName != null ? psiParameterName : Name.identifier("p" + number);
098        }
099    
100        @NotNull
101        public List<ValueParameterDescriptor> resolveValueParameters(
102                @NotNull DeclarationDescriptor container,
103                @NotNull JavaMethod method,
104                @NotNull TypeVariableResolver typeVariableResolver
105        ) {
106            List<JavaValueParameter> parameters = method.getValueParameters();
107            List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>(parameters.size());
108            for (int i = 0, size = parameters.size(); i < size; i++) {
109                result.add(resolveValueParameter(container, i, parameters.get(i), typeVariableResolver));
110            }
111            return result;
112        }
113    }