diff --git a/idea/resources/inspectionDescriptions/UnusedLambdaExpressionBody.html b/idea/resources/inspectionDescriptions/UnusedLambdaExpressionBody.html
new file mode 100644
index 00000000000..bbc8be913ff
--- /dev/null
+++ b/idea/resources/inspectionDescriptions/UnusedLambdaExpressionBody.html
@@ -0,0 +1,6 @@
+
+
+This inspection reports calls with unused return value when the function is defined with lambda as expression body.
+Happens when someone accidentally puts '=' between function header and body block.
+
+
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index 387b4e8ada0..cdfac892b4c 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -2071,6 +2071,14 @@
language="kotlin"
/>
+
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt
new file mode 100644
index 00000000000..52988b39ec8
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedLambdaExpressionBodyInspection.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.inspections
+
+import com.intellij.codeInsight.FileModificationService
+import com.intellij.codeInspection.LocalQuickFix
+import com.intellij.codeInspection.ProblemDescriptor
+import com.intellij.codeInspection.ProblemsHolder
+import com.intellij.openapi.project.Project
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiElementVisitor
+import org.jetbrains.kotlin.builtins.isFunctionType
+import org.jetbrains.kotlin.descriptors.CallableDescriptor
+import org.jetbrains.kotlin.idea.caches.resolve.analyze
+import org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.resolve.BindingContext
+import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
+import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
+import org.jetbrains.kotlin.resolve.source.getPsi
+
+
+class UnusedLambdaExpressionBodyInspection : AbstractKotlinInspection() {
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
+ return object : KtVisitorVoid() {
+ override fun visitCallExpression(expression: KtCallExpression) {
+ val context = expression.analyze(BodyResolveMode.PARTIAL)
+ if (expression.used(context)) {
+ return
+ }
+
+ val descriptor = expression.getResolvedCall(context)?.resultingDescriptor ?: return
+ if (!descriptor.returnsFunction()) {
+ return
+ }
+
+ val function = descriptor.source.getPsi() as? KtFunction ?: return
+ if (function.hasBlockBody() || function.bodyExpression !is KtLambdaExpression) {
+ return
+ }
+
+ holder.registerProblem(expression,
+ "Unused return value of a function with lambda expression body",
+ RemoveEqTokenFromFunctionDeclarationFix(function))
+ }
+ }
+ }
+
+ private fun KtExpression.used(context: BindingContext): Boolean = context[BindingContext.USED_AS_EXPRESSION, this] ?: true
+
+ private fun CallableDescriptor.returnsFunction() = returnType?.isFunctionType ?: false
+
+ class RemoveEqTokenFromFunctionDeclarationFix(val function: KtFunction) : LocalQuickFix {
+ override fun getName(): String = "Remove '=' token from function declaration"
+
+ override fun getFamilyName(): String = name
+
+ override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
+ if (!FileModificationService.getInstance().preparePsiElementForWrite(function)) {
+ return
+ }
+
+ function.equalsToken?.apply {
+ // TODO: This should be done by formatter but there is no rule for this now
+ if (prevSibling.isSpace() && nextSibling.isSpace()) {
+ prevSibling.delete()
+ }
+ delete()
+ }
+ }
+
+ private fun PsiElement.isSpace() = text == " "
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/expected.xml b/idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/expected.xml
new file mode 100644
index 00000000000..9bc228be6fc
--- /dev/null
+++ b/idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/expected.xml
@@ -0,0 +1,18 @@
+
+
+ simple.kt
+ 3
+ light_idea_test_case
+
+ Unused return value of a function with lambda expression body
+ Unused return value of a function with lambda expression body
+
+
+ simple.kt
+ 6
+ light_idea_test_case
+
+ Unused return value of a function with lambda expression body
+ Unused return value of a function with lambda expression body
+
+
\ No newline at end of file
diff --git a/idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/inspections.test b/idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/inspections.test
new file mode 100644
index 00000000000..ba7b69be858
--- /dev/null
+++ b/idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/inspections.test
@@ -0,0 +1 @@
+// INSPECTION_CLASS: org.jetbrains.kotlin.idea.inspections.UnusedLambdaExpressionBodyInspection
diff --git a/idea/testData/inspections/unusedLambdaExpressionBody/simple.kt b/idea/testData/inspections/unusedLambdaExpressionBody/simple.kt
new file mode 100644
index 00000000000..34dc5b3e0f3
--- /dev/null
+++ b/idea/testData/inspections/unusedLambdaExpressionBody/simple.kt
@@ -0,0 +1,13 @@
+
+fun foo() {
+ bar()
+ val a = bar()
+ if (bar() != null) {
+ bar()
+ }
+ bar()()
+}
+
+fun bar() = {
+
+}
\ No newline at end of file
diff --git a/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/.inspection b/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/.inspection
new file mode 100644
index 00000000000..607b45277a6
--- /dev/null
+++ b/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/.inspection
@@ -0,0 +1 @@
+org.jetbrains.kotlin.idea.inspections.UnusedLambdaExpressionBodyInspection
\ No newline at end of file
diff --git a/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt b/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt
new file mode 100644
index 00000000000..6aa2cd2b044
--- /dev/null
+++ b/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt
@@ -0,0 +1,9 @@
+// "Remove '=' token from function declaration" "true"
+
+fun foo() {
+ bar()
+}
+
+fun bar() = {
+
+}
\ No newline at end of file
diff --git a/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt.after b/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt.after
new file mode 100644
index 00000000000..0104a42661f
--- /dev/null
+++ b/idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt.after
@@ -0,0 +1,9 @@
+// "Remove '=' token from function declaration" "true"
+
+fun foo() {
+ bar()
+}
+
+fun bar() {
+
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
index e739a605cdb..12596416c53 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/InspectionTestGenerated.java
@@ -311,6 +311,12 @@ public class InspectionTestGenerated extends AbstractInspectionTest {
doTest(fileName);
}
+ @TestMetadata("unusedLambdaExpressionBody/inspectionData/inspections.test")
+ public void testUnusedLambdaExpressionBody_inspectionData_Inspections_test() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/unusedLambdaExpressionBody/inspectionData/inspections.test");
+ doTest(fileName);
+ }
+
@TestMetadata("unusedReceiverParameter/inspectionData/inspections.test")
public void testUnusedReceiverParameter_inspectionData_Inspections_test() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/inspections/unusedReceiverParameter/inspectionData/inspections.test");
diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java
index 502e567568d..ec4e14f3364 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java
@@ -7732,6 +7732,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
}
}
+ @TestMetadata("idea/testData/quickfix/removeEqTokenFromFunctionDeclaration")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class RemoveEqTokenFromFunctionDeclaration extends AbstractQuickFixTest {
+ public void testAllFilesPresentInRemoveEqTokenFromFunctionDeclaration() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/removeEqTokenFromFunctionDeclaration"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true);
+ }
+
+ @TestMetadata("simple.kt")
+ public void testSimple() throws Exception {
+ String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/removeEqTokenFromFunctionDeclaration/simple.kt");
+ doTest(fileName);
+ }
+ }
+
@TestMetadata("idea/testData/quickfix/removeFinalUpperBound")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)