From 93327a3e319710fe24ec31333c003d2e83cda971 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Mon, 10 Dec 2012 18:46:48 +0400 Subject: [PATCH] check uninitialized vars inside local declarations added parameter 'includeInsideLocalDeclarations' to getDeclaredVariables --- .../lang/cfg/JetFlowInformationProvider.java | 6 +- .../jet/lang/cfg/PseudocodeVariablesData.java | 67 ++++++++++++------- .../uninitializedInLocalDeclarations.kt | 50 ++++++++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++ 4 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 407c46b9d53..594e166fb65 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -192,7 +192,7 @@ public class JetFlowInformationProvider { final boolean processClassOrObject = subroutine instanceof JetClassOrObject; Map>> initializers = pseudocodeVariablesData.getVariableInitializers(); - final Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode); + final Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true); final Map reportedDiagnosticMap = Maps.newHashMap(); @@ -412,7 +412,7 @@ public class JetFlowInformationProvider { private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map>> initializersMap) { Edges> initializers = initializersMap.get(pseudocode.getExitInstruction()); Set usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode); - Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode); + Set 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 declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner()); + Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner(), false); VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false, trace.getBindingContext()); if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) || diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java index 0d01da4e0e4..fea60d5e361 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java @@ -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> declaredVariablesInEachDeclaration = Maps.newHashMap(); - private final Map> usedVariablesInEachDeclaration = Maps.newHashMap(); + private final Map> declaredVariablesForDeclaration = Maps.newHashMap(); + private final Map> usedVariablesForDeclaration = Maps.newHashMap(); private Map>> variableInitializersMap; private Map>> variableStatusMap; @@ -59,7 +58,7 @@ public class PseudocodeVariablesData { @NotNull public Set getUsedVariables(@NotNull Pseudocode pseudocode) { - Set usedVariables = usedVariablesInEachDeclaration.get(pseudocode); + Set usedVariables = usedVariablesForDeclaration.get(pseudocode); if (usedVariables == null) { final Set 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 getDeclaredVariables(@NotNull Pseudocode pseudocode) { - Set 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 getDeclaredVariables(@NotNull Pseudocode pseudocode, boolean includeInsideLocalDeclarations) { + if (!includeInsideLocalDeclarations) { + return getUpperLevelDeclaredVariables(pseudocode); + } + Set 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 getUpperLevelDeclaredVariables(@NotNull Pseudocode pseudocode) { + Set declaredVariables = declaredVariablesForDeclaration.get(pseudocode); + if (declaredVariables == null) { + declaredVariables = computeDeclaredVariablesForPseudocode(pseudocode); + declaredVariablesForDeclaration.put(pseudocode, declaredVariables); + } + return declaredVariables; + } + + @NotNull + private Set computeDeclaredVariablesForPseudocode(Pseudocode pseudocode) { + Set 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>> getVariableInitializers() { @@ -113,7 +132,7 @@ public class PseudocodeVariablesData { private Map>> getVariableInitializers(@NotNull Pseudocode pseudocode) { Set usedVariables = getUsedVariables(pseudocode); - Set declaredVariables = getDeclaredVariables(pseudocode); + Set declaredVariables = getDeclaredVariables(pseudocode, false); Map initialMap = Collections.emptyMap(); final Map initialMapForStartInstruction = prepareInitializersMapForStartInstruction( usedVariables, declaredVariables); @@ -226,7 +245,7 @@ public class PseudocodeVariablesData { public Map>> getVariableUseStatusData() { if (variableStatusMap == null) { Map sinkInstructionData = Maps.newHashMap(); - for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) { + for (VariableDescriptor usedVariable : usedVariablesForDeclaration.get(pseudocode)) { sinkInstructionData.put(usedVariable, VariableUseState.UNUSED); } InstructionDataMergeStrategy> collectVariableUseStatusStrategy = new InstructionDataMergeStrategy>() { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt new file mode 100644 index 00000000000..e86fb04f8c6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/uninitializedInLocalDeclarations.kt @@ -0,0 +1,50 @@ +fun test1() { + fun bar() { + var i : Int + doSmth(i) + } +} + +fun test2() { + fun foo() { + val s: String? + + try { + s = "" + } + catch(e: Exception) { + doSmth(e) + } + + doSmth(s) + } +} + +fun test3() { + val f = { + val a : Int + doSmth(a) + } +} + +fun test4() { + doSmth { + val a : Int + doSmth(a) + } +} + +fun test5() { + fun inner1() { + fun inner2() { + fun inner3() { + fun inner4() { + val a : Int + doSmth(a) + } + } + } + } +} + +fun doSmth(a: Any?) = a \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index bb7c94980fa..4773e798765 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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")