[FIR] Create CFG node for ::class calls

This commit is contained in:
Dmitriy Novozhilov
2021-07-22 14:14:54 +03:00
committed by teamcityserver
parent c5ce52eef5
commit 9b00776dba
14 changed files with 119 additions and 0 deletions
@@ -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");
@@ -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|<local>/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|<local>/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|<local>/x|.R|kotlin/let|<R|kotlin/String|, R|kotlin/reflect/KClass<out kotlin/String>|>(...)"];
7 [label="Jump: ^test R|<local>/x|.R|kotlin/let|<R|kotlin/String|, R|kotlin/reflect/KClass<out kotlin/String>|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/reflect/KClass<out kotlin/String>| <inline=Inline, kind=EXACTLY_ONCE> {
^ <getClass>(R|<local>/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];
}
@@ -0,0 +1,7 @@
FILE: classCallInLambda.kt
public final fun test(x: R|kotlin/String|): R|kotlin/reflect/KClass<*>| {
^test R|<local>/x|.R|kotlin/let|<R|kotlin/String|, R|kotlin/reflect/KClass<out kotlin/String>|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/reflect/KClass<out kotlin/String>| <inline=Inline, kind=EXACTLY_ONCE> {
^ <getClass>(R|<local>/it|)
}
)
}
@@ -0,0 +1,7 @@
// WITH_STDLIB
// DUMP_CFG
import kotlin.reflect.KClass
fun test(x: String): KClass<*> {
return x.let { it::class }
}
@@ -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 {
@@ -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 {
@@ -1342,6 +1342,10 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
graphBuilder.exitCallableReference(callableReferenceAccess).mergeIncomingFlow()
}
fun exitGetClassCall(getClassCall: FirGetClassCall) {
graphBuilder.exitGetClassCall(getClassCall).mergeIncomingFlow()
}
// ------------------------------------------------------ Utils ------------------------------------------------------
private fun getOrCreateLocalVariableAssignmentAnalyzer(firFunction: FirFunction): FirLocalVariableAssignmentAnalyzer? {
@@ -609,6 +609,12 @@ class CallableReferenceNode(
}
}
class GetClassCallNode(owner: ControlFlowGraph, override val fir: FirGetClassCall, level: Int, id: Int) : CFGNode<FirGetClassCall>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitGetClassCallNode(this, data)
}
}
class DelegatedConstructorCallNode(
owner: ControlFlowGraph,
override val fir: FirDelegatedConstructorCall,
@@ -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()
},
@@ -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<InitBlockEnterNode, CFGNode<*>?> {
@@ -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())
@@ -299,6 +299,10 @@ abstract class ControlFlowGraphVisitor<out R, in D> {
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)
}
@@ -846,6 +846,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
buildResolvedTypeRef {
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(typeOfExpression), false)
}
dataFlowAnalyzer.exitGetClassCall(transformedGetClassCall)
return transformedGetClassCall
}
@@ -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 {