From e6de8e9cd34111ced09f0cf7e7e7c9051f246302 Mon Sep 17 00:00:00 2001 From: kenji tomita Date: Sat, 10 Mar 2018 05:20:25 +0300 Subject: [PATCH] Inspection to convert Arrays.copyOf(a, size) to a.copyOf(size) --- .../ReplaceArraysCopyOfWithCopyOf.html | 5 ++ idea/src/META-INF/plugin.xml | 9 +++ idea/src/META-INF/plugin.xml.173 | 9 +++ idea/src/META-INF/plugin.xml.181 | 9 +++ idea/src/META-INF/plugin.xml.183 | 9 +++ idea/src/META-INF/plugin.xml.as31 | 9 +++ idea/src/META-INF/plugin.xml.as32 | 9 +++ idea/src/META-INF/plugin.xml.as33 | 9 +++ ...ReplaceArraysCopyOfWithCopyOfInspection.kt | 57 +++++++++++++++++++ .../replaceArraysCopyOfWithCopyOf/.inspection | 1 + .../nonArraysCopyOf.kt | 10 ++++ .../replaceArraysCopyOfWithCopyOf/simple.kt | 7 +++ .../simple.kt.after | 7 +++ .../LocalInspectionTestGenerated.java | 21 +++++++ 14 files changed, 171 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/ReplaceArraysCopyOfWithCopyOf.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceArraysCopyOfWithCopyOfInspection.kt create mode 100644 idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/.inspection create mode 100644 idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/nonArraysCopyOf.kt create mode 100644 idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt create mode 100644 idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt.after diff --git a/idea/resources/inspectionDescriptions/ReplaceArraysCopyOfWithCopyOf.html b/idea/resources/inspectionDescriptions/ReplaceArraysCopyOfWithCopyOf.html new file mode 100644 index 00000000000..05d19098e40 --- /dev/null +++ b/idea/resources/inspectionDescriptions/ReplaceArraysCopyOfWithCopyOf.html @@ -0,0 +1,5 @@ + + +This inspection reports Arrays.copyOf function calls replaceable with copyOf. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 1e4ae558228..3f93b5d4322 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -3085,6 +3085,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173 index 3ed788f4488..399ebb0ef3c 100644 --- a/idea/src/META-INF/plugin.xml.173 +++ b/idea/src/META-INF/plugin.xml.173 @@ -3083,6 +3083,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.181 b/idea/src/META-INF/plugin.xml.181 index d4830ccb535..7f9845bcb5c 100644 --- a/idea/src/META-INF/plugin.xml.181 +++ b/idea/src/META-INF/plugin.xml.181 @@ -3084,6 +3084,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.183 b/idea/src/META-INF/plugin.xml.183 index 07cc471768f..44c890a5623 100644 --- a/idea/src/META-INF/plugin.xml.183 +++ b/idea/src/META-INF/plugin.xml.183 @@ -3085,6 +3085,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31 index de71a9656a1..adf5bfbfcf9 100644 --- a/idea/src/META-INF/plugin.xml.as31 +++ b/idea/src/META-INF/plugin.xml.as31 @@ -3083,6 +3083,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32 index 013563f1806..ac1f7040445 100644 --- a/idea/src/META-INF/plugin.xml.as32 +++ b/idea/src/META-INF/plugin.xml.as32 @@ -3083,6 +3083,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as33 b/idea/src/META-INF/plugin.xml.as33 index fab115f77fd..21ab89b6a6e 100644 --- a/idea/src/META-INF/plugin.xml.as33 +++ b/idea/src/META-INF/plugin.xml.as33 @@ -3085,6 +3085,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceArraysCopyOfWithCopyOfInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceArraysCopyOfWithCopyOfInspection.kt new file mode 100644 index 00000000000..8513c19b556 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ReplaceArraysCopyOfWithCopyOfInspection.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2000-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.inspections + +import com.intellij.codeInspection.LocalQuickFix +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.idea.intentions.callExpression +import org.jetbrains.kotlin.idea.intentions.calleeName +import org.jetbrains.kotlin.idea.intentions.getCallableDescriptor +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe + +class ReplaceArraysCopyOfWithCopyOfInspection : AbstractKotlinInspection() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor { + return object : KtVisitorVoid() { + override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) { + super.visitDotQualifiedExpression(expression) + + if (expression.isArraysCopyOf()) { + holder.registerProblem( + expression, + "Replace 'Arrays.copyOf' with 'copyOf'", + ProblemHighlightType.WEAK_WARNING, + ReplaceArraysCopyOfWithCopyOfQuickfix() + ) + } + } + } + } +} + +class ReplaceArraysCopyOfWithCopyOfQuickfix : LocalQuickFix { + override fun getName() = "Replace 'Arrays.copyOf' with 'copyOf'" + + override fun getFamilyName() = name + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + val element = descriptor.psiElement as KtDotQualifiedExpression + val args = element.callExpression?.valueArguments?.mapNotNull { it.getArgumentExpression() }?.toTypedArray() ?: return + element.replace(KtPsiFactory(element).createExpressionByPattern("$0.copyOf($1)", *args)) + } +} + +private fun KtDotQualifiedExpression.isArraysCopyOf(): Boolean { + if (callExpression?.valueArguments?.size != 2) return false + if (callExpression?.valueArguments?.mapNotNull { it.getArgumentExpression() }?.size != 2) return false + if (calleeName != "copyOf") return false + return getCallableDescriptor()?.containingDeclaration?.fqNameSafe == FqName("java.util.Arrays") +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/.inspection b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/.inspection new file mode 100644 index 00000000000..8c5e1815c2f --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.ReplaceArraysCopyOfWithCopyOfInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/nonArraysCopyOf.kt b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/nonArraysCopyOf.kt new file mode 100644 index 00000000000..949cbf6597e --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/nonArraysCopyOf.kt @@ -0,0 +1,10 @@ +// PROBLEM: none + +class A { + fun copyOf(x: Int, y: Int) { + } +} + +fun test() { + A().copyOf(1, 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt new file mode 100644 index 00000000000..acbc9f7efc7 --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME +import java.util.Arrays + +fun test() { + val array = intArrayOf(1, 2, 3) + val result = Arrays.copyOf(array, 3) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt.after b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt.after new file mode 100644 index 00000000000..cf70f7617ee --- /dev/null +++ b/idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME +import java.util.Arrays + +fun test() { + val array = intArrayOf(1, 2, 3) + val result = array.copyOf(3) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 051258096b4..27eee1ee784 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -5117,6 +5117,27 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ReplaceArraysCopyOfWithCopyOf extends AbstractLocalInspectionTest { + public void testAllFilesPresentInReplaceArraysCopyOfWithCopyOf() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("nonArraysCopyOf.kt") + public void testNonArraysCopyOf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/nonArraysCopyOf.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArraysCopyOfWithCopyOf/simple.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/inspectionsLocal/replacePutWithAssignment") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)