Experimental fixes: introduce "add -Xuse-experimental" (KT-22760)
This commit is contained in:
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.idea.core.toDescriptor
|
|||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
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.psi.psiUtil.getParentOfTypesAndPredicate
|
||||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
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
|
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
|
// WITH_RUNTIME
|
||||||
// ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Bar'
|
// ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Bar'
|
||||||
// ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to '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)'
|
||||||
// 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)'
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
// ACTION: Add '@MyExperimentalAPI' annotation to 'bar'
|
// ACTION: Add '@MyExperimentalAPI' annotation to 'bar'
|
||||||
// ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Inner'
|
// ACTION: Add '@MyExperimentalAPI' annotation to containing class 'Inner'
|
||||||
// ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to '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)'
|
||||||
|
|
||||||
@Experimental
|
@Experimental
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
// ACTION: Add '@MyExperimentalAPI' annotation to 'foo'
|
// ACTION: Add '@MyExperimentalAPI' annotation to 'foo'
|
||||||
// ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'foo'
|
// ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'foo'
|
||||||
// ACTION: Add '@UseExperimental(MyExperimentalAPI::class)' annotation to containing class 'Derived'
|
// 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'
|
// ERROR: This declaration overrides experimental member of supertype 'Base' and must be annotated with '@MyExperimentalAPI'
|
||||||
|
|
||||||
@Experimental
|
@Experimental
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.intellij.rt.execution.junit.FileComparisonFailure
|
|||||||
import com.intellij.testFramework.*
|
import com.intellij.testFramework.*
|
||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile
|
import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile
|
||||||
import org.jetbrains.kotlin.idea.test.*
|
import org.jetbrains.kotlin.idea.test.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
@@ -114,6 +115,13 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase() {
|
|||||||
|
|
||||||
applyAction(contents, fileName)
|
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)
|
UsefulTestCase.assertEmpty(expectedErrorMessage)
|
||||||
}
|
}
|
||||||
catch (e: FileComparisonFailure) {
|
catch (e: FileComparisonFailure) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.intellij.rt.execution.junit.FileComparisonFailure
|
|||||||
import com.intellij.testFramework.*
|
import com.intellij.testFramework.*
|
||||||
import com.intellij.util.ui.UIUtil
|
import com.intellij.util.ui.UIUtil
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile
|
import org.jetbrains.kotlin.idea.quickfix.utils.findInspectionFile
|
||||||
import org.jetbrains.kotlin.idea.test.*
|
import org.jetbrains.kotlin.idea.test.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
@@ -98,6 +99,13 @@ abstract class AbstractQuickFixTest : KotlinLightCodeInsightFixtureTestCase() {
|
|||||||
|
|
||||||
applyAction(contents, testFile.canonicalPath)
|
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)
|
UsefulTestCase.assertEmpty(expectedErrorMessage)
|
||||||
}
|
}
|
||||||
catch (e: FileComparisonFailure) {
|
catch (e: FileComparisonFailure) {
|
||||||
|
|||||||
@@ -6047,6 +6047,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
runTest("idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt");
|
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")
|
@TestMetadata("basicUseExperimental.kt")
|
||||||
public void testBasicUseExperimental() throws Exception {
|
public void testBasicUseExperimental() throws Exception {
|
||||||
runTest("idea/testData/quickfix/experimental/basicUseExperimental.kt");
|
runTest("idea/testData/quickfix/experimental/basicUseExperimental.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user