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.google.common.collect.Lists;
020    import com.intellij.psi.*;
021    import com.intellij.util.containers.ContainerUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
027    import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl;
028    import org.jetbrains.jet.lang.resolve.BindingContext;
029    import org.jetbrains.jet.lang.resolve.BindingTrace;
030    import org.jetbrains.jet.lang.resolve.DescriptorResolver;
031    import org.jetbrains.jet.lang.resolve.java.*;
032    import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData;
033    import org.jetbrains.jet.lang.resolve.java.kt.JetConstructorAnnotation;
034    import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider;
035    import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
036    import org.jetbrains.jet.lang.resolve.name.Name;
037    import org.jetbrains.jet.lang.types.JetType;
038    
039    import javax.inject.Inject;
040    import java.util.Collection;
041    import java.util.Collections;
042    import java.util.List;
043    
044    import static org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver.recordSamAdapter;
045    import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.createSamAdapterConstructor;
046    import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.isSamAdapterNecessary;
047    
048    public final class JavaConstructorResolver {
049        private BindingTrace trace;
050        private JavaTypeTransformer typeTransformer;
051        private JavaValueParameterResolver valueParameterResolver;
052    
053        public JavaConstructorResolver() {
054        }
055    
056        @Inject
057        public void setTrace(BindingTrace trace) {
058            this.trace = trace;
059        }
060    
061        @Inject
062        public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
063            this.typeTransformer = typeTransformer;
064        }
065    
066        @Inject
067        public void setValueParameterResolver(JavaValueParameterResolver valueParameterResolver) {
068            this.valueParameterResolver = valueParameterResolver;
069        }
070    
071        @NotNull
072        public Collection<ConstructorDescriptor> resolveConstructors(
073                @NotNull ClassPsiDeclarationProvider classData, @NotNull ClassDescriptor containingClass
074        ) {
075            Collection<ConstructorDescriptor> constructors = Lists.newArrayList();
076    
077            PsiClass psiClass = classData.getPsiClass();
078    
079            TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver(
080                    containingClass, "class " + psiClass.getQualifiedName());
081    
082            List<TypeParameterDescriptor> typeParameters = containingClass.getTypeConstructor().getParameters();
083    
084            PsiMethod[] psiConstructors = psiClass.getConstructors();
085    
086            boolean isStatic = psiClass.hasModifierProperty(PsiModifier.STATIC);
087            if (containingClass.getKind() == ClassKind.OBJECT || containingClass.getKind() == ClassKind.CLASS_OBJECT) {
088                constructors.add(DescriptorResolver.createPrimaryConstructorForObject(containingClass));
089            }
090            else if (psiConstructors.length == 0) {
091                if (trace.get(BindingContext.CONSTRUCTOR, psiClass) != null) {
092                    constructors.add(trace.get(BindingContext.CONSTRUCTOR, psiClass));
093                }
094                else {
095                    Visibility constructorVisibility = DescriptorResolverUtils.getConstructorVisibility(containingClass);
096                    // We need to create default constructors for classes and abstract classes.
097                    // Example:
098                    // class Kotlin() : Java() {}
099                    // abstract public class Java {}
100                    if (!psiClass.isInterface()) {
101                        ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
102                                containingClass,
103                                Collections.<AnnotationDescriptor>emptyList(),
104                                true);
105                        constructorDescriptor.initialize(typeParameters, Collections.<ValueParameterDescriptor>emptyList(), constructorVisibility, isStatic);
106                        constructors.add(constructorDescriptor);
107                        trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
108                    }
109                    if (psiClass.isAnnotationType()) {
110                        // A constructor for an annotation type takes all the "methods" in the @interface as parameters
111                        ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
112                                containingClass,
113                                Collections.<AnnotationDescriptor>emptyList(),
114                                true);
115    
116                        List<ValueParameterDescriptor> valueParameters = Lists.newArrayList();
117                        PsiMethod[] methods = psiClass.getMethods();
118                        for (int i = 0; i < methods.length; i++) {
119                            PsiMethod method = methods[i];
120                            if (method instanceof PsiAnnotationMethod) {
121                                PsiAnnotationMethod annotationMethod = (PsiAnnotationMethod) method;
122                                assert annotationMethod.getParameterList().getParameters().length == 0;
123    
124                                PsiType returnType = annotationMethod.getReturnType();
125    
126                                // We take the following heuristical convention:
127                                // if the last method of the @interface is an array, we convert it into a vararg
128                                JetType varargElementType = null;
129                                if (i == methods.length - 1 && (returnType instanceof PsiArrayType)) {
130                                    varargElementType = typeTransformer
131                                            .transformToType(((PsiArrayType) returnType).getComponentType(), resolverForTypeParameters);
132                                }
133    
134                                assert returnType != null;
135                                valueParameters.add(new ValueParameterDescriptorImpl(
136                                        constructorDescriptor,
137                                        i,
138                                        Collections.<AnnotationDescriptor>emptyList(),
139                                        Name.identifier(method.getName()),
140                                        typeTransformer.transformToType(returnType, resolverForTypeParameters),
141                                        annotationMethod.getDefaultValue() != null,
142                                        varargElementType));
143                            }
144                        }
145    
146                        constructorDescriptor.initialize(typeParameters, valueParameters, constructorVisibility, isStatic);
147                        constructors.add(constructorDescriptor);
148                        trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
149                    }
150                }
151            }
152            else {
153                for (PsiMethod psiConstructor : psiConstructors) {
154                    ConstructorDescriptor constructor = resolveConstructor(psiClass, isStatic, psiConstructor, containingClass);
155                    if (constructor != null) {
156                        constructors.add(constructor);
157                        ContainerUtil.addIfNotNull(constructors, resolveSamAdapter(constructor));
158                    }
159                }
160            }
161    
162            for (ConstructorDescriptor constructor : constructors) {
163                ((ConstructorDescriptorImpl) constructor).setReturnType(containingClass.getDefaultType());
164            }
165    
166            return constructors;
167        }
168    
169        @Nullable
170        private ConstructorDescriptor resolveConstructor(
171                PsiClass psiClass,
172                boolean aStatic,
173                PsiMethod psiConstructor,
174                ClassDescriptor classDescriptor
175        ) {
176            PsiMethodWrapper constructor = new PsiMethodWrapper(psiConstructor);
177    
178            JetConstructorAnnotation constructorAnnotation = constructor.getJetConstructorAnnotation();
179            //noinspection deprecation
180            if (constructorAnnotation.hidden()) {
181                return null;
182            }
183    
184            // Do not resolve kotlin constructors without JetConstructorAnnotation
185            if (DescriptorResolverUtils.isKotlinClass(psiClass) && !constructorAnnotation.isDefined()) {
186                return null;
187            }
188    
189            if (trace.get(BindingContext.CONSTRUCTOR, psiConstructor) != null) {
190                return trace.get(BindingContext.CONSTRUCTOR, psiConstructor);
191            }
192    
193            boolean primary = constructor.getJetConstructorAnnotation().isDefined();
194    
195            ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
196                    classDescriptor,
197                    Collections.<AnnotationDescriptor>emptyList(), // TODO
198                    primary);
199    
200            String context = "constructor of class " + psiClass.getQualifiedName();
201            JavaDescriptorResolver.ValueParameterDescriptors valueParameterDescriptors = valueParameterResolver.resolveParameterDescriptors(
202                    constructorDescriptor, constructor.getParameters(),
203                    TypeVariableResolvers.classTypeVariableResolver(classDescriptor, context));
204    
205            if (valueParameterDescriptors.getReceiverType() != null) {
206                throw new IllegalStateException();
207            }
208    
209            AlternativeMethodSignatureData alternativeMethodSignatureData =
210                    new AlternativeMethodSignatureData(constructor, valueParameterDescriptors, null,
211                                                       Collections.<TypeParameterDescriptor>emptyList(), false);
212            if (alternativeMethodSignatureData.isAnnotated() && !alternativeMethodSignatureData.hasErrors()) {
213                valueParameterDescriptors = alternativeMethodSignatureData.getValueParameters();
214            }
215            else if (alternativeMethodSignatureData.hasErrors()) {
216                trace.record(JavaBindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, constructorDescriptor,
217                             Collections.singletonList(alternativeMethodSignatureData.getError()));
218            }
219    
220            constructorDescriptor.initialize(classDescriptor.getTypeConstructor().getParameters(),
221                                             valueParameterDescriptors.getDescriptors(),
222                                             DescriptorResolverUtils.resolveVisibility(psiConstructor, constructorAnnotation),
223                                             aStatic);
224            trace.record(BindingContext.CONSTRUCTOR, psiConstructor, constructorDescriptor);
225            return constructorDescriptor;
226        }
227    
228        @Nullable
229        private ConstructorDescriptor resolveSamAdapter(@NotNull ConstructorDescriptor original) {
230            return isSamAdapterNecessary(original)
231                   ? recordSamAdapter(original, createSamAdapterConstructor(original), trace)
232                   : null;
233        }
234    }