diff --git a/idea/resources/inspectionDescriptions/PlatformExtensionReceiverOfInline.html b/idea/resources/inspectionDescriptions/PlatformExtensionReceiverOfInline.html
new file mode 100644
index 00000000000..fceeb563d1c
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/PlatformExtensionReceiverOfInline.html
@@ -0,0 +1,9 @@
+
+
+Reports potentially unsafe calls of inline functions with flexible nullable (platform type with unknown nullability) extension receivers.
+In Kotlin 1.0 or 1.1, such calls do not include nullability check in bytecode,
+but in Kotlin 1.2, nullability check is included and can provoke NPE if actual receiver is null.
+It's recommended to add explicit '!!' if exception is what you want,
+or consider changing the function' receiver type to nullable if it should work without exceptions.
+
+
\ No newline at end of file
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 68e642296d0..4e86a9ea8c9 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2527,7 +2527,7 @@
language="kotlin"
/>
-
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/PlatformExtensionReceiverOfInlineInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/PlatformExtensionReceiverOfInlineInspection.kt
new file mode 100644
index 00000000000..73341b61371
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/PlatformExtensionReceiverOfInlineInspection.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2000-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.IntentionWrapper
+import com.intellij.codeInspection.LocalInspectionToolSession
+import com.intellij.codeInspection.ProblemHighlightType
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.openapi.editor.event.DocumentEvent
+import com.intellij.openapi.editor.event.DocumentListener
+import com.intellij.openapi.ui.LabeledComponent
+import com.intellij.ui.EditorTextField
+import org.intellij.lang.regexp.RegExpFileType
+import org.jetbrains.kotlin.config.LanguageFeature
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.idea.project.languageVersionSettings
+import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
+import org.jetbrains.kotlin.psi.KtCallExpression
+import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
+import org.jetbrains.kotlin.psi.KtVisitorVoid
+import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.types.isNullabilityFlexible
+import java.awt.BorderLayout
+import java.util.regex.PatternSyntaxException
+import javax.swing.JPanel
+
+class PlatformExtensionReceiverOfInlineInspection : AbstractKotlinInspection() {
+
+ private var nameRegex: Regex? = defaultNamePattern.toRegex()
+ var namePattern: String = defaultNamePattern
+ set(value) {
+ field = value
+ nameRegex = try {
+ value.toRegex()
+ } catch (e: PatternSyntaxException) {
+ null
+ }
+ }
+
+
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession) =
+ object : KtVisitorVoid() {
+ override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression) {
+ super.visitDotQualifiedExpression(expression)
+
+ if (!expression.languageVersionSettings.supportsFeature(LanguageFeature.NullabilityAssertionOnExtensionReceiver)) {
+ return
+ }
+ val nameRegex = nameRegex
+ val callExpression = expression.selectorExpression as? KtCallExpression ?: return
+ val calleeText = callExpression.calleeExpression?.text ?: return
+ if (nameRegex != null && !nameRegex.matches(calleeText)) {
+ return
+ }
+
+ val context = expression.analyze(BodyResolveMode.PARTIAL)
+ val resolvedCall = expression.getResolvedCall(context) ?: return
+ val extensionReceiverType = resolvedCall.extensionReceiver?.type ?: return
+ if (!extensionReceiverType.isNullabilityFlexible()) return
+ val descriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return
+ if (!descriptor.isInline) return
+
+ val receiverExpression = expression.receiverExpression
+ holder.registerProblem(
+ receiverExpression,
+ "Call of inline function with nullable extension receiver can provoke NPE in Kotlin 1.2+",
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ IntentionWrapper(AddExclExclCallFix(receiverExpression), receiverExpression.containingKtFile)
+ )
+ }
+ }
+
+ override fun createOptionsPanel() = OptionsPanel(this)
+
+ class OptionsPanel internal constructor(owner: PlatformExtensionReceiverOfInlineInspection) : JPanel() {
+ init {
+ layout = BorderLayout()
+
+ val regexField = EditorTextField(owner.namePattern, null, RegExpFileType.INSTANCE).apply {
+ setOneLineMode(true)
+ }
+ regexField.document.addDocumentListener(object : DocumentListener {
+ override fun documentChanged(e: DocumentEvent?) {
+ owner.namePattern = regexField.text
+ }
+ })
+ val labeledComponent = LabeledComponent.create(regexField, "Pattern:", BorderLayout.WEST)
+ add(labeledComponent, BorderLayout.NORTH)
+ }
+ }
+
+ companion object {
+ const val defaultNamePattern = "(toBoolean)|(content.*)"
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/ToBoolean.iml b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/ToBoolean.iml
new file mode 100644
index 00000000000..c90834f2d60
--- /dev/null
+++ b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/ToBoolean.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/src/JavaClass.java b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/src/JavaClass.java
new file mode 100644
index 00000000000..77fb3a8fc3f
--- /dev/null
+++ b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/src/JavaClass.java
@@ -0,0 +1,9 @@
+public class JavaClass {
+ public static String getNull() {
+ return null;
+ }
+
+ public static My getMy() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/src/Test.kt b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/src/Test.kt
new file mode 100644
index 00000000000..b409c1e7aaf
--- /dev/null
+++ b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/before/ToBoolean/src/Test.kt
@@ -0,0 +1,15 @@
+fun test() {
+ JavaClass.getNull().toBoolean() // ISE in runtime
+ JavaClass.getNull().toInt() // OK
+ "123".toBoolean() // OK
+ null.toBoolean() // Compilation error, no inspection message
+
+ JavaClass.getNull().contentNotInline() // OK
+ JavaClass.getMy().contentNonExtensionInlineFun() // OK
+}
+
+fun String.contentNotInline() {}
+
+class My {
+ inline fun contentNonExtensionInlineFun() {}
+}
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/expected.xml b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/expected.xml
new file mode 100644
index 00000000000..0f42edd53d7
--- /dev/null
+++ b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/expected.xml
@@ -0,0 +1,9 @@
+
+
+ Test.kt
+ 2
+
+ Unsafe call of inline function with nullable extension receiver
+ Call of inline function with nullable extension receiver can provoke NPE in Kotlin 1.2+
+
+
diff --git a/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/platformExtensionReceiverOfInline.test b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/platformExtensionReceiverOfInline.test
new file mode 100644
index 00000000000..a689a9f467d
--- /dev/null
+++ b/idea/testData/multiFileInspections/platformExtensionReceiverOfInline/platformExtensionReceiverOfInline.test
@@ -0,0 +1,5 @@
+{
+ "inspectionClass": "org.jetbrains.kotlin.idea.inspections.PlatformExtensionReceiverOfInlineInspection",
+ "withRuntime": "true",
+ "isMultiModule": "false"
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
index 507076654bb..f17810bb673 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
@@ -54,4 +54,10 @@ public class MultiFileInspectionTestGenerated extends AbstractMultiFileInspectio
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileInspections/mismatchedProjectAndDirectory/mismatchedProjectAndDirectory.test");
doTest(fileName);
}
+
+ @TestMetadata("platformExtensionReceiverOfInline/platformExtensionReceiverOfInline.test")
+ public void testPlatformExtensionReceiverOfInline_PlatformExtensionReceiverOfInline() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/multiFileInspections/platformExtensionReceiverOfInline/platformExtensionReceiverOfInline.test");
+ doTest(fileName);
+ }
}