Added dot qualifiers for variable analysis

This commit is contained in:
svtk
2011-11-04 15:57:59 +04:00
parent dfa3783f54
commit 33fad16fd5
3 changed files with 55 additions and 36 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
@@ -116,14 +117,13 @@ public class JetFlowInformationProvider {
for (Instruction deadInstruction : pseudocode.getDeadInstructions()) { for (Instruction deadInstruction : pseudocode.getDeadInstructions()) {
if (deadInstruction instanceof JetElementInstruction && if (deadInstruction instanceof JetElementInstruction &&
// TODO : do {return} while (1 > a)
!(deadInstruction instanceof ReadUnitValueInstruction)) { !(deadInstruction instanceof ReadUnitValueInstruction)) {
unreachableElements.add(((JetElementInstruction) deadInstruction).getElement()); unreachableElements.add(((JetElementInstruction) deadInstruction).getElement());
} }
} }
} }
public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean inAnonymousInitializers, final boolean declaredLocally) { public void markUninitializedVariables(@NotNull JetElement subroutine, final boolean inAnonymousInitializers, final boolean analyzeLocalDeclaration) {
final Pseudocode pseudocode = pseudocodeMap.get(subroutine); final Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null; assert pseudocode != null;
@@ -155,7 +155,7 @@ public class JetFlowInformationProvider {
Map<VariableDescriptor, InitializationPoints> exitInstructionPointsMap = Maps.newHashMap(enterInstructionPointsMap); Map<VariableDescriptor, InitializationPoints> exitInstructionPointsMap = Maps.newHashMap(enterInstructionPointsMap);
if (instruction instanceof WriteValueInstruction) { if (instruction instanceof WriteValueInstruction) {
VariableDescriptor variable = extractVariableDescriptorIfAny(instruction); VariableDescriptor variable = extractVariableDescriptorIfAny(instruction, false);
InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement()); InitializationPoints initializationAtThisPoint = new InitializationPoints(((WriteValueInstruction) instruction).getElement());
exitInstructionPointsMap.put(variable, initializationAtThisPoint); exitInstructionPointsMap.put(variable, initializationAtThisPoint);
} }
@@ -165,7 +165,7 @@ public class JetFlowInformationProvider {
}; };
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode); Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine); final Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables); Map<VariableDescriptor, InitializationPoints> initialMapForStartInstruction = prepareInitialMapForStartInstruction(usedVariables, declaredVariables);
traverser.collectInformationFromInstructionGraph(instructionsMergeStrategy, traverser.collectInformationFromInstructionGraph(instructionsMergeStrategy,
@@ -178,10 +178,9 @@ public class JetFlowInformationProvider {
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, InitializationPoints> enterData, @Nullable Map<VariableDescriptor, InitializationPoints> exitData) { public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, InitializationPoints> enterData, @Nullable Map<VariableDescriptor, InitializationPoints> exitData) {
assert enterData != null && exitData != null; assert enterData != null && exitData != null;
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
JetElement element = ((ReadValueInstruction) instruction).getElement(); JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression && variableDescriptor != null && if (element instanceof JetSimpleNameExpression && variableDescriptor != null && declaredVariables.contains(variableDescriptor)) {
(inAnonymousInitializers || variableDescriptor instanceof LocalVariableDescriptor)) {
InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor); InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor);
assert exitInitializationPoints != null; assert exitInitializationPoints != null;
@@ -192,15 +191,15 @@ public class JetFlowInformationProvider {
isInitialized = true; isInitialized = true;
} }
} }
if (!declaredLocally && !isInitialized) { if (!analyzeLocalDeclaration && !isInitialized) {
trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor)); trace.report(Errors.UNINITIALIZED_VARIABLE.on((JetSimpleNameExpression) element, variableDescriptor));
} }
} }
} }
else if (instruction instanceof WriteValueInstruction) { else if (instruction instanceof WriteValueInstruction) {
JetElement element = ((WriteValueInstruction) instruction).getlValue(); JetElement element = ((WriteValueInstruction) instruction).getlValue();
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
if (element instanceof JetSimpleNameExpression && variableDescriptor != null) { if (element instanceof JetExpression && variableDescriptor != null) {
InitializationPoints enterInitializationPoints = enterData.get(variableDescriptor); InitializationPoints enterInitializationPoints = enterData.get(variableDescriptor);
assert enterInitializationPoints != null; assert enterInitializationPoints != null;
InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor); InitializationPoints exitInitializationPoints = exitData.get(variableDescriptor);
@@ -213,16 +212,17 @@ public class JetFlowInformationProvider {
hasInitializer = false; hasInitializer = false;
} }
} }
JetSimpleNameExpression expression = (JetSimpleNameExpression) element; JetExpression expression = (JetExpression) element;
if (!declaredLocally && hasInitializer && !variableDescriptor.isVar()) { if (!analyzeLocalDeclaration && hasInitializer && !variableDescriptor.isVar()) {
PsiElement psiElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor); PsiElement psiElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
JetProperty property = psiElement instanceof JetProperty ? (JetProperty) psiElement : null; JetProperty property = psiElement instanceof JetProperty ? (JetProperty) psiElement : null;
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor, property == null ? new JetProperty[0] : new JetProperty[] { property })); trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor, property == null ? new JetProperty[0] : new JetProperty[] { property }));
} }
if (!declaredLocally && inAnonymousInitializers && variableDescriptor instanceof PropertyDescriptor && if (expression instanceof JetSimpleNameExpression && !analyzeLocalDeclaration && inAnonymousInitializers &&
!enterInitializationPoints.isInitialized() && exitInitializationPoints.isInitialized()) { variableDescriptor instanceof PropertyDescriptor && !enterInitializationPoints.isInitialized() && exitInitializationPoints.isInitialized()) {
if (expression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) { JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression;
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(expression, variableDescriptor)); if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) {
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(simpleNameExpression, variableDescriptor));
} }
} }
} }
@@ -271,7 +271,7 @@ public class JetFlowInformationProvider {
@Override @Override
public void execute(Instruction instruction, Void enterData, Void exitData) { public void execute(Instruction instruction, Void enterData, Void exitData) {
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
if (variableDescriptor != null && functionVariables.contains(variableDescriptor)) { if (variableDescriptor != null && functionVariables.contains(variableDescriptor)) {
//check that we only invoke this variable //check that we only invoke this variable
JetElement element = ((ReadValueInstruction) instruction).getElement(); JetElement element = ((ReadValueInstruction) instruction).getElement();
@@ -285,29 +285,15 @@ public class JetFlowInformationProvider {
} }
@Nullable @Nullable
private VariableDescriptor extractVariableDescriptorIfAny(Instruction instruction) { private VariableDescriptor extractVariableDescriptorIfAny(Instruction instruction, boolean onlyReference) {
VariableDescriptor variableDescriptor = null; VariableDescriptor variableDescriptor = null;
if (instruction instanceof ReadValueInstruction) { if (instruction instanceof ReadValueInstruction) {
JetElement element = ((ReadValueInstruction) instruction).getElement(); JetElement element = ((ReadValueInstruction) instruction).getElement();
if (element instanceof JetSimpleNameExpression) { variableDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), element, onlyReference);
DeclarationDescriptor descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
if (descriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) descriptor;
}
}
} }
else if (instruction instanceof WriteValueInstruction) { else if (instruction instanceof WriteValueInstruction) {
DeclarationDescriptor descriptor = null;
JetElement lValue = ((WriteValueInstruction) instruction).getlValue(); JetElement lValue = ((WriteValueInstruction) instruction).getlValue();
if (lValue instanceof JetProperty || lValue instanceof JetParameter) { variableDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), lValue, onlyReference);
descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, lValue);
}
else if (lValue instanceof JetSimpleNameExpression) {
descriptor = trace.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) lValue);
}
if (descriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) descriptor;
}
} }
return variableDescriptor; return variableDescriptor;
} }
@@ -317,7 +303,7 @@ public class JetFlowInformationProvider {
JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() { JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
@Override @Override
public void execute(Instruction instruction, Void enterData, Void exitData) { public void execute(Instruction instruction, Void enterData, Void exitData) {
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction); VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
if (variableDescriptor != null) { if (variableDescriptor != null) {
usedVariables.add(variableDescriptor); usedVariables.add(variableDescriptor);
} }
@@ -1,8 +1,10 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetReferenceExpression; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
/** /**
* @author abreslav * @author abreslav
@@ -19,4 +21,21 @@ public class BindingContextUtils {
return bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor); return bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
} }
@Nullable
public static VariableDescriptor extractVariableDescriptorIfAny(BindingContext bindingContext, JetElement element, boolean onlyReference) {
DeclarationDescriptor descriptor = null;
if (!onlyReference && (element instanceof JetProperty || element instanceof JetParameter)) {
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
}
else if (element instanceof JetSimpleNameExpression) {
descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, (JetSimpleNameExpression) element);
}
else if (element instanceof JetQualifiedExpression) {
descriptor = extractVariableDescriptorIfAny(bindingContext, ((JetQualifiedExpression) element).getSelectorExpression(), onlyReference);
}
if (descriptor instanceof VariableDescriptor) {
return (VariableDescriptor) descriptor;
}
return null;
}
} }
@@ -305,4 +305,18 @@ fun foo() {
<!UNRESOLVED_REFERENCE!>$b<!> = 3 <!UNRESOLVED_REFERENCE!>$b<!> = 3
} }
} }
}
// ------------------------------------------------
// dot qualifiers
class M() {
val x = 11
var y = 12
}
fun test(m : M) {
<!VAL_REASSIGNMENT!>m.x<!> = 23
m.y = 23
<!VAL_REASSIGNMENT!>m.x<!>++
m.y--
} }