From cf655fd5adb63c337ee50e54069fbaf72b11ad29 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Wed, 9 Aug 2023 12:14:10 +0300 Subject: [PATCH] [FIR] Report CONFLICTING_OVERLOADS for local functions ^KT-59186 Fixed --- ...CompilerTestFE10TestdataTestGenerated.java | 6 + ...sticCompilerFE10TestDataTestGenerated.java | 6 + ...eeOldFrontendDiagnosticsTestGenerated.java | 6 + ...siOldFrontendDiagnosticsTestGenerated.java | 6 + .../analysis/checkers/FirConflictsHelpers.kt | 31 +++- .../FirConflictsExpressionChecker.kt | 16 ++ .../NameDeprecation.fir.kt | 8 +- .../tests/missingConflictingOverloads.kt | 12 ++ .../tests/overload/LocalFunctions.fir.kt | 146 +++++++++--------- .../test/runners/DiagnosticTestGenerated.java | 6 + 10 files changed, 163 insertions(+), 80 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/missingConflictingOverloads.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index baee454be01..6c4fbae9698 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -729,6 +729,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/missedTypeArgumentsInAnnotationCall.kt"); } + @Test + @TestMetadata("missingConflictingOverloads.kt") + public void testMissingConflictingOverloads() throws Exception { + runTest("compiler/testData/diagnostics/tests/missingConflictingOverloads.kt"); + } + @Test @TestMetadata("missingIteratorMissing.kt") public void testMissingIteratorMissing() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index f81b8fc7750..8876d3c6da6 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -729,6 +729,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/missedTypeArgumentsInAnnotationCall.kt"); } + @Test + @TestMetadata("missingConflictingOverloads.kt") + public void testMissingConflictingOverloads() throws Exception { + runTest("compiler/testData/diagnostics/tests/missingConflictingOverloads.kt"); + } + @Test @TestMetadata("missingIteratorMissing.kt") public void testMissingIteratorMissing() throws Exception { 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 b773fcf4d67..8199f7d4a73 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 @@ -729,6 +729,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/missedTypeArgumentsInAnnotationCall.kt"); } + @Test + @TestMetadata("missingConflictingOverloads.kt") + public void testMissingConflictingOverloads() throws Exception { + runTest("compiler/testData/diagnostics/tests/missingConflictingOverloads.kt"); + } + @Test @TestMetadata("missingIteratorMissing.kt") public void testMissingIteratorMissing() 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 56158d36302..74a9b1981a4 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 @@ -729,6 +729,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/missedTypeArgumentsInAnnotationCall.kt"); } + @Test + @TestMetadata("missingConflictingOverloads.kt") + public void testMissingConflictingOverloads() throws Exception { + runTest("compiler/testData/diagnostics/tests/missingConflictingOverloads.kt"); + } + @Test @TestMetadata("missingIteratorMissing.kt") public void testMissingIteratorMissing() throws Exception { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt index a4b370c4783..58f19f6fa57 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/FirConflictsHelpers.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.FirOuterClassTypeParameterRef import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_STATUSLESS_DECLARATIONS import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl.Companion.DEFAULT_STATUS_FOR_SUSPEND_MAIN_FUNCTION import org.jetbrains.kotlin.fir.declarations.impl.modifiersRepresentation +import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope @@ -140,6 +141,7 @@ fun FirDeclarationCollector.collectClassMembers(klass: FirRegula val otherDeclarations = mutableMapOf>() val functionDeclarations = mutableMapOf>() + // TODO, KT-61243: Use declaredMemberScope for (it in klass.declarations) { if (!it.isCollectable()) continue @@ -153,9 +155,32 @@ fun FirDeclarationCollector.collectClassMembers(klass: FirRegula } } - private fun collect(declaration: FirDeclaration, representation: String, map: MutableMap>) { - map.getOrPut(representation, ::mutableListOf).also { - it.add(declaration) +fun collectConflictingLocalFunctionsFrom(block: FirBlock, context: CheckerContext): Map>> { + val collectables = + block.statements.filter { + (it is FirSimpleFunction || it is FirRegularClass) && (it as FirDeclaration).isCollectable() + } + + if (collectables.isEmpty()) return emptyMap() + + val inspector = FirDeclarationCollector(context) + val functionDeclarations = mutableMapOf>() + + for (collectable in collectables) { + when (collectable) { + is FirSimpleFunction -> + inspector.collect(collectable, FirRedeclarationPresenter.represent(collectable), functionDeclarations) + is FirRegularClass -> + // TODO, KT-61243: Use declaredMemberScope + collectable.declarations.filterIsInstance().forEach { + inspector.collect(it, FirRedeclarationPresenter.represent(it, collectable), functionDeclarations) + } + else -> {} + } + } + + return inspector.declarationConflictingSymbols +} private fun FirDeclarationCollector.collect( declaration: D, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt index 44dd92895f7..e54f953d4f7 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirConflictsExpressionChecker.kt @@ -6,12 +6,28 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.checkers.checkForLocalRedeclarations +import org.jetbrains.kotlin.fir.analysis.checkers.collectConflictingLocalFunctionsFrom import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.expressions.FirBlock object FirConflictsExpressionChecker : FirBlockChecker() { override fun check(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) { checkForLocalRedeclarations(expression.statements, context, reporter) + checkForLocalConflictingFunctions(expression, context, reporter) + } + + private fun checkForLocalConflictingFunctions(expression: FirBlock, context: CheckerContext, reporter: DiagnosticReporter) { + val conflictingFunctions = collectConflictingLocalFunctionsFrom(expression, context) + + for ((function, otherFunctionsThatConflictWithIt) in conflictingFunctions) { + if (otherFunctionsThatConflictWithIt.isEmpty()) { + continue + } + + reporter.reportOn(function.source, FirErrors.CONFLICTING_OVERLOADS, otherFunctionsThatConflictWithIt, context) + } } } diff --git a/compiler/testData/diagnostics/tests/functionAsExpression/NameDeprecation.fir.kt b/compiler/testData/diagnostics/tests/functionAsExpression/NameDeprecation.fir.kt index b26e8810996..651dd1ec9b4 100644 --- a/compiler/testData/diagnostics/tests/functionAsExpression/NameDeprecation.fir.kt +++ b/compiler/testData/diagnostics/tests/functionAsExpression/NameDeprecation.fir.kt @@ -1,9 +1,9 @@ fun foo() { class A - fun bar() {} - (fun bar() {}) - fun A.foo() {} - (fun A.foo() {}) + fun bar() {} + (fun bar() {}) + fun A.foo() {} + (fun A.foo() {}) run(fun foo() {}) } diff --git a/compiler/testData/diagnostics/tests/missingConflictingOverloads.kt b/compiler/testData/diagnostics/tests/missingConflictingOverloads.kt new file mode 100644 index 00000000000..551ed33ff6e --- /dev/null +++ b/compiler/testData/diagnostics/tests/missingConflictingOverloads.kt @@ -0,0 +1,12 @@ +// FIR_IDENTICAL +// ISSUE: KT-59186 + +fun main() { + fun p () : Char { + return 'c' + } + + fun p () : Float { + return 13.0f + } +} diff --git a/compiler/testData/diagnostics/tests/overload/LocalFunctions.fir.kt b/compiler/testData/diagnostics/tests/overload/LocalFunctions.fir.kt index 1e9a89bbffd..a86496c9a57 100644 --- a/compiler/testData/diagnostics/tests/overload/LocalFunctions.fir.kt +++ b/compiler/testData/diagnostics/tests/overload/LocalFunctions.fir.kt @@ -1,15 +1,15 @@ fun test() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -18,17 +18,17 @@ fun test() { fun Test5(x: Int) = x fun local() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -40,37 +40,37 @@ fun test() { class Test { init { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" - class Test5(val x: Int) { - constructor(): this(0) + class Test5(val x: Int) { + constructor(): this(0) } - fun Test5() {} - fun Test5(x: Int) = x + fun Test5() {} + fun Test5(x: Int) = x } fun test() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -80,17 +80,17 @@ class Test { } val property: Any get() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -103,17 +103,17 @@ class Test { } val property: Any get() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -126,17 +126,17 @@ val property: Any get() { object Object { fun test() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -146,17 +146,17 @@ object Object { } val property: Any get() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" class Test5(val x: Int) { constructor(): this(0) @@ -170,44 +170,44 @@ object Object { val obj = object { fun test() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" - class Test5(val x: Int) { - constructor(): this(0) + class Test5(val x: Int) { + constructor(): this(0) } - fun Test5() {} - fun Test5(x: Int) = x + fun Test5() {} + fun Test5(x: Int) = x } val property: Any get() { - fun test1() {} - fun test1() {} + fun test1() {} + fun test1() {} fun Any.test2() {} fun test2(x: Any) = x - fun Any.test3() {} - fun Any.test3() {} + fun Any.test3() {} + fun Any.test3() {} - fun test4(): Int = 0 - fun test4(): String = "" + fun test4(): Int = 0 + fun test4(): String = "" - class Test5(val x: Int) { - constructor(): this(0) + class Test5(val x: Int) { + constructor(): this(0) } - fun Test5() {} - fun Test5(x: Int) = x + fun Test5() {} + fun Test5(x: Int) = x return 0 } -} \ No newline at end of file +} 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 04c33b8ba7f..7032434e62f 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 @@ -729,6 +729,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/missedTypeArgumentsInAnnotationCall.kt"); } + @Test + @TestMetadata("missingConflictingOverloads.kt") + public void testMissingConflictingOverloads() throws Exception { + runTest("compiler/testData/diagnostics/tests/missingConflictingOverloads.kt"); + } + @Test @TestMetadata("missingIteratorMissing.kt") public void testMissingIteratorMissing() throws Exception {