Skip to content

Commit

Permalink
formatting local methods
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanelamyaghri committed Jul 18, 2023
1 parent b91e77a commit bdf9ed7
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ class Scala3Unpickler(
else matchingSymbols.headOption

def findLocalMethodOrLazyVal(declaringClass: ClassSymbol, name: String, index: Int): TermSymbol =
def findLocalSymbol(tree: Tree): Seq[TermSymbol] =
tree.walkTree {
case DefDef(_, _, _, _, symbol) if matchTargetName(name, symbol) => Seq(symbol)
case ValDef(_, _, _, symbol) if matchTargetName(name, symbol) => Seq(symbol)
case _ => Seq.empty
}(_ ++ _, Seq.empty)

val declaringClasses = declaringClass.companionClass match
case Some(companionClass) if companionClass.isSubclass(ctx.defn.AnyValClass) =>
Seq(declaringClass, companionClass)
Expand All @@ -97,14 +90,13 @@ class Scala3Unpickler(
for
declaringSym <- declaringClasses
decl <- declaringSym.declarations
tree <- decl.tree.toSeq
localSym <- findLocalSymbol(tree)
localSym <- findMatchingSymbols(decl, name)
yield localSym
if matchingSymbols.size < index
then
// TODO we cannot find the local symbol of Scala 2.13 classes, it should not throw
throw new Exception(s"Cannot find local symbol $name$$$index in ${declaringClass.name}")
matchingSymbols(index - 1)
matchingSymbols(index - 1).asTerm

def formatType(t: Type): String =
t match
Expand Down Expand Up @@ -245,53 +237,46 @@ class Scala3Unpickler(
if method.declaringType.isObject && !method.isExtensionMethod then obj.headOption else cls.headOption

private def findSymbolsRecursively(owner: DeclaringSymbol, encodedName: String): Seq[ClassSymbol] =
owner.declarations
.collect { case sym: ClassSymbol => sym }
.flatMap { sym =>
val encodedSymName = NameTransformer.encode(sym.name.toString)
val Symbol = s"${Regex.quote(encodedSymName)}\\$$?(.*)".r
encodedName match
case Symbol(remaining) =>
if remaining.isEmpty then Some(sym)
else findSymbolsRecursively(sym, remaining)
case _ => None
}
// if(a.isEmpty) walkingtree(owner,encodedName).toSeq else a

private def walkingtree( sym : DeclaringSymbol, remaining : String) : Option[DeclaringSymbol] = {

( sym.tree match
case Some(tree) =>
val x =tree.walkTree(tree =>

tree match
case ClassDef(_,_,symbol) =>
val Pattern = s"${Regex.quote(symbol.name.toString)}\\$$\\d+\\$$?(.*)".r
val xoo=symbol.name.toString
val xo = Regex.quote(symbol.name.toString)
remaining match
case Pattern(rem) =>
if(rem.isEmpty) List(symbol)
else List()
case _ => List()
case _ => List()

)((l1, l2) => l1 ++ l2, List())
if(x.isEmpty) None
else Some(x.head)

case None =>None)


}

val pattern = """^([^$]+)[$](\d+)[$]?(.*)$""".r
encodedName match
case pattern(className, index, remaining) =>
val sym = (for
decl <- owner.declarations
sym <- findMatchingSymbols(decl, className)
yield sym)(index.toInt - 1)
if remaining.isEmpty then Seq(sym.asClass)
else findSymbolsRecursively(sym.asDeclaringSymbol, remaining)
case _ =>
owner.declarations
.collect { case sym: ClassSymbol => sym }
.flatMap { sym =>
val encodedSymName = NameTransformer.encode(sym.name.toString)
val Symbol = s"${Regex.quote(encodedSymName)}\\$$?(.*)".r
encodedName match
case Symbol(remaining) =>
if remaining.isEmpty then Some(sym)
else findSymbolsRecursively(sym, remaining)
case _ => None
}

private def findMatchingSymbols(owner: Symbol, name: String): Seq[Symbol] =
owner.tree match
case Some(tree) =>
tree.walkTree {
case ClassDef(_, _, symbol) =>
if matchTargetName(name, symbol) && symbol.owner.isTerm then Seq(symbol) else Seq.empty
case DefDef(_, _, _, _, symbol) if matchTargetName(name, symbol) && symbol.owner.isTerm => Seq(symbol)
case ValDef(_, _, _, symbol) if matchTargetName(name, symbol) && symbol.owner.isTerm => Seq(symbol)
case _ => Seq.empty
}(_ ++ _, Seq.empty)
case None => Seq.empty

private def matchSymbol(method: jdi.Method, symbol: TermSymbol): Boolean =
matchTargetName(method, symbol) && (method.isTraitInitializer || matchSignature(method, symbol))

private def matchesLocalMethodOrLazyVal(method: jdi.Method): Option[(String, Int)] =
val javaPrefix = method.declaringType.name.replace('.', '$') + "$$"
val expectedName = method.name.stripPrefix(javaPrefix)
val expectedName = method.name.stripPrefix(javaPrefix).split("\\$_\\$").last
val pattern = """^(.+)[$](\d+)$""".r
expectedName match
case pattern(stringPart, numberPart) if (!stringPart.endsWith("$lzyINIT1") && !stringPart.endsWith("$default")) =>
Expand All @@ -312,8 +297,8 @@ class Scala3Unpickler(
if method.isExtensionMethod then encodedScalaName == expectedName.stripSuffix("$extension")
else encodedScalaName == expectedName

private def matchTargetName(expectedName: String, symbol: TermSymbol): Boolean =
val symbolName = symbol.targetName.toString
private def matchTargetName(expectedName: String, symbol: Symbol): Boolean =
val symbolName = symbol.name.toString
expectedName == NameTransformer.encode(symbolName)

private def matchSignature(method: jdi.Method, symbol: TermSymbol): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ abstract class Scala3UnpicklerTests(val scalaVersion: ScalaVersion) extends FunS
unpickler.assertNotFound("example.F$", javaSig)
unpickler.assertFormat("example.Main$G", javaSig, "Main.G.m(): String")
unpickler.assertNotFound("example.Main$H", javaSig)
unpickler.assertFailure("example.Main$$anon$1", javaSig)
unpickler.assertNotFound("example.Main$$anon$1", javaSig)
// TODO fix: we could find it by traversing the tree of `Main`
unpickler.assertFailure("example.Main$$anon$2", javaSig)
unpickler.assertFind("example.Main$$anon$2", javaSig)
}

test("local classes or local objects") {
Expand Down Expand Up @@ -100,43 +100,47 @@ abstract class Scala3UnpicklerTests(val scalaVersion: ScalaVersion) extends FunS
unpickler.assertFind("example.Main$B$2$", "void m()")
}

test("local classes or local objects within local method") {
test("local class and object with same name within a local method") {
val source =
"""|package example
|
|object Main3 {
|object Main {
| def main(args: Array[String]) = {
| class A {
| class C {
| def m(): Unit = {
| class D {
| println("A.m")
| def m1() : Unit = {
| println("")
| }
| }
| D().m1()
| class A {
| def m(t : Int) = {
|
| }
| }
| }
| object B {
| def m(): Unit = {
| println("B.m")
| }
| object A {
| def m(s : String) = {
|
| }
| }
|
| val a = A()
| val c = a.C()
| c.m()
| }
| }
|}
|""".stripMargin
val debuggee = TestingDebuggee.mainClass(source, "example.Main", scalaVersion)
val unpickler = getUnpickler(debuggee)
unpickler.assertFind("example.Main$A$1", "void m()")
unpickler.assertFind("example.Main$B$2$", "void m()")
unpickler.assertFind("example.Main$A$1$C", "void m()")
unpickler.assertFormat("example.Main$A$1", "void m(int t)", "Main.main.A.m(t: Int): Unit")
unpickler.assertFormat("example.Main$", "Main$A$3$ A$2(LazyRef A$lzy1$2)", "Main.main.A: A")
unpickler.assertFormat("example.Main$A$3$", "void m(java.lang.String s)", "Main.main.A.m(s: String): Unit")
}

test("local class in a local method in a local class in a local method") {
val source =
"""|package example
|object Main {
| def m =
| class A // Main$A$1
| class Bar :
| def A = ()
| def m =
| class A // Main$A$2
| def A = () // Main.example$Main$Bar$1$$_$A$3()
|}
|""".stripMargin
val debuggee = TestingDebuggee.mainClass(source, "example.Main", scalaVersion)
val unpickler = getUnpickler(debuggee)
unpickler.assertFormat("example.Main", "void example$Main$Bar$1$$_$A$3()", "Main.Foo.m.Bar.m.A: Unit")
}

test("local methods with same name") {
Expand Down

0 comments on commit bdf9ed7

Please sign in to comment.