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 declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.owner, false)
val variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
instruction, false, trace.bindingContext)
instruction, trace.bindingContext)
if (variableDescriptor == null
|| !declaredVariables.contains(variableDescriptor)
|| !ExpressionTypingUtils.isLocal(variableDescriptor.containingDeclaration, variableDescriptor)) {
@@ -884,7 +884,7 @@ class ControlFlowInformationProvider private constructor(
internal val instruction: Instruction,
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(
@@ -125,7 +125,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (instruction !is WriteValueInstruction && instruction !is VariableDeclarationInstruction) {
return enterInstructionData
}
val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext) ?: return enterInstructionData
val variable = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext) ?: return enterInstructionData
val exitInstructionData = enterInstructionData.copy()
if (instruction is WriteValueInstruction) {
// 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) {
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.eval.AccessTarget;
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.descriptors.VariableDescriptor;
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.KtExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingContextUtils;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilKt;
@@ -41,6 +38,8 @@ import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.Collection;
import static org.jetbrains.kotlin.resolve.BindingContextUtils.variableDescriptorForDeclaration;
public class PseudocodeUtil {
@NotNull
public static Pseudocode generatePseudocode(@NotNull KtDeclaration declaration, @NotNull final BindingContext bindingContext) {
@@ -88,23 +87,37 @@ public class PseudocodeUtil {
}
@Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull Instruction instruction, boolean onlyReference, @NotNull BindingContext bindingContext) {
KtElement element = null;
if (instruction instanceof ReadValueInstruction) {
ReadValueInstruction readValueInstruction = (ReadValueInstruction) instruction;
AccessTarget target = readValueInstruction.getTarget();
public static VariableDescriptor extractVariableDescriptorFromReference(
@NotNull Instruction instruction,
@NotNull BindingContext bindingContext
) {
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) {
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) {
element = ((WriteValueInstruction) instruction).getLValue();
}
else if (instruction instanceof VariableDeclarationInstruction) {
element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
}
return BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, element, onlyReference);
return null;
}
// 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? {
return when (this) {
is CallInstruction -> return resolvedCall.resultingDescriptor
else -> PseudocodeUtil.extractVariableDescriptorIfAny(this, false, bindingContext)
else -> PseudocodeUtil.extractVariableDescriptorIfAny(this, bindingContext)
}
}
@@ -68,20 +68,17 @@ public class BindingContextUtils {
}
@Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable KtElement element, boolean onlyReference) {
DeclarationDescriptor descriptor = null;
if (!onlyReference &&
(element instanceof KtVariableDeclaration || element instanceof KtParameter ||
element instanceof KtEnumEntry || element instanceof KtObjectDeclaration)) {
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
}
else if (element instanceof KtSimpleNameExpression) {
descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (KtSimpleNameExpression) element);
public static VariableDescriptor extractVariableDescriptorFromReference(
@NotNull BindingContext bindingContext,
@Nullable KtElement element
) {
if (element instanceof KtSimpleNameExpression) {
return variableDescriptorForDeclaration(bindingContext.get(BindingContext.REFERENCE_TARGET, (KtSimpleNameExpression) element));
}
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,
@@ -919,7 +919,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return info.getType() != null;
}
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), expression, true);
VariableDescriptor variable = BindingContextUtils.extractVariableDescriptorFromReference(trace.getBindingContext(), expression);
boolean result = true;
KtExpression reportOn = expression != null ? expression : expressionWithParenthesis;
@@ -70,7 +70,7 @@ class KotlinSourcePositionProvider: SourcePositionProvider() {
val expression = codeFragment.getContentElement()
if (expression is KtSimpleNameExpression) {
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
val declarationDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(bindingContext, expression, false)
val declarationDescriptor = BindingContextUtils.extractVariableDescriptorFromReference(bindingContext, expression)
val sourceElement = declarationDescriptor?.source
if (sourceElement is KotlinSourceElement) {
val element = sourceElement.getPsi() ?: return null
@@ -133,7 +133,7 @@ fun KtPostfixExpression.inlineBaseExpressionIfApplicableWithPrompt(editor: Edito
fun KtExpression.isStableVariable(): Boolean {
val context = this.analyze()
val descriptor = BindingContextUtils.extractVariableDescriptorIfAny(context, this, false)
val descriptor = BindingContextUtils.extractVariableDescriptorFromReference(context, this)
return descriptor is VariableDescriptor &&
DataFlowValueFactory.isStableValue(descriptor, DescriptorUtils.getContainingModule(descriptor))
}
@@ -92,7 +92,7 @@ private fun List<Instruction>.getModifiedVarDescriptors(bindingContext: BindingC
val result = HashMap<VariableDescriptor, MutableList<KtExpression>>()
for (instruction in filterIsInstance<WriteValueInstruction>()) {
val expression = instruction.element as? KtExpression
val descriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, bindingContext)
val descriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
if (expression != null && descriptor != null) {
result.getOrPut(descriptor) { ArrayList() }.add(expression)
}
@@ -109,7 +109,7 @@ private fun List<Instruction>.getVarDescriptorsAccessedAfterwards(bindingContext
traverseFollowingInstructions(instruction, visitedInstructions) {
when {
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 ->
doTraversal(it.body.enterInstruction)