Fix loading default Java annotation values in actual typealias from binary classes

#KT-22704 Fixed
This commit is contained in:
Alexander Udalov
2018-12-24 17:48:01 +01:00
parent 3fee84b966
commit 8ab9226805
15 changed files with 243 additions and 84 deletions
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.javac.wrappers.symbols
import org.jetbrains.kotlin.javac.JavacWrapper
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
import javax.lang.model.element.ExecutableElement
class SymbolBasedMethod(
@@ -35,7 +36,9 @@ class SymbolBasedMethod(
override val returnType: JavaType
get() = SymbolBasedType.create(element.returnType, javac)
override val hasAnnotationParameterDefaultValue: Boolean
get() = element.defaultValue != null
// TODO: allow nullable names in Symbol-based annotation arguments and pass null instead of a synthetic name
override val annotationParameterDefaultValue: JavaAnnotationArgument?
get() = element.defaultValue?.let { defaultValue ->
SymbolBasedAnnotationArgument.create(defaultValue, Name.identifier("value"), javac)
}
}
@@ -100,46 +100,50 @@ class TreeBasedAnnotationAsAnnotationArgument(private val annotation: JCTree.JCA
}
private fun createAnnotationArguments(annotation: TreeBasedAnnotation,
javac: JavacWrapper,
onElement: JavaElement): Collection<JavaAnnotationArgument> =
private fun createAnnotationArguments(
annotation: TreeBasedAnnotation, javac: JavacWrapper, onElement: JavaElement
): Collection<JavaAnnotationArgument> =
annotation.annotation.arguments.mapNotNull {
val name = if (it is JCTree.JCAssign) Name.identifier(it.lhs.toString()) else Name.identifier("value")
createAnnotationArgument(it, name, annotation.compilationUnit, javac, annotation, onElement)
createAnnotationArgument(it, name, annotation.compilationUnit, javac, annotation.resolve(), onElement)
}
private fun createAnnotationArgument(argument: JCTree.JCExpression,
name: Name,
compilationUnit: CompilationUnitTree,
javac: JavacWrapper,
annotation: TreeBasedAnnotation,
onElement: JavaElement): JavaAnnotationArgument? =
when (argument) {
is JCTree.JCLiteral -> TreeBasedLiteralAnnotationArgument(name, argument.value, javac)
is JCTree.JCFieldAccess -> {
if (argument.name.contentEquals("class")) {
TreeBasedJavaClassObjectAnnotationArgument(argument.selected, name, compilationUnit, javac, onElement)
}
else {
TreeBasedReferenceAnnotationArgument(name, compilationUnit, argument, javac, onElement)
}
internal fun createAnnotationArgument(
argument: JCTree.JCExpression,
name: Name,
compilationUnit: CompilationUnitTree,
javac: JavacWrapper,
containingClass: JavaClass?,
onElement: JavaElement
): JavaAnnotationArgument? =
when (argument) {
is JCTree.JCLiteral -> TreeBasedLiteralAnnotationArgument(name, argument.value, javac)
is JCTree.JCFieldAccess -> {
if (argument.name.contentEquals("class")) {
TreeBasedJavaClassObjectAnnotationArgument(argument.selected, name, compilationUnit, javac, onElement)
} else {
TreeBasedReferenceAnnotationArgument(name, compilationUnit, argument, javac, onElement)
}
is JCTree.JCAssign -> createAnnotationArgument(argument.rhs, name, compilationUnit, javac, annotation, onElement)
is JCTree.JCNewArray -> TreeBasedArrayAnnotationArgument(argument.elems.mapNotNull { createAnnotationArgument(it, name, compilationUnit, javac, annotation, onElement) }, name, javac)
is JCTree.JCAnnotation -> TreeBasedAnnotationAsAnnotationArgument(argument, name, compilationUnit, javac, onElement)
is JCTree.JCParens -> createAnnotationArgument(argument.expr, name, compilationUnit, javac, annotation, onElement)
is JCTree.JCBinary -> resolveArgumentValue(argument, annotation, name, compilationUnit, javac)
is JCTree.JCUnary -> resolveArgumentValue(argument, annotation, name, compilationUnit, javac)
else -> throw UnsupportedOperationException("Unknown annotation argument $argument")
}
is JCTree.JCAssign -> createAnnotationArgument(argument.rhs, name, compilationUnit, javac, containingClass, onElement)
is JCTree.JCNewArray -> TreeBasedArrayAnnotationArgument(argument.elems.mapNotNull {
createAnnotationArgument(it, name, compilationUnit, javac, containingClass, onElement)
}, name, javac)
is JCTree.JCAnnotation -> TreeBasedAnnotationAsAnnotationArgument(argument, name, compilationUnit, javac, onElement)
is JCTree.JCParens -> createAnnotationArgument(argument.expr, name, compilationUnit, javac, containingClass, onElement)
is JCTree.JCBinary -> resolveArgumentValue(argument, containingClass, name, compilationUnit, javac)
is JCTree.JCUnary -> resolveArgumentValue(argument, containingClass, name, compilationUnit, javac)
else -> throw UnsupportedOperationException("Unknown annotation argument $argument")
}
private fun resolveArgumentValue(argument: JCTree.JCExpression,
annotation: TreeBasedAnnotation,
name: Name,
compilationUnit: CompilationUnitTree,
javac: JavacWrapper): JavaAnnotationArgument? {
val containingAnnotation = annotation.resolve() ?: return null
val evaluator = ConstantEvaluator(containingAnnotation, javac, compilationUnit)
private fun resolveArgumentValue(
argument: JCTree.JCExpression,
containingClass: JavaClass?,
name: Name,
compilationUnit: CompilationUnitTree,
javac: JavacWrapper
): JavaAnnotationArgument? {
if (containingClass == null) return null
val evaluator = ConstantEvaluator(containingClass, javac, compilationUnit)
return evaluator.getValue(argument)?.let { TreeBasedLiteralAnnotationArgument(name, it, javac) }
}
}
@@ -55,6 +55,9 @@ class TreeBasedMethod(
override val returnType: JavaType
get() = TreeBasedType.create(tree.returnType, compilationUnit, javac, annotations, this)
override val hasAnnotationParameterDefaultValue: Boolean
get() = tree.defaultValue != null
}
// TODO: allow nullable names in Tree-based annotation arguments and pass null instead of a synthetic name
override val annotationParameterDefaultValue: JavaAnnotationArgument?
get() = tree.defaultValue?.let { defaultValue ->
createAnnotationArgument(defaultValue, Name.identifier("value"), compilationUnit, javac, containingClass, this)
}
}