diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt index 468025fb57d..6e50e8855b8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.idea.util.projectStructure.module import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate import org.jetbrains.kotlin.resolve.AnnotationChecker import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker @@ -87,6 +88,13 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() { } } } + val containingFile = containingDeclaration.containingKtFile + val module = containingFile.module + if (module != null) { + result.add( + MakeModuleExperimentalFix(containingFile, module, annotationFqName) + ) + } return result } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt new file mode 100644 index 00000000000..75ae943aff8 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeModuleExperimentalFix.kt @@ -0,0 +1,37 @@ +/* + * 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.idea.quickfix + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.config.CompilerSettings +import org.jetbrains.kotlin.idea.facet.getOrCreateFacet +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtFile + +class MakeModuleExperimentalFix( + file: KtFile, + private val module: Module, + private val annotationFqName: FqName +) : KotlinQuickFixAction(file) { + override fun getText(): String = "Add '-Xuse-experimental=$annotationFqName' to module ${module.name} compiler arguments" + + override fun getFamilyName(): String = "Make module experimental" + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val modelsProvider = IdeModifiableModelsProviderImpl(project) + val facet = module.getOrCreateFacet(modelsProvider, useProjectSettings = false, commitModel = true) + val facetSettings = facet.configuration.settings + val compilerSettings = facetSettings.compilerSettings ?: CompilerSettings().also { + facetSettings.compilerSettings = it + } + + compilerSettings.additionalArguments += " -Xuse-experimental=$annotationFqName" + facetSettings.updateMergedArguments() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt b/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt index d8c49612bde..488f55d3b29 100644 --- a/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt +++ b/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt @@ -3,6 +3,7 @@ // WITH_RUNTIME // ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Bar' // ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'bar' +// ACTION: Add '-Xuse-experimental=MyExperimentalAPI' to module light_idea_test_case compiler arguments // ERROR: This declaration is experimental and its usage must be marked with '@MyExperimentalAPI' or '@UseExperimental(MyExperimentalAPI::class)' // ERROR: This declaration is experimental and its usage must be marked with '@MyExperimentalAPI' or '@UseExperimental(MyExperimentalAPI::class)' diff --git a/idea/testData/quickfix/experimental/basicModule.kt b/idea/testData/quickfix/experimental/basicModule.kt new file mode 100644 index 00000000000..2c69f775cbd --- /dev/null +++ b/idea/testData/quickfix/experimental/basicModule.kt @@ -0,0 +1,21 @@ +// "Add '-Xuse-experimental=test.MyExperimentalAPI' to module light_idea_test_case compiler arguments" "true" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// COMPILER_ARGUMENTS_AFTER: -Xuse-experimental=kotlin.Experimental -Xuse-experimental=test.MyExperimentalAPI +// DISABLE-ERRORS +// WITH_RUNTIME + +package test + +@Experimental +annotation class MyExperimentalAPI + +@MyExperimentalAPI +class Some { + fun foo() {} +} + +class Bar { + fun bar() { + Some().foo() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/basicModule.kt.after b/idea/testData/quickfix/experimental/basicModule.kt.after new file mode 100644 index 00000000000..fa1e80b5a40 --- /dev/null +++ b/idea/testData/quickfix/experimental/basicModule.kt.after @@ -0,0 +1,21 @@ +// "Add '-Xuse-experimental=test.MyExperimentalAPI' to module light_idea_test_case compiler arguments" "true" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// COMPILER_ARGUMENTS_AFTER: -Xuse-experimental=kotlin.Experimental -Xuse-experimental=test.MyExperimentalAPI +// DISABLE-ERRORS +// WITH_RUNTIME + +package test + +@Experimental +annotation class MyExperimentalAPI + +@MyExperimentalAPI +class Some { + fun foo() {} +} + +class Bar { + fun bar() { + Some().foo() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/nestedClasses.kt b/idea/testData/quickfix/experimental/nestedClasses.kt index a4e6c037cf0..20e5d9030f8 100644 --- a/idea/testData/quickfix/experimental/nestedClasses.kt +++ b/idea/testData/quickfix/experimental/nestedClasses.kt @@ -4,6 +4,7 @@ // ACTION: Add '@MyExperimentalAPI' annotation to 'bar' // ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Inner' // ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'bar' +// ACTION: Add '-Xuse-experimental=MyExperimentalAPI' to module light_idea_test_case compiler arguments // ERROR: This declaration is experimental and its usage must be marked with '@MyExperimentalAPI' or '@UseExperimental(MyExperimentalAPI::class)' @Experimental diff --git a/idea/testData/quickfix/experimental/override.kt b/idea/testData/quickfix/experimental/override.kt index a85723b5ad9..7f85a7faca5 100644 --- a/idea/testData/quickfix/experimental/override.kt +++ b/idea/testData/quickfix/experimental/override.kt @@ -4,6 +4,7 @@ // ACTION: Add '@MyExperimentalAPI' annotation to 'foo' // ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'foo' // ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to containing class 'Derived' +// ACTION: Add '-Xuse-experimental=MyExperimentalAPI' to module light_idea_test_case compiler arguments // ERROR: This declaration overrides experimental member of supertype 'Base' and must be annotated with '@MyExperimentalAPI' @Experimental diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt index a2ad98ed0e9..1fcf78de605 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt @@ -29,6 +29,7 @@ import com.intellij.rt.execution.junit.FileComparisonFailure import com.intellij.testFramework.* import com.intellij.util.ui.UIUtil import junit.framework.TestCase +import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile import org.jetbrains.kotlin.idea.test.* import org.jetbrains.kotlin.psi.KtFile @@ -114,6 +115,13 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase() { applyAction(contents, fileName) + val compilerArgumentsAfter = InTextDirectivesUtils.findStringWithPrefixes(fileText, "COMPILER_ARGUMENTS_AFTER: ") + if (compilerArgumentsAfter != null) { + val facetSettings = KotlinFacet.get(module)!!.configuration.settings + val compilerSettings = facetSettings.compilerSettings + TestCase.assertEquals(compilerArgumentsAfter, compilerSettings?.additionalArguments) + } + UsefulTestCase.assertEmpty(expectedErrorMessage) } catch (e: FileComparisonFailure) { diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt.172 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt.172 index d45bfe0d005..63a5c82231c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt.172 +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixTest.kt.172 @@ -29,6 +29,7 @@ import com.intellij.rt.execution.junit.FileComparisonFailure import com.intellij.testFramework.* import com.intellij.util.ui.UIUtil import junit.framework.TestCase +import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile import org.jetbrains.kotlin.idea.test.* import org.jetbrains.kotlin.psi.KtFile @@ -98,6 +99,13 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase() { applyAction(contents, testFile.canonicalPath) + val compilerArgumentsAfter = InTextDirectivesUtils.findStringWithPrefixes(fileText, "COMPILER_ARGUMENTS_AFTER: ") + if (compilerArgumentsAfter != null) { + val facetSettings = KotlinFacet.get(module)!!.configuration.settings + val compilerSettings = facetSettings.compilerSettings + TestCase.assertEquals(compilerArgumentsAfter, compilerSettings?.additionalArguments) + } + UsefulTestCase.assertEmpty(expectedErrorMessage) } catch (e: FileComparisonFailure) { diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index d6b1c45bb6a..2b6dadc6e63 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6047,6 +6047,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt"); } + @TestMetadata("basicModule.kt") + public void testBasicModule() throws Exception { + runTest("idea/testData/quickfix/experimental/basicModule.kt"); + } + @TestMetadata("basicUseExperimental.kt") public void testBasicUseExperimental() throws Exception { runTest("idea/testData/quickfix/experimental/basicUseExperimental.kt");