From f80f41d254a84190d7c842be9ab9ce78a8ff123b Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 22 Jun 2017 18:05:12 +0300 Subject: [PATCH] Introduce "redundant explicit type" inspection #KT-18517 Fixed Reported cases: constants, constructors, object references --- .../RedundantExplicitType.html | 8 ++ idea/src/META-INF/plugin.xml | 8 ++ .../RedundantExplicitTypeInspection.kt | 89 +++++++++++++++++ .../redundantExplicitType/.inspection | 1 + .../redundantExplicitType/boolean.kt | 3 + .../redundantExplicitType/boolean.kt.after | 3 + .../redundantExplicitType/char.kt | 3 + .../redundantExplicitType/char.kt.after | 3 + .../redundantExplicitType/constructor.kt | 5 + .../constructor.kt.after | 5 + .../redundantExplicitType/double.kt | 3 + .../redundantExplicitType/double.kt.after | 3 + .../redundantExplicitType/float.kt | 3 + .../redundantExplicitType/float.kt.after | 3 + .../redundantExplicitType/int.kt | 3 + .../redundantExplicitType/int.kt.after | 3 + .../redundantExplicitType/intExpr.kt | 5 + .../redundantExplicitType/interface.kt | 12 +++ .../redundantExplicitType/long.kt | 3 + .../redundantExplicitType/long.kt.after | 3 + .../redundantExplicitType/member.kt | 5 + .../redundantExplicitType/null.kt | 5 + .../redundantExplicitType/object.kt | 5 + .../redundantExplicitType/object.kt.after | 5 + .../redundantExplicitType/short.kt | 5 + .../redundantExplicitType/string.kt | 3 + .../redundantExplicitType/string.kt.after | 3 + .../redundantExplicitType/top.kt | 3 + .../LocalInspectionTestGenerated.java | 99 +++++++++++++++++++ 29 files changed, 302 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/RedundantExplicitType.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/RedundantExplicitTypeInspection.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/.inspection create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/char.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/char.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/double.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/double.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/float.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/float.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/int.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/int.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/intExpr.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/interface.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/long.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/long.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/member.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/null.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/object.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/object.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/short.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/string.kt create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/string.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantExplicitType/top.kt diff --git a/idea/resources/inspectionDescriptions/RedundantExplicitType.html b/idea/resources/inspectionDescriptions/RedundantExplicitType.html new file mode 100644 index 00000000000..4da8c816d27 --- /dev/null +++ b/idea/resources/inspectionDescriptions/RedundantExplicitType.html @@ -0,0 +1,8 @@ + + +This inspection reports local variables' explicitly given types which are obvious and thus redundant, like +

