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 017package org.jetbrains.jet.lang.resolve.java.resolver; 018 019import com.google.common.collect.Lists; 020import com.intellij.psi.*; 021import com.intellij.util.containers.ContainerUtil; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.annotations.Nullable; 024import org.jetbrains.jet.lang.descriptors.*; 025import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 026import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; 027import org.jetbrains.jet.lang.descriptors.impl.ValueParameterDescriptorImpl; 028import org.jetbrains.jet.lang.resolve.BindingContext; 029import org.jetbrains.jet.lang.resolve.BindingTrace; 030import org.jetbrains.jet.lang.resolve.DescriptorResolver; 031import org.jetbrains.jet.lang.resolve.java.*; 032import org.jetbrains.jet.lang.resolve.java.kotlinSignature.AlternativeMethodSignatureData; 033import org.jetbrains.jet.lang.resolve.java.kt.JetConstructorAnnotation; 034import org.jetbrains.jet.lang.resolve.java.provider.ClassPsiDeclarationProvider; 035import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper; 036import org.jetbrains.jet.lang.resolve.name.Name; 037import org.jetbrains.jet.lang.types.JetType; 038 039import javax.inject.Inject; 040import java.util.Collection; 041import java.util.Collections; 042import java.util.List; 043 044import static org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver.recordSamAdapter; 045import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.createSamAdapterConstructor; 046import static org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils.isSamAdapterNecessary; 047 048public 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}