check uninitialized vars inside local declarations

added parameter 'includeInsideLocalDeclarations' to getDeclaredVariables
This commit is contained in:
Svetlana Isakova
2012-12-10 18:46:48 +04:00
parent d45a4f9d27
commit 93327a3e31
4 changed files with 101 additions and 27 deletions
@@ -192,7 +192,7 @@ public class JetFlowInformationProvider {
final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode);
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true);
final Map<Instruction, AbstractDiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
@@ -412,7 +412,7 @@ public class JetFlowInformationProvider {
private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map<Instruction, Edges<Map<VariableDescriptor,PseudocodeVariablesData.VariableInitState>>> initializersMap) {
Edges<Map<VariableDescriptor, VariableInitState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
Set<VariableDescriptor> usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false);
for (VariableDescriptor variable : usedVariables) {
if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) {
PseudocodeVariablesData.VariableInitState variableInitState = initializers.in.get(variable);
@@ -437,7 +437,7 @@ public class JetFlowInformationProvider {
assert in != null && out != null;
VariableContext ctxt = new VariableUseContext(instruction, reportedDiagnosticMap, in, out);
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner());
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner(), false);
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false,
trace.getBindingContext());
if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) ||
@@ -25,7 +25,6 @@ import org.jetbrains.jet.lang.cfg.pseudocode.*;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetProperty;
import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -41,8 +40,8 @@ public class PseudocodeVariablesData {
private final Pseudocode pseudocode;
private final BindingContext bindingContext;
private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration = Maps.newHashMap();
private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesInEachDeclaration = Maps.newHashMap();
private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesForDeclaration = Maps.newHashMap();
private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesForDeclaration = Maps.newHashMap();
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> variableInitializersMap;
private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusMap;
@@ -59,7 +58,7 @@ public class PseudocodeVariablesData {
@NotNull
public Set<VariableDescriptor> getUsedVariables(@NotNull Pseudocode pseudocode) {
Set<VariableDescriptor> usedVariables = usedVariablesInEachDeclaration.get(pseudocode);
Set<VariableDescriptor> usedVariables = usedVariablesForDeclaration.get(pseudocode);
if (usedVariables == null) {
final Set<VariableDescriptor> result = Sets.newHashSet();
PseudocodeTraverser.traverseForward(pseudocode, new InstructionAnalyzeStrategy() {
@@ -73,33 +72,53 @@ public class PseudocodeVariablesData {
}
});
usedVariables = Collections.unmodifiableSet(result);
usedVariablesInEachDeclaration.put(pseudocode, usedVariables);
usedVariablesForDeclaration.put(pseudocode, usedVariables);
}
return usedVariables;
}
@NotNull
public Set<VariableDescriptor> getDeclaredVariables(@NotNull Pseudocode pseudocode) {
Set<VariableDescriptor> declaredVariables = declaredVariablesInEachDeclaration.get(pseudocode);
if (declaredVariables == null) {
declaredVariables = Sets.newHashSet();
for (Instruction instruction : pseudocode.getInstructions()) {
if (instruction instanceof VariableDeclarationInstruction) {
JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement);
if (descriptor != null) {
assert descriptor instanceof VariableDescriptor;
declaredVariables.add((VariableDescriptor) descriptor);
}
}
}
declaredVariables = Collections.unmodifiableSet(declaredVariables);
declaredVariablesInEachDeclaration.put(pseudocode, declaredVariables);
public Set<VariableDescriptor> getDeclaredVariables(@NotNull Pseudocode pseudocode, boolean includeInsideLocalDeclarations) {
if (!includeInsideLocalDeclarations) {
return getUpperLevelDeclaredVariables(pseudocode);
}
Set<VariableDescriptor> declaredVariables = Sets.newHashSet();
declaredVariables.addAll(getUpperLevelDeclaredVariables(pseudocode));
for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
Pseudocode localPseudocode = localDeclarationInstruction.getBody();
declaredVariables.addAll(getUpperLevelDeclaredVariables(localPseudocode));
}
return declaredVariables;
}
// variable initializers
@NotNull
private Set<VariableDescriptor> getUpperLevelDeclaredVariables(@NotNull Pseudocode pseudocode) {
Set<VariableDescriptor> declaredVariables = declaredVariablesForDeclaration.get(pseudocode);
if (declaredVariables == null) {
declaredVariables = computeDeclaredVariablesForPseudocode(pseudocode);
declaredVariablesForDeclaration.put(pseudocode, declaredVariables);
}
return declaredVariables;
}
@NotNull
private Set<VariableDescriptor> computeDeclaredVariablesForPseudocode(Pseudocode pseudocode) {
Set<VariableDescriptor> declaredVariables = Sets.newHashSet();
for (Instruction instruction : pseudocode.getInstructions()) {
if (instruction instanceof VariableDeclarationInstruction) {
JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement);
if (descriptor != null) {
assert descriptor instanceof VariableDescriptor;
declaredVariables.add((VariableDescriptor) descriptor);
}
}
}
return Collections.unmodifiableSet(declaredVariables);
}
// variable initializers
@NotNull
public Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> getVariableInitializers() {
@@ -113,7 +132,7 @@ public class PseudocodeVariablesData {
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> getVariableInitializers(@NotNull Pseudocode pseudocode) {
Set<VariableDescriptor> usedVariables = getUsedVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode);
Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode, false);
Map<VariableDescriptor, VariableInitState> initialMap = Collections.emptyMap();
final Map<VariableDescriptor, VariableInitState> initialMapForStartInstruction = prepareInitializersMapForStartInstruction(
usedVariables, declaredVariables);
@@ -226,7 +245,7 @@ public class PseudocodeVariablesData {
public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> getVariableUseStatusData() {
if (variableStatusMap == null) {
Map<VariableDescriptor, VariableUseState> sinkInstructionData = Maps.newHashMap();
for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) {
for (VariableDescriptor usedVariable : usedVariablesForDeclaration.get(pseudocode)) {
sinkInstructionData.put(usedVariable, VariableUseState.UNUSED);
}
InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>> collectVariableUseStatusStrategy = new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>>() {
@@ -0,0 +1,50 @@
fun test1() {
fun bar() {
var i : Int
doSmth(<!UNINITIALIZED_VARIABLE!>i<!>)
}
}
fun test2() {
fun foo() {
val s: String?
try {
s = ""
}
catch(e: Exception) {
doSmth(e)
}
doSmth(<!UNINITIALIZED_VARIABLE!>s<!>)
}
}
fun test3() {
val <!UNUSED_VARIABLE!>f<!> = {
val a : Int
doSmth(<!UNINITIALIZED_VARIABLE!>a<!>)
}
}
fun test4() {
doSmth {
val a : Int
doSmth(<!UNINITIALIZED_VARIABLE!>a<!>)
}
}
fun test5() {
fun inner1() {
fun inner2() {
fun inner3() {
fun inner4() {
val a : Int
doSmth(<!UNINITIALIZED_VARIABLE!>a<!>)
}
}
}
}
}
fun doSmth(a: Any?) = a
@@ -934,6 +934,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/kt897.kt");
}
@TestMetadata("uninitializedInLocalDeclarations.kt")
public void testUninitializedInLocalDeclarations() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures")