From 9b00776dba3a89b65a11b40a108e519f3e36cd85 Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 22 Jul 2021 14:14:54 +0300 Subject: [PATCH] [FIR] Create CFG node for ::class calls --- ...TouchedTilContractsPhaseTestGenerated.java | 5 ++ .../testData/resolve/classCallInLambda.dot | 59 +++++++++++++++++++ .../resolve/classCallInLambda.fir.txt | 7 +++ .../testData/resolve/classCallInLambda.kt | 7 +++ .../runners/FirDiagnosticTestGenerated.java | 6 ++ ...DiagnosticsWithLightTreeTestGenerated.java | 6 ++ .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 4 ++ .../kotlin/fir/resolve/dfa/cfg/CFGNode.kt | 6 ++ .../fir/resolve/dfa/cfg/CFGNodeRenderer.kt | 1 + .../dfa/cfg/ControlFlowGraphBuilder.kt | 4 ++ .../dfa/cfg/ControlFlowGraphNodeBuilder.kt | 3 + .../dfa/cfg/ControlFlowGraphVisitor.kt | 4 ++ .../FirExpressionsResolveTransformer.kt | 1 + ...nosisCompilerFirTestdataTestGenerated.java | 6 ++ 14 files changed, 119 insertions(+) create mode 100644 compiler/fir/analysis-tests/testData/resolve/classCallInLambda.dot create mode 100644 compiler/fir/analysis-tests/testData/resolve/classCallInLambda.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 5db74e8328f..05c783eca71 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -64,6 +64,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); } + @TestMetadata("classCallInLambda.kt") + public void testClassCallInLambda() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt"); + } + @TestMetadata("companion.kt") public void testCompanion() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/companion.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.dot b/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.dot new file mode 100644 index 00000000000..0b89489a7aa --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.dot @@ -0,0 +1,59 @@ +digraph classCallInLambda_kt { + graph [nodesep=3] + node [shape=box penwidth=2] + edge [penwidth=2] + + subgraph cluster_0 { + color=red + 0 [label="Enter function test" style="filled" fillcolor=red]; + subgraph cluster_1 { + color=blue + 1 [label="Enter block"]; + 2 [label="Access variable R|/x|"]; + 3 [label="Postponed enter to lambda"]; + subgraph cluster_2 { + color=blue + 11 [label="Enter function anonymousFunction" style="filled" fillcolor=red]; + subgraph cluster_3 { + color=blue + 12 [label="Enter block"]; + 13 [label="Access variable R|/it|"]; + 14 [label="::class call"]; + 15 [label="Exit block"]; + } + 16 [label="Exit function anonymousFunction" style="filled" fillcolor=red]; + } + 4 [label="Call arguments union" style="filled" fillcolor=yellow]; + 5 [label="Postponed exit from lambda"]; + 6 [label="Function call: R|/x|.R|kotlin/let||>(...)"]; + 7 [label="Jump: ^test R|/x|.R|kotlin/let||>( = let@fun (it: R|kotlin/String|): R|kotlin/reflect/KClass| { + ^ (R|/it|) +} +)"]; + 8 [label="Stub" style="filled" fillcolor=gray]; + 9 [label="Exit block" style="filled" fillcolor=gray]; + } + 10 [label="Exit function test" style="filled" fillcolor=red]; + } + 0 -> {1}; + 1 -> {2}; + 2 -> {3}; + 3 -> {11}; + 3 -> {5} [color=red]; + 3 -> {11} [style=dashed]; + 4 -> {6} [color=red]; + 5 -> {6} [color=green]; + 6 -> {7}; + 7 -> {10}; + 7 -> {8} [style=dotted]; + 8 -> {9} [style=dotted]; + 9 -> {10} [style=dotted]; + 11 -> {12}; + 12 -> {13}; + 13 -> {14}; + 14 -> {15}; + 15 -> {16}; + 16 -> {4} [color=red]; + 16 -> {5} [color=green]; + +} diff --git a/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.fir.txt b/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.fir.txt new file mode 100644 index 00000000000..5c94877f888 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.fir.txt @@ -0,0 +1,7 @@ +FILE: classCallInLambda.kt + public final fun test(x: R|kotlin/String|): R|kotlin/reflect/KClass<*>| { + ^test R|/x|.R|kotlin/let||>( = let@fun (it: R|kotlin/String|): R|kotlin/reflect/KClass| { + ^ (R|/it|) + } + ) + } diff --git a/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt b/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt new file mode 100644 index 00000000000..419435b2998 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt @@ -0,0 +1,7 @@ +// WITH_STDLIB +// DUMP_CFG +import kotlin.reflect.KClass + +fun test(x: String): KClass<*> { + return x.let { it::class } +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index 28d5b9df587..f743752de7d 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -68,6 +68,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); } + @Test + @TestMetadata("classCallInLambda.kt") + public void testClassCallInLambda() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index f5c8eb46fb7..0e11e04ab91 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -68,6 +68,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); } + @Test + @TestMetadata("classCallInLambda.kt") + public void testClassCallInLambda() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 4ddf76f0855..323c0fab84c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -1342,6 +1342,10 @@ abstract class FirDataFlowAnalyzer( graphBuilder.exitCallableReference(callableReferenceAccess).mergeIncomingFlow() } + fun exitGetClassCall(getClassCall: FirGetClassCall) { + graphBuilder.exitGetClassCall(getClassCall).mergeIncomingFlow() + } + // ------------------------------------------------------ Utils ------------------------------------------------------ private fun getOrCreateLocalVariableAssignmentAnalyzer(firFunction: FirFunction): FirLocalVariableAssignmentAnalyzer? { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt index 0b6b787c66a..95605d65521 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNode.kt @@ -609,6 +609,12 @@ class CallableReferenceNode( } } +class GetClassCallNode(owner: ControlFlowGraph, override val fir: FirGetClassCall, level: Int, id: Int) : CFGNode(owner, level, id) { + override fun accept(visitor: ControlFlowGraphVisitor, data: D): R { + return visitor.visitGetClassCallNode(this, data) + } +} + class DelegatedConstructorCallNode( owner: ControlFlowGraph, override val fir: FirDelegatedConstructorCall, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt index 03602ed1349..6d07e8bca0f 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt @@ -123,6 +123,7 @@ fun CFGNode<*>.render(): String = is ElvisExitNode -> "Exit ?:" is CallableReferenceNode -> "Callable reference: ${fir.render(CfgRenderMode)}" + is GetClassCallNode -> "::class call" is AbstractBinaryExitNode -> throw IllegalStateException() }, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index e7f1d70a918..7c457f39fd3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -1121,6 +1121,10 @@ class ControlFlowGraphBuilder { return createCallableReferenceNode(callableReferenceAccess).also { addNewSimpleNode(it) } } + fun exitGetClassCall(getClassCall: FirGetClassCall): GetClassCallNode { + return createGetClassCallNode(getClassCall).also { addNewSimpleNode(it) } + } + // ----------------------------------- Block ----------------------------------- fun enterInitBlock(initBlock: FirAnonymousInitializer): Pair?> { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt index 2a650d0f849..1c685183db9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphNodeBuilder.kt @@ -128,6 +128,9 @@ fun ControlFlowGraphBuilder.createFunctionCallNode(fir: FirFunctionCall): Functi fun ControlFlowGraphBuilder.createCallableReferenceNode(fir: FirCallableReferenceAccess): CallableReferenceNode = CallableReferenceNode(currentGraph, fir, levelCounter, createId()) +fun ControlFlowGraphBuilder.createGetClassCallNode(fir: FirGetClassCall): GetClassCallNode = + GetClassCallNode(currentGraph, fir, levelCounter, createId()) + fun ControlFlowGraphBuilder.createDelegatedConstructorCallNode(fir: FirDelegatedConstructorCall): DelegatedConstructorCallNode = DelegatedConstructorCallNode(currentGraph, fir, levelCounter, createId()) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt index 0e997d8533d..7353543f8d1 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphVisitor.kt @@ -299,6 +299,10 @@ abstract class ControlFlowGraphVisitor { return visitNode(node, data) } + open fun visitGetClassCallNode(node: GetClassCallNode, data: D): R { + return visitNode(node, data) + } + open fun visitDelegatedConstructorCallNode(node: DelegatedConstructorCallNode, data: D): R { return visitNode(node, data) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index d9d8ea483b3..5a01fa04e48 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -846,6 +846,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform buildResolvedTypeRef { type = StandardClassIds.KClass.constructClassLikeType(arrayOf(typeOfExpression), false) } + dataFlowAnalyzer.exitGetClassCall(transformedGetClassCall) return transformedGetClassCall } diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java index e15dca9526b..e5c70c26226 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/tests/org/jetbrains/kotlin/idea/fir/low/level/api/diagnostic/compiler/based/DiagnosisCompilerFirTestdataTestGenerated.java @@ -68,6 +68,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt"); } + @Test + @TestMetadata("classCallInLambda.kt") + public void testClassCallInLambda() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/classCallInLambda.kt"); + } + @Test @TestMetadata("companion.kt") public void testCompanion() throws Exception {