Introduce inspection "replace arrayOf with literal" #KT-17164 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
fb9d88315a
commit
9990550429
@@ -40,7 +40,7 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.createTypeInfo
|
||||
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
||||
|
||||
object CollectionLiteralResolver {
|
||||
private val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
|
||||
val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
|
||||
PrimitiveType.BOOLEAN to Name.identifier("booleanArrayOf"),
|
||||
PrimitiveType.CHAR to Name.identifier("charArrayOf"),
|
||||
PrimitiveType.INT to Name.identifier("intArrayOf"),
|
||||
@@ -51,7 +51,7 @@ object CollectionLiteralResolver {
|
||||
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
|
||||
)
|
||||
|
||||
private val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
|
||||
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
|
||||
|
||||
fun resolveCollectionLiteral(collectionLiteralExpression: KtCollectionLiteralExpression,
|
||||
context: ExpressionTypingContext,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports 'arrayOf' calls that can be replaced with array literals [...].
|
||||
</body>
|
||||
</html>
|
||||
@@ -2151,6 +2151,14 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.ReplaceArrayOfWithLiteralInspection"
|
||||
displayName="'arrayOf' call can be replaced with array literal [...]"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.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.application.ApplicationManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ArrayLiteralsInAnnotations
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.CollectionLiteralResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
|
||||
class ReplaceArrayOfWithLiteralInspection : AbstractKotlinInspection() {
|
||||
|
||||
private val acceptableNames = setOf(CollectionLiteralResolver.ARRAY_OF_FUNCTION) +
|
||||
CollectionLiteralResolver.PRIMITIVE_TYPE_TO_ARRAY.values.toSet() +
|
||||
Name.identifier("emptyArray")
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
return object : KtVisitorVoid() {
|
||||
override fun visitCallExpression(expression: KtCallExpression) {
|
||||
super.visitCallExpression(expression)
|
||||
|
||||
val project = expression.project
|
||||
if (!project.getLanguageVersionSettings().supportsFeature(ArrayLiteralsInAnnotations) &&
|
||||
!ApplicationManager.getApplication().isUnitTestMode) return
|
||||
|
||||
val calleeExpression = expression.calleeExpression as? KtNameReferenceExpression ?: return
|
||||
val resolvedCall = expression.getResolvedCall(expression.analyze()) ?: return
|
||||
val descriptor = resolvedCall.candidateDescriptor
|
||||
if (descriptor.containingDeclaration !is BuiltInsPackageFragment) return
|
||||
if (descriptor.name !in acceptableNames) return
|
||||
|
||||
val parent = expression.parent
|
||||
when (parent) {
|
||||
is KtValueArgument -> parent.parent.parent as? KtAnnotationEntry ?: return
|
||||
is KtParameter -> {
|
||||
val constructor = parent.parent.parent as? KtPrimaryConstructor ?: return
|
||||
val containingClass = constructor.getContainingClassOrObject()
|
||||
if (!containingClass.isAnnotation()) return
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
|
||||
val calleeName = calleeExpression.getReferencedName()
|
||||
holder.registerProblem(
|
||||
calleeExpression,
|
||||
"'$calleeName' call can be replaced with array literal [...]",
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
|
||||
ReplaceWithArrayLiteralFix()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ReplaceWithArrayLiteralFix : LocalQuickFix {
|
||||
override fun getFamilyName() = "Replace with [...]"
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val calleeExpression = descriptor.psiElement as KtExpression
|
||||
val callExpression = calleeExpression.parent as KtCallExpression
|
||||
val arguments = callExpression.valueArguments
|
||||
val arrayLiteral = KtPsiFactory(callExpression).buildExpression {
|
||||
appendFixedText("[")
|
||||
for ((index, argument) in arguments.withIndex()) {
|
||||
appendExpression(argument.getArgumentExpression())
|
||||
if (index != arguments.size - 1) {
|
||||
appendFixedText(", ")
|
||||
}
|
||||
}
|
||||
appendFixedText("]")
|
||||
} as KtCollectionLiteralExpression
|
||||
callExpression.replace(arrayLiteral)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.jetbrains.kotlin.idea.inspections.ReplaceArrayOfWithLiteralInspection
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String>)
|
||||
|
||||
@Some(strings = <caret>arrayOf("alpha", "beta", "omega"))
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String>)
|
||||
|
||||
@Some(strings = ["alpha", "beta", "omega"])
|
||||
class My
|
||||
@@ -0,0 +1,3 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String> = <caret>arrayOf("default"))
|
||||
@@ -0,0 +1,3 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String> = ["default"])
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
// PROBLEM: none
|
||||
class Some(val strings: Array<String> = <caret>arrayOf("default"))
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String>)
|
||||
|
||||
@Some(strings = <caret>emptyArray())
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String>)
|
||||
|
||||
@Some(strings = [])
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val nums: IntArray)
|
||||
|
||||
@Some(nums = <caret>intArrayOf(1, 2))
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val nums: IntArray)
|
||||
|
||||
@Some(nums = [1, 2])
|
||||
class My
|
||||
@@ -0,0 +1,5 @@
|
||||
// PROBLEM: none
|
||||
|
||||
fun foo() {
|
||||
val x = <caret>arrayOf("1")
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// PROBLEM: none
|
||||
// ERROR: Type mismatch: inferred type is Int but Array<String> was expected
|
||||
|
||||
annotation class Some(val arg: Array<String>)
|
||||
|
||||
fun create(x: Int) = x
|
||||
|
||||
@Some(arg = <caret>create(123))
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String>)
|
||||
|
||||
@Some(<caret>arrayOf("alpha", "beta", "omega"))
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(val strings: Array<String>)
|
||||
|
||||
@Some(["alpha", "beta", "omega"])
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(vararg val strings: String)
|
||||
|
||||
@Some(strings = *<caret>arrayOf("alpha", "beta", "omega"))
|
||||
class My
|
||||
@@ -0,0 +1,6 @@
|
||||
// ERROR: The feature "array literals in annotations" is only available since language version 1.2
|
||||
|
||||
annotation class Some(vararg val strings: String)
|
||||
|
||||
@Some(strings = *["alpha", "beta", "omega"])
|
||||
class My
|
||||
@@ -131,4 +131,67 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class ReplaceArrayOfWithLiteral extends AbstractLocalInspectionTest {
|
||||
public void testAllFilesPresentInReplaceArrayOfWithLiteral() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("base.kt")
|
||||
public void testBase() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/base.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("default.kt")
|
||||
public void testDefault() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/default.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("defaultNotAnnotation.kt")
|
||||
public void testDefaultNotAnnotation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/defaultNotAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("empty.kt")
|
||||
public void testEmpty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/empty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("intArray.kt")
|
||||
public void testIntArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/intArray.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noAnnotation.kt")
|
||||
public void testNoAnnotation() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/noAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noArray.kt")
|
||||
public void testNoArray() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/noArray.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unnamed.kt")
|
||||
public void testUnnamed() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/unnamed.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("vararg.kt")
|
||||
public void testVararg() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/replaceArrayOfWithLiteral/vararg.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user