Introduce inspection "async result unused" #KT-24433 Fixed
This commit is contained in:
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
abstract class AbstractResultUnusedChecker(
|
||||
private val expressionChecker: (KtExpression) -> Boolean,
|
||||
private val callChecker: (ResolvedCall<*>) -> Boolean
|
||||
) : AbstractKotlinInspection() {
|
||||
protected fun check(expression: KtExpression): Boolean {
|
||||
// Check whatever possible by PSI
|
||||
if (!expressionChecker(expression)) return false
|
||||
var parent: PsiElement? = expression.parent
|
||||
while (parent != null) {
|
||||
if (parent is KtBlockExpression || parent is KtFunction || parent is KtFile) break
|
||||
if (parent is KtValueArgument) return false
|
||||
if (parent is KtBinaryExpression && parent.operationToken in KtTokens.ALL_ASSIGNMENTS) return false
|
||||
parent = parent.parent
|
||||
}
|
||||
// Then check by call
|
||||
val context = expression.analyze(BodyResolveMode.PARTIAL_WITH_CFA)
|
||||
if (expression.isUsedAsExpression(context)) return false
|
||||
val resolvedCall = expression.getResolvedCall(context) ?: return false
|
||||
return callChecker(resolvedCall)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports <b>async</b> call that is never used,
|
||||
so all actions inside <b>async</b> are never executed.
|
||||
</body>
|
||||
</html>
|
||||
@@ -2846,7 +2846,7 @@
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.RedundantAsyncInspection"
|
||||
displayName="Redundant async call"
|
||||
displayName="Redundant 'async' call"
|
||||
groupPath="Kotlin"
|
||||
groupName="Style issues"
|
||||
enabledByDefault="true"
|
||||
@@ -2854,6 +2854,15 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection"
|
||||
displayName="Result of 'async' is not used"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -2854,6 +2854,15 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection"
|
||||
displayName="Result of 'async' is not used"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -2854,6 +2854,15 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection"
|
||||
displayName="Result of 'async' is not used"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -2855,6 +2855,15 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection"
|
||||
displayName="Result of 'async' is not used"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -2854,6 +2854,15 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection"
|
||||
displayName="Result of 'async' is not used"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
@@ -2854,6 +2854,15 @@
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection"
|
||||
displayName="Result of 'async' is not used"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
enabledByDefault="true"
|
||||
level="WARNING"
|
||||
language="kotlin"
|
||||
/>
|
||||
|
||||
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
|
||||
|
||||
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.ProblemsHolder
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.idea.inspections.AbstractResultUnusedChecker
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.callExpressionVisitor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||
|
||||
class AsyncResultUnusedInspection : AbstractResultUnusedChecker(
|
||||
expressionChecker = fun(expression): Boolean =
|
||||
expression is KtCallExpression && expression.calleeExpression?.text == "async",
|
||||
callChecker = fun(resolvedCall): Boolean =
|
||||
resolvedCall.resultingDescriptor.fqNameOrNull()?.asString() == "kotlinx.coroutines.experimental.async"
|
||||
) {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor =
|
||||
callExpressionVisitor(fun(expression) {
|
||||
if (!check(expression)) return
|
||||
holder.registerProblem(expression.calleeExpression ?: expression, "Result of 'async' is never used")
|
||||
})
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<problems>
|
||||
<problem>
|
||||
<file>simple.kt</file>
|
||||
<line>30</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<package><default></package>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/simple.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Result of 'async' is not used</problem_class>
|
||||
<description>Result of 'async' is never used</description>
|
||||
</problem>
|
||||
</problems>
|
||||
+1
@@ -0,0 +1 @@
|
||||
// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.coroutines.AsyncResultUnusedInspection
|
||||
@@ -0,0 +1,39 @@
|
||||
package kotlinx.coroutines.experimental
|
||||
|
||||
interface Deferred<T> {
|
||||
suspend fun await(): T
|
||||
}
|
||||
|
||||
interface CoroutineContext
|
||||
|
||||
object DefaultContext : CoroutineContext
|
||||
|
||||
enum class CoroutineStart {
|
||||
DEFAULT,
|
||||
LAZY,
|
||||
ATOMIC,
|
||||
UNDISPATCHED
|
||||
}
|
||||
|
||||
interface Job
|
||||
|
||||
fun <T> async(
|
||||
context: CoroutineContext = DefaultContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
parent: Job? = null,
|
||||
f: suspend () -> T
|
||||
): Deferred<T> {
|
||||
TODO()
|
||||
}
|
||||
|
||||
fun test() {
|
||||
async { 42 }
|
||||
}
|
||||
|
||||
fun useIt(d: Deferred<Int>) {}
|
||||
|
||||
fun falsePositives() {
|
||||
async { 3 }.await()
|
||||
val res = async { 13 }
|
||||
useIt(async { 7 })
|
||||
}
|
||||
+5
@@ -139,6 +139,11 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
|
||||
runTest("idea/testData/inspections/copyWithoutNamedArguments/inspectionData/inspections.test");
|
||||
}
|
||||
|
||||
@TestMetadata("coroutines/asyncResultUnused/inspectionData/inspections.test")
|
||||
public void testCoroutines_asyncResultUnused_inspectionData_Inspections_test() throws Exception {
|
||||
runTest("idea/testData/inspections/coroutines/asyncResultUnused/inspectionData/inspections.test");
|
||||
}
|
||||
|
||||
@TestMetadata("dataClassPrivateConstructor/inspectionData/inspections.test")
|
||||
public void testDataClassPrivateConstructor_inspectionData_Inspections_test() throws Exception {
|
||||
runTest("idea/testData/inspections/dataClassPrivateConstructor/inspectionData/inspections.test");
|
||||
|
||||
Reference in New Issue
Block a user