Skip to content

Commit 82d22c6

Browse files
authored
bugfix: rename end marker (#18838)
metals backport scalameta/metals#5803 CC: @tgodzik
2 parents 8a0799b + 81063dd commit 82d22c6

File tree

8 files changed

+93
-18
lines changed

8 files changed

+93
-18
lines changed

presentation-compiler/src/main/dotty/tools/pc/PcCollector.scala

+37-3
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ abstract class PcCollector[T](
6969
case _ => rawPath
7070
def collect(
7171
parent: Option[Tree]
72-
)(tree: Tree, pos: SourcePosition, symbol: Option[Symbol]): T
72+
)(tree: Tree| EndMarker, pos: SourcePosition, symbol: Option[Symbol]): T
7373

7474
/**
7575
* @return (adjusted position, should strip backticks)
@@ -423,7 +423,7 @@ abstract class PcCollector[T](
423423
parent: Option[Tree]
424424
): Set[T] =
425425
def collect(
426-
tree: Tree,
426+
tree: Tree | EndMarker,
427427
pos: SourcePosition,
428428
symbol: Option[Symbol] = None
429429
) =
@@ -461,6 +461,9 @@ abstract class PcCollector[T](
461461
case df: NamedDefTree
462462
if df.span.isCorrect && df.nameSpan.isCorrect &&
463463
filter(df) && !isGeneratedGiven(df) =>
464+
def collectEndMarker =
465+
EndMarker.getPosition(df, pos, sourceText).map:
466+
collect(EndMarker(df.symbol), _)
464467
val annots = collectTrees(df.mods.annotations)
465468
val traverser =
466469
new PcCollector.DeepFolderWithParent[Set[T]](
@@ -470,7 +473,7 @@ abstract class PcCollector[T](
470473
occurrences + collect(
471474
df,
472475
pos.withSpan(df.nameSpan)
473-
)
476+
) ++ collectEndMarker
474477
) { case (set, tree) =>
475478
traverser(set, tree)
476479
}
@@ -635,3 +638,34 @@ case class ExtensionParamOccurence(
635638
sym: Symbol,
636639
methods: List[untpd.Tree]
637640
)
641+
642+
case class EndMarker(symbol: Symbol)
643+
644+
object EndMarker:
645+
/**
646+
* Matches end marker line from start to the name's beginning.
647+
* E.g.
648+
* end /* some comment */
649+
*/
650+
private val endMarkerRegex = """.*end(/\*.*\*/|\s)+""".r
651+
def getPosition(df: NamedDefTree, pos: SourcePosition, sourceText: String)(
652+
implicit ct: Context
653+
): Option[SourcePosition] =
654+
val name = df.name.toString()
655+
val endMarkerLine =
656+
sourceText.slice(df.span.start, df.span.end).split('\n').last
657+
val index = endMarkerLine.length() - name.length()
658+
if index < 0 then None
659+
else
660+
val (possiblyEndMarker, possiblyEndMarkerName) =
661+
endMarkerLine.splitAt(index)
662+
Option.when(
663+
possiblyEndMarkerName == name &&
664+
endMarkerRegex.matches(possiblyEndMarker)
665+
)(
666+
pos
667+
.withStart(df.span.end - name.length())
668+
.withEnd(df.span.end)
669+
)
670+
end getPosition
671+
end EndMarker

presentation-compiler/src/main/dotty/tools/pc/PcDocumentHighlightProvider.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ final class PcDocumentHighlightProvider(
1919
def collect(
2020
parent: Option[Tree]
2121
)(
22-
tree: Tree,
22+
tree: Tree | EndMarker,
2323
toAdjust: SourcePosition,
2424
sym: Option[Symbol]
2525
): DocumentHighlight =

presentation-compiler/src/main/dotty/tools/pc/PcInlineValueProviderImpl.scala

+9-6
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,27 @@ import org.eclipse.lsp4j as l
2424
final class PcInlineValueProviderImpl(
2525
val driver: InteractiveDriver,
2626
val params: OffsetParams
27-
) extends PcCollector[Occurence](driver, params)
27+
) extends PcCollector[Option[Occurence]](driver, params)
2828
with InlineValueProvider:
2929

3030
val text = params.text.toCharArray()
3131

3232
val position: l.Position = pos.toLsp.getStart()
3333

3434
override def collect(parent: Option[Tree])(
35-
tree: Tree,
35+
tree: Tree | EndMarker,
3636
pos: SourcePosition,
3737
sym: Option[Symbol]
38-
): Occurence =
39-
val (adjustedPos, _) = adjust(pos)
40-
Occurence(tree, parent, adjustedPos)
38+
): Option[Occurence] =
39+
tree match
40+
case tree: Tree =>
41+
val (adjustedPos, _) = adjust(pos)
42+
Some(Occurence(tree, parent, adjustedPos))
43+
case _ => None
4144

