diff --git a/idea/src/META-INF/plugin.xml.183 b/idea/src/META-INF/plugin.xml.183
index 3b67ec5a0d6..7b33983f439 100644
--- a/idea/src/META-INF/plugin.xml.183
+++ b/idea/src/META-INF/plugin.xml.183
@@ -3140,6 +3140,10 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
+
+
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt.183 b/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt.183
new file mode 100644
index 00000000000..4fb01f7e247
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/blockingCallsDetection/CoroutineNonBlockingContextChecker.kt.183
@@ -0,0 +1,75 @@
+/*
+ * 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.blockingCallsDetection
+
+import com.intellij.codeInspection.blockingCallsDetection.NonBlockingContextChecker
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
+import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
+import org.jetbrains.kotlin.builtins.isSuspendFunctionType
+import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.config.LanguageVersion
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
+import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.parents
+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.lazy.BodyResolveMode
+
+
+class CoroutineNonBlockingContextChecker : NonBlockingContextChecker {
+
+ override fun isApplicable(file: PsiFile): Boolean {
+ val languageVersionSettings = file.project.getLanguageVersionSettings()
+ return languageVersionSettings.supportsFeature(LanguageFeature.Coroutines) &&
+ languageVersionSettings.languageVersion >= LanguageVersion.KOTLIN_1_3
+ }
+
+ override fun isContextNonBlockingFor(element: PsiElement): Boolean {
+ if (element !is KtCallExpression)
+ return false
+
+ val containingLambda = element.parents
+ .firstOrNull { it is KtLambdaExpression && it.analyze().get(BindingContext.LAMBDA_INVOCATIONS, it) == null }
+ val containingArgument = PsiTreeUtil.getParentOfType(containingLambda, KtValueArgument::class.java)
+ if (containingArgument != null) {
+ val callExpression = PsiTreeUtil.getParentOfType(element, KtCallExpression::class.java) ?: return false
+ val call = callExpression.resolveToCall(BodyResolveMode.FULL) ?: return false
+
+ val hasBlockingAnnotation = call.getFirstArgument()?.resolveToCall()
+ ?.resultingDescriptor?.annotations?.hasAnnotation(FqName(BLOCKING_CONTEXT_ANNOTATION))
+ if (hasBlockingAnnotation == true)
+ return false
+
+ val parameterForArgument = call.getParameterForArgument(containingArgument) ?: return false
+ val type = parameterForArgument.returnType ?: return false
+
+ val hasRestrictSuspensionAnnotation = if (type.isBuiltinFunctionalType) {
+ type.getReceiverTypeFromFunctionType()?.isRestrictsSuspensionReceiver(element.project.getLanguageVersionSettings())
+ } else null
+
+ return hasRestrictSuspensionAnnotation != true && type.isSuspendFunctionType
+ }
+
+ val callingMethod = PsiTreeUtil.getParentOfType(element, KtNamedFunction::class.java) ?: return false
+ return callingMethod.hasModifier(KtTokens.SUSPEND_KEYWORD)
+ }
+
+ private fun ResolvedCall<*>.getFirstArgument(): KtExpression? =
+ valueArgumentsByIndex?.firstOrNull()?.arguments?.firstOrNull()?.getArgumentExpression()
+
+ companion object {
+ private const val BLOCKING_CONTEXT_ANNOTATION = "org.jetbrains.annotations.BlockingContext"
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt.183 b/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt.183
new file mode 100644
index 00000000000..7a5656eced5
--- /dev/null
+++ b/idea/testData/inspections/blockingCallsDetection/ContextCheck.kt.183
@@ -0,0 +1,32 @@
+@file:Suppress("UNUSED_PARAMETER")
+
+import kotlin.coroutines.*
+import org.jetbrains.annotations.BlockingContext
+import kotlin.coroutines.experimental.buildSequence
+import java.lang.Thread.sleep
+
+suspend fun testFunction() {
+ @BlockingContext
+ val ctx = getContext()
+ // no warnings with @BlockingContext annotation on ctx object
+ withContext(ctx) {Thread.sleep (2)}
+
+ // no warnings with @BlockingContext annotation on getContext() method
+ withContext(getContext()) {Thread.sleep(3)}
+
+ withContext(getNonBlockingContext()) {
+ Thread.sleep(3);
+ }
+}
+
+@BlockingContext
+fun getContext(): CoroutineContext = TODO()
+
+fun getNonBlockingContext(): CoroutineContext = TODO()
+
+suspend fun withContext(
+ context: CoroutineContext,
+ f: suspend () -> T
+) {
+ TODO()
+}
\ No newline at end of file
diff --git a/idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt.183 b/idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt.183
new file mode 100644
index 00000000000..a6affbaabde
--- /dev/null
+++ b/idea/testData/inspections/blockingCallsDetection/InsideCoroutine.kt.183
@@ -0,0 +1,10 @@
+@file:Suppress("UNUSED_PARAMETER")
+
+import kotlin.coroutines.*
+import java.lang.Thread.sleep
+
+class InsideCoroutine {
+ suspend fun example1() {
+ Thread.sleep(1);
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt.183 b/idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt.183
new file mode 100644
index 00000000000..1ef40df0f63
--- /dev/null
+++ b/idea/testData/inspections/blockingCallsDetection/LambdaReceiverTypeCheck.kt.183
@@ -0,0 +1,20 @@
+@file:Suppress("UNUSED_PARAMETER")
+
+import java.lang.Thread.sleep
+import kotlin.coroutines.RestrictsSuspension
+
+suspend fun testFunction() {
+ // @RestrictsSuspension annotation allows blocking calls
+ withRestrictedReceiver({Thread.sleep(0)}, {Thread.sleep(1)})
+
+ withSimpleReceiver({Thread.sleep(2)})
+}
+
+fun withRestrictedReceiver(firstParam: suspend Test1.() -> Unit, secondParam: () -> Unit) {}
+
+fun withSimpleReceiver(firstParam: suspend Test2.() -> Unit) {}
+
+@RestrictsSuspension
+class Test1
+
+class Test2
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt.183 b/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt.183
new file mode 100644
index 00000000000..04ac6cac445
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/inspections/CoroutineNonBlockingontextDetectionTest.kt.183
@@ -0,0 +1,41 @@
+/*
+ * 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.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection
+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"
+
+ override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
+
+ override fun setUp() {
+ super.setUp()
+ myFixture.addClass("""package org.jetbrains.annotations; public @interface BlockingContext {}""")
+ myFixture.enableInspections(BlockingMethodInNonBlockingContextInspection::class.java)
+ }
+
+ fun testSimpleCoroutineScope() {
+ myFixture.configureByFile("InsideCoroutine.kt")
+ myFixture.testHighlighting(true, false, false, "InsideCoroutine.kt")
+ }
+
+ fun testCoroutineContextCheck() {
+ myFixture.configureByFiles("ContextCheck.kt")
+ myFixture.testHighlighting(true, false, false, "ContextCheck.kt")
+ }
+
+ fun testLambdaReceiverType() {
+ myFixture.configureByFile("LambdaReceiverTypeCheck.kt")
+ myFixture.testHighlighting(true, false, false, "LambdaReceiverTypeCheck.kt")
+ }
+}
\ No newline at end of file