From fbbfb958614883ca545261ab325bd52dc3624b30 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 5 Mar 2014 19:42:05 +0400 Subject: [PATCH] added 'mergeDataWithLocalDeclarations' option for collecting variable data for pseudocode removed using data from outer context for local declarations for 'variable initializers' analysis --- .../lang/cfg/JetFlowInformationProvider.java | 13 +- .../jet/lang/cfg/PseudocodeTraverser.kt | 9 -- .../cfg/PseudocodeVariableDataCollector.kt | 42 +++--- .../jet/lang/cfg/PseudocodeVariablesData.java | 31 ++-- .../jet/lang/cfg/pseudocode/LexicalScope.kt | 14 ++ .../basic/UsageInFunctionLiteral.instructions | 24 ++-- ...eferenceToPropertyInitializer.instructions | 135 ++++++++++++++++++ .../bugs/referenceToPropertyInitializer.kt | 22 +++ .../varInitializationInIf.instructions | 0 .../{basic => bugs}/varInitializationInIf.kt | 0 .../varInitializationInIfInCycle.instructions | 0 .../varInitializationInIfInCycle.kt | 0 .../functionLiteralScope.instructions | 22 +-- .../lexicalScopes/localClass.instructions | 14 +- .../localFunctionScope.instructions | 22 +-- .../objectLiteralScope.instructions | 14 +- .../referenceToPropertyInitializer.kt | 32 +++++ .../jet/cfg/DataFlowTestGenerated.java | 36 +++-- .../checkers/JetDiagnosticsTestGenerated.java | 5 + 19 files changed, 332 insertions(+), 103 deletions(-) create mode 100644 compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions create mode 100644 compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt rename compiler/testData/cfg-variables/{basic => bugs}/varInitializationInIf.instructions (100%) rename compiler/testData/cfg-variables/{basic => bugs}/varInitializationInIf.kt (100%) rename compiler/testData/cfg-variables/{basic => bugs}/varInitializationInIfInCycle.instructions (100%) rename compiler/testData/cfg-variables/{basic => bugs}/varInitializationInIfInCycle.kt (100%) create mode 100644 compiler/testData/diagnostics/tests/controlFlowAnalysis/referenceToPropertyInitializer.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 73393e1f740..9f74daec6c0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -261,6 +261,7 @@ public class JetFlowInformationProvider { PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData(); Map>> initializers = pseudocodeVariablesData.getVariableInitializers(); final Set declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true); + final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariablesData.getLexicalScopeVariableInfo(); final Map reportedDiagnosticMap = Maps.newHashMap(); @@ -272,7 +273,7 @@ public class JetFlowInformationProvider { @Nullable Map in, @Nullable Map 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 map, @NotNull Map in, @NotNull Map out, - @NotNull Set 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 declaredVariables, + LexicalScopeVariableInfo lexicalScopeVariableInfo, Map 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); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt index 24057bef9cf..5be1b079e04 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeTraverser.kt @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt index e27c00fd774..dcaa7e7f8f1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariableDataCollector.kt @@ -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 collectDataJ( traversalOrder: TraversalOrder, + mergeDataWithLocalDeclarations: Boolean, instructionDataMergeStrategy: InstructionDataMergeStrategy> ): MutableMap>> { //see KT-4605 return collectData( - traversalOrder, instructionDataMergeStrategy as InstructionDataMergeStrategy> + traversalOrder, mergeDataWithLocalDeclarations, + instructionDataMergeStrategy as InstructionDataMergeStrategy> ) as MutableMap>> } public fun collectData( traversalOrder: TraversalOrder, + mergeDataWithLocalDeclarations: Boolean, instructionDataMergeStrategy: InstructionDataMergeStrategy> ): Map>> { val initialDataValue : Map = Collections.emptyMap() @@ -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(), 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 collectDataFromSubgraph( pseudocode: Pseudocode, traversalOrder: TraversalOrder, - lookInside: LookInsideStrategy, + mergeDataWithLocalDeclarations: Boolean, edgesMap: MutableMap>>, instructionDataMergeStrategy: InstructionDataMergeStrategy>, previousSubGraphInstructions: Collection, @@ -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) 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 d9c999970af..0a7355b609a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/PseudocodeVariablesData.java @@ -62,6 +62,11 @@ public class PseudocodeVariablesData { return pseudocode; } + @NotNull + public LexicalScopeVariableInfo getLexicalScopeVariableInfo() { + return pseudocodeVariableDataCollector.getLexicalScopeVariableInfo(); + } + @NotNull public Set getUsedVariables(@NotNull Pseudocode pseudocode) { Set usedVariables = usedVariablesForDeclaration.get(pseudocode); @@ -139,10 +144,10 @@ public class PseudocodeVariablesData { @NotNull private Map>> computeVariableInitializers() { - final Set declaredVariables = getDeclaredVariables(pseudocode, true); + final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariableDataCollector.getLexicalScopeVariableInfo(); return pseudocodeVariableDataCollector.collectDataJ( - FORWARD, + FORWARD, /*mergeDataWithLocalDeclarations=*/ false, new InstructionDataMergeStrategy>() { @NotNull @Override @@ -153,8 +158,8 @@ public class PseudocodeVariablesData { Map enterInstructionData = mergeIncomingEdgesDataForInitializers(incomingEdgesData); - Map exitInstructionData = - addVariableInitStateFromCurrentInstructionIfAny(instruction, enterInstructionData, declaredVariables); + Map exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny( + instruction, enterInstructionData, lexicalScopeVariableInfo); return createEdges(enterInstructionData, exitInstructionData); } } @@ -162,12 +167,16 @@ public class PseudocodeVariablesData { } public static VariableInitState getDefaultValueForInitializers( - @NotNull Set 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 addVariableInitStateFromCurrentInstructionIfAny( @NotNull Instruction instruction, @NotNull Map enterInstructionData, - @NotNull Set 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>> getVariableUseStatusData() { return pseudocodeVariableDataCollector.collectDataJ( - BACKWARD, + BACKWARD, /*mergeDataWithLocalDeclarations=*/ true, new InstructionDataMergeStrategy>() { @NotNull @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LexicalScope.kt b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LexicalScope.kt index b69610ed5de..8bedda02d2c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LexicalScope.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/LexicalScope.kt @@ -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 + } } diff --git a/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions b/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions index 2c682b98d02..91156a3288c 100644 --- a/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions +++ b/compiler/testData/cfg-variables/basic/UsageInFunctionLiteral.instructions @@ -34,25 +34,25 @@ sink: } --------------------- L3: - 3 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 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 INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID} + 3 INIT: in: {x=ID} out: {x=ID} error: INIT: in: {} out: {} sink: - INIT: in: {a=ID, f=D, x=ID} out: {a=ID, f=D, x=ID} USE: in: {} out: {} + INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {} ===================== == use == fun use(vararg a: Any?) = a diff --git a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions new file mode 100644 index 00000000000..d1085549b90 --- /dev/null +++ b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.instructions @@ -0,0 +1,135 @@ +== TestFunctionLiteral == +class TestFunctionLiteral { + val sum: (Int)->Int = { (x: Int) -> + sum(x - 1) + x + } +} +--------------------- +L0: + 1 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: + INIT: in: {sum=ID} out: {sum=ID} +error: + INIT: in: {} out: {} +sink: + INIT: in: {sum=D} out: {sum=D} USE: in: {} out: {} +===================== +== anonymous_0 == +{ (x: Int) -> + sum(x - 1) + x + } +--------------------- +L3: + 2 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 +error: + INIT: in: {} out: {} +sink: + INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {} +===================== +== A == +open class A(val a: A) +--------------------- +L0: + 1 INIT: in: {} out: {} + v(val a: A) INIT: in: {} out: {a=D} + w(a) INIT: in: {a=D} out: {a=ID} +L1: + INIT: in: {a=ID} out: {a=ID} +error: + INIT: in: {} out: {} +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 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: + INIT: in: {obj=ID} out: {obj=ID} +error: + INIT: in: {} out: {} +sink: + INIT: in: {obj=D} out: {obj=D} USE: in: {} out: {} +===================== +== foo == +fun foo() { + val y = obj + } +--------------------- +L3: + 2 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 INIT: in: {} out: {} +error: + +sink: + USE: in: {} out: {} +===================== +== TestOther == +class TestOther { + val x: Int = x + 1 +} +--------------------- +L0: + 1 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: + INIT: in: {x=ID} out: {x=ID} +error: + INIT: in: {} out: {} +sink: + INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {} +===================== diff --git a/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt new file mode 100644 index 00000000000..52af0fc669e --- /dev/null +++ b/compiler/testData/cfg-variables/bugs/referenceToPropertyInitializer.kt @@ -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 +} \ No newline at end of file diff --git a/compiler/testData/cfg-variables/basic/varInitializationInIf.instructions b/compiler/testData/cfg-variables/bugs/varInitializationInIf.instructions similarity index 100% rename from compiler/testData/cfg-variables/basic/varInitializationInIf.instructions rename to compiler/testData/cfg-variables/bugs/varInitializationInIf.instructions diff --git a/compiler/testData/cfg-variables/basic/varInitializationInIf.kt b/compiler/testData/cfg-variables/bugs/varInitializationInIf.kt similarity index 100% rename from compiler/testData/cfg-variables/basic/varInitializationInIf.kt rename to compiler/testData/cfg-variables/bugs/varInitializationInIf.kt diff --git a/compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.instructions b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions similarity index 100% rename from compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.instructions rename to compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.instructions diff --git a/compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.kt b/compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.kt similarity index 100% rename from compiler/testData/cfg-variables/basic/varInitializationInIfInCycle.kt rename to compiler/testData/cfg-variables/bugs/varInitializationInIfInCycle.kt diff --git a/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions index de3a1b5783f..139683a6ac4 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/functionLiteralScope.instructions @@ -38,20 +38,20 @@ sink: } --------------------- L3: - 3 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 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 INIT: in: {b=ID, f=D, x=ID} out: {b=ID, f=D, x=ID} + 3 INIT: in: {x=ID} out: {x=ID} error: INIT: in: {} out: {} sink: - INIT: in: {b=ID, f=D, x=ID} out: {b=ID, f=D, x=ID} USE: in: {} out: {} + INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {} ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/localClass.instructions b/compiler/testData/cfg-variables/lexicalScopes/localClass.instructions index 37cac3519b8..dca38922935 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localClass.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/localClass.instructions @@ -41,15 +41,15 @@ fun foo() { } --------------------- L3: - 3 INIT: in: {x=ID} out: {x=ID} + 3 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 INIT: in: {x=ID} out: {x=ID} + 3 INIT: in: {} out: {} error: - INIT: in: {} out: {} + sink: - INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {} + USE: in: {} out: {} ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions index 302b097e67b..6a61fc57981 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/localFunctionScope.instructions @@ -34,20 +34,20 @@ fun local(x: Int) { } --------------------- L3: - 3 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 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 INIT: in: {b=ID, x=ID} out: {b=ID, x=ID} + 3 INIT: in: {x=ID} out: {x=ID} error: INIT: in: {} out: {} sink: - INIT: in: {b=ID, x=ID} out: {b=ID, x=ID} USE: in: {} out: {} + INIT: in: {x=ID} out: {x=ID} USE: in: {} out: {} ===================== diff --git a/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.instructions b/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.instructions index 5ca5758f30b..966c98c0601 100644 --- a/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.instructions +++ b/compiler/testData/cfg-variables/lexicalScopes/objectLiteralScope.instructions @@ -43,15 +43,15 @@ fun foo() { } --------------------- L3: - 3 INIT: in: {bar=D} out: {bar=D} + 3 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 INIT: in: {bar=D} out: {bar=D} + 3 INIT: in: {} out: {} error: - INIT: in: {} out: {} + sink: - INIT: in: {bar=D} out: {bar=D} USE: in: {} out: {} + USE: in: {} out: {} ===================== diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/referenceToPropertyInitializer.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/referenceToPropertyInitializer.kt new file mode 100644 index 00000000000..99bc9d5f2ac --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/referenceToPropertyInitializer.kt @@ -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(obj) { + { + val x = obj + } + fun foo() { + val y = obj + } + } + val obj1: A = @l ( object: A(obj1) { + { + val x = obj1 + } + fun foo() = obj1 + }) +} + +class TestOther { + val x: Int = x + 1 +} diff --git a/compiler/tests/org/jetbrains/jet/cfg/DataFlowTestGenerated.java b/compiler/tests/org/jetbrains/jet/cfg/DataFlowTestGenerated.java index 47b66d18485..97876548c47 100644 --- a/compiler/tests/org/jetbrains/jet/cfg/DataFlowTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/cfg/DataFlowTestGenerated.java @@ -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; } diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 0e9071a7931..2a61d65a9a4 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -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");