FIR: introduce RETURN_FOR_BUILT_IN_SUSPEND diagnostic
This commit is contained in:
committed by
teamcityserver
parent
229dfd3f5f
commit
807f031dcc
+1
@@ -1194,6 +1194,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
val NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
val NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
|
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -614,5 +614,6 @@ object FirErrors {
|
|||||||
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
val ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
val NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
val NON_MODIFIER_FORM_FOR_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||||
|
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-1
@@ -6,14 +6,18 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
|
|
||||||
object FirReturnAllowedChecker : FirReturnExpressionChecker() {
|
object FirReturnAllowedChecker : FirReturnExpressionChecker() {
|
||||||
override fun check(expression: FirReturnExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirReturnExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
@@ -26,6 +30,25 @@ object FirReturnAllowedChecker : FirReturnExpressionChecker() {
|
|||||||
reporter.reportOn(source, FirErrors.RETURN_NOT_ALLOWED, context)
|
reporter.reportOn(source, FirErrors.RETURN_NOT_ALLOWED, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (targetSymbol is FirAnonymousFunctionSymbol) {
|
||||||
|
val label = targetSymbol.label
|
||||||
|
if (label?.source?.kind !is FirRealSourceElementKind) {
|
||||||
|
val functionCall = context.qualifiedAccessOrAnnotationCalls.asReversed().find {
|
||||||
|
it is FirFunctionCall &&
|
||||||
|
((it.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirNamedFunctionSymbol)?.callableId ==
|
||||||
|
FirSuspendCallChecker.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID
|
||||||
|
}
|
||||||
|
if (functionCall is FirFunctionCall &&
|
||||||
|
functionCall.arguments.any {
|
||||||
|
it is FirLambdaArgumentExpression &&
|
||||||
|
(it.expression as? FirAnonymousFunctionExpression)?.anonymousFunction?.symbol == targetSymbol
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
reporter.reportOn(source, FirErrors.RETURN_FOR_BUILT_IN_SUSPEND, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val containingDeclaration = context.containingDeclarations.last()
|
val containingDeclaration = context.containingDeclarations.last()
|
||||||
if (containingDeclaration is FirFunction && containingDeclaration.body is FirSingleExpressionBlock) {
|
if (containingDeclaration is FirFunction && containingDeclaration.body is FirSingleExpressionBlock) {
|
||||||
reporter.reportOn(source, FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY, context)
|
reporter.reportOn(source, FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY, context)
|
||||||
|
|||||||
+5
-1
@@ -29,8 +29,10 @@ import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
|||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_2_20_FQ_NAME
|
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_2_20_FQ_NAME
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_2_30_FQ_NAME
|
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_2_30_FQ_NAME
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_3_FQ_NAME
|
import org.jetbrains.kotlin.resolve.calls.checkers.COROUTINE_CONTEXT_1_3_FQ_NAME
|
||||||
@@ -47,6 +49,8 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
|||||||
|
|
||||||
private val BUILTIN_SUSPEND_NAME = KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME.shortName()
|
private val BUILTIN_SUSPEND_NAME = KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME.shortName()
|
||||||
|
|
||||||
|
internal val KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID = CallableId(StandardClassIds.BASE_KOTLIN_PACKAGE, BUILTIN_SUSPEND_NAME)
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
@OptIn(SymbolInternals::class)
|
||||||
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
val reference = expression.calleeReference as? FirResolvedNamedReference ?: return
|
val reference = expression.calleeReference as? FirResolvedNamedReference ?: return
|
||||||
@@ -89,7 +93,7 @@ object FirSuspendCallChecker : FirQualifiedAccessExpressionChecker() {
|
|||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
reporter: DiagnosticReporter
|
reporter: DiagnosticReporter
|
||||||
) {
|
) {
|
||||||
if (symbol.callableId.asSingleFqName() == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME) {
|
if (symbol.callableId == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_CALLABLE_ID) {
|
||||||
if (reference.name != BUILTIN_SUSPEND_NAME ||
|
if (reference.name != BUILTIN_SUSPEND_NAME ||
|
||||||
expression.explicitReceiver != null ||
|
expression.explicitReceiver != null ||
|
||||||
!expression.hasFormOfSuspendModifierForLambda()
|
!expression.hasFormOfSuspendModifierForLambda()
|
||||||
|
|||||||
+2
@@ -339,6 +339,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESOLUTION_TO_CLASSIFIER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESOLUTION_TO_CLASSIFIER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESULT_TYPE_MISMATCH
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESULT_TYPE_MISMATCH
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_FOR_BUILT_IN_SUSPEND
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
||||||
@@ -1507,6 +1508,7 @@ class FirDefaultErrorMessages {
|
|||||||
MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND,
|
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() { ... }''"
|
"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(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
|
||||||
|
|
||||||
// Extended checkers group
|
// Extended checkers group
|
||||||
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
|
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
|
||||||
|
|||||||
+8
-2
@@ -143,7 +143,10 @@ class ExpressionsConverter(
|
|||||||
symbol = FirAnonymousFunctionSymbol()
|
symbol = FirAnonymousFunctionSymbol()
|
||||||
isLambda = true
|
isLambda = true
|
||||||
label = context.firLabels.pop() ?: context.calleeNamesForLambda.lastOrNull()?.let {
|
label = context.firLabels.pop() ?: context.calleeNamesForLambda.lastOrNull()?.let {
|
||||||
buildLabel { name = it.asString() }
|
buildLabel {
|
||||||
|
source = expressionSource.fakeElement(FirFakeSourceElementKind.GeneratedLambdaLabel)
|
||||||
|
name = it.asString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
target = FirFunctionTarget(labelName = label?.name, isLambda = true)
|
target = FirFunctionTarget(labelName = label?.name, isLambda = true)
|
||||||
context.firFunctionTargets += target
|
context.firFunctionTargets += target
|
||||||
@@ -332,7 +335,10 @@ class ExpressionsConverter(
|
|||||||
var firExpression: FirElement? = null
|
var firExpression: FirElement? = null
|
||||||
labeledExpression.forEachChildren {
|
labeledExpression.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
LABEL_QUALIFIER -> context.firLabels += buildLabel { name = it.toString().replace("@", "") }
|
LABEL_QUALIFIER -> context.firLabels += buildLabel {
|
||||||
|
source = labeledExpression.toFirLightSourceElement(tree)
|
||||||
|
name = it.toString().replace("@", "")
|
||||||
|
}
|
||||||
BLOCK -> firExpression = declarationsConverter.convertBlock(it)
|
BLOCK -> firExpression = declarationsConverter.convertBlock(it)
|
||||||
PROPERTY -> firExpression = declarationsConverter.convertPropertyDeclaration(it)
|
PROPERTY -> firExpression = declarationsConverter.convertPropertyDeclaration(it)
|
||||||
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
|
else -> if (it.isExpression()) firExpression = getAsFirExpression(it)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.symbols.impl
|
package org.jetbrains.kotlin.fir.symbols.impl
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirLabel
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.AccessorSymbol
|
import org.jetbrains.kotlin.fir.symbols.AccessorSymbol
|
||||||
@@ -63,7 +64,9 @@ sealed class FirFunctionWithoutNameSymbol<F : FirFunction>(
|
|||||||
stubName: Name
|
stubName: Name
|
||||||
) : FirFunctionSymbol<F>(CallableId(FqName("special"), stubName))
|
) : FirFunctionSymbol<F>(CallableId(FqName("special"), stubName))
|
||||||
|
|
||||||
class FirAnonymousFunctionSymbol : FirFunctionWithoutNameSymbol<FirAnonymousFunction>(Name.identifier("anonymous"))
|
class FirAnonymousFunctionSymbol : FirFunctionWithoutNameSymbol<FirAnonymousFunction>(Name.identifier("anonymous")) {
|
||||||
|
val label: FirLabel? get() = fir.label
|
||||||
|
}
|
||||||
|
|
||||||
class FirPropertyAccessorSymbol : FirFunctionWithoutNameSymbol<FirPropertyAccessor>(Name.identifier("accessor"))
|
class FirPropertyAccessorSymbol : FirFunctionWithoutNameSymbol<FirPropertyAccessor>(Name.identifier("accessor"))
|
||||||
|
|
||||||
|
|||||||
Vendored
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
fun bar() {
|
fun bar() {
|
||||||
suspend {
|
suspend {
|
||||||
return@suspend
|
<!RETURN_FOR_BUILT_IN_SUSPEND!>return@suspend<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend {
|
suspend {
|
||||||
run {
|
run {
|
||||||
return@suspend
|
<!RETURN_FOR_BUILT_IN_SUSPEND!>return@suspend<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ fun bar() {
|
|||||||
val x = suspend@{
|
val x = suspend@{
|
||||||
suspend {
|
suspend {
|
||||||
// Might be resolved to outer lambda, but doesn't make sense because suspend-lambdas here is noinline
|
// Might be resolved to outer lambda, but doesn't make sense because suspend-lambdas here is noinline
|
||||||
return@suspend
|
<!RETURN_FOR_BUILT_IN_SUSPEND!>return@suspend<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -3180,6 +3180,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.RETURN_FOR_BUILT_IN_SUSPEND) { firDiagnostic ->
|
||||||
|
ReturnForBuiltInSuspendImpl(
|
||||||
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirJvmErrors.CONFLICTING_JVM_DECLARATIONS) { firDiagnostic ->
|
add(FirJvmErrors.CONFLICTING_JVM_DECLARATIONS) { firDiagnostic ->
|
||||||
ConflictingJvmDeclarationsImpl(
|
ConflictingJvmDeclarationsImpl(
|
||||||
firDiagnostic as FirPsiDiagnostic,
|
firDiagnostic as FirPsiDiagnostic,
|
||||||
|
|||||||
+4
@@ -2223,6 +2223,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = ModifierFormForNonBuiltInSuspend::class
|
override val diagnosticClass get() = ModifierFormForNonBuiltInSuspend::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class ReturnForBuiltInSuspend : KtFirDiagnostic<KtReturnExpression>() {
|
||||||
|
override val diagnosticClass get() = ReturnForBuiltInSuspend::class
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ConflictingJvmDeclarations : KtFirDiagnostic<PsiElement>() {
|
abstract class ConflictingJvmDeclarations : KtFirDiagnostic<PsiElement>() {
|
||||||
override val diagnosticClass get() = ConflictingJvmDeclarations::class
|
override val diagnosticClass get() = ConflictingJvmDeclarations::class
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -3589,6 +3589,13 @@ internal class ModifierFormForNonBuiltInSuspendImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class ReturnForBuiltInSuspendImpl(
|
||||||
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.ReturnForBuiltInSuspend(), KtAbstractFirDiagnostic<KtReturnExpression> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ConflictingJvmDeclarationsImpl(
|
internal class ConflictingJvmDeclarationsImpl(
|
||||||
firDiagnostic: FirPsiDiagnostic,
|
firDiagnostic: FirPsiDiagnostic,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
|
|||||||
Reference in New Issue
Block a user