From 04caa5c61275ccb49f3b63a2f1431dc54f18b881 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 17 Feb 2021 16:26:34 +0300 Subject: [PATCH] Fix DEBUG_INFO_CALL positioning in FIR --- .../LightTreePositioningStrategies.kt | 2 +- .../fir/handlers/FirDiagnosticsHandler.kt | 57 ++++++++++++------- .../p-12/pos/2.1.fir.kt | 30 +++++----- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index da3031de9b1..b5ba01f5d06 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -466,7 +466,7 @@ private fun FlyweightCapableTreeStructure.defaultValue(node: Lig return null } -private fun FlyweightCapableTreeStructure.selector(node: LighterASTNode): LighterASTNode? { +fun FlyweightCapableTreeStructure.selector(node: LighterASTNode): LighterASTNode? { val childrenRef = Ref>() getChildren(node, childrenRef) val children = childrenRef.get() ?: return null diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt index 2eefc1a3f02..5071bea1172 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/frontend/fir/handlers/FirDiagnosticsHandler.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.fir.types.coneTypeSafe import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid import org.jetbrains.kotlin.name.FqNameUnsafe +import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.resolve.AnalyzingUtils import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives @@ -180,6 +181,31 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes Renderers.renderCallInfo(fqName, getTypeOfCall(reference, resolvedSymbol)) } + private fun DebugInfoDiagnosticFactory1.getPositionedElement(sourceElement: FirSourceElement): FirSourceElement { + return if (this === DebugInfoDiagnosticFactory1.CALL + && sourceElement.elementType == KtNodeTypes.DOT_QUALIFIED_EXPRESSION + ) { + if (sourceElement is FirPsiSourceElement<*>) { + val psi = (sourceElement.psi as KtDotQualifiedExpression).selectorExpression + psi?.let { FirRealPsiSourceElement(it) } ?: sourceElement + } else { + val tree = sourceElement.treeStructure + val selector = tree.selector(sourceElement.lighterASTNode) + if (selector == null) { + sourceElement + } else { + val startDelta = tree.getStartOffset(selector) - tree.getStartOffset(sourceElement.lighterASTNode) + val endDelta = tree.getEndOffset(selector) - tree.getEndOffset(sourceElement.lighterASTNode) + FirLightSourceElement( + selector, sourceElement.startOffset + startDelta, sourceElement.endOffset + endDelta, tree + ) + } + } + } else { + sourceElement + } + } + private inline fun DebugInfoDiagnosticFactory1.createDebugInfoDiagnostic( element: FirElement, diagnosedRangesToDiagnosticNames: Map>, @@ -187,31 +213,22 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes ): FirDiagnosticWithParameters1? { val sourceElement = element.source ?: return null if (sourceElement.kind !in allowedKindsForDebugInfo) return null + // Lambda argument is always (?) duplicated by function literal // Block expression is always (?) duplicated by single block expression if (sourceElement.elementType == KtNodeTypes.LAMBDA_ARGUMENT || sourceElement.elementType == KtNodeTypes.BLOCK) return null - if (diagnosedRangesToDiagnosticNames[sourceElement.startOffset..sourceElement.endOffset]?.contains(this.name) != true) return null + // Unfortunately I had to repeat positioning strategy logic here + // (we need to check diagnostic range before applying it) + val positionedElement = getPositionedElement(sourceElement) + if (diagnosedRangesToDiagnosticNames[positionedElement.startOffset..positionedElement.endOffset]?.contains(this.name) != true) { + return null + } val argumentText = argument() - return when (sourceElement) { - is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1( - sourceElement, - argumentText, - severity, - FirDiagnosticFactory1( - name, - severity, - ) - ) - is FirLightSourceElement -> FirLightDiagnosticWithParameters1( - sourceElement, - argumentText, - severity, - FirDiagnosticFactory1( - name, - severity - ) - ) + val factory = FirDiagnosticFactory1, PsiElement, String>(name, severity) + return when (positionedElement) { + is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1(positionedElement, argumentText, severity, factory) + is FirLightSourceElement -> FirLightDiagnosticWithParameters1(positionedElement, argumentText, severity, factory) } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-12/pos/2.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-12/pos/2.1.fir.kt index 8dc04d634b0..011f6984143 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-12/pos/2.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-12/pos/2.1.fir.kt @@ -10,11 +10,11 @@ fun case1(case: Case1) { //to (1.1) case.boo(1) //(1.1) return type is String - case.boo(1) + case.boo(1) //to (1.1) case.boo(x = 1) //(1.1) return type is String - case.boo(x = 1) + case.boo(x = 1) } @@ -35,11 +35,11 @@ fun case2(case: Case2) { //to (1.1) case.boo(1, 2) //(1.1) return type is String - case.boo(1, 2) + case.boo(1, 2) //to (1.1) case.boo(x = 1, y = 2) //(1.1) return type is String - case.boo(x = 1, y = 2) + case.boo(x = 1, y = 2) } // TESTCASE NUMBER: 3 @@ -52,11 +52,11 @@ fun case3(case: Case3) { //to (1.1) case.boo(1, 2) //(1.1) return type is String - case.boo(1, 2) + case.boo(1, 2) //to (1.1) case.boo(x = 1, y = 2) //(1.1) return type is String - case.boo(x = 1, y = 2) + case.boo(x = 1, y = 2) } // TESTCASE NUMBER: 4 @@ -71,11 +71,11 @@ fun case4(case: Case4) { //to (1.1) case.plus(1) //(1.1) return type is String - case.plus(1) + case.plus(1) //to (1.1) case.plus(x = 1) //(1.1) return type is String - case.plus(x = 1) + case.plus(x = 1) //as operator call case + 1 //to (1.1) case+1 @@ -91,7 +91,7 @@ class Case5 { fun case(list: List) { list.foo(1) - list.foo(1) + list.foo(1) } } @@ -103,7 +103,7 @@ class Case6 { fun case(list: List) { list.foo(1) - list.foo(1) + list.foo(1) } } @@ -115,7 +115,7 @@ class Case7 { fun case(list: List) { list.foo(1, 1) - list.foo(1, 1) + list.foo(1, 1) } } @@ -127,7 +127,7 @@ class Case8() { fun testcase8(case: Case8) { case.foo(1, 1) - case.foo(1, 1) + case.foo(1, 1) } // TESTCASE NUMBER: 9 @@ -138,7 +138,7 @@ class Case9() { fun testcase9(case: Case9) { case.xoo(1, 1) - case.xoo(1, 1) + case.xoo(1, 1) } // TESTCASE NUMBER: 10 @@ -149,7 +149,7 @@ class Case10() { fun testcase10(case: Case10) { case.xoo(1, 1) - case.xoo(1, 1) + case.xoo(1, 1) } // TESTCASE NUMBER: 11 @@ -160,5 +160,5 @@ class Case11() { fun testcase11(case: Case11) { case.xoo(1, 1) - case.xoo(1, 1) + case.xoo(1, 1) }