added 'mergeDataWithLocalDeclarations' option
for collecting variable data for pseudocode removed using data from outer context for local declarations for 'variable initializers' analysis
This commit is contained in:
@@ -261,6 +261,7 @@ public class JetFlowInformationProvider {
|
||||
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
|
||||
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true);
|
||||
final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariablesData.getLexicalScopeVariableInfo();
|
||||
|
||||
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
|
||||
|
||||
@@ -272,7 +273,7 @@ public class JetFlowInformationProvider {
|
||||
@Nullable Map<VariableDescriptor, VariableInitState> in,
|
||||
@Nullable Map<VariableDescriptor, VariableInitState> out) {
|
||||
assert in != null && out != null;
|
||||
VariableInitContext ctxt = new VariableInitContext(instruction, reportedDiagnosticMap, in, out, declaredVariables);
|
||||
VariableInitContext ctxt = new VariableInitContext(instruction, reportedDiagnosticMap, in, out, lexicalScopeVariableInfo);
|
||||
if (ctxt.variableDescriptor == null) return;
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
||||
@@ -847,22 +848,22 @@ public class JetFlowInformationProvider {
|
||||
@NotNull Map<Instruction, DiagnosticFactory> map,
|
||||
@NotNull Map<VariableDescriptor, VariableInitState> in,
|
||||
@NotNull Map<VariableDescriptor, VariableInitState> out,
|
||||
@NotNull Set<VariableDescriptor> declaredVariables
|
||||
@NotNull LexicalScopeVariableInfo lexicalScopeVariableInfo
|
||||
) {
|
||||
super(instruction, map);
|
||||
enterInitState = initialize(variableDescriptor, declaredVariables, in);
|
||||
exitInitState = initialize(variableDescriptor, declaredVariables, out);
|
||||
enterInitState = initialize(variableDescriptor, lexicalScopeVariableInfo, in);
|
||||
exitInitState = initialize(variableDescriptor, lexicalScopeVariableInfo, out);
|
||||
}
|
||||
|
||||
private VariableInitState initialize(
|
||||
VariableDescriptor variableDescriptor,
|
||||
Set<VariableDescriptor> declaredVariables,
|
||||
LexicalScopeVariableInfo lexicalScopeVariableInfo,
|
||||
Map<VariableDescriptor, VariableInitState> map
|
||||
) {
|
||||
if (variableDescriptor == null) return null;
|
||||
VariableInitState state = map.get(variableDescriptor);
|
||||
if (state != null) return state;
|
||||
return PseudocodeVariablesData.getDefaultValueForInitializers(declaredVariables, variableDescriptor);
|
||||
return PseudocodeVariablesData.getDefaultValueForInitializers(variableDescriptor, instruction, lexicalScopeVariableInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,15 +44,6 @@ fun Instruction.getPreviousInstructions(traversalOrder: TraversalOrder): Collect
|
||||
fun Instruction.isStartInstruction(traversalOrder: TraversalOrder): Boolean =
|
||||
if (traversalOrder == FORWARD) this is SubroutineEnterInstruction else this is SubroutineSinkInstruction
|
||||
|
||||
enum class LookInsideStrategy {
|
||||
ANALYSE_LOCAL_DECLARATIONS
|
||||
SKIP_LOCAL_DECLARATIONS
|
||||
}
|
||||
|
||||
fun Instruction.shouldLookInside(lookInside: LookInsideStrategy): Boolean =
|
||||
lookInside == LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS && this is LocalFunctionDeclarationInstruction
|
||||
|
||||
|
||||
fun Pseudocode.traverse(
|
||||
traversalOrder: TraversalOrder,
|
||||
analyzeInstruction: (Instruction) -> Unit
|
||||
|
||||
+24
-18
@@ -29,6 +29,7 @@ import org.jetbrains.jet.utils.addToStdlib.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
import java.util.*
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
|
||||
public class PseudocodeVariableDataCollector(
|
||||
private val bindingContext: BindingContext,
|
||||
@@ -39,16 +40,19 @@ public class PseudocodeVariableDataCollector(
|
||||
suppress("UNCHECKED_CAST")
|
||||
public fun <D> collectDataJ(
|
||||
traversalOrder: TraversalOrder,
|
||||
mergeDataWithLocalDeclarations: Boolean,
|
||||
instructionDataMergeStrategy: InstructionDataMergeStrategy<MutableMap<VariableDescriptor, D>>
|
||||
): MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, D>>> {
|
||||
//see KT-4605
|
||||
return collectData(
|
||||
traversalOrder, instructionDataMergeStrategy as InstructionDataMergeStrategy<Map<VariableDescriptor, D>>
|
||||
traversalOrder, mergeDataWithLocalDeclarations,
|
||||
instructionDataMergeStrategy as InstructionDataMergeStrategy<Map<VariableDescriptor, D>>
|
||||
) as MutableMap<Instruction, Edges<MutableMap<VariableDescriptor, D>>>
|
||||
}
|
||||
|
||||
public fun <D> collectData(
|
||||
traversalOrder: TraversalOrder,
|
||||
mergeDataWithLocalDeclarations: Boolean,
|
||||
instructionDataMergeStrategy: InstructionDataMergeStrategy<Map<VariableDescriptor, D>>
|
||||
): Map<Instruction, Edges<Map<VariableDescriptor, D>>> {
|
||||
val initialDataValue : Map<VariableDescriptor, D> = Collections.emptyMap<VariableDescriptor, D>()
|
||||
@@ -61,7 +65,7 @@ public class PseudocodeVariableDataCollector(
|
||||
while (changed[0]) {
|
||||
changed[0] = false
|
||||
collectDataFromSubgraph(
|
||||
pseudocode, traversalOrder, LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS, edgesMap,
|
||||
pseudocode, traversalOrder, mergeDataWithLocalDeclarations, edgesMap,
|
||||
instructionDataMergeStrategy, Collections.emptyList<Instruction>(), changed, false)
|
||||
}
|
||||
return edgesMap
|
||||
@@ -76,8 +80,8 @@ public class PseudocodeVariableDataCollector(
|
||||
val initialEdge = Edges(initialDataValue, initialDataValue)
|
||||
for (instruction in instructions) {
|
||||
edgesMap.put(instruction, initialEdge)
|
||||
if (instruction.shouldLookInside(LookInsideStrategy.ANALYSE_LOCAL_DECLARATIONS)) {
|
||||
initializeEdgesMap((instruction as LocalFunctionDeclarationInstruction).getBody(), edgesMap, initialDataValue)
|
||||
if (instruction is LocalFunctionDeclarationInstruction) {
|
||||
initializeEdgesMap(instruction.getBody(), edgesMap, initialDataValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +89,7 @@ public class PseudocodeVariableDataCollector(
|
||||
private fun <D> collectDataFromSubgraph(
|
||||
pseudocode: Pseudocode,
|
||||
traversalOrder: TraversalOrder,
|
||||
lookInside: LookInsideStrategy,
|
||||
mergeDataWithLocalDeclarations: Boolean,
|
||||
edgesMap: MutableMap<Instruction, Edges<Map<VariableDescriptor, D>>>,
|
||||
instructionDataMergeStrategy: InstructionDataMergeStrategy<Map<VariableDescriptor, D>>,
|
||||
previousSubGraphInstructions: Collection<Instruction>,
|
||||
@@ -121,20 +125,22 @@ public class PseudocodeVariableDataCollector(
|
||||
}
|
||||
}
|
||||
|
||||
if (instruction.shouldLookInside(lookInside)) {
|
||||
val functionInstruction = (instruction as LocalFunctionDeclarationInstruction)
|
||||
val subroutinePseudocode = functionInstruction.getBody()
|
||||
if (instruction is LocalFunctionDeclarationInstruction) {
|
||||
val subroutinePseudocode = instruction.getBody()
|
||||
val previous = if (mergeDataWithLocalDeclarations) previousInstructions else Collections.emptyList()
|
||||
collectDataFromSubgraph(
|
||||
subroutinePseudocode, traversalOrder, lookInside, edgesMap, instructionDataMergeStrategy,
|
||||
previousInstructions, changed, true)
|
||||
val lastInstruction = subroutinePseudocode.getLastInstruction(traversalOrder)
|
||||
val previousValue = edgesMap.get(instruction)
|
||||
val newValue = edgesMap.get(lastInstruction)
|
||||
val updatedValue = if (newValue == null) null else
|
||||
Edges(filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.`in`),
|
||||
filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.out))
|
||||
updateEdgeDataForInstruction(previousValue, updatedValue)
|
||||
continue
|
||||
subroutinePseudocode, traversalOrder, mergeDataWithLocalDeclarations,
|
||||
edgesMap, instructionDataMergeStrategy, previous, changed, true)
|
||||
if (mergeDataWithLocalDeclarations) {
|
||||
val lastInstruction = subroutinePseudocode.getLastInstruction(traversalOrder)
|
||||
val previousValue = edgesMap.get(instruction)
|
||||
val newValue = edgesMap.get(lastInstruction)
|
||||
val updatedValue = if (newValue == null) null else
|
||||
Edges(filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.`in`),
|
||||
filterOutVariablesOutOfScope(lastInstruction, instruction, newValue.out))
|
||||
updateEdgeDataForInstruction(previousValue, updatedValue)
|
||||
continue
|
||||
}
|
||||
}
|
||||
val previousDataValue = edgesMap.get(instruction)
|
||||
|
||||
|
||||
@@ -62,6 +62,11 @@ public class PseudocodeVariablesData {
|
||||
return pseudocode;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LexicalScopeVariableInfo getLexicalScopeVariableInfo() {
|
||||
return pseudocodeVariableDataCollector.getLexicalScopeVariableInfo();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<VariableDescriptor> getUsedVariables(@NotNull Pseudocode pseudocode) {
|
||||
Set<VariableDescriptor> usedVariables = usedVariablesForDeclaration.get(pseudocode);
|
||||
@@ -139,10 +144,10 @@ public class PseudocodeVariablesData {
|
||||
@NotNull
|
||||
private Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> computeVariableInitializers() {
|
||||
|
||||
final Set<VariableDescriptor> declaredVariables = getDeclaredVariables(pseudocode, true);
|
||||
final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariableDataCollector.getLexicalScopeVariableInfo();
|
||||
|
||||
return pseudocodeVariableDataCollector.collectDataJ(
|
||||
FORWARD,
|
||||
FORWARD, /*mergeDataWithLocalDeclarations=*/ false,
|
||||
new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableInitState>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -153,8 +158,8 @@ public class PseudocodeVariablesData {
|
||||
|
||||
Map<VariableDescriptor, VariableInitState> enterInstructionData =
|
||||
mergeIncomingEdgesDataForInitializers(incomingEdgesData);
|
||||
Map<VariableDescriptor, VariableInitState> exitInstructionData =
|
||||
addVariableInitStateFromCurrentInstructionIfAny(instruction, enterInstructionData, declaredVariables);
|
||||
Map<VariableDescriptor, VariableInitState> exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
|
||||
instruction, enterInstructionData, lexicalScopeVariableInfo);
|
||||
return createEdges(enterInstructionData, exitInstructionData);
|
||||
}
|
||||
}
|
||||
@@ -162,12 +167,16 @@ public class PseudocodeVariablesData {
|
||||
}
|
||||
|
||||
public static VariableInitState getDefaultValueForInitializers(
|
||||
@NotNull Set<VariableDescriptor> declaredVariables,
|
||||
@NotNull VariableDescriptor variable
|
||||
@NotNull VariableDescriptor variable,
|
||||
@NotNull Instruction instruction,
|
||||
@NotNull LexicalScopeVariableInfo lexicalScopeVariableInfo
|
||||
) {
|
||||
//todo: think of replacing it with "MapWithDefaultValue"
|
||||
boolean isInitialized = !declaredVariables.contains(variable);
|
||||
return VariableInitState.create(isInitialized);
|
||||
LexicalScope declaredIn = lexicalScopeVariableInfo.getDeclaredIn().get(variable);
|
||||
boolean declaredOutsideThisDeclaration =
|
||||
declaredIn == null //declared outside this pseudocode
|
||||
|| declaredIn.getLexicalScopeForContainingDeclaration() != instruction.getLexicalScope().getLexicalScopeForContainingDeclaration();
|
||||
return VariableInitState.create(/*isInitialized=*/declaredOutsideThisDeclaration);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -203,7 +212,7 @@ public class PseudocodeVariablesData {
|
||||
private Map<VariableDescriptor, VariableInitState> addVariableInitStateFromCurrentInstructionIfAny(
|
||||
@NotNull Instruction instruction,
|
||||
@NotNull Map<VariableDescriptor, VariableInitState> enterInstructionData,
|
||||
@NotNull Set<VariableDescriptor> declaredVariables
|
||||
@NotNull LexicalScopeVariableInfo lexicalScopeVariableInfo
|
||||
) {
|
||||
if (!(instruction instanceof WriteValueInstruction) && !(instruction instanceof VariableDeclarationInstruction)) {
|
||||
return enterInstructionData;
|
||||
@@ -222,7 +231,7 @@ public class PseudocodeVariablesData {
|
||||
else { // instruction instanceof VariableDeclarationInstruction
|
||||
VariableInitState enterInitState = enterInstructionData.get(variable);
|
||||
if (enterInitState == null) {
|
||||
enterInitState = getDefaultValueForInitializers(declaredVariables, variable);
|
||||
enterInitState = getDefaultValueForInitializers(variable, instruction, lexicalScopeVariableInfo);
|
||||
}
|
||||
if (enterInitState == null || !enterInitState.isInitialized || !enterInitState.isDeclared) {
|
||||
boolean isInitialized = enterInitState != null && enterInitState.isInitialized;
|
||||
@@ -238,7 +247,7 @@ public class PseudocodeVariablesData {
|
||||
@NotNull
|
||||
public Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> getVariableUseStatusData() {
|
||||
return pseudocodeVariableDataCollector.collectDataJ(
|
||||
BACKWARD,
|
||||
BACKWARD, /*mergeDataWithLocalDeclarations=*/ true,
|
||||
new InstructionDataMergeStrategy<Map<VariableDescriptor, VariableUseState>>() {
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
@@ -17,9 +17,23 @@
|
||||
package org.jetbrains.jet.lang.cfg.pseudocode
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetElement
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
public class LexicalScope(val parentScope: LexicalScope?, val element: JetElement) {
|
||||
//todo remove after KT-4126
|
||||
private val _d = (parentScope?.depth ?: 0) + 1
|
||||
val depth: Int get() = _d
|
||||
|
||||
val lexicalScopeForContainingDeclaration: LexicalScope? by Delegates.lazy { computeLexicalScopeForContainingDeclaration() }
|
||||
private fun computeLexicalScopeForContainingDeclaration(): LexicalScope? {
|
||||
var scope: LexicalScope? = this
|
||||
while (scope != null) {
|
||||
if (scope?.element is JetDeclaration) {
|
||||
return scope
|
||||
}
|
||||
scope = scope?.parentScope
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,25 +34,25 @@ sink:
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
3 <START> INIT: in: {a=ID, f=D} out: {a=ID, f=D}
|
||||
v(x: Int) INIT: in: {a=ID, f=D} out: {a=ID, f=D, x=D}
|
||||
w(x) INIT: in: {a=ID, f=D, x=D} out: {a=ID, f=D, x=ID}
|
||||
4 mark(val y = x + a use(a)) INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID}
|
||||
v(val y = x + a) INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID, y=D}
|
||||
mark(x + a) INIT: in: {a=ID, f=D, x=ID, y=D} out: {a=ID, f=D, x=ID, y=D} USE: in: {a=READ, x=READ} out: {a=READ, x=READ}
|
||||
r(x) USE: in: {a=READ} out: {a=READ, x=READ}
|
||||
3 <START> INIT: in: {} out: {}
|
||||
v(x: Int) INIT: in: {} out: {x=D}
|
||||
w(x) INIT: in: {x=D} out: {x=ID}
|
||||
4 mark(val y = x + a use(a)) INIT: in: {x=ID} out: {x=ID}
|
||||
v(val y = x + a) INIT: in: {x=ID} out: {x=ID, y=D}
|
||||
mark(x + a) INIT: in: {x=ID, y=D} out: {x=ID, y=D} USE: in: {a=READ, x=READ} out: {a=READ, x=READ}
|
||||
r(x) USE: in: {a=READ} out: {a=READ, x=READ}
|
||||
r(a)
|
||||
call(+, plus)
|
||||
w(y) INIT: in: {a=ID, f=D, x=ID, y=D} out: {a=ID, f=D, x=ID, y=ID}
|
||||
mark(use(a)) INIT: in: {a=ID, f=D, x=ID, y=ID} out: {a=ID, f=D, x=ID, y=ID} USE: in: {a=READ} out: {a=READ}
|
||||
r(a) USE: in: {} out: {a=READ}
|
||||
w(y) INIT: in: {x=ID, y=D} out: {x=ID, y=ID}
|
||||
mark(use(a)) INIT: in: {x=ID, y=ID} out: {x=ID, y=ID} USE: in: {a=READ} out: {a=READ}
|
||||
r(a) USE: in: {} out: {a=READ}
|
||||
call(use, use)
|
||||
L4:
|
||||
3 <END> INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID}
|
||||
3 <END> INIT: in: {x=ID} out: {x=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID} USE: in: {} out: {}
|
||||
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
== use ==
|
||||
fun use(vararg a: Any?) = a
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
== TestFunctionLiteral ==
|
||||
class TestFunctionLiteral {
|
||||
val sum: (Int)->Int = { (x: Int) ->
|
||||
sum(x - 1) + x
|
||||
}
|
||||
}
|
||||
---------------------
|
||||
L0:
|
||||
1 <START> INIT: in: {} out: {}
|
||||
v(val sum: (Int)->Int = { (x: Int) -> sum(x - 1) + x }) INIT: in: {} out: {sum=D}
|
||||
mark({ (x: Int) -> sum(x - 1) + x }) INIT: in: {sum=D} out: {sum=D}
|
||||
jmp?(L2)
|
||||
d({ (x: Int) -> sum(x - 1) + x }) USE: in: {sum=READ} out: {sum=READ}
|
||||
L2:
|
||||
r({ (x: Int) -> sum(x - 1) + x })
|
||||
w(sum) INIT: in: {sum=D} out: {sum=ID}
|
||||
L1:
|
||||
<END> INIT: in: {sum=ID} out: {sum=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {sum=D} out: {sum=D} USE: in: {} out: {}
|
||||
=====================
|
||||
== anonymous_0 ==
|
||||
{ (x: Int) ->
|
||||
sum(x - 1) + x
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
2 <START> INIT: in: {} out: {}
|
||||
v(x: Int) INIT: in: {} out: {x=D}
|
||||
w(x) INIT: in: {x=D} out: {x=ID}
|
||||
3 mark(sum(x - 1) + x) INIT: in: {x=ID} out: {x=ID}
|
||||
mark(sum(x - 1) + x)
|
||||
mark(sum(x - 1)) USE: in: {sum=READ, x=READ} out: {sum=READ, x=READ}
|
||||
r(sum) USE: in: {x=READ} out: {sum=READ, x=READ}
|
||||
mark(x - 1)
|
||||
r(x)
|
||||
r(1)
|
||||
call(-, minus)
|
||||
call(sum, invoke) USE: in: {x=READ} out: {x=READ}
|
||||
r(x) USE: in: {} out: {x=READ}
|
||||
call(+, plus)
|
||||
L4:
|
||||
2 <END>
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
== A ==
|
||||
open class A(val a: A)
|
||||
---------------------
|
||||
L0:
|
||||
1 <START> INIT: in: {} out: {}
|
||||
v(val a: A) INIT: in: {} out: {a=D}
|
||||
w(a) INIT: in: {a=D} out: {a=ID}
|
||||
L1:
|
||||
<END> INIT: in: {a=ID} out: {a=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {a=ID} out: {a=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
== TestObjectLiteral ==
|
||||
class TestObjectLiteral {
|
||||
val obj: A = object: A(obj) {
|
||||
{
|
||||
val x = obj
|
||||
}
|
||||
fun foo() {
|
||||
val y = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
---------------------
|
||||
L0:
|
||||
1 <START> INIT: in: {} out: {}
|
||||
v(val obj: A = object: A(obj) { { val x = obj } fun foo() { val y = obj } }) INIT: in: {} out: {obj=D}
|
||||
mark(object: A(obj) { { val x = obj } fun foo() { val y = obj } }) INIT: in: {obj=D} out: {obj=D}
|
||||
r(obj)
|
||||
2 mark({ val x = obj })
|
||||
v(val x = obj) INIT: in: {obj=D} out: {obj=D, x=D}
|
||||
r(obj) INIT: in: {obj=D, x=D} out: {obj=D, x=D}
|
||||
w(x) INIT: in: {obj=D, x=D} out: {obj=D, x=ID}
|
||||
1 jmp?(L2) INIT: in: {obj=D} out: {obj=D}
|
||||
d(fun foo() { val y = obj }) USE: in: {obj=READ} out: {obj=READ}
|
||||
L2:
|
||||
r(object: A(obj) { { val x = obj } fun foo() { val y = obj } })
|
||||
w(obj) INIT: in: {obj=D} out: {obj=ID}
|
||||
L1:
|
||||
<END> INIT: in: {obj=ID} out: {obj=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {obj=D} out: {obj=D} USE: in: {} out: {}
|
||||
=====================
|
||||
== foo ==
|
||||
fun foo() {
|
||||
val y = obj
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
2 <START> INIT: in: {} out: {}
|
||||
3 mark({ val y = obj })
|
||||
v(val y = obj) INIT: in: {} out: {y=D} USE: in: {obj=READ} out: {obj=READ}
|
||||
r(obj) INIT: in: {y=D} out: {y=D} USE: in: {} out: {obj=READ}
|
||||
w(y) INIT: in: {y=D} out: {y=ID}
|
||||
L4:
|
||||
2 <END> INIT: in: {} out: {}
|
||||
error:
|
||||
<ERROR>
|
||||
sink:
|
||||
<SINK> USE: in: {} out: {}
|
||||
=====================
|
||||
== TestOther ==
|
||||
class TestOther {
|
||||
val x: Int = x + 1
|
||||
}
|
||||
---------------------
|
||||
L0:
|
||||
1 <START> INIT: in: {} out: {}
|
||||
v(val x: Int = x + 1) INIT: in: {} out: {x=D}
|
||||
mark(x + 1) INIT: in: {x=D} out: {x=D} USE: in: {x=READ} out: {x=READ}
|
||||
r(x) USE: in: {} out: {x=READ}
|
||||
r(1)
|
||||
call(+, plus)
|
||||
w(x) INIT: in: {x=D} out: {x=ID}
|
||||
L1:
|
||||
<END> INIT: in: {x=ID} out: {x=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
@@ -0,0 +1,22 @@
|
||||
class TestFunctionLiteral {
|
||||
val sum: (Int)->Int = { (x: Int) ->
|
||||
sum(x - 1) + x
|
||||
}
|
||||
}
|
||||
|
||||
open class A(val a: A)
|
||||
|
||||
class TestObjectLiteral {
|
||||
val obj: A = object: A(obj) {
|
||||
{
|
||||
val x = obj
|
||||
}
|
||||
fun foo() {
|
||||
val y = obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestOther {
|
||||
val x: Int = x + 1
|
||||
}
|
||||
@@ -38,20 +38,20 @@ sink:
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
3 <START> INIT: in: {b=ID, f=D} out: {b=ID, f=D}
|
||||
v(x: Int) INIT: in: {b=ID, f=D} out: {b=ID, f=D, x=D}
|
||||
w(x) INIT: in: {b=ID, f=D, x=D} out: {b=ID, f=D, x=ID}
|
||||
4 mark(val a = x + b) INIT: in: {b=ID, f=D, x=ID} out: {b=ID, f=D, x=ID}
|
||||
v(val a = x + b) INIT: in: {b=ID, f=D, x=ID} out: {a=D, b=ID, f=D, x=ID}
|
||||
mark(x + b) INIT: in: {a=D, b=ID, f=D, x=ID} out: {a=D, b=ID, f=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ}
|
||||
r(x) USE: in: {b=READ} out: {b=READ, x=READ}
|
||||
r(b) USE: in: {} out: {b=READ}
|
||||
3 <START> INIT: in: {} out: {}
|
||||
v(x: Int) INIT: in: {} out: {x=D}
|
||||
w(x) INIT: in: {x=D} out: {x=ID}
|
||||
4 mark(val a = x + b) INIT: in: {x=ID} out: {x=ID}
|
||||
v(val a = x + b) INIT: in: {x=ID} out: {a=D, x=ID}
|
||||
mark(x + b) INIT: in: {a=D, x=ID} out: {a=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ}
|
||||
r(x) USE: in: {b=READ} out: {b=READ, x=READ}
|
||||
r(b) USE: in: {} out: {b=READ}
|
||||
call(+, plus)
|
||||
w(a) INIT: in: {a=D, b=ID, f=D, x=ID} out: {a=ID, b=ID, f=D, x=ID}
|
||||
w(a) INIT: in: {a=D, x=ID} out: {a=ID, x=ID}
|
||||
L4:
|
||||
3 <END> INIT: in: {b=ID, f=D, x=ID} out: {b=ID, f=D, x=ID}
|
||||
3 <END> INIT: in: {x=ID} out: {x=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {b=ID, f=D, x=ID} out: {b=ID, f=D, x=ID} USE: in: {} out: {}
|
||||
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
|
||||
@@ -41,15 +41,15 @@ fun foo() {
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
3 <START> INIT: in: {x=ID} out: {x=ID}
|
||||
3 <START> INIT: in: {} out: {}
|
||||
4 mark({ val b = x })
|
||||
v(val b = x) INIT: in: {x=ID} out: {b=D, x=ID} USE: in: {x=READ} out: {x=READ}
|
||||
r(x) INIT: in: {b=D, x=ID} out: {b=D, x=ID} USE: in: {} out: {x=READ}
|
||||
w(b) INIT: in: {b=D, x=ID} out: {b=ID, x=ID}
|
||||
v(val b = x) INIT: in: {} out: {b=D} USE: in: {x=READ} out: {x=READ}
|
||||
r(x) INIT: in: {b=D} out: {b=D} USE: in: {} out: {x=READ}
|
||||
w(b) INIT: in: {b=D} out: {b=ID}
|
||||
L4:
|
||||
3 <END> INIT: in: {x=ID} out: {x=ID}
|
||||
3 <END> INIT: in: {} out: {}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
<ERROR>
|
||||
sink:
|
||||
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
|
||||
<SINK> USE: in: {} out: {}
|
||||
=====================
|
||||
|
||||
@@ -34,20 +34,20 @@ fun local(x: Int) {
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
3 <START> INIT: in: {b=ID} out: {b=ID}
|
||||
v(x: Int) INIT: in: {b=ID} out: {b=ID, x=D}
|
||||
w(x) INIT: in: {b=ID, x=D} out: {b=ID, x=ID}
|
||||
4 mark({ val a = x + b }) INIT: in: {b=ID, x=ID} out: {b=ID, x=ID}
|
||||
v(val a = x + b) INIT: in: {b=ID, x=ID} out: {a=D, b=ID, x=ID}
|
||||
mark(x + b) INIT: in: {a=D, b=ID, x=ID} out: {a=D, b=ID, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ}
|
||||
r(x) USE: in: {b=READ} out: {b=READ, x=READ}
|
||||
r(b) USE: in: {} out: {b=READ}
|
||||
3 <START> INIT: in: {} out: {}
|
||||
v(x: Int) INIT: in: {} out: {x=D}
|
||||
w(x) INIT: in: {x=D} out: {x=ID}
|
||||
4 mark({ val a = x + b }) INIT: in: {x=ID} out: {x=ID}
|
||||
v(val a = x + b) INIT: in: {x=ID} out: {a=D, x=ID}
|
||||
mark(x + b) INIT: in: {a=D, x=ID} out: {a=D, x=ID} USE: in: {b=READ, x=READ} out: {b=READ, x=READ}
|
||||
r(x) USE: in: {b=READ} out: {b=READ, x=READ}
|
||||
r(b) USE: in: {} out: {b=READ}
|
||||
call(+, plus)
|
||||
w(a) INIT: in: {a=D, b=ID, x=ID} out: {a=ID, b=ID, x=ID}
|
||||
w(a) INIT: in: {a=D, x=ID} out: {a=ID, x=ID}
|
||||
L4:
|
||||
3 <END> INIT: in: {b=ID, x=ID} out: {b=ID, x=ID}
|
||||
3 <END> INIT: in: {x=ID} out: {x=ID}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> INIT: in: {b=ID, x=ID} out: {b=ID, x=ID} USE: in: {} out: {}
|
||||
<SINK> INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
|
||||
@@ -43,15 +43,15 @@ fun foo() {
|
||||
}
|
||||
---------------------
|
||||
L3:
|
||||
3 <START> INIT: in: {bar=D} out: {bar=D}
|
||||
3 <START> INIT: in: {} out: {}
|
||||
4 mark({ val a = 2 })
|
||||
v(val a = 2) INIT: in: {bar=D} out: {a=D, bar=D}
|
||||
r(2) INIT: in: {a=D, bar=D} out: {a=D, bar=D}
|
||||
w(a) INIT: in: {a=D, bar=D} out: {a=ID, bar=D}
|
||||
v(val a = 2) INIT: in: {} out: {a=D}
|
||||
r(2) INIT: in: {a=D} out: {a=D}
|
||||
w(a) INIT: in: {a=D} out: {a=ID}
|
||||
L4:
|
||||
3 <END> INIT: in: {bar=D} out: {bar=D}
|
||||
3 <END> INIT: in: {} out: {}
|
||||
error:
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
<ERROR>
|
||||
sink:
|
||||
<SINK> INIT: in: {bar=D} out: {bar=D} USE: in: {} out: {}
|
||||
<SINK> USE: in: {} out: {}
|
||||
=====================
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
package o
|
||||
|
||||
class TestFunctionLiteral {
|
||||
val sum: (Int) -> Int = { (x: Int) ->
|
||||
sum(x - 1) + x
|
||||
}
|
||||
val foo: () -> Unit = @l ({ foo() })
|
||||
}
|
||||
|
||||
open class A(val a: A)
|
||||
|
||||
class TestObjectLiteral {
|
||||
val obj: A = object: A(<!UNINITIALIZED_VARIABLE!>obj<!>) {
|
||||
{
|
||||
val x = <!UNINITIALIZED_VARIABLE!>obj<!>
|
||||
}
|
||||
fun foo() {
|
||||
val y = obj
|
||||
}
|
||||
}
|
||||
val obj1: A = @l ( object: A(<!UNINITIALIZED_VARIABLE!>obj1<!>) {
|
||||
{
|
||||
val x = <!UNINITIALIZED_VARIABLE!>obj1<!>
|
||||
}
|
||||
fun foo() = obj1
|
||||
})
|
||||
}
|
||||
|
||||
class TestOther {
|
||||
val x: Int = <!UNINITIALIZED_VARIABLE!>x<!> + 1
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import org.jetbrains.jet.cfg.AbstractDataFlowTest;
|
||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("compiler/testData/cfg-variables")
|
||||
@InnerTestClasses({DataFlowTestGenerated.Basic.class, DataFlowTestGenerated.LexicalScopes.class})
|
||||
@InnerTestClasses({DataFlowTestGenerated.Basic.class, DataFlowTestGenerated.Bugs.class, DataFlowTestGenerated.LexicalScopes.class})
|
||||
public class DataFlowTestGenerated extends AbstractDataFlowTest {
|
||||
public void testAllFilesPresentInCfg_variables() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg-variables"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -58,16 +58,6 @@ public class DataFlowTestGenerated extends AbstractDataFlowTest {
|
||||
doTest("compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varInitializationInIf.kt")
|
||||
public void testVarInitializationInIf() throws Exception {
|
||||
doTest("compiler/testData/cfg-variables/basic/varInitializationInIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varInitializationInIfInCycle.kt")
|
||||
public void testVarInitializationInIfInCycle() throws Exception {
|
||||
doTest("compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("VariablesInitialization.kt")
|
||||
public void testVariablesInitialization() throws Exception {
|
||||
doTest("compiler/testData/cfg-variables/basic/VariablesInitialization.kt");
|
||||
@@ -80,6 +70,29 @@ public class DataFlowTestGenerated extends AbstractDataFlowTest {
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/cfg-variables/bugs")
|
||||
public static class Bugs extends AbstractDataFlowTest {
|
||||
public void testAllFilesPresentInBugs() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/cfg-variables/bugs"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("referenceToPropertyInitializer.kt")
|
||||
public void testReferenceToPropertyInitializer() throws Exception {
|
||||
doTest("compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varInitializationInIf.kt")
|
||||
public void testVarInitializationInIf() throws Exception {
|
||||
doTest("compiler/testData/cfg-variables/bugs/varInitializationInIf.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("varInitializationInIfInCycle.kt")
|
||||
public void testVarInitializationInIfInCycle() throws Exception {
|
||||
doTest("compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/cfg-variables/lexicalScopes")
|
||||
public static class LexicalScopes extends AbstractDataFlowTest {
|
||||
public void testAllFilesPresentInLexicalScopes() throws Exception {
|
||||
@@ -152,6 +165,7 @@ public class DataFlowTestGenerated extends AbstractDataFlowTest {
|
||||
TestSuite suite = new TestSuite("DataFlowTestGenerated");
|
||||
suite.addTestSuite(DataFlowTestGenerated.class);
|
||||
suite.addTestSuite(Basic.class);
|
||||
suite.addTestSuite(Bugs.class);
|
||||
suite.addTestSuite(LexicalScopes.class);
|
||||
return suite;
|
||||
}
|
||||
|
||||
@@ -1673,6 +1673,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/propertiesOrderInPackage.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("referenceToPropertyInitializer.kt")
|
||||
public void testReferenceToPropertyInitializer() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/referenceToPropertyInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("repeatUnitializedErrorOnlyForLocalVars.kt")
|
||||
public void testRepeatUnitializedErrorOnlyForLocalVars() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/repeatUnitializedErrorOnlyForLocalVars.kt");
|
||||
|
||||
Reference in New Issue
Block a user