Skip to content

Compare span points in pathTo to determine best span #23581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions compiler/src/dotty/tools/dotc/ast/NavigateAST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,29 @@ object NavigateAST {
* When choosing better fit we compare spans. If candidate span has starting or ending point inside (exclusive)
* current best fit it is selected as new best fit. This means that same spans are failing the first predicate.
*
* In case when spans start and end at same offsets we prefer non synthethic one.
* In case when spans start and end at same offsets we prefer non synthethic one,
* and then one with better point (see isBetterPoint below).
*/
def isBetterFit(currentBest: List[Positioned], candidate: List[Positioned]): Boolean =
if currentBest.isEmpty && candidate.nonEmpty then true
else if currentBest.nonEmpty && candidate.nonEmpty then
val bestSpan = currentBest.head.span
val candidateSpan = candidate.head.span

bestSpan != candidateSpan &&
envelops(bestSpan, candidateSpan) ||
bestSpan.contains(candidateSpan) && bestSpan.isSynthetic && !candidateSpan.isSynthetic
def isBetterPoint =
// Given two spans with same end points,
// we compare their points in relation to the point we are looking for (span.point)
// The candidate (candidateSpan.point) is better than what we have so far (bestSpan.point), when:
// 1) candidate is closer to target from the right
span.point <= candidateSpan.point && candidateSpan.point < bestSpan.point
// 2) candidate is closer to target from the left
|| bestSpan.point < candidateSpan.point && candidateSpan.point <= span.point
// 3) candidate is to on the left side of target, and best so far is on the right
|| candidateSpan.point <= span.point && span.point < bestSpan.point

bestSpan != candidateSpan && envelops(bestSpan, candidateSpan)
|| bestSpan.contains(candidateSpan) && bestSpan.isSynthetic && !candidateSpan.isSynthetic
|| candidateSpan.start == bestSpan.start && candidateSpan.end == bestSpan.end && isBetterPoint
else false

def isRecoveryTree(sel: untpd.Select): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -815,3 +815,39 @@ class HoverTermSuite extends BaseHoverSuite:
|""".stripMargin,
"def substring(x$0: Int, x$1: Int): String".hover
)

@Test def `multiple-valdefs-1` =
check(
"""|object O {
| val x@@x, yy, zz = 1
|}
|""".stripMargin,
"val xx: Int".hover
)

@Test def `multiple-valdefs-2` =
check(
"""|object O {
| val xx, y@@y, zz = 1
|}
|""".stripMargin,
"val yy: Int".hover
)

@Test def `multiple-valdefs-3` =
check(
"""|object O {
| val xx, yy, z@@z = 1
|}
|""".stripMargin,
"val zz: Int".hover
)

@Test def `multiple-valdefs-4` =
check(
"""|object O {
| val xx, thisIsAVeryLongNa@@me, zz = 1
|}
|""".stripMargin,
"val thisIsAVeryLongName: Int".hover
)
Loading