[FIR] Create CFG node for ::class calls
This commit is contained in:
committed by
teamcityserver
parent
c5ce52eef5
commit
9b00776dba
+5
@@ -64,6 +64,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt");
|
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")
|
@TestMetadata("companion.kt")
|
||||||
public void testCompanion() throws Exception {
|
public void testCompanion() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/companion.kt");
|
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 }
|
||||||
|
}
|
||||||
+6
@@ -68,6 +68,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt");
|
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
|
@Test
|
||||||
@TestMetadata("companion.kt")
|
@TestMetadata("companion.kt")
|
||||||
public void testCompanion() throws Exception {
|
public void testCompanion() throws Exception {
|
||||||
|
|||||||
+6
@@ -68,6 +68,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt");
|
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
|
@Test
|
||||||
@TestMetadata("companion.kt")
|
@TestMetadata("companion.kt")
|
||||||
public void testCompanion() throws Exception {
|
public void testCompanion() throws Exception {
|
||||||
|
|||||||
@@ -1342,6 +1342,10 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
graphBuilder.exitCallableReference(callableReferenceAccess).mergeIncomingFlow()
|
graphBuilder.exitCallableReference(callableReferenceAccess).mergeIncomingFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun exitGetClassCall(getClassCall: FirGetClassCall) {
|
||||||
|
graphBuilder.exitGetClassCall(getClassCall).mergeIncomingFlow()
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------ Utils ------------------------------------------------------
|
// ------------------------------------------------------ Utils ------------------------------------------------------
|
||||||
|
|
||||||
private fun getOrCreateLocalVariableAssignmentAnalyzer(firFunction: FirFunction): FirLocalVariableAssignmentAnalyzer? {
|
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(
|
class DelegatedConstructorCallNode(
|
||||||
owner: ControlFlowGraph,
|
owner: ControlFlowGraph,
|
||||||
override val fir: FirDelegatedConstructorCall,
|
override val fir: FirDelegatedConstructorCall,
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ fun CFGNode<*>.render(): String =
|
|||||||
is ElvisExitNode -> "Exit ?:"
|
is ElvisExitNode -> "Exit ?:"
|
||||||
|
|
||||||
is CallableReferenceNode -> "Callable reference: ${fir.render(CfgRenderMode)}"
|
is CallableReferenceNode -> "Callable reference: ${fir.render(CfgRenderMode)}"
|
||||||
|
is GetClassCallNode -> "::class call"
|
||||||
|
|
||||||
is AbstractBinaryExitNode -> throw IllegalStateException()
|
is AbstractBinaryExitNode -> throw IllegalStateException()
|
||||||
},
|
},
|
||||||
|
|||||||
+4
@@ -1121,6 +1121,10 @@ class ControlFlowGraphBuilder {
|
|||||||
return createCallableReferenceNode(callableReferenceAccess).also { addNewSimpleNode(it) }
|
return createCallableReferenceNode(callableReferenceAccess).also { addNewSimpleNode(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun exitGetClassCall(getClassCall: FirGetClassCall): GetClassCallNode {
|
||||||
|
return createGetClassCallNode(getClassCall).also { addNewSimpleNode(it) }
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------- Block -----------------------------------
|
// ----------------------------------- Block -----------------------------------
|
||||||
|
|
||||||
fun enterInitBlock(initBlock: FirAnonymousInitializer): Pair<InitBlockEnterNode, CFGNode<*>?> {
|
fun enterInitBlock(initBlock: FirAnonymousInitializer): Pair<InitBlockEnterNode, CFGNode<*>?> {
|
||||||
|
|||||||
+3
@@ -128,6 +128,9 @@ fun ControlFlowGraphBuilder.createFunctionCallNode(fir: FirFunctionCall): Functi
|
|||||||
fun ControlFlowGraphBuilder.createCallableReferenceNode(fir: FirCallableReferenceAccess): CallableReferenceNode =
|
fun ControlFlowGraphBuilder.createCallableReferenceNode(fir: FirCallableReferenceAccess): CallableReferenceNode =
|
||||||
CallableReferenceNode(currentGraph, fir, levelCounter, createId())
|
CallableReferenceNode(currentGraph, fir, levelCounter, createId())
|
||||||
|
|
||||||
|
fun ControlFlowGraphBuilder.createGetClassCallNode(fir: FirGetClassCall): GetClassCallNode =
|
||||||
|
GetClassCallNode(currentGraph, fir, levelCounter, createId())
|
||||||
|
|
||||||
fun ControlFlowGraphBuilder.createDelegatedConstructorCallNode(fir: FirDelegatedConstructorCall): DelegatedConstructorCallNode =
|
fun ControlFlowGraphBuilder.createDelegatedConstructorCallNode(fir: FirDelegatedConstructorCall): DelegatedConstructorCallNode =
|
||||||
DelegatedConstructorCallNode(currentGraph, fir, levelCounter, createId())
|
DelegatedConstructorCallNode(currentGraph, fir, levelCounter, createId())
|
||||||
|
|
||||||
|
|||||||
+4
@@ -299,6 +299,10 @@ abstract class ControlFlowGraphVisitor<out R, in D> {
|
|||||||
return visitNode(node, data)
|
return visitNode(node, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun visitGetClassCallNode(node: GetClassCallNode, data: D): R {
|
||||||
|
return visitNode(node, data)
|
||||||
|
}
|
||||||
|
|
||||||
open fun visitDelegatedConstructorCallNode(node: DelegatedConstructorCallNode, data: D): R {
|
open fun visitDelegatedConstructorCallNode(node: DelegatedConstructorCallNode, data: D): R {
|
||||||
return visitNode(node, data)
|
return visitNode(node, data)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -846,6 +846,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
buildResolvedTypeRef {
|
buildResolvedTypeRef {
|
||||||
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(typeOfExpression), false)
|
type = StandardClassIds.KClass.constructClassLikeType(arrayOf(typeOfExpression), false)
|
||||||
}
|
}
|
||||||
|
dataFlowAnalyzer.exitGetClassCall(transformedGetClassCall)
|
||||||
return transformedGetClassCall
|
return transformedGetClassCall
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -68,6 +68,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/catchParameter.kt");
|
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
|
@Test
|
||||||
@TestMetadata("companion.kt")
|
@TestMetadata("companion.kt")
|
||||||
public void testCompanion() throws Exception {
|
public void testCompanion() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user