Add quickfix for replacing positioned arguments in Java annotation
This commit is contained in:
+1
-6
@@ -60,12 +60,7 @@ public class JavaAnnotationCallChecker : CallChecker {
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
context: BasicCallResolutionContext
|
||||
) {
|
||||
resolvedCall.getValueArguments().filter {
|
||||
p ->
|
||||
p.key.getName() != JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME &&
|
||||
p.value is ExpressionValueArgument &&
|
||||
!((p.value as ExpressionValueArgument).getValueArgument()?.isNamed() ?: true)
|
||||
}.forEach {
|
||||
getJavaAnnotationCallValueArgumentsThatShouldBeNamed(resolvedCall).forEach {
|
||||
reportOnValueArgument(context, it, ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.load.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||
|
||||
fun getJavaAnnotationCallValueArgumentsThatShouldBeNamed(resolvedCall: ResolvedCall<*>): Map<ValueParameterDescriptor, ResolvedValueArgument> =
|
||||
resolvedCall.getValueArguments().filter {
|
||||
p ->
|
||||
p.key.getName() != JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME &&
|
||||
p.value is ExpressionValueArgument &&
|
||||
!((p.value as ExpressionValueArgument).getValueArgument()?.isNamed() ?: true)
|
||||
}
|
||||
|
||||
@@ -76,7 +76,8 @@ public class KotlinCleanupInspection(): LocalInspectionTool(), CleanupLocalInspe
|
||||
Errors.UNNECESSARY_NOT_NULL_ASSERTION,
|
||||
Errors.UNNECESSARY_SAFE_CALL,
|
||||
Errors.USELESS_CAST,
|
||||
Errors.USELESS_ELVIS
|
||||
Errors.USELESS_ELVIS,
|
||||
ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION
|
||||
)
|
||||
|
||||
private fun Diagnostic.isObsoleteLabel(): Boolean {
|
||||
|
||||
@@ -346,5 +346,7 @@ public class QuickFixRegistrar {
|
||||
|
||||
QuickFixes.factories.put(DEPRECATED_SYMBOL_WITH_MESSAGE, DeprecatedSymbolUsageFix.Companion);
|
||||
QuickFixes.factories.put(DEPRECATED_SYMBOL_WITH_MESSAGE, DeprecatedSymbolUsageInWholeProjectFix.Companion);
|
||||
|
||||
QuickFixes.factories.put(ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION, ReplaceJavaAnnotationPositionedArgumentsFix.Companion);
|
||||
}
|
||||
}
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
|
||||
import org.jetbrains.kotlin.load.kotlin.getJavaAnnotationCallValueArgumentsThatShouldBeNamed
|
||||
import org.jetbrains.kotlin.psi.JetAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ExpressionValueArgument
|
||||
|
||||
public class ReplaceJavaAnnotationPositionedArgumentsFix(element: JetAnnotationEntry)
|
||||
: JetIntentionAction<JetAnnotationEntry>(element), CleanupFix {
|
||||
override fun getText(): String = "Replace invalid positioned arguments for annotation"
|
||||
override fun getFamilyName(): String = getText()
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return
|
||||
val psiFactory = JetPsiFactory(project)
|
||||
|
||||
getJavaAnnotationCallValueArgumentsThatShouldBeNamed(resolvedCall).forEach argumentProcessor@{
|
||||
argument ->
|
||||
val valueArgument = (argument.value as? ExpressionValueArgument)?.getValueArgument() ?: return@argumentProcessor
|
||||
val expression = valueArgument.getArgumentExpression() ?: return@argumentProcessor
|
||||
|
||||
valueArgument.asElement().replace(psiFactory.createArgument(expression, argument.getKey().getName().asString()))
|
||||
}
|
||||
}
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic) =
|
||||
diagnostic.createIntentionForFirstParentOfType(::ReplaceJavaAnnotationPositionedArgumentsFix)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
public @interface JavaAnn {
|
||||
int value();
|
||||
String arg1();
|
||||
Class<?>[] arg2();
|
||||
Class<?> arg3();
|
||||
int arg4() default 0;
|
||||
}
|
||||
@@ -42,3 +42,5 @@ fun unnecessaryExclExcl(x: String) {
|
||||
fun unnecessaryCast(x: String) = x as String
|
||||
|
||||
fun unnecessaryElvis(x: String) = x ?: ""
|
||||
|
||||
JavaAnn(1, "abc", arrayOf(javaClass<Array<Int>>()), javaClass<String>()) class MyClass
|
||||
|
||||
@@ -44,3 +44,5 @@ fun unnecessaryExclExcl(x: String) {
|
||||
fun unnecessaryCast(x: String) = x
|
||||
|
||||
fun unnecessaryElvis(x: String) = x
|
||||
|
||||
JavaAnn(1, arg1 = "abc", arg2 = arrayOf(Array<Int>::class), arg3 = String::class) class MyClass
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Replace invalid positioned arguments for annotation" "true"
|
||||
// WITH_RUNTIME
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
|
||||
Ann(1, /*abc*/arg1 = "abc", arg2 = arrayOf(Int::class, Array<Int>::class), arg3 = String::class) class A
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Replace invalid positioned arguments for annotation" "true"
|
||||
// WITH_RUNTIME
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
|
||||
Ann(1, /*abc*/"abc", arrayOf(Int::class, Array<Int>::class)<caret>, arg3 = String::class) class A
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public @interface Ann {
|
||||
int value();
|
||||
String arg1();
|
||||
Class<?>[] arg2();
|
||||
Class<?> arg3();
|
||||
int arg4() default 0;
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Replace invalid positioned arguments for annotation" "true"
|
||||
// WITH_RUNTIME
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
// ERROR: No value passed for parameter arg2
|
||||
|
||||
Ann(1, arg1 = "abc") class A
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Replace invalid positioned arguments for annotation" "true"
|
||||
// WITH_RUNTIME
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
// ERROR: No value passed for parameter arg2
|
||||
|
||||
Ann(1, "abc"<caret>) class A
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
public @interface Ann {
|
||||
int value();
|
||||
String arg1();
|
||||
Class<?> arg2();
|
||||
int arg3() default 0;
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Replace invalid positioned arguments for annotation" "true"
|
||||
// WITH_RUNTIME
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
// ERROR: An integer literal does not conform to the expected type kotlin.String
|
||||
|
||||
Ann(1, arg1 = 2) class A
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Replace invalid positioned arguments for annotation" "true"
|
||||
// WITH_RUNTIME
|
||||
// ERROR: Only named arguments are available for Java annotations
|
||||
// ERROR: An integer literal does not conform to the expected type kotlin.String
|
||||
|
||||
Ann(1, 2<caret>) class A
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
public @interface Ann {
|
||||
int value();
|
||||
String arg1();
|
||||
int arg2() default 0;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ class KotlinCleanupInspectionTest(): JetLightCodeInsightFixtureTestCase() {
|
||||
|
||||
public fun testCleanup() {
|
||||
myFixture.enableInspections(javaClass<KotlinCleanupInspection>())
|
||||
myFixture.configureByFile("cleanup.kt")
|
||||
myFixture.configureByFiles("cleanup.kt", "JavaAnn.java")
|
||||
|
||||
val project = myFixture.getProject()
|
||||
val managerEx = InspectionManager.getInstance(project)
|
||||
|
||||
@@ -948,6 +948,33 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/migration/javaAnnotationPositionedArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class JavaAnnotationPositionedArguments extends AbstractQuickFixMultiFileTest {
|
||||
public void testAllFilesPresentInJavaAnnotationPositionedArguments() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/migration/javaAnnotationPositionedArguments"), Pattern.compile("^(\\w+)\\.before\\.Main\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("basicMultiple.before.Main.kt")
|
||||
public void testBasicMultiple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/javaAnnotationPositionedArguments/basicMultiple.before.Main.kt");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noValueForArgumentMultiple.before.Main.kt")
|
||||
public void testNoValueForArgumentMultiple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/javaAnnotationPositionedArguments/noValueForArgumentMultiple.before.Main.kt");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("wrongTypeMultiple.before.Main.kt")
|
||||
public void testWrongTypeMultiple() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/migration/javaAnnotationPositionedArguments/wrongTypeMultiple.before.Main.kt");
|
||||
doTestWithExtraFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/migration/lambdaSyntax")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user