Experimental fixes: introduce "Add @UseExperimental" #KT-22760 Fixed
This commit is contained in:
+1
-1
@@ -61,7 +61,7 @@ class ExperimentalUsageChecker(project: Project) : CallChecker {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
|
val EXPERIMENTAL_FQ_NAME = FqName("kotlin.Experimental")
|
||||||
internal val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
|
val USE_EXPERIMENTAL_FQ_NAME = FqName("kotlin.UseExperimental")
|
||||||
internal val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental")
|
internal val WAS_EXPERIMENTAL_FQ_NAME = FqName("kotlin.WasExperimental")
|
||||||
internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
internal val USE_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
||||||
internal val WAS_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
internal val WAS_EXPERIMENTAL_ANNOTATION_CLASS = Name.identifier("markerClass")
|
||||||
|
|||||||
@@ -15,13 +15,17 @@ import org.jetbrains.kotlin.psi.KtFile
|
|||||||
open class AddAnnotationFix(
|
open class AddAnnotationFix(
|
||||||
element: KtDeclaration,
|
element: KtDeclaration,
|
||||||
private val annotationFqName: FqName,
|
private val annotationFqName: FqName,
|
||||||
private val suffix: String = ""
|
private val suffix: String = "",
|
||||||
|
private val argumentClassFqName: FqName? = null
|
||||||
) : KotlinQuickFixAction<KtDeclaration>(element) {
|
) : KotlinQuickFixAction<KtDeclaration>(element) {
|
||||||
override fun getText(): String = "Add '@${annotationFqName.shortName()}' annotation$suffix"
|
override fun getText(): String {
|
||||||
|
val argumentsAsString = argumentClassFqName?.shortName()?.let { "($it::class)" } ?: ""
|
||||||
|
return "Add '@${annotationFqName.shortName()}$argumentsAsString' annotation$suffix"
|
||||||
|
}
|
||||||
|
|
||||||
override fun getFamilyName(): String = "Add annotation"
|
override fun getFamilyName(): String = "Add annotation"
|
||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
element?.addAnnotation(annotationFqName)
|
element?.addAnnotation(annotationFqName, annotationInnerText = argumentClassFqName?.let { "$it::class" })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.psi.KtElement
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||||
|
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
object ExperimentalFixesFactory : KotlinIntentionActionsFactory() {
|
object ExperimentalFixesFactory : KotlinIntentionActionsFactory() {
|
||||||
@@ -56,15 +57,30 @@ object ExperimentalFixesFactory : KotlinIntentionActionsFactory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val result = mutableListOf<IntentionAction>()
|
val result = mutableListOf<IntentionAction>()
|
||||||
if (isApplicableTo(containingDeclaration, applicableTargets)) {
|
run {
|
||||||
result.add(AddAnnotationFix(containingDeclaration, annotationFqName, " to '${containingDeclaration.name}'"))
|
val suffix = " to '${containingDeclaration.name}'"
|
||||||
|
if (isApplicableTo(containingDeclaration, applicableTargets)) {
|
||||||
|
result.add(AddAnnotationFix(containingDeclaration, annotationFqName, suffix))
|
||||||
|
}
|
||||||
|
result.add(
|
||||||
|
AddAnnotationFix(
|
||||||
|
containingDeclaration, ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME, suffix, annotationFqName
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (containingDeclaration is KtCallableDeclaration) {
|
if (containingDeclaration is KtCallableDeclaration) {
|
||||||
val containingClassOrObject = containingDeclaration.containingClassOrObject
|
val containingClassOrObject = containingDeclaration.containingClassOrObject
|
||||||
if (containingClassOrObject != null && isApplicableTo(containingClassOrObject, applicableTargets)) {
|
if (containingClassOrObject != null) {
|
||||||
result.add(
|
val suffix = " to containing class '${containingClassOrObject.name}'"
|
||||||
AddAnnotationFix(containingClassOrObject, annotationFqName, " to containing class '${containingClassOrObject.name}'")
|
if (isApplicableTo(containingClassOrObject, applicableTargets)) {
|
||||||
)
|
result.add(AddAnnotationFix(containingClassOrObject, annotationFqName, suffix))
|
||||||
|
} else {
|
||||||
|
result.add(
|
||||||
|
AddAnnotationFix(
|
||||||
|
containingClassOrObject, ExperimentalUsageChecker.USE_EXPERIMENTAL_FQ_NAME, suffix, annotationFqName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
||||||
// 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'
|
||||||
// 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,20 @@
|
|||||||
|
// "Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'bar'" "true"
|
||||||
|
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
package a.b
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
annotation class MyExperimentalAPI
|
||||||
|
|
||||||
|
@MyExperimentalAPI
|
||||||
|
class Some {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
fun bar() {
|
||||||
|
Some().foo<caret>()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// "Add '@UseExperimental(MyExperimentalAPI::class)' annotation to 'bar'" "true"
|
||||||
|
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
package a.b
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
annotation class MyExperimentalAPI
|
||||||
|
|
||||||
|
@MyExperimentalAPI
|
||||||
|
class Some {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
@UseExperimental(MyExperimentalAPI::class)
|
||||||
|
fun bar() {
|
||||||
|
Some().foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// "Add '@UseExperimental(MyExperimentalAPI::class)' annotation to containing class 'Bar'" "true"
|
||||||
|
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
package a.b
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
|
annotation class MyExperimentalAPI
|
||||||
|
|
||||||
|
@MyExperimentalAPI
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
class Bar {
|
||||||
|
fun bar() {
|
||||||
|
foo<caret>()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// "Add '@UseExperimental(MyExperimentalAPI::class)' annotation to containing class 'Bar'" "true"
|
||||||
|
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
package a.b
|
||||||
|
|
||||||
|
@Experimental
|
||||||
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
|
annotation class MyExperimentalAPI
|
||||||
|
|
||||||
|
@MyExperimentalAPI
|
||||||
|
fun foo() {}
|
||||||
|
|
||||||
|
@UseExperimental(MyExperimentalAPI::class)
|
||||||
|
class Bar {
|
||||||
|
fun bar() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental
|
||||||
// WITH_RUNTIME
|
// WITH_RUNTIME
|
||||||
// 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 containing class 'Derived'
|
||||||
// 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
|
||||||
|
|||||||
@@ -6053,6 +6053,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
runTest("idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt");
|
runTest("idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("basicUseExperimental.kt")
|
||||||
|
public void testBasicUseExperimental() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/experimental/basicUseExperimental.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classUseExperimental.kt")
|
||||||
|
public void testClassUseExperimental() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/experimental/classUseExperimental.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("override.kt")
|
@TestMetadata("override.kt")
|
||||||
public void testOverride() throws Exception {
|
public void testOverride() throws Exception {
|
||||||
runTest("idea/testData/quickfix/experimental/override.kt");
|
runTest("idea/testData/quickfix/experimental/override.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user