From f404d6c97a89ab54fa43d1861ab69114a2b9f2a5 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 4 May 2018 15:45:43 +0300 Subject: [PATCH] Experimental fixes: introduce "add annotation" (KT-22760) --- .../kotlin/resolve/AnnotationChecker.kt | 18 ++--- .../kotlin/resolve/ModifiersChecker.kt | 4 +- .../kotlin/idea/quickfix/AddAnnotationFix.kt | 27 +++++++ .../idea/quickfix/AddAnnotationTargetFix.kt | 2 +- .../idea/quickfix/AddJvmDefaultAnnotation.kt | 12 +-- .../idea/quickfix/ExperimentalFixesFactory.kt | 73 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 5 ++ .../quickfix/experimental/basicFunction.kt | 15 ++++ .../experimental/basicFunction.kt.after | 16 ++++ .../basicFunctionContainingClass.kt | 15 ++++ .../basicFunctionContainingClass.kt.after | 16 ++++ .../basicFunctionNotApplicable.kt | 21 ++++++ .../quickfix/experimental/override.kt | 18 +++++ .../QuickFixMultiFileTestGenerated.java | 13 ++++ .../idea/quickfix/QuickFixTestGenerated.java | 33 +++++++++ 15 files changed, 266 insertions(+), 22 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationFix.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt create mode 100644 idea/testData/quickfix/experimental/basicFunction.kt create mode 100644 idea/testData/quickfix/experimental/basicFunction.kt.after create mode 100644 idea/testData/quickfix/experimental/basicFunctionContainingClass.kt create mode 100644 idea/testData/quickfix/experimental/basicFunctionContainingClass.kt.after create mode 100644 idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt create mode 100644 idea/testData/quickfix/experimental/override.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt index 8c068cb091d..78712c80403 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationChecker.kt @@ -34,7 +34,7 @@ class AnnotationChecker( private val languageVersionSettings: LanguageVersionSettings ) { fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) { - val actualTargets = getActualTargetList(annotated, descriptor, trace) + val actualTargets = getActualTargetList(annotated, descriptor, trace.bindingContext) checkEntries(annotated.annotationEntries, actualTargets, trace, annotated) if (annotated is KtCallableDeclaration) { annotated.typeReference?.let { check(it, trace) } @@ -64,7 +64,7 @@ class AnnotationChecker( } fun checkExpression(expression: KtExpression, trace: BindingTrace) { - checkEntries(expression.getAnnotationEntries(), getActualTargetList(expression, null, trace), trace) + checkEntries(expression.getAnnotationEntries(), getActualTargetList(expression, null, trace.bindingContext), trace) if (expression is KtLambdaExpression) { for (parameter in expression.valueParameters) { parameter.typeReference?.let { check(it, trace) } @@ -197,15 +197,15 @@ class AnnotationChecker( }.toSet() } - fun getDeclarationSiteActualTargetList(annotated: KtElement, descriptor: ClassDescriptor?, trace: BindingTrace): + fun getDeclarationSiteActualTargetList(annotated: KtElement, descriptor: ClassDescriptor?, context: BindingContext): List { - return getActualTargetList(annotated, descriptor, trace).defaultTargets + return getActualTargetList(annotated, descriptor, context).defaultTargets } - private fun DeclarationDescriptor?.hasBackingField(bindingTrace: BindingTrace) = - (this as? PropertyDescriptor)?.let { bindingTrace.get(BindingContext.BACKING_FIELD_REQUIRED, it) } ?: false + private fun DeclarationDescriptor?.hasBackingField(context: BindingContext) = + (this as? PropertyDescriptor)?.let { context.get(BindingContext.BACKING_FIELD_REQUIRED, it) } ?: false - fun getActualTargetList(annotated: KtElement, descriptor: DeclarationDescriptor?, trace: BindingTrace): TargetList { + fun getActualTargetList(annotated: KtElement, descriptor: DeclarationDescriptor?, context: BindingContext): TargetList { return when (annotated) { is KtClassOrObject -> (descriptor as? ClassDescriptor)?.let { TargetList(KotlinTarget.classActualTargets(it)) } ?: TargetLists.T_CLASSIFIER @@ -213,8 +213,8 @@ class AnnotationChecker( is KtProperty -> { when { annotated.isLocal -> TargetLists.T_LOCAL_VARIABLE - annotated.isMember -> TargetLists.T_MEMBER_PROPERTY(descriptor.hasBackingField(trace), annotated.hasDelegate()) - else -> TargetLists.T_TOP_LEVEL_PROPERTY(descriptor.hasBackingField(trace), annotated.hasDelegate()) + annotated.isMember -> TargetLists.T_MEMBER_PROPERTY(descriptor.hasBackingField(context), annotated.hasDelegate()) + else -> TargetLists.T_TOP_LEVEL_PROPERTY(descriptor.hasBackingField(context), annotated.hasDelegate()) } } is KtParameter -> { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt index 6c6ef1f3752..24a93d35b24 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt @@ -446,7 +446,9 @@ object ModifierCheckerCore { } } } - val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor, trace) + val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList( + listOwner, descriptor as? ClassDescriptor, trace.bindingContext + ) val list = listOwner.modifierList ?: return checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets, languageVersionSettings) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationFix.kt new file mode 100644 index 00000000000..b14fb63cbb1 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationFix.kt @@ -0,0 +1,27 @@ +/* + * 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.project.Project +import org.jetbrains.kotlin.idea.util.addAnnotation +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtFile + +open class AddAnnotationFix( + element: KtDeclaration, + private val annotationFqName: FqName, + private val suffix: String = "" +) : KotlinQuickFixAction(element) { + override fun getText(): String = "Add '@${annotationFqName.shortName()}' annotation$suffix" + + override fun getFamilyName(): String = "Add annotation" + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + element?.addAnnotation(annotationFqName) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationTargetFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationTargetFix.kt index 1fc6d5d7924..6a288f30c35 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationTargetFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddAnnotationTargetFix.kt @@ -122,7 +122,7 @@ private fun KtAnnotationEntry.getActualTargetList(): List { ?: getStrictParentOfType() ?: return emptyList() - val targetList = AnnotationChecker.getActualTargetList(annotatedElement, null, BindingTraceContext()) + val targetList = AnnotationChecker.getActualTargetList(annotatedElement, null, BindingTraceContext().bindingContext) val useSiteTarget = this.useSiteTarget ?: return targetList.defaultTargets val annotationUseSiteTarget = useSiteTarget.getAnnotationUseSiteTarget() diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmDefaultAnnotation.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmDefaultAnnotation.kt index 910a6ba2bc5..c1705859086 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmDefaultAnnotation.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddJvmDefaultAnnotation.kt @@ -6,25 +6,15 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInsight.intention.IntentionAction -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.project.Project import org.jetbrains.kotlin.diagnostics.Diagnostic -import org.jetbrains.kotlin.idea.util.addAnnotation import org.jetbrains.kotlin.psi.KtCallableDeclaration -import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.resolve.annotations.JVM_DEFAULT_FQ_NAME -class AddJvmDefaultAnnotation(declaration: KtCallableDeclaration) : KotlinQuickFixAction(declaration) { - override fun getText(): String = "Add '@JvmDefault' annotation" - +class AddJvmDefaultAnnotation(declaration: KtCallableDeclaration) : AddAnnotationFix(declaration, JVM_DEFAULT_FQ_NAME) { override fun getFamilyName(): String = text - override fun invoke(project: Project, editor: Editor?, file: KtFile) { - element?.addAnnotation(JVM_DEFAULT_FQ_NAME) - } - companion object : KotlinSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { val psiElement = diagnostic.psiElement diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt new file mode 100644 index 00000000000..e3aa38d935a --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ExperimentalFixesFactory.kt @@ -0,0 +1,73 @@ +/* + * 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.codeInsight.intention.IntentionAction +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget +import org.jetbrains.kotlin.descriptors.resolveClassByFqName +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny +import org.jetbrains.kotlin.idea.core.toDescriptor +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.psi.KtCallableDeclaration +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType +import org.jetbrains.kotlin.resolve.AnnotationChecker +import org.jetbrains.kotlin.resolve.descriptorUtil.module + +object ExperimentalFixesFactory : KotlinIntentionActionsFactory() { + override fun doCreateActions(diagnostic: Diagnostic): List { + val element = diagnostic.psiElement + val containingDeclaration: KtDeclaration = element.getStrictParentOfType() ?: return emptyList() + + val factory = diagnostic.factory + val annotationFqName = when (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 + EXPERIMENTAL_OVERRIDE_ERROR -> EXPERIMENTAL_OVERRIDE_ERROR.cast(diagnostic).a + else -> null + } ?: return emptyList() + + val moduleDescriptor = containingDeclaration.resolveToDescriptorIfAny()?.module ?: return emptyList() + val annotationClassDescriptor = moduleDescriptor.resolveClassByFqName( + annotationFqName, NoLookupLocation.FROM_IDE + ) ?: return emptyList() + val applicableTargets = AnnotationChecker.applicableTargetSet(annotationClassDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET + + val context = when (element) { + is KtElement -> element.analyze() + else -> containingDeclaration.analyze() + } + + fun isApplicableTo(declaration: KtDeclaration, applicableTargets: Set): Boolean { + val actualTargetList = AnnotationChecker.getDeclarationSiteActualTargetList( + declaration, declaration.toDescriptor() as? ClassDescriptor, context + ) + return actualTargetList.any { it in applicableTargets } + } + + val result = mutableListOf() + if (isApplicableTo(containingDeclaration, applicableTargets)) { + result.add(AddAnnotationFix(containingDeclaration, annotationFqName, " to '${containingDeclaration.name}'")) + } + if (containingDeclaration is KtCallableDeclaration) { + val containingClassOrObject = containingDeclaration.containingClassOrObject + if (containingClassOrObject != null && isApplicableTo(containingClassOrObject, applicableTargets)) { + result.add( + AddAnnotationFix(containingClassOrObject, annotationFqName, " to containing class '${containingClassOrObject.name}'") + ) + } + } + + return result + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 96f6ed68f54..fc732930eac 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -546,5 +546,10 @@ class QuickFixRegistrar : QuickFixContributor { JVM_DEFAULT_REQUIRED_FOR_OVERRIDE.registerFactory(AddJvmDefaultAnnotation) NON_JVM_DEFAULT_OVERRIDES_JAVA_DEFAULT.registerFactory(AddJvmDefaultAnnotation) + + EXPERIMENTAL_API_USAGE.registerFactory(ExperimentalFixesFactory) + EXPERIMENTAL_API_USAGE_ERROR.registerFactory(ExperimentalFixesFactory) + EXPERIMENTAL_OVERRIDE.registerFactory(ExperimentalFixesFactory) + EXPERIMENTAL_OVERRIDE_ERROR.registerFactory(ExperimentalFixesFactory) } } diff --git a/idea/testData/quickfix/experimental/basicFunction.kt b/idea/testData/quickfix/experimental/basicFunction.kt new file mode 100644 index 00000000000..418e6774efd --- /dev/null +++ b/idea/testData/quickfix/experimental/basicFunction.kt @@ -0,0 +1,15 @@ +// "Add '@MyExperimentalAPI' annotation to 'bar'" "true" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// WITH_RUNTIME + +@Experimental +annotation class MyExperimentalAPI + +@MyExperimentalAPI +fun foo() {} + +class Bar { + fun bar() { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/basicFunction.kt.after b/idea/testData/quickfix/experimental/basicFunction.kt.after new file mode 100644 index 00000000000..4013f9269fa --- /dev/null +++ b/idea/testData/quickfix/experimental/basicFunction.kt.after @@ -0,0 +1,16 @@ +// "Add '@MyExperimentalAPI' annotation to 'bar'" "true" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// WITH_RUNTIME + +@Experimental +annotation class MyExperimentalAPI + +@MyExperimentalAPI +fun foo() {} + +class Bar { + @MyExperimentalAPI + fun bar() { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/basicFunctionContainingClass.kt b/idea/testData/quickfix/experimental/basicFunctionContainingClass.kt new file mode 100644 index 00000000000..d5e71f12560 --- /dev/null +++ b/idea/testData/quickfix/experimental/basicFunctionContainingClass.kt @@ -0,0 +1,15 @@ +// "Add '@MyExperimentalAPI' annotation to containing class 'Bar'" "true" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// WITH_RUNTIME + +@Experimental +annotation class MyExperimentalAPI + +@MyExperimentalAPI +fun foo() {} + +class Bar { + fun bar() { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/basicFunctionContainingClass.kt.after b/idea/testData/quickfix/experimental/basicFunctionContainingClass.kt.after new file mode 100644 index 00000000000..3ebbfa17822 --- /dev/null +++ b/idea/testData/quickfix/experimental/basicFunctionContainingClass.kt.after @@ -0,0 +1,16 @@ +// "Add '@MyExperimentalAPI' annotation to containing class 'Bar'" "true" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// WITH_RUNTIME + +@Experimental +annotation class MyExperimentalAPI + +@MyExperimentalAPI +fun foo() {} + +@MyExperimentalAPI +class Bar { + fun bar() { + foo() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt b/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt new file mode 100644 index 00000000000..c58e4d17e2a --- /dev/null +++ b/idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt @@ -0,0 +1,21 @@ +// "Add '@MyExperimentalAPI' annotation to 'bar'" "false" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// WITH_RUNTIME +// ACTION: Add '@MyExperimentalAPI' annotation to containing class '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)' + +@Experimental +@Target(AnnotationTarget.CLASS) +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/override.kt b/idea/testData/quickfix/experimental/override.kt new file mode 100644 index 00000000000..9bd3122e33b --- /dev/null +++ b/idea/testData/quickfix/experimental/override.kt @@ -0,0 +1,18 @@ +// "Add '@MyExperimentalAPI' annotation to containing class 'Derived'" "false" +// COMPILER_ARGUMENTS: -Xuse-experimental=kotlin.Experimental +// WITH_RUNTIME +// ACTION: Add '@MyExperimentalAPI' annotation to 'foo' +// ERROR: This declaration overrides experimental member of supertype 'Base' and must be annotated with '@MyExperimentalAPI' + +@Experimental +@Target(AnnotationTarget.FUNCTION) +annotation class MyExperimentalAPI + +open class Base { + @MyExperimentalAPI + open fun foo() {} +} + +class Derived : Base() { + override fun foo() {} +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index ee242dcd0f5..b769db2efa3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -2455,6 +2455,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/experimental") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Experimental extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInExperimental() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/experimental"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + @TestMetadata("idea/testData/quickfix/expressions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 69e65b4b46a..25c2595a3a1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6026,6 +6026,39 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/experimental") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Experimental extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInExperimental() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/experimental"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("basicFunction.kt") + public void testBasicFunction() throws Exception { + runTest("idea/testData/quickfix/experimental/basicFunction.kt"); + } + + @TestMetadata("basicFunctionContainingClass.kt") + public void testBasicFunctionContainingClass() throws Exception { + runTest("idea/testData/quickfix/experimental/basicFunctionContainingClass.kt"); + } + + @TestMetadata("basicFunctionNotApplicable.kt") + public void testBasicFunctionNotApplicable() throws Exception { + runTest("idea/testData/quickfix/experimental/basicFunctionNotApplicable.kt"); + } + + @TestMetadata("override.kt") + public void testOverride() throws Exception { + runTest("idea/testData/quickfix/experimental/override.kt"); + } + } + @TestMetadata("idea/testData/quickfix/expressions") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)