From f4eb4393eeaaa069c7b65db8d4132f825a7d05cf Mon Sep 17 00:00:00 2001 From: Katarzyna Marek Date: Thu, 31 Aug 2023 14:20:30 +0200 Subject: [PATCH] feature: index overridden symbols in top level --- .../meta/internal/mtags/MtagsIndexer.scala | 17 +++--- .../internal/mtags/ScalaToplevelMtags.scala | 54 ++++++++++++++++--- .../mtags/UnresolvedOverriddenSymbol.scala | 12 +++++ .../test/scala/tests/ScalaToplevelSuite.scala | 17 ++++-- 4 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 mtags/src/main/scala/scala/meta/internal/mtags/UnresolvedOverriddenSymbol.scala diff --git a/mtags/src/main/scala/scala/meta/internal/mtags/MtagsIndexer.scala b/mtags/src/main/scala/scala/meta/internal/mtags/MtagsIndexer.scala index 590a7b3a1f1..730feaab2e1 100644 --- a/mtags/src/main/scala/scala/meta/internal/mtags/MtagsIndexer.scala +++ b/mtags/src/main/scala/scala/meta/internal/mtags/MtagsIndexer.scala @@ -64,8 +64,8 @@ trait MtagsIndexer { ) } } - def term(name: String, pos: m.Position, kind: Kind, properties: Int): String = - addSignature(Descriptor.Term(name), pos, kind, properties) + def term(name: String, pos: m.Position, kind: Kind, properties: Int, overriddenSymbols: List[(String, m.Position)] = List.empty): String = + addSignature(Descriptor.Term(name), pos, kind, properties, overriddenSymbols) def term(name: Term.Name, kind: Kind, properties: Int): String = addSignature(Descriptor.Term(name.value), name.pos, kind, properties) def tparam(name: Name, kind: Kind, properties: Int): String = @@ -122,8 +122,8 @@ trait MtagsIndexer { properties ) } - def tpe(name: String, pos: m.Position, kind: Kind, properties: Int): String = - addSignature(Descriptor.Type(name), pos, kind, properties) + def tpe(name: String, pos: m.Position, kind: Kind, properties: Int, overriddenSymbols: List[(String, m.Position)] = List.empty): String = + addSignature(Descriptor.Type(name), pos, kind, properties, overriddenSymbols) def tpe(name: Name, kind: Kind, properties: Int): String = addSignature(Descriptor.Type(name.value), name.pos, kind, properties) def pkg(name: String, pos: m.Position): String = { @@ -141,7 +141,8 @@ trait MtagsIndexer { signature: Descriptor, definition: m.Position, kind: s.SymbolInformation.Kind, - properties: Int + properties: Int, + overriddenSymbols: List[(String, m.Position)] = List.empty ): String = { val previousOwner = currentOwner currentOwner = symbol(signature) @@ -155,12 +156,16 @@ trait MtagsIndexer { syntax, role ) + val encodedOverriddenSymbols = overriddenSymbols.map{ + case (simpleName, pos) => UnresolvedOverriddenSymbol(simpleName, pos.start) + } val info = s.SymbolInformation( symbol = syntax, language = language, kind = kind, properties = properties, - displayName = signature.name.value + displayName = signature.name.value, + overriddenSymbols = encodedOverriddenSymbols ) visitOccurrence(occ, info, previousOwner) syntax diff --git a/mtags/src/main/scala/scala/meta/internal/mtags/ScalaToplevelMtags.scala b/mtags/src/main/scala/scala/meta/internal/mtags/ScalaToplevelMtags.scala index 3ba1066a8cd..ce4145b6dd9 100644 --- a/mtags/src/main/scala/scala/meta/internal/mtags/ScalaToplevelMtags.scala +++ b/mtags/src/main/scala/scala/meta/internal/mtags/ScalaToplevelMtags.scala @@ -177,13 +177,13 @@ class ScalaToplevelMtags( newExpectExtensionTemplate(nextOwner) ) case CLASS | TRAIT | OBJECT | ENUM if needEmitMember(currRegion) => - emitMember(false, currRegion.owner) + val maybeNewIdent = emitMember(false, currRegion.owner) val template = expectTemplate match { case Some(expect) if expect.isCaseClassConstructor => newExpectCaseClassTemplate case _ => newExpectClassTemplate } - loop(indent, isAfterNewline = false, currRegion, template) + loop(maybeNewIdent.getOrElse(indent), isAfterNewline = maybeNewIdent.isDefined, currRegion, template) // also covers extension methods because of `def` inside case DEF // extension group @@ -485,30 +485,59 @@ class ScalaToplevelMtags( buf.result() } + @tailrec + private def acceptAllAfterOverriddenIdentifier(): Unit = { + scanner.curr.token match { + case LPAREN => + acceptBalancedDelimeters(LPAREN, RPAREN) + acceptAllAfterOverriddenIdentifier() + case LBRACKET => + acceptBalancedDelimeters(LBRACKET, RBRACKET) + acceptAllAfterOverriddenIdentifier() + case _ => + } + + } + + @tailrec + private def findOverridden(acc : List[Identifier]): (List[Identifier], Option[Int]) = { + val maybeNewIdent = acceptTrivia() + scanner.curr.token match { + case EXTENDS | WITH => + acceptTrivia() + val curr = newIdentifier.toList + acceptAllAfterOverriddenIdentifier() + findOverridden(curr ++ acc) + case _ => (acc, maybeNewIdent) + } + } + /** * Enters a toplevel symbol such as class, trait or object */ - def emitMember(isPackageObject: Boolean, owner: String): Unit = { + def emitMember(isPackageObject: Boolean, owner: String): Option[Int] = { val kind = scanner.curr.token acceptTrivia() val maybeName = newIdentifier currentOwner = owner + val (overridden0, maybeNewIdent) = findOverridden(List.empty) + val overridden = overridden0.map(id => (id.name, id.pos)) maybeName.foreach { name => kind match { case CLASS | ENUM => - tpe(name.name, name.pos, Kind.CLASS, 0) + tpe(name.name, name.pos, Kind.CLASS, 0, overridden) case TRAIT => - tpe(name.name, name.pos, Kind.TRAIT, 0) + tpe(name.name, name.pos, Kind.TRAIT, 0, overridden) case OBJECT => if (isPackageObject) { currentOwner = symbol(Scala.Descriptor.Package(name.name)) term("package", name.pos, Kind.OBJECT, 0) } else { - term(name.name, name.pos, Kind.OBJECT, 0) + term(name.name, name.pos, Kind.OBJECT, 0, overridden) } } } - scanner.nextToken() + maybeNewIdent } /** @@ -668,7 +697,9 @@ class ScalaToplevelMtags( } } - private def acceptTrivia(): Unit = { + private def acceptTrivia(): Option[Int] = { + var includedNewline = false + var ident = 0 scanner.nextToken() while ( !isDone && @@ -677,8 +708,15 @@ class ScalaToplevelMtags( case _ => false }) ) { + if(isNewline){ + includedNewline = true + ident = 0 + } else if(scanner.curr.token == WHITESPACE) { + ident += 1 + } scanner.nextToken() } + if(includedNewline) Some(ident) else None } private def nextIsNL(): Boolean = { diff --git a/mtags/src/main/scala/scala/meta/internal/mtags/UnresolvedOverriddenSymbol.scala b/mtags/src/main/scala/scala/meta/internal/mtags/UnresolvedOverriddenSymbol.scala new file mode 100644 index 00000000000..791bad1e680 --- /dev/null +++ b/mtags/src/main/scala/scala/meta/internal/mtags/UnresolvedOverriddenSymbol.scala @@ -0,0 +1,12 @@ +package scala.meta.internal.mtags + +object UnresolvedOverriddenSymbol { + def apply(name: String, pos: Int): String = + s"unresolved::$name::$pos" + + def unapply(unresolved: String): Option[(String, Int)] = + unresolved match { + case s"unresolved::$name::$pos" => pos.toIntOption.map((name, _)) + case _ => None + } +} diff --git a/tests/unit/src/test/scala/tests/ScalaToplevelSuite.scala b/tests/unit/src/test/scala/tests/ScalaToplevelSuite.scala index 312fa346954..86a049abc1c 100644 --- a/tests/unit/src/test/scala/tests/ScalaToplevelSuite.scala +++ b/tests/unit/src/test/scala/tests/ScalaToplevelSuite.scala @@ -4,6 +4,7 @@ import scala.meta.Dialect import scala.meta.dialects import scala.meta.inputs.Input import scala.meta.internal.mtags.Mtags +import scala.meta.internal.mtags.UnresolvedOverriddenSymbol import munit.TestOptions @@ -530,7 +531,7 @@ class ScalaToplevelSuite extends BaseSuite { | } |} |""".stripMargin, - List("a/", "a/TypeProxy#"), + List("a/", "a/TypeProxy# -> Type"), dialect = dialects.Scala3, mode = ToplevelWithInner, ) @@ -603,6 +604,7 @@ class ScalaToplevelSuite extends BaseSuite { expected: List[String], mode: Mode = Toplevel, dialect: Dialect = dialects.Scala3, + includeOverridden: Boolean = true )(implicit location: munit.Location): Unit = { test(options) { val input = Input.VirtualFile("Test.scala", code) @@ -612,8 +614,17 @@ class ScalaToplevelSuite extends BaseSuite { val includeMembers = mode == All Mtags .allToplevels(input, dialect, includeMembers) - .occurrences - .map(_.symbol) + .symbols + .map{ si => + if(!includeOverridden || si.overriddenSymbols.isEmpty) si.symbol + else { + val overridden = + si.overriddenSymbols.collect{ + case UnresolvedOverriddenSymbol(name, _) => name + }.mkString(", ") + s"${si.symbol} -> $overridden" + } + } .toList case Toplevel => Mtags.toplevels(input, dialect) }