Support Class<?> as annotation arguments in java

This commit is contained in:
Alexander Udalov
2013-09-06 20:49:11 +04:00
parent b8f9ef9910
commit c0a4d8d24f
13 changed files with 170 additions and 11 deletions
@@ -131,6 +131,7 @@ public class InjectorForJavaDescriptorResolver {
javaAnnotationArgumentResolver.setAnnotationResolver(javaAnnotationResolver);
javaAnnotationArgumentResolver.setClassResolver(javaClassResolver);
javaAnnotationArgumentResolver.setTypeTransformer(javaTypeTransformer);
javaClassResolver.setAnnotationResolver(javaAnnotationResolver);
javaClassResolver.setCache(traceBasedJavaResolverCache);
@@ -59,12 +59,12 @@ import org.jetbrains.jet.lang.resolve.ScriptBodyResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaClassResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationArgumentResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaTypeTransformer;
import org.jetbrains.jet.lang.resolve.java.resolver.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.AnnotationDescriptorDeserializer;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaNamespaceResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaMemberResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaConstructorResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaTypeTransformer;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaFunctionResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaTypeParameterResolver;
@@ -119,12 +119,12 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
private final JavaClassResolver javaClassResolver;
private final JavaAnnotationResolver javaAnnotationResolver;
private final JavaAnnotationArgumentResolver javaAnnotationArgumentResolver;
private final JavaTypeTransformer javaTypeTransformer;
private final DeserializedDescriptorResolver deserializedDescriptorResolver;
private final AnnotationDescriptorDeserializer annotationDescriptorDeserializer;
private final JavaNamespaceResolver javaNamespaceResolver;
private final JavaMemberResolver javaMemberResolver;
private final JavaConstructorResolver javaConstructorResolver;
private final JavaTypeTransformer javaTypeTransformer;
private final JavaValueParameterResolver javaValueParameterResolver;
private final JavaFunctionResolver javaFunctionResolver;
private final JavaTypeParameterResolver javaTypeParameterResolver;
@@ -180,12 +180,12 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
this.javaClassResolver = new JavaClassResolver();
this.javaAnnotationResolver = new JavaAnnotationResolver();
this.javaAnnotationArgumentResolver = new JavaAnnotationArgumentResolver();
this.javaTypeTransformer = new JavaTypeTransformer();
this.deserializedDescriptorResolver = new DeserializedDescriptorResolver();
this.annotationDescriptorDeserializer = new AnnotationDescriptorDeserializer();
this.javaNamespaceResolver = new JavaNamespaceResolver();
this.javaMemberResolver = new JavaMemberResolver();
this.javaConstructorResolver = new JavaConstructorResolver();
this.javaTypeTransformer = new JavaTypeTransformer();
this.javaValueParameterResolver = new JavaValueParameterResolver();
this.javaFunctionResolver = new JavaFunctionResolver();
this.javaTypeParameterResolver = new JavaTypeParameterResolver();
@@ -333,6 +333,9 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
javaAnnotationArgumentResolver.setAnnotationResolver(javaAnnotationResolver);
javaAnnotationArgumentResolver.setClassResolver(javaClassResolver);
javaAnnotationArgumentResolver.setTypeTransformer(javaTypeTransformer);
javaTypeTransformer.setClassResolver(javaClassResolver);
deserializedDescriptorResolver.setAnnotationDeserializer(annotationDescriptorDeserializer);
deserializedDescriptorResolver.setErrorReporter(traceBasedErrorReporter);
@@ -359,8 +362,6 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
javaConstructorResolver.setTypeTransformer(javaTypeTransformer);
javaConstructorResolver.setValueParameterResolver(javaValueParameterResolver);
javaTypeTransformer.setClassResolver(javaClassResolver);
javaValueParameterResolver.setAnnotationResolver(javaAnnotationResolver);
javaValueParameterResolver.setTypeTransformer(javaTypeTransformer);
@@ -47,6 +47,9 @@ public abstract class JavaAnnotationArgumentImpl<Psi extends PsiAnnotationMember
else if (argument instanceof PsiAnnotation) {
return new JavaAnnotationAsAnnotationArgumentImpl((PsiAnnotation) argument, name);
}
else if (argument instanceof PsiClassObjectAccessExpression) {
return new JavaClassObjectAnnotationArgumentImpl((PsiClassObjectAccessExpression) argument, name);
}
else {
throw new UnsupportedOperationException("Unsupported annotation argument type: " + argument);
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.java.structure.impl;
import com.intellij.psi.PsiClassObjectAccessExpression;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.java.structure.JavaClassObjectAnnotationArgument;
import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
import org.jetbrains.jet.lang.resolve.name.Name;
public class JavaClassObjectAnnotationArgumentImpl extends JavaAnnotationArgumentImpl<PsiClassObjectAccessExpression>
implements JavaClassObjectAnnotationArgument {
public JavaClassObjectAnnotationArgumentImpl(@NotNull PsiClassObjectAccessExpression expression, @Nullable Name name) {
super(expression, name);
}
@NotNull
@Override
public JavaType getReferencedType() {
return JavaTypeImpl.create(getPsi().getOperand().getType());
}
}
@@ -0,0 +1,10 @@
package test;
public class ClassObjectArrayInParam {
public @interface Anno {
Class<?>[] value();
}
@Anno({ClassObjectArrayInParam.class, Nested.class, String.class})
public static class Nested {}
}
@@ -0,0 +1,14 @@
package test
public open class ClassObjectArrayInParam : java.lang.Object {
public constructor ClassObjectArrayInParam()
public final annotation class Anno : jet.Annotation {
public constructor Anno(/*0*/ vararg value: java.lang.Class<out jet.Any?>? /*jet.Array<java.lang.Class<out jet.Any?>>?*/)
public abstract fun value(): jet.Array<java.lang.Class<out jet.Any?>>?
}
test.ClassObjectArrayInParam.Anno(value = [ClassObjectArrayInParam?.class, Nested?.class, String?.class]: jet.Array<java.lang.Class<out jet.Any?>>?) public open class Nested : java.lang.Object {
public constructor Nested()
}
}
@@ -0,0 +1,10 @@
package test;
public class ClassObjectInParam {
public @interface Anno {
Class<?> value();
}
@Anno(ClassObjectInParam.class)
public static class Nested {}
}
@@ -0,0 +1,14 @@
package test
public open class ClassObjectInParam : java.lang.Object {
public constructor ClassObjectInParam()
public final annotation class Anno : jet.Annotation {
public constructor Anno(/*0*/ value: java.lang.Class<out jet.Any?>?)
public abstract fun value(): java.lang.Class<out jet.Any?>?
}
test.ClassObjectInParam.Anno(value = ClassObjectInParam?.class: java.lang.Class<test.ClassObjectInParam?>) public open class Nested : java.lang.Object {
public constructor Nested()
}
}
@@ -3,13 +3,13 @@ package test
public trait ErrorTypes : java.lang.Object {
public trait Sub : test.ErrorTypes.Super {
public abstract fun errorTypeInParameter(/*0*/ list: jet.List<jet.Array<[ERROR : Unresolved java class: T]>?>?): jet.Unit
public abstract override /*1*/ /*fake_override*/ fun errorTypeInParameter(/*0*/ list: jet.List<jet.Array<[ERROR : Unresolved java class: T]>?>?): jet.Unit
public abstract override /*1*/ fun returnErrorType(): [ERROR : Unresolved java class: T]
public abstract fun errorTypeInParameter(/*0*/ list: jet.List<jet.Array<[ERROR : Unresolved java classifier: T]>?>?): jet.Unit
public abstract override /*1*/ /*fake_override*/ fun errorTypeInParameter(/*0*/ list: jet.List<jet.Array<[ERROR : Unresolved java classifier: T]>?>?): jet.Unit
public abstract override /*1*/ fun returnErrorType(): [ERROR : Unresolved java classifier: T]
}
public trait Super : java.lang.Object {
public abstract fun errorTypeInParameter(/*0*/ list: jet.List<jet.Array<[ERROR : Unresolved java class: T]>?>?): jet.Unit
public abstract fun returnErrorType(): [ERROR : Unresolved java class: T]
public abstract fun errorTypeInParameter(/*0*/ list: jet.List<jet.Array<[ERROR : Unresolved java classifier: T]>?>?): jet.Unit
public abstract fun returnErrorType(): [ERROR : Unresolved java classifier: T]
}
}
@@ -1080,6 +1080,16 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/annotations/ArrayOfStringInParam.java");
}
@TestMetadata("ClassObjectArrayInParam.java")
public void testClassObjectArrayInParam() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/annotations/ClassObjectArrayInParam.java");
}
@TestMetadata("ClassObjectInParam.java")
public void testClassObjectInParam() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/annotations/ClassObjectInParam.java");
}
@TestMetadata("CustomAnnotation.java")
public void testCustomAnnotation() throws Exception {
doTestCompiledJava("compiler/testData/loadJava/compiledJava/annotations/CustomAnnotation.java");
@@ -168,7 +168,7 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
annotation.setAnnotationType(annotationClass.getDefaultType());
return new AnnotationVisitor(Opcodes.ASM4) {
// TODO: arrays, annotations
// TODO: arrays, annotations, java.lang.Class
@Override
public void visit(String name, Object value) {
CompileTimeConstant<?> argument = JavaAnnotationArgumentResolver.resolveCompileTimeConstantValue(value, null);
@@ -29,19 +29,26 @@ import org.jetbrains.jet.lang.resolve.java.structure.*;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeImpl;
import org.jetbrains.jet.lang.types.TypeProjection;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getEnumEntriesScope;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.IGNORE_KOTLIN_SOURCES;
import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN_SOURCES;
public final class JavaAnnotationArgumentResolver {
public static final FqName JL_CLASS_FQ_NAME = new FqName("java.lang.Class");
private JavaAnnotationResolver annotationResolver;
private JavaClassResolver classResolver;
private JavaTypeTransformer typeTransformer;
@Inject
public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
@@ -53,6 +60,11 @@ public final class JavaAnnotationArgumentResolver {
this.classResolver = classResolver;
}
@Inject
public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
this.typeTransformer = typeTransformer;
}
@Nullable
public CompileTimeConstant<?> resolveAnnotationArgument(
@NotNull FqName annotationFqName,
@@ -80,6 +92,10 @@ public final class JavaAnnotationArgumentResolver {
else if (argument instanceof JavaAnnotationAsAnnotationArgument) {
return resolveFromAnnotation(((JavaAnnotationAsAnnotationArgument) argument).getAnnotation(), postponedTasks);
}
// Class<?>
else if (argument instanceof JavaClassObjectAnnotationArgument) {
return resolveFromJavaClassObjectType(((JavaClassObjectAnnotationArgument) argument).getReferencedType());
}
return null;
}
@@ -135,6 +151,25 @@ public final class JavaAnnotationArgumentResolver {
return null;
}
@Nullable
private CompileTimeConstant<?> resolveFromJavaClassObjectType(@NotNull JavaType javaType) {
JetType type = typeTransformer.transformToType(javaType, TypeVariableResolver.EMPTY);
ClassDescriptor jlClass = classResolver.resolveClass(JL_CLASS_FQ_NAME, IGNORE_KOTLIN_SOURCES);
if (jlClass == null) return null;
List<TypeProjection> arguments = Collections.singletonList(new TypeProjection(type));
JetTypeImpl javaClassType = new JetTypeImpl(
jlClass.getAnnotations(),
jlClass.getTypeConstructor(),
false,
arguments,
jlClass.getMemberScope(arguments)
);
return new JavaClassValue(javaClassType);
}
@Nullable
public static CompileTimeConstant<?> resolveCompileTimeConstantValue(@Nullable Object value, @Nullable JetType expectedType) {
if (value instanceof String) {
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.lang.resolve.java.structure;
import org.jetbrains.annotations.NotNull;
public interface JavaClassObjectAnnotationArgument extends JavaAnnotationArgument {
@NotNull
JavaType getReferencedType();
}