From 5ecf9cce2569a437395fb69ced742dad00001110 Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Tue, 21 Feb 2023 16:24:21 +0100 Subject: [PATCH] [FIR] Don't resolve already resolved qualified access ^KT-30507 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 6 ++ .../delegates/delegateWithAnonymousObject.dot | 78 +++++++++---------- ...eeOldFrontendDiagnosticsTestGenerated.java | 6 ++ ...siOldFrontendDiagnosticsTestGenerated.java | 6 ++ ...bstractBodyResolveTransformerDispatcher.kt | 4 + .../FirExpressionsResolveTransformer.kt | 11 ++- .../LightTreePositioningStrategies.kt | 6 ++ .../smartcasts/unsoundSmartcast.fir.kt | 41 ++++++++++ .../smartcasts/unsoundSmartcast.kt | 41 ++++++++++ .../test/runners/DiagnosticTestGenerated.java | 6 ++ .../diagnostics/notLinked/dfa/neg/13.fir.kt | 2 +- 11 files changed, 163 insertions(+), 44 deletions(-) create mode 100644 compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.fir.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index d51d3f5a427..0282d88b01f 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -40198,6 +40198,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/listOfGeneric.kt"); } + @Test + @TestMetadata("unsoundSmartcast.kt") + public void testUnsoundSmartcast() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt"); + } + @Test @TestMetadata("withChangesToNull.kt") public void testWithChangesToNull() throws Exception { diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot b/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot index 170cab7fa2e..8a2a64ccdc0 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/delegates/delegateWithAnonymousObject.dot @@ -138,51 +138,48 @@ digraph delegateWithAnonymousObject_kt { } 53 [label="Postponed exit from lambda"]; 54 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|(...)" style="filled" fillcolor=yellow]; - 55 [label="Access variable this@R|/IssuesListUserProfile|"]; - 56 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|(...).#(...)" style="filled" fillcolor=yellow]; - 57 [label="Exit property delegate" style="filled" fillcolor=yellow]; - 58 [label="Exit property" style="filled" fillcolor=red]; + 55 [label="Function call: this@R|/IssuesListUserProfile|.R|/delegate|(...).#(...)" style="filled" fillcolor=yellow]; + 56 [label="Exit property delegate" style="filled" fillcolor=yellow]; + 57 [label="Exit property" style="filled" fillcolor=red]; } subgraph cluster_18 { color=blue - 59 [label="Enter function " style="filled" fillcolor=red]; - 60 [label="Delegated constructor call: super|>()" style="filled" fillcolor=yellow]; - 61 [label="Exit function " style="filled" fillcolor=red]; + 58 [label="Enter function " style="filled" fillcolor=red]; + 59 [label="Delegated constructor call: super|>()" style="filled" fillcolor=yellow]; + 60 [label="Exit function " style="filled" fillcolor=red]; } - 62 [label="Exit class IssuesListUserProfile" style="filled" fillcolor=red]; + 61 [label="Exit class IssuesListUserProfile" style="filled" fillcolor=red]; } subgraph cluster_19 { color=blue - 63 [label="Enter function " style="filled" fillcolor=red]; + 62 [label="Enter function " style="filled" fillcolor=red]; subgraph cluster_20 { color=blue - 64 [label="Enter block"]; - 65 [label="Access variable D|/IssuesListUserProfile.issueListView|"]; - 66 [label="Access variable this@R|/IssuesListUserProfile|"]; - 67 [label="Access variable R|/issueListView|"]; - 68 [label="Function call: this@R|/IssuesListUserProfile|.D|/IssuesListUserProfile.issueListView|.R|SubstitutionOverride|(...)" style="filled" fillcolor=yellow]; - 69 [label="Exit block"]; + 63 [label="Enter block"]; + 64 [label="Access variable D|/IssuesListUserProfile.issueListView|"]; + 65 [label="Access variable R|/issueListView|"]; + 66 [label="Function call: this@R|/IssuesListUserProfile|.D|/IssuesListUserProfile.issueListView|.R|SubstitutionOverride|(...)" style="filled" fillcolor=yellow]; + 67 [label="Exit block"]; } - 70 [label="Exit function " style="filled" fillcolor=red]; + 68 [label="Exit function " style="filled" fillcolor=red]; } subgraph cluster_21 { color=blue - 71 [label="Enter function " style="filled" fillcolor=red]; + 69 [label="Enter function " style="filled" fillcolor=red]; subgraph cluster_22 { color=blue - 72 [label="Enter block"]; - 73 [label="Access variable D|/IssuesListUserProfile.issueListView|"]; - 74 [label="Access variable this@R|/IssuesListUserProfile|"]; - 75 [label="Function call: this@R|/IssuesListUserProfile|.D|/IssuesListUserProfile.issueListView|.R|SubstitutionOverride|(...)" style="filled" fillcolor=yellow]; - 76 [label="Jump: ^ this@R|/IssuesListUserProfile|.D|/IssuesListUserProfile.issueListView|.R|SubstitutionOverride|(this@R|/IssuesListUserProfile|, ::R|/IssuesListUserProfile.issueListView|)"]; - 77 [label="Stub" style="filled" fillcolor=gray]; - 78 [label="Exit block" style="filled" fillcolor=gray]; + 70 [label="Enter block"]; + 71 [label="Access variable D|/IssuesListUserProfile.issueListView|"]; + 72 [label="Function call: this@R|/IssuesListUserProfile|.D|/IssuesListUserProfile.issueListView|.R|SubstitutionOverride|(...)" style="filled" fillcolor=yellow]; + 73 [label="Jump: ^ this@R|/IssuesListUserProfile|.D|/IssuesListUserProfile.issueListView|.R|SubstitutionOverride|(this@R|/IssuesListUserProfile|, ::R|/IssuesListUserProfile.issueListView|)"]; + 74 [label="Stub" style="filled" fillcolor=gray]; + 75 [label="Exit block" style="filled" fillcolor=gray]; } - 79 [label="Exit function " style="filled" fillcolor=red]; + 76 [label="Exit function " style="filled" fillcolor=red]; } 23 -> {24} [color=green]; - 23 -> {62} [style=dotted]; - 23 -> {24 59} [style=dashed]; + 23 -> {61} [style=dotted]; + 23 -> {24 58} [style=dashed]; 24 -> {25}; 25 -> {26 53 54}; 25 -> {26} [style=dashed]; @@ -220,32 +217,29 @@ digraph delegateWithAnonymousObject_kt { 50 -> {51} [style=dotted]; 51 -> {52} [style=dotted]; 53 -> {54} [color=green]; - 53 -> {57} [color=red]; + 53 -> {56} [color=red]; 54 -> {55}; 55 -> {56}; 56 -> {57}; - 57 -> {58}; - 58 -> {59} [color=green]; + 57 -> {58} [color=green]; + 58 -> {59}; 59 -> {60}; - 60 -> {61}; - 61 -> {62} [color=green]; - 62 -> {63 71} [color=green]; - 62 -> {63 71} [style=dashed]; + 60 -> {61} [color=green]; + 61 -> {62 69} [color=green]; + 61 -> {62 69} [style=dashed]; + 62 -> {63}; 63 -> {64}; 64 -> {65}; 65 -> {66}; 66 -> {67}; 67 -> {68}; - 68 -> {69}; 69 -> {70}; + 70 -> {71}; 71 -> {72}; 72 -> {73}; - 73 -> {74}; - 74 -> {75}; - 75 -> {76}; - 76 -> {79}; - 76 -> {77} [style=dotted]; - 77 -> {78} [style=dotted]; - 78 -> {79} [style=dotted]; + 73 -> {76}; + 73 -> {74} [style=dotted]; + 74 -> {75} [style=dotted]; + 75 -> {76} [style=dotted]; } diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 48e7ea3c3e3..31d69a0d68c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -40262,6 +40262,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/listOfGeneric.kt"); } + @Test + @TestMetadata("unsoundSmartcast.kt") + public void testUnsoundSmartcast() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt"); + } + @Test @TestMetadata("withChangesToNull.kt") public void testWithChangesToNull() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 28f6940ebeb..5b255d19433 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -40358,6 +40358,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/listOfGeneric.kt"); } + @Test + @TestMetadata("unsoundSmartcast.kt") + public void testUnsoundSmartcast() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt"); + } + @Test @TestMetadata("withChangesToNull.kt") public void testWithChangesToNull() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformerDispatcher.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformerDispatcher.kt index 630f86b450b..051209b0b2b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformerDispatcher.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirAbstractBodyResolveTransformerDispatcher.kt @@ -257,6 +257,10 @@ abstract class FirAbstractBodyResolveTransformerDispatcher( return expressionsTransformer.transformArrayOfCall(arrayOfCall, data) } + override fun transformSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: ResolutionMode): FirStatement { + return expressionsTransformer.transformSmartCastExpression(smartCastExpression, data) + } + // ------------------------------------- Declarations ------------------------------------- override fun transformDeclaration(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration { 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 c67382aa16a..a9f01d9fed4 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 @@ -80,6 +80,10 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT return (expression.transformChildren(transformer, data) as FirStatement) } + override fun transformSmartCastExpression(smartCastExpression: FirSmartCastExpression, data: ResolutionMode): FirStatement { + return smartCastExpression + } + override fun transformQualifiedAccessExpression( qualifiedAccessExpression: FirQualifiedAccessExpression, data: ResolutionMode, @@ -92,6 +96,10 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT data: ResolutionMode, isUsedAsReceiver: Boolean, ): FirStatement { + if (qualifiedAccessExpression.typeRef is FirResolvedTypeRef && qualifiedAccessExpression.calleeReference !is FirSimpleNamedReference) { + return qualifiedAccessExpression + } + qualifiedAccessExpression.transformAnnotations(this, data) qualifiedAccessExpression.transformTypeArguments(transformer, ResolutionMode.ContextIndependent) @@ -1420,7 +1428,8 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT session.moduleData, source = index.source?.fakeElement(KtFakeSourceElementKind.DesugaredCompoundAssignment), name = SpecialNames.subscribeOperatorIndex(i), - initializer = index + initializer = index, + typeRef = index.typeRef, ) } diff --git a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt index 6963eb072e4..bb61501a369 100644 --- a/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/frontend.common-psi/src/org/jetbrains/kotlin/diagnostics/LightTreePositioningStrategies.kt @@ -683,6 +683,12 @@ object LightTreePositioningStrategies { endOffset: Int, tree: FlyweightCapableTreeStructure ): List { + if (node.tokenType == KtNodeTypes.BINARY_EXPRESSION) { + tree.findDescendantByTypes(node, KtTokens.AUGMENTED_ASSIGNMENTS)?.let { + return markElement(it, startOffset, endOffset, tree, node) + } + } + when { node.tokenType == KtNodeTypes.BINARY_EXPRESSION && tree.findDescendantByType(node, KtTokens.EQ, followFunctions = false) != null -> { // Look for reference in LHS of variable assignment. diff --git a/compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.fir.kt new file mode 100644 index 00000000000..b95f03fc4f4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.fir.kt @@ -0,0 +1,41 @@ +// SKIP_TXT +// ISSUE: KT-30507 + +fun test1() { + var x: MutableList? = mutableListOf(1) + x!! + x[if (true) { x = null; 0 } else 0] += x[0] + x[0].inv() +} + +fun test2() { + var x: MutableList? = mutableListOf(1) + x!! + x[if (true) { x = null; 0 } else 0] = 11 + x[0].inv() +} + +fun test3() { + var x: MutableList? = mutableListOf(1) + x!! + x[0] = if (true) { x = null; 0 } else 0 + x[0].inv() +} + +operator fun MutableList.get(i1: Int, i2: Int) {} +operator fun MutableList.set(i1: Int, i2: Int, el: Int) = 10 + +fun test4() { + var x: MutableList? = mutableListOf(1) + x!! + val y = x[if (true) { x = null; 0 } else 0, x[0]] +} + +operator fun Int.invoke(y: Int, z: Int) {} + +fun test5() { + var x: Int? = 10 + x!! + x(if (true) { x = null; 0 } else 0, x) + x.inv() +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt b/compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt new file mode 100644 index 00000000000..b0e4499268f --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt @@ -0,0 +1,41 @@ +// SKIP_TXT +// ISSUE: KT-30507 + +fun test1() { + var x: MutableList? = mutableListOf(1) + x!! + x[if (true) { x = null; 0 } else 0] += x[0] + x[0].inv() +} + +fun test2() { + var x: MutableList? = mutableListOf(1) + x!! + x[if (true) { x = null; 0 } else 0] = 11 + x[0].inv() +} + +fun test3() { + var x: MutableList? = mutableListOf(1) + x!! + x[0] = if (true) { x = null; 0 } else 0 + x[0].inv() +} + +operator fun MutableList.get(i1: Int, i2: Int) {} +operator fun MutableList.set(i1: Int, i2: Int, el: Int) = 10 + +fun test4() { + var x: MutableList? = mutableListOf(1) + x!! + val y = x[if (true) { x = null; 0 } else 0, x[0]] +} + +operator fun Int.invoke(y: Int, z: Int) {} + +fun test5() { + var x: Int? = 10 + x!! + x(if (true) { x = null; 0 } else 0, x) + x.inv() +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 47ecba0f7b7..eb067bcd32c 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -40358,6 +40358,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/listOfGeneric.kt"); } + @Test + @TestMetadata("unsoundSmartcast.kt") + public void testUnsoundSmartcast() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/smartcasts/unsoundSmartcast.kt"); + } + @Test @TestMetadata("withChangesToNull.kt") public void testWithChangesToNull() throws Exception { diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/13.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/13.fir.kt index afecbebb145..530be466f30 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/13.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/13.fir.kt @@ -4,7 +4,7 @@ // TESTCASE NUMBER: 1 fun case_1(x: Class?) { x!! - x[if (true) {x=null;0} else 0] += x[0] + x[if (true) {x=null;0} else 0] += x[0] x x[0].inv() }