From ef71f7707d3f3de478bf12266bf56b0676f1cbf0 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Thu, 12 Oct 2017 10:28:21 +0300 Subject: [PATCH] Introduce inspection to detect use of Unit as a standalone expression So #KT-20631 Fixed --- .../RedundantUnitExpression.html | 5 ++ idea/src/META-INF/plugin.xml | 9 +++ .../RedundantUnitExpressionInspection.kt | 56 ++++++++++++++++++ .../redundantUnitExpression/.inspection | 1 + .../redundantUnitExpression/notRedundant1.kt | 4 ++ .../redundantUnitExpression/notRedundant2.kt | 2 + .../redundantUnitExpression/notRedundant3.kt | 7 +++ .../redundantUnitExpression/redundant1.kt | 3 + .../redundant1.kt.after | 3 + .../redundantUnitExpression/redundant2.kt | 5 ++ .../redundant2.kt.after | 4 ++ .../redundantUnitExpression/redundant3.kt | 6 ++ .../redundant3.kt.after | 5 ++ .../redundantUnitExpression/redundant4.kt | 8 +++ .../redundant4.kt.after | 7 +++ .../redundantUnitExpression/redundant5.kt | 7 +++ .../redundant5.kt.after | 7 +++ .../LocalInspectionTestGenerated.java | 57 +++++++++++++++++++ 18 files changed, 196 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/RedundantUnitExpression.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/RedundantUnitExpressionInspection.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/.inspection create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant1.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant2.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant3.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt.after create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt create mode 100644 idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt.after diff --git a/idea/resources/inspectionDescriptions/RedundantUnitExpression.html b/idea/resources/inspectionDescriptions/RedundantUnitExpression.html new file mode 100644 index 00000000000..deacacb6ff2 --- /dev/null +++ b/idea/resources/inspectionDescriptions/RedundantUnitExpression.html @@ -0,0 +1,5 @@ + + +This inspection reports redundant 'Unit' which can be omitted. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 9d14467519c..795999c9258 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -2624,6 +2624,15 @@ language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantUnitExpressionInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantUnitExpressionInspection.kt new file mode 100644 index 00000000000..20f8bdb53a0 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/RedundantUnitExpressionInspection.kt @@ -0,0 +1,56 @@ +/* + * 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.* +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElementVisitor +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.psi.* + +class RedundantUnitExpressionInspection : AbstractKotlinInspection(), CleanupLocalInspectionTool { + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { + return object : KtVisitorVoid() { + + override fun visitReferenceExpression(expression: KtReferenceExpression) { + super.visitReferenceExpression(expression) + + if (KotlinBuiltIns.FQ_NAMES.unit.shortName() != (expression as? KtNameReferenceExpression)?.getReferencedNameAsName()) { + return + } + + val parent = expression.parent + if (parent !is KtReturnExpression && parent !is KtBlockExpression) return + + holder.registerProblem(expression, + "Redundant 'Unit'", + ProblemHighlightType.LIKE_UNUSED_SYMBOL, + RemoveRedundantUnitFix()) + } + } + } +} + +private class RemoveRedundantUnitFix : LocalQuickFix { + override fun getName() = "Remove redundant 'Unit'" + + override fun getFamilyName() = name + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + (descriptor.psiElement as? KtReferenceExpression)?.delete() + } +} diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/.inspection b/idea/testData/inspectionsLocal/redundantUnitExpression/.inspection new file mode 100644 index 00000000000..c5349be205b --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.RedundantUnitExpressionInspection \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant1.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant1.kt new file mode 100644 index 00000000000..a88c1b5a67a --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant1.kt @@ -0,0 +1,4 @@ +// PROBLEM: none +fun test() { + val u = Unit +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant2.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant2.kt new file mode 100644 index 00000000000..32ba1afac10 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant2.kt @@ -0,0 +1,2 @@ +// PROBLEM: none +fun test() = Unit diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant3.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant3.kt new file mode 100644 index 00000000000..a15f2e14b66 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant3.kt @@ -0,0 +1,7 @@ +// PROBLEM: none +fun test(s: String?) { + val x: Any = if (s == null) + "" + else + Unit +} diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt new file mode 100644 index 00000000000..31fcd0347dd --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt @@ -0,0 +1,3 @@ +fun test() { + return Unit +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt.after b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt.after new file mode 100644 index 00000000000..4d3735975a5 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt.after @@ -0,0 +1,3 @@ +fun test() { + return +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt new file mode 100644 index 00000000000..db80df532e5 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt @@ -0,0 +1,5 @@ +fun test() { + val f: () -> Unit = { + Unit + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt.after b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt.after new file mode 100644 index 00000000000..20ea98bdc43 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt.after @@ -0,0 +1,4 @@ +fun test() { + val f: () -> Unit = { + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt new file mode 100644 index 00000000000..385c99b2597 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt @@ -0,0 +1,6 @@ +fun test() { + val f: () -> Unit = { + Unit + Unit + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt.after b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt.after new file mode 100644 index 00000000000..4e97610283e --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt.after @@ -0,0 +1,5 @@ +fun test() { + val f: () -> Unit = { + Unit + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt new file mode 100644 index 00000000000..86bb49c9d9b --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt @@ -0,0 +1,8 @@ +fun test(s: String?) { + val x: Any = if (s == null) { + "" + } + else { + Unit + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt.after b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt.after new file mode 100644 index 00000000000..aff196e2657 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt.after @@ -0,0 +1,7 @@ +fun test(s: String?) { + val x: Any = if (s == null) { + "" + } + else { + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt new file mode 100644 index 00000000000..d3899ae73ac --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test() { + val x: List = listOf(1, 2, 3).map { + return@map Unit + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt.after b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt.after new file mode 100644 index 00000000000..97d47788488 --- /dev/null +++ b/idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt.after @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +fun test() { + val x: List = listOf(1, 2, 3).map { + return@map + } +} \ 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 7e11071b58c..92b35229ec5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1623,6 +1623,63 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/redundantUnitExpression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantUnitExpression extends AbstractLocalInspectionTest { + public void testAllFilesPresentInRedundantUnitExpression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/redundantUnitExpression"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("notRedundant1.kt") + public void testNotRedundant1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant1.kt"); + doTest(fileName); + } + + @TestMetadata("notRedundant2.kt") + public void testNotRedundant2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant2.kt"); + doTest(fileName); + } + + @TestMetadata("notRedundant3.kt") + public void testNotRedundant3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/notRedundant3.kt"); + doTest(fileName); + } + + @TestMetadata("redundant1.kt") + public void testRedundant1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/redundant1.kt"); + doTest(fileName); + } + + @TestMetadata("redundant2.kt") + public void testRedundant2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/redundant2.kt"); + doTest(fileName); + } + + @TestMetadata("redundant3.kt") + public void testRedundant3() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/redundant3.kt"); + doTest(fileName); + } + + @TestMetadata("redundant4.kt") + public void testRedundant4() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/redundant4.kt"); + doTest(fileName); + } + + @TestMetadata("redundant5.kt") + public void testRedundant5() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspectionsLocal/redundantUnitExpression/redundant5.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/inspectionsLocal/removeRedundantSpreadOperator") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)