check uninitialized vars inside local declarations
added parameter 'includeInsideLocalDeclarations' to getDeclaredVariables
This commit is contained in:
@@ -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>>() {
|
||||
|
||||
+50
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user