From 297054037c9de23b64cfb850dbd94c89df7e48db Mon Sep 17 00:00:00 2001 From: Nikita Katkov Date: Thu, 6 Dec 2018 16:59:15 +0300 Subject: [PATCH] Dispatchers IO is now considered non-blocking context See BlockingMethodInNonBlockingContextInspection --- .../CoroutineNonBlockingContextChecker.kt | 12 ++++---- .../blockingCallsDetection/ContextCheck.kt | 1 - .../DispatchersTypeCheck.kt | 28 +++++++++++++++++++ .../DispatchersTypeCheck.kt.182 | 0 ...CoroutineNonBlockingontextDetectionTest.kt | 11 +++++--- 5 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt create mode 100644 idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt.182 diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt index 28c33e0ef98..983d5b66b56 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt @@ -24,9 +24,9 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getParameterForArgument import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode - class CoroutineNonBlockingContextChecker : NonBlockingContextChecker { override fun isApplicable(file: PsiFile): Boolean { @@ -45,10 +45,11 @@ class CoroutineNonBlockingContextChecker : NonBlockingContextChecker { val callExpression = PsiTreeUtil.getParentOfType(containingArgument, KtCallExpression::class.java) ?: return false val call = callExpression.resolveToCall(BodyResolveMode.PARTIAL) ?: return false - val hasBlockingAnnotation = call.getFirstArgument()?.resolveToCall() - ?.resultingDescriptor?.annotations?.hasAnnotation(FqName(BLOCKING_CONTEXT_ANNOTATION)) - if (hasBlockingAnnotation == true) - return false + val argumentDescriptor = call.getFirstArgument()?.resolveToCall()?.resultingDescriptor + val hasBlockingAnnotation = argumentDescriptor?.annotations?.hasAnnotation(FqName(BLOCKING_CONTEXT_ANNOTATION)) + if (hasBlockingAnnotation == true) return false + val isIoDispatcherUsed = argumentDescriptor?.fqNameOrNull()?.asString() == IO_DISPATCHER_FQN + if (isIoDispatcherUsed) return false val parameterForArgument = call.getParameterForArgument(containingArgument) ?: return false val type = parameterForArgument.returnType ?: return false @@ -69,5 +70,6 @@ class CoroutineNonBlockingContextChecker : NonBlockingContextChecker { companion object { private const val BLOCKING_CONTEXT_ANNOTATION = "org.jetbrains.annotations.BlockingContext" + private const val IO_DISPATCHER_FQN = "kotlinx.coroutines.Dispatchers.IO" } } \ No newline at end of file diff --git a/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt b/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt index 7a5656eced5..09e6f088768 100644 --- a/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt +++ b/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt @@ -2,7 +2,6 @@ import kotlin.coroutines.* import org.jetbrains.annotations.BlockingContext -import kotlin.coroutines.experimental.buildSequence import java.lang.Thread.sleep suspend fun testFunction() { diff --git a/idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt b/idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt new file mode 100644 index 00000000000..3d1071a062e --- /dev/null +++ b/idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt @@ -0,0 +1,28 @@ +@file:Suppress("UNUSED_PARAMETER") +package kotlinx.coroutines + +import java.lang.Thread.sleep + +suspend fun withIoDispatcher() { + withContext(Dispatchers.IO) { + //no warning since IO dispatcher type used + Thread.sleep(42) + } + + withContext(Dispatchers.Default) { + Thread.sleep(1) + } +} + +class CoroutineDispatcher() +object Dispatchers { + val IO: kotlinx.coroutines.CoroutineDispatcher = TODO() + val Default: kotlinx.coroutines.CoroutineDispatcher = TODO() +} + +suspend fun withContext( + context: CoroutineDispatcher, + f: suspend () -> T +) { + TODO() +} \ No newline at end of file diff --git a/idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt.182 b/idea/testData/inspections/blockingCallsDetection/DispatchersTypeCheck.kt.182 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt index a5c8a189bda..de5b5db5404 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt @@ -10,11 +10,9 @@ import com.intellij.testFramework.LightProjectDescriptor import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.PluginTestCaseBase -import org.jetbrains.kotlin.idea.test.configureCompilerOptions -class CoroutineNonBlockingontextDetectionTest: KotlinLightCodeInsightFixtureTestCase() { - override fun getTestDataPath(): String - = PluginTestCaseBase.getTestDataPathBase() + "/inspections/blockingCallsDetection" +class CoroutineNonBlockingContextDetectionTest : KotlinLightCodeInsightFixtureTestCase() { + override fun getTestDataPath(): String = PluginTestCaseBase.getTestDataPathBase() + "/inspections/blockingCallsDetection" override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE @@ -43,4 +41,9 @@ class CoroutineNonBlockingontextDetectionTest: KotlinLightCodeInsightFixtureTest myFixture.configureByFile("NestedFunctionsInsideSuspendLambda.kt") myFixture.testHighlighting(true, false, false, "NestedFunctionsInsideSuspendLambda.kt") } + + fun testDispatchersTypeDetection() { + myFixture.configureByFile("DispatchersTypeCheck.kt") + myFixture.testHighlighting(true, false, false, "DispatchersTypeCheck.kt") + } } \ No newline at end of file