Skip to content

Commit

Permalink
Merge pull request #381 from adpi2/fix-target-name
Browse files Browse the repository at this point in the history
Fix stepping into method with @TargetNAME
  • Loading branch information
adpi2 authored Mar 8, 2023
2 parents 75f7f72 + bdeb4e6 commit f1a7f09
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 31 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ lazy val scala3StepFilter: Project = project
scalaVersion := Dependencies.scala31Plus,
Compile / doc / sources := Seq.empty,
libraryDependencies ++= Seq(
"ch.epfl.scala" %% "tasty-query" % "0.5.7",
"ch.epfl.scala" %% "tasty-query" % "0.6.1",
"org.scala-lang" %% "tasty-core" % scalaVersion.value,
Dependencies.munit % Test
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,7 @@ class ScalaStepFilterBridge(
.collect { case sym: TermSymbol if sym.isTerm => sym }
yield term

private def findDeclaringType(
fqcn: String,
isExtensionMethod: Boolean
): Option[DeclaringSymbol] =
private def findDeclaringType(fqcn: String, isExtensionMethod: Boolean): Option[DeclaringSymbol] =
val javaParts = fqcn.split('.')
val isObject = fqcn.endsWith("$")
val packageNames = javaParts.dropRight(1).toList.map(SimpleName.apply)
Expand All @@ -75,36 +72,30 @@ class ScalaStepFilterBridge(
then ctx.findSymbolFromRoot(packageNames).asInstanceOf[PackageSymbol]
else ctx.defn.EmptyPackage
val className = javaParts.last
def findRec(
owner: DeclaringSymbol,
encodedName: String
): Seq[DeclaringSymbol] =
owner.declarations
.collect { case sym: DeclaringSymbol => 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 findRec(sym, remaining)
case _ => None
}
val clsSymbols = findRec(packageSym, className)
val clsSymbols = findSymbolsRecursively(packageSym, className)
val obj = clsSymbols.filter(_.is(Flags.Module))
val cls = clsSymbols.filter(!_.is(Flags.Module))
assert(obj.size <= 1 && cls.size <= 1)
if isObject && !isExtensionMethod then obj.headOption else cls.headOption

private def matchSymbol(
method: jdi.Method,
symbol: TermSymbol,
isExtensionMethod: Boolean
): Boolean =
matchName(method, symbol, isExtensionMethod) &&
private def findSymbolsRecursively(owner: DeclaringSymbol, encodedName: String): Seq[DeclaringSymbol] =
owner.declarations
.collect { case sym: DeclaringSymbol => 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 matchSymbol(method: jdi.Method, symbol: TermSymbol, isExtensionMethod: Boolean): Boolean =
matchTargetName(method, symbol, isExtensionMethod) &&
matchSignature(method, symbol, isExtensionMethod)

def matchName(
def matchTargetName(
method: jdi.Method,
symbol: TermSymbol,
isExtensionMethod: Boolean
Expand All @@ -114,7 +105,7 @@ class ScalaStepFilterBridge(
// and prefixes its name with the full class name.
// Example: method foo in class example.Inner becomes example$Inner$$foo
val expectedName = method.name.stripPrefix(javaPrefix)
val encodedScalaName = NameTransformer.encode(symbol.name.toString)
val encodedScalaName = NameTransformer.encode(symbol.targetName.toString)
if isExtensionMethod then encodedScalaName == expectedName.stripSuffix("$extension")
else encodedScalaName == expectedName

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,27 @@ package ch.epfl.scala.debugadapter

import ch.epfl.scala.debugadapter.testfmk.*

class Scala3StepFilterTests extends StepFilterTests(ScalaVersion.`3.1+`)
class Scala3StepFilterTests extends StepFilterTests(ScalaVersion.`3.1+`) {
test("step into method with @targetName") {
val source =
"""|package example
|
|import scala.annotation.targetName
|
|object Main {
| def main(args: Array[String]): Unit =
| m("Hello")
|
| @targetName("mTarget")
| def m(message: String): Unit =
| println(message)
|}
|""".stripMargin
implicit val debuggee: TestingDebuggee = TestingDebuggee.mainClass(source, "example.Main", scalaVersion)
check(Breakpoint(7), StepIn.method("Main$.mTarget(String)"))
}
}

class Scala212StepFilterTests extends StepFilterTests(ScalaVersion.`2.12`)
class Scala213StepFilterTests extends StepFilterTests(ScalaVersion.`2.13`) {
test("should match all kinds of Scala 2 types (not valid in Scala 3)") {
Expand Down Expand Up @@ -31,7 +51,7 @@ class Scala213StepFilterTests extends StepFilterTests(ScalaVersion.`2.13`) {
}
}

abstract class StepFilterTests(scalaVersion: ScalaVersion) extends DebugTestSuite {
abstract class StepFilterTests(protected val scalaVersion: ScalaVersion) extends DebugTestSuite {
test("should not step into mixin forwarder") {
val source =
"""|package example
Expand Down

0 comments on commit f1a7f09

Please sign in to comment.