Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decode variables and fields #729

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ import com.microsoft.java.debug.core.adapter.{StackTraceProvider => JavaStackTra
import com.microsoft.java.debug.core.protocol.Requests.StepFilters
import com.sun.jdi.Location
import com.sun.jdi.Method
import com.sun.jdi.LocalVariable
import com.sun.jdi.Field
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedMethod
import ch.epfl.scala.debugadapter.DebugConfig
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField

class StackTraceProvider(
stepFilters: Seq[StepFilter],
Expand All @@ -22,14 +26,20 @@ class StackTraceProvider(
override def decode(method: Method): DecodedMethod =
decoder.map(_.decode(method)).getOrElse(JavaMethod(method, isGenerated = false))

override def decode(variable: LocalVariable, method: Method, sourceLine: Int): DecodedVariable =
decoder.map(_.decode(variable, method, sourceLine)).getOrElse(JavaVariable(variable))

override def decode(field: Field): DecodedField =
decoder.map(_.decode(field)).getOrElse(JavaField(field))

override def skipOver(method: Method, filters: StepFilters): Boolean = {
try {
val skipOver = super.skipOver(method, filters) || stepFilters.exists(_.skipOver(method))
if (skipOver) logger.debug(s"Skipping over $method")
skipOver
} catch {
case cause: Throwable =>
throwOrWarn(s"Failed to determine if $method should be skipped over: ${cause.getMessage}")
throwOrWarn(s"Failed to determine if $method should be skipped over", cause)
false
}
}
Expand All @@ -43,7 +53,7 @@ class StackTraceProvider(
skipOut
} catch {
case cause: Throwable =>
throwOrWarn(s"Failed to determine if $method should be skipped out: ${cause.getMessage}")
throwOrWarn(s"Failed to determine if $method should be skipped out", cause)
false
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ch.epfl.scala.debugadapter.internal.stacktrace

import ch.epfl.scala.debugadapter.internal.Errors
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField

import java.lang.reflect.InvocationTargetException

class DecodedFieldBridge(instance: Any) extends DecodedField {

override def show(): Boolean = invoke[Boolean]("show")

override def format(): String = invoke[String]("format")

private def invoke[T](methodName: String): T =
try instance.getClass.getMethod(methodName).invoke(instance).asInstanceOf[T]
catch { case e: InvocationTargetException => throw Errors.frameDecodingFailure(e.getCause) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ch.epfl.scala.debugadapter.internal.stacktrace

import ch.epfl.scala.debugadapter.internal.Errors
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable

import java.lang.reflect.InvocationTargetException

class DecodedVariableBridge(instance: Any) extends DecodedVariable {

override def format(): String = invoke[String]("format")

private def invoke[T](methodName: String): T =
try instance.getClass.getMethod(methodName).invoke(instance).asInstanceOf[T]
catch {
case e: InvocationTargetException =>
throw Errors.frameDecodingFailure(e.getCause)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ch.epfl.scala.debugadapter.internal.stacktrace

import com.sun.jdi
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField

final case class JavaField(field: jdi.Field) extends DecodedField {

override def show(): Boolean =
!field.isStatic() || field.declaringType.name.endsWith("$")

def format: String = {
field.name()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ch.epfl.scala.debugadapter.internal.stacktrace

import com.sun.jdi
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable

final case class JavaVariable(variable: jdi.LocalVariable) extends DecodedVariable {
def format: String = {
variable.name()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import ch.epfl.scala.debugadapter.internal.scalasig.ScalaSigPrinter
import ch.epfl.scala.debugadapter.internal.scalasig.*
import ch.epfl.scala.debugadapter.internal.stacktrace.JdiExtensions.*
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedMethod
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField

import com.sun.jdi

import scala.jdk.CollectionConverters.*
Expand Down Expand Up @@ -76,6 +79,12 @@ class Scala2Decoder(
override def decode(method: jdi.Method): DecodedMethod =
JavaMethod(method, isGenerated = skipOver(method))

override def decode(variable: jdi.LocalVariable, method: jdi.Method, sourceLine: Int): DecodedVariable =
JavaVariable(variable)

override def decode(field: jdi.Field): DecodedField =
JavaField(field)

private def containsLazyField(interface: jdi.InterfaceType, fieldName: String): Boolean = {
val fqcn = interface.name
sourceLookUp.getScalaSig(fqcn).exists(containsLazyField(_, fieldName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import ch.epfl.scala.debugadapter.internal.ByteCode
import ch.epfl.scala.debugadapter.internal.ThrowOrWarn
import ch.epfl.scala.debugadapter.internal.stacktrace.JdiExtensions.*
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedMethod
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField
import com.sun.jdi

import scala.util.control.NonFatal
Expand Down Expand Up @@ -43,6 +45,29 @@ class Scala3Decoder(
JavaMethod(method, isGenerated = method.isBridge)
}

override def decode(variable: jdi.LocalVariable, method: jdi.Method, sourceLine: Int): DecodedVariable =
try
if (method.declaringType().isDynamicClass) {
JavaVariable(variable)
} else if (method.isJava) {
JavaVariable(variable)
} else if (method.isStaticMain || method.isStaticConstructor) {
JavaVariable(variable)
} else bridge.decode(variable, method, sourceLine)
catch {
case NonFatal(e) =>
throwOrWarn(e)
JavaVariable(variable)
}

override def decode(field: jdi.Field): DecodedField =
try bridge.decode(field)
catch {
case NonFatal(e) =>
throwOrWarn(e)
JavaField(field)
}

override def reload(): Unit =
bridge = Scala3DecoderBridge(debuggee, classLoader, logger, testMode)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,44 @@ import ch.epfl.scala.debugadapter.Java9OrAbove
import ch.epfl.scala.debugadapter.Logger
import ch.epfl.scala.debugadapter.internal.Errors
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedMethod
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField
import com.sun.jdi

import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
// import java.lang.reflect.Field
import java.nio.file.Files
import java.nio.file.Path
import java.util.function.Consumer
import scala.jdk.CollectionConverters.*
// import sourcecode.Macros.Chunk.Obj

private class Scala3DecoderBridge(
instance: Any,
decodeMethod: Method
decodeMethod: Method,
decodeVariable: Method,
decodeField: Method
) {
def decode(method: jdi.Method): DecodedMethod =
try new DecodedMethodBridge(decodeMethod.invoke(instance, method))
catch {
case e: InvocationTargetException => throw Errors.frameDecodingFailure(e.getCause)
}

def decode(variable: jdi.LocalVariable, method: jdi.Method, sourceLine: Int): DecodedVariable =
try {
val res = decodeVariable.invoke(instance, variable, method, sourceLine.asInstanceOf[Object])
new DecodedVariableBridge(res)
} catch {
case e: InvocationTargetException => throw Errors.frameDecodingFailure(e.getCause)
}

def decode(field: jdi.Field): DecodedField =
try new DecodedFieldBridge(decodeField.invoke(instance, field))
catch {
case e: InvocationTargetException => throw Errors.frameDecodingFailure(e.getCause)
}
}

private object Scala3DecoderBridge {
Expand All @@ -32,7 +52,9 @@ private object Scala3DecoderBridge {
val cls = classLoader.loadClass(className)
val instance = newInstance(debuggee, cls, logger, testMode)
val decodeMethod = cls.getMethod("decode", classOf[jdi.Method])
new Scala3DecoderBridge(instance, decodeMethod)
val decodeVariable = cls.getMethod("decode", classOf[jdi.LocalVariable], classOf[jdi.Method], classOf[Int])
val decodeField = cls.getMethod("decode", classOf[jdi.Field])
new Scala3DecoderBridge(instance, decodeMethod, decodeVariable, decodeField)
}

private def newInstance(debuggee: Debuggee, decoderClass: Class[?], logger: Logger, testMode: Boolean) = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ import ch.epfl.scala.debugadapter.internal.ScalaExtension.*
import com.sun.jdi
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedMethod
import scala.util.Try
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedVariable
import com.microsoft.java.debug.core.adapter.stacktrace.DecodedField

trait ScalaDecoder extends StepFilter {
def decode(method: jdi.Method): DecodedMethod
def decode(variable: jdi.LocalVariable, method: jdi.Method, sourceLine: Int): DecodedVariable
def decode(field: jdi.Field): DecodedField
def reload(): Unit
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ch.epfl.scala.debugadapter.internal

import ch.epfl.scala.decoder.DecodedField
import ch.epfl.scala.decoder.StackTraceFormatter
import tastyquery.Symbols.*
import tastyquery.Modifiers.*
import tastyquery.Names.*
import ch.epfl.scala.decoder.DecodedField.ValDef
import ch.epfl.scala.decoder.DecodedField.ModuleVal
import ch.epfl.scala.decoder.DecodedField.LazyValOffset
import ch.epfl.scala.decoder.DecodedField.Outer
import ch.epfl.scala.decoder.DecodedField.Capture
import ch.epfl.scala.decoder.DecodedField.LazyValBitmap

class DecodedFieldBridge(field: DecodedField):
def format: String = field match
case field: ValDef => format(field.symbol.name)
case field: ModuleVal => ""
case field: LazyValOffset => ""
case field: Outer => "<outer>"
case field: ch.epfl.scala.decoder.DecodedField.SerialVersionUID => ""
case field: Capture => field.symbol.name.toString()
case field: LazyValBitmap => ""

def show: Boolean = true

// formatter.format(variable)
private def format(name: Name): String =
def rec(name: Name): String = name match
case DefaultGetterName(termName, num) => s"${termName.toString()}.<default ${num + 1}>"
case name: TypeName => rec(name.toTermName)
case SimpleName("$anonfun") => "<anon fun>"
case SimpleName("$anon") => "<anon class>"
case ObjectClassName(underlying) => rec(underlying)
case UniqueName(SimpleName(""), _, _) => "<anon>"
case _ => name.toString
rec(name)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ch.epfl.scala.debugadapter.internal

import ch.epfl.scala.decoder.DecodedVariable
import ch.epfl.scala.decoder.StackTraceFormatter
import tastyquery.Symbols.*
import tastyquery.Modifiers.*
import ch.epfl.scala.decoder.DecodedVariable.ValDef
import ch.epfl.scala.decoder.DecodedVariable.CapturedVariable
import ch.epfl.scala.decoder.DecodedVariable.This
import ch.epfl.scala.decoder.DecodedVariable.AnyValThis

class DecodedVariableBridge(variable: DecodedVariable):
def format: String = variable match
case v: ValDef => v.symbol.name.toString
case v: CapturedVariable => v.symbol.name.toString
case v: This => "this"
case v: AnyValThis => v.symbol.name.toString

// formatter.format(variable)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import ch.epfl.scala.decoder.binary
import java.nio.file.Path
import java.util.function.Consumer
import ch.epfl.scala.decoder.*
import ch.epfl.scala.decoder.jdi.JdiMethod
import ch.epfl.scala.decoder.jdi.*

class Scala3DecoderBridge(
classEntries: Array[Path],
Expand All @@ -20,3 +20,11 @@ class Scala3DecoderBridge(

def decode(obj: com.sun.jdi.Method): DecodedMethodBridge =
new DecodedMethodBridge(decoder.decode(JdiMethod(obj)), formatter)

// TODO //
// methode qui decode des variables pr l'appeler dans le Scala3DecoderBridge apply
def decode(obj: com.sun.jdi.LocalVariable, method: com.sun.jdi.Method, sourceLine: Int): DecodedVariableBridge =
new DecodedVariableBridge(decoder.decode(JdiVariable(obj, method), sourceLine))

def decode(obj: com.sun.jdi.Field): DecodedFieldBridge =
new DecodedFieldBridge(decoder.decode(JdiField(obj)))
Loading
Loading