From ecb747879472dd4b2aafcde519469d25dcdfe69c Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Mon, 2 Mar 2020 13:18:20 +0700 Subject: [PATCH] ExperimentalFixesFactory: `OptIn` shouldn't be added for old version #KT-36478 --- .../idea/quickfix/ExperimentalFixesFactory.kt | 16 ++++++++++---- .../quickfix/MakeModuleExperimentalFix.kt | 21 +++++++++++++++---- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt index 77322d2d67d..d63a74a4604 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInsight.intention.IntentionAction import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.descriptors.resolveClassByFqName import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -16,6 +17,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.util.projectStructure.module import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate @@ -36,8 +38,7 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() { !KtPsiUtil.isLocal(it) } ?: return emptyList() - val factory = diagnostic.factory - val annotationFqName = when (factory) { + val annotationFqName = when (diagnostic.factory) { EXPERIMENTAL_API_USAGE -> EXPERIMENTAL_API_USAGE.cast(diagnostic).a EXPERIMENTAL_API_USAGE_ERROR -> EXPERIMENTAL_API_USAGE_ERROR.cast(diagnostic).a EXPERIMENTAL_OVERRIDE -> EXPERIMENTAL_OVERRIDE.cast(diagnostic).a @@ -71,7 +72,7 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() { } result.add( AddAnnotationFix( - containingDeclaration, ExperimentalUsageChecker.OPT_IN_FQ_NAME, suffix, annotationFqName + containingDeclaration, moduleDescriptor.OPT_IN_FQ_NAME, suffix, annotationFqName ) ) } @@ -84,7 +85,7 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() { } else { result.add( AddAnnotationFix( - containingClassOrObject, ExperimentalUsageChecker.OPT_IN_FQ_NAME, suffix, annotationFqName + containingClassOrObject, moduleDescriptor.OPT_IN_FQ_NAME, suffix, annotationFqName ) ) } @@ -100,4 +101,11 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() { return result } + + private val ModuleDescriptor.OPT_IN_FQ_NAME: FqName + get() = ExperimentalUsageChecker.OPT_IN_FQ_NAME.takeIf { fqNameIsExisting(it) } + ?: ExperimentalUsageChecker.OLD_USE_EXPERIMENTAL_FQ_NAME + + + fun ModuleDescriptor.fqNameIsExisting(fqName: FqName): Boolean = resolveClassByFqName(fqName, NoLookupLocation.FROM_IDE) != null } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt index e23b7655db2..801798a292e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt @@ -13,10 +13,12 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.config.CompilerSettings import org.jetbrains.kotlin.config.additionalArgumentsAsList import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.caches.project.toDescriptor import org.jetbrains.kotlin.idea.configuration.BuildSystemType import org.jetbrains.kotlin.idea.configuration.getBuildSystemType import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.facet.getOrCreateFacet +import org.jetbrains.kotlin.idea.quickfix.ExperimentalFixesFactory.fqNameIsExisting import org.jetbrains.kotlin.idea.roots.invalidateProjectRoots import org.jetbrains.kotlin.idea.util.projectStructure.module import org.jetbrains.kotlin.name.FqName @@ -28,11 +30,16 @@ class MakeModuleExperimentalFix( private val module: Module, private val annotationFqName: FqName ) : KotlinQuickFixAction(file) { - override fun getText(): String = "Add '-Xopt-in=$annotationFqName' to module ${module.name} compiler arguments" + private val experimentalPrefix = if (module.toDescriptor()?.fqNameIsExisting(ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME) == true) + "opt-in" + else + "use-experimental" + + override fun getText(): String = "Add '$compilerArgument' to module ${module.name} compiler arguments" override fun getFamilyName(): String = "Add an opt-in requirement marker compiler argument" - private val compilerArgument = "-Xopt-in=$annotationFqName" + private val compilerArgument = "-X$experimentalPrefix=$annotationFqName" override fun invoke(project: Project, editor: Editor?, file: KtFile) { val modelsProvider = IdeModifiableModelsProviderImpl(project) @@ -56,7 +63,7 @@ class MakeModuleExperimentalFix( val facet = KotlinFacet.get(module) ?: return true val facetSettings = facet.configuration.settings val compilerSettings = facetSettings.compilerSettings ?: return true - return if (annotationFqName != ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME) { + return if (annotationFqName != ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME && annotationFqName != ExperimentalUsageChecker.OLD_EXPERIMENTAL_FQ_NAME) { compilerArgument !in compilerSettings.additionalArgumentsAsList } else { compilerSettings.additionalArgumentsAsList.none { @@ -69,7 +76,13 @@ class MakeModuleExperimentalFix( override fun createAction(diagnostic: Diagnostic): IntentionAction? { val containingKtFile = diagnostic.psiElement.containingFile as? KtFile ?: return null val module = containingKtFile.module ?: return null - return MakeModuleExperimentalFix(containingKtFile, module, ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME) + return MakeModuleExperimentalFix( + containingKtFile, + module, + ExperimentalUsageChecker.REQUIRES_OPT_IN_FQ_NAME.takeIf { + module.toDescriptor()?.fqNameIsExisting(it) == true + } ?: ExperimentalUsageChecker.OLD_EXPERIMENTAL_FQ_NAME + ) } } }