KT-22274 report error/warning on incorrect return target label
This commit is contained in:
@@ -70,7 +70,7 @@ class ControlFlowInformationProvider private constructor(
|
||||
) : this(
|
||||
declaration,
|
||||
trace,
|
||||
ControlFlowProcessor(trace).generatePseudocode(declaration),
|
||||
ControlFlowProcessor(trace, languageVersionSettings).generatePseudocode(declaration),
|
||||
languageVersionSettings,
|
||||
diagnosticSuppressor
|
||||
)
|
||||
|
||||
@@ -30,11 +30,14 @@ import org.jetbrains.kotlin.cfg.pseudocode.PseudocodeImpl
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValue
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.contracts.description.InvocationKind
|
||||
import org.jetbrains.kotlin.contracts.description.canBeRevisited
|
||||
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
@@ -63,7 +66,10 @@ import java.util.*
|
||||
|
||||
typealias DeferredGenerator = (ControlFlowBuilder) -> Unit
|
||||
|
||||
class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
class ControlFlowProcessor(
|
||||
private val trace: BindingTrace,
|
||||
private val languageVersionSettings: LanguageVersionSettings?
|
||||
) {
|
||||
|
||||
private val builder: ControlFlowBuilder = ControlFlowInstructionsGenerator()
|
||||
|
||||
@@ -927,12 +933,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
val subroutine: KtElement?
|
||||
val labelName = expression.getLabelName()
|
||||
subroutine = if (labelElement != null && labelName != null) {
|
||||
val labeledElement = trace.get(BindingContext.LABEL_TARGET, labelElement)
|
||||
if (labeledElement != null) {
|
||||
assert(labeledElement is KtElement)
|
||||
labeledElement as KtElement?
|
||||
} else {
|
||||
null
|
||||
trace.get(BindingContext.LABEL_TARGET, labelElement)?.let { labeledElement ->
|
||||
val labeledKtElement = labeledElement as KtElement
|
||||
checkReturnLabelTarget(expression, labeledKtElement)
|
||||
labeledKtElement
|
||||
}
|
||||
} else {
|
||||
builder.returnSubroutine
|
||||
@@ -951,6 +955,17 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReturnLabelTarget(returnExpression: KtReturnExpression, labeledElement: KtElement) {
|
||||
if (languageVersionSettings == null) return
|
||||
if (labeledElement !is KtFunctionLiteral && labeledElement !is KtNamedFunction) {
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.RestrictReturnStatementTarget)) {
|
||||
trace.report(Errors.NOT_A_FUNCTION_LABEL.on(returnExpression))
|
||||
} else {
|
||||
trace.report(Errors.NOT_A_FUNCTION_LABEL_WARNING.on(returnExpression))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitParameter(parameter: KtParameter) {
|
||||
builder.declareParameter(parameter)
|
||||
val defaultValue = parameter.defaultValue
|
||||
|
||||
@@ -89,7 +89,7 @@ public class PseudocodeUtil {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return new ControlFlowProcessor(mockTrace).generatePseudocode(declaration);
|
||||
return new ControlFlowProcessor(mockTrace, null).generatePseudocode(declaration);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -819,6 +819,9 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtExpressionWithLabel> BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<KtExpressionWithLabel, String> NOT_A_LOOP_LABEL = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory0<KtExpressionWithLabel> NOT_A_FUNCTION_LABEL = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtExpressionWithLabel> NOT_A_FUNCTION_LABEL_WARNING = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
// Control flow / Data flow
|
||||
|
||||
DiagnosticFactory1<KtElement, List<TextRange>> UNREACHABLE_CODE = DiagnosticFactory1.create(
|
||||
|
||||
+3
@@ -599,6 +599,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, "'break' or 'continue' jumps across a function or a class boundary");
|
||||
MAP.put(NOT_A_LOOP_LABEL, "The label ''{0}'' does not denote a loop", STRING);
|
||||
|
||||
MAP.put(NOT_A_FUNCTION_LABEL, "Target label does not denote a function");
|
||||
MAP.put(NOT_A_FUNCTION_LABEL_WARNING, "Target label does not denote a function");
|
||||
|
||||
MAP.put(ANONYMOUS_INITIALIZER_IN_INTERFACE, "Anonymous initializers are not allowed in interfaces");
|
||||
MAP.put(NULLABLE_SUPERTYPE, "A supertype cannot be nullable");
|
||||
MAP.put(DYNAMIC_SUPERTYPE, "A supertype cannot be dynamic");
|
||||
|
||||
Reference in New Issue
Block a user