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<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
context: BasicCallResolutionContext
|
context: BasicCallResolutionContext
|
||||||
) {
|
) {
|
||||||
resolvedCall.getValueArguments().filter {
|
getJavaAnnotationCallValueArgumentsThatShouldBeNamed(resolvedCall).forEach {
|
||||||
p ->
|
|
||||||
p.key.getName() != JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME &&
|
|
||||||
p.value is ExpressionValueArgument &&
|
|
||||||
!((p.value as ExpressionValueArgument).getValueArgument()?.isNamed() ?: true)
|
|
||||||
}.forEach {
|
|
||||||
reportOnValueArgument(context, it, ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION)
|
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_NOT_NULL_ASSERTION,
|
||||||
Errors.UNNECESSARY_SAFE_CALL,
|
Errors.UNNECESSARY_SAFE_CALL,
|
||||||
Errors.USELESS_CAST,
|
Errors.USELESS_CAST,
|
||||||
Errors.USELESS_ELVIS
|
Errors.USELESS_ELVIS,
|
||||||
|
ErrorsJvm.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun Diagnostic.isObsoleteLabel(): Boolean {
|
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, DeprecatedSymbolUsageFix.Companion);
|
||||||
QuickFixes.factories.put(DEPRECATED_SYMBOL_WITH_MESSAGE, DeprecatedSymbolUsageInWholeProjectFix.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 unnecessaryCast(x: String) = x as String
|
||||||
|
|
||||||
fun unnecessaryElvis(x: String) = x ?: ""
|
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 unnecessaryCast(x: String) = x
|
||||||
|
|
||||||
fun unnecessaryElvis(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() {
|
public fun testCleanup() {
|
||||||
myFixture.enableInspections(javaClass<KotlinCleanupInspection>())
|
myFixture.enableInspections(javaClass<KotlinCleanupInspection>())
|
||||||
myFixture.configureByFile("cleanup.kt")
|
myFixture.configureByFiles("cleanup.kt", "JavaAnn.java")
|
||||||
|
|
||||||
val project = myFixture.getProject()
|
val project = myFixture.getProject()
|
||||||
val managerEx = InspectionManager.getInstance(project)
|
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")
|
@TestMetadata("idea/testData/quickfix/migration/lambdaSyntax")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user