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 }