FIR checker: make unused checker handle invoke properly
#KT-43688 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
d907c48d9c
commit
44c6ec2c44
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo(): Int {
|
||||||
|
val x = fun() = 4
|
||||||
|
val y = fun() = 2
|
||||||
|
return 10 * x() + y()
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
FILE: invoke.kt
|
||||||
|
public final fun foo(): R|kotlin/Int| {
|
||||||
|
lval x: R|() -> kotlin/Int| = fun <anonymous>(): R|kotlin/Int| {
|
||||||
|
^ Int(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
lval y: R|() -> kotlin/Int| = fun <anonymous>(): R|kotlin/Int| {
|
||||||
|
^ Int(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
^foo Int(10).R|kotlin/Int.times|(R|<local>/x|.R|SubstitutionOverride<kotlin/Function0.invoke: R|kotlin/Int|>|()).R|kotlin/Int.plus|(R|<local>/y|.R|SubstitutionOverride<kotlin/Function0.invoke: R|kotlin/Int|>|())
|
||||||
|
}
|
||||||
+5
@@ -330,6 +330,11 @@ public class ExtendedFirDiagnosticsTestGenerated extends AbstractExtendedFirDiag
|
|||||||
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/classProperty.kt");
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/classProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invoke.kt")
|
||||||
|
public void testInvoke() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/invoke.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambda.kt")
|
@TestMetadata("lambda.kt")
|
||||||
public void testLambda() throws Exception {
|
public void testLambda() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/lambda.kt");
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/lambda.kt");
|
||||||
|
|||||||
+5
@@ -330,6 +330,11 @@ public class ExtendedFirWithLightTreeDiagnosticsTestGenerated extends AbstractEx
|
|||||||
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/classProperty.kt");
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/classProperty.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invoke.kt")
|
||||||
|
public void testInvoke() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/invoke.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("lambda.kt")
|
@TestMetadata("lambda.kt")
|
||||||
public void testLambda() throws Exception {
|
public void testLambda() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/lambda.kt");
|
runTest("compiler/fir/analysis-tests/testData/extendedCheckers/unused/lambda.kt");
|
||||||
|
|||||||
+23
-1
@@ -10,6 +10,7 @@ import kotlinx.collections.immutable.persistentMapOf
|
|||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.FirSymbolOwner
|
import org.jetbrains.kotlin.fir.FirSymbolOwner
|
||||||
import org.jetbrains.kotlin.fir.analysis.cfa.*
|
import org.jetbrains.kotlin.fir.analysis.cfa.*
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||||
@@ -23,7 +24,10 @@ import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
|||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.isFunctionalType
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
|
||||||
object UnusedChecker : FirControlFlowChecker() {
|
object UnusedChecker : FirControlFlowChecker() {
|
||||||
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) {
|
override fun analyze(graph: ControlFlowGraph, reporter: DiagnosticReporter, checkerContext: CheckerContext) {
|
||||||
@@ -34,7 +38,7 @@ object UnusedChecker : FirControlFlowChecker() {
|
|||||||
val properties = LocalPropertyCollector.collect(graph)
|
val properties = LocalPropertyCollector.collect(graph)
|
||||||
if (properties.isEmpty()) return
|
if (properties.isEmpty()) return
|
||||||
|
|
||||||
val data = ValueWritesWithoutReading(properties).getData(graph)
|
val data = ValueWritesWithoutReading(checkerContext.session, properties).getData(graph)
|
||||||
graph.traverse(TraverseDirection.Backward, CfaVisitor(data, reporter))
|
graph.traverse(TraverseDirection.Backward, CfaVisitor(data, reporter))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,6 +155,7 @@ object UnusedChecker : FirControlFlowChecker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ValueWritesWithoutReading(
|
private class ValueWritesWithoutReading(
|
||||||
|
private val session: FirSession,
|
||||||
private val localProperties: Set<FirPropertySymbol>
|
private val localProperties: Set<FirPropertySymbol>
|
||||||
) : ControlFlowGraphVisitor<PathAwareVariableStatusInfo, Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>>() {
|
) : ControlFlowGraphVisitor<PathAwareVariableStatusInfo, Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>>() {
|
||||||
fun getData(graph: ControlFlowGraph): Map<CFGNode<*>, PathAwareVariableStatusInfo> {
|
fun getData(graph: ControlFlowGraph): Map<CFGNode<*>, PathAwareVariableStatusInfo> {
|
||||||
@@ -265,6 +270,23 @@ object UnusedChecker : FirControlFlowChecker() {
|
|||||||
return update(dataForNode, *symbols) { status }
|
return update(dataForNode, *symbols) { status }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionCallNode(
|
||||||
|
node: FunctionCallNode,
|
||||||
|
data: Collection<Pair<EdgeLabel, PathAwareVariableStatusInfo>>
|
||||||
|
): PathAwareVariableStatusInfo {
|
||||||
|
val dataForNode = visitNode(node, data)
|
||||||
|
val reference = node.fir.calleeReference as? FirResolvedNamedReference ?: return dataForNode
|
||||||
|
val functionSymbol = reference.resolvedSymbol as? FirFunctionSymbol<*> ?: return dataForNode
|
||||||
|
val symbol = if (functionSymbol.callableId.callableName.identifier == "invoke") {
|
||||||
|
localProperties.find { it.fir.name == reference.name && it.fir.returnTypeRef.coneType.isFunctionalType(session) }
|
||||||
|
} else null
|
||||||
|
symbol ?: return dataForNode
|
||||||
|
|
||||||
|
val status = VariableStatus.READ
|
||||||
|
status.isRead = true
|
||||||
|
return update(dataForNode, symbol) { status }
|
||||||
|
}
|
||||||
|
|
||||||
private fun update(
|
private fun update(
|
||||||
pathAwareInfo: PathAwareVariableStatusInfo,
|
pathAwareInfo: PathAwareVariableStatusInfo,
|
||||||
vararg symbols: FirPropertySymbol,
|
vararg symbols: FirPropertySymbol,
|
||||||
|
|||||||
Reference in New Issue
Block a user