diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java index cbcaf8768bf..4e9a2fc3347 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirDiagnosticsSmokeTestGenerated.java @@ -17591,6 +17591,11 @@ public class FirDiagnosticsSmokeTestGenerated extends AbstractFirDiagnosticsSmok runTest("compiler/testData/diagnostics/tests/resolve/localObject.kt"); } + @TestMetadata("newLineLambda.kt") + public void testNewLineLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/newLineLambda.kt"); + } + @TestMetadata("objectLiteralAsArgument.kt") public void testObjectLiteralAsArgument() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/objectLiteralAsArgument.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 3d0bb60d00f..a761c14fff3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -695,6 +695,7 @@ public interface Errors { DiagnosticFactory0 SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 MANY_LAMBDA_EXPRESSION_ARGUMENTS = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 TOO_MANY_ARGUMENTS = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 2fb829ccde2..d9ec4596688 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -203,6 +203,7 @@ public class DefaultErrorMessages { MAP.put(SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE, "The spread operator (*foo) cannot be applied to lambda argument or callable reference"); MAP.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list"); + MAP.put(UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE, "Expression is treated a trailing lambda argument; consider separating it from call with semicolon"); MAP.put(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, "This property must either have a type annotation, be initialized or be delegated"); MAP.put(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER, "This variable must either have a type annotation or be initialized"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt index 2daa47dfa2b..20510b7cdfb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/DiagnosticReporterByTrackingStrategy.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.isNull import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.callUtil.reportTrailingLambdaErrorOr import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.model.* @@ -118,14 +119,15 @@ class DiagnosticReporterByTrackingStrategy( SmartCastDiagnostic::class.java -> reportSmartCast(diagnostic as SmartCastDiagnostic) UnstableSmartCast::class.java -> reportUnstableSmartCast(diagnostic as UnstableSmartCast) TooManyArguments::class.java -> { - reportIfNonNull(callArgument.psiExpression) { - trace.report(TOO_MANY_ARGUMENTS.on(it, (diagnostic as TooManyArguments).descriptor)) + trace.reportTrailingLambdaErrorOr(callArgument.psiExpression) { expr -> + TOO_MANY_ARGUMENTS.on(expr, (diagnostic as TooManyArguments).descriptor) } trace.markAsReported() } - VarargArgumentOutsideParentheses::class.java -> - reportIfNonNull(callArgument.psiExpression) { trace.report(VARARG_OUTSIDE_PARENTHESES.on(it)) } + VarargArgumentOutsideParentheses::class.java -> trace.reportTrailingLambdaErrorOr(callArgument.psiExpression) { expr -> + VARARG_OUTSIDE_PARENTHESES.on(expr) + } MixingNamedAndPositionArguments::class.java -> trace.report(MIXING_NAMED_AND_POSITIONED_ARGUMENTS.on(callArgument.psiCallArgument.valueArgument.asElement())) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ValueArgumentsToParametersMapper.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ValueArgumentsToParametersMapper.java index f211a1f6932..3a0ae7dc46f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ValueArgumentsToParametersMapper.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/ValueArgumentsToParametersMapper.java @@ -278,17 +278,26 @@ public class ValueArgumentsToParametersMapper { KtExpression possiblyLabeledFunctionLiteral = lambdaArgument.getArgumentExpression(); if (parameters.isEmpty()) { - report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidateCall.getCandidateDescriptor())); + CallUtilKt.reportTrailingLambdaErrorOr( + candidateCall.getTrace(), possiblyLabeledFunctionLiteral, + expression -> TOO_MANY_ARGUMENTS.on(expression, candidateCall.getCandidateDescriptor()) + ); setStatus(ERROR); } else { ValueParameterDescriptor lastParameter = CollectionsKt.last(parameters); if (lastParameter.getVarargElementType() != null) { - report(VARARG_OUTSIDE_PARENTHESES.on(possiblyLabeledFunctionLiteral)); + CallUtilKt.reportTrailingLambdaErrorOr( + candidateCall.getTrace(), possiblyLabeledFunctionLiteral, + expression -> VARARG_OUTSIDE_PARENTHESES.on(expression) + ); setStatus(ERROR); } else if (!usedParameters.add(lastParameter)) { - report(TOO_MANY_ARGUMENTS.on(possiblyLabeledFunctionLiteral, candidateCall.getCandidateDescriptor())); + CallUtilKt.reportTrailingLambdaErrorOr( + candidateCall.getTrace(), possiblyLabeledFunctionLiteral, + expr -> TOO_MANY_ARGUMENTS.on(expr, candidateCall.getCandidateDescriptor()) + ); setStatus(WEAK_ERROR); } else { @@ -298,7 +307,12 @@ public class ValueArgumentsToParametersMapper { for (int i = 1; i < functionLiteralArguments.size(); i++) { KtExpression argument = functionLiteralArguments.get(i).getArgumentExpression(); - report(MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(argument)); + if (argument instanceof KtLambdaExpression) { + report(MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(argument)); + if (CallUtilKt.isTrailingLambdaOnNewLIne((KtLambdaExpression) argument)) { + report(UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE.on((KtLambdaExpression) argument)); + } + } setStatus(WEAK_ERROR); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 0b9b5be438c..f9363e5491e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -538,6 +538,9 @@ class PSICallResolver( if (i == 0) continue val lambdaExpression = externalLambdaArguments[i].getLambdaExpression() ?: continue + if (lambdaExpression.isTrailingLambdaOnNewLIne) { + context.trace.report(Errors.UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE.on(lambdaExpression)) + } context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(lambdaExpression)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt index 249696038e2..15a96da84bc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/callUtil.kt @@ -17,14 +17,18 @@ package org.jetbrains.kotlin.resolve.calls.callUtil import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getTextWithLocation import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.CALL import org.jetbrains.kotlin.resolve.BindingContext.RESOLVED_CALL +import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.CallTransformer import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext @@ -278,4 +282,33 @@ fun ResolvedCall<*>.getFirstArgumentExpression(): KtExpression? = valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() } fun ResolvedCall<*>.getReceiverExpression(): KtExpression? = - extensionReceiver.safeAs()?.expression ?: dispatchReceiver.safeAs()?.expression \ No newline at end of file + extensionReceiver.safeAs()?.expression ?: dispatchReceiver.safeAs()?.expression + +val KtLambdaExpression.isTrailingLambdaOnNewLIne + get(): Boolean { + parent?.safeAs()?.let { lambdaArgument -> + var prevSibling = lambdaArgument.prevSibling + + while (prevSibling != null && prevSibling !is KtElement) { + if (prevSibling is PsiWhiteSpace && prevSibling.textContains('\n')) + return true + prevSibling = prevSibling.prevSibling + } + } + + return false + } + + +inline fun BindingTrace.reportTrailingLambdaErrorOr( + expression: KtExpression?, + originalDiagnostic: (KtExpression) -> Diagnostic +) { + expression?.let { expr -> + if (expr is KtLambdaExpression && expr.isTrailingLambdaOnNewLIne) { + report(Errors.UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE.on(expr)) + } else { + report(originalDiagnostic(expr)) + } + } +} diff --git a/compiler/testData/diagnostics/tests/resolve/newLineLambda.kt b/compiler/testData/diagnostics/tests/resolve/newLineLambda.kt new file mode 100644 index 00000000000..d8c1eab4f37 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/newLineLambda.kt @@ -0,0 +1,118 @@ +// !WITH_NEW_INFERENCE +// !DIAGNOSTICS: -UNUSED_PARAMETER + +fun noArgs() {} +fun oneLambdaArg(fn: () -> Unit) {} +fun twoLambdaArgs(f1: () -> Unit, f2: () -> Unit) {} +fun varargFn(vararg args: Int) {} + +fun testNoArgs() { + noArgs() + noArgs {} + noArgs() {} + noArgs() // {} + noArgs() /* */ {} + noArgs() /* + block comment, no new line + */ {} + noArgs() + /* + block comment with new line + */ + {} + noArgs() // comment + // comment + {} + noArgs() {} {} + noArgs() {} + {} +} + +fun testLambdaArg() { + oneLambdaArg() + oneLambdaArg {} + oneLambdaArg() + {} + oneLambdaArg() + {} + {} + oneLambdaArg( + {}, + {} + ) + oneLambdaArg() {} + oneLambdaArg() // {} + oneLambdaArg() /* */ {} + oneLambdaArg() /* + block + comment + */ {} + oneLambdaArg() // comment + // comment + {} + oneLambdaArg() {}/* + block comment, no new line + */ {} + oneLambdaArg() {}/* + block comment with new line + */ + {} + oneLambdaArg() {}// comment + // comment + {} + oneLambdaArg() {} {} + oneLambdaArg() {} + {} + oneLambdaArg() {} // comment + {} +} + +fun testVararg() { + varargFn(1,2,3) + varargFn {} + varargFn(1,2,3) {} + varargFn(1,2,3) // {} + varargFn(1,2,3) /* */ {} + varargFn(1,2,3) /* + block comment, no new line + */ {} + varargFn(1,2,3) + /* + block comment with new line + */ {} + varargFn(1,2,3) // comment + // comment + {} + varargFn(1,2,3) {} {} + varargFn(1,2,3) {} + {} +} + +fun testTwoLambdas() { + twoLambdaArgs( + f1 = {}, + f2 = + {} + ) + + fun bar(): () -> Unit { + twoLambdaArgs() + {} + {} + + return if (true) { + twoLambdaArgs({}) + {} + {} + } else { + {} + } + } +} + +fun f1(): (() -> Unit) -> (() -> Unit) -> Unit { + return { l1 -> + l1() + { l2 -> l2() } + } +} diff --git a/compiler/testData/diagnostics/tests/resolve/newLineLambda.txt b/compiler/testData/diagnostics/tests/resolve/newLineLambda.txt new file mode 100644 index 00000000000..df0d23676e6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/newLineLambda.txt @@ -0,0 +1,11 @@ +package + +public fun f1(): (() -> kotlin.Unit) -> (() -> kotlin.Unit) -> kotlin.Unit +public fun noArgs(): kotlin.Unit +public fun oneLambdaArg(/*0*/ fn: () -> kotlin.Unit): kotlin.Unit +public fun testLambdaArg(): kotlin.Unit +public fun testNoArgs(): kotlin.Unit +public fun testTwoLambdas(): kotlin.Unit +public fun testVararg(): kotlin.Unit +public fun twoLambdaArgs(/*0*/ f1: () -> kotlin.Unit, /*1*/ f2: () -> kotlin.Unit): kotlin.Unit +public fun varargFn(/*0*/ vararg args: kotlin.Int /*kotlin.IntArray*/): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 801136fec4f..4bce66ca116 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -17603,6 +17603,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { runTest("compiler/testData/diagnostics/tests/resolve/localObject.kt"); } + @TestMetadata("newLineLambda.kt") + public void testNewLineLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/newLineLambda.kt"); + } + @TestMetadata("objectLiteralAsArgument.kt") public void testObjectLiteralAsArgument() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/objectLiteralAsArgument.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 82d7ce3ac34..7b805010b87 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -17593,6 +17593,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/resolve/localObject.kt"); } + @TestMetadata("newLineLambda.kt") + public void testNewLineLambda() throws Exception { + runTest("compiler/testData/diagnostics/tests/resolve/newLineLambda.kt"); + } + @TestMetadata("objectLiteralAsArgument.kt") public void testObjectLiteralAsArgument() throws Exception { runTest("compiler/testData/diagnostics/tests/resolve/objectLiteralAsArgument.kt"); diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddSemicolonBeforeLambdaExpressionFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddSemicolonBeforeLambdaExpressionFix.kt new file mode 100644 index 00000000000..08c3d64b91b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddSemicolonBeforeLambdaExpressionFix.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.quickfix + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.startOffset +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +class AddSemicolonBeforeLambdaExpressionFix(element: KtLambdaExpression) : KotlinQuickFixAction(element) { + override fun getText(): String = "Terminate preceding call with semicolon" + override fun getFamilyName(): String = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val lambdaExpressionArgument = element?.parent?.safeAs() + ?: return + val callExpression = lambdaExpressionArgument.parent.safeAs() + ?: return + val desiredEndOfCallExpression = + PsiTreeUtil.findSiblingBackward( + lambdaExpressionArgument, + KtNodeTypes.LAMBDA_ARGUMENT, + null + ) ?: PsiTreeUtil.findSiblingBackward( + lambdaExpressionArgument, + KtNodeTypes.VALUE_ARGUMENT_LIST, + null + ) + desiredEndOfCallExpression?.let { endOfCall -> + makeNewExpressionsFromFollowingLambdas(callExpression, endOfCall) + val semicolon = callExpression.parent.addAfter( + KtPsiFactory(project).createSemicolon(), + callExpression + ) + editor?.caretModel?.moveToOffset(semicolon.startOffset) + } + } + + private fun makeNewExpressionsFromFollowingLambdas( + oldCallExpression: KtCallExpression, + endOfArguments: PsiElement + ) { + var lastSibling = oldCallExpression.lastChild + val parentForCallExpression = oldCallExpression.parent + + while (lastSibling != endOfArguments) { + when (lastSibling) { + is KtLambdaArgument -> parentForCallExpression.addAfter( + lastSibling.getLambdaExpression() ?: lastSibling, + oldCallExpression + ) + else -> parentForCallExpression.addAfter( + lastSibling, + oldCallExpression + ) + } + lastSibling = lastSibling.prevSibling + } + + oldCallExpression.deleteChildRange(endOfArguments.nextSibling, oldCallExpression.lastChild) + } + + companion object Factory : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic) = + diagnostic.createIntentionForFirstParentOfType(::AddSemicolonBeforeLambdaExpressionFix) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 8d76240ee19..5676a02090a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -611,5 +611,7 @@ class QuickFixRegistrar : QuickFixContributor { RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION_WARNING.registerFactory(RestrictedRetentionForExpressionAnnotationFactory) NO_VALUE_FOR_PARAMETER.registerFactory(AddConstructorParameterFromSuperTypeCallFix) + + UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE.registerFactory(AddSemicolonBeforeLambdaExpressionFix.Factory) } } diff --git a/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt new file mode 100644 index 00000000000..01d368e9583 --- /dev/null +++ b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt @@ -0,0 +1,8 @@ +// "Terminate preceding call with semicolon" "true" + +fun foo() {} + +fun test() { + foo() + {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt.after b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt.after new file mode 100644 index 00000000000..71118749403 --- /dev/null +++ b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt.after @@ -0,0 +1,8 @@ +// "Terminate preceding call with semicolon" "true" + +fun foo() {} + +fun test() { + foo(); + {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt new file mode 100644 index 00000000000..232bff4a8f5 --- /dev/null +++ b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt @@ -0,0 +1,12 @@ +// "Terminate preceding call with semicolon" "true" + +fun foo( + fn: () -> Unit +) {} + +fun test() { + foo() + {} + {} + {} +} diff --git a/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt.after b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt.after new file mode 100644 index 00000000000..c93fd6e0f1b --- /dev/null +++ b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt.after @@ -0,0 +1,12 @@ +// "Terminate preceding call with semicolon" "true" + +fun foo( + fn: () -> Unit +) {} + +fun test() { + foo() + {}; + {} + {} +} diff --git a/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt new file mode 100644 index 00000000000..e67076b6914 --- /dev/null +++ b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt @@ -0,0 +1,12 @@ +// "Terminate preceding call with semicolon" "true" + +fun foo() {} + +fun test() { + foo()/* + block + comment + */ + // comment + {} +} \ No newline at end of file diff --git a/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt.after b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt.after new file mode 100644 index 00000000000..9ab45266ed4 --- /dev/null +++ b/idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt.after @@ -0,0 +1,12 @@ +// "Terminate preceding call with semicolon" "true" + +fun foo() {} + +fun test() { + foo();/* + block + comment + */ + // comment + {} +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 1ab12cb23f9..8c07814bb94 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -312,6 +312,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/addSemicolonBeforeLambdaExpression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddSemicolonBeforeLambdaExpression extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInAddSemicolonBeforeLambdaExpression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/addSemicolonBeforeLambdaExpression"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + @TestMetadata("idea/testData/quickfix/addStarProjections") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 8be146be202..e55ba25f76b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1097,6 +1097,34 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/addSemicolonBeforeLambdaExpression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddSemicolonBeforeLambdaExpression extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInAddSemicolonBeforeLambdaExpression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/addSemicolonBeforeLambdaExpression"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("idea/testData/quickfix/addSemicolonBeforeLambdaExpression/basic.kt"); + } + + @TestMetadata("multipleLambdas.kt") + public void testMultipleLambdas() throws Exception { + runTest("idea/testData/quickfix/addSemicolonBeforeLambdaExpression/multipleLambdas.kt"); + } + + @TestMetadata("withComments.kt") + public void testWithComments() throws Exception { + runTest("idea/testData/quickfix/addSemicolonBeforeLambdaExpression/withComments.kt"); + } + } + @TestMetadata("idea/testData/quickfix/addStarProjections") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)