4245
override def defAndRefs(): Either[String, (Definition, List[Reference])] =
4346
val newctx = driver.currentCtx.fresh.setCompilationUnit(unit)
44-
val allOccurences = result()
47+
val allOccurences = result().flatten
4548
for
4649
definition <- allOccurences
4750
.collectFirst { case Occurence(defn: ValDef, _, pos) =>

presentation-compiler/src/main/dotty/tools/pc/PcRenameProvider.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ final class PcRenameProvider(
3434

3535
def collect(
3636
parent: Option[Tree]
37-
)(tree: Tree, toAdjust: SourcePosition, sym: Option[Symbol]): l.TextEdit =
37+
)(tree: Tree | EndMarker, toAdjust: SourcePosition, sym: Option[Symbol]): l.TextEdit =
3838
val (pos, stripBackticks) = adjust(toAdjust, forRename = true)
3939
l.TextEdit(
4040
pos.toLsp,

presentation-compiler/src/main/dotty/tools/pc/PcSemanticTokensProvider.scala

+9-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ final class PcSemanticTokensProvider(
3232
* 3. type parameters,
3333
* In all those cases we don't have a specific value for sure.
3434
*/
35-
private def isDeclaration(tree: Tree) = tree match
35+
private def isDeclaration(tree: Tree | EndMarker) = tree match
3636
case df: ValOrDefDef => df.rhs.isEmpty
3737
case df: TypeDef =>
3838
df.rhs match
@@ -49,7 +49,8 @@ final class PcSemanticTokensProvider(
4949
* that the compiler sees them as vals, as it's not clear
5050
* if they should be declaration/definition at all.
5151
*/
52-
private def isDefinition(tree: Tree) = tree match
52+
private def isDefinition(tree: Tree | EndMarker) = tree match
53+
case _: EndMarker => true
5354
case df: Bind => true
5455
case df: ValOrDefDef =>
5556
!df.rhs.isEmpty && !df.symbol.isAllOf(Flags.EnumCase)
@@ -62,8 +63,12 @@ final class PcSemanticTokensProvider(
6263
object Collector extends PcCollector[Option[Node]](driver, params):
6364
override def collect(
6465
parent: Option[Tree]
65-
)(tree: Tree, pos: SourcePosition, symbol: Option[Symbol]): Option[Node] =
66-
val sym = symbol.fold(tree.symbol)(identity)
66+
)(tree: Tree | EndMarker, pos: SourcePosition, symbol: Option[Symbol]): Option[Node] =
67+
val sym =
68+
tree match
69+
case tree: Tree =>
70+
symbol.fold(tree.symbol)(identity)
71+
case EndMarker(sym) => sym
6772
if !pos.exists || sym == null || sym == NoSymbol then None
6873
else
6974
Some(

presentation-compiler/test/dotty/tools/pc/tests/edit/PcRenameSuite.scala

+26-2
Original file line numberDiff line numberDiff line change
@@ -478,9 +478,33 @@ class PcRenameSuite extends BasePcRenameSuite:
478478
| def <<ma@@p>>(f: Int => Int): Bar = Bar(x.map(f))
479479
|}
480480
|
481-
|val f =
481+
|val f =
482482
| for {
483483
| b <- Bar(List(1,2,3))
484484
| } yield b
485-
|""".stripMargin,
485+
|""".stripMargin
486+
)
487+
488+
@Test def `end-marker` =
489+
check(
490+
"""|def <<he@@llo>>(a: Int) =
491+
| ???
492+
|end <<hello>>
493+
|""".stripMargin
494+
)
495+
496+
@Test def `end-marker-with-comment` =
497+
check(
498+
"""|def <<he@@llo>>(a: Int) =
499+
| ???
500+
|end /* a comment */ <<hello>> /* a comment */
501+
|""".stripMargin
502+
)
503+
504+
@Test def `end-marker-wrong` =
505+
check(
506+
"""|def <<f@@oo>> =
507+
| def bar =
508+
| ???
509+
| end bar""".stripMargin
486510
)

presentation-compiler/test/dotty/tools/pc/tests/tokens/SemanticTokensSuite.scala

+8
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,11 @@ class SemanticTokensSuite extends BaseSemanticTokensSuite:
343343
|}
344344
|""".stripMargin,
345345
)
346+
347+
@Test def `end-marker` =
348+
check(
349+
"""|def <<foo>>/*method,definition*/ =
350+
| 1
351+
|end <<foo>>/*method,definition*/
352+
|""".stripMargin,
353+
)

presentation-compiler/test/dotty/tools/pc/utils/DefSymbolCollector.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ import dotty.tools.dotc.core.Symbols.*
88
import dotty.tools.dotc.interactive.InteractiveDriver
99
import dotty.tools.dotc.util.SourcePosition
1010
import dotty.tools.pc.PcCollector
11+
import dotty.tools.pc.EndMarker
1112

1213
final class DefSymbolCollector(
1314
driver: InteractiveDriver,
1415
params: VirtualFileParams
1516
) extends PcCollector[Option[Symbol]](driver, params):
1617

1718
def collect(parent: Option[Tree])(
18-
tree: Tree,
19+
tree: Tree | EndMarker,
1920
toAdjust: SourcePosition,
2021
sym: Option[Symbol]
2122
): Option[Symbol] =

0 commit comments

Comments
 (0)