Experimental fixes: introduce "add -Xuse-experimental" (KT-22760)

This commit is contained in:
Mikhail Glukhikh
2018-05-08 13:06:27 +03:00
parent 30c62bccb2
commit c77c8d872c
10 changed files with 111 additions and 0 deletions
@@ -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
}
@@ -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<KtFile>(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()
}
}
@@ -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)'
+21
View File
@@ -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<caret>()
}
}
@@ -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()
}
}
+1
View File
@@ -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
+1
View File
@@ -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
@@ -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) {
@@ -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) {
@@ -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");