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)