Refactor and improve code obtaining actual Java annotation parameter values

Extract Java-specific code into module 'frontend.java' and use already
existing JavaAnnotationArgument facilities to determine the default
parameter value in an actual Java annotation class.

Annotation arguments are not yet supported because to create an instance
of AnnotationValue, we need a descriptor, which is not available at this
point.

 #KT-22704 In Progress
 #KT-28077 Open
This commit is contained in:
Alexander Udalov
2018-10-18 13:13:25 +02:00
parent c08540175b
commit 49d6a7a7cb
13 changed files with 342 additions and 66 deletions
@@ -65,7 +65,7 @@ private fun StorageComponentContainer.configureJavaTopDownAnalysis(
useInstance(VirtualFileFinderFactory.getInstance(project).create(moduleContentScope))
useImpl<JavaPropertyInitializerEvaluatorImpl>()
useInstance(JavaPropertyInitializerEvaluatorImpl)
useImpl<AnnotationResolverImpl>()
useImpl<SignaturePropagatorImpl>()
useImpl<TraceBasedErrorReporter>()
@@ -20,20 +20,21 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.types.KotlinType
class JavaPropertyInitializerEvaluatorImpl : JavaPropertyInitializerEvaluator {
override fun getInitializerConstant(field: JavaField, descriptor: PropertyDescriptor): ConstantValue<*>? {
val evaluated = field.initializerValue ?: return null
object JavaPropertyInitializerEvaluatorImpl : JavaPropertyInitializerEvaluator {
override fun getInitializerConstant(field: JavaField, descriptor: PropertyDescriptor): ConstantValue<*>? =
field.initializerValue?.let { value -> convertLiteralValue(value, descriptor.type) }
return when (evaluated) {
//Note: evaluated expression may be of class that does not match field type in some cases
// tested for Int, left other checks just in case
internal fun convertLiteralValue(value: Any, expectedType: KotlinType): ConstantValue<*>? =
when (value) {
// Note: `value` expression may be of class that does not match field type in some cases
// tested for Int, left other checks just in case
is Byte, is Short, is Int, is Long -> {
ConstantValueFactory.createIntegerConstantValue((evaluated as Number).toLong(), descriptor.type, false)
ConstantValueFactory.createIntegerConstantValue((value as Number).toLong(), expectedType, false)
}
else -> {
ConstantValueFactory.createConstantValue(evaluated)
ConstantValueFactory.createConstantValue(value)
}
}
}
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.jvm.multiplatform
import com.intellij.psi.PsiAnnotationMethod
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.load.java.components.JavaPropertyInitializerEvaluatorImpl
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.impl.JavaAnnotationArgumentImpl
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.builtIns
class JavaActualAnnotationArgumentExtractor : ExpectedActualDeclarationChecker.ActualAnnotationArgumentExtractor {
override fun extractActualValue(argument: PsiElement, expectedType: KotlinType): ConstantValue<*>? =
(argument as? PsiAnnotationMethod)
?.defaultValue
?.let { JavaAnnotationArgumentImpl.create(it, null) }
?.convert(expectedType)
// This code is similar to LazyJavaAnnotationDescriptor.resolveAnnotationArgument, but cannot be reused until
// KClassValue/AnnotationValue are untied from descriptors/types, because here we do not have an instance of LazyJavaResolverContext.
private fun JavaAnnotationArgument.convert(expectedType: KotlinType): ConstantValue<*>? {
return when (this) {
is JavaLiteralAnnotationArgument -> value?.let {
JavaPropertyInitializerEvaluatorImpl.convertLiteralValue(it, expectedType)
}
is JavaEnumValueAnnotationArgument -> {
enumClassId?.let { enumClassId ->
entryName?.let { entryName ->
EnumValue(enumClassId, entryName)
}
}
}
is JavaArrayAnnotationArgument -> {
val elementType = expectedType.builtIns.getArrayElementType(expectedType)
ConstantValueFactory.createArrayValue(getElements().mapNotNull { it.convert(elementType) }, expectedType)
}
is JavaAnnotationAsAnnotationArgument -> {
// TODO: support annotations as annotation arguments (KT-28077)
null
}
is JavaClassObjectAnnotationArgument -> {
// TODO: support class literals as annotation arguments
null
}
else -> null
}
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.resolve.checkers.BigFunctionTypeAvailabilityChecker
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.jvm.*
import org.jetbrains.kotlin.resolve.jvm.checkers.*
import org.jetbrains.kotlin.resolve.jvm.multiplatform.JavaActualAnnotationArgumentExtractor
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
import org.jetbrains.kotlin.types.DynamicTypesSettings
import org.jetbrains.kotlin.types.expressions.FunctionWithBigAritySupport
@@ -34,7 +35,7 @@ object JvmPlatformConfigurator : PlatformConfigurator(
TypeParameterBoundIsNotArrayChecker(),
JvmSyntheticApplicabilityChecker(),
StrictfpApplicabilityChecker(),
ExpectedActualDeclarationChecker,
ExpectedActualDeclarationChecker(listOf(JavaActualAnnotationArgumentExtractor())),
JvmAnnotationsTargetNonExistentAccessorChecker(),
BadInheritedJavaSignaturesChecker
),