[FE 1.0] Cleanup code of ControlFlowProcessor

- Always pass not nullable language version settings
- Fix warnings and style
- Remove redundant pseudocode utils
This commit is contained in:
Dmitriy Novozhilov
2022-01-12 16:49:36 +03:00
committed by teamcity
parent 9f870b0549
commit 50f6825775
4 changed files with 51 additions and 47 deletions
@@ -33,16 +33,13 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithValu
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.MagicKind
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.contracts.description.canBeRevisited import org.jetbrains.kotlin.contracts.description.canBeRevisited
import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited import org.jetbrains.kotlin.contracts.description.isDefinitelyVisited
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.lexer.KtToken import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
@@ -71,7 +68,7 @@ typealias DeferredGenerator = (ControlFlowBuilder) -> Unit
class ControlFlowProcessor( class ControlFlowProcessor(
private val trace: BindingTrace, private val trace: BindingTrace,
private val languageVersionSettings: LanguageVersionSettings? private val languageVersionSettings: LanguageVersionSettings
) { ) {
private val builder: ControlFlowBuilder = ControlFlowInstructionsGenerator() private val builder: ControlFlowBuilder = ControlFlowInstructionsGenerator()
@@ -169,7 +166,7 @@ class ControlFlowProcessor(
} }
override fun visitKtElement(element: KtElement) { override fun visitKtElement(element: KtElement) {
throw UnsupportedOperationException("[ControlFlowProcessor] " + element.toString()) throw UnsupportedOperationException("[ControlFlowProcessor] $element")
} }
} }
@@ -310,7 +307,7 @@ class ControlFlowProcessor(
deparenthesizedBaseExpression !is KtLoopExpression && deparenthesizedBaseExpression !is KtLoopExpression &&
deparenthesizedBaseExpression !is KtNamedFunction deparenthesizedBaseExpression !is KtNamedFunction
) { ) {
trace.report(Errors.REDUNDANT_LABEL_WARNING.on(labelNameExpression)) trace.report(REDUNDANT_LABEL_WARNING.on(labelNameExpression))
} }
} }
} }
@@ -348,7 +345,7 @@ class ControlFlowProcessor(
generateInstructions(right) generateInstructions(right)
builder.bindLabel(afterElvis) builder.bindLabel(afterElvis)
mergeValues(listOfNotNull(left, right), expression) mergeValues(listOfNotNull(left, right), expression)
if (right != null && languageVersionSettings?.supportsFeature(LanguageFeature.ProhibitNonExhaustiveIfInRhsOfElvis) == true) { if (right != null && languageVersionSettings.supportsFeature(LanguageFeature.ProhibitNonExhaustiveIfInRhsOfElvis)) {
trace.record(USED_AS_EXPRESSION, right, true) trace.record(USED_AS_EXPRESSION, right, true)
} }
} else { } else {
@@ -373,12 +370,12 @@ class ControlFlowProcessor(
generateInstructions(right) generateInstructions(right)
builder.bindLabel(resultLabel) builder.bindLabel(resultLabel)
val operation = if (operationType === ANDAND) ControlFlowBuilder.PredefinedOperation.AND else OR val operation = if (operationType === ANDAND) ControlFlowBuilder.PredefinedOperation.AND else OR
builder.predefinedOperation(expression, operation, elementsToValues(listOf(left, right).filterNotNull())) builder.predefinedOperation(expression, operation, elementsToValues(listOfNotNull(left, right)))
} }
private fun getValueAsFunction(value: PseudoValue?) = { value } private fun getValueAsFunction(value: PseudoValue?): () -> PseudoValue? = { value }
private fun getDeferredValue(expression: KtExpression?) = { private fun getDeferredValue(expression: KtExpression?): () -> PseudoValue? = {
generateInstructions(expression) generateInstructions(expression)
getBoundOrUnreachableValue(expression) getBoundOrUnreachableValue(expression)
} }
@@ -413,7 +410,7 @@ class ControlFlowProcessor(
return return
} }
var receiverValues: Map<PseudoValue, ReceiverValue> = SmartFMap.emptyMap<PseudoValue, ReceiverValue>() var receiverValues: Map<PseudoValue, ReceiverValue> = SmartFMap.emptyMap()
var accessTarget: AccessTarget = AccessTarget.BlackBox var accessTarget: AccessTarget = AccessTarget.BlackBox
if (left is KtSimpleNameExpression || left is KtQualifiedExpression) { if (left is KtSimpleNameExpression || left is KtQualifiedExpression) {
accessTarget = getResolvedCallAccessTarget(left.getQualifiedElementSelector()) accessTarget = getResolvedCallAccessTarget(left.getQualifiedElementSelector())
@@ -444,7 +441,7 @@ class ControlFlowProcessor(
if (setResolvedCall == null) { if (setResolvedCall == null) {
generateArrayAccess(lhs, null) generateArrayAccess(lhs, null)
val arguments = listOf(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke()).filterNotNull() val arguments = listOfNotNull(getBoundOrUnreachableValue(lhs), rhsDeferredValue.invoke())
builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNRESOLVED_CALL) builder.magic(parentExpression, parentExpression, arguments, MagicKind.UNRESOLVED_CALL)
return return
@@ -474,7 +471,7 @@ class ControlFlowProcessor(
setResolvedCall: ResolvedCall<FunctionDescriptor> setResolvedCall: ResolvedCall<FunctionDescriptor>
): SmartFMap<PseudoValue, ValueParameterDescriptor> { ): SmartFMap<PseudoValue, ValueParameterDescriptor> {
val valueArguments = setResolvedCall.resultingDescriptor.valueParameters.flatMapTo( val valueArguments = setResolvedCall.resultingDescriptor.valueParameters.flatMapTo(
ArrayList<ValueArgument>() ArrayList()
) { descriptor -> setResolvedCall.valueArguments[descriptor]?.arguments ?: emptyList() } ) { descriptor -> setResolvedCall.valueArguments[descriptor]?.arguments ?: emptyList() }
val rhsArgument = valueArguments.lastOrNull() val rhsArgument = valueArguments.lastOrNull()
@@ -527,7 +524,7 @@ class ControlFlowProcessor(
val operationSign = expression.operationReference val operationSign = expression.operationReference
val operationType = operationSign.getReferencedNameElementType() val operationType = operationSign.getReferencedNameElementType()
val baseExpression = expression.baseExpression ?: return val baseExpression = expression.baseExpression ?: return
if (KtTokens.EXCLEXCL === operationType) { if (EXCLEXCL === operationType) {
generateInstructions(baseExpression) generateInstructions(baseExpression)
builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(listOf(baseExpression))) builder.predefinedOperation(expression, NOT_NULL_ASSERTION, elementsToValues(listOf(baseExpression)))
return return
@@ -552,7 +549,7 @@ class ControlFlowProcessor(
} }
private fun isIncrementOrDecrement(operationType: IElementType): Boolean = private fun isIncrementOrDecrement(operationType: IElementType): Boolean =
operationType === KtTokens.PLUSPLUS || operationType === KtTokens.MINUSMINUS operationType === PLUSPLUS || operationType === MINUSMINUS
override fun visitIfExpression(expression: KtIfExpression) { override fun visitIfExpression(expression: KtIfExpression) {
mark(expression) mark(expression)
@@ -656,7 +653,7 @@ class ControlFlowProcessor(
// Returns label for 'finally' block // Returns label for 'finally' block
private fun generateTryAndCatches(expression: KtTryExpression): Label? { private fun generateTryAndCatches(expression: KtTryExpression): Label? {
val catchClauses = expression.catchClauses val catchClauses = expression.catchClauses
val hasCatches = !catchClauses.isEmpty() val hasCatches = catchClauses.isNotEmpty()
var onException: Label? = null var onException: Label? = null
if (hasCatches) { if (hasCatches) {
@@ -684,7 +681,7 @@ class ControlFlowProcessor(
val catchLabels = LinkedList<Label>() val catchLabels = LinkedList<Label>()
val catchClausesSize = catchClauses.size val catchClausesSize = catchClauses.size
for (i in 0 until catchClausesSize - 1) { for (i in 0 until catchClausesSize - 1) {
catchLabels.add(builder.createUnboundLabel("catch " + i)) catchLabels.add(builder.createUnboundLabel("catch $i"))
} }
if (!catchLabels.isEmpty()) { if (!catchLabels.isEmpty()) {
builder.nondeterministicJump(catchLabels, expression) builder.nondeterministicJump(catchLabels, expression)
@@ -884,7 +881,7 @@ class ControlFlowProcessor(
if (loop == null) { if (loop == null) {
trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)) trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression))
} else { } else {
if (true != languageVersionSettings?.supportsFeature(LanguageFeature.AllowBreakAndContinueInsideWhen)) { if (!languageVersionSettings.supportsFeature(LanguageFeature.AllowBreakAndContinueInsideWhen)) {
val whenExpression = PsiTreeUtil.getParentOfType( val whenExpression = PsiTreeUtil.getParentOfType(
expression, KtWhenExpression::class.java, true, expression, KtWhenExpression::class.java, true,
KtLoopExpression::class.java KtLoopExpression::class.java
@@ -977,12 +974,11 @@ class ControlFlowProcessor(
} }
private fun checkReturnLabelTarget(returnExpression: KtReturnExpression, labeledElement: KtElement) { private fun checkReturnLabelTarget(returnExpression: KtReturnExpression, labeledElement: KtElement) {
if (languageVersionSettings == null) return
if (labeledElement !is KtFunctionLiteral && labeledElement !is KtNamedFunction) { if (labeledElement !is KtFunctionLiteral && labeledElement !is KtNamedFunction) {
if (languageVersionSettings.supportsFeature(LanguageFeature.RestrictReturnStatementTarget)) { if (languageVersionSettings.supportsFeature(LanguageFeature.RestrictReturnStatementTarget)) {
trace.report(Errors.NOT_A_FUNCTION_LABEL.on(returnExpression)) trace.report(NOT_A_FUNCTION_LABEL.on(returnExpression))
} else { } else {
trace.report(Errors.NOT_A_FUNCTION_LABEL_WARNING.on(returnExpression)) trace.report(NOT_A_FUNCTION_LABEL_WARNING.on(returnExpression))
} }
} }
} }
@@ -1056,24 +1052,24 @@ class ControlFlowProcessor(
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, eventOccurrencesRange: EventOccurrencesRange) { private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, eventOccurrencesRange: EventOccurrencesRange) {
// Defer emitting of inlined declaration // Defer emitting of inlined declaration
deferredGeneratorsStack.peek().add({ builder -> deferredGeneratorsStack.peek().add { builder ->
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration") val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
val afterDeclaration = builder.createUnboundLabel("after inlined declaration") val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
builder.bindLabel(beforeDeclaration) builder.bindLabel(beforeDeclaration)
if (!eventOccurrencesRange.isDefinitelyVisited()) { if (!eventOccurrencesRange.isDefinitelyVisited()) {
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null) builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
} }
generate(lambdaFunctionLiteral, eventOccurrencesRange) generate(lambdaFunctionLiteral, eventOccurrencesRange)
if (eventOccurrencesRange.canBeRevisited()) { if (eventOccurrencesRange.canBeRevisited()) {
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null) builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
} }
builder.bindLabel(afterDeclaration) builder.bindLabel(afterDeclaration)
}) }
} }
override fun visitNamedFunction(function: KtNamedFunction) { override fun visitNamedFunction(function: KtNamedFunction) {
@@ -1185,8 +1181,7 @@ class ControlFlowProcessor(
val resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) val resolvedCall = trace.get(BindingContext.COMPONENT_RESOLVED_CALL, entry)
val writtenValue: PseudoValue? val writtenValue = if (resolvedCall != null) {
writtenValue = if (resolvedCall != null) {
builder.call( builder.call(
entry, entry,
resolvedCall, resolvedCall,
@@ -1212,7 +1207,7 @@ class ControlFlowProcessor(
val operationType = expression.operationReference.getReferencedNameElementType() val operationType = expression.operationReference.getReferencedNameElementType()
val left = expression.left val left = expression.left
if (operationType === KtTokens.AS_KEYWORD || operationType === KtTokens.`AS_SAFE`) { if (operationType === AS_KEYWORD || operationType === `AS_SAFE`) {
generateInstructions(left) generateInstructions(left)
if (getBoundOrUnreachableValue(left) != null) { if (getBoundOrUnreachableValue(left) != null) {
createNonSyntheticValue(expression, MagicKind.CAST, left) createNonSyntheticValue(expression, MagicKind.CAST, left)
@@ -1325,7 +1320,7 @@ class ControlFlowProcessor(
WhenChecker.checkDuplicatedLabels( WhenChecker.checkDuplicatedLabels(
expression, expression,
trace, trace,
languageVersionSettings ?: LanguageVersionSettingsImpl.DEFAULT languageVersionSettings
) )
} }
@@ -1604,9 +1599,8 @@ class ControlFlowProcessor(
if (resolvedCall is VariableAsFunctionResolvedCall) { if (resolvedCall is VariableAsFunctionResolvedCall) {
varCallResult = generateCall(resolvedCall.variableCall).outputValue varCallResult = generateCall(resolvedCall.variableCall).outputValue
val kind = resolvedCall.explicitReceiverKind
//noinspection EnumSwitchStatementWhichMissesCases //noinspection EnumSwitchStatementWhichMissesCases
when (kind) { when (resolvedCall.explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver = ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver =
resolvedCall.extensionReceiver resolvedCall.extensionReceiver
@@ -1662,7 +1656,7 @@ class ControlFlowProcessor(
// Do nothing // Do nothing
} }
else -> { else -> {
throw IllegalArgumentException("Unknown receiver kind: " + receiver) throw IllegalArgumentException("Unknown receiver kind: $receiver")
} }
} }
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessTarget;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessValueInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.AccessValueInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl;
import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.psi.KtDeclaration; import org.jetbrains.kotlin.psi.KtDeclaration;
@@ -44,6 +46,11 @@ import static org.jetbrains.kotlin.resolve.BindingContextUtils.variableDescripto
public class PseudocodeUtil { public class PseudocodeUtil {
@NotNull @NotNull
public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull BindingContext bindingContext) { public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull BindingContext bindingContext) {
return generatePseudocode(declaration, bindingContext, LanguageVersionSettingsImpl.DEFAULT);
}
@NotNull
public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull BindingContext bindingContext, @NotNull LanguageVersionSettings languageVersionSettings) {
BindingTrace mockTrace = new BindingTrace() { BindingTrace mockTrace = new BindingTrace() {
@NotNull @NotNull
@Override @Override
@@ -89,7 +96,7 @@ public class PseudocodeUtil {
return false; return false;
} }
}; };
return new ControlFlowProcessor(mockTrace, null).generatePseudocode(declaration); return new ControlFlowProcessor(mockTrace, languageVersionSettings).generatePseudocode(declaration);
} }
@Nullable @Nullable
@@ -287,7 +287,7 @@ fun KtDeclaration.getContainingPseudocode(context: BindingContext): Pseudocode?
it.parents.firstOrNull { it is KtDeclaration && it !is KtFunctionLiteral } as? KtDeclaration it.parents.firstOrNull { it is KtDeclaration && it !is KtFunctionLiteral } as? KtDeclaration
} ?: this } ?: this
val enclosingPseudocode = PseudocodeUtil.generatePseudocode(enclosingPseudocodeDeclaration, context) val enclosingPseudocode = PseudocodeUtil.generatePseudocode(enclosingPseudocodeDeclaration, context, LanguageVersionSettingsImpl.DEFAULT)
return enclosingPseudocode.getPseudocodeByElement(this) return enclosingPseudocode.getPseudocodeByElement(this)
} }
@@ -34,6 +34,8 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.LocalFunctionDeclarationInstruction;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt; import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.config.CommonConfigurationKeys;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
@@ -66,14 +68,15 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironmentMa
AnalysisResult analysisResult = KotlinTestUtils.analyzeFile(ktFile, environment); AnalysisResult analysisResult = KotlinTestUtils.analyzeFile(ktFile, environment);
List<KtDeclaration> declarations = ktFile.getDeclarations(); List<KtDeclaration> declarations = ktFile.getDeclarations();
BindingContext bindingContext = analysisResult.getBindingContext(); BindingContext bindingContext = analysisResult.getBindingContext();
final LanguageVersionSettings languageVersionSettings = environment.getConfiguration().get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS);
for (KtDeclaration declaration : declarations) { for (KtDeclaration declaration : declarations) {
addDeclaration(data, bindingContext, declaration); addDeclaration(data, bindingContext, declaration, languageVersionSettings);
if (declaration instanceof KtDeclarationContainer) { if (declaration instanceof KtDeclarationContainer) {
for (KtDeclaration member : ((KtDeclarationContainer) declaration).getDeclarations()) { for (KtDeclaration member : ((KtDeclarationContainer) declaration).getDeclarations()) {
// Properties and initializers are processed elsewhere // Properties and initializers are processed elsewhere
if (member instanceof KtNamedFunction || member instanceof KtSecondaryConstructor) { if (member instanceof KtNamedFunction || member instanceof KtSecondaryConstructor) {
addDeclaration(data, bindingContext, member); addDeclaration(data, bindingContext, member, languageVersionSettings);
} }
} }
} }
@@ -92,8 +95,8 @@ public abstract class AbstractPseudocodeTest extends KotlinTestWithEnvironmentMa
} }
} }
private static void addDeclaration(SetMultimap<KtElement, Pseudocode> data, BindingContext bindingContext, KtDeclaration declaration) { private static void addDeclaration(SetMultimap<KtElement, Pseudocode> data, BindingContext bindingContext, KtDeclaration declaration, LanguageVersionSettings languageVersionSettings) {
Pseudocode pseudocode = PseudocodeUtil.generatePseudocode(declaration, bindingContext); Pseudocode pseudocode = PseudocodeUtil.generatePseudocode(declaration, bindingContext, languageVersionSettings);
data.put(declaration, pseudocode); data.put(declaration, pseudocode);
for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) { for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
Pseudocode localPseudocode = instruction.getBody(); Pseudocode localPseudocode = instruction.getBody();