Update diagnostics for trailing lambdas, add quickfix
Alternative message for errors, caused by unexpected lambda expression arguments on a new line. Both diagnostic are reported, if multiple lambda expressions were passed to the call. For other errors trailing lambda diagnostic overrides the original one. Quickfix for erroneous trailing lambdas on a new line after call. Fix separates lambda expression from previous call with semicolon. All trailing lambda arguments become standalone lambda expressions.
This commit is contained in:
+5
@@ -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");
|
||||
|
||||
@@ -695,6 +695,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<LeafPsiElement> SPREAD_OF_LAMBDA_OR_CALLABLE_REFERENCE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtExpression> MANY_LAMBDA_EXPRESSION_ARGUMENTS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtLambdaExpression> UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> TOO_MANY_ARGUMENTS = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
|
||||
+1
@@ -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");
|
||||
|
||||
|
||||
+6
-4
@@ -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()))
|
||||
|
||||
+18
-4
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ExpressionReceiver>()?.expression ?: dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
|
||||
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
|
||||
|
||||
val KtLambdaExpression.isTrailingLambdaOnNewLIne
|
||||
get(): Boolean {
|
||||
parent?.safeAs<KtLambdaArgument>()?.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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 <!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
noArgs() <!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
noArgs() // {}
|
||||
noArgs() /* */ <!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
noArgs() /*
|
||||
block comment, no new line
|
||||
*/ <!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
noArgs()
|
||||
/*
|
||||
block comment with new line
|
||||
*/
|
||||
<!UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
noArgs() // comment
|
||||
// comment
|
||||
<!UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
noArgs() <!TOO_MANY_ARGUMENTS!>{}<!> <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
|
||||
noArgs() <!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
}
|
||||
|
||||
fun testLambdaArg() {
|
||||
oneLambdaArg(<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
oneLambdaArg {}
|
||||
oneLambdaArg()
|
||||
{}
|
||||
oneLambdaArg()
|
||||
{}
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
oneLambdaArg(
|
||||
{},
|
||||
<!TOO_MANY_ARGUMENTS!>{}<!>
|
||||
)
|
||||
oneLambdaArg() {}
|
||||
oneLambdaArg(<!NO_VALUE_FOR_PARAMETER!>)<!> // {}
|
||||
oneLambdaArg() /* */ {}
|
||||
oneLambdaArg() /*
|
||||
block
|
||||
comment
|
||||
*/ {}
|
||||
oneLambdaArg() // comment
|
||||
// comment
|
||||
{}
|
||||
oneLambdaArg() {}/*
|
||||
block comment, no new line
|
||||
*/ <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
|
||||
oneLambdaArg() {}/*
|
||||
block comment with new line
|
||||
*/
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
oneLambdaArg() {}// comment
|
||||
// comment
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
oneLambdaArg() {} <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
|
||||
oneLambdaArg() {}
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
oneLambdaArg() {} // comment
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
}
|
||||
|
||||
fun testVararg() {
|
||||
varargFn(1,2,3)
|
||||
varargFn <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
varargFn(1,2,3) <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
varargFn(1,2,3) // {}
|
||||
varargFn(1,2,3) /* */ <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
varargFn(1,2,3) /*
|
||||
block comment, no new line
|
||||
*/ <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
varargFn(1,2,3)
|
||||
/*
|
||||
block comment with new line
|
||||
*/ <!UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
varargFn(1,2,3) // comment
|
||||
// comment
|
||||
<!UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
varargFn(1,2,3) <!VARARG_OUTSIDE_PARENTHESES!>{}<!> <!MANY_LAMBDA_EXPRESSION_ARGUMENTS!>{}<!>
|
||||
varargFn(1,2,3) <!VARARG_OUTSIDE_PARENTHESES!>{}<!>
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
}
|
||||
|
||||
fun testTwoLambdas() {
|
||||
twoLambdaArgs(
|
||||
f1 = {},
|
||||
f2 =
|
||||
{}
|
||||
)
|
||||
|
||||
fun bar(): () -> Unit {
|
||||
twoLambdaArgs(<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
{}
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!>
|
||||
|
||||
return <!NI;TYPE_MISMATCH, NI;TYPE_MISMATCH!>if (true) {
|
||||
<!OI;TYPE_MISMATCH!>twoLambdaArgs({})
|
||||
{}
|
||||
<!MANY_LAMBDA_EXPRESSION_ARGUMENTS, UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{}<!><!>
|
||||
} else <!NI;TYPE_MISMATCH!>{
|
||||
{}
|
||||
}<!><!>
|
||||
}
|
||||
}
|
||||
|
||||
fun f1(): (() -> Unit) -> (() -> Unit) -> Unit {
|
||||
return { l1 ->
|
||||
<!NI;TYPE_MISMATCH, TYPE_MISMATCH!>l1()
|
||||
<!UNEXPECTED_TRAILING_LAMBDA_ON_A_NEW_LINE!>{ <!OI;CANNOT_INFER_PARAMETER_TYPE!>l2<!> -> <!OI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!><!NI;FUNCTION_EXPECTED!>l2<!>()<!> }<!><!>
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
@@ -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<KtLambdaExpression>(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<KtLambdaArgument>()
|
||||
?: return
|
||||
val callExpression = lambdaExpressionArgument.parent.safeAs<KtCallExpression>()
|
||||
?: 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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Terminate preceding call with semicolon" "true"
|
||||
|
||||
fun foo() {}
|
||||
|
||||
fun test() {
|
||||
foo()
|
||||
{<caret>}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Terminate preceding call with semicolon" "true"
|
||||
|
||||
fun foo() {}
|
||||
|
||||
fun test() {
|
||||
foo()<caret>;
|
||||
{}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Terminate preceding call with semicolon" "true"
|
||||
|
||||
fun foo(
|
||||
fn: () -> Unit
|
||||
) {}
|
||||
|
||||
fun test() {
|
||||
foo()
|
||||
{}
|
||||
{}<caret>
|
||||
{}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Terminate preceding call with semicolon" "true"
|
||||
|
||||
fun foo(
|
||||
fn: () -> Unit
|
||||
) {}
|
||||
|
||||
fun test() {
|
||||
foo()
|
||||
{}<caret>;
|
||||
{}
|
||||
{}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Terminate preceding call with semicolon" "true"
|
||||
|
||||
fun foo() {}
|
||||
|
||||
fun test() {
|
||||
foo()/*
|
||||
block
|
||||
comment
|
||||
*/
|
||||
// comment
|
||||
{}<caret>
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Terminate preceding call with semicolon" "true"
|
||||
|
||||
fun foo() {}
|
||||
|
||||
fun test() {
|
||||
foo()<caret>;/*
|
||||
block
|
||||
comment
|
||||
*/
|
||||
// comment
|
||||
{}
|
||||
}
|
||||
+13
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user