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;
|
final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
|
||||||
|
|
||||||
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
|
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();
|
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) {
|
private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map<Instruction, Edges<Map<VariableDescriptor,PseudocodeVariablesData.VariableInitState>>> initializersMap) {
|
||||||
Edges<Map<VariableDescriptor, VariableInitState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
|
Edges<Map<VariableDescriptor, VariableInitState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
|
||||||
Set<VariableDescriptor> usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode);
|
Set<VariableDescriptor> usedVariables = pseudocodeVariablesData.getUsedVariables(pseudocode);
|
||||||
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode);
|
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false);
|
||||||
for (VariableDescriptor variable : usedVariables) {
|
for (VariableDescriptor variable : usedVariables) {
|
||||||
if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) {
|
if (variable instanceof PropertyDescriptor && declaredVariables.contains(variable)) {
|
||||||
PseudocodeVariablesData.VariableInitState variableInitState = initializers.in.get(variable);
|
PseudocodeVariablesData.VariableInitState variableInitState = initializers.in.get(variable);
|
||||||
@@ -437,7 +437,7 @@ public class JetFlowInformationProvider {
|
|||||||
|
|
||||||
assert in != null && out != null;
|
assert in != null && out != null;
|
||||||
VariableContext ctxt = new VariableUseContext(instruction, reportedDiagnosticMap, in, out);
|
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,
|
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false,
|
||||||
trace.getBindingContext());
|
trace.getBindingContext());
|
||||||
if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) ||
|
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.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
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.psi.JetProperty;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
|
||||||
@@ -41,8 +40,8 @@ public class PseudocodeVariablesData {
|
|||||||
private final Pseudocode pseudocode;
|
private final Pseudocode pseudocode;
|
||||||
private final BindingContext bindingContext;
|
private final BindingContext bindingContext;
|
||||||
|
|
||||||
private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesInEachDeclaration = Maps.newHashMap();
|
private final Map<Pseudocode, Set<VariableDescriptor>> declaredVariablesForDeclaration = Maps.newHashMap();
|
||||||
private final Map<Pseudocode, Set<VariableDescriptor>> usedVariablesInEachDeclaration = 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, VariableInitState>>> variableInitializersMap;
|
||||||
private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusMap;
|
private Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusMap;
|
||||||
@@ -59,7 +58,7 @@ public class PseudocodeVariablesData {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Set<VariableDescriptor> getUsedVariables(@NotNull Pseudocode pseudocode) {
|
public Set<VariableDescriptor> getUsedVariables(@NotNull Pseudocode pseudocode) {
|
||||||
Set<VariableDescriptor> usedVariables = usedVariablesInEachDeclaration.get(pseudocode);
|
Set<VariableDescriptor> usedVariables = usedVariablesForDeclaration.get(pseudocode);
|
||||||
if (usedVariables == null) {
|
if (usedVariables == null) {
|
||||||
final Set<VariableDescriptor> result = Sets.newHashSet();
|
final Set<VariableDescriptor> result = Sets.newHashSet();
|
||||||
PseudocodeTraverser.traverseForward(pseudocode, new InstructionAnalyzeStrategy() {
|
PseudocodeTraverser.traverseForward(pseudocode, new InstructionAnalyzeStrategy() {
|
||||||
@@ -73,33 +72,53 @@ public class PseudocodeVariablesData {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
usedVariables = Collections.unmodifiableSet(result);
|
usedVariables = Collections.unmodifiableSet(result);
|
||||||
usedVariablesInEachDeclaration.put(pseudocode, usedVariables);
|
usedVariablesForDeclaration.put(pseudocode, usedVariables);
|
||||||
}
|
}
|
||||||
return usedVariables;
|
return usedVariables;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Set<VariableDescriptor> getDeclaredVariables(@NotNull Pseudocode pseudocode) {
|
public Set<VariableDescriptor> getDeclaredVariables(@NotNull Pseudocode pseudocode, boolean includeInsideLocalDeclarations) {
|
||||||
Set<VariableDescriptor> declaredVariables = declaredVariablesInEachDeclaration.get(pseudocode);
|
if (!includeInsideLocalDeclarations) {
|
||||||
if (declaredVariables == null) {
|
return getUpperLevelDeclaredVariables(pseudocode);
|
||||||
declaredVariables = Sets.newHashSet();
|
}
|
||||||
for (Instruction instruction : pseudocode.getInstructions()) {
|
Set<VariableDescriptor> declaredVariables = Sets.newHashSet();
|
||||||
if (instruction instanceof VariableDeclarationInstruction) {
|
declaredVariables.addAll(getUpperLevelDeclaredVariables(pseudocode));
|
||||||
JetDeclaration variableDeclarationElement = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
|
||||||
DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement);
|
for (LocalDeclarationInstruction localDeclarationInstruction : pseudocode.getLocalDeclarations()) {
|
||||||
if (descriptor != null) {
|
Pseudocode localPseudocode = localDeclarationInstruction.getBody();
|
||||||
assert descriptor instanceof VariableDescriptor;
|
declaredVariables.addAll(getUpperLevelDeclaredVariables(localPseudocode));
|
||||||
declaredVariables.add((VariableDescriptor) descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
declaredVariables = Collections.unmodifiableSet(declaredVariables);
|
|
||||||
declaredVariablesInEachDeclaration.put(pseudocode, declaredVariables);
|
|
||||||
}
|
}
|
||||||
return declaredVariables;
|
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
|
@NotNull
|
||||||
public Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> getVariableInitializers() {
|
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) {
|
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> getVariableInitializers(@NotNull Pseudocode pseudocode) {
|
||||||
|
|
||||||
Set<VariableDescriptor> usedVariables = getUsedVariables(pseudocode);
|
Set<VariableDescriptor> usedVariables = getUsedVariables(pseudocode);
|
||||||
Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode);
|
Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode, false);
|
||||||
Map<VariableDescriptor, VariableInitState> initialMap = Collections.emptyMap();
|
Map<VariableDescriptor, VariableInitState> initialMap = Collections.emptyMap();
|
||||||
final Map<VariableDescriptor, VariableInitState> initialMapForStartInstruction = prepareInitializersMapForStartInstruction(
|
final Map<VariableDescriptor, VariableInitState> initialMapForStartInstruction = prepareInitializersMapForStartInstruction(
|
||||||
usedVariables, declaredVariables);
|
usedVariables, declaredVariables);
|
||||||
@@ -226,7 +245,7 @@ public class PseudocodeVariablesData {
|
|||||||
public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> getVariableUseStatusData() {
|
public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> getVariableUseStatusData() {
|
||||||
if (variableStatusMap == null) {
|
if (variableStatusMap == null) {
|
||||||
Map<VariableDescriptor, VariableUseState> sinkInstructionData = Maps.newHashMap();
|
Map<VariableDescriptor, VariableUseState> sinkInstructionData = Maps.newHashMap();
|
||||||
for (VariableDescriptor usedVariable : usedVariablesInEachDeclaration.get(pseudocode)) {
|
for (VariableDescriptor usedVariable : usedVariablesForDeclaration.get(pseudocode)) {
|
||||||
sinkInstructionData.put(usedVariable, VariableUseState.UNUSED);
|
sinkInstructionData.put(usedVariable, VariableUseState.UNUSED);
|
||||||
}
|
}
|
||||||
InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>> collectVariableUseStatusStrategy = new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>>() {
|
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");
|
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")
|
@TestMetadata("compiler/testData/diagnostics/tests/controlStructures")
|
||||||
|
|||||||
Reference in New Issue
Block a user