KT-22274 report error/warning on incorrect return target label

This commit is contained in:
Dmitry Petrov
2018-07-24 13:41:37 +03:00
parent 5241b37ad9
commit 6fb913a463
15 changed files with 222 additions and 14 deletions
@@ -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(
@@ -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");