From 9290d58ed00ff37d76f02b79389f413bb773c9b5 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 29 Dec 2017 16:54:04 +0100 Subject: [PATCH] Improve "firstArgumentValue" and "argumentValue" extension functions Using the argument value, which is of type "Any?", is more implicit and thus difficult to read than using the ConstantValue instance and casting it to the needed constant value implementation before taking the value --- .../kotlin/resolve/AnnotationUtil.kt | 5 ++-- .../kotlin/resolve/deprecationUtil.kt | 27 +++++++++---------- .../java/AnnotationTypeQualifierResolver.kt | 4 +-- .../kotlin/load/java/descriptors/util.kt | 9 ++++--- .../java/lazy/descriptors/LazyJavaScope.kt | 7 ++--- .../typeEnhancement/signatureEnhancement.kt | 7 +++-- .../kotlin/resolve/DescriptorUtils.kt | 3 ++- .../idea/injection/KotlinLanguageInjector.kt | 4 ++- .../DeprecatedSymbolUsageFixBase.kt | 11 +++++--- 9 files changed, 42 insertions(+), 35 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt index f2bb40c799a..103e33a8190 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.ErrorValue val JVM_STATIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmStatic") @@ -43,6 +44,6 @@ private val STRICTFP_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Strictfp") fun DeclarationDescriptor.findStrictfpAnnotation() = DescriptorUtils.getAnnotationByFqName(annotations, STRICTFP_ANNOTATION_FQ_NAME) -fun AnnotationDescriptor.argumentValue(parameterName: String): Any? { - return allValueArguments[Name.identifier(parameterName)].takeUnless { it is ErrorValue }?.value +fun AnnotationDescriptor.argumentValue(parameterName: String): ConstantValue<*>? { + return allValueArguments[Name.identifier(parameterName)].takeUnless { it is ErrorValue } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt index eb15f5411b0..abd8d055222 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/deprecationUtil.kt @@ -33,6 +33,9 @@ import org.jetbrains.kotlin.resolve.DeprecationLevelValue.* import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.calls.checkers.isOperatorMod import org.jetbrains.kotlin.resolve.calls.checkers.shouldWarnAboutDeprecatedModFromBuiltIns +import org.jetbrains.kotlin.resolve.constants.AnnotationValue +import org.jetbrains.kotlin.resolve.constants.EnumValue +import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor @@ -42,6 +45,7 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.utils.SmartList +import org.jetbrains.kotlin.utils.addToStdlib.safeAs private val JAVA_DEPRECATED = FqName("java.lang.Deprecated") @@ -55,27 +59,22 @@ fun Deprecation.deprecatedByOverriddenMessage(): String? = (this as? DeprecatedB fun Deprecation.deprecatedByAnnotationReplaceWithExpression(): String? { val annotation = (this as? DeprecatedByAnnotation)?.annotation ?: return null - val replaceWithAnnotation = annotation.argumentValue(kotlin.Deprecated::replaceWith.name) - as? AnnotationDescriptor ?: return null - - return replaceWithAnnotation.argumentValue(kotlin.ReplaceWith::expression.name) as String + val replaceWithAnnotation = + annotation.argumentValue(kotlin.Deprecated::replaceWith.name)?.safeAs()?.value ?: return null + return replaceWithAnnotation.argumentValue(kotlin.ReplaceWith::expression.name)?.safeAs()?.value } private data class DeprecatedByAnnotation(val annotation: AnnotationDescriptor, override val target: DeclarationDescriptor) : Deprecation { override val deprecationLevel: DeprecationLevelValue - get() { - val level = annotation.argumentValue("level") as? ClassDescriptor - - return when (level?.name?.asString()) { - "WARNING" -> WARNING - "ERROR" -> ERROR - "HIDDEN" -> HIDDEN - else -> WARNING - } + get() = when (annotation.argumentValue("level")?.safeAs()?.enumEntryName?.asString()) { + "WARNING" -> WARNING + "ERROR" -> ERROR + "HIDDEN" -> HIDDEN + else -> WARNING } override val message: String? - get() = annotation.argumentValue("message") as? String + get() = annotation.argumentValue("message")?.safeAs()?.value } private data class DeprecatedByOverridden(private val deprecations: Collection) : Deprecation { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt index 04d32d21dc3..30c6ce18554 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/AnnotationTypeQualifierResolver.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass -import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue +import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.utils.Jsr305State @@ -148,7 +148,7 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va } private fun ClassDescriptor.migrationAnnotationStatus(): ReportLevel? { - val stateDescriptor = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgumentValue()?.safeAs() + val stateDescriptor = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgument()?.safeAs()?.value ?: return null jsr305State.migration?.let { return jsr305State.migration } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/descriptors/util.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/descriptors/util.kt index 8b3907a84a8..a8b0cb2992e 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/descriptors/util.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/descriptors/util.kt @@ -24,7 +24,8 @@ import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaStaticClassScope import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource -import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue +import org.jetbrains.kotlin.resolve.constants.StringValue +import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.jvm.JvmClassName @@ -78,7 +79,7 @@ fun DeserializedMemberDescriptor.isFromJvmPackagePart(): Boolean = fun ValueParameterDescriptor.getParameterNameAnnotation(): AnnotationDescriptor? { val annotation = annotations.findAnnotation(JvmAnnotationNames.PARAMETER_NAME_FQ_NAME) ?: return null - if (annotation.firstArgumentValue()?.safeAs()?.isEmpty() != false) { + if (annotation.firstArgument()?.safeAs()?.value?.isEmpty() != false) { return null } @@ -91,8 +92,8 @@ object NullDefaultValue : AnnotationDefaultValue() fun ValueParameterDescriptor.getDefaultValueFromAnnotation(): AnnotationDefaultValue? { annotations.findAnnotation(JvmAnnotationNames.DEFAULT_VALUE_FQ_NAME) - ?.firstArgumentValue() - ?.safeAs() + ?.firstArgument() + ?.safeAs()?.value ?.let { return StringDefaultValue(it) } if (annotations.hasAnnotation(JvmAnnotationNames.DEFAULT_NULL_FQ_NAME)) { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt index d683e87b631..7b94d638c88 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaScope.kt @@ -36,7 +36,8 @@ import org.jetbrains.kotlin.load.java.structure.JavaMethod import org.jetbrains.kotlin.load.java.structure.JavaValueParameter import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue +import org.jetbrains.kotlin.resolve.constants.StringValue +import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument import org.jetbrains.kotlin.resolve.retainMostSpecificInEachOverridableGroup import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude.NonExtensions import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter @@ -174,8 +175,8 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS val typeUsage = TypeUsage.COMMON.toAttributes() val parameterName = annotations .findAnnotation(JvmAnnotationNames.PARAMETER_NAME_FQ_NAME) - ?.firstArgumentValue() - ?.safeAs() + ?.firstArgument() + ?.safeAs()?.value val (outType, varargElementType) = if (javaParameter.isVararg) { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt index 98aa35220f3..d5bcc376032 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/typeEnhancement/signatureEnhancement.kt @@ -30,7 +30,8 @@ import org.jetbrains.kotlin.load.kotlin.SignatureBuildingComponents import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.platform.JavaToKotlinClassMap -import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgumentValue +import org.jetbrains.kotlin.resolve.constants.EnumValue +import org.jetbrains.kotlin.resolve.descriptorUtil.firstArgument import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.typeUtil.isTypeParameter @@ -49,12 +50,10 @@ class SignatureEnhancement( ) { private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? { - val enumEntryDescriptor = firstArgumentValue() + val enumEntryDescriptor = firstArgument().safeAs()?.value // if no argument is specified, use default value: NOT_NULL ?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) - if (enumEntryDescriptor !is ClassDescriptor) return null - return when (enumEntryDescriptor.name.asString()) { "ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL) "MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE) diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index f5366fb3e92..412710122b5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils.getContainingClass +import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -416,7 +417,7 @@ fun ClassDescriptor.isSubclassOf(superclass: ClassDescriptor): Boolean = Descrip val AnnotationDescriptor.annotationClass: ClassDescriptor? get() = type.constructor.declarationDescriptor as? ClassDescriptor -fun AnnotationDescriptor.firstArgumentValue() = allValueArguments.values.firstOrNull()?.value +fun AnnotationDescriptor.firstArgument(): ConstantValue<*>? = allValueArguments.values.firstOrNull() fun MemberDescriptor.isEffectivelyExternal(): Boolean { if (isExternal) return true diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt index d7c430e51d8..ad5793a51a4 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/injection/KotlinLanguageInjector.kt @@ -54,10 +54,12 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.annotations.argumentValue +import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.util.aliasImportMap import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs class KotlinLanguageInjector( private val configuration: Configuration, @@ -334,7 +336,7 @@ class KotlinLanguageInjector( val parameterDescriptor = functionDescriptor.valueParameters.getOrNull(argumentIndex) ?: return null val injectAnnotation = parameterDescriptor.annotations.findAnnotation(FqName(AnnotationUtil.LANGUAGE)) ?: return null - val languageId = injectAnnotation.argumentValue("value") as? String ?: return null + val languageId = injectAnnotation.argumentValue("value")?.safeAs()?.value ?: return null return InjectionInfo(languageId, null, null) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt index d312b484554..60508a68448 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageFixBase.kt @@ -24,7 +24,6 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.searches.ReferencesSearch import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory @@ -45,10 +44,13 @@ import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.annotations.argumentValue import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess +import org.jetbrains.kotlin.resolve.constants.AnnotationValue +import org.jetbrains.kotlin.resolve.constants.ArrayValue import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.util.constructors +import org.jetbrains.kotlin.utils.addToStdlib.safeAs //TODO: different replacements for property accessors @@ -77,10 +79,11 @@ abstract class DeprecatedSymbolUsageFixBase( companion object { fun fetchReplaceWithPattern(descriptor: DeclarationDescriptor, project: Project): ReplaceWith? { val annotation = descriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated) ?: return null - val replaceWithValue = annotation.argumentValue(kotlin.Deprecated::replaceWith.name) as? AnnotationDescriptor ?: return null - val pattern = replaceWithValue.argumentValue(kotlin.ReplaceWith::expression.name) as? String ?: return null + val replaceWithValue = + annotation.argumentValue(kotlin.Deprecated::replaceWith.name)?.safeAs()?.value ?: return null + val pattern = replaceWithValue.argumentValue(kotlin.ReplaceWith::expression.name)?.safeAs()?.value ?: return null if (pattern.isEmpty()) return null - val importValues = replaceWithValue.argumentValue(kotlin.ReplaceWith::imports.name) as? List<*> ?: return null + val importValues = replaceWithValue.argumentValue(kotlin.ReplaceWith::imports.name)?.safeAs()?.value ?: return null if (importValues.any { it !is StringValue }) return null val imports = importValues.map { (it as StringValue).value }