Introduce "redundant explicit type" inspection #KT-18517 Fixed
Reported cases: constants, constructors, object references
This commit is contained in:
committed by
Mikhail Glukhikh
parent
0f4ae3b727
commit
f80f41d254
@@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This inspection reports local variables' explicitly given types which are obvious and thus redundant, like
|
||||||
|
<pre><code>
|
||||||
|
val f: Foo = Foo()
|
||||||
|
</code></pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -2250,6 +2250,14 @@
|
|||||||
language="kotlin"
|
language="kotlin"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.RedundantExplicitTypeInspection"
|
||||||
|
displayName="Explicitly given type is redundant here"
|
||||||
|
groupName="Kotlin"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="WARNING"
|
||||||
|
language="kotlin"
|
||||||
|
/>
|
||||||
|
|
||||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||||
|
|
||||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||||
|
|||||||
@@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.jetbrains.kotlin.idea.inspections.RedundantExplicitTypeInspection
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val t: <caret>Boolean = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val t = true
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val ch: <caret>Char = 'z'
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val ch = 'z'
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class Point(val x: Int, val y: Int)
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val p: <caret>Point = Point(1, 2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class Point(val x: Int, val y: Int)
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val p = Point(1, 2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val pi: <caret>Double = 3.14
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val pi = 3.14
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val pi: <caret>Float = 3.14f
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val pi = 3.14f
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val i: <caret>Int = 42
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val i = 42
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val i: <caret>Int = 2 * 2
|
||||||
|
}
|
||||||
@@ -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: <caret>Point = PointImpl(1, 2)
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val l: <caret>Long = 1234567890123L
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val l = 1234567890123L
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
|
||||||
|
class My {
|
||||||
|
val x: <caret>Int = 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val s: <caret>String? = null
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
object Obj
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val o: <caret>Obj = Obj
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
object Obj
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val o = Obj
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val i: <caret>Short = 42
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s: <caret>String = "Hello"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = "Hello"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// PROBLEM: none
|
||||||
|
|
||||||
|
val ZERO: <caret>Int = 0
|
||||||
@@ -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")
|
@TestMetadata("idea/testData/inspectionsLocal/removeRedundantSpreadOperator")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user