From f46ca8cde7e7a2ab7bab605c4ea2a07565a9d1a1 Mon Sep 17 00:00:00 2001 From: Katarzyna Marek Date: Tue, 31 Oct 2023 17:56:47 +0100 Subject: [PATCH] bugfix: rename end marker for lolac definitions --- .../scala/meta/internal/pc/PcCollector.scala | 43 +++++++++++++++++-- .../pc/PcDocumentHighlightProvider.scala | 2 +- .../pc/PcInlineValueProviderImpl.scala | 12 +++--- .../meta/internal/pc/PcRenameProvider.scala | 6 ++- .../pc/PcSemanticTokensProvider.scala | 17 ++++++-- .../test/scala/tests/pc/PcRenameSuite.scala | 24 +++++++++++ .../src/main/scala-3/example/EndMarker.scala | 6 +++ .../definition-scala3/example/EndMarker.scala | 6 +++ .../example/EndMarker.scala | 6 +++ .../resources/expect/toplevels-scala3.expect | 3 +- .../mtags-scala3/example/EndMarker.scala | 6 +++ .../semanticTokens3/example/EndMarker.scala | 6 +++ .../semanticdb-scala3/example/EndMarker.scala | 6 +++ .../example/EndMarker.scala | 6 +++ 14 files changed, 134 insertions(+), 15 deletions(-) create mode 100644 tests/input/src/main/scala-3/example/EndMarker.scala create mode 100644 tests/unit/src/test/resources/definition-scala3/example/EndMarker.scala create mode 100644 tests/unit/src/test/resources/documentSymbol-scala3/example/EndMarker.scala create mode 100644 tests/unit/src/test/resources/mtags-scala3/example/EndMarker.scala create mode 100644 tests/unit/src/test/resources/semanticTokens3/example/EndMarker.scala create mode 100644 tests/unit/src/test/resources/semanticdb-scala3/example/EndMarker.scala create mode 100644 tests/unit/src/test/resources/toplevel-with-inner-scala3/example/EndMarker.scala diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala index a4e33785e04..6b5e62df886 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcCollector.scala @@ -70,7 +70,7 @@ abstract class PcCollector[T]( case _ => rawPath def collect( parent: Option[Tree] - )(tree: Tree, pos: SourcePosition, symbol: Option[Symbol]): T + )(tree: Tree | EndMarker, pos: SourcePosition, symbol: Option[Symbol]): T /** * @return (adjusted position, should strip backticks) @@ -435,7 +435,7 @@ abstract class PcCollector[T]( parent: Option[Tree], ): Set[T] = def collect( - tree: Tree, + tree: Tree | EndMarker, pos: SourcePosition, symbol: Option[Symbol] = None, ) = @@ -493,6 +493,12 @@ abstract class PcCollector[T]( case df: NamedDefTree if df.span.isCorrect && df.nameSpan.isCorrect && filter(df) && !isGeneratedGiven(df) => + def collectEndMarker = + EndMarker.getPosition(df, pos, sourceText).map { + collect(EndMarker(df.symbol), _) + } + end collectEndMarker + val annots = collectTrees(df.mods.annotations) val traverser = new PcCollector.DeepFolderWithParent[Set[T]]( @@ -502,7 +508,7 @@ abstract class PcCollector[T]( occurences + collect( df, pos.withSpan(df.nameSpan), - ) + ) ++ collectEndMarker ) { case (set, tree) => traverser(set, tree) } @@ -667,3 +673,34 @@ case class ExtensionParamOccurence( sym: Symbol, methods: List[untpd.Tree], ) + +case class EndMarker(symbol: Symbol) + +object EndMarker: + /** + * Matches end marker line from start to the name's beginning. + * E.g. + * end /* some comment */ + */ + private val endMarkerRegex = """.*end(/\*.*\*/|\s)+""".r + def getPosition(df: NamedDefTree, pos: SourcePosition, sourceText: String)( + implicit ct: Context + ): Option[SourcePosition] = + val name = df.name.toString() + val endMarkerLine = + sourceText.slice(df.span.start, df.span.end).split('\n').last + val index = endMarkerLine.length() - name.length() + if index < 0 then None + else + val (possiblyEndMarker, possiblyEndMarkerName) = + endMarkerLine.splitAt(index) + Option.when( + possiblyEndMarkerName == name && + endMarkerRegex.matches(possiblyEndMarker) + )( + pos + .withStart(df.span.end - name.length()) + .withEnd(df.span.end) + ) + end getPosition +end EndMarker diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcDocumentHighlightProvider.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcDocumentHighlightProvider.scala index e36fa9c152b..de9561feebb 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcDocumentHighlightProvider.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcDocumentHighlightProvider.scala @@ -18,7 +18,7 @@ final class PcDocumentHighlightProvider( def collect( parent: Option[Tree] )( - tree: Tree, + tree: Tree | EndMarker, toAdjust: SourcePosition, sym: Option[Symbol], ): DocumentHighlight = diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlineValueProviderImpl.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlineValueProviderImpl.scala index a249125ed0c..4942fa17fb8 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlineValueProviderImpl.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlineValueProviderImpl.scala @@ -19,7 +19,7 @@ import org.eclipse.{lsp4j as l} final class PcInlineValueProviderImpl( val driver: InteractiveDriver, val params: OffsetParams, -) extends PcCollector[Occurence](driver, params) +) extends PcCollector[Option[Occurence]](driver, params) with InlineValueProvider: val text = params.text.toCharArray() @@ -27,16 +27,18 @@ final class PcInlineValueProviderImpl( val position: l.Position = pos.toLsp.getStart() override def collect(parent: Option[Tree])( - tree: Tree, + tree: Tree | EndMarker, pos: SourcePosition, sym: Option[Symbol], - ): Occurence = + ): Option[Occurence] = val (adjustedPos, _) = adjust(pos) - Occurence(tree, parent, adjustedPos) + tree match + case tree: Tree => Some(Occurence(tree, parent, adjustedPos)) + case _ => None override def defAndRefs(): Either[String, (Definition, List[Reference])] = val newctx = driver.currentCtx.fresh.setCompilationUnit(unit) - val allOccurences = result() + val allOccurences = result().flatten for definition <- allOccurences .collectFirst { case Occurence(defn: ValDef, _, pos) => diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcRenameProvider.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcRenameProvider.scala index 1837d3aa420..d415ac4e20c 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcRenameProvider.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcRenameProvider.scala @@ -33,7 +33,11 @@ final class PcRenameProvider( def collect( parent: Option[Tree] - )(tree: Tree, toAdjust: SourcePosition, sym: Option[Symbol]): l.TextEdit = + )( + tree: Tree | EndMarker, + toAdjust: SourcePosition, + sym: Option[Symbol], + ): l.TextEdit = val (pos, stripBackticks) = adjust(toAdjust, forRename = true) l.TextEdit( pos.toLsp, diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcSemanticTokensProvider.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcSemanticTokensProvider.scala index 3f6654e8ff0..bbd6608e7bb 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcSemanticTokensProvider.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcSemanticTokensProvider.scala @@ -30,7 +30,7 @@ final class PcSemanticTokensProvider( * 3. type parameters, * In all those cases we don't have a specific value for sure. */ - private def isDeclaration(tree: Tree) = tree match + private def isDeclaration(tree: Tree | EndMarker) = tree match case df: ValOrDefDef => df.rhs.isEmpty case df: TypeDef => df.rhs match @@ -47,7 +47,8 @@ final class PcSemanticTokensProvider( * that the compiler sees them as vals, as it's not clear * if they should be declaration/definition at all. */ - private def isDefinition(tree: Tree) = tree match + private def isDefinition(tree: Tree | EndMarker) = tree match + case _: EndMarker => true case df: Bind => true case df: ValOrDefDef => !df.rhs.isEmpty && !df.symbol.isAllOf(Flags.EnumCase) @@ -60,8 +61,16 @@ final class PcSemanticTokensProvider( object Collector extends PcCollector[Option[Node]](driver, params): override def collect( parent: Option[Tree] - )(tree: Tree, pos: SourcePosition, symbol: Option[Symbol]): Option[Node] = - val sym = symbol.fold(tree.symbol)(identity) + )( + tree: Tree | EndMarker, + pos: SourcePosition, + symbol: Option[Symbol], + ): Option[Node] = + val sym = + tree match + case tree: Tree => + symbol.fold(tree.symbol)(identity) + case EndMarker(sym) => sym if !pos.exists || sym == null || sym == NoSymbol then None else Some( diff --git a/tests/cross/src/test/scala/tests/pc/PcRenameSuite.scala b/tests/cross/src/test/scala/tests/pc/PcRenameSuite.scala index d454728eb71..42fac71bb05 100644 --- a/tests/cross/src/test/scala/tests/pc/PcRenameSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/PcRenameSuite.scala @@ -488,4 +488,28 @@ class PcRenameSuite extends BasePcRenameSuite { | } yield b |""".stripMargin, ) + + check( + "end-marker".tag(IgnoreScala2), + """|def <>(a: Int) = + | ??? + |end <> + |""".stripMargin, + ) + + check( + "end-marker-with-comment".tag(IgnoreScala2), + """|def <>(a: Int) = + | ??? + |end /* a comment */ <> /* a comment */ + |""".stripMargin, + ) + + check( + "end-marker-wrong".tag(IgnoreScala2), + """|def <> = + | def bar = + | ??? + | end bar""".stripMargin, + ) } diff --git a/tests/input/src/main/scala-3/example/EndMarker.scala b/tests/input/src/main/scala-3/example/EndMarker.scala new file mode 100644 index 00000000000..367ba09749f --- /dev/null +++ b/tests/input/src/main/scala-3/example/EndMarker.scala @@ -0,0 +1,6 @@ +package example + +object EndMarker: + def foo = + 1 + end foo diff --git a/tests/unit/src/test/resources/definition-scala3/example/EndMarker.scala b/tests/unit/src/test/resources/definition-scala3/example/EndMarker.scala new file mode 100644 index 00000000000..78a79b2a52a --- /dev/null +++ b/tests/unit/src/test/resources/definition-scala3/example/EndMarker.scala @@ -0,0 +1,6 @@ +package example + +object EndMarker/*EndMarker.scala*/: + def foo/*EndMarker.scala*/ = + 1 + end/**/ foo/*EndMarker.scala*/ diff --git a/tests/unit/src/test/resources/documentSymbol-scala3/example/EndMarker.scala b/tests/unit/src/test/resources/documentSymbol-scala3/example/EndMarker.scala new file mode 100644 index 00000000000..bd7c5d3fe1f --- /dev/null +++ b/tests/unit/src/test/resources/documentSymbol-scala3/example/EndMarker.scala @@ -0,0 +1,6 @@ +/*example(Package):6*/package example + +/*example.EndMarker(Module):6*/object EndMarker: + /*example.EndMarker.foo(Method):5*/def foo = + 1 + end foo diff --git a/tests/unit/src/test/resources/expect/toplevels-scala3.expect b/tests/unit/src/test/resources/expect/toplevels-scala3.expect index 780a51c4066..39a344acf53 100644 --- a/tests/unit/src/test/resources/expect/toplevels-scala3.expect +++ b/tests/unit/src/test/resources/expect/toplevels-scala3.expect @@ -8,6 +8,7 @@ example/ColorEnum.scala -> example/Color# example/Comments.scala -> example/Comments# example/Companion.scala -> example/Companion# example/Companion.scala -> example/Companion. +example/EndMarker.scala -> example/EndMarker. example/EtaExpansion.scala -> example/EtaExpansion# example/Extension.scala -> example/AbstractExtension# example/Extension.scala -> example/Extension$package. @@ -52,4 +53,4 @@ example/nested/LocalClass.scala -> example/nested/LocalClass# example/nested/package.scala -> example/PackageObjectSibling# example/nested/package.scala -> example/nested/package. example/package.scala -> example/package. -example/type/Backtick.scala -> example/type/Backtick# \ No newline at end of file +example/type/Backtick.scala -> example/type/Backtick# diff --git a/tests/unit/src/test/resources/mtags-scala3/example/EndMarker.scala b/tests/unit/src/test/resources/mtags-scala3/example/EndMarker.scala new file mode 100644 index 00000000000..2d1eaedf91e --- /dev/null +++ b/tests/unit/src/test/resources/mtags-scala3/example/EndMarker.scala @@ -0,0 +1,6 @@ +package example + +object EndMarker/*example.EndMarker.*/: + def foo/*example.EndMarker.foo().*/ = + 1 + end foo diff --git a/tests/unit/src/test/resources/semanticTokens3/example/EndMarker.scala b/tests/unit/src/test/resources/semanticTokens3/example/EndMarker.scala new file mode 100644 index 00000000000..7e4e14ab074 --- /dev/null +++ b/tests/unit/src/test/resources/semanticTokens3/example/EndMarker.scala @@ -0,0 +1,6 @@ +<>/*keyword*/ <>/*namespace*/ + +<>/*keyword*/ <>/*class*/: + <>/*keyword*/ <>/*method,definition*/ = + <<1>>/*number*/ + <>/*keyword*/ <>/*method,definition*/ diff --git a/tests/unit/src/test/resources/semanticdb-scala3/example/EndMarker.scala b/tests/unit/src/test/resources/semanticdb-scala3/example/EndMarker.scala new file mode 100644 index 00000000000..cabfdaf9b4a --- /dev/null +++ b/tests/unit/src/test/resources/semanticdb-scala3/example/EndMarker.scala @@ -0,0 +1,6 @@ +package example + +object EndMarker/*example.EndMarker.*/: + def foo/*example.EndMarker.foo().*/ = + 1 + end foo/*example.EndMarker.foo().*/ diff --git a/tests/unit/src/test/resources/toplevel-with-inner-scala3/example/EndMarker.scala b/tests/unit/src/test/resources/toplevel-with-inner-scala3/example/EndMarker.scala new file mode 100644 index 00000000000..f5682d86d5e --- /dev/null +++ b/tests/unit/src/test/resources/toplevel-with-inner-scala3/example/EndMarker.scala @@ -0,0 +1,6 @@ +package example + +object EndMarker/*example.EndMarker.*/: + def foo = + 1 + end foo