CFG refactoring: extractVariableDescriptorFrom

(cherry picked from commit 95add79)
This commit is contained in:
Mikhail Glukhikh
2016-08-12 14:17:08 +03:00
committed by Mikhail Glukhikh
parent 25d8af3112
commit 902232c8ad
9 changed files with 47 additions and 37 deletions
@@ -541,7 +541,7 @@ class ControlFlowInformationProvider private constructor(
val ctxt = VariableUseContext(instruction, reportedDiagnosticMap) val ctxt = VariableUseContext(instruction, reportedDiagnosticMap)
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false) val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny( val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
instruction, false, trace.bindingContext) instruction, trace.bindingContext)
if (variableDescriptor == null if (variableDescriptor == null
|| !declaredVariables.contains(variableDescriptor) || !declaredVariables.contains(variableDescriptor)
|| !ExpressionTypingUtils.isLocal(variableDescriptor.containingDeclaration, variableDescriptor)) { || !ExpressionTypingUtils.isLocal(variableDescriptor.containingDeclaration, variableDescriptor)) {
@@ -884,7 +884,7 @@ class ControlFlowInformationProvider private constructor(
internal val instruction: Instruction, internal val instruction: Instruction,
internal val reportedDiagnosticMap: MutableMap<Instruction, DiagnosticFactory<*>> internal val reportedDiagnosticMap: MutableMap<Instruction, DiagnosticFactory<*>>
) { ) {
internal val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, trace.bindingContext) internal val variableDescriptor = PseudocodeUtil.extractVariableDescriptorFromReference(instruction, trace.bindingContext)
} }
private inner class VariableInitContext( private inner class VariableInitContext(
@@ -125,7 +125,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (instruction !is WriteValueInstruction && instruction !is VariableDeclarationInstruction) { if (instruction !is WriteValueInstruction && instruction !is VariableDeclarationInstruction) {
return enterInstructionData return enterInstructionData
} }
val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext) ?: return enterInstructionData val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext) ?: return enterInstructionData
val exitInstructionData = enterInstructionData.copy() val exitInstructionData = enterInstructionData.copy()
if (instruction is WriteValueInstruction) { if (instruction is WriteValueInstruction) {
// if writing to already initialized object // if writing to already initialized object
@@ -172,7 +172,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
} }
} }
} }
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, true, bindingContext) val variableDescriptor = PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) { if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
Edges(enterResult, enterResult) Edges(enterResult, enterResult)
} }
@@ -22,8 +22,6 @@ import org.jetbrains.kotlin.cfg.ControlFlowProcessor;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction; 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.eval.ReadValueInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.WriteValueInstruction;
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction;
import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Diagnostic;
@@ -31,7 +29,6 @@ import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtElement; import org.jetbrains.kotlin.psi.KtElement;
import org.jetbrains.kotlin.psi.KtExpression; import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilKt; import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilKt;
@@ -41,6 +38,8 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.Collection; import java.util.Collection;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.variableDescriptorForDeclaration;
public class PseudocodeUtil { public class PseudocodeUtil {
@NotNull @NotNull
public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull final BindingContext bindingContext) { public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull final BindingContext bindingContext) {
@@ -88,23 +87,37 @@ public class PseudocodeUtil {
} }
@Nullable @Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull Instruction instruction, boolean onlyReference, @NotNull BindingContext bindingContext) { public static VariableDescriptor extractVariableDescriptorFromReference(
KtElement element = null; @NotNull Instruction instruction,
if (instruction instanceof ReadValueInstruction) { @NotNull BindingContext bindingContext
ReadValueInstruction readValueInstruction = (ReadValueInstruction) instruction; ) {
AccessTarget target = readValueInstruction.getTarget(); if (instruction instanceof AccessValueInstruction) {
KtElement element = ((AccessValueInstruction) instruction).getElement();
return element instanceof KtDeclaration ? null : extractVariableDescriptorIfAny(instruction, bindingContext);
}
return null;
}
@Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(
@NotNull Instruction instruction,
@NotNull BindingContext bindingContext
) {
if (instruction instanceof VariableDeclarationInstruction) {
KtDeclaration declaration = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
return variableDescriptorForDeclaration(bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration));
}
else if (instruction instanceof AccessValueInstruction) {
AccessTarget target = ((AccessValueInstruction) instruction).getTarget();
if (target instanceof AccessTarget.Declaration) { if (target instanceof AccessTarget.Declaration) {
return ((AccessTarget.Declaration) target).getDescriptor(); return ((AccessTarget.Declaration) target).getDescriptor();
} }
element = readValueInstruction.getElement(); else if (target instanceof AccessTarget.Call) {
return variableDescriptorForDeclaration(((AccessTarget.Call) target).getResolvedCall().getResultingDescriptor());
}
} }
else if (instruction instanceof WriteValueInstruction) { return null;
element = ((WriteValueInstruction) instruction).getLValue();
}
else if (instruction instanceof VariableDeclarationInstruction) {
element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
}
return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference);
} }
// When deal with constructed object (not this) treat it like it's fully initialized // When deal with constructed object (not this) treat it like it's fully initialized
@@ -240,7 +240,7 @@ fun getExpectedTypePredicate(
fun Instruction.getPrimaryDeclarationDescriptorIfAny(bindingContext: BindingContext): DeclarationDescriptor? { fun Instruction.getPrimaryDeclarationDescriptorIfAny(bindingContext: BindingContext): DeclarationDescriptor? {
return when (this) { return when (this) {
is CallInstruction -> return resolvedCall.resultingDescriptor is CallInstruction -> return resolvedCall.resultingDescriptor
else -> PseudocodeUtil.extractVariableDescriptorIfAny(this, false, bindingContext) else -> PseudocodeUtil.extractVariableDescriptorIfAny(this, bindingContext)
} }
} }
@@ -68,20 +68,17 @@ public class BindingContextUtils {
} }
@Nullable @Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable KtElement element, boolean onlyReference) { public static VariableDescriptor extractVariableDescriptorFromReference(
DeclarationDescriptor descriptor = null; @NotNull BindingContext bindingContext,
if (!onlyReference && @Nullable KtElement element
(element instanceof KtVariableDeclaration || element instanceof KtParameter || ) {
element instanceof KtEnumEntry || element instanceof KtObjectDeclaration)) { if (element instanceof KtSimpleNameExpression) {
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); return variableDescriptorForDeclaration(bindingContext.get(BindingContext.REFERENCE_TARGET, (KtSimpleNameExpression) element));
}
else if (element instanceof KtSimpleNameExpression) {
descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (KtSimpleNameExpression) element);
} }
else if (element instanceof KtQualifiedExpression) { else if (element instanceof KtQualifiedExpression) {
descriptor = extractVariableDescriptorIfAny(bindingContext, ((KtQualifiedExpression) element).getSelectorExpression(), onlyReference); return extractVariableDescriptorFromReference(bindingContext, ((KtQualifiedExpression) element).getSelectorExpression());
} }
return variableDescriptorForDeclaration(descriptor); return null;
} }
public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace, public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
@@ -919,7 +919,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return info.getType() != null; return info.getType() != null;
} }
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true); VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorFromReference(trace.getBindingContext(), expression);
boolean result = true; boolean result = true;
KtExpression reportOn = expression != null ? expression : expressionWithParenthesis; KtExpression reportOn = expression != null ? expression : expressionWithParenthesis;
@@ -70,7 +70,7 @@ class KotlinSourcePositionProvider: SourcePositionProvider() {
val expression = codeFragment.getContentElement() val expression = codeFragment.getContentElement()
if (expression is KtSimpleNameExpression) { if (expression is KtSimpleNameExpression) {
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL) val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
val declarationDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, expression, false) val declarationDescriptor = BindingContextUtils.extractVariableDescriptorFromReference(bindingContext, expression)
val sourceElement = declarationDescriptor?.source val sourceElement = declarationDescriptor?.source
if (sourceElement is KotlinSourceElement) { if (sourceElement is KotlinSourceElement) {
val element = sourceElement.getPsi() ?: return null val element = sourceElement.getPsi() ?: return null
@@ -133,7 +133,7 @@ fun KtPostfixExpression.inlineBaseExpressionIfApplicableWithPrompt(editor: Edito
fun KtExpression.isStableVariable(): Boolean { fun KtExpression.isStableVariable(): Boolean {
val context = this.analyze() val context = this.analyze()
val descriptor = BindingContextUtils.extractVariableDescriptorIfAny(context, this, false) val descriptor = BindingContextUtils.extractVariableDescriptorFromReference(context, this)
return descriptor is VariableDescriptor && return descriptor is VariableDescriptor &&
DataFlowValueFactory.isStableValue(descriptor, DescriptorUtils.getContainingModule(descriptor)) DataFlowValueFactory.isStableValue(descriptor, DescriptorUtils.getContainingModule(descriptor))
} }
@@ -92,7 +92,7 @@ private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingC
val result = HashMap<VariableDescriptor, MutableList<KtExpression>>() val result = HashMap<VariableDescriptor, MutableList<KtExpression>>()
for (instruction in filterIsInstance<WriteValueInstruction>()) { for (instruction in filterIsInstance<WriteValueInstruction>()) {
val expression = instruction.element as? KtExpression val expression = instruction.element as? KtExpression
val descriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext) val descriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
if (expression != null && descriptor != null) { if (expression != null && descriptor != null) {
result.getOrPut(descriptor) { ArrayList() }.add(expression) result.getOrPut(descriptor) { ArrayList() }.add(expression)
} }
@@ -109,7 +109,7 @@ private fun List<Instruction>.getVarDescriptorsAccessedAfterwards(bindingContext
traverseFollowingInstructions(instruction, visitedInstructions) { traverseFollowingInstructions(instruction, visitedInstructions) {
when { when {
it is AccessValueInstruction && it !in this -> it is AccessValueInstruction && it !in this ->
PseudocodeUtil.extractVariableDescriptorIfAny(it, false, bindingContext)?.let { accessedAfterwards.add(it) } PseudocodeUtil.extractVariableDescriptorIfAny(it, bindingContext)?.let { accessedAfterwards.add(it) }
it is LocalFunctionDeclarationInstruction -> it is LocalFunctionDeclarationInstruction ->
doTraversal(it.body.enterInstruction) doTraversal(it.body.enterInstruction)