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