+  val f: Foo = Foo()
+
+ + diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index e35e97fea4d..13ef197560c 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2250,6 +2250,14 @@ language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantExplicitTypeInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantExplicitTypeInspection.kt new file mode 100644 index 00000000000..cd5a96444d9 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantExplicitTypeInspection.kt @@ -0,0 +1,89 @@ +/* + * 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.IntentionWrapper +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeIntention +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +class RedundantExplicitTypeInspection : AbstractKotlinInspection() { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = + object : KtVisitorVoid() { + override fun visitProperty(property: KtProperty) { + super.visitProperty(property) + + if (!property.isLocal) return + val typeReference = property.typeReference ?: return + val initializer = property.initializer ?: return + + val type = property.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference] ?: return + when (initializer) { + is KtConstantExpression -> { + when (initializer.node.elementType) { + KtNodeTypes.BOOLEAN_CONSTANT -> { + if (!KotlinBuiltIns.isBoolean(type)) return + } + KtNodeTypes.INTEGER_CONSTANT -> { + if (initializer.text.endsWith("L")) { + if (!KotlinBuiltIns.isLong(type)) return + } + else { + if (!KotlinBuiltIns.isInt(type)) return + } + } + KtNodeTypes.FLOAT_CONSTANT -> { + if (initializer.text.endsWith("f") || initializer.text.endsWith("F")) { + if (!KotlinBuiltIns.isFloat(type)) return + } + else { + if (!KotlinBuiltIns.isDouble(type)) return + } + } + KtNodeTypes.CHARACTER_CONSTANT -> { + if (!KotlinBuiltIns.isChar(type)) return + } + else -> return + } + } + is KtStringTemplateExpression -> { + if (!KotlinBuiltIns.isString(type)) return + } + is KtNameReferenceExpression -> { + if (typeReference.text != initializer.getReferencedName()) return + } + is KtCallExpression -> { + if (typeReference.text != initializer.calleeExpression?.text) return + } + else -> return + } + + holder.registerProblem( + typeReference, + "Explicitly given type is redundant here", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, + IntentionWrapper(RemoveExplicitTypeIntention(), property.containingKtFile) + ) + } + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/.inspection b/idea/testData/inspectionsLocal/redundantExplicitType/.inspection new file mode 100644 index 00000000000..8f2b34b5c2e --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.RedundantExplicitTypeInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt b/idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt new file mode 100644 index 00000000000..2f9b0e91819 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt @@ -0,0 +1,3 @@ +fun foo() { + val t: Boolean = true +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt.after new file mode 100644 index 00000000000..206f4efd93a --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val t = true +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/char.kt b/idea/testData/inspectionsLocal/redundantExplicitType/char.kt new file mode 100644 index 00000000000..d5e68f8a544 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/char.kt @@ -0,0 +1,3 @@ +fun foo() { + val ch: Char = 'z' +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/char.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/char.kt.after new file mode 100644 index 00000000000..c4cd73bda03 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/char.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val ch = 'z' +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt b/idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt new file mode 100644 index 00000000000..6632c92c2a7 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt @@ -0,0 +1,5 @@ +class Point(val x: Int, val y: Int) + +fun foo() { + val p: Point = Point(1, 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt.after new file mode 100644 index 00000000000..0df6f4db010 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt.after @@ -0,0 +1,5 @@ +class Point(val x: Int, val y: Int) + +fun foo() { + val p = Point(1, 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/double.kt b/idea/testData/inspectionsLocal/redundantExplicitType/double.kt new file mode 100644 index 00000000000..571e2aeba61 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/double.kt @@ -0,0 +1,3 @@ +fun foo() { + val pi: Double = 3.14 +} diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/double.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/double.kt.after new file mode 100644 index 00000000000..49ec0e3cbdd --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/double.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val pi = 3.14 +} diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/float.kt b/idea/testData/inspectionsLocal/redundantExplicitType/float.kt new file mode 100644 index 00000000000..e47fc0ced79 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/float.kt @@ -0,0 +1,3 @@ +fun foo() { + val pi: Float = 3.14f +} diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/float.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/float.kt.after new file mode 100644 index 00000000000..0784ff23072 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/float.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val pi = 3.14f +} diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/int.kt b/idea/testData/inspectionsLocal/redundantExplicitType/int.kt new file mode 100644 index 00000000000..a39d928f867 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/int.kt @@ -0,0 +1,3 @@ +fun foo() { + val i: Int = 42 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/int.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/int.kt.after new file mode 100644 index 00000000000..bc8fbb02fd5 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/int.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val i = 42 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/intExpr.kt b/idea/testData/inspectionsLocal/redundantExplicitType/intExpr.kt new file mode 100644 index 00000000000..7c215ea2d19 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/intExpr.kt @@ -0,0 +1,5 @@ +// PROBLEM: none + +fun foo() { + val i: Int = 2 * 2 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/interface.kt b/idea/testData/inspectionsLocal/redundantExplicitType/interface.kt new file mode 100644 index 00000000000..9ca10ccd549 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/interface.kt @@ -0,0 +1,12 @@ +// PROBLEM: none + +interface Point { + val x: Int + val y: Int +} + +class PointImpl(override val x: Int, override val y: Int) : Point + +fun foo() { + val p: Point = PointImpl(1, 2) +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/long.kt b/idea/testData/inspectionsLocal/redundantExplicitType/long.kt new file mode 100644 index 00000000000..a35c5b45be5 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/long.kt @@ -0,0 +1,3 @@ +fun foo() { + val l: Long = 1234567890123L +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/long.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/long.kt.after new file mode 100644 index 00000000000..ec37056dbfe --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/long.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val l = 1234567890123L +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/member.kt b/idea/testData/inspectionsLocal/redundantExplicitType/member.kt new file mode 100644 index 00000000000..12956ccd484 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/member.kt @@ -0,0 +1,5 @@ +// PROBLEM: none + +class My { + val x: Int = 1 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/null.kt b/idea/testData/inspectionsLocal/redundantExplicitType/null.kt new file mode 100644 index 00000000000..f3b5f1a1192 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/null.kt @@ -0,0 +1,5 @@ +// PROBLEM: none + +fun foo() { + val s: String? = null +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/object.kt b/idea/testData/inspectionsLocal/redundantExplicitType/object.kt new file mode 100644 index 00000000000..f3857b354b5 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/object.kt @@ -0,0 +1,5 @@ +object Obj + +fun foo() { + val o: Obj = Obj +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/object.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/object.kt.after new file mode 100644 index 00000000000..04fc3d54253 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/object.kt.after @@ -0,0 +1,5 @@ +object Obj + +fun foo() { + val o = Obj +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/short.kt b/idea/testData/inspectionsLocal/redundantExplicitType/short.kt new file mode 100644 index 00000000000..6606e38eb8c --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/short.kt @@ -0,0 +1,5 @@ +// PROBLEM: none + +fun foo() { + val i: Short = 42 +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/string.kt b/idea/testData/inspectionsLocal/redundantExplicitType/string.kt new file mode 100644 index 00000000000..125b0cd6886 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/string.kt @@ -0,0 +1,3 @@ +fun foo() { + val s: String = "Hello" +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/string.kt.after b/idea/testData/inspectionsLocal/redundantExplicitType/string.kt.after new file mode 100644 index 00000000000..82f8ef4740b --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/string.kt.after @@ -0,0 +1,3 @@ +fun foo() { + val s = "Hello" +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantExplicitType/top.kt b/idea/testData/inspectionsLocal/redundantExplicitType/top.kt new file mode 100644 index 00000000000..9cfb0caeb00 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantExplicitType/top.kt @@ -0,0 +1,3 @@ +// PROBLEM: none + +val ZERO: Int = 0 \ 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 f21015a6bbf..c6374efb7eb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -282,6 +282,105 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/redundantExplicitType") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantExplicitType extends AbstractLocalInspectionTest { + public void testAllFilesPresentInRedundantExplicitType() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/redundantExplicitType"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("boolean.kt") + public void testBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/boolean.kt"); + doTest(fileName); + } + + @TestMetadata("char.kt") + public void testChar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/char.kt"); + doTest(fileName); + } + + @TestMetadata("constructor.kt") + public void testConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/constructor.kt"); + doTest(fileName); + } + + @TestMetadata("double.kt") + public void testDouble() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/double.kt"); + doTest(fileName); + } + + @TestMetadata("float.kt") + public void testFloat() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/float.kt"); + doTest(fileName); + } + + @TestMetadata("int.kt") + public void testInt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/int.kt"); + doTest(fileName); + } + + @TestMetadata("intExpr.kt") + public void testIntExpr() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/intExpr.kt"); + doTest(fileName); + } + + @TestMetadata("interface.kt") + public void testInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/interface.kt"); + doTest(fileName); + } + + @TestMetadata("long.kt") + public void testLong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/long.kt"); + doTest(fileName); + } + + @TestMetadata("member.kt") + public void testMember() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/member.kt"); + doTest(fileName); + } + + @TestMetadata("null.kt") + public void testNull() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/null.kt"); + doTest(fileName); + } + + @TestMetadata("object.kt") + public void testObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/object.kt"); + doTest(fileName); + } + + @TestMetadata("short.kt") + public void testShort() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/short.kt"); + doTest(fileName); + } + + @TestMetadata("string.kt") + public void testString() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/string.kt"); + doTest(fileName); + } + + @TestMetadata("top.kt") + public void testTop() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantExplicitType/top.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/inspectionsLocal/removeRedundantSpreadOperator") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)