From 7a2d0a3bb2d011a7cce4cae242e4dda4610b0cbd Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Thu, 23 Aug 2018 13:30:04 +0300 Subject: [PATCH] Add inspection "Redundant runCatching {}" (related to KT-25621) --- .../RedundantRunCatching.html | 6 +++ idea/src/META-INF/plugin.xml | 9 ++++ idea/src/META-INF/plugin.xml.173 | 9 ++++ idea/src/META-INF/plugin.xml.181 | 9 ++++ idea/src/META-INF/plugin.xml.183 | 9 ++++ idea/src/META-INF/plugin.xml.as31 | 9 ++++ idea/src/META-INF/plugin.xml.as32 | 9 ++++ idea/src/META-INF/plugin.xml.as33 | 9 ++++ .../RedundantRunCatchingInspection.kt | 43 +++++++++++++++++++ .../redundantRunCatching/.inspection | 1 + .../coroutines/redundantRunCatching/simple.kt | 11 +++++ .../redundantRunCatching/simple.kt.after | 11 +++++ .../LocalInspectionTestGenerated.java | 18 ++++++++ 13 files changed, 153 insertions(+) create mode 100644 idea/resources/inspectionDescriptions/RedundantRunCatching.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/inspections/coroutines/RedundantRunCatchingInspection.kt create mode 100644 idea/testData/inspectionsLocal/coroutines/redundantRunCatching/.inspection create mode 100644 idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt create mode 100644 idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt.after diff --git a/idea/resources/inspectionDescriptions/RedundantRunCatching.html b/idea/resources/inspectionDescriptions/RedundantRunCatching.html new file mode 100644 index 00000000000..626e86a56bf --- /dev/null +++ b/idea/resources/inspectionDescriptions/RedundantRunCatching.html @@ -0,0 +1,6 @@ + + +This inspection reports runCatching call that is immediately followed by getOrThrow. +Such a call can be replaced with just run call. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 07d3721ecba..3b3aab34d3e 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -3030,6 +3030,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.173 b/idea/src/META-INF/plugin.xml.173 index ef3653a0822..75bd0654ed3 100644 --- a/idea/src/META-INF/plugin.xml.173 +++ b/idea/src/META-INF/plugin.xml.173 @@ -3028,6 +3028,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.181 b/idea/src/META-INF/plugin.xml.181 index c9ec7c48914..c542d11f27f 100644 --- a/idea/src/META-INF/plugin.xml.181 +++ b/idea/src/META-INF/plugin.xml.181 @@ -3029,6 +3029,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.183 b/idea/src/META-INF/plugin.xml.183 index 69b9706687d..8dc1dd707de 100644 --- a/idea/src/META-INF/plugin.xml.183 +++ b/idea/src/META-INF/plugin.xml.183 @@ -3030,6 +3030,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as31 b/idea/src/META-INF/plugin.xml.as31 index 28bd6f9d9c5..ce0af6fba39 100644 --- a/idea/src/META-INF/plugin.xml.as31 +++ b/idea/src/META-INF/plugin.xml.as31 @@ -3028,6 +3028,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as32 b/idea/src/META-INF/plugin.xml.as32 index a11e151bdb4..69071da5303 100644 --- a/idea/src/META-INF/plugin.xml.as32 +++ b/idea/src/META-INF/plugin.xml.as32 @@ -3028,6 +3028,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/META-INF/plugin.xml.as33 b/idea/src/META-INF/plugin.xml.as33 index 508155b8aec..5996d7bee09 100644 --- a/idea/src/META-INF/plugin.xml.as33 +++ b/idea/src/META-INF/plugin.xml.as33 @@ -3030,6 +3030,15 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio. language="kotlin" /> + + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/coroutines/RedundantRunCatchingInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/coroutines/RedundantRunCatchingInspection.kt new file mode 100644 index 00000000000..642860fb1aa --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/coroutines/RedundantRunCatchingInspection.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.inspections.coroutines + +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.codeInspection.ProblemsHolder +import org.jetbrains.kotlin.idea.inspections.collections.AbstractCallChainChecker +import org.jetbrains.kotlin.idea.inspections.collections.SimplifyCallChainFix +import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.psi.qualifiedExpressionVisitor + +class RedundantRunCatchingInspection : AbstractCallChainChecker() { + + override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean) = + qualifiedExpressionVisitor(fun(expression) { + val conversion = findQualifiedConversion(expression, conversionGroups) { _, _, _, _ -> true } ?: return + val replacement = conversion.replacement + val descriptor = holder.manager.createProblemDescriptor( + expression, + expression.firstCalleeExpression()!!.textRange.shiftRight(-expression.startOffset), + "Redundant 'runCatching' call may be reduced to '$replacement'", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + isOnTheFly, + SimplifyCallChainFix(replacement) + ) + holder.registerProblem(descriptor) + }) + + private val conversionGroups = conversions.group() + + companion object { + private val conversions = listOf( + Conversion( + "kotlin.runCatching", + "kotlin.SuccessOrFailure.getOrThrow", + "run" + ) + ) + } +} \ No newline at end of file diff --git a/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/.inspection b/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/.inspection new file mode 100644 index 00000000000..58adb029c27 --- /dev/null +++ b/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/.inspection @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.inspections.coroutines.RedundantRunCatchingInspection diff --git a/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt b/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt new file mode 100644 index 00000000000..57ca33eb0eb --- /dev/null +++ b/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +package kotlin + +class SuccessOrFailure(val value: T?) { + fun getOrThrow(): T = value ?: throw AssertionError("") +} + +fun runCatching(block: () -> T) = SuccessOrFailure(block()) + +fun correct(arg: Boolean) = runCatching { if (arg) throw AssertionError("") else 12 }.getOrThrow() diff --git a/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt.after b/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt.after new file mode 100644 index 00000000000..152c1daa6d6 --- /dev/null +++ b/idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt.after @@ -0,0 +1,11 @@ +// WITH_RUNTIME + +package kotlin + +class SuccessOrFailure(val value: T?) { + fun getOrThrow(): T = value ?: throw AssertionError("") +} + +fun runCatching(block: () -> T) = SuccessOrFailure(block()) + +fun correct(arg: Boolean) = run { if (arg) throw AssertionError("") else 12 } diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java index 41ef1d1dd76..6309607f25b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/LocalInspectionTestGenerated.java @@ -1865,6 +1865,24 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest { } } + @TestMetadata("idea/testData/inspectionsLocal/coroutines/redundantRunCatching") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class RedundantRunCatching extends AbstractLocalInspectionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInRedundantRunCatching() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/inspectionsLocal/coroutines/redundantRunCatching"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + runTest("idea/testData/inspectionsLocal/coroutines/redundantRunCatching/simple.kt"); + } + } + @TestMetadata("idea/testData/inspectionsLocal/coroutines/resultIsSuccessOrFailure") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)