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