Use a separate diagnostic for 'suspend fun' sequence

instead of reusing existing one, since existing one
is ERROR, and we cannot turn code red without deprecating
it with WARNING.
 #KT-49264
This commit is contained in:
Ilmir Usmanov
2021-10-19 01:08:59 +02:00
parent dbfe3524ce
commit 2b8963455f
5 changed files with 47 additions and 8 deletions
@@ -1176,6 +1176,7 @@ public interface Errors {
DiagnosticFactory0<PsiElement> NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtReturnExpression> RETURN_FOR_BUILT_IN_SUSPEND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN = DiagnosticFactory0.create(WARNING);
DiagnosticFactory1<PsiElement, RenderedDiagnostic<?>> PLUGIN_ERROR = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<PsiElement, RenderedDiagnostic<?>> PLUGIN_WARNING = DiagnosticFactory1.create(WARNING);
@@ -1069,6 +1069,7 @@ public class DefaultErrorMessages {
MAP.put(IMPLICIT_NOTHING_TYPE_ARGUMENT_AGAINST_NOT_NOTHING_EXPECTED_TYPE, "Returning type parameter has been inferred to Nothing implicitly because Nothing is more specific than specified expected type. Please specify type arguments explicitly in accordance with expected type to hide this warning. Nothing can produce an exception at runtime. See KT-36776 for more details.");
MAP.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited");
MAP.put(MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND, "Calls having a form of ''suspend {}'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Add empty argument list to the call: ''suspend() { ... }''");
MAP.put(MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN, "Calls having a form of ''suspend fun'' are deprecated because ''suspend'' in the context will have a meaning of a modifier. Surround the argument of the call with parens: ''suspend(fun() { ... })''");
MAP.put(PLUGIN_ERROR, "{0}", (d, c) -> d.getText());
MAP.put(PLUGIN_WARNING, "{0}", (d, c) -> d.getText());
@@ -34,7 +34,12 @@ object LambdaWithSuspendModifierCallChecker : CallChecker {
}
else -> {
if ((calleeName == "suspend" || variableCalleeName == "suspend") && call.hasFormOfSuspendModifierForLambdaOrFun()) {
context.trace.report(Errors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND.on(reportOn))
if (call.hasNoArgumentListButDanglingLambdas() || call.isInfixWithRightLambda()) {
context.trace.report(Errors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND.on(reportOn))
} else {
require(call.isInfixWithRightFun())
context.trace.report(Errors.MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN.on(reportOn))
}
}
}
}
@@ -43,7 +48,7 @@ object LambdaWithSuspendModifierCallChecker : CallChecker {
private fun Call.hasFormOfSuspendModifierForLambdaOrFun() =
!isCallableReference()
&& typeArguments.isEmpty()
&& (hasNoArgumentListButDanglingLambdas() || isInfixWithRightLambdaOrFun())
&& (hasNoArgumentListButDanglingLambdas() || isInfixWithRightLambda() || isInfixWithRightFun())
private fun Call.referencedName() =
calleeExpression?.safeAs<KtSimpleNameExpression>()?.getReferencedName()
@@ -51,7 +56,11 @@ object LambdaWithSuspendModifierCallChecker : CallChecker {
private fun Call.hasNoArgumentListButDanglingLambdas() =
valueArgumentList?.leftParenthesis == null && functionLiteralArguments.isNotEmpty()
private fun Call.isInfixWithRightLambdaOrFun() =
private fun Call.isInfixWithRightLambda() =
isInfixCall(this)
&& callElement.safeAs<KtBinaryExpression>()?.right.let { it is KtLambdaExpression || it is KtNamedFunction }
&& callElement.safeAs<KtBinaryExpression>()?.right is KtLambdaExpression
private fun Call.isInfixWithRightFun() =
isInfixCall(this)
&& callElement.safeAs<KtBinaryExpression>()?.right is KtNamedFunction
}
@@ -0,0 +1,29 @@
// SKIP_TXT
infix fun Int.suspend(c: () -> Unit) { c() }
fun bar() {
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> fun() {
println()
}
1 <!SYNTAX!>@Ann suspend fun()<!> {
println()
}
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> @Ann fun() {
println()
}
}
@Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class Ann
fun main(suspend: WLambdaInvoke) {
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> fun() {}
}
class WLambdaInvoke {
operator fun Int.invoke(l: () -> Unit) {}
}
@@ -1,10 +1,9 @@
// FIR_IDENTICAL
// SKIP_TXT
infix fun Int.suspend(c: () -> Unit) { c() }
fun bar() {
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> fun() {
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN!>suspend<!> fun() {
println()
}
@@ -12,7 +11,7 @@ fun bar() {
println()
}
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> @Ann fun() {
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN!>suspend<!> @Ann fun() {
println()
}
}
@@ -22,7 +21,7 @@ fun bar() {
annotation class Ann
fun main(suspend: WLambdaInvoke) {
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND!>suspend<!> fun() {}
1 <!MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND_FUN!>suspend<!> fun() {}
}
class WLambdaInvoke {