From 6821547c921934c4decbe4bf18d1e1735aa0fd80 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sat, 28 Jan 2017 23:08:46 -0600 Subject: [PATCH 01/36] Added some frozen classes (not finished) --- .../api/profiles/frozen/FrozenException.scala | 39 ++++ .../frozen/info/FrozenCommonInfo.scala | 21 +++ .../profiles/frozen/info/FrozenJavaInfo.scala | 24 +++ .../profiles/frozen/info/FrozenTypeInfo.scala | 17 ++ .../frozen/info/FrozenTypeInfoLike.scala | 113 ++++++++++++ .../frozen/info/FrozenValueInfo.scala | 23 +++ .../frozen/info/FrozenValueInfoLike.scala | 173 ++++++++++++++++++ 7 files changed, 410 insertions(+) create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala new file mode 100644 index 00000000..4b7a9e47 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala @@ -0,0 +1,39 @@ +package org.scaladebugger.api.profiles.frozen + +/** + * Represents a generic frozen exception that occurs only on frozen entities. + */ +sealed trait FrozenException extends Exception + +/** + * Represents an exception thrown when trying to invoke a method on + * a frozen entity. + */ +case object InvocationFrozenException + extends FrozenException("Method cannot be invoked while frozen!") + +/** + * Represents an exception thrown when trying to access data on a frozen + * entity that is unavailable. + */ +case object DataUnavailableFrozenException + extends FrozenException("Data is unavailable while frozen!") + +/** + * Represents an exception thrown when trying to cast to another value which + * is incorrect for the frozen type. + */ +case object InvalidCastFrozenException + extends FrozenException("Invalid cast type on frozen entity!") + +/** + * Represents an exception thrown when trying to freeze. + * + * @param cause The cause of the exception + */ +case class UnexpectedErrorFrozenException( + cause: Exception +) extends FrozenException( + "An unexpected error was encountered when freezing!", + cause +) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala new file mode 100644 index 00000000..47080f85 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala @@ -0,0 +1,21 @@ +package org.scaladebugger.api.profiles.frozen.info + +import com.sun.jdi.Mirror +import org.scaladebugger.api.profiles.frozen.DataUnavailableFrozenException +import org.scaladebugger.api.profiles.traits.info.CommonInfo +import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine + +/** + * Represents a frozen implementation of the common info trait. + */ +trait FrozenCommonInfo extends CommonInfo with FrozenJavaInfo { + /** Unavailable on frozen entity. */ + @throws[UnavailableDataFrozenException] + override def scalaVirtualMachine: ScalaVirtualMachine = + throw new UnavailableDataFrozenException("scalaVirtualMachine") + + /** Unavailable on frozen entity. */ + @throws[UnavailableDataFrozenException] + override def toJdiInstance: Mirror = + throw new UnavailableDataFrozenException("JDI Instance") +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala new file mode 100644 index 00000000..2d984893 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala @@ -0,0 +1,24 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.frozen.InvocationFrozenException +import org.scaladebugger.api.profiles.traits.info.JavaInfo + +/** + * Represents a frozen implementation of the Java info trait. + */ +trait FrozenJavaInfo extends JavaInfo { + /** + * Returns whether or not this info profile represents the low-level Java + * implementation. + * + * @return If true, this profile represents the low-level Java information, + * otherwise this profile represents something higher-level like + * Scala, Jython, or JRuby + */ + override def isJavaInfo: Boolean = false + + /** Unavailable on frozen entity. */ + @throws[InvocationFrozenException] + override def toJavaInfo: AnyRef = + throw new InvocationFrozenException("toJavaInfo") +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala new file mode 100644 index 00000000..1206e98b --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala @@ -0,0 +1,17 @@ +package org.scaladebugger.api.profiles.frozen.info +import org.scaladebugger.api.profiles.frozen.FrozenException +import org.scaladebugger.api.profiles.traits.info._ + +/** + * Represents type information frozen (snapshot at a point in time) for a remote + * JVM. + */ +case class FrozenTypeInfo( + name: String, + signature: String, + protected val arrayType: Either[FrozenException, ArrayTypeInfo], + protected val classType: Either[FrozenException, ClassTypeInfo], + protected val interfaceType: Either[FrozenException, InterfaceTypeInfo], + protected val referenceType: Either[FrozenException, ReferenceTypeInfo], + protected val primitiveType: Either[FrozenException, PrimitiveTypeInfo] +) extends FrozenTypeInfoLike diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala new file mode 100644 index 00000000..74131cac --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala @@ -0,0 +1,113 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.frozen.FrozenException +import org.scaladebugger.api.profiles.traits.info._ + +/** Represents a frozen instance of some type information on a remote JVM. */ +trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { + protected val arrayType: Either[FrozenException, ArrayTypeInfo] + protected val classType: Either[FrozenException, ClassTypeInfo] + protected val interfaceType: Either[FrozenException, InterfaceTypeInfo] + protected val referenceType: Either[FrozenException, ReferenceTypeInfo] + protected val primitiveType: Either[FrozenException, PrimitiveTypeInfo] + + /** + * Returns whether or not this type represents an array type. + * + * @return True if an array type, otherwise false + */ + override def isArrayType: Boolean = arrayType.isRight + + /** + * Returns whether or not this type represents a class type. + * + * @return True if a class type, otherwise false + */ + override def isClassType: Boolean = classType.isRight + + /** + * Returns whether or not this type represents an interface type. + * + * @return True if an interface type, otherwise false + */ + override def isInterfaceType: Boolean = interfaceType.isRight + + /** + * Returns whether or not this type represents a reference type. + * + * @return True if a reference type, otherwise false + */ + override def isReferenceType: Boolean = referenceType.isRight + + /** + * Returns whether or not this type represents a primitive type. + * + * @return True if a primitive type, otherwise false + */ + override def isPrimitiveType: Boolean = primitiveType.isRight + + /** + * Returns whether or not this type is for a value that is null. + * + * @return True if representing the type of a null value, otherwise false + */ + override def isNullType: Boolean = !( + isArrayType || isClassType || isInterfaceType || + isReferenceType || isPrimitiveType + ) + + /** + * Returns the type as an array type (profile). + * + * @return The array type profile wrapping this type + */ + @throws[FrozenException] + override def toArrayType: ArrayTypeInfo = arrayType match { + case Left(e) => throw e + case Right(t) => t + } + + /** + * Returns the type as an class type (profile). + * + * @return The class type profile wrapping this type + */ + @throws[FrozenException] + override def toClassType: ClassTypeInfo = classType match { + case Left(e) => throw e + case Right(t) => t + } + + /** + * Returns the type as an interface type (profile). + * + * @return The interface type profile wrapping this type + */ + @throws[FrozenException] + override def toInterfaceType: InterfaceTypeInfo = interfaceType match { + case Left(e) => throw e + case Right(t) => t + } + + /** + * Returns the type as an reference type (profile). + * + * @return The reference type profile wrapping this type + */ + @throws[FrozenException] + override def toReferenceType: ReferenceTypeInfo = referenceType match { + case Left(e) => throw e + case Right(t) => t + } + + /** + * Returns the type as an primitive type (profile). + * + * @return The primitive type profile wrapping this type + */ + @throws[FrozenException] + override def toPrimitiveType: PrimitiveTypeInfo = primitiveType match { + case Left(e) => throw e + case Right(t) => t + } +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala new file mode 100644 index 00000000..e3487480 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala @@ -0,0 +1,23 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.frozen.FrozenException +import org.scaladebugger.api.profiles.traits.info._ + +/** + * Represents value information frozen (snapshot at a point in time) for a + * remote JVM. + */ +case class FrozenValueInfo( + `type`: TypeInfo, + isNull: Boolean, + isVoid: Boolean, + protected val localValue: Either[FrozenException, Any], + protected val arrayInfo: Either[FrozenException, ArrayInfo], + protected val stringInfo: Either[FrozenException, StringInfo], + protected val objectInfo: Either[FrozenException, ObjectInfo], + protected val threadInfo: Either[FrozenException, ThreadInfo], + protected val threadGroupInfo: Either[FrozenException, ThreadGroupInfo], + protected val classObjectInfo: Either[FrozenException, ClassObjectInfo], + protected val classLoaderInfo: Either[FrozenException, ClassLoaderInfo], + protected val primitiveInfo: Either[FrozenException, PrimitiveInfo] +) extends FrozenValueInfoLike diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala new file mode 100644 index 00000000..5e508b12 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala @@ -0,0 +1,173 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.frozen.FrozenException +import org.scaladebugger.api.profiles.traits.info._ + +trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { + override val isNull: Boolean + override val isVoid: Boolean + protected val localValue: Either[FrozenException, Any] + protected val arrayInfo: Either[FrozenException, ArrayInfo] + protected val stringInfo: Either[FrozenException, StringInfo] + protected val objectInfo: Either[FrozenException, ObjectInfo] + protected val threadInfo: Either[FrozenException, ThreadInfo] + protected val threadGroupInfo: Either[FrozenException, ThreadGroupInfo] + protected val classObjectInfo: Either[FrozenException, ClassObjectInfo] + protected val classLoaderInfo: Either[FrozenException, ClassLoaderInfo] + protected val primitiveInfo: Either[FrozenException, PrimitiveInfo] + + /** + * Returns whether or not this value represents a primitive. + * + * @return True if a primitive, otherwise false + */ + override def isPrimitive: Boolean = primitiveInfo.isRight + + /** + * Returns whether or not this value represents an array. + * + * @return True if an array, otherwise false + */ + override def isArray: Boolean = arrayInfo.isRight + + /** + * Returns whether or not this value represents a class loader. + * + * @return True if a class loader, otherwise false + */ + override def isClassLoader: Boolean = classLoaderInfo.isRight + + /** + * Returns whether or not this value represents a class object. + * + * @return True if a class object, otherwise false + */ + override def isClassObject: Boolean = classObjectInfo.isRight + + /** + * Returns whether or not this value represents a thread group. + * + * @return True if a thread group, otherwise false + */ + override def isThreadGroup: Boolean = threadGroupInfo.isRight + + /** + * Returns whether or not this value represents a thread. + * + * @return True if a thread, otherwise false + */ + override def isThread: Boolean = threadInfo.isRight + + /** + * Returns whether or not this value represents an object. + * + * @return True if an object, otherwise false + */ + override def isObject: Boolean = objectInfo.isRight + + /** + * Returns whether or not this value represents a string. + * + * @return True if a string, otherwise false + */ + override def isString: Boolean = stringInfo.isRight + + /** + * Returns the value as a value local to this JVM. + * + * @return The value as a local instance + */ + @throws[FrozenException] + override def toLocalValue: Any = localValue match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as a primitive (profile). + * + * @return The primitive profile wrapping this value + */ + @throws[FrozenException] + override def toPrimitiveInfo: PrimitiveInfo = primitiveInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as a class loader (profile). + * + * @return The class loader profile wrapping this value + */ + @throws[FrozenException] + override def toClassLoaderInfo: ClassLoaderInfo = classLoaderInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as a class object (profile). + * + * @return The class object profile wrapping this value + */ + @throws[FrozenException] + override def toClassObjectInfo: ClassObjectInfo = classObjectInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as a thread group (profile). + * + * @return The thread group profile wrapping this value + */ + @throws[FrozenException] + override def toThreadGroupInfo: ThreadGroupInfo = threadGroupInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as a thread (profile). + * + * @return The thread profile wrapping this value + */ + @throws[FrozenException] + override def toThreadInfo: ThreadInfo = threadInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as an object (profile). + * + * @return The object profile wrapping this value + */ + @throws[FrozenException] + override def toObjectInfo: ObjectInfo = objectInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as an string (profile). + * + * @return The string profile wrapping this value + */ + @throws[FrozenException] + override def toStringInfo: StringInfo = stringInfo match { + case Left(e) => throw e + case Right(v) => v + } + + /** + * Returns the value as an array (profile). + * + * @return The array profile wrapping this value + */ + @throws[FrozenException] + override def toArrayInfo: ArrayInfo = arrayInfo match { + case Left(e) => throw e + case Right(v) => v + } +} From fcc65f22ccf0d0219a1e6d18ed78e015821d3026 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 31 Jan 2017 21:20:22 -0600 Subject: [PATCH 02/36] Unfinished work on frozen api --- .../frozen/info/FrozenCommonInfo.scala | 11 +- .../frozen/info/FrozenCreateInfo.scala | 19 ++ .../profiles/frozen/info/FrozenJavaInfo.scala | 7 +- .../info/FrozenReferenceTypeInfoLike.scala | 233 ++++++++++++++++++ .../profiles/frozen/info/FrozenTypeInfo.scala | 13 +- .../frozen/info/FrozenTypeInfoLike.scala | 47 ++-- .../frozen/info/FrozenValueInfo.scala | 21 +- .../frozen/info/FrozenValueInfoLike.scala | 81 +++--- 8 files changed, 323 insertions(+), 109 deletions(-) create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala index 47080f85..72fa0965 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala @@ -1,7 +1,7 @@ package org.scaladebugger.api.profiles.frozen.info import com.sun.jdi.Mirror -import org.scaladebugger.api.profiles.frozen.DataUnavailableFrozenException +import org.scaladebugger.api.profiles.frozen.{DataUnavailableFrozenException, FrozenException} import org.scaladebugger.api.profiles.traits.info.CommonInfo import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine @@ -10,12 +10,11 @@ import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine */ trait FrozenCommonInfo extends CommonInfo with FrozenJavaInfo { /** Unavailable on frozen entity. */ - @throws[UnavailableDataFrozenException] + @throws[FrozenException] override def scalaVirtualMachine: ScalaVirtualMachine = - throw new UnavailableDataFrozenException("scalaVirtualMachine") + throw DataUnavailableFrozenException /** Unavailable on frozen entity. */ - @throws[UnavailableDataFrozenException] - override def toJdiInstance: Mirror = - throw new UnavailableDataFrozenException("JDI Instance") + @throws[FrozenException] + override def toJdiInstance: Mirror = throw DataUnavailableFrozenException } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala new file mode 100644 index 00000000..bd24e0c4 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala @@ -0,0 +1,19 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.frozen.{FrozenException, InvocationFrozenException} +import org.scaladebugger.api.profiles.traits.info.{CreateInfo, ValueInfo} + +/** + * Represents a frozen implementation of the create info trait. + */ +trait FrozenCreateInfo extends CreateInfo { + /** Unavailable on frozen entity. */ + @throws[FrozenException] + override def createRemotely(value: AnyVal): ValueInfo = + throw InvocationFrozenException + + /** Unavailable on frozen entity. */ + @throws[FrozenException] + override def createRemotely(value: String): ValueInfo = + throw InvocationFrozenException +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala index 2d984893..71754d69 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala @@ -1,6 +1,6 @@ package org.scaladebugger.api.profiles.frozen.info -import org.scaladebugger.api.profiles.frozen.InvocationFrozenException +import org.scaladebugger.api.profiles.frozen.{FrozenException, InvalidCastFrozenException} import org.scaladebugger.api.profiles.traits.info.JavaInfo /** @@ -18,7 +18,6 @@ trait FrozenJavaInfo extends JavaInfo { override def isJavaInfo: Boolean = false /** Unavailable on frozen entity. */ - @throws[InvocationFrozenException] - override def toJavaInfo: AnyRef = - throw new InvocationFrozenException("toJavaInfo") + @throws[FrozenException] + override def toJavaInfo: AnyRef = throw InvalidCastFrozenException } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala new file mode 100644 index 00000000..2c7f4dc7 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala @@ -0,0 +1,233 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.frozen.FrozenException +import org.scaladebugger.api.profiles.traits.info._ + +import scala.util.Try + +/** + * Represents type information frozen (snapshot at a point in time) for a remote + * JVM. + */ +trait FrozenReferenceTypeInfoLike extends ReferenceTypeInfo with FrozenTypeInfoLike { + protected val _allFields: Try[Seq[FieldVariableInfo]] + protected val _visibleFields: Try[Seq[FieldVariableInfo]] + protected val _indexedVisibleFields: Try[Seq[FieldVariableInfo]] + + /** + * Retrieves all fields declared in this type, its superclasses, implemented + * interfaces, and superinterfaces. + * + * @return The collection of fields as variable info profiles + */ + @throws[FrozenException] + override def allFields: Seq[FieldVariableInfo] = _allFields.get + + /** + * Retrieves unhidden and unambiguous fields in this type. Fields hidden + * by other fields with the same name (in a more recently inherited class) + * are not included. Fields that are ambiguously multiply inherited are also + * not included. All other inherited fields are included. + * + * @return The collection of fields as variable info profiles + */ + @throws[FrozenException] + override def visibleFields: Seq[FieldVariableInfo] = _visibleFields.get + + /** + * Retrieves unhidden and unambiguous fields in this type. Fields hidden + * by other fields with the same name (in a more recently inherited class) + * are not included. Fields that are ambiguously multiply inherited are also + * not included. All other inherited fields are included. Offset index + * information is included. + * + * @return The collection of fields as variable info profiles + */ + override def indexedVisibleFields: Seq[FieldVariableInfo] = + _indexedVisibleFields.get + + /** + * Retrieves the visible field with the matching name with offset index + * information. + * + * @param name The name of the field to retrieve + * @return Some field as a variable info profile, or None if doesn't exist + */ + override def indexedFieldOption(name: String): Option[FieldVariableInfo] = + _indexedVisibleFields.get.find(_.name == name) + + /** + * Retrieves the visible field with the matching name. + * + * @param name The name of the field to retrieve + * @return Some field as a variable info profile, or None if doesn't exist + */ + override def fieldOption(name: String): Option[FieldVariableInfo] = + _visibleFields.get.find(_.name == name) + + /** + * Retrieves all methods declared in this type, its superclasses, implemented + * interfaces, and superinterfaces. + * + * @return The collection of methods as method info profiles + */ + override def allMethods: Seq[MethodInfo] = ??? + + /** + * Retrieves unhidden and unambiguous methods in this type. Methods hidden + * by other methods with the same name (in a more recently inherited class) + * are not included. Methods that are ambiguously multiply inherited are also + * not included. All other inherited methods are included. + * + * @return The collection of methods as method info profiles + */ + override def visibleMethods: Seq[MethodInfo] = ??? + + /** + * Retrieves the visible methods with the matching name. + * + * @param name The name of the method to retrieve + * @return The collection of method info profiles + */ + override def methods(name: String): Seq[MethodInfo] = ??? + + /** + * Retrieves the classloader object which loaded the class associated with + * this type. + * + * @return Some profile representing the classloader, + * otherwise None if loaded through the bootstrap classloader + */ + override def classLoaderOption: Option[ClassLoaderInfo] = ??? + + /** + * Retrieves the class object associated with this type. + * + * @return The profile representing the class + */ + override def classObject: ClassObjectInfo = ??? + + /** + * Retrieves the generic signature type if it exists. + * + * @return Some signature if it exists, otherwise None + */ + override def genericSignature: Option[String] = ??? + + /** + * Retrieves reachable instances of this type. + * + * @param maxInstances The maximum number of instances to return, or zero + * to get all reachable instances + * @return The collection of object instances + */ + override def instances(maxInstances: Long): Seq[ObjectInfo] = ??? + + /** + * Indicates whether or not this type is abstract. + * + * @return True if abstract, otherwise false + */ + override def isAbstract: Boolean = ??? + + /** + * Indicates whether or not this type is final. + * + * @return True if final, otherwise false + */ + override def isFinal: Boolean = ??? + + /** + * Indicates whether or not this type has been initialized. This value is + * the same as isPrepared for interfaces and is undefined for arrays and + * primitive types. + * + * @return True if initialized, otherwise false + */ + override def isInitialized: Boolean = ??? + + /** + * Indicates whether or not this type's class has been prepared. + * + * @return True if prepared, otherwise false + */ + override def isPrepared: Boolean = ??? + + /** + * Indicates whether or not this type is static. + * + * @return True if static, otherwise false + */ + override def isStatic: Boolean = ??? + + /** + * Indicates whether or not this type has been verified. This value is + * the same as isPrepared for interfaces and is undefined for arrays and + * primitive types. + * + * @return True if verified, otherwise false + */ + override def isVerified: Boolean = ??? + + /** + * Retrieves and returns all valid locations for executable lines within + * this type. + * + * @return The collection of location information + */ + override def allLineLocations: Seq[LocationInfo] = ??? + + /** + * Retrieves and returns all valid locations for a specific executable line + * within this type. + * + * @return The collection of location information + */ + override def locationsOfLine(line: Int): Seq[LocationInfo] = ??? + + /** + * Retrieves the major class version number defined in the class file format + * of the JVM specification. + * + * @return The major version number + */ + override def majorVersion: Int = ??? + + /** + * Retrieves the minor class version number defined in the class file format + * of the JVM specification. + * + * @return The minor version number + */ + override def minorVersion: Int = ??? + + /** + * Retrieves reference type information for all types declared inside this + * type. + * + * @return The collection of reference type information + */ + override def nestedTypes: Seq[ReferenceTypeInfo] = ??? + + /** + * Retrieves the source debug extension for this type. + * + * @return The source debug extension + */ + override def sourceDebugExtension: String = ??? + + /** + * Retrieves all identifying names for the source(s) corresponding to this + * type. + * + * @return The collection of identifying names + */ + override def sourceNames: Seq[String] = ??? + + /** + * Retrieves all source paths corresponding to this type. + * + * @return The collection of source paths + */ + override def sourcePaths: Seq[String] = ??? +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala index 1206e98b..223bdb97 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala @@ -1,7 +1,8 @@ package org.scaladebugger.api.profiles.frozen.info -import org.scaladebugger.api.profiles.frozen.FrozenException import org.scaladebugger.api.profiles.traits.info._ +import scala.util.Try + /** * Represents type information frozen (snapshot at a point in time) for a remote * JVM. @@ -9,9 +10,9 @@ import org.scaladebugger.api.profiles.traits.info._ case class FrozenTypeInfo( name: String, signature: String, - protected val arrayType: Either[FrozenException, ArrayTypeInfo], - protected val classType: Either[FrozenException, ClassTypeInfo], - protected val interfaceType: Either[FrozenException, InterfaceTypeInfo], - protected val referenceType: Either[FrozenException, ReferenceTypeInfo], - protected val primitiveType: Either[FrozenException, PrimitiveTypeInfo] + protected val _arrayType: Try[ArrayTypeInfo], + protected val _classType: Try[ClassTypeInfo], + protected val _interfaceType: Try[InterfaceTypeInfo], + protected val _referenceType: Try[ReferenceTypeInfo], + protected val _primitiveType: Try[PrimitiveTypeInfo] ) extends FrozenTypeInfoLike diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala index 74131cac..f3c997a0 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala @@ -3,48 +3,50 @@ package org.scaladebugger.api.profiles.frozen.info import org.scaladebugger.api.profiles.frozen.FrozenException import org.scaladebugger.api.profiles.traits.info._ +import scala.util.Try + /** Represents a frozen instance of some type information on a remote JVM. */ trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { - protected val arrayType: Either[FrozenException, ArrayTypeInfo] - protected val classType: Either[FrozenException, ClassTypeInfo] - protected val interfaceType: Either[FrozenException, InterfaceTypeInfo] - protected val referenceType: Either[FrozenException, ReferenceTypeInfo] - protected val primitiveType: Either[FrozenException, PrimitiveTypeInfo] + protected val _arrayType: Try[ArrayTypeInfo] + protected val _classType: Try[ClassTypeInfo] + protected val _interfaceType: Try[InterfaceTypeInfo] + protected val _referenceType: Try[ReferenceTypeInfo] + protected val _primitiveType: Try[PrimitiveTypeInfo] /** * Returns whether or not this type represents an array type. * * @return True if an array type, otherwise false */ - override def isArrayType: Boolean = arrayType.isRight + override def isArrayType: Boolean = _arrayType.isSuccess /** * Returns whether or not this type represents a class type. * * @return True if a class type, otherwise false */ - override def isClassType: Boolean = classType.isRight + override def isClassType: Boolean = _classType.isSuccess /** * Returns whether or not this type represents an interface type. * * @return True if an interface type, otherwise false */ - override def isInterfaceType: Boolean = interfaceType.isRight + override def isInterfaceType: Boolean = _interfaceType.isSuccess /** * Returns whether or not this type represents a reference type. * * @return True if a reference type, otherwise false */ - override def isReferenceType: Boolean = referenceType.isRight + override def isReferenceType: Boolean = _referenceType.isSuccess /** * Returns whether or not this type represents a primitive type. * * @return True if a primitive type, otherwise false */ - override def isPrimitiveType: Boolean = primitiveType.isRight + override def isPrimitiveType: Boolean = _primitiveType.isSuccess /** * Returns whether or not this type is for a value that is null. @@ -62,10 +64,7 @@ trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { * @return The array type profile wrapping this type */ @throws[FrozenException] - override def toArrayType: ArrayTypeInfo = arrayType match { - case Left(e) => throw e - case Right(t) => t - } + override def toArrayType: ArrayTypeInfo = _arrayType.get /** * Returns the type as an class type (profile). @@ -73,10 +72,7 @@ trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { * @return The class type profile wrapping this type */ @throws[FrozenException] - override def toClassType: ClassTypeInfo = classType match { - case Left(e) => throw e - case Right(t) => t - } + override def toClassType: ClassTypeInfo = _classType.get /** * Returns the type as an interface type (profile). @@ -84,10 +80,7 @@ trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { * @return The interface type profile wrapping this type */ @throws[FrozenException] - override def toInterfaceType: InterfaceTypeInfo = interfaceType match { - case Left(e) => throw e - case Right(t) => t - } + override def toInterfaceType: InterfaceTypeInfo = _interfaceType.get /** * Returns the type as an reference type (profile). @@ -95,10 +88,7 @@ trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { * @return The reference type profile wrapping this type */ @throws[FrozenException] - override def toReferenceType: ReferenceTypeInfo = referenceType match { - case Left(e) => throw e - case Right(t) => t - } + override def toReferenceType: ReferenceTypeInfo = _referenceType.get /** * Returns the type as an primitive type (profile). @@ -106,8 +96,5 @@ trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { * @return The primitive type profile wrapping this type */ @throws[FrozenException] - override def toPrimitiveType: PrimitiveTypeInfo = primitiveType match { - case Left(e) => throw e - case Right(t) => t - } + override def toPrimitiveType: PrimitiveTypeInfo = _primitiveType.get } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala index e3487480..d226b051 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala @@ -1,8 +1,9 @@ package org.scaladebugger.api.profiles.frozen.info -import org.scaladebugger.api.profiles.frozen.FrozenException import org.scaladebugger.api.profiles.traits.info._ +import scala.util.Try + /** * Represents value information frozen (snapshot at a point in time) for a * remote JVM. @@ -11,13 +12,13 @@ case class FrozenValueInfo( `type`: TypeInfo, isNull: Boolean, isVoid: Boolean, - protected val localValue: Either[FrozenException, Any], - protected val arrayInfo: Either[FrozenException, ArrayInfo], - protected val stringInfo: Either[FrozenException, StringInfo], - protected val objectInfo: Either[FrozenException, ObjectInfo], - protected val threadInfo: Either[FrozenException, ThreadInfo], - protected val threadGroupInfo: Either[FrozenException, ThreadGroupInfo], - protected val classObjectInfo: Either[FrozenException, ClassObjectInfo], - protected val classLoaderInfo: Either[FrozenException, ClassLoaderInfo], - protected val primitiveInfo: Either[FrozenException, PrimitiveInfo] + protected val _localValue: Try[Any], + protected val _arrayInfo: Try[ArrayInfo], + protected val _stringInfo: Try[StringInfo], + protected val _objectInfo: Try[ObjectInfo], + protected val _threadInfo: Try[ThreadInfo], + protected val _threadGroupInfo: Try[ThreadGroupInfo], + protected val _classObjectInfo: Try[ClassObjectInfo], + protected val _classLoaderInfo: Try[ClassLoaderInfo], + protected val _primitiveInfo: Try[PrimitiveInfo] ) extends FrozenValueInfoLike diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala index 5e508b12..1d2ed221 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala @@ -3,74 +3,76 @@ package org.scaladebugger.api.profiles.frozen.info import org.scaladebugger.api.profiles.frozen.FrozenException import org.scaladebugger.api.profiles.traits.info._ +import scala.util.Try + trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { override val isNull: Boolean override val isVoid: Boolean - protected val localValue: Either[FrozenException, Any] - protected val arrayInfo: Either[FrozenException, ArrayInfo] - protected val stringInfo: Either[FrozenException, StringInfo] - protected val objectInfo: Either[FrozenException, ObjectInfo] - protected val threadInfo: Either[FrozenException, ThreadInfo] - protected val threadGroupInfo: Either[FrozenException, ThreadGroupInfo] - protected val classObjectInfo: Either[FrozenException, ClassObjectInfo] - protected val classLoaderInfo: Either[FrozenException, ClassLoaderInfo] - protected val primitiveInfo: Either[FrozenException, PrimitiveInfo] + protected val _localValue: Try[Any] + protected val _arrayInfo: Try[ArrayInfo] + protected val _stringInfo: Try[StringInfo] + protected val _objectInfo: Try[ObjectInfo] + protected val _threadInfo: Try[ThreadInfo] + protected val _threadGroupInfo: Try[ThreadGroupInfo] + protected val _classObjectInfo: Try[ClassObjectInfo] + protected val _classLoaderInfo: Try[ClassLoaderInfo] + protected val _primitiveInfo: Try[PrimitiveInfo] /** * Returns whether or not this value represents a primitive. * * @return True if a primitive, otherwise false */ - override def isPrimitive: Boolean = primitiveInfo.isRight + override def isPrimitive: Boolean = _primitiveInfo.isSuccess /** * Returns whether or not this value represents an array. * * @return True if an array, otherwise false */ - override def isArray: Boolean = arrayInfo.isRight + override def isArray: Boolean = _arrayInfo.isSuccess /** * Returns whether or not this value represents a class loader. * * @return True if a class loader, otherwise false */ - override def isClassLoader: Boolean = classLoaderInfo.isRight + override def isClassLoader: Boolean = _classLoaderInfo.isSuccess /** * Returns whether or not this value represents a class object. * * @return True if a class object, otherwise false */ - override def isClassObject: Boolean = classObjectInfo.isRight + override def isClassObject: Boolean = _classObjectInfo.isSuccess /** * Returns whether or not this value represents a thread group. * * @return True if a thread group, otherwise false */ - override def isThreadGroup: Boolean = threadGroupInfo.isRight + override def isThreadGroup: Boolean = _threadGroupInfo.isSuccess /** * Returns whether or not this value represents a thread. * * @return True if a thread, otherwise false */ - override def isThread: Boolean = threadInfo.isRight + override def isThread: Boolean = _threadInfo.isSuccess /** * Returns whether or not this value represents an object. * * @return True if an object, otherwise false */ - override def isObject: Boolean = objectInfo.isRight + override def isObject: Boolean = _objectInfo.isSuccess /** * Returns whether or not this value represents a string. * * @return True if a string, otherwise false */ - override def isString: Boolean = stringInfo.isRight + override def isString: Boolean = _stringInfo.isSuccess /** * Returns the value as a value local to this JVM. @@ -78,10 +80,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The value as a local instance */ @throws[FrozenException] - override def toLocalValue: Any = localValue match { - case Left(e) => throw e - case Right(v) => v - } + override def toLocalValue: Any = _localValue.get /** * Returns the value as a primitive (profile). @@ -89,10 +88,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The primitive profile wrapping this value */ @throws[FrozenException] - override def toPrimitiveInfo: PrimitiveInfo = primitiveInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toPrimitiveInfo: PrimitiveInfo = _primitiveInfo.get /** * Returns the value as a class loader (profile). @@ -100,10 +96,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The class loader profile wrapping this value */ @throws[FrozenException] - override def toClassLoaderInfo: ClassLoaderInfo = classLoaderInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toClassLoaderInfo: ClassLoaderInfo = _classLoaderInfo.get /** * Returns the value as a class object (profile). @@ -111,10 +104,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The class object profile wrapping this value */ @throws[FrozenException] - override def toClassObjectInfo: ClassObjectInfo = classObjectInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toClassObjectInfo: ClassObjectInfo = _classObjectInfo.get /** * Returns the value as a thread group (profile). @@ -122,10 +112,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The thread group profile wrapping this value */ @throws[FrozenException] - override def toThreadGroupInfo: ThreadGroupInfo = threadGroupInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toThreadGroupInfo: ThreadGroupInfo = _threadGroupInfo.get /** * Returns the value as a thread (profile). @@ -133,10 +120,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The thread profile wrapping this value */ @throws[FrozenException] - override def toThreadInfo: ThreadInfo = threadInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toThreadInfo: ThreadInfo = _threadInfo.get /** * Returns the value as an object (profile). @@ -144,10 +128,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The object profile wrapping this value */ @throws[FrozenException] - override def toObjectInfo: ObjectInfo = objectInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toObjectInfo: ObjectInfo = _objectInfo.get /** * Returns the value as an string (profile). @@ -155,10 +136,7 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The string profile wrapping this value */ @throws[FrozenException] - override def toStringInfo: StringInfo = stringInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toStringInfo: StringInfo = _stringInfo.get /** * Returns the value as an array (profile). @@ -166,8 +144,5 @@ trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { * @return The array profile wrapping this value */ @throws[FrozenException] - override def toArrayInfo: ArrayInfo = arrayInfo match { - case Left(e) => throw e - case Right(v) => v - } + override def toArrayInfo: ArrayInfo = _arrayInfo.get } From 9240dba158cfbcad2d6e1515ed9cfbded0a2f0bc Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 6 Aug 2017 11:23:53 -0700 Subject: [PATCH 03/36] Added a couple more missing implementations to frozen --- .../frozen/info/FrozenReferenceTypeInfoLike.scala | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala index 2c7f4dc7..98b77135 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala @@ -14,6 +14,9 @@ trait FrozenReferenceTypeInfoLike extends ReferenceTypeInfo with FrozenTypeInfoL protected val _visibleFields: Try[Seq[FieldVariableInfo]] protected val _indexedVisibleFields: Try[Seq[FieldVariableInfo]] + protected val _allMethods: Try[Seq[MethodInfo]] + protected val _visibleMethods: Try[Seq[MethodInfo]] + /** * Retrieves all fields declared in this type, its superclasses, implemented * interfaces, and superinterfaces. @@ -71,7 +74,8 @@ trait FrozenReferenceTypeInfoLike extends ReferenceTypeInfo with FrozenTypeInfoL * * @return The collection of methods as method info profiles */ - override def allMethods: Seq[MethodInfo] = ??? + @throws[FrozenException] + override def allMethods: Seq[MethodInfo] = _allMethods.get /** * Retrieves unhidden and unambiguous methods in this type. Methods hidden @@ -81,7 +85,8 @@ trait FrozenReferenceTypeInfoLike extends ReferenceTypeInfo with FrozenTypeInfoL * * @return The collection of methods as method info profiles */ - override def visibleMethods: Seq[MethodInfo] = ??? + @throws[FrozenException] + override def visibleMethods: Seq[MethodInfo] = _visibleMethods.get /** * Retrieves the visible methods with the matching name. @@ -89,7 +94,9 @@ trait FrozenReferenceTypeInfoLike extends ReferenceTypeInfo with FrozenTypeInfoL * @param name The name of the method to retrieve * @return The collection of method info profiles */ - override def methods(name: String): Seq[MethodInfo] = ??? + @throws[FrozenException] + override def methods(name: String): Seq[MethodInfo] = + visibleMethods.filter(_.name == name) /** * Retrieves the classloader object which loaded the class associated with From 5ffa41aaa2d56697bf9050e21182dde6572da711 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 00:29:05 -0700 Subject: [PATCH 04/36] More code towards freeze support --- .../frozen/info/FrozenCommonInfo.scala | 8 ++++++- .../frozen/info/FrozenFrozenInfo.scala | 16 +++++++++++++ .../api/profiles/traits/info/CommonInfo.scala | 2 +- .../api/profiles/traits/info/FrozenInfo.scala | 24 +++++++++++++++++++ .../api/profiles/traits/info/TypeInfo.scala | 16 +++++++++++++ .../api/profiles/traits/info/ValueInfo.scala | 21 ++++++++++++++++ 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala index 72fa0965..af0c0de4 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala @@ -1,5 +1,7 @@ package org.scaladebugger.api.profiles.frozen.info +import java.io.File + import com.sun.jdi.Mirror import org.scaladebugger.api.profiles.frozen.{DataUnavailableFrozenException, FrozenException} import org.scaladebugger.api.profiles.traits.info.CommonInfo @@ -8,7 +10,11 @@ import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine /** * Represents a frozen implementation of the common info trait. */ -trait FrozenCommonInfo extends CommonInfo with FrozenJavaInfo { +trait FrozenCommonInfo + extends CommonInfo + with FrozenJavaInfo + with FrozenFrozenInfo +{ /** Unavailable on frozen entity. */ @throws[FrozenException] override def scalaVirtualMachine: ScalaVirtualMachine = diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala new file mode 100644 index 00000000..7620c9d5 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala @@ -0,0 +1,16 @@ +package org.scaladebugger.api.profiles.frozen.info + +import org.scaladebugger.api.profiles.traits.info.FrozenInfo + +/** + * Represents a frozen implementation of the frozen info trait. + */ +trait FrozenFrozenInfo extends FrozenInfo { + /** + * Returns whether or not this information is frozen. + * + * @return If true, this information has been frozen, otherwise it + * represents live data + */ + override def isFrozen: Boolean = true +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 0c762109..6262a15b 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine /** * Represents common methods between information-gathering profiles. */ -trait CommonInfo extends JavaInfo { +trait CommonInfo extends JavaInfo with FrozenInfo { /** * Returns the Scala virtual machine containing this instance. * diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala new file mode 100644 index 00000000..f8ad992e --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala @@ -0,0 +1,24 @@ +package org.scaladebugger.api.profiles.traits.info + +import java.io.Serializable + +/** + * Represents a profile that provides common methods to freeze information + * such that it can be persisted and processed elsewhere. + */ +trait FrozenInfo { + /** + * Returns whether or not this information is frozen. + * + * @return If true, this information has been frozen, otherwise it + * represents live data + */ + def isFrozen: Boolean + + /** + * Freezes the information, collecting all data at the current point in time. + * + * @return The information frozen at the current point in time + */ + def freeze(): _ <: Serializable +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index 469508db..dd1e1fde 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -1,6 +1,7 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Type +import org.scaladebugger.api.profiles.frozen.info.FrozenTypeInfo import scala.util.Try @@ -283,4 +284,19 @@ trait TypeInfo extends CommonInfo { * @return The human-readable description */ override def toPrettyString: String = s"Type $name ($signature)" + + /** + * Freezes the information, collecting all data at the current point in time. + * + * @return The information frozen at the current point in time + */ + override def freeze(): FrozenTypeInfo = FrozenTypeInfo( + name = this.name, + signature = this.signature, + _arrayType = this.tryToArrayType, + _classType = this.tryToClassType, + _interfaceType = this.tryToInterfaceType, + _referenceType = this.tryToReferenceType, + _primitiveType = this.tryToPrimitiveType + ) } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 421f1267..43db2545 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,6 +1,7 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value +import org.scaladebugger.api.profiles.frozen.info.FrozenValueInfo import scala.util.Try @@ -273,4 +274,24 @@ trait ValueInfo extends CommonInfo { else "???" }.getOrElse("") } + + /** + * Freezes the information, collecting all data at the current point in time. + * + * @return The information frozen at the current point in time + */ + override def freeze(): FrozenValueInfo = FrozenValueInfo( + `type` = this.`type`, + isNull = this.isNull, + isVoid = this.isVoid, + _localValue = this.tryToLocalValue, + _arrayInfo = this.tryToArrayInfo, + _stringInfo = this.tryToStringInfo, + _objectInfo = this.tryToObjectInfo, + _threadInfo = this.tryToThreadInfo, + _threadGroupInfo = this.tryToThreadGroupInfo, + _classObjectInfo = this.tryToClassObjectInfo, + _classLoaderInfo = this.tryToClassLoaderInfo, + _primitiveInfo = this.tryToPrimitiveInfo + ) } From 05bfd58ec12eb0bb10da1fdc416c9497255ef0e6 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 00:41:38 -0700 Subject: [PATCH 05/36] Trying to create test macro --- .../api/profiles/frozen/FrozenException.scala | 39 --- .../frozen/info/FrozenCommonInfo.scala | 26 -- .../frozen/info/FrozenCreateInfo.scala | 19 -- .../frozen/info/FrozenFrozenInfo.scala | 16 -- .../profiles/frozen/info/FrozenJavaInfo.scala | 23 -- .../info/FrozenReferenceTypeInfoLike.scala | 240 ------------------ .../profiles/frozen/info/FrozenTypeInfo.scala | 18 -- .../frozen/info/FrozenTypeInfoLike.scala | 100 -------- .../frozen/info/FrozenValueInfo.scala | 24 -- .../frozen/info/FrozenValueInfoLike.scala | 148 ----------- .../api/profiles/traits/info/TypeInfo.scala | 16 -- .../api/profiles/traits/info/ValueInfo.scala | 21 -- .../org/scaladebugger/macros/.placeholder | 0 .../macros/freeze/Freezable.scala | 28 ++ 14 files changed, 28 insertions(+), 690 deletions(-) delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala delete mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/.placeholder create mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala deleted file mode 100644 index 4b7a9e47..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/FrozenException.scala +++ /dev/null @@ -1,39 +0,0 @@ -package org.scaladebugger.api.profiles.frozen - -/** - * Represents a generic frozen exception that occurs only on frozen entities. - */ -sealed trait FrozenException extends Exception - -/** - * Represents an exception thrown when trying to invoke a method on - * a frozen entity. - */ -case object InvocationFrozenException - extends FrozenException("Method cannot be invoked while frozen!") - -/** - * Represents an exception thrown when trying to access data on a frozen - * entity that is unavailable. - */ -case object DataUnavailableFrozenException - extends FrozenException("Data is unavailable while frozen!") - -/** - * Represents an exception thrown when trying to cast to another value which - * is incorrect for the frozen type. - */ -case object InvalidCastFrozenException - extends FrozenException("Invalid cast type on frozen entity!") - -/** - * Represents an exception thrown when trying to freeze. - * - * @param cause The cause of the exception - */ -case class UnexpectedErrorFrozenException( - cause: Exception -) extends FrozenException( - "An unexpected error was encountered when freezing!", - cause -) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala deleted file mode 100644 index af0c0de4..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCommonInfo.scala +++ /dev/null @@ -1,26 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import java.io.File - -import com.sun.jdi.Mirror -import org.scaladebugger.api.profiles.frozen.{DataUnavailableFrozenException, FrozenException} -import org.scaladebugger.api.profiles.traits.info.CommonInfo -import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine - -/** - * Represents a frozen implementation of the common info trait. - */ -trait FrozenCommonInfo - extends CommonInfo - with FrozenJavaInfo - with FrozenFrozenInfo -{ - /** Unavailable on frozen entity. */ - @throws[FrozenException] - override def scalaVirtualMachine: ScalaVirtualMachine = - throw DataUnavailableFrozenException - - /** Unavailable on frozen entity. */ - @throws[FrozenException] - override def toJdiInstance: Mirror = throw DataUnavailableFrozenException -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala deleted file mode 100644 index bd24e0c4..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenCreateInfo.scala +++ /dev/null @@ -1,19 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.frozen.{FrozenException, InvocationFrozenException} -import org.scaladebugger.api.profiles.traits.info.{CreateInfo, ValueInfo} - -/** - * Represents a frozen implementation of the create info trait. - */ -trait FrozenCreateInfo extends CreateInfo { - /** Unavailable on frozen entity. */ - @throws[FrozenException] - override def createRemotely(value: AnyVal): ValueInfo = - throw InvocationFrozenException - - /** Unavailable on frozen entity. */ - @throws[FrozenException] - override def createRemotely(value: String): ValueInfo = - throw InvocationFrozenException -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala deleted file mode 100644 index 7620c9d5..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenFrozenInfo.scala +++ /dev/null @@ -1,16 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.traits.info.FrozenInfo - -/** - * Represents a frozen implementation of the frozen info trait. - */ -trait FrozenFrozenInfo extends FrozenInfo { - /** - * Returns whether or not this information is frozen. - * - * @return If true, this information has been frozen, otherwise it - * represents live data - */ - override def isFrozen: Boolean = true -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala deleted file mode 100644 index 71754d69..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenJavaInfo.scala +++ /dev/null @@ -1,23 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.frozen.{FrozenException, InvalidCastFrozenException} -import org.scaladebugger.api.profiles.traits.info.JavaInfo - -/** - * Represents a frozen implementation of the Java info trait. - */ -trait FrozenJavaInfo extends JavaInfo { - /** - * Returns whether or not this info profile represents the low-level Java - * implementation. - * - * @return If true, this profile represents the low-level Java information, - * otherwise this profile represents something higher-level like - * Scala, Jython, or JRuby - */ - override def isJavaInfo: Boolean = false - - /** Unavailable on frozen entity. */ - @throws[FrozenException] - override def toJavaInfo: AnyRef = throw InvalidCastFrozenException -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala deleted file mode 100644 index 98b77135..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenReferenceTypeInfoLike.scala +++ /dev/null @@ -1,240 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.frozen.FrozenException -import org.scaladebugger.api.profiles.traits.info._ - -import scala.util.Try - -/** - * Represents type information frozen (snapshot at a point in time) for a remote - * JVM. - */ -trait FrozenReferenceTypeInfoLike extends ReferenceTypeInfo with FrozenTypeInfoLike { - protected val _allFields: Try[Seq[FieldVariableInfo]] - protected val _visibleFields: Try[Seq[FieldVariableInfo]] - protected val _indexedVisibleFields: Try[Seq[FieldVariableInfo]] - - protected val _allMethods: Try[Seq[MethodInfo]] - protected val _visibleMethods: Try[Seq[MethodInfo]] - - /** - * Retrieves all fields declared in this type, its superclasses, implemented - * interfaces, and superinterfaces. - * - * @return The collection of fields as variable info profiles - */ - @throws[FrozenException] - override def allFields: Seq[FieldVariableInfo] = _allFields.get - - /** - * Retrieves unhidden and unambiguous fields in this type. Fields hidden - * by other fields with the same name (in a more recently inherited class) - * are not included. Fields that are ambiguously multiply inherited are also - * not included. All other inherited fields are included. - * - * @return The collection of fields as variable info profiles - */ - @throws[FrozenException] - override def visibleFields: Seq[FieldVariableInfo] = _visibleFields.get - - /** - * Retrieves unhidden and unambiguous fields in this type. Fields hidden - * by other fields with the same name (in a more recently inherited class) - * are not included. Fields that are ambiguously multiply inherited are also - * not included. All other inherited fields are included. Offset index - * information is included. - * - * @return The collection of fields as variable info profiles - */ - override def indexedVisibleFields: Seq[FieldVariableInfo] = - _indexedVisibleFields.get - - /** - * Retrieves the visible field with the matching name with offset index - * information. - * - * @param name The name of the field to retrieve - * @return Some field as a variable info profile, or None if doesn't exist - */ - override def indexedFieldOption(name: String): Option[FieldVariableInfo] = - _indexedVisibleFields.get.find(_.name == name) - - /** - * Retrieves the visible field with the matching name. - * - * @param name The name of the field to retrieve - * @return Some field as a variable info profile, or None if doesn't exist - */ - override def fieldOption(name: String): Option[FieldVariableInfo] = - _visibleFields.get.find(_.name == name) - - /** - * Retrieves all methods declared in this type, its superclasses, implemented - * interfaces, and superinterfaces. - * - * @return The collection of methods as method info profiles - */ - @throws[FrozenException] - override def allMethods: Seq[MethodInfo] = _allMethods.get - - /** - * Retrieves unhidden and unambiguous methods in this type. Methods hidden - * by other methods with the same name (in a more recently inherited class) - * are not included. Methods that are ambiguously multiply inherited are also - * not included. All other inherited methods are included. - * - * @return The collection of methods as method info profiles - */ - @throws[FrozenException] - override def visibleMethods: Seq[MethodInfo] = _visibleMethods.get - - /** - * Retrieves the visible methods with the matching name. - * - * @param name The name of the method to retrieve - * @return The collection of method info profiles - */ - @throws[FrozenException] - override def methods(name: String): Seq[MethodInfo] = - visibleMethods.filter(_.name == name) - - /** - * Retrieves the classloader object which loaded the class associated with - * this type. - * - * @return Some profile representing the classloader, - * otherwise None if loaded through the bootstrap classloader - */ - override def classLoaderOption: Option[ClassLoaderInfo] = ??? - - /** - * Retrieves the class object associated with this type. - * - * @return The profile representing the class - */ - override def classObject: ClassObjectInfo = ??? - - /** - * Retrieves the generic signature type if it exists. - * - * @return Some signature if it exists, otherwise None - */ - override def genericSignature: Option[String] = ??? - - /** - * Retrieves reachable instances of this type. - * - * @param maxInstances The maximum number of instances to return, or zero - * to get all reachable instances - * @return The collection of object instances - */ - override def instances(maxInstances: Long): Seq[ObjectInfo] = ??? - - /** - * Indicates whether or not this type is abstract. - * - * @return True if abstract, otherwise false - */ - override def isAbstract: Boolean = ??? - - /** - * Indicates whether or not this type is final. - * - * @return True if final, otherwise false - */ - override def isFinal: Boolean = ??? - - /** - * Indicates whether or not this type has been initialized. This value is - * the same as isPrepared for interfaces and is undefined for arrays and - * primitive types. - * - * @return True if initialized, otherwise false - */ - override def isInitialized: Boolean = ??? - - /** - * Indicates whether or not this type's class has been prepared. - * - * @return True if prepared, otherwise false - */ - override def isPrepared: Boolean = ??? - - /** - * Indicates whether or not this type is static. - * - * @return True if static, otherwise false - */ - override def isStatic: Boolean = ??? - - /** - * Indicates whether or not this type has been verified. This value is - * the same as isPrepared for interfaces and is undefined for arrays and - * primitive types. - * - * @return True if verified, otherwise false - */ - override def isVerified: Boolean = ??? - - /** - * Retrieves and returns all valid locations for executable lines within - * this type. - * - * @return The collection of location information - */ - override def allLineLocations: Seq[LocationInfo] = ??? - - /** - * Retrieves and returns all valid locations for a specific executable line - * within this type. - * - * @return The collection of location information - */ - override def locationsOfLine(line: Int): Seq[LocationInfo] = ??? - - /** - * Retrieves the major class version number defined in the class file format - * of the JVM specification. - * - * @return The major version number - */ - override def majorVersion: Int = ??? - - /** - * Retrieves the minor class version number defined in the class file format - * of the JVM specification. - * - * @return The minor version number - */ - override def minorVersion: Int = ??? - - /** - * Retrieves reference type information for all types declared inside this - * type. - * - * @return The collection of reference type information - */ - override def nestedTypes: Seq[ReferenceTypeInfo] = ??? - - /** - * Retrieves the source debug extension for this type. - * - * @return The source debug extension - */ - override def sourceDebugExtension: String = ??? - - /** - * Retrieves all identifying names for the source(s) corresponding to this - * type. - * - * @return The collection of identifying names - */ - override def sourceNames: Seq[String] = ??? - - /** - * Retrieves all source paths corresponding to this type. - * - * @return The collection of source paths - */ - override def sourcePaths: Seq[String] = ??? -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala deleted file mode 100644 index 223bdb97..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfo.scala +++ /dev/null @@ -1,18 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info -import org.scaladebugger.api.profiles.traits.info._ - -import scala.util.Try - -/** - * Represents type information frozen (snapshot at a point in time) for a remote - * JVM. - */ -case class FrozenTypeInfo( - name: String, - signature: String, - protected val _arrayType: Try[ArrayTypeInfo], - protected val _classType: Try[ClassTypeInfo], - protected val _interfaceType: Try[InterfaceTypeInfo], - protected val _referenceType: Try[ReferenceTypeInfo], - protected val _primitiveType: Try[PrimitiveTypeInfo] -) extends FrozenTypeInfoLike diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala deleted file mode 100644 index f3c997a0..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenTypeInfoLike.scala +++ /dev/null @@ -1,100 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.frozen.FrozenException -import org.scaladebugger.api.profiles.traits.info._ - -import scala.util.Try - -/** Represents a frozen instance of some type information on a remote JVM. */ -trait FrozenTypeInfoLike extends TypeInfo with FrozenCommonInfo { - protected val _arrayType: Try[ArrayTypeInfo] - protected val _classType: Try[ClassTypeInfo] - protected val _interfaceType: Try[InterfaceTypeInfo] - protected val _referenceType: Try[ReferenceTypeInfo] - protected val _primitiveType: Try[PrimitiveTypeInfo] - - /** - * Returns whether or not this type represents an array type. - * - * @return True if an array type, otherwise false - */ - override def isArrayType: Boolean = _arrayType.isSuccess - - /** - * Returns whether or not this type represents a class type. - * - * @return True if a class type, otherwise false - */ - override def isClassType: Boolean = _classType.isSuccess - - /** - * Returns whether or not this type represents an interface type. - * - * @return True if an interface type, otherwise false - */ - override def isInterfaceType: Boolean = _interfaceType.isSuccess - - /** - * Returns whether or not this type represents a reference type. - * - * @return True if a reference type, otherwise false - */ - override def isReferenceType: Boolean = _referenceType.isSuccess - - /** - * Returns whether or not this type represents a primitive type. - * - * @return True if a primitive type, otherwise false - */ - override def isPrimitiveType: Boolean = _primitiveType.isSuccess - - /** - * Returns whether or not this type is for a value that is null. - * - * @return True if representing the type of a null value, otherwise false - */ - override def isNullType: Boolean = !( - isArrayType || isClassType || isInterfaceType || - isReferenceType || isPrimitiveType - ) - - /** - * Returns the type as an array type (profile). - * - * @return The array type profile wrapping this type - */ - @throws[FrozenException] - override def toArrayType: ArrayTypeInfo = _arrayType.get - - /** - * Returns the type as an class type (profile). - * - * @return The class type profile wrapping this type - */ - @throws[FrozenException] - override def toClassType: ClassTypeInfo = _classType.get - - /** - * Returns the type as an interface type (profile). - * - * @return The interface type profile wrapping this type - */ - @throws[FrozenException] - override def toInterfaceType: InterfaceTypeInfo = _interfaceType.get - - /** - * Returns the type as an reference type (profile). - * - * @return The reference type profile wrapping this type - */ - @throws[FrozenException] - override def toReferenceType: ReferenceTypeInfo = _referenceType.get - - /** - * Returns the type as an primitive type (profile). - * - * @return The primitive type profile wrapping this type - */ - @throws[FrozenException] - override def toPrimitiveType: PrimitiveTypeInfo = _primitiveType.get -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala deleted file mode 100644 index d226b051..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfo.scala +++ /dev/null @@ -1,24 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.traits.info._ - -import scala.util.Try - -/** - * Represents value information frozen (snapshot at a point in time) for a - * remote JVM. - */ -case class FrozenValueInfo( - `type`: TypeInfo, - isNull: Boolean, - isVoid: Boolean, - protected val _localValue: Try[Any], - protected val _arrayInfo: Try[ArrayInfo], - protected val _stringInfo: Try[StringInfo], - protected val _objectInfo: Try[ObjectInfo], - protected val _threadInfo: Try[ThreadInfo], - protected val _threadGroupInfo: Try[ThreadGroupInfo], - protected val _classObjectInfo: Try[ClassObjectInfo], - protected val _classLoaderInfo: Try[ClassLoaderInfo], - protected val _primitiveInfo: Try[PrimitiveInfo] -) extends FrozenValueInfoLike diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala deleted file mode 100644 index 1d2ed221..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/frozen/info/FrozenValueInfoLike.scala +++ /dev/null @@ -1,148 +0,0 @@ -package org.scaladebugger.api.profiles.frozen.info - -import org.scaladebugger.api.profiles.frozen.FrozenException -import org.scaladebugger.api.profiles.traits.info._ - -import scala.util.Try - -trait FrozenValueInfoLike extends ValueInfo with FrozenCommonInfo { - override val isNull: Boolean - override val isVoid: Boolean - protected val _localValue: Try[Any] - protected val _arrayInfo: Try[ArrayInfo] - protected val _stringInfo: Try[StringInfo] - protected val _objectInfo: Try[ObjectInfo] - protected val _threadInfo: Try[ThreadInfo] - protected val _threadGroupInfo: Try[ThreadGroupInfo] - protected val _classObjectInfo: Try[ClassObjectInfo] - protected val _classLoaderInfo: Try[ClassLoaderInfo] - protected val _primitiveInfo: Try[PrimitiveInfo] - - /** - * Returns whether or not this value represents a primitive. - * - * @return True if a primitive, otherwise false - */ - override def isPrimitive: Boolean = _primitiveInfo.isSuccess - - /** - * Returns whether or not this value represents an array. - * - * @return True if an array, otherwise false - */ - override def isArray: Boolean = _arrayInfo.isSuccess - - /** - * Returns whether or not this value represents a class loader. - * - * @return True if a class loader, otherwise false - */ - override def isClassLoader: Boolean = _classLoaderInfo.isSuccess - - /** - * Returns whether or not this value represents a class object. - * - * @return True if a class object, otherwise false - */ - override def isClassObject: Boolean = _classObjectInfo.isSuccess - - /** - * Returns whether or not this value represents a thread group. - * - * @return True if a thread group, otherwise false - */ - override def isThreadGroup: Boolean = _threadGroupInfo.isSuccess - - /** - * Returns whether or not this value represents a thread. - * - * @return True if a thread, otherwise false - */ - override def isThread: Boolean = _threadInfo.isSuccess - - /** - * Returns whether or not this value represents an object. - * - * @return True if an object, otherwise false - */ - override def isObject: Boolean = _objectInfo.isSuccess - - /** - * Returns whether or not this value represents a string. - * - * @return True if a string, otherwise false - */ - override def isString: Boolean = _stringInfo.isSuccess - - /** - * Returns the value as a value local to this JVM. - * - * @return The value as a local instance - */ - @throws[FrozenException] - override def toLocalValue: Any = _localValue.get - - /** - * Returns the value as a primitive (profile). - * - * @return The primitive profile wrapping this value - */ - @throws[FrozenException] - override def toPrimitiveInfo: PrimitiveInfo = _primitiveInfo.get - - /** - * Returns the value as a class loader (profile). - * - * @return The class loader profile wrapping this value - */ - @throws[FrozenException] - override def toClassLoaderInfo: ClassLoaderInfo = _classLoaderInfo.get - - /** - * Returns the value as a class object (profile). - * - * @return The class object profile wrapping this value - */ - @throws[FrozenException] - override def toClassObjectInfo: ClassObjectInfo = _classObjectInfo.get - - /** - * Returns the value as a thread group (profile). - * - * @return The thread group profile wrapping this value - */ - @throws[FrozenException] - override def toThreadGroupInfo: ThreadGroupInfo = _threadGroupInfo.get - - /** - * Returns the value as a thread (profile). - * - * @return The thread profile wrapping this value - */ - @throws[FrozenException] - override def toThreadInfo: ThreadInfo = _threadInfo.get - - /** - * Returns the value as an object (profile). - * - * @return The object profile wrapping this value - */ - @throws[FrozenException] - override def toObjectInfo: ObjectInfo = _objectInfo.get - - /** - * Returns the value as an string (profile). - * - * @return The string profile wrapping this value - */ - @throws[FrozenException] - override def toStringInfo: StringInfo = _stringInfo.get - - /** - * Returns the value as an array (profile). - * - * @return The array profile wrapping this value - */ - @throws[FrozenException] - override def toArrayInfo: ArrayInfo = _arrayInfo.get -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index dd1e1fde..469508db 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -1,7 +1,6 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Type -import org.scaladebugger.api.profiles.frozen.info.FrozenTypeInfo import scala.util.Try @@ -284,19 +283,4 @@ trait TypeInfo extends CommonInfo { * @return The human-readable description */ override def toPrettyString: String = s"Type $name ($signature)" - - /** - * Freezes the information, collecting all data at the current point in time. - * - * @return The information frozen at the current point in time - */ - override def freeze(): FrozenTypeInfo = FrozenTypeInfo( - name = this.name, - signature = this.signature, - _arrayType = this.tryToArrayType, - _classType = this.tryToClassType, - _interfaceType = this.tryToInterfaceType, - _referenceType = this.tryToReferenceType, - _primitiveType = this.tryToPrimitiveType - ) } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 43db2545..421f1267 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,7 +1,6 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value -import org.scaladebugger.api.profiles.frozen.info.FrozenValueInfo import scala.util.Try @@ -274,24 +273,4 @@ trait ValueInfo extends CommonInfo { else "???" }.getOrElse("") } - - /** - * Freezes the information, collecting all data at the current point in time. - * - * @return The information frozen at the current point in time - */ - override def freeze(): FrozenValueInfo = FrozenValueInfo( - `type` = this.`type`, - isNull = this.isNull, - isVoid = this.isVoid, - _localValue = this.tryToLocalValue, - _arrayInfo = this.tryToArrayInfo, - _stringInfo = this.tryToStringInfo, - _objectInfo = this.tryToObjectInfo, - _threadInfo = this.tryToThreadInfo, - _threadGroupInfo = this.tryToThreadGroupInfo, - _classObjectInfo = this.tryToClassObjectInfo, - _classLoaderInfo = this.tryToClassLoaderInfo, - _primitiveInfo = this.tryToPrimitiveInfo - ) } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/.placeholder b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/.placeholder deleted file mode 100644 index e69de29b..00000000 diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala new file mode 100644 index 00000000..48e92854 --- /dev/null +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -0,0 +1,28 @@ +package org.scaladebugger.macros.freeze + +import scala.reflect.macros.Context +import scala.language.experimental.macros +import scala.annotation.StaticAnnotation +import scala.reflect.internal.annotations.compileTimeOnly + +@compileTimeOnly("enable macro paradise to expand macro annotations") +class Freezable extends StaticAnnotation { + def macroTransform(annottees: Any*): Any = macro FreezableMacro +} + +object FreezableMacro { + def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { + import c.universe._ + val inputs = annottees.map(_.tree).toList + val (annottee, expandees) = inputs match { + case (param: ClassDef) :: (rest @ (_ :: _)) => (param, rest) + case (param: DefDef) :: (rest @ (_ :: _)) => (param, rest) + case (param: ValDef) :: (rest @ (_ :: _)) => (param, rest) + case (param: TypeDef) :: (rest @ (_ :: _)) => (param, rest) + case _ => (EmptyTree, inputs) + } + println((annottee, expandees)) + val outputs = expandees + c.Expr[Any](Block(outputs, Literal(Constant(())))) + } +} From 94c22a2d2449ef2f5cf82705e4c196c2f4de490b Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 03:56:32 -0700 Subject: [PATCH 06/36] Added notes for freeze macro wip --- .../api/profiles/traits/info/CommonInfo.scala | 2 +- .../api/profiles/traits/info/FrozenInfo.scala | 24 ---- .../api/profiles/traits/info/ValueInfo.scala | 5 +- .../macros/freeze/Freezable.scala | 134 ++++++++++++++++-- 4 files changed, 129 insertions(+), 36 deletions(-) delete mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 6262a15b..0c762109 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine /** * Represents common methods between information-gathering profiles. */ -trait CommonInfo extends JavaInfo with FrozenInfo { +trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. * diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala deleted file mode 100644 index f8ad992e..00000000 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrozenInfo.scala +++ /dev/null @@ -1,24 +0,0 @@ -package org.scaladebugger.api.profiles.traits.info - -import java.io.Serializable - -/** - * Represents a profile that provides common methods to freeze information - * such that it can be persisted and processed elsewhere. - */ -trait FrozenInfo { - /** - * Returns whether or not this information is frozen. - * - * @return If true, this information has been frozen, otherwise it - * represents live data - */ - def isFrozen: Boolean - - /** - * Freezes the information, collecting all data at the current point in time. - * - * @return The information frozen at the current point in time - */ - def freeze(): _ <: Serializable -} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 421f1267..78f043af 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,13 +1,14 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value +import org.scaladebugger.macros.freeze.Freezable import scala.util.Try /** * Represents information about a value. */ -trait ValueInfo extends CommonInfo { +@Freezable trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of * low-level Java instead of a higher-level abstraction. @@ -115,7 +116,7 @@ trait ValueInfo extends CommonInfo { * * @return True if null, otherwise false */ - def isNull: Boolean + @Freezable def isNull: Boolean /** * Returns whether or not this value is void. diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index 48e92854..be2d3929 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -7,21 +7,137 @@ import scala.reflect.internal.annotations.compileTimeOnly @compileTimeOnly("enable macro paradise to expand macro annotations") class Freezable extends StaticAnnotation { - def macroTransform(annottees: Any*): Any = macro FreezableMacro + def macroTransform(annottees: Any*): Any = macro FreezableMacro.impl } object FreezableMacro { def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ - val inputs = annottees.map(_.tree).toList - val (annottee, expandees) = inputs match { - case (param: ClassDef) :: (rest @ (_ :: _)) => (param, rest) - case (param: DefDef) :: (rest @ (_ :: _)) => (param, rest) - case (param: ValDef) :: (rest @ (_ :: _)) => (param, rest) - case (param: TypeDef) :: (rest @ (_ :: _)) => (param, rest) - case _ => (EmptyTree, inputs) + + def isFreezableAnnotation(t: Tree): Boolean = t match { + case Apply(f, args) => f match { + case Select(qual, name) => + println(s"Freezable: ${qual.getClass.getName} $name") + false + case _ => false + } + case _ => false + } + + + val (annottee, expandees) = annottees.map(_.tree) match { + case (classDef: ClassDef) :: rest => + // TODO: Should we be using + // q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" + val q""" + $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + val frozenClass = { + // TODO: Have an annotation of @Unfreezable that will force + // the method to throw an exception when frozen, so we can + // use that to fill in exception methods + // + // We leave methods with no annotation alone? + // + // Methods with Freezable will be replaced with the .get + // of a Try object and used as part of the Frozen constructor + val internals = body.map { + // TODO: Can we include other modifiers/annotations still? + case q"@Freezable $mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + if (paramss.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) + + // TODO: Should/do we need to mark this as overriden since + // that's what we are doing to the parent class? + q"def $tname[..$tparams](...$paramss): $tpt = $tname(...$args)" + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + // TODO: Should this only throw an exception if there is no + // body? In other words, just fill abstract methods with + // the exception + q"def $tname[..$tparams](...$paramss): $tpt = throw new Exception" + case t => t + } + + // TODO: scala.util.Try is not marked as serializable in 2.10/2.11; + // happens in 2.12; Success/Failure are case classes and a + // throwable in Java is already serializable. + // + // Make a wrapper for this that implements serializable? + // + // Any method not marked Freezable needs to have its + // implementation changed to throw a NotFrozenException + // + // Any method marked Freezable needs to use the .get method + // from the scala.util.Try equivalent as the implementation + // + // Constructor to class needs to take scala.util.Try equivalent + // as input for each method marked Freezable + q""" + class Frozen private(...$paramss) extends $tpname with java.io.Serializable { $self => + ..$internals + } + """ + } + + val freezeMethod = { + // TODO: Arguments need to be calls to scala.util.Try equivalent + // with input as call to parent class' method name + val args = List().map(t => q"""scala.util.Try.apply($t)""") + q""" + def freeze(): ${frozenClass.name} = new ${frozenClass.name} { + ..$args + } + """ + } + + val newContent = List(frozenClass, freezeMethod) + + // Generate a new class containing the helper methods and + // inner "Frozen" class representation + val newClassDef = q""" + $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + ..$newContent + } + """ + + (EmptyTree, newClassDef +: rest) + /*case (d: ClassDef) :: rest => + println(q""" + @Freezable private def potato: Int = 3 + """) + (EmptyTree, d +: rest)*/ + case (d: DefDef) :: rest => + if (d.tparams.nonEmpty) c.abort( + c.enclosingPosition, + "Freezable cannot be placed on a method with arguments!" + ) + + (EmptyTree, d +: rest) + case (d: ValDef) :: rest => d.tpt match { + // TODO: What types can we support here? + case _: Constant => (EmptyTree, d +: rest) + case _ => c.abort( + c.enclosingPosition, + "Freezable can only be placed on vals of constants!" + ) + } + case _ => + c.abort( + c.enclosingPosition, + "Freezable can only be placed on traits/classes, vals, and methods!" + ) } - println((annottee, expandees)) + //println((annottee, expandees)) val outputs = expandees c.Expr[Any](Block(outputs, Literal(Constant(())))) } From 76e48ef4b05fe7aafa31f0996b005980c35cf494 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 16:42:43 -0700 Subject: [PATCH 07/36] Added wip code generator (not working) --- .../api/profiles/traits/info/CommonInfo.scala | 11 +- .../api/profiles/traits/info/JavaInfo.scala | 8 +- .../api/profiles/traits/info/ValueInfo.scala | 44 ++-- .../macros/freeze/Freezable.scala | 223 +++++++++++------- .../macros/freeze/NotFrozenException.scala | 7 + .../macros/freeze/Unfreezable.scala | 10 + 6 files changed, 189 insertions(+), 114 deletions(-) create mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala create mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 0c762109..f2fd8741 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -2,24 +2,25 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Mirror import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine +import org.scaladebugger.macros.freeze.{Freezable, Unfreezable} /** * Represents common methods between information-gathering profiles. */ -trait CommonInfo extends JavaInfo { +@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. * * @return The Scala virtual machine instance */ - def scalaVirtualMachine: ScalaVirtualMachine + @Unfreezable def scalaVirtualMachine: ScalaVirtualMachine /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - def toJdiInstance: Mirror + @Unfreezable def toJdiInstance: Mirror /** * Returns a string presenting a better human-readable description of @@ -27,7 +28,7 @@ trait CommonInfo extends JavaInfo { * * @return The human-readable description */ - def toPrettyString: String + @Freezable def toPrettyString: String /** * Converts the current profile instance to a representation of @@ -36,5 +37,5 @@ trait CommonInfo extends JavaInfo { * @return The profile instance providing an implementation corresponding * to Java */ - override def toJavaInfo: CommonInfo + @Freezable override def toJavaInfo: CommonInfo } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index 7d2b08b1..dc375119 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -1,10 +1,12 @@ package org.scaladebugger.api.profiles.traits.info +import org.scaladebugger.macros.freeze.Freezable + /** * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -trait JavaInfo { +@Freezable trait JavaInfo { /** * Returns whether or not this info profile represents the low-level Java * implementation. @@ -13,7 +15,7 @@ trait JavaInfo { * otherwise this profile represents something higher-level like * Scala, Jython, or JRuby */ - def isJavaInfo: Boolean + @Freezable def isJavaInfo: Boolean /** * Converts the current profile instance to a representation of @@ -22,5 +24,5 @@ trait JavaInfo { * @return The profile instance providing an implementation corresponding * to Java */ - def toJavaInfo: AnyRef + @Freezable def toJavaInfo: AnyRef } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 78f043af..c2750857 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,7 +1,7 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value -import org.scaladebugger.macros.freeze.Freezable +import org.scaladebugger.macros.freeze.{Freezable, Unfreezable} import scala.util.Try @@ -16,21 +16,21 @@ import scala.util.Try * @return The profile instance providing an implementation corresponding * to Java */ - override def toJavaInfo: ValueInfo + @Freezable override def toJavaInfo: ValueInfo /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - override def toJdiInstance: Value + @Unfreezable override def toJdiInstance: Value /** * Returns the type information for the value. * * @return The profile containing type information */ - def `type`: TypeInfo + @Freezable def `type`: TypeInfo /** * Returns the type information for the value. @@ -53,63 +53,63 @@ import scala.util.Try * * @return The value as a local instance */ - def toLocalValue: Any + @Freezable def toLocalValue: Any /** * Returns whether or not this value represents a primitive. * * @return True if a primitive, otherwise false */ - def isPrimitive: Boolean + @Freezable def isPrimitive: Boolean /** * Returns whether or not this value represents an array. * * @return True if an array, otherwise false */ - def isArray: Boolean + @Freezable def isArray: Boolean /** * Returns whether or not this value represents a class loader. * * @return True if a class loader, otherwise false */ - def isClassLoader: Boolean + @Freezable def isClassLoader: Boolean /** * Returns whether or not this value represents a class object. * * @return True if a class object, otherwise false */ - def isClassObject: Boolean + @Freezable def isClassObject: Boolean /** * Returns whether or not this value represents a thread group. * * @return True if a thread group, otherwise false */ - def isThreadGroup: Boolean + @Freezable def isThreadGroup: Boolean /** * Returns whether or not this value represents a thread. * * @return True if a thread, otherwise false */ - def isThread: Boolean + @Freezable def isThread: Boolean /** * Returns whether or not this value represents an object. * * @return True if an object, otherwise false */ - def isObject: Boolean + @Freezable def isObject: Boolean /** * Returns whether or not this value represents a string. * * @return True if a string, otherwise false */ - def isString: Boolean + @Freezable def isString: Boolean /** * Returns whether or not this value is null. @@ -123,7 +123,7 @@ import scala.util.Try * * @return True if void, otherwise false */ - def isVoid: Boolean + @Freezable def isVoid: Boolean /** * Returns the value as a primitive (profile). @@ -139,7 +139,7 @@ import scala.util.Try * @return The primitive profile wrapping this value */ @throws[AssertionError] - def toPrimitiveInfo: PrimitiveInfo + @Freezable def toPrimitiveInfo: PrimitiveInfo /** * Returns the value as a class loader (profile). @@ -155,7 +155,7 @@ import scala.util.Try * @return The class loader profile wrapping this value */ @throws[AssertionError] - def toClassLoaderInfo: ClassLoaderInfo + @Freezable def toClassLoaderInfo: ClassLoaderInfo /** * Returns the value as a class object (profile). @@ -171,7 +171,7 @@ import scala.util.Try * @return The class object profile wrapping this value */ @throws[AssertionError] - def toClassObjectInfo: ClassObjectInfo + @Freezable def toClassObjectInfo: ClassObjectInfo /** * Returns the value as a thread group (profile). @@ -187,7 +187,7 @@ import scala.util.Try * @return The thread group profile wrapping this value */ @throws[AssertionError] - def toThreadGroupInfo: ThreadGroupInfo + @Freezable def toThreadGroupInfo: ThreadGroupInfo /** * Returns the value as a thread (profile). @@ -203,7 +203,7 @@ import scala.util.Try * @return The thread profile wrapping this value */ @throws[AssertionError] - def toThreadInfo: ThreadInfo + @Freezable def toThreadInfo: ThreadInfo /** * Returns the value as an object (profile). @@ -219,7 +219,7 @@ import scala.util.Try * @return The object profile wrapping this value */ @throws[AssertionError] - def toObjectInfo: ObjectInfo + @Freezable def toObjectInfo: ObjectInfo /** * Returns the value as a string (profile). @@ -235,7 +235,7 @@ import scala.util.Try * @return The string profile wrapping this value */ @throws[AssertionError] - def toStringInfo: StringInfo + @Freezable def toStringInfo: StringInfo /** * Returns the value as an array (profile). @@ -251,7 +251,7 @@ import scala.util.Try * @return The array profile wrapping this value */ @throws[AssertionError] - def toArrayInfo: ArrayInfo + @Freezable def toArrayInfo: ArrayInfo /** * Returns a string presenting a better human-readable description of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index be2d3929..6d6a17f8 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -2,9 +2,25 @@ package org.scaladebugger.macros.freeze import scala.reflect.macros.Context import scala.language.experimental.macros -import scala.annotation.StaticAnnotation +import scala.annotation.{StaticAnnotation, tailrec} import scala.reflect.internal.annotations.compileTimeOnly +/** + * Represents a freezable bit of information. + * + *

If placed on a trait, injects a `freeze()` method along with a `Frozen` + * class implementing the trait.

+ * + *

Any internal method marked with this annotation will have its live value + * from an implementation stored at freeze time.

+ * + *

Any internal method marked with the + * [[org.scaladebugger.macros.freeze.Unfreezable]] annotation will + * be marked to always throw an exception when accessed.

+ * + *

Any internal method not marked with either annotation will keep its + * current implementation from the trait itself.

+ */ @compileTimeOnly("enable macro paradise to expand macro annotations") class Freezable extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro FreezableMacro.impl @@ -14,108 +30,156 @@ object FreezableMacro { def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ - def isFreezableAnnotation(t: Tree): Boolean = t match { + def findClassPackage(classDef: ClassDef): TermName = { + val dummyClassName = newTypeName(s"Dummy${newTypeName(c.fresh())}") + val dummyClass = c.typeCheck(q"class $dummyClassName") + newTermName(packageFromSymbol(dummyClass.symbol.owner)) + } + + def packageFromSymbol(symbol: Symbol): String = { + @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { + if (symbol == NoSymbol) tokens.mkString(".") + else buildPackage(symbol.owner, symbol.name.decoded +: tokens) + } + + buildPackage(symbol, Nil) + } + + def containsAnnotation(d: DefDef, aName: String): Boolean = + d.mods.annotations.exists(a => isAnnotation(a, aName)) + + def isAnnotation(t: Tree, aName: String): Boolean = t match { case Apply(f, args) => f match { - case Select(qual, name) => - println(s"Freezable: ${qual.getClass.getName} $name") - false - case _ => false + case Select(qual, name) => qual match { + case New(tpt) => tpt match { + case Ident(iName) => iName.decoded == aName + case _ => false + } + case _ => false + } } case _ => false } + def isTrait(classDef: ClassDef): Boolean = { + try { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + true + } catch { + case _: Throwable => false + } + } + val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: rest => - // TODO: Should we be using - // q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" + case (classDef: ClassDef) :: Nil if isTrait(classDef) => val q""" - $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { + $mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$body } """ = classDef - val frozenClass = { - // TODO: Have an annotation of @Unfreezable that will force - // the method to throw an exception when frozen, so we can - // use that to fill in exception methods - // - // We leave methods with no annotation alone? - // - // Methods with Freezable will be replaced with the .get - // of a Try object and used as part of the Frozen constructor - val internals = body.map { - // TODO: Can we include other modifiers/annotations still? - case q"@Freezable $mods def $tname[..$tparams](...$paramss): $tpt = $expr" => - if (paramss.nonEmpty) c.abort( + // Represents name of companion object + val traitTypeName: TypeName = tpname + val oName = newTermName(traitTypeName.toString) + + // Represents name of variable passed to freeze method + val freezeObjName = newTermName("valueToFreeze") + + val (frozenClass, freezeMethod) = { + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body + val internals = bodyTrees.collect { + case d: DefDef if containsAnnotation(d, "Freezable") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + val paramTrees: List[List[ValDef]] = paramss + if (paramTrees.nonEmpty) c.abort( c.enclosingPosition, s"Unable to freeze $tname! Must have zero arguments!" ) - // TODO: Should/do we need to mark this as overriden since - // that's what we are doing to the parent class? - q"def $tname[..$tparams](...$paramss): $tpt = $tname(...$args)" - case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => - // TODO: Should this only throw an exception if there is no - // body? In other words, just fill abstract methods with - // the exception - q"def $tname[..$tparams](...$paramss): $tpt = throw new Exception" - case t => t - } + val name = newTermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "Freezable") || + isAnnotation(a, "Unfreezable") + }) + ) + + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + case d: DefDef if containsAnnotation(d, "Unfreezable") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "Freezable") || + isAnnotation(a, "Unfreezable") + }) + ) - // TODO: scala.util.Try is not marked as serializable in 2.10/2.11; - // happens in 2.12; Success/Failure are case classes and a - // throwable in Java is already serializable. - // - // Make a wrapper for this that implements serializable? - // - // Any method not marked Freezable needs to have its - // implementation changed to throw a NotFrozenException - // - // Any method marked Freezable needs to use the .get method - // from the scala.util.Try equivalent as the implementation - // - // Constructor to class needs to take scala.util.Try equivalent - // as input for each method marked Freezable - q""" - class Frozen private(...$paramss) extends $tpname with java.io.Serializable { $self => + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!") + """ + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" + class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => ..$internals } """ - } - - val freezeMethod = { - // TODO: Arguments need to be calls to scala.util.Try equivalent - // with input as call to parent class' method name - val args = List().map(t => q"""scala.util.Try.apply($t)""") - q""" - def freeze(): ${frozenClass.name} = new ${frozenClass.name} { - ..$args - } + val method = q""" + def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) """ - } - val newContent = List(frozenClass, freezeMethod) + (klass, method) + } // Generate a new class containing the helper methods and - // inner "Frozen" class representation - val newClassDef = q""" - $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - ..$newContent + // object containing "Frozen" class representation + val newObjDef = q""" + object $oName { + $frozenClass + $freezeMethod } """ - (EmptyTree, newClassDef +: rest) - /*case (d: ClassDef) :: rest => - println(q""" - @Freezable private def potato: Int = 3 - """) - (EmptyTree, d +: rest)*/ + println("NEW OBJ:: " + newObjDef) + + (EmptyTree, List(classDef, newObjDef)) case (d: DefDef) :: rest => if (d.tparams.nonEmpty) c.abort( c.enclosingPosition, @@ -123,21 +187,12 @@ object FreezableMacro { ) (EmptyTree, d +: rest) - case (d: ValDef) :: rest => d.tpt match { - // TODO: What types can we support here? - case _: Constant => (EmptyTree, d +: rest) - case _ => c.abort( - c.enclosingPosition, - "Freezable can only be placed on vals of constants!" - ) - } case _ => c.abort( c.enclosingPosition, - "Freezable can only be placed on traits/classes, vals, and methods!" + "Freezable can only be placed on traits and methods!" ) } - //println((annottee, expandees)) val outputs = expandees c.Expr[Any](Block(outputs, Literal(Constant(())))) } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala new file mode 100644 index 00000000..69f0fb07 --- /dev/null +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala @@ -0,0 +1,7 @@ +package org.scaladebugger.macros.freeze + +/** + * Exception indicating that a particular construct was not frozen during + * a freeze request. + */ +class NotFrozenException extends Exception with Serializable diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala new file mode 100644 index 00000000..9a6039cb --- /dev/null +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala @@ -0,0 +1,10 @@ +package org.scaladebugger.macros.freeze +import scala.language.experimental.macros +import scala.annotation.StaticAnnotation + +/** + * Marks an internal method of a [[org.scaladebugger.macros.freeze.Freezable]] + * component as unable to be frozen, which means it will be swapped with an + * exception when frozen. + */ +class Unfreezable extends StaticAnnotation From 7d6900714be7a43b9f4d1119e81ff327d7217719 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 17:09:20 -0700 Subject: [PATCH 08/36] Still not working --- .../api/profiles/traits/info/CommonInfo.scala | 11 ++--- .../api/profiles/traits/info/JavaInfo.scala | 6 +-- .../api/profiles/traits/info/ValueInfo.scala | 47 +++++++++---------- .../macros/freeze/CanFreeze.scala | 11 +++++ .../{Unfreezable.scala => CannotFreeze.scala} | 2 +- .../macros/freeze/Freezable.scala | 29 +++++------- .../macros/freeze/NotFrozenException.scala | 7 --- 7 files changed, 55 insertions(+), 58 deletions(-) create mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala rename scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/{Unfreezable.scala => CannotFreeze.scala} (87%) delete mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index f2fd8741..0c762109 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -2,25 +2,24 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Mirror import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine -import org.scaladebugger.macros.freeze.{Freezable, Unfreezable} /** * Represents common methods between information-gathering profiles. */ -@Freezable trait CommonInfo extends JavaInfo { +trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. * * @return The Scala virtual machine instance */ - @Unfreezable def scalaVirtualMachine: ScalaVirtualMachine + def scalaVirtualMachine: ScalaVirtualMachine /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - @Unfreezable def toJdiInstance: Mirror + def toJdiInstance: Mirror /** * Returns a string presenting a better human-readable description of @@ -28,7 +27,7 @@ import org.scaladebugger.macros.freeze.{Freezable, Unfreezable} * * @return The human-readable description */ - @Freezable def toPrettyString: String + def toPrettyString: String /** * Converts the current profile instance to a representation of @@ -37,5 +36,5 @@ import org.scaladebugger.macros.freeze.{Freezable, Unfreezable} * @return The profile instance providing an implementation corresponding * to Java */ - @Freezable override def toJavaInfo: CommonInfo + override def toJavaInfo: CommonInfo } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index dc375119..a4a917bc 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -1,6 +1,6 @@ package org.scaladebugger.api.profiles.traits.info -import org.scaladebugger.macros.freeze.Freezable +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents a profile that provides common methods to convert info profiles @@ -15,7 +15,7 @@ import org.scaladebugger.macros.freeze.Freezable * otherwise this profile represents something higher-level like * Scala, Jython, or JRuby */ - @Freezable def isJavaInfo: Boolean + @CanFreeze def isJavaInfo: Boolean /** * Converts the current profile instance to a representation of @@ -24,5 +24,5 @@ import org.scaladebugger.macros.freeze.Freezable * @return The profile instance providing an implementation corresponding * to Java */ - @Freezable def toJavaInfo: AnyRef + @CannotFreeze def toJavaInfo: AnyRef } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index c2750857..421f1267 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,14 +1,13 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value -import org.scaladebugger.macros.freeze.{Freezable, Unfreezable} import scala.util.Try /** * Represents information about a value. */ -@Freezable trait ValueInfo extends CommonInfo { +trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of * low-level Java instead of a higher-level abstraction. @@ -16,21 +15,21 @@ import scala.util.Try * @return The profile instance providing an implementation corresponding * to Java */ - @Freezable override def toJavaInfo: ValueInfo + override def toJavaInfo: ValueInfo /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - @Unfreezable override def toJdiInstance: Value + override def toJdiInstance: Value /** * Returns the type information for the value. * * @return The profile containing type information */ - @Freezable def `type`: TypeInfo + def `type`: TypeInfo /** * Returns the type information for the value. @@ -53,77 +52,77 @@ import scala.util.Try * * @return The value as a local instance */ - @Freezable def toLocalValue: Any + def toLocalValue: Any /** * Returns whether or not this value represents a primitive. * * @return True if a primitive, otherwise false */ - @Freezable def isPrimitive: Boolean + def isPrimitive: Boolean /** * Returns whether or not this value represents an array. * * @return True if an array, otherwise false */ - @Freezable def isArray: Boolean + def isArray: Boolean /** * Returns whether or not this value represents a class loader. * * @return True if a class loader, otherwise false */ - @Freezable def isClassLoader: Boolean + def isClassLoader: Boolean /** * Returns whether or not this value represents a class object. * * @return True if a class object, otherwise false */ - @Freezable def isClassObject: Boolean + def isClassObject: Boolean /** * Returns whether or not this value represents a thread group. * * @return True if a thread group, otherwise false */ - @Freezable def isThreadGroup: Boolean + def isThreadGroup: Boolean /** * Returns whether or not this value represents a thread. * * @return True if a thread, otherwise false */ - @Freezable def isThread: Boolean + def isThread: Boolean /** * Returns whether or not this value represents an object. * * @return True if an object, otherwise false */ - @Freezable def isObject: Boolean + def isObject: Boolean /** * Returns whether or not this value represents a string. * * @return True if a string, otherwise false */ - @Freezable def isString: Boolean + def isString: Boolean /** * Returns whether or not this value is null. * * @return True if null, otherwise false */ - @Freezable def isNull: Boolean + def isNull: Boolean /** * Returns whether or not this value is void. * * @return True if void, otherwise false */ - @Freezable def isVoid: Boolean + def isVoid: Boolean /** * Returns the value as a primitive (profile). @@ -139,7 +138,7 @@ import scala.util.Try * @return The primitive profile wrapping this value */ @throws[AssertionError] - @Freezable def toPrimitiveInfo: PrimitiveInfo + def toPrimitiveInfo: PrimitiveInfo /** * Returns the value as a class loader (profile). @@ -155,7 +154,7 @@ import scala.util.Try * @return The class loader profile wrapping this value */ @throws[AssertionError] - @Freezable def toClassLoaderInfo: ClassLoaderInfo + def toClassLoaderInfo: ClassLoaderInfo /** * Returns the value as a class object (profile). @@ -171,7 +170,7 @@ import scala.util.Try * @return The class object profile wrapping this value */ @throws[AssertionError] - @Freezable def toClassObjectInfo: ClassObjectInfo + def toClassObjectInfo: ClassObjectInfo /** * Returns the value as a thread group (profile). @@ -187,7 +186,7 @@ import scala.util.Try * @return The thread group profile wrapping this value */ @throws[AssertionError] - @Freezable def toThreadGroupInfo: ThreadGroupInfo + def toThreadGroupInfo: ThreadGroupInfo /** * Returns the value as a thread (profile). @@ -203,7 +202,7 @@ import scala.util.Try * @return The thread profile wrapping this value */ @throws[AssertionError] - @Freezable def toThreadInfo: ThreadInfo + def toThreadInfo: ThreadInfo /** * Returns the value as an object (profile). @@ -219,7 +218,7 @@ import scala.util.Try * @return The object profile wrapping this value */ @throws[AssertionError] - @Freezable def toObjectInfo: ObjectInfo + def toObjectInfo: ObjectInfo /** * Returns the value as a string (profile). @@ -235,7 +234,7 @@ import scala.util.Try * @return The string profile wrapping this value */ @throws[AssertionError] - @Freezable def toStringInfo: StringInfo + def toStringInfo: StringInfo /** * Returns the value as an array (profile). @@ -251,7 +250,7 @@ import scala.util.Try * @return The array profile wrapping this value */ @throws[AssertionError] - @Freezable def toArrayInfo: ArrayInfo + def toArrayInfo: ArrayInfo /** * Returns a string presenting a better human-readable description of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala new file mode 100644 index 00000000..1f5e34bc --- /dev/null +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala @@ -0,0 +1,11 @@ +package org.scaladebugger.macros.freeze + +import scala.annotation.StaticAnnotation +import scala.language.experimental.macros + +/** + * Marks an internal method of a [[org.scaladebugger.macros.freeze.Freezable]] + * component as able to be frozen, which means it will be swapped with the + * result of accessing the live data when frozen. + */ +class CanFreeze extends StaticAnnotation diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CannotFreeze.scala similarity index 87% rename from scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala rename to scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CannotFreeze.scala index 9a6039cb..1de7fadb 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Unfreezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CannotFreeze.scala @@ -7,4 +7,4 @@ import scala.annotation.StaticAnnotation * component as unable to be frozen, which means it will be swapped with an * exception when frozen. */ -class Unfreezable extends StaticAnnotation +class CannotFreeze extends StaticAnnotation diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index 6d6a17f8..4824c745 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -8,14 +8,15 @@ import scala.reflect.internal.annotations.compileTimeOnly /** * Represents a freezable bit of information. * - *

If placed on a trait, injects a `freeze()` method along with a `Frozen` + *

Injects a `freeze()` method along with a `Frozen` * class implementing the trait.

* - *

Any internal method marked with this annotation will have its live value + *

Any internal method marked with + * [[org.scaladebugger.macros.freeze.CanFreeze]] will have its live value * from an implementation stored at freeze time.

* *

Any internal method marked with the - * [[org.scaladebugger.macros.freeze.Unfreezable]] annotation will + * [[org.scaladebugger.macros.freeze.CannotFreeze]] annotation will * be marked to always throw an exception when accessed.

* *

Any internal method not marked with either annotation will keep its @@ -99,7 +100,7 @@ object FreezableMacro { val cArgs = collection.mutable.ArrayBuffer[Tree]() val bodyTrees: List[Tree] = body val internals = bodyTrees.collect { - case d: DefDef if containsAnnotation(d, "Freezable") => + case d: DefDef if containsAnnotation(d, "CanFreeze") => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d val paramTrees: List[List[ValDef]] = paramss @@ -122,13 +123,13 @@ object FreezableMacro { flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "Freezable") || - isAnnotation(a, "Unfreezable") + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") }) ) q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - case d: DefDef if containsAnnotation(d, "Unfreezable") => + case d: DefDef if containsAnnotation(d, "CannotFreeze") => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d // Add override if not already there @@ -137,8 +138,8 @@ object FreezableMacro { flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "Freezable") || - isAnnotation(a, "Unfreezable") + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") }) ) @@ -177,16 +178,9 @@ object FreezableMacro { } """ - println("NEW OBJ:: " + newObjDef) + //println("NEW OBJ:: " + newObjDef) (EmptyTree, List(classDef, newObjDef)) - case (d: DefDef) :: rest => - if (d.tparams.nonEmpty) c.abort( - c.enclosingPosition, - "Freezable cannot be placed on a method with arguments!" - ) - - (EmptyTree, d +: rest) case _ => c.abort( c.enclosingPosition, @@ -194,6 +188,7 @@ object FreezableMacro { ) } val outputs = expandees + println(outputs) c.Expr[Any](Block(outputs, Literal(Constant(())))) } } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala deleted file mode 100644 index 69f0fb07..00000000 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/NotFrozenException.scala +++ /dev/null @@ -1,7 +0,0 @@ -package org.scaladebugger.macros.freeze - -/** - * Exception indicating that a particular construct was not frozen during - * a freeze request. - */ -class NotFrozenException extends Exception with Serializable From 0ec09b23ef3f77ad25221ee83390597e124eda42 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 18:50:59 -0700 Subject: [PATCH 09/36] Still not working, but supports companion object already existing --- .../macros/freeze/Freezable.scala | 225 +++++++++++------- 1 file changed, 133 insertions(+), 92 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index 4824c745..ea67b127 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -77,109 +77,147 @@ object FreezableMacro { } } + def processTrait(classDef: ClassDef): (ClassDef, ModuleDef) = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef - val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: Nil if isTrait(classDef) => + // Represents name of companion object + val traitTypeName: TypeName = tpname + val oName = newTermName(traitTypeName.toString) + + // Generate a new class containing the helper methods and + // object containing "Frozen" class representation + val moduleDef: ModuleDef = q"object $oName {}" + + processTraitAndObj(classDef, moduleDef) + } + + def processTraitAndObj( + classDef: ClassDef, + moduleDef: ModuleDef + ): (ClassDef, ModuleDef) = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of variable passed to freeze method + val freezeObjName = newTermName("valueToFreeze") + + val (frozenClass, freezeMethod) = { + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body + val internals = bodyTrees.collect { + case d: DefDef if containsAnnotation(d, "CanFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + val paramTrees: List[List[ValDef]] = paramss + if (paramTrees.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) + + val name = newTermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + case d: DefDef if containsAnnotation(d, "CannotFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!") + """ + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" + class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => + ..$internals + } + """ + val method = q""" + def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) + """ + + (klass, method) + } + + val newModuleDef: ModuleDef = { val q""" - $mods trait $tpname[..$tparams] extends { + $mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body } - """ = classDef - - // Represents name of companion object - val traitTypeName: TypeName = tpname - val oName = newTermName(traitTypeName.toString) - - // Represents name of variable passed to freeze method - val freezeObjName = newTermName("valueToFreeze") - - val (frozenClass, freezeMethod) = { - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body - val internals = bodyTrees.collect { - case d: DefDef if containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss - if (paramTrees.nonEmpty) c.abort( - c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" - ) - - val name = newTermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - """) - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - case d: DefDef if containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = - throw new IllegalStateException("Method not frozen!") - """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) - - val klass = q""" - class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => - ..$internals - } - """ - val method = q""" - def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) - """ - - (klass, method) - } + """ = moduleDef - // Generate a new class containing the helper methods and - // object containing "Frozen" class representation - val newObjDef = q""" - object $oName { + q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$body $frozenClass $freezeMethod } """ + } + + (classDef, newModuleDef) + } - //println("NEW OBJ:: " + newObjDef) + val (annottee, expandees) = annottees.map(_.tree) match { + case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => + //println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) + val (newClassDef, newObjDef) = processTraitAndObj(classDef, moduleDef) + (EmptyTree, List(classDef, newObjDef)) + case (classDef: ClassDef) :: Nil if isTrait(classDef) => + //println("INPUT CLASS ONLY :: " + classDef) + val (newClassDef, newObjDef) = processTrait(classDef) (EmptyTree, List(classDef, newObjDef)) case _ => c.abort( @@ -187,8 +225,11 @@ object FreezableMacro { "Freezable can only be placed on traits and methods!" ) } + val outputs = expandees - println(outputs) - c.Expr[Any](Block(outputs, Literal(Constant(())))) + val block = Block(outputs, Literal(Constant(()))) + + //println(block) + c.Expr[Any](block) } } From 579a4742d624d7a373d28105ad29f8736ca1b911 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 18:53:51 -0700 Subject: [PATCH 10/36] Updated error message --- .../main/scala/org/scaladebugger/macros/freeze/Freezable.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index ea67b127..f527ff4f 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -222,7 +222,7 @@ object FreezableMacro { case _ => c.abort( c.enclosingPosition, - "Freezable can only be placed on traits and methods!" + "Freezable can only be placed on traits!" ) } From 08f903aca1d2858a1b83865143661c15c8431bf7 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 19:11:58 -0700 Subject: [PATCH 11/36] Added implicit support for freeze --- .../macros/freeze/Freezable.scala | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index f527ff4f..15c58323 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -77,7 +77,7 @@ object FreezableMacro { } } - def processTrait(classDef: ClassDef): (ClassDef, ModuleDef) = { + def processTrait(classDef: ClassDef): List[Tree] = { val q""" $mods trait $tpname[..$tparams] extends { ..$earlydefns @@ -100,7 +100,7 @@ object FreezableMacro { def processTraitAndObj( classDef: ClassDef, moduleDef: ModuleDef - ): (ClassDef, ModuleDef) = { + ): List[Tree] = { val q""" $mods trait $tpname[..$tparams] extends { ..$earlydefns @@ -195,30 +195,44 @@ object FreezableMacro { } """ = moduleDef + val implicitMethodName = newTypeName(s"${tpname}FrozenWrapper") + val implicitFreezeMethod = q""" + implicit class $implicitMethodName(private val $freezeObjName: $tpname) { + def freeze(): Frozen = $tname.freeze($freezeObjName) + } + """ + + val oldBody: List[Tree] = body + val newBody = oldBody ++ List( + frozenClass, + freezeMethod, + q"object Implicits { $implicitFreezeMethod }" + ) + q""" $mods object $tname extends { ..$earlydefns } with ..$parents { $self => - ..$body - $frozenClass - $freezeMethod + ..$newBody } """ } - (classDef, newModuleDef) + List(classDef, newModuleDef) } val (annottee, expandees) = annottees.map(_.tree) match { case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => - //println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) - val (newClassDef, newObjDef) = processTraitAndObj(classDef, moduleDef) - (EmptyTree, List(classDef, newObjDef)) + println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) + val results = processTraitAndObj(classDef, moduleDef) + println("RESULTS :: " + results) + (EmptyTree, results) case (classDef: ClassDef) :: Nil if isTrait(classDef) => - //println("INPUT CLASS ONLY :: " + classDef) - val (newClassDef, newObjDef) = processTrait(classDef) - (EmptyTree, List(classDef, newObjDef)) + println("INPUT CLASS ONLY :: " + classDef) + val results = processTrait(classDef) + println("RESULTS :: " + results) + (EmptyTree, results) case _ => c.abort( c.enclosingPosition, @@ -229,7 +243,6 @@ object FreezableMacro { val outputs = expandees val block = Block(outputs, Literal(Constant(()))) - //println(block) c.Expr[Any](block) } } From 5ff9fe16769f104e9cad10c1409a37fa1d9bece5 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 21:27:06 -0700 Subject: [PATCH 12/36] Moved macro implementation to individual 2.10/2.11/2.12 versions (needs to be consolidated) --- .../macros/freeze/FreezableMacro.scala | 225 +++++++++++++++++ .../FreezableMacro.scala | 225 +++++++++++++++++ .../FreezableMacro.scala | 226 ++++++++++++++++++ .../macros/freeze/Freezable.scala | 223 +---------------- 4 files changed, 677 insertions(+), 222 deletions(-) create mode 100644 scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala create mode 100644 scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala create mode 100644 scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala diff --git a/scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala new file mode 100644 index 00000000..fca2d086 --- /dev/null +++ b/scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -0,0 +1,225 @@ +package org.scaladebugger.macros.freeze + +import scala.annotation.tailrec +import scala.language.experimental.macros +import scala.reflect.macros.Context + +object FreezableMacro { + def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { + import c.universe._ + + def findClassPackage(classDef: ClassDef): TermName = { + val dummyClassName = newTypeName(s"Dummy${newTypeName(c.fresh())}") + val dummyClass = c.typeCheck(q"class $dummyClassName") + newTermName(packageFromSymbol(dummyClass.symbol.owner)) + } + + def packageFromSymbol(symbol: Symbol): String = { + @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { + if (symbol == NoSymbol) tokens.mkString(".") + else buildPackage(symbol.owner, symbol.name.decoded +: tokens) + } + + buildPackage(symbol, Nil) + } + + def containsAnnotation(d: DefDef, aName: String): Boolean = + d.mods.annotations.exists(a => isAnnotation(a, aName)) + + def isAnnotation(t: Tree, aName: String): Boolean = t match { + case Apply(f, args) => f match { + case Select(qual, name) => qual match { + case New(tpt) => tpt match { + case Ident(iName) => iName.decoded == aName + case _ => false + } + case _ => false + } + } + case _ => false + } + + def isTrait(classDef: ClassDef): Boolean = { + try { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + true + } catch { + case _: Throwable => false + } + } + + def processTrait(classDef: ClassDef): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of companion object + val traitTypeName: TypeName = tpname + val oName = newTermName(traitTypeName.toString) + + // Generate a new class containing the helper methods and + // object containing "Frozen" class representation + val moduleDef: ModuleDef = q"object $oName {}" + + processTraitAndObj(classDef, moduleDef) + } + + def processTraitAndObj( + classDef: ClassDef, + moduleDef: ModuleDef + ): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of variable passed to freeze method + val freezeObjName = newTermName("valueToFreeze") + + val (frozenClass, freezeMethod) = { + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body + val internals = bodyTrees.collect { + case d: DefDef if containsAnnotation(d, "CanFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + val paramTrees: List[List[ValDef]] = paramss + if (paramTrees.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) + + val name = newTermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + case d: DefDef if containsAnnotation(d, "CannotFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!") + """ + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" + class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => + ..$internals + } + """ + val method = q""" + def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) + """ + + (klass, method) + } + + val newModuleDef: ModuleDef = { + val q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = moduleDef + + val implicitMethodName = newTypeName(s"${tpname}FrozenWrapper") + val implicitFreezeMethod = q""" + implicit class $implicitMethodName(private val $freezeObjName: $tpname) { + def freeze(): Frozen = $tname.freeze($freezeObjName) + } + """ + + val oldBody: List[Tree] = body + val newBody = oldBody ++ List( + frozenClass, + freezeMethod, + q"object Implicits { $implicitFreezeMethod }" + ) + + q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$newBody + } + """ + } + + List(classDef, newModuleDef) + } + + + val (annottee, expandees) = annottees.map(_.tree) match { + case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => + println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) + val results = processTraitAndObj(classDef, moduleDef) + println("RESULTS :: " + results) + (EmptyTree, results) + case (classDef: ClassDef) :: Nil if isTrait(classDef) => + println("INPUT CLASS ONLY :: " + classDef) + val results = processTrait(classDef) + println("RESULTS :: " + results) + (EmptyTree, results) + case _ => + c.abort( + c.enclosingPosition, + "Freezable can only be placed on traits!" + ) + } + + val outputs = expandees + val block = Block(outputs, Literal(Constant(()))) + + c.Expr[Any](block) + } +} diff --git a/scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala new file mode 100644 index 00000000..8caf7e94 --- /dev/null +++ b/scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala @@ -0,0 +1,225 @@ +package org.scaladebugger.macros.freeze + +import scala.annotation.tailrec +import scala.language.experimental.macros +import scala.reflect.macros.whitebox.Context + +object FreezableMacro { + def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { + import c.universe._ + + def findClassPackage(classDef: ClassDef): TermName = { + val dummyClassName = TypeName(s"Dummy${TypeName(c.freshName())}") + val dummyClass = c.typecheck(q"class $dummyClassName") + TermName(packageFromSymbol(dummyClass.symbol.owner)) + } + + def packageFromSymbol(symbol: Symbol): String = { + @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { + if (symbol == NoSymbol) tokens.mkString(".") + else buildPackage(symbol.owner, symbol.name.decodedName.toString +: tokens) + } + + buildPackage(symbol, Nil) + } + + def containsAnnotation(d: DefDef, aName: String): Boolean = + d.mods.annotations.exists(a => isAnnotation(a, aName)) + + def isAnnotation(t: Tree, aName: String): Boolean = t match { + case Apply(f, args) => f match { + case Select(qual, name) => qual match { + case New(tpt) => tpt match { + case Ident(iName) => iName.decodedName.toString == aName + case _ => false + } + case _ => false + } + } + case _ => false + } + + def isTrait(classDef: ClassDef): Boolean = { + try { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + true + } catch { + case _: Throwable => false + } + } + + def processTrait(classDef: ClassDef): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of companion object + val traitTypeName: TypeName = tpname + val oName = TermName(traitTypeName.toString) + + // Generate a new class containing the helper methods and + // object containing "Frozen" class representation + val moduleDef: ModuleDef = q"object $oName {}" + + processTraitAndObj(classDef, moduleDef) + } + + def processTraitAndObj( + classDef: ClassDef, + moduleDef: ModuleDef + ): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of variable passed to freeze method + val freezeObjName = TermName("valueToFreeze") + + val (frozenClass, freezeMethod) = { + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body + val internals = bodyTrees.collect { + case d: DefDef if containsAnnotation(d, "CanFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + val paramTrees: List[List[ValDef]] = paramss + if (paramTrees.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) + + val name = TermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + case d: DefDef if containsAnnotation(d, "CannotFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!") + """ + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" + class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => + ..$internals + } + """ + val method = q""" + def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) + """ + + (klass, method) + } + + val newModuleDef: ModuleDef = { + val q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = moduleDef + + val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") + val implicitFreezeMethod = q""" + implicit class $implicitMethodName(private val $freezeObjName: $tpname) { + def freeze(): Frozen = $tname.freeze($freezeObjName) + } + """ + + val oldBody: List[Tree] = body + val newBody = oldBody ++ List( + frozenClass, + freezeMethod, + q"object Implicits { $implicitFreezeMethod }" + ) + + q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$newBody + } + """ + } + + List(classDef, newModuleDef) + } + + + val (annottee, expandees) = annottees.map(_.tree) match { + case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => + println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) + val results = processTraitAndObj(classDef, moduleDef) + println("RESULTS :: " + results) + (EmptyTree, results) + case (classDef: ClassDef) :: Nil if isTrait(classDef) => + println("INPUT CLASS ONLY :: " + classDef) + val results = processTrait(classDef) + println("RESULTS :: " + results) + (EmptyTree, results) + case _ => + c.abort( + c.enclosingPosition, + "Freezable can only be placed on traits!" + ) + } + + val outputs = expandees + val block = Block(outputs, Literal(Constant(()))) + + c.Expr[Any](block) + } +} diff --git a/scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala new file mode 100644 index 00000000..a1e54f74 --- /dev/null +++ b/scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala @@ -0,0 +1,226 @@ +package org.scaladebugger.macros.freeze + +import scala.annotation.tailrec +import scala.language.experimental.macros +import scala.reflect.macros.whitebox.Context + +object FreezableMacro { + def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { + import c.universe._ + + def findClassPackage(classDef: ClassDef): TermName = { + val dummyClassName = TypeName(s"Dummy${TypeName(c.freshName())}") + val dummyClass = c.typecheck(q"class $dummyClassName") + TermName(packageFromSymbol(dummyClass.symbol.owner)) + } + + def packageFromSymbol(symbol: Symbol): String = { + @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { + if (symbol == NoSymbol) tokens.mkString(".") + else buildPackage(symbol.owner, symbol.name.decodedName.toString +: tokens) + } + + buildPackage(symbol, Nil) + } + + def containsAnnotation(d: DefDef, aName: String): Boolean = + d.mods.annotations.exists(a => isAnnotation(a, aName)) + + def isAnnotation(t: Tree, aName: String): Boolean = t match { + case Apply(f, args) => f match { + case Select(qual, name) => qual match { + case New(tpt) => tpt match { + case Ident(iName) => iName.decodedName.toString == aName + case _ => false + } + case _ => false + } + } + case _ => false + } + + def isTrait(classDef: ClassDef): Boolean = { + try { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + true + } catch { + case _: Throwable => false + } + } + + def processTrait(classDef: ClassDef): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of companion object + val traitTypeName: TypeName = tpname + val oName = TermName(traitTypeName.toString) + + // Generate a new class containing the helper methods and + // object containing "Frozen" class representation + val moduleDef: ModuleDef = q"object $oName {}" + + processTraitAndObj(classDef, moduleDef) + } + + def processTraitAndObj( + classDef: ClassDef, + moduleDef: ModuleDef + ): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + + // Represents name of variable passed to freeze method + val freezeObjName = TermName("valueToFreeze") + + val (frozenClass, freezeMethod) = { + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body + val internals = bodyTrees.collect { + case d: DefDef if containsAnnotation(d, "CanFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + val paramTrees: List[List[ValDef]] = paramss + if (paramTrees.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) + + val name = TermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + case d: DefDef if containsAnnotation(d, "CannotFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods + val newMods = Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") + }) + ) + + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!") + """ + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" + class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => + ..$internals + } + """ + val method = q""" + def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) + """ + + (klass, method) + } + + val newModuleDef: ModuleDef = { + val q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = moduleDef + + val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") + val implicitFreezeMethod = q""" + implicit class $implicitMethodName(private val $freezeObjName: $tpname) { + def freeze(): Frozen = $tname.freeze($freezeObjName) + } + """ + + val oldBody: List[Tree] = body + val newBody = oldBody ++ List( + frozenClass, + freezeMethod, + q"object Implicits { $implicitFreezeMethod }" + ) + + q""" + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$newBody + } + """ + } + + List(classDef, newModuleDef) + } + + + val (annottee, expandees) = annottees.map(_.tree) match { + case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => + println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) + val results = processTraitAndObj(classDef, moduleDef) + println("RESULTS :: " + results) + (EmptyTree, results) + case (classDef: ClassDef) :: Nil if isTrait(classDef) => + println("INPUT CLASS ONLY :: " + classDef) + val results = processTrait(classDef) + println("RESULTS :: " + results) + (EmptyTree, results) + case _ => + c.abort( + c.enclosingPosition, + "Freezable can only be placed on traits!" + ) + } + + val outputs = expandees + val block = Block(outputs, Literal(Constant(()))) + + c.Expr[Any](block) + } +} + diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index 15c58323..7cefcafc 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -1,8 +1,7 @@ package org.scaladebugger.macros.freeze -import scala.reflect.macros.Context import scala.language.experimental.macros -import scala.annotation.{StaticAnnotation, tailrec} +import scala.annotation.StaticAnnotation import scala.reflect.internal.annotations.compileTimeOnly /** @@ -26,223 +25,3 @@ import scala.reflect.internal.annotations.compileTimeOnly class Freezable extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro FreezableMacro.impl } - -object FreezableMacro { - def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { - import c.universe._ - - def findClassPackage(classDef: ClassDef): TermName = { - val dummyClassName = newTypeName(s"Dummy${newTypeName(c.fresh())}") - val dummyClass = c.typeCheck(q"class $dummyClassName") - newTermName(packageFromSymbol(dummyClass.symbol.owner)) - } - - def packageFromSymbol(symbol: Symbol): String = { - @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { - if (symbol == NoSymbol) tokens.mkString(".") - else buildPackage(symbol.owner, symbol.name.decoded +: tokens) - } - - buildPackage(symbol, Nil) - } - - def containsAnnotation(d: DefDef, aName: String): Boolean = - d.mods.annotations.exists(a => isAnnotation(a, aName)) - - def isAnnotation(t: Tree, aName: String): Boolean = t match { - case Apply(f, args) => f match { - case Select(qual, name) => qual match { - case New(tpt) => tpt match { - case Ident(iName) => iName.decoded == aName - case _ => false - } - case _ => false - } - } - case _ => false - } - - def isTrait(classDef: ClassDef): Boolean = { - try { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - true - } catch { - case _: Throwable => false - } - } - - def processTrait(classDef: ClassDef): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - - // Represents name of companion object - val traitTypeName: TypeName = tpname - val oName = newTermName(traitTypeName.toString) - - // Generate a new class containing the helper methods and - // object containing "Frozen" class representation - val moduleDef: ModuleDef = q"object $oName {}" - - processTraitAndObj(classDef, moduleDef) - } - - def processTraitAndObj( - classDef: ClassDef, - moduleDef: ModuleDef - ): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - - // Represents name of variable passed to freeze method - val freezeObjName = newTermName("valueToFreeze") - - val (frozenClass, freezeMethod) = { - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body - val internals = bodyTrees.collect { - case d: DefDef if containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss - if (paramTrees.nonEmpty) c.abort( - c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" - ) - - val name = newTermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - """) - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - case d: DefDef if containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = - throw new IllegalStateException("Method not frozen!") - """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) - - val klass = q""" - class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => - ..$internals - } - """ - val method = q""" - def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) - """ - - (klass, method) - } - - val newModuleDef: ModuleDef = { - val q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = moduleDef - - val implicitMethodName = newTypeName(s"${tpname}FrozenWrapper") - val implicitFreezeMethod = q""" - implicit class $implicitMethodName(private val $freezeObjName: $tpname) { - def freeze(): Frozen = $tname.freeze($freezeObjName) - } - """ - - val oldBody: List[Tree] = body - val newBody = oldBody ++ List( - frozenClass, - freezeMethod, - q"object Implicits { $implicitFreezeMethod }" - ) - - q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$newBody - } - """ - } - - List(classDef, newModuleDef) - } - - - val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) - val results = processTraitAndObj(classDef, moduleDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case (classDef: ClassDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS ONLY :: " + classDef) - val results = processTrait(classDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case _ => - c.abort( - c.enclosingPosition, - "Freezable can only be placed on traits!" - ) - } - - val outputs = expandees - val block = Block(outputs, Literal(Constant(()))) - - c.Expr[Any](block) - } -} From 880a2fc877b4e129b8cf1fdb14fec93b2292e878 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 21:58:06 -0700 Subject: [PATCH 13/36] Switched to using macro-compat to get compiling under all three Scala versions --- project/Macros.scala | 6 +- .../macros/freeze/FreezableMacro.scala | 225 ----------------- .../FreezableMacro.scala | 226 ------------------ .../macros/freeze}/FreezableMacro.scala | 12 +- 4 files changed, 11 insertions(+), 458 deletions(-) delete mode 100644 scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala delete mode 100644 scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala rename scala-debugger-macros/src/main/{scala-2.11/org.scaladebugger.macros.freeze => scala/org/scaladebugger/macros/freeze}/FreezableMacro.scala (96%) diff --git a/project/Macros.scala b/project/Macros.scala index d04994a1..90587630 100644 --- a/project/Macros.scala +++ b/project/Macros.scala @@ -14,9 +14,11 @@ object Macros { /** Macro-specific project settings. */ val settings = pluginSettings ++ Seq( - libraryDependencies += { + libraryDependencies ++= Seq( + "org.typelevel" %% "macro-compat" % "1.1.1", + "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", scalaVersion("org.scala-lang" % "scala-reflect" % _).value - }, + ), libraryDependencies ++= ( if (scalaVersion.value.startsWith("2.10")) Seq( diff --git a/scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala deleted file mode 100644 index fca2d086..00000000 --- a/scala-debugger-macros/src/main/scala-2.10/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ /dev/null @@ -1,225 +0,0 @@ -package org.scaladebugger.macros.freeze - -import scala.annotation.tailrec -import scala.language.experimental.macros -import scala.reflect.macros.Context - -object FreezableMacro { - def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { - import c.universe._ - - def findClassPackage(classDef: ClassDef): TermName = { - val dummyClassName = newTypeName(s"Dummy${newTypeName(c.fresh())}") - val dummyClass = c.typeCheck(q"class $dummyClassName") - newTermName(packageFromSymbol(dummyClass.symbol.owner)) - } - - def packageFromSymbol(symbol: Symbol): String = { - @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { - if (symbol == NoSymbol) tokens.mkString(".") - else buildPackage(symbol.owner, symbol.name.decoded +: tokens) - } - - buildPackage(symbol, Nil) - } - - def containsAnnotation(d: DefDef, aName: String): Boolean = - d.mods.annotations.exists(a => isAnnotation(a, aName)) - - def isAnnotation(t: Tree, aName: String): Boolean = t match { - case Apply(f, args) => f match { - case Select(qual, name) => qual match { - case New(tpt) => tpt match { - case Ident(iName) => iName.decoded == aName - case _ => false - } - case _ => false - } - } - case _ => false - } - - def isTrait(classDef: ClassDef): Boolean = { - try { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - true - } catch { - case _: Throwable => false - } - } - - def processTrait(classDef: ClassDef): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - - // Represents name of companion object - val traitTypeName: TypeName = tpname - val oName = newTermName(traitTypeName.toString) - - // Generate a new class containing the helper methods and - // object containing "Frozen" class representation - val moduleDef: ModuleDef = q"object $oName {}" - - processTraitAndObj(classDef, moduleDef) - } - - def processTraitAndObj( - classDef: ClassDef, - moduleDef: ModuleDef - ): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - - // Represents name of variable passed to freeze method - val freezeObjName = newTermName("valueToFreeze") - - val (frozenClass, freezeMethod) = { - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body - val internals = bodyTrees.collect { - case d: DefDef if containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss - if (paramTrees.nonEmpty) c.abort( - c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" - ) - - val name = newTermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - """) - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - case d: DefDef if containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = - throw new IllegalStateException("Method not frozen!") - """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) - - val klass = q""" - class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => - ..$internals - } - """ - val method = q""" - def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) - """ - - (klass, method) - } - - val newModuleDef: ModuleDef = { - val q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = moduleDef - - val implicitMethodName = newTypeName(s"${tpname}FrozenWrapper") - val implicitFreezeMethod = q""" - implicit class $implicitMethodName(private val $freezeObjName: $tpname) { - def freeze(): Frozen = $tname.freeze($freezeObjName) - } - """ - - val oldBody: List[Tree] = body - val newBody = oldBody ++ List( - frozenClass, - freezeMethod, - q"object Implicits { $implicitFreezeMethod }" - ) - - q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$newBody - } - """ - } - - List(classDef, newModuleDef) - } - - - val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) - val results = processTraitAndObj(classDef, moduleDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case (classDef: ClassDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS ONLY :: " + classDef) - val results = processTrait(classDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case _ => - c.abort( - c.enclosingPosition, - "Freezable can only be placed on traits!" - ) - } - - val outputs = expandees - val block = Block(outputs, Literal(Constant(()))) - - c.Expr[Any](block) - } -} diff --git a/scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala deleted file mode 100644 index a1e54f74..00000000 --- a/scala-debugger-macros/src/main/scala-2.12/org.scaladebugger.macros.freeze/FreezableMacro.scala +++ /dev/null @@ -1,226 +0,0 @@ -package org.scaladebugger.macros.freeze - -import scala.annotation.tailrec -import scala.language.experimental.macros -import scala.reflect.macros.whitebox.Context - -object FreezableMacro { - def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { - import c.universe._ - - def findClassPackage(classDef: ClassDef): TermName = { - val dummyClassName = TypeName(s"Dummy${TypeName(c.freshName())}") - val dummyClass = c.typecheck(q"class $dummyClassName") - TermName(packageFromSymbol(dummyClass.symbol.owner)) - } - - def packageFromSymbol(symbol: Symbol): String = { - @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { - if (symbol == NoSymbol) tokens.mkString(".") - else buildPackage(symbol.owner, symbol.name.decodedName.toString +: tokens) - } - - buildPackage(symbol, Nil) - } - - def containsAnnotation(d: DefDef, aName: String): Boolean = - d.mods.annotations.exists(a => isAnnotation(a, aName)) - - def isAnnotation(t: Tree, aName: String): Boolean = t match { - case Apply(f, args) => f match { - case Select(qual, name) => qual match { - case New(tpt) => tpt match { - case Ident(iName) => iName.decodedName.toString == aName - case _ => false - } - case _ => false - } - } - case _ => false - } - - def isTrait(classDef: ClassDef): Boolean = { - try { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - true - } catch { - case _: Throwable => false - } - } - - def processTrait(classDef: ClassDef): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - - // Represents name of companion object - val traitTypeName: TypeName = tpname - val oName = TermName(traitTypeName.toString) - - // Generate a new class containing the helper methods and - // object containing "Frozen" class representation - val moduleDef: ModuleDef = q"object $oName {}" - - processTraitAndObj(classDef, moduleDef) - } - - def processTraitAndObj( - classDef: ClassDef, - moduleDef: ModuleDef - ): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - - // Represents name of variable passed to freeze method - val freezeObjName = TermName("valueToFreeze") - - val (frozenClass, freezeMethod) = { - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body - val internals = bodyTrees.collect { - case d: DefDef if containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss - if (paramTrees.nonEmpty) c.abort( - c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" - ) - - val name = TermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - """) - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - case d: DefDef if containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods - val newMods = Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = - throw new IllegalStateException("Method not frozen!") - """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) - - val klass = q""" - class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => - ..$internals - } - """ - val method = q""" - def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) - """ - - (klass, method) - } - - val newModuleDef: ModuleDef = { - val q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = moduleDef - - val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") - val implicitFreezeMethod = q""" - implicit class $implicitMethodName(private val $freezeObjName: $tpname) { - def freeze(): Frozen = $tname.freeze($freezeObjName) - } - """ - - val oldBody: List[Tree] = body - val newBody = oldBody ++ List( - frozenClass, - freezeMethod, - q"object Implicits { $implicitFreezeMethod }" - ) - - q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$newBody - } - """ - } - - List(classDef, newModuleDef) - } - - - val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) - val results = processTraitAndObj(classDef, moduleDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case (classDef: ClassDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS ONLY :: " + classDef) - val results = processTrait(classDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case _ => - c.abort( - c.enclosingPosition, - "Freezable can only be placed on traits!" - ) - } - - val outputs = expandees - val block = Block(outputs, Literal(Constant(()))) - - c.Expr[Any](block) - } -} - diff --git a/scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala similarity index 96% rename from scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala rename to scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 8caf7e94..f81e46a9 100644 --- a/scala-debugger-macros/src/main/scala-2.11/org.scaladebugger.macros.freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -2,10 +2,12 @@ package org.scaladebugger.macros.freeze import scala.annotation.tailrec import scala.language.experimental.macros -import scala.reflect.macros.whitebox.Context +import macrocompat.bundle +import scala.reflect.macros.whitebox -object FreezableMacro { - def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { +@bundle +class FreezableMacro(val c: whitebox.Context) { + def impl(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ def findClassPackage(classDef: ClassDef): TermName = { @@ -113,7 +115,7 @@ object FreezableMacro { // Add override if not already there val oldMods: Modifiers = mods - val newMods = Modifiers( + val newMods = c.universe.Modifiers( flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { @@ -128,7 +130,7 @@ object FreezableMacro { // Add override if not already there val oldMods: Modifiers = mods - val newMods = Modifiers( + val newMods = c.universe.Modifiers( flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { From 894bef5fd26182b65c036db1c46e2bcbebe868e0 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 22:06:06 -0700 Subject: [PATCH 14/36] Switched default Scala version to 2.11 --- project/Common.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Common.scala b/project/Common.scala index 9a7db24a..1afbd9c3 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -21,7 +21,7 @@ object Common { homepage := Some(url("https://scala-debugger.org")), // Default version when not cross-compiling - scalaVersion := "2.10.6", + scalaVersion := "2.11.8", crossScalaVersions := Seq("2.10.6", "2.11.8", "2.12.1"), From 58daedb1f83eede4c012a10898186d7ec3bf99c6 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 22:21:48 -0700 Subject: [PATCH 15/36] Fixed to compile against all three Scala versions (again) --- .../macros/freeze/Freezable.scala | 3 +-- .../macros/freeze/FreezableMacro.scala | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala index 7cefcafc..cc958667 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala @@ -1,8 +1,7 @@ package org.scaladebugger.macros.freeze import scala.language.experimental.macros -import scala.annotation.StaticAnnotation -import scala.reflect.internal.annotations.compileTimeOnly +import scala.annotation.{StaticAnnotation, compileTimeOnly} /** *

Represents a freezable bit of information. diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index f81e46a9..5295c4f8 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -1,12 +1,13 @@ package org.scaladebugger.macros.freeze -import scala.annotation.tailrec import scala.language.experimental.macros -import macrocompat.bundle +import scala.annotation.tailrec import scala.reflect.macros.whitebox +import macrocompat.bundle -@bundle -class FreezableMacro(val c: whitebox.Context) { +@bundle class FreezableMacro(val c: whitebox.Context) { + // NOTE: Stuck with c.Expr[Any] instead of c.Tree for now; + // blows up in Scala 2.10 even with @bundle otherwise def impl(annottees: c.Expr[Any]*): c.Expr[Any] = { import c.universe._ @@ -120,7 +121,7 @@ class FreezableMacro(val c: whitebox.Context) { privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") + isAnnotation(a, "CannotFreeze") }) ) @@ -135,7 +136,7 @@ class FreezableMacro(val c: whitebox.Context) { privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") + isAnnotation(a, "CannotFreeze") }) ) @@ -200,7 +201,6 @@ class FreezableMacro(val c: whitebox.Context) { List(classDef, newModuleDef) } - val (annottee, expandees) = annottees.map(_.tree) match { case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) @@ -220,8 +220,9 @@ class FreezableMacro(val c: whitebox.Context) { } val outputs = expandees - val block = Block(outputs, Literal(Constant(()))) - - c.Expr[Any](block) + c.Expr[Any]( + Block(outputs, Literal(Constant(()))) + ) } } + From 4cd0bf0e64ca44a6193bd153c7d1881a819f91e9 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 22:29:11 -0700 Subject: [PATCH 16/36] Got rid of some more red in IntelliJ --- .../macros/freeze/FreezableMacro.scala | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 5295c4f8..0ca6a3f5 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -67,12 +67,16 @@ import macrocompat.bundle """ = classDef // Represents name of companion object - val traitTypeName: TypeName = tpname + val traitTypeName: TypeName = tpname match { + case t: TypeName => t + } val oName = TermName(traitTypeName.toString) // Generate a new class containing the helper methods and // object containing "Frozen" class representation - val moduleDef: ModuleDef = q"object $oName {}" + val moduleDef: ModuleDef = q"object $oName {}" match { + case m: ModuleDef => m + } processTraitAndObj(classDef, moduleDef) } @@ -95,12 +99,16 @@ import macrocompat.bundle val (frozenClass, freezeMethod) = { val cParams = collection.mutable.ArrayBuffer[Tree]() val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body + val bodyTrees: List[Tree] = body match { + case l: List[Tree] => l + } val internals = bodyTrees.collect { case d: DefDef if containsAnnotation(d, "CanFreeze") => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val paramTrees: List[List[ValDef]] = paramss + val paramTrees: List[List[ValDef]] = paramss match { + case l: List[List[ValDef]] => l + } if (paramTrees.nonEmpty) c.abort( c.enclosingPosition, s"Unable to freeze $tname! Must have zero arguments!" @@ -115,7 +123,9 @@ import macrocompat.bundle """) // Add override if not already there - val oldMods: Modifiers = mods + val oldMods: Modifiers = mods match { + case m: Modifiers => m + } val newMods = c.universe.Modifiers( flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, @@ -130,7 +140,9 @@ import macrocompat.bundle val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d // Add override if not already there - val oldMods: Modifiers = mods + val oldMods: Modifiers = mods match { + case m: Modifiers => m + } val newMods = c.universe.Modifiers( flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, @@ -146,7 +158,9 @@ import macrocompat.bundle """ case d: DefDef => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr + val exprTree: Tree = expr match { + case t: Tree => t + } if (exprTree.isEmpty) c.abort( c.enclosingPosition, s"$tname has no implementation and is not marked as freezable or unfreezable!" @@ -182,7 +196,9 @@ import macrocompat.bundle } """ - val oldBody: List[Tree] = body + val oldBody: List[Tree] = body match { + case l: List[Tree] => l + } val newBody = oldBody ++ List( frozenClass, freezeMethod, From c245198537e98f7336b34a75edf50cba5e1aa2a7 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 22:36:32 -0700 Subject: [PATCH 17/36] Got rid of last red in macro file --- .../org/scaladebugger/macros/freeze/FreezableMacro.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 0ca6a3f5..03a4e152 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -205,13 +205,15 @@ import macrocompat.bundle q"object Implicits { $implicitFreezeMethod }" ) - q""" + val newObjDef = q""" $mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$newBody } """ + + newObjDef match { case m: ModuleDef => m } } List(classDef, newModuleDef) From 03ac81001ede8439606f1dc9ea019d914a17f894 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 13 Aug 2017 22:54:49 -0700 Subject: [PATCH 18/36] Added commented-out attempt at filling in abstract methods --- .../macros/freeze/FreezableMacro.scala | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 03a4e152..ed9d263e 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -180,6 +180,41 @@ import macrocompat.bundle (klass, method) } + // TODO: Remove this hack that is injecting ??? into all + // non-implemented methods + val newClassDef: ClassDef = { + val bodyTrees: List[Tree] = body match { + case l: List[Tree] => l + } + val newBody = bodyTrees.map { + /*case vDef: ValDef if vDef.rhs.isEmpty => ValDef( + mods = vDef.mods, + name = vDef.name, + tpt = vDef.tpt, + rhs = q"throw new NotImplementedError" + ) + case dDef: DefDef if dDef.rhs.isEmpty => DefDef( + mods = dDef.mods, + name = dDef.name, + tparams = dDef.tparams, + vparamss = dDef.vparamss, + tpt = dDef.tpt, + rhs = q"throw new NotImplementedError" + )*/ + case t => t + } + + val tree = q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$newBody + } + """ + + tree match { case c: ClassDef => c } + } + val newModuleDef: ModuleDef = { val q""" $mods object $tname extends { @@ -216,7 +251,7 @@ import macrocompat.bundle newObjDef match { case m: ModuleDef => m } } - List(classDef, newModuleDef) + List(newClassDef, newModuleDef) } val (annottee, expandees) = annottees.map(_.tree) match { From d6c27d9f5e6576e56fd73210bf76833806f02f0a Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Mon, 14 Aug 2017 22:05:48 -0700 Subject: [PATCH 19/36] Added ability to look up inherited methods -- need to use it to add more methods to fill in with generation --- .../api/profiles/traits/info/CommonInfo.scala | 11 +- .../api/profiles/traits/info/ValueInfo.scala | 47 +- .../macros/freeze/FreezableMacro.scala | 495 +++++++++++------- .../macros/freeze/FreezeMetadata.scala | 23 + 4 files changed, 357 insertions(+), 219 deletions(-) create mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 0c762109..969a22c3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -2,24 +2,25 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Mirror import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -trait CommonInfo extends JavaInfo { +@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. * * @return The Scala virtual machine instance */ - def scalaVirtualMachine: ScalaVirtualMachine + @CannotFreeze def scalaVirtualMachine: ScalaVirtualMachine /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - def toJdiInstance: Mirror + @CannotFreeze def toJdiInstance: Mirror /** * Returns a string presenting a better human-readable description of @@ -27,7 +28,7 @@ trait CommonInfo extends JavaInfo { * * @return The human-readable description */ - def toPrettyString: String + @CanFreeze def toPrettyString: String /** * Converts the current profile instance to a representation of @@ -36,5 +37,5 @@ trait CommonInfo extends JavaInfo { * @return The profile instance providing an implementation corresponding * to Java */ - override def toJavaInfo: CommonInfo + @CannotFreeze override def toJavaInfo: CommonInfo } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 421f1267..786e3640 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,13 +1,14 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try /** * Represents information about a value. */ -trait ValueInfo extends CommonInfo { +@Freezable trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of * low-level Java instead of a higher-level abstraction. @@ -15,21 +16,21 @@ trait ValueInfo extends CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ - override def toJavaInfo: ValueInfo + @CannotFreeze override def toJavaInfo: ValueInfo /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - override def toJdiInstance: Value + @CannotFreeze override def toJdiInstance: Value /** * Returns the type information for the value. * * @return The profile containing type information */ - def `type`: TypeInfo + @CanFreeze def `type`: TypeInfo /** * Returns the type information for the value. @@ -52,77 +53,77 @@ trait ValueInfo extends CommonInfo { * * @return The value as a local instance */ - def toLocalValue: Any + @CannotFreeze def toLocalValue: Any /** * Returns whether or not this value represents a primitive. * * @return True if a primitive, otherwise false */ - def isPrimitive: Boolean + @CanFreeze def isPrimitive: Boolean /** * Returns whether or not this value represents an array. * * @return True if an array, otherwise false */ - def isArray: Boolean + @CanFreeze def isArray: Boolean /** * Returns whether or not this value represents a class loader. * * @return True if a class loader, otherwise false */ - def isClassLoader: Boolean + @CanFreeze def isClassLoader: Boolean /** * Returns whether or not this value represents a class object. * * @return True if a class object, otherwise false */ - def isClassObject: Boolean + @CanFreeze def isClassObject: Boolean /** * Returns whether or not this value represents a thread group. * * @return True if a thread group, otherwise false */ - def isThreadGroup: Boolean + @CanFreeze def isThreadGroup: Boolean /** * Returns whether or not this value represents a thread. * * @return True if a thread, otherwise false */ - def isThread: Boolean + @CanFreeze def isThread: Boolean /** * Returns whether or not this value represents an object. * * @return True if an object, otherwise false */ - def isObject: Boolean + @CanFreeze def isObject: Boolean /** * Returns whether or not this value represents a string. * * @return True if a string, otherwise false */ - def isString: Boolean + @CanFreeze def isString: Boolean /** * Returns whether or not this value is null. * * @return True if null, otherwise false */ - def isNull: Boolean + @CanFreeze def isNull: Boolean /** * Returns whether or not this value is void. * * @return True if void, otherwise false */ - def isVoid: Boolean + @CanFreeze def isVoid: Boolean /** * Returns the value as a primitive (profile). @@ -138,7 +139,7 @@ trait ValueInfo extends CommonInfo { * @return The primitive profile wrapping this value */ @throws[AssertionError] - def toPrimitiveInfo: PrimitiveInfo + @CanFreeze def toPrimitiveInfo: PrimitiveInfo /** * Returns the value as a class loader (profile). @@ -154,7 +155,7 @@ trait ValueInfo extends CommonInfo { * @return The class loader profile wrapping this value */ @throws[AssertionError] - def toClassLoaderInfo: ClassLoaderInfo + @CanFreeze def toClassLoaderInfo: ClassLoaderInfo /** * Returns the value as a class object (profile). @@ -170,7 +171,7 @@ trait ValueInfo extends CommonInfo { * @return The class object profile wrapping this value */ @throws[AssertionError] - def toClassObjectInfo: ClassObjectInfo + @CanFreeze def toClassObjectInfo: ClassObjectInfo /** * Returns the value as a thread group (profile). @@ -186,7 +187,7 @@ trait ValueInfo extends CommonInfo { * @return The thread group profile wrapping this value */ @throws[AssertionError] - def toThreadGroupInfo: ThreadGroupInfo + @CanFreeze def toThreadGroupInfo: ThreadGroupInfo /** * Returns the value as a thread (profile). @@ -202,7 +203,7 @@ trait ValueInfo extends CommonInfo { * @return The thread profile wrapping this value */ @throws[AssertionError] - def toThreadInfo: ThreadInfo + @CanFreeze def toThreadInfo: ThreadInfo /** * Returns the value as an object (profile). @@ -218,7 +219,7 @@ trait ValueInfo extends CommonInfo { * @return The object profile wrapping this value */ @throws[AssertionError] - def toObjectInfo: ObjectInfo + @CanFreeze def toObjectInfo: ObjectInfo /** * Returns the value as a string (profile). @@ -234,7 +235,7 @@ trait ValueInfo extends CommonInfo { * @return The string profile wrapping this value */ @throws[AssertionError] - def toStringInfo: StringInfo + @CanFreeze def toStringInfo: StringInfo /** * Returns the value as an array (profile). @@ -250,7 +251,7 @@ trait ValueInfo extends CommonInfo { * @return The array profile wrapping this value */ @throws[AssertionError] - def toArrayInfo: ArrayInfo + @CanFreeze def toArrayInfo: ArrayInfo /** * Returns a string presenting a better human-readable description of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index ed9d263e..5ab3b906 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -6,59 +6,158 @@ import scala.reflect.macros.whitebox import macrocompat.bundle @bundle class FreezableMacro(val c: whitebox.Context) { + import c.universe._ + // NOTE: Stuck with c.Expr[Any] instead of c.Tree for now; // blows up in Scala 2.10 even with @bundle otherwise def impl(annottees: c.Expr[Any]*): c.Expr[Any] = { - import c.universe._ - - def findClassPackage(classDef: ClassDef): TermName = { - val dummyClassName = TypeName(s"Dummy${TypeName(c.freshName())}") - val dummyClass = c.typecheck(q"class $dummyClassName") - TermName(packageFromSymbol(dummyClass.symbol.owner)) + val (annottee, expandees) = annottees.map(_.tree) match { + case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => + //println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) + val results = processTraitAndObj(classDef, moduleDef) + //println("RESULTS :: " + results) + (EmptyTree, results) + case (classDef: ClassDef) :: Nil if isTrait(classDef) => + //println("INPUT CLASS ONLY :: " + classDef) + val results = processTrait(classDef) + //println("RESULTS :: " + results) + (EmptyTree, results) + case _ => + c.abort( + c.enclosingPosition, + "Freezable can only be placed on traits!" + ) } - def packageFromSymbol(symbol: Symbol): String = { - @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { - if (symbol == NoSymbol) tokens.mkString(".") - else buildPackage(symbol.owner, symbol.name.decodedName.toString +: tokens) - } + val outputs = expandees + c.Expr[Any]( + Block(outputs, Literal(Constant(()))) + ) + } + + private def findClassPackage(classDef: ClassDef): TermName = { + val dummyClass = c.typecheck(classDef.duplicate) + TermName(packageFromSymbol(dummyClass.symbol.owner)) + } - buildPackage(symbol, Nil) + private def packageFromSymbol(symbol: Symbol): String = { + @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { + if (symbol == NoSymbol) tokens.mkString(".") + else buildPackage(symbol.owner, symbol.name.decodedName.toString +: tokens) } - def containsAnnotation(d: DefDef, aName: String): Boolean = - d.mods.annotations.exists(a => isAnnotation(a, aName)) + buildPackage(symbol, Nil) + } - def isAnnotation(t: Tree, aName: String): Boolean = t match { - case Apply(f, args) => f match { - case Select(qual, name) => qual match { - case New(tpt) => tpt match { - case Ident(iName) => iName.decodedName.toString == aName - case _ => false - } + private def containsAnnotation(d: DefDef, aName: String): Boolean = + findAnnotation(d, aName).nonEmpty + + private def findAnnotation(d: DefDef, aName: String): Option[Tree] = + d.mods.annotations.find(a => isAnnotation(a, aName)) + + private def isAnnotation(t: Tree, aName: String): Boolean = t match { + case Apply(f, args) => f match { + case Select(qual, name) => qual match { + case New(tpt) => tpt match { + case Ident(iName) => iName.decodedName.toString == aName case _ => false } + case _ => false } - case _ => false } + case _ => false + } - def isTrait(classDef: ClassDef): Boolean = { - try { - val q""" + private def isTrait(classDef: ClassDef): Boolean = { + try { + val q""" $mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$body } """ = classDef - true - } catch { - case _: Throwable => false + true + } catch { + case _: Throwable => false + } + } + + private def extractInheritedMethods(parents: List[Type]): List[MethodSymbol] = { + val anyTypeSymbol = typeOf[Any].typeSymbol + val objectTypeSymbol = typeOf[Object].typeSymbol + + def stripDuplicateMethods(methods: List[MethodSymbol]): List[MethodSymbol] = { + val overrides = methods.flatMap(_.overrides) + methods.filterNot(overrides.contains) + } + + @tailrec def extract(types: List[Type], methods: List[MethodSymbol]): List[MethodSymbol] = { + val parentMethods = types.flatMap(pt => { + pt.members + .filter(_.isMethod) + .filter(_.owner == pt.typeSymbol) + .map(_.asMethod) + }) + val parentTypes = types + .flatMap(t => { + t.baseClasses.filterNot(c => + c == t.typeSymbol || + c == anyTypeSymbol || + c == objectTypeSymbol + ) + }) + .filter(_.isClass) + .map(_.asClass.toType) + + val allMethods = stripDuplicateMethods(methods ++ parentMethods) + + if (parentTypes.nonEmpty) extract(parentTypes, allMethods) + else allMethods + } + + extract(parents, Nil) + } + + private def extractParentTypes(parents: List[Tree]): List[Option[Type]] = { + parents match { + case p: List[Tree] => p.map(extractParentType) + } + } + + private def extractParentType(parent: Tree): Option[Type] = { + def isBaseType(n1: Name, n2: Name = null): Boolean = { + val name = if (n2 != null) { + n1.toString + "." + n2.toString + } else { + n1.toString } + + val baseTypeNames = Seq( + "Any", "scala.Any", "AnyRef", "scala.AnyRef", + "AnyVal", "scala.AnyVal", "java.lang.Object" + ) + + baseTypeNames.contains(name) } - def processTrait(classDef: ClassDef): List[Tree] = { - val q""" + parent match { + case Ident(name) if !isBaseType(name) => + val typeName = name.toTypeName + val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$typeName]")) + typedTree.toOption.flatMap(tt => Option(tt.tpe)) + case Select(Ident(name), typeName) if !isBaseType(name, typeName) => + val t1 = name.toTermName + val t2 = typeName.toTypeName + val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$t1.$t2]")) + typedTree.toOption.flatMap(tt => Option(tt.tpe)) + case a => + None + } + } + + private def processTrait(classDef: ClassDef): List[Tree] = { + val q""" $mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => @@ -66,145 +165,183 @@ import macrocompat.bundle } """ = classDef - // Represents name of companion object - val traitTypeName: TypeName = tpname match { - case t: TypeName => t + // Represents name of companion object + val traitTypeName: TypeName = tpname match { + case t: TypeName => t + } + val oName = TermName(traitTypeName.toString) + + // Generate a new class containing the helper methods and + // object containing "Frozen" class representation + val moduleDef: ModuleDef = q"object $oName {}" match { + case m: ModuleDef => m + } + + processTraitAndObj(classDef, moduleDef) + } + + private def processTraitAndObj( + classDef: ClassDef, + moduleDef: ModuleDef + ): List[Tree] = { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body } - val oName = TermName(traitTypeName.toString) + """ = classDef - // Generate a new class containing the helper methods and - // object containing "Frozen" class representation - val moduleDef: ModuleDef = q"object $oName {}" match { - case m: ModuleDef => m + val inheritedMethods = extractInheritedMethods( + extractParentTypes(parents.asInstanceOf[List[Tree]]).flatten + ) + println("INHERTED METHODS FOR " + tpname.toString() + " :: " + inheritedMethods.map(m => + m.name.toString + " from " + m.owner.name.toString + ).mkString(" | ")) + + // Represents name of variable passed to freeze method + val freezeObjName = TermName("valueToFreeze") + + val (frozenClass, freezeMethod) = { + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body match { + case l: List[Tree] => l + } + val internalMethods = bodyTrees.collect { + case d: DefDef => d } - processTraitAndObj(classDef, moduleDef) - } + // TODO: Also process inherited methods that are not covered + // by the tree methods + val internals = internalMethods.map { + case d: DefDef if containsAnnotation(d, "CanFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - def processTraitAndObj( - classDef: ClassDef, - moduleDef: ModuleDef - ): List[Tree] = { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef + val paramTrees: List[List[ValDef]] = paramss match { + case l: List[List[ValDef]] => l + } + if (paramTrees.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) - // Represents name of variable passed to freeze method - val freezeObjName = TermName("valueToFreeze") + val name = TermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + + // TODO: Remove runtime checks by getting better understanding of + // return type, if it contains a freeze method, etc. + findAnnotation(d, "FreezeMetadata") match { + case Some(a) => + import FreezeMetadata.{ReturnType => RT} + type RT = FreezeMetadata.ReturnType.ReturnType + a match { + case Literal(Constant(rt: RT)) if rt == RT.Normal => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + case Literal(Constant(rt: RT)) if rt == RT.FreezeObject => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) + """) + case Literal(Constant(rt: RT)) if rt == RT.FreezeCollection => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(_map(_.freeze())) + """) + } + case None => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + """) + } - val (frozenClass, freezeMethod) = { - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body match { - case l: List[Tree] => l - } - val internals = bodyTrees.collect { - case d: DefDef if containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss match { - case l: List[List[ValDef]] => l - } - if (paramTrees.nonEmpty) c.abort( - c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" - ) - - val name = TermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - """) - - // Add override if not already there - val oldMods: Modifiers = mods match { - case m: Modifiers => m - } - val newMods = c.universe.Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - case d: DefDef if containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods match { - case m: Modifiers => m - } - val newMods = c.universe.Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") - }) - ) - - q""" + // Add override if not already there + val oldMods: Modifiers = mods match { + case m: Modifiers => m + } + val newMods = c.universe.Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") || + isAnnotation(a, "FreezeMetadata") + }) + ) + + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + case d: DefDef if containsAnnotation(d, "CannotFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods match { + case m: Modifiers => m + } + val newMods = c.universe.Modifiers( + flags = Flag.OVERRIDE | oldMods.flags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + isAnnotation(a, "CanFreeze") || + isAnnotation(a, "CannotFreeze") || + isAnnotation(a, "FreezeMetadata") + }) + ) + + q""" $newMods def $tname[..$tparams](...$paramss): $tpt = throw new IllegalStateException("Method not frozen!") """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr match { - case t: Tree => t - } - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) - - val klass = q""" + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr match { + case t: Tree => t + } + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => ..$internals } """ - val method = q""" + val method = q""" def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) """ - (klass, method) - } + (klass, method) + } - // TODO: Remove this hack that is injecting ??? into all - // non-implemented methods - val newClassDef: ClassDef = { - val bodyTrees: List[Tree] = body match { - case l: List[Tree] => l - } - val newBody = bodyTrees.map { - /*case vDef: ValDef if vDef.rhs.isEmpty => ValDef( - mods = vDef.mods, - name = vDef.name, - tpt = vDef.tpt, - rhs = q"throw new NotImplementedError" - ) - case dDef: DefDef if dDef.rhs.isEmpty => DefDef( - mods = dDef.mods, - name = dDef.name, - tparams = dDef.tparams, - vparamss = dDef.vparamss, - tpt = dDef.tpt, - rhs = q"throw new NotImplementedError" - )*/ - case t => t - } + // TODO: Remove this hack that is injecting ??? into all + // non-implemented methods + val newClassDef: ClassDef = { + val bodyTrees: List[Tree] = body match { + case l: List[Tree] => l + } + val newBody = bodyTrees.map { + /*case vDef: ValDef if vDef.rhs.isEmpty => ValDef( + mods = vDef.mods, + name = vDef.name, + tpt = vDef.tpt, + rhs = q"throw new NotImplementedError" + ) + case dDef: DefDef if dDef.rhs.isEmpty => DefDef( + mods = dDef.mods, + name = dDef.name, + tparams = dDef.tparams, + vparamss = dDef.vparamss, + tpt = dDef.tpt, + rhs = q"throw new NotImplementedError" + )*/ + case t => t + } - val tree = q""" + val tree = q""" $mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => @@ -212,11 +349,11 @@ import macrocompat.bundle } """ - tree match { case c: ClassDef => c } - } + tree match { case c: ClassDef => c } + } - val newModuleDef: ModuleDef = { - val q""" + val newModuleDef: ModuleDef = { + val q""" $mods object $tname extends { ..$earlydefns } with ..$parents { $self => @@ -224,23 +361,23 @@ import macrocompat.bundle } """ = moduleDef - val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") - val implicitFreezeMethod = q""" + val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") + val implicitFreezeMethod = q""" implicit class $implicitMethodName(private val $freezeObjName: $tpname) { def freeze(): Frozen = $tname.freeze($freezeObjName) } """ - val oldBody: List[Tree] = body match { - case l: List[Tree] => l - } - val newBody = oldBody ++ List( - frozenClass, - freezeMethod, - q"object Implicits { $implicitFreezeMethod }" - ) + val oldBody: List[Tree] = body match { + case l: List[Tree] => l + } + val newBody = oldBody ++ List( + frozenClass, + freezeMethod, + q"object Implicits { $implicitFreezeMethod }" + ) - val newObjDef = q""" + val newObjDef = q""" $mods object $tname extends { ..$earlydefns } with ..$parents { $self => @@ -248,34 +385,10 @@ import macrocompat.bundle } """ - newObjDef match { case m: ModuleDef => m } - } - - List(newClassDef, newModuleDef) - } - - val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) - val results = processTraitAndObj(classDef, moduleDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case (classDef: ClassDef) :: Nil if isTrait(classDef) => - println("INPUT CLASS ONLY :: " + classDef) - val results = processTrait(classDef) - println("RESULTS :: " + results) - (EmptyTree, results) - case _ => - c.abort( - c.enclosingPosition, - "Freezable can only be placed on traits!" - ) + newObjDef match { case m: ModuleDef => m } } - val outputs = expandees - c.Expr[Any]( - Block(outputs, Literal(Constant(()))) - ) + List(newClassDef, newModuleDef) } } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala new file mode 100644 index 00000000..fd0f8625 --- /dev/null +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala @@ -0,0 +1,23 @@ +package org.scaladebugger.macros.freeze + +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType.ReturnType + +import scala.annotation.StaticAnnotation +import scala.language.experimental.macros + +/** + * Internal metadata assigned to methods upon inspection. + * + * @param returnType Freeze-related information about the method's return type + */ +case class FreezeMetadata private[freeze]( + returnType: ReturnType +) extends StaticAnnotation + +object FreezeMetadata { + /** Return type of method being frozen. */ + object ReturnType extends Enumeration { + type ReturnType = Value + val Normal, FreezeObject, FreezeCollection = Value + } +} From e72a46e740903a5e4f93d60c271263124a3a4970 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Mon, 14 Aug 2017 23:40:00 -0700 Subject: [PATCH 20/36] Added freezable to all info classes (code generation still not working) --- .../api/profiles/traits/info/ArrayInfo.scala | 15 ++++ .../profiles/traits/info/ArrayTypeInfo.scala | 10 +++ .../traits/info/ClassLoaderInfo.scala | 9 +++ .../traits/info/ClassObjectInfo.scala | 7 ++ .../profiles/traits/info/ClassTypeInfo.scala | 19 +++++ .../api/profiles/traits/info/CreateInfo.scala | 5 ++ .../traits/info/FieldVariableInfo.scala | 9 +++ .../api/profiles/traits/info/FrameInfo.scala | 36 +++++++++ .../traits/info/IndexedVariableInfo.scala | 8 ++ .../traits/info/InterfaceTypeInfo.scala | 11 +++ .../profiles/traits/info/LocationInfo.scala | 13 +++ .../api/profiles/traits/info/MethodInfo.scala | 14 ++++ .../api/profiles/traits/info/ObjectInfo.scala | 20 +++++ .../profiles/traits/info/PrimitiveInfo.scala | 16 ++++ .../traits/info/PrimitiveTypeInfo.scala | 4 + .../traits/info/ReferenceTypeInfo.scala | 41 ++++++++++ .../api/profiles/traits/info/StringInfo.scala | 11 ++- .../traits/info/ThreadGroupInfo.scala | 16 +++- .../api/profiles/traits/info/ThreadInfo.scala | 18 +++++ .../traits/info/ThreadStatusInfo.scala | 14 ++++ .../api/profiles/traits/info/TypeInfo.scala | 23 ++++++ .../api/profiles/traits/info/ValueInfo.scala | 81 +++++++++++++------ .../profiles/traits/info/VariableInfo.scala | 16 ++++ .../macros/freeze/FreezableMacro.scala | 66 +++++++-------- .../macros/freeze/FreezeMetadata.scala | 3 +- 25 files changed, 415 insertions(+), 70 deletions(-) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index 65da1990..ec687f3a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -4,6 +4,8 @@ import com.sun.jdi.ArrayReference import scala.util.Try import ArrayInfo._ +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} /** * Contains constants available to all array-focused information profiles. @@ -19,6 +21,7 @@ object ArrayInfo { /** * Represents the interface for array-based interaction. */ +@Freezable trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { import scala.reflect.runtime.universe.{TypeTag, typeOf} @@ -29,6 +32,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ArrayInfo /** @@ -36,6 +40,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ArrayReference /** @@ -43,6 +48,8 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * * @return The profile containing type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze override def `type`: ArrayTypeInfo /** @@ -50,6 +57,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * * @return The length of the array */ + @CanFreeze def length: Int /** @@ -66,6 +74,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * @param index The location in the array to retrieve a value * @return The retrieved value */ + @CannotFreeze def value(index: Int): ValueInfo /** @@ -97,6 +106,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * all remaining values to the end of the array * @return The retrieved values */ + @CannotFreeze def values(index: Int, length: Int): Seq[ValueInfo] /** @@ -123,6 +133,8 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * * @return The retrieved values */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def values: Seq[ValueInfo] /** @@ -190,6 +202,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * @param value The new value to place in the array * @return The updated remote value */ + @CannotFreeze def setValueFromInfo(index: Int, value: ValueInfo): ValueInfo /** @@ -278,6 +291,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * beginning of the index * @return The updated remote values */ + @CannotFreeze def setValuesFromInfo( index: Int, values: Seq[ValueInfo], @@ -324,6 +338,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * @param values The new values to use when overwriting elements in the array * @return The updated remote values */ + @CannotFreeze def setValuesFromInfo(values: Seq[ValueInfo]): Seq[ValueInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index 98e0cc6f..4eeb7bef 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ArrayType +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ +@Freezable trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ArrayTypeInfo /** @@ -22,6 +26,7 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ArrayType /** @@ -30,6 +35,7 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * @return The declared type of the elements (the runtime type may be a * subclass of this type) */ + @CanFreeze def elementSignature: String /** @@ -37,6 +43,7 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The type name as a string */ + @CanFreeze def elementTypeName: String /** @@ -44,6 +51,8 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The profile containing type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def elementType: TypeInfo /** @@ -60,6 +69,7 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * @param length The total length of the array * @return The profile representing the new instance */ + @CannotFreeze def newInstance(length: Int): ArrayInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index 517cbcde..d32b3659 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -1,10 +1,13 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ClassLoaderReference +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} /** * Represents the interface for "class loader"-based interaction. */ +@Freezable trait ClassLoaderInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -13,6 +16,7 @@ trait ClassLoaderInfo extends ObjectInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ClassLoaderInfo /** @@ -20,6 +24,7 @@ trait ClassLoaderInfo extends ObjectInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ClassLoaderReference /** @@ -27,6 +32,8 @@ trait ClassLoaderInfo extends ObjectInfo with CommonInfo { * * @return The collection of reference types for the loaded classes */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def definedClasses: Seq[ReferenceTypeInfo] /** @@ -35,5 +42,7 @@ trait ClassLoaderInfo extends ObjectInfo with CommonInfo { * * @return The collection of reference types for the initiated classes */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def visibleClasses: Seq[ReferenceTypeInfo] } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 4cb9bc76..5486f164 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -1,10 +1,13 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ClassObjectReference +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} /** * Represents the interface for "class object"-based interaction. */ +@Freezable trait ClassObjectInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -13,6 +16,7 @@ trait ClassObjectInfo extends ObjectInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ClassObjectInfo /** @@ -20,6 +24,7 @@ trait ClassObjectInfo extends ObjectInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ClassObjectReference /** @@ -28,5 +33,7 @@ trait ClassObjectInfo extends ObjectInfo with CommonInfo { * * @return The reference type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def reflectedType: ReferenceTypeInfo } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index e5a57eeb..33a26ad2 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -2,12 +2,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ClassType import org.scaladebugger.api.lowlevel.JDIArgument +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for retrieving class type-based information. */ +@Freezable trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of @@ -16,6 +19,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ClassTypeInfo /** @@ -23,6 +27,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ClassType /** @@ -31,6 +36,8 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def allInterfaces: Seq[InterfaceTypeInfo] /** @@ -47,6 +54,8 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def interfaces: Seq[InterfaceTypeInfo] /** @@ -62,6 +71,8 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of class type info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def subclasses: Seq[ClassTypeInfo] /** @@ -69,6 +80,8 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return Some class type info if the super class exists, otherwise None */ + @FreezeMetadata(ReturnType.FreezeOption) + @CanFreeze def superclassOption: Option[ClassTypeInfo] /** @@ -76,6 +89,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return True if it is an enumeration, otherwise false */ + @CanFreeze def isEnumeration: Boolean /** @@ -86,6 +100,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * @param signature The JNI signature of the method * @return Some method if found, otherwise None */ + @CannotFreeze def methodOption(name: String, signature: String): Option[MethodInfo] /** @@ -131,6 +146,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * the method invocation * @return The resulting value of the invocation */ + @CannotFreeze def invokeStaticMethod( thread: ThreadInfo, method: MethodInfo, @@ -175,6 +191,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * method invocation * @return The resulting value of the invocation */ + @CannotFreeze def invokeStaticMethod( thread: ThreadInfo, methodName: String, @@ -220,6 +237,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * the constructor invocation * @return The instantiated object */ + @CannotFreeze def newInstance( thread: ThreadInfo, constructorName: String, @@ -238,6 +256,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * the constructor invocation * @return The instantiated object */ + @CannotFreeze def newInstance( thread: ThreadInfo, constructor: MethodInfo, diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 720e6258..8bc68919 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -1,11 +1,14 @@ package org.scaladebugger.api.profiles.traits.info +import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} + import scala.util.Try /** * Represents the interface that needs to be implemented to provide * ability to create data using a specific debug profile. */ +@Freezable trait CreateInfo { /** * Creates the provided value on the remote JVM. @@ -13,6 +16,7 @@ trait CreateInfo { * @param value The value to create (mirror) on the remote JVM * @return The information about the remote value */ + @CannotFreeze def createRemotely(value: AnyVal): ValueInfo /** @@ -31,6 +35,7 @@ trait CreateInfo { * @param value The value to create (mirror) on the remote JVM * @return The information about the remote value */ + @CannotFreeze def createRemotely(value: String): ValueInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index a99197d5..eca992f6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -1,6 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Field +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try @@ -9,6 +11,7 @@ import scala.util.Try * Represents the interface for variable-based interaction with field-specific * information. */ +@Freezable trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -17,6 +20,7 @@ trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: FieldVariableInfo /** @@ -24,6 +28,7 @@ trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: Field /** @@ -32,6 +37,8 @@ trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * @return The reference type information (if a static field) or object * information (if a non-static field) */ + @FreezeMetadata(ReturnType.FreezeEither) + @CanFreeze def parent: Either[ObjectInfo, ReferenceTypeInfo] /** @@ -39,6 +46,8 @@ trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * * @return The reference type information that declared this field */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def declaringType: ReferenceTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 690746c0..12a967a4 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.StackFrame +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for frame-based interaction. */ +@Freezable trait FrameInfo extends CommonInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait FrameInfo extends CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: FrameInfo /** @@ -22,6 +26,7 @@ trait FrameInfo extends CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: StackFrame /** @@ -29,6 +34,7 @@ trait FrameInfo extends CommonInfo { * * @return The index with 0 being the top frame */ + @CanFreeze def index: Int /** @@ -58,6 +64,8 @@ trait FrameInfo extends CommonInfo { * * @return Some profile of this object, or None if not available */ + @FreezeMetadata(ReturnType.FreezeOption) + @CanFreeze def thisObjectOption: Option[ObjectInfo] /** @@ -72,6 +80,8 @@ trait FrameInfo extends CommonInfo { * * @return The profile of the thread */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def currentThread: ThreadInfo /** @@ -86,6 +96,8 @@ trait FrameInfo extends CommonInfo { * * @return The profile of the location */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def location: LocationInfo /** @@ -103,6 +115,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of argument values in order as provided to the frame */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def argumentValues: Seq[ValueInfo] /** @@ -130,6 +144,7 @@ trait FrameInfo extends CommonInfo { * @param name The name of the variable to retrieve * @return Some profile of the variable, or None if it doesn't exist */ + @CannotFreeze def variableOption(name: String): Option[VariableInfo] /** @@ -161,6 +176,7 @@ trait FrameInfo extends CommonInfo { * @param name The name of the variable to retrieve * @return Some profile of the variable, or None if it doesn't exist */ + @CannotFreeze def indexedVariableOption(name: String): Option[VariableInfo] /** @@ -262,6 +278,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def allVariables: Seq[VariableInfo] /** @@ -269,6 +287,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def argumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -276,6 +296,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def nonArgumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -283,6 +305,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def localVariables: Seq[IndexedVariableInfo] /** @@ -290,6 +314,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def fieldVariables: Seq[FieldVariableInfo] /** @@ -297,6 +323,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedAllVariables: Seq[VariableInfo] /** @@ -305,6 +333,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedArgumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -313,6 +343,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedNonArgumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -321,6 +353,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedLocalVariables: Seq[IndexedVariableInfo] /** @@ -329,6 +363,8 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedFieldVariables: Seq[FieldVariableInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index 1a9eb4c1..7ee359ed 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -1,10 +1,14 @@ package org.scaladebugger.api.profiles.traits.info +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} + /** * Represents the interface for variable-based interaction with indexed * location information. */ +@Freezable trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -13,6 +17,7 @@ trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: IndexedVariableInfo /** @@ -20,6 +25,8 @@ trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * * @return The profile of the frame */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def frame: FrameInfo /** @@ -27,5 +34,6 @@ trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * * @return The frame starting from 0 (top of the stack) */ + @CanFreeze def frameIndex: Int } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index e8751a0a..d41d153d 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.InterfaceType +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ +@Freezable trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: InterfaceTypeInfo /** @@ -22,6 +26,7 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: InterfaceType /** @@ -29,6 +34,8 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of class type info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def implementors: Seq[ClassTypeInfo] /** @@ -36,6 +43,8 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def subinterfaces: Seq[InterfaceTypeInfo] /** @@ -43,6 +52,8 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def superinterfaces: Seq[InterfaceTypeInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index 040f8d14..7bb6dc1f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Location +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for location-based interaction. */ +@Freezable trait LocationInfo extends CommonInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait LocationInfo extends CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: LocationInfo /** @@ -22,6 +26,7 @@ trait LocationInfo extends CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: Location /** @@ -30,6 +35,8 @@ trait LocationInfo extends CommonInfo { * * @return The reference type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def declaringType: ReferenceTypeInfo /** @@ -37,6 +44,8 @@ trait LocationInfo extends CommonInfo { * * @return The method information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def method: MethodInfo /** @@ -44,6 +53,7 @@ trait LocationInfo extends CommonInfo { * * @return The code position, or -1 if not available */ + @CanFreeze def codeIndex: Long /** @@ -58,6 +68,7 @@ trait LocationInfo extends CommonInfo { * * @return The line number, or -1 if not available */ + @CanFreeze def lineNumber: Int /** @@ -73,6 +84,7 @@ trait LocationInfo extends CommonInfo { * * @return The identifying name */ + @CanFreeze def sourceName: String /** @@ -88,6 +100,7 @@ trait LocationInfo extends CommonInfo { * * @return The source path */ + @CanFreeze def sourcePath: String /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index b0bc6cb0..95590f25 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Method +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for method-based interaction. */ +@Freezable trait MethodInfo extends CommonInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait MethodInfo extends CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: MethodInfo /** @@ -22,6 +26,7 @@ trait MethodInfo extends CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: Method /** @@ -29,6 +34,7 @@ trait MethodInfo extends CommonInfo { * * @return The name of the method */ + @CanFreeze def name: String /** @@ -46,6 +52,7 @@ trait MethodInfo extends CommonInfo { * * @return The collection of parameter type names */ + @CanFreeze def parameterTypeNames: Seq[String] /** @@ -53,6 +60,8 @@ trait MethodInfo extends CommonInfo { * * @return The collection of profiles containing type information */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def parameterTypes: Seq[TypeInfo] /** @@ -77,6 +86,7 @@ trait MethodInfo extends CommonInfo { * * @return The return type name */ + @CanFreeze def returnTypeName: String /** @@ -84,6 +94,8 @@ trait MethodInfo extends CommonInfo { * * @return The profile containing type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def returnType: TypeInfo /** @@ -98,6 +110,8 @@ trait MethodInfo extends CommonInfo { * * @return The reference type information that declared this method */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def declaringType: ReferenceTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index 08845aef..37d86cd0 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -2,12 +2,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ObjectReference import org.scaladebugger.api.lowlevel.JDIArgument +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for object-based interaction. */ +@Freezable trait ObjectInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -16,6 +19,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ObjectInfo /** @@ -23,6 +27,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ObjectReference /** @@ -30,6 +35,8 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profile containing type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze override def `type`: ReferenceTypeInfo /** @@ -37,6 +44,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The unique id as a long */ + @CanFreeze def uniqueId: Long /** @@ -55,6 +63,8 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * yield the reference type for String, not AnyRef. * @return The reference type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def referenceType: ReferenceTypeInfo /** @@ -197,6 +207,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * method invocation * @return The resulting value of the invocation */ + @CannotFreeze def invoke( thread: ThreadInfo, method: MethodInfo, @@ -217,6 +228,8 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profiles wrapping the visible fields in this object */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def fields: Seq[FieldVariableInfo] /** @@ -232,6 +245,8 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profiles wrapping the visible fields in this object */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedFields: Seq[FieldVariableInfo] /** @@ -263,6 +278,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * @param name The name of the field * @return Some profile wrapping the field, or None if doesn't exist */ + @CannotFreeze def indexedFieldOption(name: String): Option[FieldVariableInfo] /** @@ -289,6 +305,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * @param name The name of the field * @return Some profile wrapping the field, or None if doesn't exist */ + @CannotFreeze def fieldOption(name: String): Option[FieldVariableInfo] /** @@ -304,6 +321,8 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profiles wrapping the visible methods in this object */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def methods: Seq[MethodInfo] /** @@ -342,6 +361,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * of the method to find * @return Some profile wrapping the method, otherwise None if doesn't exist */ + @CannotFreeze def methodOption( name: String, parameterTypeNames: String* diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala index 793eaac9..79069c72 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala @@ -2,12 +2,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.{PrimitiveValue, Value} +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.{Failure, Success, Try} /** * Represents information about a primitive value. */ +@Freezable trait PrimitiveInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -16,6 +19,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: PrimitiveInfo /** @@ -23,6 +27,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: Value /** @@ -30,6 +35,8 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return The profile containing type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze override def `type`: PrimitiveTypeInfo /** @@ -45,6 +52,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return The value as a local instance */ + @CanFreeze override def toLocalValue: AnyVal /** @@ -52,6 +60,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a boolean, otherwise false */ + @CanFreeze def isBoolean: Boolean /** @@ -59,6 +68,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a byte, otherwise false */ + @CanFreeze def isByte: Boolean /** @@ -66,6 +76,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a char, otherwise false */ + @CanFreeze def isChar: Boolean /** @@ -73,6 +84,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a double, otherwise false */ + @CanFreeze def isDouble: Boolean /** @@ -80,6 +92,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a float, otherwise false */ + @CanFreeze def isFloat: Boolean /** @@ -87,6 +100,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a integer, otherwise false */ + @CanFreeze def isInteger: Boolean /** @@ -94,6 +108,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a long, otherwise false */ + @CanFreeze def isLong: Boolean /** @@ -101,6 +116,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return True if the primitive is a short, otherwise false */ + @CanFreeze def isShort: Boolean /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala index 4b9f0ae0..e22bbb32 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala @@ -1,8 +1,11 @@ package org.scaladebugger.api.profiles.traits.info +import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} + /** * Represents the interface for retrieving primitive type-based information. */ +@Freezable trait PrimitiveTypeInfo extends TypeInfo { /** * Converts the current profile instance to a representation of @@ -11,6 +14,7 @@ trait PrimitiveTypeInfo extends TypeInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: PrimitiveTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 149b2ce9..e8b8caeb 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ReferenceType +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for "reference type"-based interaction. */ +@Freezable trait ReferenceTypeInfo extends CommonInfo with TypeInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ReferenceTypeInfo /** @@ -22,6 +26,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ReferenceType /** @@ -30,6 +35,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of fields as variable info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def allFields: Seq[FieldVariableInfo] /** @@ -49,6 +56,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of fields as variable info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def visibleFields: Seq[FieldVariableInfo] /** @@ -71,6 +80,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of fields as variable info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def indexedVisibleFields: Seq[FieldVariableInfo] /** @@ -104,6 +115,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * @param name The name of the field to retrieve * @return Some field as a variable info profile, or None if doesn't exist */ + @CannotFreeze def indexedFieldOption(name: String): Option[FieldVariableInfo] /** @@ -123,6 +135,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * @param name The name of the field to retrieve * @return Some field as a variable info profile, or None if doesn't exist */ + @CannotFreeze def fieldOption(name: String): Option[FieldVariableInfo] /** @@ -149,6 +162,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of methods as method info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def allMethods: Seq[MethodInfo] /** @@ -168,6 +183,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of methods as method info profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def visibleMethods: Seq[MethodInfo] /** @@ -187,6 +204,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * @param name The name of the method to retrieve * @return The collection of method info profiles */ + @CannotFreeze def methods(name: String): Seq[MethodInfo] /** @@ -215,6 +233,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * @return Some profile representing the classloader, * otherwise None if loaded through the bootstrap classloader */ + @FreezeMetadata(ReturnType.FreezeOption) + @CanFreeze def classLoaderOption: Option[ClassLoaderInfo] /** @@ -222,6 +242,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The profile representing the class */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def classObject: ClassObjectInfo /** @@ -229,6 +251,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return Some signature if it exists, otherwise None */ + @CanFreeze def genericSignature: Option[String] /** @@ -238,6 +261,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * to get all reachable instances * @return The collection of object instances */ + @CannotFreeze def instances(maxInstances: Long): Seq[ObjectInfo] /** @@ -271,6 +295,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return True if abstract, otherwise false */ + @CanFreeze def isAbstract: Boolean /** @@ -278,6 +303,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return True if final, otherwise false */ + @CanFreeze def isFinal: Boolean /** @@ -287,6 +313,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return True if initialized, otherwise false */ + @CanFreeze def isInitialized: Boolean /** @@ -294,6 +321,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return True if prepared, otherwise false */ + @CanFreeze def isPrepared: Boolean /** @@ -301,6 +329,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return True if static, otherwise false */ + @CanFreeze def isStatic: Boolean /** @@ -310,6 +339,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return True if verified, otherwise false */ + @CanFreeze def isVerified: Boolean /** @@ -318,6 +348,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of location information */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def allLineLocations: Seq[LocationInfo] /** @@ -336,6 +368,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of location information */ + @CannotFreeze def locationsOfLine(line: Int): Seq[LocationInfo] /** @@ -354,6 +387,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The major version number */ + @CanFreeze def majorVersion: Int /** @@ -370,6 +404,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The minor version number */ + @CanFreeze def minorVersion: Int /** @@ -385,6 +420,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The fully-qualified class name */ + @CanFreeze def name: String /** @@ -393,6 +429,8 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of reference type information */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def nestedTypes: Seq[ReferenceTypeInfo] /** @@ -400,6 +438,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The source debug extension */ + @CanFreeze def sourceDebugExtension: String /** @@ -415,6 +454,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of identifying names */ + @CanFreeze def sourceNames: Seq[String] /** @@ -431,6 +471,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of source paths */ + @CanFreeze def sourcePaths: Seq[String] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index b1ef8b37..b4657a4a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -1,15 +1,12 @@ package org.scaladebugger.api.profiles.traits.info - -import com.sun.jdi.{ArrayReference, StringReference} -import org.scaladebugger.api.profiles.traits.info.ArrayInfo._ - -import scala.util.Try - +import com.sun.jdi.StringReference +import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for string-based interaction. */ +@Freezable trait StringInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -18,6 +15,7 @@ trait StringInfo extends ObjectInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: StringInfo /** @@ -25,6 +23,7 @@ trait StringInfo extends ObjectInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: StringReference /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index 11335ff8..becd040c 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -2,12 +2,13 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.{ThreadGroupReference, ThreadReference} - -import scala.util.Try +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} /** * Represents the interface for thread-based interaction. */ +@Freezable trait ThreadGroupInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -16,6 +17,7 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ThreadGroupInfo /** @@ -23,6 +25,7 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ThreadGroupReference /** @@ -30,6 +33,7 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return The thread group name as a string */ + @CanFreeze def name: String /** @@ -37,18 +41,22 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return Some thread group if a parent exists, otherwise None if top-level */ + @FreezeMetadata(ReturnType.FreezeOption) + @CanFreeze def parent: Option[ThreadGroupInfo] /** * Resumes all threads in the thread group and subgroups. This is not an * atomic operation, so new threads added to a group will be unaffected. */ + @CannotFreeze def resume(): Unit /** * Suspends all threads in the thread group and subgroups. This is not an * atomic operation, so new threads added to a group will be unaffected. */ + @CannotFreeze def suspend(): Unit /** @@ -57,6 +65,8 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return The collection of threads */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def threads: Seq[ThreadInfo] /** @@ -65,6 +75,8 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return The collection of thread groups */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def threadGroups: Seq[ThreadGroupInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index 6c2e894e..fa1f2f81 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ThreadReference +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for thread-based interaction. */ +@Freezable trait ThreadInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: ThreadInfo /** @@ -22,6 +26,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: ThreadReference /** @@ -29,6 +34,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The thread name as a string */ + @CanFreeze def name: String /** @@ -36,6 +42,8 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The thread's status as a profile */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def status: ThreadStatusInfo /** @@ -43,6 +51,8 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The profile of the thread group */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def threadGroup: ThreadGroupInfo /** @@ -50,11 +60,13 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * counter. If the counter remains greater than zero, the thread remains * suspended. */ + @CannotFreeze def resume(): Unit /** * Suspends the thread by incrementing the pending suspension counter. */ + @CannotFreeze def suspend(): Unit /** @@ -65,6 +77,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * @tparam T The return type of the block of code * @return Success containing the result of the thunk, or a failure */ + @CannotFreeze def suspendAndExecute[T](thunk: => T): Try[T] = { suspend() @@ -87,6 +100,8 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The collection of frame profiles */ + @FreezeMetadata(ReturnType.FreezeCollection) + @CanFreeze def frames: Seq[FrameInfo] /** @@ -136,6 +151,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * at index * @return The collection of frame profiles */ + @CannotFreeze protected def rawFrames(index: Int, length: Int): Seq[FrameInfo] /** @@ -150,6 +166,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The total number of frames */ + @CanFreeze def totalFrames: Int /** @@ -169,6 +186,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * profile to retrieve * @return The new frame profile instance */ + @CannotFreeze def frame(index: Int): FrameInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index d5bac47d..cedb0e1f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -1,14 +1,18 @@ package org.scaladebugger.api.profiles.traits.info +import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} + /** * Represents information about a thread's status. */ +@Freezable trait ThreadStatusInfo { /** * Represents the status code for the thread. * * @return The status code as a number */ + @CanFreeze def statusCode: Int /** @@ -34,6 +38,7 @@ trait ThreadStatusInfo { * * @return False if the status is known, otherwise true */ + @CanFreeze def isUnknown: Boolean /** @@ -41,6 +46,7 @@ trait ThreadStatusInfo { * * @return True if a zombie, otherwise false */ + @CanFreeze def isZombie: Boolean /** @@ -48,6 +54,7 @@ trait ThreadStatusInfo { * * @return True if running, otherwise false */ + @CanFreeze def isRunning: Boolean /** @@ -55,6 +62,7 @@ trait ThreadStatusInfo { * * @return True if sleeping, otherwise false */ + @CanFreeze def isSleeping: Boolean /** @@ -62,6 +70,7 @@ trait ThreadStatusInfo { * * @return True if monitoring, otherwise false */ + @CanFreeze def isMonitor: Boolean /** @@ -69,6 +78,7 @@ trait ThreadStatusInfo { * * @return True if waiting, otherwise false */ + @CanFreeze def isWait: Boolean /** @@ -76,6 +86,7 @@ trait ThreadStatusInfo { * * @return True if has started, otherwise false */ + @CanFreeze def isNotStarted: Boolean /** @@ -83,6 +94,7 @@ trait ThreadStatusInfo { * * @return True if suspended at a breakpoint, otherwise false */ + @CanFreeze def isAtBreakpoint: Boolean /** @@ -90,6 +102,7 @@ trait ThreadStatusInfo { * * @return True if suspended, otherwise false */ + @CanFreeze def isSuspended: Boolean /** @@ -97,5 +110,6 @@ trait ThreadStatusInfo { * * @return The total number of pending suspensions */ + @CanFreeze def suspendCount: Int } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index 469508db..875fe670 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Type +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for retrieving type-based information. */ +@Freezable trait TypeInfo extends CommonInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait TypeInfo extends CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: TypeInfo /** @@ -22,6 +26,7 @@ trait TypeInfo extends CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: Type /** @@ -29,6 +34,7 @@ trait TypeInfo extends CommonInfo { * * @return The text representation of the type */ + @CanFreeze def name: String /** @@ -38,6 +44,7 @@ trait TypeInfo extends CommonInfo { * * @return The JNI-style signature */ + @CanFreeze def signature: String /** @@ -108,6 +115,7 @@ trait TypeInfo extends CommonInfo { * * @return True if an array type, otherwise false */ + @CanFreeze def isArrayType: Boolean /** @@ -115,6 +123,7 @@ trait TypeInfo extends CommonInfo { * * @return True if a class type, otherwise false */ + @CanFreeze def isClassType: Boolean /** @@ -122,6 +131,7 @@ trait TypeInfo extends CommonInfo { * * @return True if an interface type, otherwise false */ + @CanFreeze def isInterfaceType: Boolean /** @@ -129,6 +139,7 @@ trait TypeInfo extends CommonInfo { * * @return True if a reference type, otherwise false */ + @CanFreeze def isReferenceType: Boolean /** @@ -136,6 +147,7 @@ trait TypeInfo extends CommonInfo { * * @return True if a primitive type, otherwise false */ + @CanFreeze def isPrimitiveType: Boolean /** @@ -143,6 +155,7 @@ trait TypeInfo extends CommonInfo { * * @return True if representing the type of a null value, otherwise false */ + @CanFreeze def isNullType: Boolean /** @@ -150,6 +163,8 @@ trait TypeInfo extends CommonInfo { * * @return The array type profile wrapping this type */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def toArrayType: ArrayTypeInfo /** @@ -165,6 +180,8 @@ trait TypeInfo extends CommonInfo { * * @return The class type profile wrapping this type */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def toClassType: ClassTypeInfo /** @@ -180,6 +197,8 @@ trait TypeInfo extends CommonInfo { * * @return The interface type profile wrapping this type */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def toInterfaceType: InterfaceTypeInfo /** @@ -195,6 +214,8 @@ trait TypeInfo extends CommonInfo { * * @return The reference type profile wrapping this type */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def toReferenceType: ReferenceTypeInfo /** @@ -210,6 +231,8 @@ trait TypeInfo extends CommonInfo { * * @return The primitive type profile wrapping this type */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def toPrimitiveType: PrimitiveTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 786e3640..9a0f9226 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,14 +1,16 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents information about a value. */ -@Freezable trait ValueInfo extends CommonInfo { +@Freezable +trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of * low-level Java instead of a higher-level abstraction. @@ -16,21 +18,25 @@ import scala.util.Try * @return The profile instance providing an implementation corresponding * to Java */ - @CannotFreeze override def toJavaInfo: ValueInfo + @CannotFreeze + override def toJavaInfo: ValueInfo /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - @CannotFreeze override def toJdiInstance: Value + @CannotFreeze + override def toJdiInstance: Value /** * Returns the type information for the value. * * @return The profile containing type information */ - @CanFreeze def `type`: TypeInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def `type`: TypeInfo /** * Returns the type information for the value. @@ -53,77 +59,88 @@ import scala.util.Try * * @return The value as a local instance */ - @CannotFreeze def toLocalValue: Any + @CannotFreeze + def toLocalValue: Any /** * Returns whether or not this value represents a primitive. * * @return True if a primitive, otherwise false */ - @CanFreeze def isPrimitive: Boolean + @CanFreeze + def isPrimitive: Boolean /** * Returns whether or not this value represents an array. * * @return True if an array, otherwise false */ - @CanFreeze def isArray: Boolean + @CanFreeze + def isArray: Boolean /** * Returns whether or not this value represents a class loader. * * @return True if a class loader, otherwise false */ - @CanFreeze def isClassLoader: Boolean + @CanFreeze + def isClassLoader: Boolean /** * Returns whether or not this value represents a class object. * * @return True if a class object, otherwise false */ - @CanFreeze def isClassObject: Boolean + @CanFreeze + def isClassObject: Boolean /** * Returns whether or not this value represents a thread group. * * @return True if a thread group, otherwise false */ - @CanFreeze def isThreadGroup: Boolean + @CanFreeze + def isThreadGroup: Boolean /** * Returns whether or not this value represents a thread. * * @return True if a thread, otherwise false */ - @CanFreeze def isThread: Boolean + @CanFreeze + def isThread: Boolean /** * Returns whether or not this value represents an object. * * @return True if an object, otherwise false */ - @CanFreeze def isObject: Boolean + @CanFreeze + def isObject: Boolean /** * Returns whether or not this value represents a string. * * @return True if a string, otherwise false */ - @CanFreeze def isString: Boolean + @CanFreeze + def isString: Boolean /** * Returns whether or not this value is null. * * @return True if null, otherwise false */ - @CanFreeze def isNull: Boolean + @CanFreeze + def isNull: Boolean /** * Returns whether or not this value is void. * * @return True if void, otherwise false */ - @CanFreeze def isVoid: Boolean + @CanFreeze + def isVoid: Boolean /** * Returns the value as a primitive (profile). @@ -139,7 +156,9 @@ import scala.util.Try * @return The primitive profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toPrimitiveInfo: PrimitiveInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toPrimitiveInfo: PrimitiveInfo /** * Returns the value as a class loader (profile). @@ -155,7 +174,9 @@ import scala.util.Try * @return The class loader profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toClassLoaderInfo: ClassLoaderInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toClassLoaderInfo: ClassLoaderInfo /** * Returns the value as a class object (profile). @@ -171,7 +192,9 @@ import scala.util.Try * @return The class object profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toClassObjectInfo: ClassObjectInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toClassObjectInfo: ClassObjectInfo /** * Returns the value as a thread group (profile). @@ -187,7 +210,9 @@ import scala.util.Try * @return The thread group profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toThreadGroupInfo: ThreadGroupInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toThreadGroupInfo: ThreadGroupInfo /** * Returns the value as a thread (profile). @@ -203,7 +228,9 @@ import scala.util.Try * @return The thread profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toThreadInfo: ThreadInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toThreadInfo: ThreadInfo /** * Returns the value as an object (profile). @@ -219,7 +246,9 @@ import scala.util.Try * @return The object profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toObjectInfo: ObjectInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toObjectInfo: ObjectInfo /** * Returns the value as a string (profile). @@ -235,7 +264,9 @@ import scala.util.Try * @return The string profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toStringInfo: StringInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toStringInfo: StringInfo /** * Returns the value as an array (profile). @@ -251,7 +282,9 @@ import scala.util.Try * @return The array profile wrapping this value */ @throws[AssertionError] - @CanFreeze def toArrayInfo: ArrayInfo + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze + def toArrayInfo: ArrayInfo /** * Returns a string presenting a better human-readable description of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 5a668e3a..2f9c7a7b 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -1,12 +1,15 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Mirror +import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} import scala.util.Try /** * Represents the interface for variable-based interaction. */ +@Freezable trait VariableInfo extends CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of @@ -15,6 +18,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * @return The profile instance providing an implementation corresponding * to Java */ + @CannotFreeze override def toJavaInfo: VariableInfo /** @@ -22,6 +26,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The JDI instance */ + @CannotFreeze override def toJdiInstance: Mirror /** @@ -29,6 +34,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The name of the variable */ + @CanFreeze def name: String /** @@ -44,6 +50,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return Non-negative number if provided with an index, otherwise -1 */ + @CanFreeze def offsetIndex: Int /** @@ -51,6 +58,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The type name as a string */ + @CanFreeze def typeName: String /** @@ -58,6 +66,8 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The profile containing type information */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def `type`: TypeInfo /** @@ -73,6 +83,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return True if a field, otherwise false */ + @CanFreeze def isField: Boolean /** @@ -80,6 +91,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return True if a local variable, otherwise false */ + @CanFreeze def isLocal: Boolean /** @@ -87,6 +99,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return True if an argument, otherwise false */ + @CanFreeze def isArgument: Boolean /** @@ -102,6 +115,8 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The profile representing the value */ + @FreezeMetadata(ReturnType.FreezeObject) + @CanFreeze def toValueInfo: ValueInfo /** @@ -154,6 +169,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * @param valueInfo The remote value to set for the variable * @return The info for the variable's new value */ + @CannotFreeze def setValueFromInfo(valueInfo: ValueInfo): ValueInfo /** diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 5ab3b906..33dcee13 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -209,7 +209,12 @@ import macrocompat.bundle case l: List[Tree] => l } val internalMethods = bodyTrees.collect { - case d: DefDef => d + case d: DefDef => + /*println("Running type check on " + d.name.decodedName.toString + + " returning " + d.tpt.toString() + + " from " + classDef.name.decodedName.toString) + println("Method Type: " + c.typecheck(d.duplicate).tpe)*/ + d } // TODO: Also process inherited methods that are not covered @@ -250,6 +255,10 @@ import macrocompat.bundle cArgs.append(q""" scala.util.Try.apply($freezeObjName.$tname).map(_map(_.freeze())) """) + case Literal(Constant(rt: RT)) if rt == RT.FreezeOption => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(_map(_.freeze())) + """) } case None => cArgs.append(q""" @@ -306,46 +315,29 @@ import macrocompat.bundle }.filterNot(_ == null) val klass = q""" - class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => - ..$internals - } - """ + class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => + ..$internals + } + """ val method = q""" - def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) - """ + def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) + """ (klass, method) } - // TODO: Remove this hack that is injecting ??? into all - // non-implemented methods + // TODO: Inject freeze method directly into trait rather than + // relying on object implicit val newClassDef: ClassDef = { val bodyTrees: List[Tree] = body match { case l: List[Tree] => l } - val newBody = bodyTrees.map { - /*case vDef: ValDef if vDef.rhs.isEmpty => ValDef( - mods = vDef.mods, - name = vDef.name, - tpt = vDef.tpt, - rhs = q"throw new NotImplementedError" - ) - case dDef: DefDef if dDef.rhs.isEmpty => DefDef( - mods = dDef.mods, - name = dDef.name, - tparams = dDef.tparams, - vparamss = dDef.vparamss, - tpt = dDef.tpt, - rhs = q"throw new NotImplementedError" - )*/ - case t => t - } val tree = q""" $mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => - ..$newBody + ..$bodyTrees } """ @@ -354,19 +346,19 @@ import macrocompat.bundle val newModuleDef: ModuleDef = { val q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = moduleDef + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = moduleDef val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") val implicitFreezeMethod = q""" - implicit class $implicitMethodName(private val $freezeObjName: $tpname) { - def freeze(): Frozen = $tname.freeze($freezeObjName) - } - """ + implicit class $implicitMethodName(private val $freezeObjName: $tpname) { + def freeze(): Frozen = $tname.freeze($freezeObjName) + } + """ val oldBody: List[Tree] = body match { case l: List[Tree] => l diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala index fd0f8625..408ccccc 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala @@ -18,6 +18,7 @@ object FreezeMetadata { /** Return type of method being frozen. */ object ReturnType extends Enumeration { type ReturnType = Value - val Normal, FreezeObject, FreezeCollection = Value + val Normal, FreezeObject, FreezeCollection, + FreezeOption, FreezeEither = Value } } From 3f05d8d70b1ae61e66cf52d14144b84090226307 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 01:09:25 -0700 Subject: [PATCH 21/36] Updated @CanFreeze to have metadata, updated method generation for different metadata types --- .../api/profiles/traits/info/ArrayInfo.scala | 12 +-- .../profiles/traits/info/ArrayTypeInfo.scala | 7 +- .../traits/info/ClassLoaderInfo.scala | 10 +- .../traits/info/ClassObjectInfo.scala | 7 +- .../profiles/traits/info/ClassTypeInfo.scala | 16 ++- .../api/profiles/traits/info/CommonInfo.scala | 15 ++- .../traits/info/FieldVariableInfo.scala | 10 +- .../api/profiles/traits/info/FrameInfo.scala | 46 +++----- .../traits/info/GrabInfoProfile.scala | 3 +- .../traits/info/IndexedVariableInfo.scala | 7 +- .../traits/info/InterfaceTypeInfo.scala | 13 +-- .../api/profiles/traits/info/JavaInfo.scala | 9 +- .../profiles/traits/info/LocationInfo.scala | 10 +- .../api/profiles/traits/info/MethodInfo.scala | 13 +-- .../api/profiles/traits/info/ObjectInfo.scala | 19 ++-- .../profiles/traits/info/PrimitiveInfo.scala | 9 +- .../traits/info/ReferenceTypeInfo.scala | 31 ++---- .../traits/info/ThreadGroupInfo.scala | 15 ++- .../api/profiles/traits/info/ThreadInfo.scala | 13 +-- .../api/profiles/traits/info/TypeInfo.scala | 19 ++-- .../api/profiles/traits/info/ValueInfo.scala | 31 ++---- .../profiles/traits/info/VariableInfo.scala | 10 +- .../macros/freeze/CanFreeze.scala | 19 +++- .../macros/freeze/FreezableMacro.scala | 102 ++++++++---------- .../macros/freeze/FreezeMetadata.scala | 24 ----- 25 files changed, 196 insertions(+), 274 deletions(-) delete mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index ec687f3a..9676b9df 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -1,11 +1,11 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ArrayReference +import org.scaladebugger.api.profiles.traits.info.ArrayInfo._ +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try -import ArrayInfo._ -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} /** * Contains constants available to all array-focused information profiles. @@ -48,8 +48,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) override def `type`: ArrayTypeInfo /** @@ -133,8 +132,7 @@ trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { * * @return The retrieved values */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def values: Seq[ValueInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index 4eeb7bef..f3182fe9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ArrayType -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -51,8 +51,7 @@ trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def elementType: TypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index d32b3659..b8ec04dd 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ClassLoaderReference -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class loader"-based interaction. @@ -32,8 +32,7 @@ trait ClassLoaderInfo extends ObjectInfo with CommonInfo { * * @return The collection of reference types for the loaded classes */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def definedClasses: Seq[ReferenceTypeInfo] /** @@ -42,7 +41,6 @@ trait ClassLoaderInfo extends ObjectInfo with CommonInfo { * * @return The collection of reference types for the initiated classes */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def visibleClasses: Seq[ReferenceTypeInfo] } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 5486f164..8e9848d3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ClassObjectReference -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class object"-based interaction. @@ -33,7 +33,6 @@ trait ClassObjectInfo extends ObjectInfo with CommonInfo { * * @return The reference type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def reflectedType: ReferenceTypeInfo } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 33a26ad2..81764288 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -2,8 +2,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ClassType import org.scaladebugger.api.lowlevel.JDIArgument -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -36,8 +36,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def allInterfaces: Seq[InterfaceTypeInfo] /** @@ -54,8 +53,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def interfaces: Seq[InterfaceTypeInfo] /** @@ -71,8 +69,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of class type info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def subclasses: Seq[ClassTypeInfo] /** @@ -80,8 +77,7 @@ trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return Some class type info if the super class exists, otherwise None */ - @FreezeMetadata(ReturnType.FreezeOption) - @CanFreeze + @CanFreeze(ReturnType.FreezeOption) def superclassOption: Option[ClassTypeInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 969a22c3..395c38fa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -7,20 +7,23 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -@Freezable trait CommonInfo extends JavaInfo { +@Freezable +trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. * * @return The Scala virtual machine instance */ - @CannotFreeze def scalaVirtualMachine: ScalaVirtualMachine + @CannotFreeze + def scalaVirtualMachine: ScalaVirtualMachine /** * Returns the JDI representation this profile instance wraps. * * @return The JDI instance */ - @CannotFreeze def toJdiInstance: Mirror + @CannotFreeze + def toJdiInstance: Mirror /** * Returns a string presenting a better human-readable description of @@ -28,7 +31,8 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * * @return The human-readable description */ - @CanFreeze def toPrettyString: String + @CanFreeze + def toPrettyString: String /** * Converts the current profile instance to a representation of @@ -37,5 +41,6 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * @return The profile instance providing an implementation corresponding * to Java */ - @CannotFreeze override def toJavaInfo: CommonInfo + @CannotFreeze + override def toJavaInfo: CommonInfo } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index eca992f6..94441dad 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Field -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -37,8 +37,7 @@ trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * @return The reference type information (if a static field) or object * information (if a non-static field) */ - @FreezeMetadata(ReturnType.FreezeEither) - @CanFreeze + @CanFreeze(ReturnType.FreezeEither) def parent: Either[ObjectInfo, ReferenceTypeInfo] /** @@ -46,8 +45,7 @@ trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * * @return The reference type information that declared this field */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def declaringType: ReferenceTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 12a967a4..1c9928cd 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.StackFrame -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -64,8 +64,7 @@ trait FrameInfo extends CommonInfo { * * @return Some profile of this object, or None if not available */ - @FreezeMetadata(ReturnType.FreezeOption) - @CanFreeze + @CanFreeze(ReturnType.FreezeOption) def thisObjectOption: Option[ObjectInfo] /** @@ -80,8 +79,7 @@ trait FrameInfo extends CommonInfo { * * @return The profile of the thread */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def currentThread: ThreadInfo /** @@ -96,8 +94,7 @@ trait FrameInfo extends CommonInfo { * * @return The profile of the location */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def location: LocationInfo /** @@ -115,8 +112,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of argument values in order as provided to the frame */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def argumentValues: Seq[ValueInfo] /** @@ -278,8 +274,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def allVariables: Seq[VariableInfo] /** @@ -287,8 +282,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def argumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -296,8 +290,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def nonArgumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -305,8 +298,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def localVariables: Seq[IndexedVariableInfo] /** @@ -314,8 +306,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def fieldVariables: Seq[FieldVariableInfo] /** @@ -323,8 +314,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedAllVariables: Seq[VariableInfo] /** @@ -333,8 +323,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedArgumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -343,8 +332,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedNonArgumentLocalVariables: Seq[IndexedVariableInfo] /** @@ -353,8 +341,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedLocalVariables: Seq[IndexedVariableInfo] /** @@ -363,8 +350,7 @@ trait FrameInfo extends CommonInfo { * * @return The collection of variables as their profile equivalents */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedFieldVariables: Seq[FieldVariableInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala index b16eebfb..fcb8166e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala @@ -1,8 +1,9 @@ package org.scaladebugger.api.profiles.traits.info -import com.sun.jdi._ import java.util.NoSuchElementException +import com.sun.jdi._ + import scala.annotation.tailrec import scala.util.Try diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index 7ee359ed..99b62489 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -1,7 +1,7 @@ package org.scaladebugger.api.profiles.traits.info -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** @@ -25,8 +25,7 @@ trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { * * @return The profile of the frame */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def frame: FrameInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index d41d153d..2b7ff13e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.InterfaceType -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -34,8 +34,7 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of class type info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def implementors: Seq[ClassTypeInfo] /** @@ -43,8 +42,7 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def subinterfaces: Seq[InterfaceTypeInfo] /** @@ -52,8 +50,7 @@ trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { * * @return The collection of interface type info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def superinterfaces: Seq[InterfaceTypeInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index a4a917bc..8263df20 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -6,7 +6,8 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -@Freezable trait JavaInfo { +@Freezable +trait JavaInfo { /** * Returns whether or not this info profile represents the low-level Java * implementation. @@ -15,7 +16,8 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * otherwise this profile represents something higher-level like * Scala, Jython, or JRuby */ - @CanFreeze def isJavaInfo: Boolean + @CanFreeze + def isJavaInfo: Boolean /** * Converts the current profile instance to a representation of @@ -24,5 +26,6 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * @return The profile instance providing an implementation corresponding * to Java */ - @CannotFreeze def toJavaInfo: AnyRef + @CannotFreeze + def toJavaInfo: AnyRef } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index 7bb6dc1f..188c91eb 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Location -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -35,8 +35,7 @@ trait LocationInfo extends CommonInfo { * * @return The reference type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def declaringType: ReferenceTypeInfo /** @@ -44,8 +43,7 @@ trait LocationInfo extends CommonInfo { * * @return The method information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def method: MethodInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index 95590f25..e7d24563 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Method -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -60,8 +60,7 @@ trait MethodInfo extends CommonInfo { * * @return The collection of profiles containing type information */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def parameterTypes: Seq[TypeInfo] /** @@ -94,8 +93,7 @@ trait MethodInfo extends CommonInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def returnType: TypeInfo /** @@ -110,8 +108,7 @@ trait MethodInfo extends CommonInfo { * * @return The reference type information that declared this method */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def declaringType: ReferenceTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index 37d86cd0..a6d11395 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -2,8 +2,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ObjectReference import org.scaladebugger.api.lowlevel.JDIArgument -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -35,8 +35,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) override def `type`: ReferenceTypeInfo /** @@ -63,8 +62,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * yield the reference type for String, not AnyRef. * @return The reference type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def referenceType: ReferenceTypeInfo /** @@ -228,8 +226,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profiles wrapping the visible fields in this object */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def fields: Seq[FieldVariableInfo] /** @@ -245,8 +242,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profiles wrapping the visible fields in this object */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedFields: Seq[FieldVariableInfo] /** @@ -321,8 +317,7 @@ trait ObjectInfo extends ValueInfo with CommonInfo { * * @return The profiles wrapping the visible methods in this object */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def methods: Seq[MethodInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala index 79069c72..7f02b8ec 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala @@ -1,9 +1,9 @@ package org.scaladebugger.api.profiles.traits.info -import com.sun.jdi.{PrimitiveValue, Value} -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import com.sun.jdi.Value +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.{Failure, Success, Try} @@ -35,8 +35,7 @@ trait PrimitiveInfo extends ValueInfo with CommonInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) override def `type`: PrimitiveTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index e8b8caeb..3c14a96e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ReferenceType -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -35,8 +35,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of fields as variable info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def allFields: Seq[FieldVariableInfo] /** @@ -56,8 +55,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of fields as variable info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def visibleFields: Seq[FieldVariableInfo] /** @@ -80,8 +78,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of fields as variable info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def indexedVisibleFields: Seq[FieldVariableInfo] /** @@ -162,8 +159,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of methods as method info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def allMethods: Seq[MethodInfo] /** @@ -183,8 +179,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of methods as method info profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def visibleMethods: Seq[MethodInfo] /** @@ -233,8 +228,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * @return Some profile representing the classloader, * otherwise None if loaded through the bootstrap classloader */ - @FreezeMetadata(ReturnType.FreezeOption) - @CanFreeze + @CanFreeze(ReturnType.FreezeOption) def classLoaderOption: Option[ClassLoaderInfo] /** @@ -242,8 +236,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The profile representing the class */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def classObject: ClassObjectInfo /** @@ -348,8 +341,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of location information */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def allLineLocations: Seq[LocationInfo] /** @@ -429,8 +421,7 @@ trait ReferenceTypeInfo extends CommonInfo with TypeInfo { * * @return The collection of reference type information */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def nestedTypes: Seq[ReferenceTypeInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index becd040c..b5762dc6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -1,9 +1,9 @@ package org.scaladebugger.api.profiles.traits.info -import com.sun.jdi.{ThreadGroupReference, ThreadReference} -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import com.sun.jdi.ThreadGroupReference +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for thread-based interaction. @@ -41,8 +41,7 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return Some thread group if a parent exists, otherwise None if top-level */ - @FreezeMetadata(ReturnType.FreezeOption) - @CanFreeze + @CanFreeze(ReturnType.FreezeOption) def parent: Option[ThreadGroupInfo] /** @@ -65,8 +64,7 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return The collection of threads */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def threads: Seq[ThreadInfo] /** @@ -75,8 +73,7 @@ trait ThreadGroupInfo extends ObjectInfo with CommonInfo { * * @return The collection of thread groups */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def threadGroups: Seq[ThreadGroupInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index fa1f2f81..cdadfaec 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.ThreadReference -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -42,8 +42,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The thread's status as a profile */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def status: ThreadStatusInfo /** @@ -51,8 +50,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The profile of the thread group */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def threadGroup: ThreadGroupInfo /** @@ -100,8 +98,7 @@ trait ThreadInfo extends ObjectInfo with CommonInfo { * * @return The collection of frame profiles */ - @FreezeMetadata(ReturnType.FreezeCollection) - @CanFreeze + @CanFreeze(ReturnType.FreezeCollection) def frames: Seq[FrameInfo] /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index 875fe670..d988f003 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Type -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -163,8 +163,7 @@ trait TypeInfo extends CommonInfo { * * @return The array type profile wrapping this type */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toArrayType: ArrayTypeInfo /** @@ -180,8 +179,7 @@ trait TypeInfo extends CommonInfo { * * @return The class type profile wrapping this type */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toClassType: ClassTypeInfo /** @@ -197,8 +195,7 @@ trait TypeInfo extends CommonInfo { * * @return The interface type profile wrapping this type */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toInterfaceType: InterfaceTypeInfo /** @@ -214,8 +211,7 @@ trait TypeInfo extends CommonInfo { * * @return The reference type profile wrapping this type */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toReferenceType: ReferenceTypeInfo /** @@ -231,8 +227,7 @@ trait TypeInfo extends CommonInfo { * * @return The primitive type profile wrapping this type */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toPrimitiveType: PrimitiveTypeInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index 9a0f9226..a2f28192 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Value -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -34,8 +34,7 @@ trait ValueInfo extends CommonInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def `type`: TypeInfo /** @@ -156,8 +155,7 @@ trait ValueInfo extends CommonInfo { * @return The primitive profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toPrimitiveInfo: PrimitiveInfo /** @@ -174,8 +172,7 @@ trait ValueInfo extends CommonInfo { * @return The class loader profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toClassLoaderInfo: ClassLoaderInfo /** @@ -192,8 +189,7 @@ trait ValueInfo extends CommonInfo { * @return The class object profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toClassObjectInfo: ClassObjectInfo /** @@ -210,8 +206,7 @@ trait ValueInfo extends CommonInfo { * @return The thread group profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toThreadGroupInfo: ThreadGroupInfo /** @@ -228,8 +223,7 @@ trait ValueInfo extends CommonInfo { * @return The thread profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toThreadInfo: ThreadInfo /** @@ -246,8 +240,7 @@ trait ValueInfo extends CommonInfo { * @return The object profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toObjectInfo: ObjectInfo /** @@ -264,8 +257,7 @@ trait ValueInfo extends CommonInfo { * @return The string profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toStringInfo: StringInfo /** @@ -282,8 +274,7 @@ trait ValueInfo extends CommonInfo { * @return The array profile wrapping this value */ @throws[AssertionError] - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toArrayInfo: ArrayInfo /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 2f9c7a7b..67419f38 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -1,8 +1,8 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Mirror -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType -import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable, FreezeMetadata} +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -66,8 +66,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The profile containing type information */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def `type`: TypeInfo /** @@ -115,8 +114,7 @@ trait VariableInfo extends CreateInfo with CommonInfo { * * @return The profile representing the value */ - @FreezeMetadata(ReturnType.FreezeObject) - @CanFreeze + @CanFreeze(ReturnType.FreezeObject) def toValueInfo: ValueInfo /** diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala index 1f5e34bc..f6daa895 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/CanFreeze.scala @@ -1,5 +1,8 @@ package org.scaladebugger.macros.freeze +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType.ReturnType + import scala.annotation.StaticAnnotation import scala.language.experimental.macros @@ -7,5 +10,19 @@ import scala.language.experimental.macros * Marks an internal method of a [[org.scaladebugger.macros.freeze.Freezable]] * component as able to be frozen, which means it will be swapped with the * result of accessing the live data when frozen. + * + * @param returnType Freeze-related information about the method's return type + * (defaults to normal freezing with no additional work) */ -class CanFreeze extends StaticAnnotation +case class CanFreeze( + returnType: ReturnType = ReturnType.Normal +) extends StaticAnnotation + +object CanFreeze { + /** Return type of method being frozen. */ + object ReturnType extends Enumeration { + type ReturnType = Value + val Normal, FreezeObject, FreezeCollection, + FreezeOption, FreezeEither = Value + } +} diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 33dcee13..cfb982b3 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -35,20 +35,6 @@ import macrocompat.bundle ) } - private def findClassPackage(classDef: ClassDef): TermName = { - val dummyClass = c.typecheck(classDef.duplicate) - TermName(packageFromSymbol(dummyClass.symbol.owner)) - } - - private def packageFromSymbol(symbol: Symbol): String = { - @tailrec def buildPackage(symbol: Symbol, tokens: Seq[String]): String = { - if (symbol == NoSymbol) tokens.mkString(".") - else buildPackage(symbol.owner, symbol.name.decodedName.toString +: tokens) - } - - buildPackage(symbol, Nil) - } - private def containsAnnotation(d: DefDef, aName: String): Boolean = findAnnotation(d, aName).nonEmpty @@ -195,9 +181,6 @@ import macrocompat.bundle val inheritedMethods = extractInheritedMethods( extractParentTypes(parents.asInstanceOf[List[Tree]]).flatten ) - println("INHERTED METHODS FOR " + tpname.toString() + " :: " + inheritedMethods.map(m => - m.name.toString + " from " + m.owner.name.toString - ).mkString(" | ")) // Represents name of variable passed to freeze method val freezeObjName = TermName("valueToFreeze") @@ -208,17 +191,11 @@ import macrocompat.bundle val bodyTrees: List[Tree] = body match { case l: List[Tree] => l } - val internalMethods = bodyTrees.collect { - case d: DefDef => - /*println("Running type check on " + d.name.decodedName.toString + - " returning " + d.tpt.toString() + - " from " + classDef.name.decodedName.toString) - println("Method Type: " + c.typecheck(d.duplicate).tpe)*/ - d - } + val internalMethods = bodyTrees.collect { case d: DefDef => d } // TODO: Also process inherited methods that are not covered // by the tree methods + // TODO: CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP val internals = internalMethods.map { case d: DefDef if containsAnnotation(d, "CanFreeze") => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d @@ -238,32 +215,46 @@ import macrocompat.bundle // TODO: Remove runtime checks by getting better understanding of // return type, if it contains a freeze method, etc. - findAnnotation(d, "FreezeMetadata") match { - case Some(a) => - import FreezeMetadata.{ReturnType => RT} - type RT = FreezeMetadata.ReturnType.ReturnType - a match { - case Literal(Constant(rt: RT)) if rt == RT.Normal => + findAnnotation(d, "CanFreeze").get match { + case q"new CanFreeze()" => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case q"new CanFreeze($returnType)" => + // TODO: Find better way to match against the input + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + val r = ReturnType.withName(returnType.toString().split('.').last) + + r match { + case ReturnType.Normal => cArgs.append(q""" scala.util.Try.apply($freezeObjName.$tname) + .asInstanceOf[scala.util.Try[$tpt]] """) - case Literal(Constant(rt: RT)) if rt == RT.FreezeObject => + case ReturnType.FreezeObject => cArgs.append(q""" scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) + .asInstanceOf[scala.util.Try[$tpt]] """) - case Literal(Constant(rt: RT)) if rt == RT.FreezeCollection => + case ReturnType.FreezeCollection => cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_map(_.freeze())) + scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$tpt]] """) - case Literal(Constant(rt: RT)) if rt == RT.FreezeOption => + case ReturnType.FreezeOption => cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_map(_.freeze())) + scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case ReturnType.FreezeEither => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(r => r match { + case scala.util.Left(o) => scala.util.Left(o.freeze()) + case scala.util.Right(o) => scala.util.Right(o.freeze()) + }).asInstanceOf[scala.util.Try[$tpt]] """) } - case None => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - """) } // Add override if not already there @@ -333,13 +324,22 @@ import macrocompat.bundle case l: List[Tree] => l } + // TODO: Find better way to know when to mark as overriden + val o = TermName(tpname.toString()) + val freezeMethod = + if (inheritedMethods.exists(_.name.toString == "freeze")) + q"override def freeze(): $tpname = $o.freeze(this)" + else + q"def freeze(): $tpname = $o.freeze(this)" + val tree = q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$bodyTrees - } - """ + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$bodyTrees + $freezeMethod + } + """ tree match { case c: ClassDef => c } } @@ -353,20 +353,12 @@ import macrocompat.bundle } """ = moduleDef - val implicitMethodName = TypeName(s"${tpname}FrozenWrapper") - val implicitFreezeMethod = q""" - implicit class $implicitMethodName(private val $freezeObjName: $tpname) { - def freeze(): Frozen = $tname.freeze($freezeObjName) - } - """ - val oldBody: List[Tree] = body match { case l: List[Tree] => l } val newBody = oldBody ++ List( frozenClass, - freezeMethod, - q"object Implicits { $implicitFreezeMethod }" + freezeMethod ) val newObjDef = q""" diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala deleted file mode 100644 index 408ccccc..00000000 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezeMetadata.scala +++ /dev/null @@ -1,24 +0,0 @@ -package org.scaladebugger.macros.freeze - -import org.scaladebugger.macros.freeze.FreezeMetadata.ReturnType.ReturnType - -import scala.annotation.StaticAnnotation -import scala.language.experimental.macros - -/** - * Internal metadata assigned to methods upon inspection. - * - * @param returnType Freeze-related information about the method's return type - */ -case class FreezeMetadata private[freeze]( - returnType: ReturnType -) extends StaticAnnotation - -object FreezeMetadata { - /** Return type of method being frozen. */ - object ReturnType extends Enumeration { - type ReturnType = Value - val Normal, FreezeObject, FreezeCollection, - FreezeOption, FreezeEither = Value - } -} From 31cd7ec444c5d1527ae6df0890a2544780ee5c1d Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 02:03:27 -0700 Subject: [PATCH 22/36] Removed old reference to FreezeMetadata --- .../org/scaladebugger/macros/freeze/FreezableMacro.scala | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index cfb982b3..b3599ced 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -265,9 +265,7 @@ import macrocompat.bundle flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") || - isAnnotation(a, "FreezeMetadata") + isAnnotation(a, "CanFreeze") || isAnnotation(a, "CannotFreeze") }) ) @@ -283,9 +281,7 @@ import macrocompat.bundle flags = Flag.OVERRIDE | oldMods.flags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || - isAnnotation(a, "CannotFreeze") || - isAnnotation(a, "FreezeMetadata") + isAnnotation(a, "CanFreeze") || isAnnotation(a, "CannotFreeze") }) ) From 3c053453edbc2c8d0429d9ba202deb2dc22607dc Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 02:22:45 -0700 Subject: [PATCH 23/36] Minor refactoring --- .../macros/freeze/FreezableMacro.scala | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index b3599ced..b95dc69e 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -185,7 +185,7 @@ import macrocompat.bundle // Represents name of variable passed to freeze method val freezeObjName = TermName("valueToFreeze") - val (frozenClass, freezeMethod) = { + val freezeTrees = { val cParams = collection.mutable.ArrayBuffer[Tree]() val cArgs = collection.mutable.ArrayBuffer[Tree]() val bodyTrees: List[Tree] = body match { @@ -286,9 +286,9 @@ import macrocompat.bundle ) q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = - throw new IllegalStateException("Method not frozen!") - """ + $newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!") + """ case d: DefDef => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d val exprTree: Tree = expr match { @@ -302,15 +302,15 @@ import macrocompat.bundle }.filterNot(_ == null) val klass = q""" - class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => + final class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => ..$internals } """ val method = q""" - def freeze($freezeObjName: $tpname): Frozen = new Frozen(..$cArgs) + def freeze($freezeObjName: $tpname): $tpname = new Frozen(..$cArgs) """ - (klass, method) + List(klass, method) } // TODO: Inject freeze method directly into trait rather than @@ -352,10 +352,7 @@ import macrocompat.bundle val oldBody: List[Tree] = body match { case l: List[Tree] => l } - val newBody = oldBody ++ List( - frozenClass, - freezeMethod - ) + val newBody = oldBody ++ freezeTrees val newObjDef = q""" $mods object $tname extends { From 6b396b448fc7d1f9a5b2634d80000eba923373d0 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 02:34:17 -0700 Subject: [PATCH 24/36] Updated to blocks --- .../org/scaladebugger/macros/freeze/FreezableMacro.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index b95dc69e..a70b09f0 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -269,7 +269,11 @@ import macrocompat.bundle }) ) - q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = { + this.$name.get + } + """ case d: DefDef if containsAnnotation(d, "CannotFreeze") => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d @@ -286,8 +290,9 @@ import macrocompat.bundle ) q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = + $newMods def $tname[..$tparams](...$paramss): $tpt = { throw new IllegalStateException("Method not frozen!") + } """ case d: DefDef => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d From a7b2c1cac387bf169f447a99adc977e5b91691c5 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 19:55:55 -0700 Subject: [PATCH 25/36] Added empty tests for @Freezable, fixed issue where filled in methods were still using Flag.DEFERRED --- project/Macros.scala | 5 ++-- .../macros/freeze/FreezableMacro.scala | 14 +++++++++-- .../macros/freeze/FreezableSpec.scala | 23 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 scala-debugger-macros/src/test/scala/org/scaladebugger/macros/freeze/FreezableSpec.scala diff --git a/project/Macros.scala b/project/Macros.scala index 90587630..c7cdd217 100644 --- a/project/Macros.scala +++ b/project/Macros.scala @@ -13,11 +13,12 @@ object Macros { ) /** Macro-specific project settings. */ - val settings = pluginSettings ++ Seq( + val settings: Seq[Setting[_]] = pluginSettings ++ Seq( libraryDependencies ++= Seq( "org.typelevel" %% "macro-compat" % "1.1.1", "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", - scalaVersion("org.scala-lang" % "scala-reflect" % _).value + scalaVersion("org.scala-lang" % "scala-reflect" % _).value, + "org.scalatest" %% "scalatest" % "3.0.0" % "test,it" ), libraryDependencies ++= ( diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index a70b09f0..55e74bdb 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -261,8 +261,13 @@ import macrocompat.bundle val oldMods: Modifiers = mods match { case m: Modifiers => m } + + // TODO: Is there a way to filter out just the DEFERRED flag? + val newFlags = Flag.OVERRIDE | + (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) + val newMods = c.universe.Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, + flags = newFlags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { isAnnotation(a, "CanFreeze") || isAnnotation(a, "CannotFreeze") @@ -281,8 +286,13 @@ import macrocompat.bundle val oldMods: Modifiers = mods match { case m: Modifiers => m } + + // TODO: Is there a way to filter out just the DEFERRED flag? + val newFlags = Flag.OVERRIDE | + (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) + val newMods = c.universe.Modifiers( - flags = Flag.OVERRIDE | oldMods.flags, + flags = newFlags, privateWithin = oldMods.privateWithin, annotations = oldMods.annotations.filterNot(a => { isAnnotation(a, "CanFreeze") || isAnnotation(a, "CannotFreeze") diff --git a/scala-debugger-macros/src/test/scala/org/scaladebugger/macros/freeze/FreezableSpec.scala b/scala-debugger-macros/src/test/scala/org/scaladebugger/macros/freeze/FreezableSpec.scala new file mode 100644 index 00000000..09200040 --- /dev/null +++ b/scala-debugger-macros/src/test/scala/org/scaladebugger/macros/freeze/FreezableSpec.scala @@ -0,0 +1,23 @@ +package org.scaladebugger.macros.freeze + +import org.scalatest.{FunSpec, Matchers} + +class FreezableSpec extends FunSpec with Matchers { + describe("@Freezable") { + it("should generate a companion object with a freeze method") { + fail() + } + + it("should modify an existing companion object with a freeze method") { + fail() + } + + it("should convert @CannotFreeze methods to throw an exception") { + fail() + } + + it("should convert @CanFreeze(Normal) methods to store ") { + fail() + } + } +} From c2cd929dd2c1f169c66d17ea6a0fd6ef741adeab Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 21:15:59 -0700 Subject: [PATCH 26/36] Migrated some code to util class --- .../org/scaladebugger/macros/MacroUtils.scala | 125 +++++ .../macros/freeze/FreezableMacro.scala | 441 +++++++----------- 2 files changed, 296 insertions(+), 270 deletions(-) create mode 100644 scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala new file mode 100644 index 00000000..1154d81e --- /dev/null +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -0,0 +1,125 @@ +package org.scaladebugger.macros + +import scala.language.experimental.macros +import scala.annotation.tailrec +import scala.reflect.macros.whitebox +import macrocompat.bundle + +@bundle class MacroUtils[C <: whitebox.Context](val c: C) { + import c.universe._ + + def containsAnnotation(d: DefDef, aName: String): Boolean = + findAnnotation(d, aName).nonEmpty + + def findAnnotation(d: DefDef, aName: String): Option[Tree] = + d.mods.annotations.find(a => isAnnotation(a, aName)) + + def isAnnotation(t: Tree, aName: String): Boolean = t match { + case Apply(f, args) => f match { + case Select(qual, name) => qual match { + case New(tpt) => tpt match { + case Ident(iName) => iName.decodedName.toString == aName + case _ => false + } + case _ => false + } + } + case _ => false + } + + def isTrait(classDef: ClassDef): Boolean = { + try { + val q""" + $mods trait $tpname[..$tparams] extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + } + """ = classDef + true + } catch { + case _: Throwable => false + } + } + + def extractInheritedMethods(parents: List[Type]): List[MethodSymbol] = { + val anyTypeSymbol = typeOf[Any].typeSymbol + val objectTypeSymbol = typeOf[Object].typeSymbol + + def stripDuplicateMethods(methods: List[MethodSymbol]): List[MethodSymbol] = { + val overrides = methods.flatMap(_.overrides) + methods.filterNot(overrides.contains) + } + + @tailrec def extract(types: List[Type], methods: List[MethodSymbol]): List[MethodSymbol] = { + val parentMethods = types.flatMap(pt => { + pt.members + .filter(_.isMethod) + .filter(_.owner == pt.typeSymbol) + .map(_.asMethod) + }) + val parentTypes = types + .flatMap(t => { + t.baseClasses.filterNot(c => + c == t.typeSymbol || + c == anyTypeSymbol || + c == objectTypeSymbol + ) + }) + .filter(_.isClass) + .map(_.asClass.toType) + + val allMethods = stripDuplicateMethods(methods ++ parentMethods) + + if (parentTypes.nonEmpty) extract(parentTypes, allMethods) + else allMethods + } + + extract(parents, Nil) + } + + def extractParentTypes(parents: List[Tree]): List[Option[Type]] = { + parents match { + case p: List[Tree] => p.map(extractParentType) + } + } + + private def extractParentType(parent: Tree): Option[Type] = { + def isBaseType(n1: Name, n2: Name = null): Boolean = { + val name = if (n2 != null) { + n1.toString + "." + n2.toString + } else { + n1.toString + } + + val baseTypeNames = Seq( + "Any", "scala.Any", "AnyRef", "scala.AnyRef", + "AnyVal", "scala.AnyVal", "java.lang.Object" + ) + + baseTypeNames.contains(name) + } + + parent match { + case Ident(name) if !isBaseType(name) => + val typeName = name.toTypeName + val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$typeName]")) + typedTree.toOption.flatMap(tt => Option(tt.tpe)) + case Select(Ident(name), typeName) if !isBaseType(name, typeName) => + val t1 = name.toTermName + val t2 = typeName.toTypeName + val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$t1.$t2]")) + typedTree.toOption.flatMap(tt => Option(tt.tpe)) + case a => + None + } + } + + def newEmptyObject(name: String): ModuleDef = { + val oName = TermName(name) + val moduleDef: ModuleDef = q"object $oName {}" match { + case m: ModuleDef => m + } + moduleDef + } +} diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 55e74bdb..9792c354 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -1,23 +1,25 @@ package org.scaladebugger.macros.freeze import scala.language.experimental.macros -import scala.annotation.tailrec import scala.reflect.macros.whitebox import macrocompat.bundle +import org.scaladebugger.macros.MacroUtils @bundle class FreezableMacro(val c: whitebox.Context) { import c.universe._ + val M = new MacroUtils[c.type](c) + // NOTE: Stuck with c.Expr[Any] instead of c.Tree for now; // blows up in Scala 2.10 even with @bundle otherwise def impl(annottees: c.Expr[Any]*): c.Expr[Any] = { val (annottee, expandees) = annottees.map(_.tree) match { - case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if isTrait(classDef) => + case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if M.isTrait(classDef) => //println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) val results = processTraitAndObj(classDef, moduleDef) //println("RESULTS :: " + results) (EmptyTree, results) - case (classDef: ClassDef) :: Nil if isTrait(classDef) => + case (classDef: ClassDef) :: Nil if M.isTrait(classDef) => //println("INPUT CLASS ONLY :: " + classDef) val results = processTrait(classDef) //println("RESULTS :: " + results) @@ -35,113 +37,6 @@ import macrocompat.bundle ) } - private def containsAnnotation(d: DefDef, aName: String): Boolean = - findAnnotation(d, aName).nonEmpty - - private def findAnnotation(d: DefDef, aName: String): Option[Tree] = - d.mods.annotations.find(a => isAnnotation(a, aName)) - - private def isAnnotation(t: Tree, aName: String): Boolean = t match { - case Apply(f, args) => f match { - case Select(qual, name) => qual match { - case New(tpt) => tpt match { - case Ident(iName) => iName.decodedName.toString == aName - case _ => false - } - case _ => false - } - } - case _ => false - } - - private def isTrait(classDef: ClassDef): Boolean = { - try { - val q""" - $mods trait $tpname[..$tparams] extends { - ..$earlydefns - } with ..$parents { $self => - ..$body - } - """ = classDef - true - } catch { - case _: Throwable => false - } - } - - private def extractInheritedMethods(parents: List[Type]): List[MethodSymbol] = { - val anyTypeSymbol = typeOf[Any].typeSymbol - val objectTypeSymbol = typeOf[Object].typeSymbol - - def stripDuplicateMethods(methods: List[MethodSymbol]): List[MethodSymbol] = { - val overrides = methods.flatMap(_.overrides) - methods.filterNot(overrides.contains) - } - - @tailrec def extract(types: List[Type], methods: List[MethodSymbol]): List[MethodSymbol] = { - val parentMethods = types.flatMap(pt => { - pt.members - .filter(_.isMethod) - .filter(_.owner == pt.typeSymbol) - .map(_.asMethod) - }) - val parentTypes = types - .flatMap(t => { - t.baseClasses.filterNot(c => - c == t.typeSymbol || - c == anyTypeSymbol || - c == objectTypeSymbol - ) - }) - .filter(_.isClass) - .map(_.asClass.toType) - - val allMethods = stripDuplicateMethods(methods ++ parentMethods) - - if (parentTypes.nonEmpty) extract(parentTypes, allMethods) - else allMethods - } - - extract(parents, Nil) - } - - private def extractParentTypes(parents: List[Tree]): List[Option[Type]] = { - parents match { - case p: List[Tree] => p.map(extractParentType) - } - } - - private def extractParentType(parent: Tree): Option[Type] = { - def isBaseType(n1: Name, n2: Name = null): Boolean = { - val name = if (n2 != null) { - n1.toString + "." + n2.toString - } else { - n1.toString - } - - val baseTypeNames = Seq( - "Any", "scala.Any", "AnyRef", "scala.AnyRef", - "AnyVal", "scala.AnyVal", "java.lang.Object" - ) - - baseTypeNames.contains(name) - } - - parent match { - case Ident(name) if !isBaseType(name) => - val typeName = name.toTypeName - val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$typeName]")) - typedTree.toOption.flatMap(tt => Option(tt.tpe)) - case Select(Ident(name), typeName) if !isBaseType(name, typeName) => - val t1 = name.toTermName - val t2 = typeName.toTypeName - val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$t1.$t2]")) - typedTree.toOption.flatMap(tt => Option(tt.tpe)) - case a => - None - } - } - private def processTrait(classDef: ClassDef): List[Tree] = { val q""" $mods trait $tpname[..$tparams] extends { @@ -159,9 +54,7 @@ import macrocompat.bundle // Generate a new class containing the helper methods and // object containing "Frozen" class representation - val moduleDef: ModuleDef = q"object $oName {}" match { - case m: ModuleDef => m - } + val moduleDef = M.newEmptyObject(traitTypeName.toString) processTraitAndObj(classDef, moduleDef) } @@ -178,155 +71,16 @@ import macrocompat.bundle } """ = classDef - val inheritedMethods = extractInheritedMethods( - extractParentTypes(parents.asInstanceOf[List[Tree]]).flatten + val inheritedMethods = M.extractInheritedMethods( + M.extractParentTypes(parents.asInstanceOf[List[Tree]]).flatten ) // Represents name of variable passed to freeze method - val freezeObjName = TermName("valueToFreeze") - - val freezeTrees = { - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body match { - case l: List[Tree] => l - } - val internalMethods = bodyTrees.collect { case d: DefDef => d } - - // TODO: Also process inherited methods that are not covered - // by the tree methods - // TODO: CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP - val internals = internalMethods.map { - case d: DefDef if containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss match { - case l: List[List[ValDef]] => l - } - if (paramTrees.nonEmpty) c.abort( - c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" - ) - - val name = TermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - - // TODO: Remove runtime checks by getting better understanding of - // return type, if it contains a freeze method, etc. - findAnnotation(d, "CanFreeze").get match { - case q"new CanFreeze()" => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case q"new CanFreeze($returnType)" => - // TODO: Find better way to match against the input - import org.scaladebugger.macros.freeze.CanFreeze.ReturnType - val r = ReturnType.withName(returnType.toString().split('.').last) - - r match { - case ReturnType.Normal => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeObject => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeCollection => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeOption => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeEither => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(r => r match { - case scala.util.Left(o) => scala.util.Left(o.freeze()) - case scala.util.Right(o) => scala.util.Right(o.freeze()) - }).asInstanceOf[scala.util.Try[$tpt]] - """) - } - } - - // Add override if not already there - val oldMods: Modifiers = mods match { - case m: Modifiers => m - } - - // TODO: Is there a way to filter out just the DEFERRED flag? - val newFlags = Flag.OVERRIDE | - (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) - - val newMods = c.universe.Modifiers( - flags = newFlags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || isAnnotation(a, "CannotFreeze") - }) - ) - - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = { - this.$name.get - } - """ - case d: DefDef if containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods match { - case m: Modifiers => m - } - - // TODO: Is there a way to filter out just the DEFERRED flag? - val newFlags = Flag.OVERRIDE | - (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) - - val newMods = c.universe.Modifiers( - flags = newFlags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - isAnnotation(a, "CanFreeze") || isAnnotation(a, "CannotFreeze") - }) - ) - - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = { - throw new IllegalStateException("Method not frozen!") - } - """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr match { - case t: Tree => t - } - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) - - val klass = q""" - final class Frozen(..$cParams) extends $tpname with java.io.Serializable { $self => - ..$internals - } - """ - val method = q""" - def freeze($freezeObjName: $tpname): $tpname = new Frozen(..$cArgs) - """ - List(klass, method) - } + val freezeTrees = generateTrees( + body match { case l: List[Tree] => l }, + tpname match { case t: TypeName => t } + ) // TODO: Inject freeze method directly into trait rather than // relying on object implicit @@ -352,7 +106,9 @@ import macrocompat.bundle } """ - tree match { case c: ClassDef => c } + tree match { + case c: ClassDef => c + } } val newModuleDef: ModuleDef = { @@ -364,23 +120,168 @@ import macrocompat.bundle } """ = moduleDef - val oldBody: List[Tree] = body match { - case l: List[Tree] => l - } - val newBody = oldBody ++ freezeTrees - val newObjDef = q""" - $mods object $tname extends { - ..$earlydefns - } with ..$parents { $self => - ..$newBody - } - """ + $mods object $tname extends { + ..$earlydefns + } with ..$parents { $self => + ..$body + ..$freezeTrees + } + """ newObjDef match { case m: ModuleDef => m } } List(newClassDef, newModuleDef) } + + private def generateTrees(body: List[Tree], traitTypeName: TypeName): List[Tree] = { + val freezeObjName = TermName("valueToFreeze") + val cParams = collection.mutable.ArrayBuffer[Tree]() + val cArgs = collection.mutable.ArrayBuffer[Tree]() + val bodyTrees: List[Tree] = body match { + case l: List[Tree] => l + } + val internalMethods = bodyTrees.collect { case d: DefDef => d } + + // TODO: Also process inherited methods that are not covered + // by the tree methods + // TODO: CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP + // + // See https://github.com/paulbutcher/ScalaMock/blob/master/shared/src/main/scala/org/scalamock/clazz/MockMaker.scala + // for example of loading inherited methods in method symbols not found in object + val internals = internalMethods.map { + case d: DefDef if M.containsAnnotation(d, "CanFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + val paramTrees: List[List[ValDef]] = paramss match { + case l: List[List[ValDef]] => l + } + if (paramTrees.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" + ) + + val name = TermName(s"$$$tname") + cParams.append(q""" + private val $name: scala.util.Try[$tpt] + """) + + // TODO: Remove runtime checks by getting better understanding of + // return type, if it contains a freeze method, etc. + M.findAnnotation(d, "CanFreeze").get match { + case q"new CanFreeze()" => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case q"new CanFreeze($returnType)" => + // TODO: Find better way to match against the input + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + val r = ReturnType.withName(returnType.toString().split('.').last) + + r match { + case ReturnType.Normal => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case ReturnType.FreezeObject => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case ReturnType.FreezeCollection => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case ReturnType.FreezeOption => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$tpt]] + """) + case ReturnType.FreezeEither => + cArgs.append(q""" + scala.util.Try.apply($freezeObjName.$tname).map(r => r match { + case scala.util.Left(o) => scala.util.Left(o.freeze()) + case scala.util.Right(o) => scala.util.Right(o.freeze()) + }).asInstanceOf[scala.util.Try[$tpt]] + """) + } + } + + // Add override if not already there + val oldMods: Modifiers = mods match { + case m: Modifiers => m + } + + // TODO: Is there a way to filter out just the DEFERRED flag? + val newFlags = Flag.OVERRIDE | + (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) + + val newMods = c.universe.Modifiers( + flags = newFlags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + M.isAnnotation(a, "CanFreeze") || + M.isAnnotation(a, "CannotFreeze") + }) + ) + + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = { + this.$name.get + } + """ + case d: DefDef if M.containsAnnotation(d, "CannotFreeze") => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + // Add override if not already there + val oldMods: Modifiers = mods match { + case m: Modifiers => m + } + + // TODO: Is there a way to filter out just the DEFERRED flag? + val newFlags = Flag.OVERRIDE | + (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) + + val newMods = c.universe.Modifiers( + flags = newFlags, + privateWithin = oldMods.privateWithin, + annotations = oldMods.annotations.filterNot(a => { + M.isAnnotation(a, "CanFreeze") || + M.isAnnotation(a, "CannotFreeze") + }) + ) + + q""" + $newMods def $tname[..$tparams](...$paramss): $tpt = { + throw new IllegalStateException("Method not frozen!") + } + """ + case d: DefDef => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + val exprTree: Tree = expr match { + case t: Tree => t + } + if (exprTree.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as freezable or unfreezable!" + ) + null + }.filterNot(_ == null) + + val klass = q""" + final class Frozen(..$cParams) extends $traitTypeName with java.io.Serializable { + ..$internals + } + """ + val method = q""" + def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) + """ + + List(klass, method) + } } From ac3d0001e6ec6868f920385dc05b5a9f5e0aa897 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 21:44:31 -0700 Subject: [PATCH 27/36] Removed mutable object buildup --- .../macros/freeze/FreezableMacro.scala | 236 ++++++++---------- 1 file changed, 110 insertions(+), 126 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 9792c354..e5c94f56 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -135,151 +135,135 @@ import org.scaladebugger.macros.MacroUtils List(newClassDef, newModuleDef) } + private def markModifiersOverride(modifiers: Modifiers): Modifiers = { + // TODO: Is there a way to filter out just the DEFERRED flag? + val newFlags = Flag.OVERRIDE | + (if (modifiers.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) + + c.universe.Modifiers( + flags = newFlags, + privateWithin = modifiers.privateWithin, + annotations = modifiers.annotations.filterNot(a => { + M.isAnnotation(a, "CanFreeze") || + M.isAnnotation(a, "CannotFreeze") + }) + ) + } + private def generateTrees(body: List[Tree], traitTypeName: TypeName): List[Tree] = { val freezeObjName = TermName("valueToFreeze") - val cParams = collection.mutable.ArrayBuffer[Tree]() - val cArgs = collection.mutable.ArrayBuffer[Tree]() - val bodyTrees: List[Tree] = body match { - case l: List[Tree] => l - } - val internalMethods = bodyTrees.collect { case d: DefDef => d } - // TODO: Also process inherited methods that are not covered - // by the tree methods - // TODO: CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP CHIP - // - // See https://github.com/paulbutcher/ScalaMock/blob/master/shared/src/main/scala/org/scalamock/clazz/MockMaker.scala - // for example of loading inherited methods in method symbols not found in object - val internals = internalMethods.map { - case d: DefDef if M.containsAnnotation(d, "CanFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - val paramTrees: List[List[ValDef]] = paramss match { - case l: List[List[ValDef]] => l - } - if (paramTrees.nonEmpty) c.abort( + val internalMethods = body.collect { case d: DefDef => d }.groupBy(d => { + if (M.containsAnnotation(d, "CanFreeze")) "CanFreeze" + else if (M.containsAnnotation(d, "CannotFreeze")) "CannotFreeze" + else "Other" + }) + val freezableMethods = internalMethods.getOrElse("CanFreeze", Nil) + val unfreezableMethods = internalMethods.getOrElse("CannotFreeze", Nil) + val otherMethods = internalMethods.getOrElse("Other", Nil) + + // Validate that we don't have a method left behind without an implementation + otherMethods.foreach { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + if (expr.isEmpty) c.abort( c.enclosingPosition, - s"Unable to freeze $tname! Must have zero arguments!" + s"$tname has no implementation and is not marked as freezable or unfreezable!" ) + } + // Build up constructor parameters for frozen class + val cParams = freezableMethods.map { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => val name = TermName(s"$$$tname") - cParams.append(q""" - private val $name: scala.util.Try[$tpt] - """) - - // TODO: Remove runtime checks by getting better understanding of - // return type, if it contains a freeze method, etc. - M.findAnnotation(d, "CanFreeze").get match { - case q"new CanFreeze()" => - cArgs.append(q""" + q"""private val $name: scala.util.Try[$tpt]""" + } + + // TODO: Remove runtime checks by getting better understanding of + // return type, if it contains a freeze method, etc. + // + // Build up constructor arguments for freeze method instantiating + // the frozen class + val cArgs = freezableMethods.map { d => + val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d + + M.findAnnotation(d, "CanFreeze").get match { + case q"new CanFreeze()" => + q""" + scala.util.Try.apply($freezeObjName.$tname) + .asInstanceOf[scala.util.Try[$tpt]] + """ + case q"new CanFreeze($returnType)" => + // TODO: Find better way to match against the input + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + val r = ReturnType.withName(returnType.toString().split('.').last) + + r match { + case ReturnType.Normal => + q""" scala.util.Try.apply($freezeObjName.$tname) .asInstanceOf[scala.util.Try[$tpt]] - """) - case q"new CanFreeze($returnType)" => - // TODO: Find better way to match against the input - import org.scaladebugger.macros.freeze.CanFreeze.ReturnType - val r = ReturnType.withName(returnType.toString().split('.').last) - - r match { - case ReturnType.Normal => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeObject => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeCollection => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeOption => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$tpt]] - """) - case ReturnType.FreezeEither => - cArgs.append(q""" - scala.util.Try.apply($freezeObjName.$tname).map(r => r match { - case scala.util.Left(o) => scala.util.Left(o.freeze()) - case scala.util.Right(o) => scala.util.Right(o.freeze()) - }).asInstanceOf[scala.util.Try[$tpt]] - """) - } - } + """ + case ReturnType.FreezeObject => + q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) + .asInstanceOf[scala.util.Try[$tpt]] + """ + case ReturnType.FreezeCollection => + q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$tpt]] + """ + case ReturnType.FreezeOption => + q""" + scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$tpt]] + """ + case ReturnType.FreezeEither => + q""" + scala.util.Try.apply($freezeObjName.$tname).map(r => r match { + case scala.util.Left(o) => scala.util.Left(o.freeze()) + case scala.util.Right(o) => scala.util.Right(o.freeze()) + }).asInstanceOf[scala.util.Try[$tpt]] + """ + } + } + } - // Add override if not already there - val oldMods: Modifiers = mods match { - case m: Modifiers => m - } + val newFreezableMethods = freezableMethods.map { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + val name = TermName(s"$$$tname") - // TODO: Is there a way to filter out just the DEFERRED flag? - val newFlags = Flag.OVERRIDE | - (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) - - val newMods = c.universe.Modifiers( - flags = newFlags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - M.isAnnotation(a, "CanFreeze") || - M.isAnnotation(a, "CannotFreeze") - }) + if (paramss.nonEmpty) c.abort( + c.enclosingPosition, + s"Unable to freeze $tname! Must have zero arguments!" ) - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = { - this.$name.get - } - """ - case d: DefDef if M.containsAnnotation(d, "CannotFreeze") => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - - // Add override if not already there - val oldMods: Modifiers = mods match { + val newMods: Modifiers = markModifiersOverride(mods match { case m: Modifiers => m - } + }) - // TODO: Is there a way to filter out just the DEFERRED flag? - val newFlags = Flag.OVERRIDE | - (if (oldMods.hasFlag(Flag.FINAL)) Flag.FINAL else NoFlags) - - val newMods = c.universe.Modifiers( - flags = newFlags, - privateWithin = oldMods.privateWithin, - annotations = oldMods.annotations.filterNot(a => { - M.isAnnotation(a, "CanFreeze") || - M.isAnnotation(a, "CannotFreeze") - }) - ) + q"$newMods def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + } - q""" - $newMods def $tname[..$tparams](...$paramss): $tpt = { - throw new IllegalStateException("Method not frozen!") - } - """ - case d: DefDef => - val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - val exprTree: Tree = expr match { - case t: Tree => t - } - if (exprTree.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" - ) - null - }.filterNot(_ == null) + val newUnfreezableMethods = unfreezableMethods.map { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + val newMods: Modifiers = markModifiersOverride(mods match { + case m: Modifiers => m + }) + + q"""$newMods def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!")""" + } val klass = q""" - final class Frozen(..$cParams) extends $traitTypeName with java.io.Serializable { - ..$internals - } - """ + final class Frozen(..$cParams) extends $traitTypeName with java.io.Serializable { + ..$newFreezableMethods + ..$newUnfreezableMethods + } + """ val method = q""" - def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) - """ + def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) + """ List(klass, method) } From ffcd7a91acb6fbee3bdb9390d5d7e39e620061bd Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Tue, 15 Aug 2017 22:03:00 -0700 Subject: [PATCH 28/36] More refactoring --- .../macros/freeze/FreezableMacro.scala | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index e5c94f56..4a3f12bb 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -150,6 +150,36 @@ import org.scaladebugger.macros.MacroUtils ) } + private def generateFreezeMethodBody( + r: org.scaladebugger.macros.freeze.CanFreeze.ReturnType.ReturnType, + freezeObjName: TermName, + methodName: TermName, + returnType: Tree + ): Tree = { + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + r match { + case ReturnType.Normal => + q"""scala.util.Try.apply($freezeObjName.$methodName) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeObject => + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.freeze()) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeCollection => + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeOption => + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeEither => + q""" + scala.util.Try.apply($freezeObjName.$methodName).map(r => r match { + case scala.util.Left(o) => scala.util.Left(o.freeze()) + case scala.util.Right(o) => scala.util.Right(o.freeze()) + }).asInstanceOf[scala.util.Try[$returnType]] + """ + } + } + private def generateTrees(body: List[Tree], traitTypeName: TypeName): List[Tree] = { val freezeObjName = TermName("valueToFreeze") @@ -186,47 +216,17 @@ import org.scaladebugger.macros.MacroUtils val cArgs = freezableMethods.map { d => val q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" = d - M.findAnnotation(d, "CanFreeze").get match { + // TODO: Find better way to match against the input + val r = M.findAnnotation(d, "CanFreeze").get match { case q"new CanFreeze()" => - q""" - scala.util.Try.apply($freezeObjName.$tname) - .asInstanceOf[scala.util.Try[$tpt]] - """ + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + ReturnType.Normal case q"new CanFreeze($returnType)" => - // TODO: Find better way to match against the input import org.scaladebugger.macros.freeze.CanFreeze.ReturnType - val r = ReturnType.withName(returnType.toString().split('.').last) - - r match { - case ReturnType.Normal => - q""" - scala.util.Try.apply($freezeObjName.$tname) - .asInstanceOf[scala.util.Try[$tpt]] - """ - case ReturnType.FreezeObject => - q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.freeze()) - .asInstanceOf[scala.util.Try[$tpt]] - """ - case ReturnType.FreezeCollection => - q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$tpt]] - """ - case ReturnType.FreezeOption => - q""" - scala.util.Try.apply($freezeObjName.$tname).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$tpt]] - """ - case ReturnType.FreezeEither => - q""" - scala.util.Try.apply($freezeObjName.$tname).map(r => r match { - case scala.util.Left(o) => scala.util.Left(o.freeze()) - case scala.util.Right(o) => scala.util.Right(o.freeze()) - }).asInstanceOf[scala.util.Try[$tpt]] - """ - } + ReturnType.withName(returnType.toString().split('.').last) } + + generateFreezeMethodBody(r, freezeObjName, tname, tpt) } val newFreezableMethods = freezableMethods.map { From 7a69f3bd40e0839f31ca58616bcc918dba268c08 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Wed, 16 Aug 2017 00:52:50 -0700 Subject: [PATCH 29/36] Temporary testing --- .../api/profiles/traits/info/ArrayInfo.scala | 2 +- .../profiles/traits/info/ArrayTypeInfo.scala | 2 +- .../traits/info/ClassLoaderInfo.scala | 2 +- .../traits/info/ClassObjectInfo.scala | 2 +- .../profiles/traits/info/ClassTypeInfo.scala | 2 +- .../api/profiles/traits/info/CommonInfo.scala | 2 +- .../api/profiles/traits/info/CreateInfo.scala | 2 +- .../traits/info/FieldVariableInfo.scala | 2 +- .../api/profiles/traits/info/FrameInfo.scala | 2 +- .../traits/info/IndexedVariableInfo.scala | 2 +- .../traits/info/InterfaceTypeInfo.scala | 2 +- .../api/profiles/traits/info/JavaInfo.scala | 2 +- .../profiles/traits/info/LocationInfo.scala | 2 +- .../api/profiles/traits/info/MethodInfo.scala | 2 +- .../api/profiles/traits/info/ObjectInfo.scala | 2 +- .../traits/info/PrimitiveTypeInfo.scala | 2 +- .../traits/info/ReferenceTypeInfo.scala | 2 +- .../api/profiles/traits/info/StringInfo.scala | 2 +- .../traits/info/ThreadGroupInfo.scala | 2 +- .../api/profiles/traits/info/ThreadInfo.scala | 2 +- .../traits/info/ThreadStatusInfo.scala | 2 +- .../api/profiles/traits/info/TypeInfo.scala | 2 +- .../api/profiles/traits/info/ValueInfo.scala | 2 +- .../profiles/traits/info/VariableInfo.scala | 2 +- .../org/scaladebugger/macros/MacroUtils.scala | 12 +- .../macros/freeze/FreezableMacro.scala | 181 ++++++++++++++++-- 26 files changed, 203 insertions(+), 38 deletions(-) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index 9676b9df..bd30404d 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -21,7 +21,7 @@ object ArrayInfo { /** * Represents the interface for array-based interaction. */ -@Freezable +//@Freezable trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { import scala.reflect.runtime.universe.{TypeTag, typeOf} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index f3182fe9..e03edf6c 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -@Freezable +//@Freezable trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index b8ec04dd..50d46a83 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class loader"-based interaction. */ -@Freezable +//@Freezable trait ClassLoaderInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 8e9848d3..1b941987 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class object"-based interaction. */ -@Freezable +//@Freezable trait ClassObjectInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 81764288..7b7692f6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for retrieving class type-based information. */ -@Freezable +//@Freezable trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 395c38fa..8a6bd488 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -@Freezable +//@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 8bc68919..494529de 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -8,7 +8,7 @@ import scala.util.Try * Represents the interface that needs to be implemented to provide * ability to create data using a specific debug profile. */ -@Freezable +//@Freezable trait CreateInfo { /** * Creates the provided value on the remote JVM. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index 94441dad..b73de387 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -11,7 +11,7 @@ import scala.util.Try * Represents the interface for variable-based interaction with field-specific * information. */ -@Freezable +//@Freezable trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 1c9928cd..4d532a5a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for frame-based interaction. */ -@Freezable +//@Freezable trait FrameInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index 99b62489..f2593185 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents the interface for variable-based interaction with indexed * location information. */ -@Freezable +//@Freezable trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index 2b7ff13e..cc5afea9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -@Freezable +//@Freezable trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index 8263df20..3f377e40 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -@Freezable +//@Freezable trait JavaInfo { /** * Returns whether or not this info profile represents the low-level Java diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index 188c91eb..c83fd2c3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for location-based interaction. */ -@Freezable +//@Freezable trait LocationInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index e7d24563..1ad3ad7f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for method-based interaction. */ -@Freezable +//@Freezable trait MethodInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index a6d11395..f60e9a3e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for object-based interaction. */ -@Freezable +//@Freezable trait ObjectInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala index e22bbb32..0c07c8b0 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for retrieving primitive type-based information. */ -@Freezable +//@Freezable trait PrimitiveTypeInfo extends TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 3c14a96e..4916841f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for "reference type"-based interaction. */ -@Freezable +//@Freezable trait ReferenceTypeInfo extends CommonInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index b4657a4a..499a30aa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for string-based interaction. */ -@Freezable +//@Freezable trait StringInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index b5762dc6..746d5b1b 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for thread-based interaction. */ -@Freezable +//@Freezable trait ThreadGroupInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index cdadfaec..50576856 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for thread-based interaction. */ -@Freezable +//@Freezable trait ThreadInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index cedb0e1f..cef33537 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} /** * Represents information about a thread's status. */ -@Freezable +//@Freezable trait ThreadStatusInfo { /** * Represents the status code for the thread. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index d988f003..9aed96c0 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving type-based information. */ -@Freezable +//@Freezable trait TypeInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index a2f28192..a731397e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents information about a value. */ -@Freezable +//@Freezable trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 67419f38..1950709f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for variable-based interaction. */ -@Freezable +//@Freezable trait VariableInfo extends CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index 1154d81e..62ba6a7b 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -100,15 +100,23 @@ import macrocompat.bundle baseTypeNames.contains(name) } + // NOTE: CHIP CHIP CHIP CHIP CHIP + // Changed withMacrosDisabled = true for testing parent match { case Ident(name) if !isBaseType(name) => val typeName = name.toTypeName - val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$typeName]")) + val typedTree = scala.util.Try(c.typecheck( + q"null.asInstanceOf[$typeName]", + withMacrosDisabled = true + )) typedTree.toOption.flatMap(tt => Option(tt.tpe)) case Select(Ident(name), typeName) if !isBaseType(name, typeName) => val t1 = name.toTermName val t2 = typeName.toTypeName - val typedTree = scala.util.Try(c.typecheck(q"null.asInstanceOf[$t1.$t2]")) + val typedTree = scala.util.Try(c.typecheck( + q"null.asInstanceOf[$t1.$t2]", + withMacrosDisabled = true + )) typedTree.toOption.flatMap(tt => Option(tt.tpe)) case a => None diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 4a3f12bb..d7ae2552 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -13,16 +13,21 @@ import org.scaladebugger.macros.MacroUtils // NOTE: Stuck with c.Expr[Any] instead of c.Tree for now; // blows up in Scala 2.10 even with @bundle otherwise def impl(annottees: c.Expr[Any]*): c.Expr[Any] = { + val id = java.util.UUID.randomUUID().toString val (annottee, expandees) = annottees.map(_.tree) match { case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if M.isTrait(classDef) => + println("PROCESSING -- " + classDef.name.decodedName.toString + " -- " + id) //println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) val results = processTraitAndObj(classDef, moduleDef) //println("RESULTS :: " + results) + println("DONE -- " + id) (EmptyTree, results) case (classDef: ClassDef) :: Nil if M.isTrait(classDef) => + println("PROCESSING -- " + classDef.name.decodedName.toString + " -- " + id) //println("INPUT CLASS ONLY :: " + classDef) val results = processTrait(classDef) - //println("RESULTS :: " + results) + println("RESULTS :: " + results) + println("DONE -- " + id) (EmptyTree, results) case _ => c.abort( @@ -50,7 +55,6 @@ import org.scaladebugger.macros.MacroUtils val traitTypeName: TypeName = tpname match { case t: TypeName => t } - val oName = TermName(traitTypeName.toString) // Generate a new class containing the helper methods and // object containing "Frozen" class representation @@ -79,7 +83,8 @@ import org.scaladebugger.macros.MacroUtils val freezeTrees = generateTrees( body match { case l: List[Tree] => l }, - tpname match { case t: TypeName => t } + tpname match { case t: TypeName => t }, + inheritedMethods ) // TODO: Inject freeze method directly into trait rather than @@ -180,24 +185,85 @@ import org.scaladebugger.macros.MacroUtils } } - private def generateTrees(body: List[Tree], traitTypeName: TypeName): List[Tree] = { + private def generateFreezeMethodBody( + r: org.scaladebugger.macros.freeze.CanFreeze.ReturnType.ReturnType, + freezeObjName: TermName, + methodName: TermName, + returnType: TypeName + ): Tree = { + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + r match { + case ReturnType.Normal => + q"""scala.util.Try.apply($freezeObjName.$methodName) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeObject => + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.freeze()) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeCollection => + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeOption => + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) + .asInstanceOf[scala.util.Try[$returnType]]""" + case ReturnType.FreezeEither => + q""" + scala.util.Try.apply($freezeObjName.$methodName).map(r => r match { + case scala.util.Left(o) => scala.util.Left(o.freeze()) + case scala.util.Right(o) => scala.util.Right(o.freeze()) + }).asInstanceOf[scala.util.Try[$returnType]] + """ + } + } + + private def generateTrees( + body: List[Tree], + traitTypeName: TypeName, + inheritedMethods: List[MethodSymbol] + ): List[Tree] = { val freezeObjName = TermName("valueToFreeze") - val internalMethods = body.collect { case d: DefDef => d }.groupBy(d => { + val internalMethodTrees = body.collect { case d: DefDef => d } + val internalGroups = internalMethodTrees.groupBy(d => { if (M.containsAnnotation(d, "CanFreeze")) "CanFreeze" else if (M.containsAnnotation(d, "CannotFreeze")) "CannotFreeze" else "Other" }) - val freezableMethods = internalMethods.getOrElse("CanFreeze", Nil) - val unfreezableMethods = internalMethods.getOrElse("CannotFreeze", Nil) - val otherMethods = internalMethods.getOrElse("Other", Nil) + val freezableMethods = internalGroups.getOrElse("CanFreeze", Nil) + val unfreezableMethods = internalGroups.getOrElse("CannotFreeze", Nil) + val otherMethods = internalGroups.getOrElse("Other", Nil) + + // TODO: Figure out why multiple of method symbol show up here, + // resulting in us using distinct + val filteredInheritedMethods = inheritedMethods.distinct.filterNot(m => { + internalMethodTrees.exists(t => + t.name.decodedName.toString == m.name.decodedName.toString && + t.vparamss.size == m.paramLists.size && + t.vparamss.zip(m.paramLists).forall { case (valDefList, paramList) => + valDefList.size == paramList.size && + valDefList.zip(paramList).forall { case (valDef, param) => + // TODO: Verify this actually works -- can we encounter + // a scenario where tpt is not the full name? + valDef.tpt.toString() == param.typeSignature.toString + } + } + ) + }) + val inheritedGroups = filteredInheritedMethods.groupBy(m => { + val a = m.annotations + if (a.exists(_.tree.tpe =:= typeOf[CanFreeze])) "CanFreeze" + else if (a.exists(_.tree.tpe =:= typeOf[CannotFreeze])) "CannotFreeze" + else "Other" + }) + val iFreezableMethods = inheritedGroups.getOrElse("CanFreeze", Nil) + val iUnfreezableMethods = inheritedGroups.getOrElse("CannotFreeze", Nil) + val iOtherMethods = inheritedGroups.getOrElse("Other", Nil) // Validate that we don't have a method left behind without an implementation otherMethods.foreach { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => if (expr.isEmpty) c.abort( c.enclosingPosition, - s"$tname has no implementation and is not marked as freezable or unfreezable!" + s"$tname has no implementation and is not marked as @CanFreeze or @CannotFreeze!" ) } @@ -205,8 +271,22 @@ import org.scaladebugger.macros.MacroUtils val cParams = freezableMethods.map { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => val name = TermName(s"$$$tname") - q"""private val $name: scala.util.Try[$tpt]""" - } + q"private val $name: scala.util.Try[$tpt]" + } ++ iFreezableMethods.map(m => { + val name = TermName(s"$$${m.name.decodedName.toString}") + + // TODO: This is a hack to get around appearing when method + // returns type of trait we are currently inspecting + val tpt = + if (m.returnType.toString == "") traitTypeName + else TypeName(m.returnType.toString) + + println("GENERATING CPARAM FOR " + m.name + " OF " + m.owner.name) + val t = q"private val $name: scala.util.Try[$tpt]" + println("RESULT = " + t) + t + }) + println("CPARAMS :: " + cParams.mkString("\n")) // TODO: Remove runtime checks by getting better understanding of // return type, if it contains a freeze method, etc. @@ -227,7 +307,31 @@ import org.scaladebugger.macros.MacroUtils } generateFreezeMethodBody(r, freezeObjName, tname, tpt) - } + } ++ iFreezableMethods.map(m => { + val tname = TermName(m.name.decodedName.toString) + + // TODO: This is a hack to get around appearing when method + // returns type of trait we are currently inspecting + val tpt = + if (m.returnType.toString == "") traitTypeName + else TypeName(m.returnType.toString) + + val a = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) + if (a.isEmpty) c.abort( + c.enclosingPosition, + s"Invalid state while processing inherited method ${m.name}" + ) + + // TODO: Figure out better way to handle this than some random hack + import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + val fullArgs = a.get.tree.children.map(_.toString()) + val r = scala.util.Try( + ReturnType.withName(fullArgs.last.split('.').last) + ).getOrElse(ReturnType.Normal) + + //println("GENERATING CARG FOR " + m.name + " OF " + m.owner.name) + generateFreezeMethodBody(r, freezeObjName, tname, tpt) + }) val newFreezableMethods = freezableMethods.map { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => @@ -255,12 +359,65 @@ import org.scaladebugger.macros.MacroUtils throw new IllegalStateException("Method not frozen!")""" } + // Filter out inherited methods that have been overidden in current trait + val newInheritedMethods = filteredInheritedMethods.flatMap(m => { + val methodName = m.name.decodedName.toString + val mods = m.annotations.map(_.tree) + val tname = TermName(methodName) + val tparams = m.typeParams.map(tp => TypeName(tp.fullName)) + val paramss = m.paramLists.map(_.map(p => { + val name = TermName(p.name.decodedName.toString) + val typeName = TypeName(p.typeSignature.toString) + + // TODO: Support default values? + // TODO: Support annotations? + q"val $name: $typeName" + })) + + // TODO: This is a hack to get around appearing when method + // returns type of trait we are currently inspecting + val tpt = + if (m.returnType.toString == "") traitTypeName + else TypeName(m.returnType.toString) + + val aFreezable = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) + val aUnfreezable = m.annotations.find(_.tree.tpe =:= typeOf[CannotFreeze]) + + val hasAnnotation = aFreezable.nonEmpty || aUnfreezable.nonEmpty + if (hasAnnotation && m.isFinal) c.abort( + c.enclosingPosition, + s"Inherited $methodName is marked as final and cannot be overridden!" + ) + if (!hasAnnotation && m.isAbstract) c.abort( + c.enclosingPosition, + Seq( + s"Inherited $methodName has no implementation and", + "is not marked as @CanFreeze or @CannotFreeze!" + ).mkString(" ") + ) + + val methodTree = if (aFreezable.nonEmpty) { + val name = TermName(s"$$$tname") + q"override def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + } else if (aUnfreezable.nonEmpty) { + q"""override def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!")""" + } else { + null + } + + //println("GENERATING METHOD FOR " + m.name + " OF " + m.owner.name) + Option(methodTree) + }) + val klass = q""" final class Frozen(..$cParams) extends $traitTypeName with java.io.Serializable { ..$newFreezableMethods ..$newUnfreezableMethods + ..$newInheritedMethods } """ + val method = q""" def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) """ From fe8afe36eeadbd81d31671920c015021863911da Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Wed, 16 Aug 2017 23:14:42 -0700 Subject: [PATCH 30/36] Still trying to get to work, using inheritance --- .../api/profiles/traits/info/ArrayInfo.scala | 2 +- .../profiles/traits/info/ArrayTypeInfo.scala | 2 +- .../traits/info/ClassLoaderInfo.scala | 2 +- .../traits/info/ClassObjectInfo.scala | 2 +- .../profiles/traits/info/ClassTypeInfo.scala | 2 +- .../api/profiles/traits/info/CommonInfo.scala | 2 +- .../api/profiles/traits/info/CreateInfo.scala | 2 +- .../traits/info/FieldVariableInfo.scala | 2 +- .../api/profiles/traits/info/FrameInfo.scala | 2 +- .../traits/info/IndexedVariableInfo.scala | 2 +- .../traits/info/InterfaceTypeInfo.scala | 2 +- .../api/profiles/traits/info/JavaInfo.scala | 4 +- .../profiles/traits/info/LocationInfo.scala | 2 +- .../api/profiles/traits/info/MethodInfo.scala | 2 +- .../api/profiles/traits/info/ObjectInfo.scala | 2 +- .../traits/info/PrimitiveTypeInfo.scala | 2 +- .../traits/info/ReferenceTypeInfo.scala | 2 +- .../api/profiles/traits/info/StringInfo.scala | 2 +- .../traits/info/ThreadGroupInfo.scala | 2 +- .../api/profiles/traits/info/ThreadInfo.scala | 2 +- .../traits/info/ThreadStatusInfo.scala | 2 +- .../api/profiles/traits/info/TypeInfo.scala | 2 +- .../api/profiles/traits/info/ValueInfo.scala | 2 +- .../profiles/traits/info/VariableInfo.scala | 2 +- .../org/scaladebugger/macros/MacroUtils.scala | 37 +++-- .../macros/freeze/FreezableMacro.scala | 146 +++++++----------- 26 files changed, 103 insertions(+), 130 deletions(-) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index bd30404d..9676b9df 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -21,7 +21,7 @@ object ArrayInfo { /** * Represents the interface for array-based interaction. */ -//@Freezable +@Freezable trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { import scala.reflect.runtime.universe.{TypeTag, typeOf} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index e03edf6c..f3182fe9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -//@Freezable +@Freezable trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index 50d46a83..b8ec04dd 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class loader"-based interaction. */ -//@Freezable +@Freezable trait ClassLoaderInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 1b941987..8e9848d3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class object"-based interaction. */ -//@Freezable +@Freezable trait ClassObjectInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 7b7692f6..81764288 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for retrieving class type-based information. */ -//@Freezable +@Freezable trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 8a6bd488..395c38fa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -//@Freezable +@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 494529de..8bc68919 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -8,7 +8,7 @@ import scala.util.Try * Represents the interface that needs to be implemented to provide * ability to create data using a specific debug profile. */ -//@Freezable +@Freezable trait CreateInfo { /** * Creates the provided value on the remote JVM. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index b73de387..94441dad 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -11,7 +11,7 @@ import scala.util.Try * Represents the interface for variable-based interaction with field-specific * information. */ -//@Freezable +@Freezable trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 4d532a5a..1c9928cd 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for frame-based interaction. */ -//@Freezable +@Freezable trait FrameInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index f2593185..99b62489 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents the interface for variable-based interaction with indexed * location information. */ -//@Freezable +@Freezable trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index cc5afea9..2b7ff13e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -//@Freezable +@Freezable trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index 3f377e40..44947979 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -6,8 +6,8 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -//@Freezable -trait JavaInfo { +@Freezable +trait JavaInfo extends java.io.Serializable { /** * Returns whether or not this info profile represents the low-level Java * implementation. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index c83fd2c3..188c91eb 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for location-based interaction. */ -//@Freezable +@Freezable trait LocationInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index 1ad3ad7f..e7d24563 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for method-based interaction. */ -//@Freezable +@Freezable trait MethodInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index f60e9a3e..a6d11395 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for object-based interaction. */ -//@Freezable +@Freezable trait ObjectInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala index 0c07c8b0..e22bbb32 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for retrieving primitive type-based information. */ -//@Freezable +@Freezable trait PrimitiveTypeInfo extends TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 4916841f..3c14a96e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for "reference type"-based interaction. */ -//@Freezable +@Freezable trait ReferenceTypeInfo extends CommonInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index 499a30aa..b4657a4a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for string-based interaction. */ -//@Freezable +@Freezable trait StringInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index 746d5b1b..b5762dc6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for thread-based interaction. */ -//@Freezable +@Freezable trait ThreadGroupInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index 50576856..cdadfaec 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for thread-based interaction. */ -//@Freezable +@Freezable trait ThreadInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index cef33537..cedb0e1f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} /** * Represents information about a thread's status. */ -//@Freezable +@Freezable trait ThreadStatusInfo { /** * Represents the status code for the thread. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index 9aed96c0..d988f003 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving type-based information. */ -//@Freezable +@Freezable trait TypeInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index a731397e..a2f28192 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents information about a value. */ -//@Freezable +@Freezable trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 1950709f..67419f38 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for variable-based interaction. */ -//@Freezable +@Freezable trait VariableInfo extends CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index 62ba6a7b..d937957d 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -62,8 +62,8 @@ import macrocompat.bundle .flatMap(t => { t.baseClasses.filterNot(c => c == t.typeSymbol || - c == anyTypeSymbol || - c == objectTypeSymbol + c == anyTypeSymbol || + c == objectTypeSymbol ) }) .filter(_.isClass) @@ -75,16 +75,18 @@ import macrocompat.bundle else allMethods } - extract(parents, Nil) + // TODO: Getting paramLists and materializing seems to trigger the + // appearance of our static annotations; figure out why and fix + extract(parents, Nil).map(m => { + m.paramLists.toString + m + }) } - def extractParentTypes(parents: List[Tree]): List[Option[Type]] = { - parents match { - case p: List[Tree] => p.map(extractParentType) - } - } + def extractTypes(trees: List[Tree]): List[Option[Type]] = + trees.map(extractType) - private def extractParentType(parent: Tree): Option[Type] = { + def extractType(tree: Tree): Option[Type] = { def isBaseType(n1: Name, n2: Name = null): Boolean = { val name = if (n2 != null) { n1.toString + "." + n2.toString @@ -100,9 +102,7 @@ import macrocompat.bundle baseTypeNames.contains(name) } - // NOTE: CHIP CHIP CHIP CHIP CHIP - // Changed withMacrosDisabled = true for testing - parent match { + tree match { case Ident(name) if !isBaseType(name) => val typeName = name.toTypeName val typedTree = scala.util.Try(c.typecheck( @@ -130,4 +130,17 @@ import macrocompat.bundle } moduleDef } + + def fqcnToTree(fqcn: String): Tree = { + val tokens = fqcn.split('.') + val packageName = tokens.take(tokens.length - 1) + val className = tokens.last + + val pTermNames = packageName.map(TermName.apply) + val pRef = pTermNames.tail.foldLeft(Ident(pTermNames.head): RefTree) { + case (s, n) => Select(s, n) + } + val cTypeName = TypeName(className) + Select(pRef, cTypeName) + } } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index d7ae2552..f5f241ba 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -26,7 +26,9 @@ import org.scaladebugger.macros.MacroUtils println("PROCESSING -- " + classDef.name.decodedName.toString + " -- " + id) //println("INPUT CLASS ONLY :: " + classDef) val results = processTrait(classDef) - println("RESULTS :: " + results) + //println("RESULTS :: " + results) + if (classDef.name.decodedName.toString == "ValueInfo") + println("RESULTS :: " + results) println("DONE -- " + id) (EmptyTree, results) case _ => @@ -75,15 +77,13 @@ import org.scaladebugger.macros.MacroUtils } """ = classDef - val inheritedMethods = M.extractInheritedMethods( - M.extractParentTypes(parents.asInstanceOf[List[Tree]]).flatten - ) - - // Represents name of variable passed to freeze method + val parentTypes = M.extractTypes(parents.asInstanceOf[List[Tree]]).flatten + val inheritedMethods = M.extractInheritedMethods(parentTypes) val freezeTrees = generateTrees( body match { case l: List[Tree] => l }, tpname match { case t: TypeName => t }, + parentTypes, inheritedMethods ) @@ -218,6 +218,7 @@ import org.scaladebugger.macros.MacroUtils private def generateTrees( body: List[Tree], traitTypeName: TypeName, + parentTypes: List[Type], inheritedMethods: List[MethodSymbol] ): List[Tree] = { val freezeObjName = TermName("valueToFreeze") @@ -232,32 +233,6 @@ import org.scaladebugger.macros.MacroUtils val unfreezableMethods = internalGroups.getOrElse("CannotFreeze", Nil) val otherMethods = internalGroups.getOrElse("Other", Nil) - // TODO: Figure out why multiple of method symbol show up here, - // resulting in us using distinct - val filteredInheritedMethods = inheritedMethods.distinct.filterNot(m => { - internalMethodTrees.exists(t => - t.name.decodedName.toString == m.name.decodedName.toString && - t.vparamss.size == m.paramLists.size && - t.vparamss.zip(m.paramLists).forall { case (valDefList, paramList) => - valDefList.size == paramList.size && - valDefList.zip(paramList).forall { case (valDef, param) => - // TODO: Verify this actually works -- can we encounter - // a scenario where tpt is not the full name? - valDef.tpt.toString() == param.typeSignature.toString - } - } - ) - }) - val inheritedGroups = filteredInheritedMethods.groupBy(m => { - val a = m.annotations - if (a.exists(_.tree.tpe =:= typeOf[CanFreeze])) "CanFreeze" - else if (a.exists(_.tree.tpe =:= typeOf[CannotFreeze])) "CannotFreeze" - else "Other" - }) - val iFreezableMethods = inheritedGroups.getOrElse("CanFreeze", Nil) - val iUnfreezableMethods = inheritedGroups.getOrElse("CannotFreeze", Nil) - val iOtherMethods = inheritedGroups.getOrElse("Other", Nil) - // Validate that we don't have a method left behind without an implementation otherMethods.foreach { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => @@ -267,11 +242,31 @@ import org.scaladebugger.macros.MacroUtils ) } + // TODO: Figure out why multiple of method symbol show up here, + // resulting in us using distinct + val filteredInheritedMethods = inheritedMethods.distinct.filterNot(m => { + internalMethodTrees.exists(t => + t.name.decodedName.toString == m.name.decodedName.toString && + t.vparamss.size == m.paramLists.size && + t.vparamss.zip(m.paramLists).forall { case (valDefList, paramList) => + valDefList.size == paramList.size && + valDefList.zip(paramList).forall { case (valDef, param) => + // TODO: Verify this actually works -- can we encounter + // a scenario where tpt is not the full name? + valDef.tpt.toString() == param.typeSignature.toString + } + } + ) + }) + val iFreezableMethods = filteredInheritedMethods.filter( + _.annotations.exists(_.tree.tpe =:= typeOf[CanFreeze]) + ) + // Build up constructor parameters for frozen class val cParams = freezableMethods.map { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => val name = TermName(s"$$$tname") - q"private val $name: scala.util.Try[$tpt]" + q"protected val $name: scala.util.Try[$tpt]" } ++ iFreezableMethods.map(m => { val name = TermName(s"$$${m.name.decodedName.toString}") @@ -281,12 +276,8 @@ import org.scaladebugger.macros.MacroUtils if (m.returnType.toString == "") traitTypeName else TypeName(m.returnType.toString) - println("GENERATING CPARAM FOR " + m.name + " OF " + m.owner.name) - val t = q"private val $name: scala.util.Try[$tpt]" - println("RESULT = " + t) - t + q"protected val $name: scala.util.Try[$tpt]" }) - println("CPARAMS :: " + cParams.mkString("\n")) // TODO: Remove runtime checks by getting better understanding of // return type, if it contains a freeze method, etc. @@ -329,7 +320,6 @@ import org.scaladebugger.macros.MacroUtils ReturnType.withName(fullArgs.last.split('.').last) ).getOrElse(ReturnType.Normal) - //println("GENERATING CARG FOR " + m.name + " OF " + m.owner.name) generateFreezeMethodBody(r, freezeObjName, tname, tpt) }) @@ -359,70 +349,40 @@ import org.scaladebugger.macros.MacroUtils throw new IllegalStateException("Method not frozen!")""" } - // Filter out inherited methods that have been overidden in current trait - val newInheritedMethods = filteredInheritedMethods.flatMap(m => { - val methodName = m.name.decodedName.toString - val mods = m.annotations.map(_.tree) - val tname = TermName(methodName) - val tparams = m.typeParams.map(tp => TypeName(tp.fullName)) - val paramss = m.paramLists.map(_.map(p => { - val name = TermName(p.name.decodedName.toString) - val typeName = TypeName(p.typeSignature.toString) - - // TODO: Support default values? - // TODO: Support annotations? - q"val $name: $typeName" - })) - - // TODO: This is a hack to get around appearing when method - // returns type of trait we are currently inspecting - val tpt = - if (m.returnType.toString == "") traitTypeName - else TypeName(m.returnType.toString) - - val aFreezable = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) - val aUnfreezable = m.annotations.find(_.tree.tpe =:= typeOf[CannotFreeze]) - - val hasAnnotation = aFreezable.nonEmpty || aUnfreezable.nonEmpty - if (hasAnnotation && m.isFinal) c.abort( - c.enclosingPosition, - s"Inherited $methodName is marked as final and cannot be overridden!" - ) - if (!hasAnnotation && m.isAbstract) c.abort( - c.enclosingPosition, - Seq( - s"Inherited $methodName has no implementation and", - "is not marked as @CanFreeze or @CannotFreeze!" - ).mkString(" ") - ) - - val methodTree = if (aFreezable.nonEmpty) { - val name = TermName(s"$$$tname") - q"override def $tname[..$tparams](...$paramss): $tpt = this.$name.get" - } else if (aUnfreezable.nonEmpty) { - q"""override def $tname[..$tparams](...$paramss): $tpt = - throw new IllegalStateException("Method not frozen!")""" - } else { - null - } + val frozenParents = parentTypes.map(t => + M.fqcnToTree(t.typeSymbol.fullName + ".Frozen") + ) - //println("GENERATING METHOD FOR " + m.name + " OF " + m.owner.name) - Option(methodTree) - }) + val parents = frozenParents ++ List( + typeOf[java.io.Serializable] + ).map(t => TypeTree(t)) - val klass = q""" - final class Frozen(..$cParams) extends $traitTypeName with java.io.Serializable { + val interface = q""" + trait Frozen extends $traitTypeName with ..$parents { + ..$cParams ..$newFreezableMethods ..$newUnfreezableMethods - ..$newInheritedMethods } """ + val klass = q""" + final class FrozenImpl(..$cParams) extends Frozen + """ + val method = q""" - def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) + def freeze($freezeObjName: $traitTypeName): $traitTypeName = new FrozenImpl(..$cArgs) """ - List(klass, method) + object Q { + object Y + type T = Test + class Test extends scala.AnyRef + trait Pants + } + val x: Q.Test = null + val y: Q.Pants = null + + List(interface, klass, method) } } From a94654f727c7b720b8ca8742b5494e5f3c287232 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Wed, 16 Aug 2017 23:30:44 -0700 Subject: [PATCH 31/36] Updated back to full method generation approach --- .../org/scaladebugger/macros/MacroUtils.scala | 17 +++-- .../macros/freeze/FreezableMacro.scala | 68 ++++++++++++++++--- 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index d937957d..15d68607 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -131,16 +131,21 @@ import macrocompat.bundle moduleDef } - def fqcnToTree(fqcn: String): Tree = { + def classNameToTree(fqcn: String): Tree = { val tokens = fqcn.split('.') + val packageName = tokens.take(tokens.length - 1) + val pTermNames = packageName.map(TermName.apply) + val className = tokens.last + val cTypeName = TypeName(className) - val pTermNames = packageName.map(TermName.apply) - val pRef = pTermNames.tail.foldLeft(Ident(pTermNames.head): RefTree) { - case (s, n) => Select(s, n) + if (tokens.length <= 1) Ident(cTypeName) + else { + val pRef = pTermNames.tail.foldLeft(Ident(pTermNames.head): RefTree) { + case (s, n) => Select(s, n) + } + Select(pRef, cTypeName) } - val cTypeName = TypeName(className) - Select(pRef, cTypeName) } } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index f5f241ba..3cec90ac 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -349,28 +349,76 @@ import org.scaladebugger.macros.MacroUtils throw new IllegalStateException("Method not frozen!")""" } + val newInheritedMethods = filteredInheritedMethods.flatMap(m => { + val methodName = m.name.decodedName.toString + val mods = m.annotations.map(_.tree) + val tname = TermName(methodName) + val tparams = m.typeParams.map(tp => TypeName(tp.fullName)) + val paramss = m.paramLists.map(_.map(p => { + val name = TermName(p.name.decodedName.toString) + val typeName = TypeName(p.typeSignature.toString) + + // TODO: Support default values? + // TODO: Support annotations? + q"val $name: $typeName" + })) + + // TODO: This is a hack to get around appearing when method + // returns type of trait we are currently inspecting + val tpt = + if (m.returnType.toString == "") + M.classNameToTree(traitTypeName.decodedName.toString) + else + M.classNameToTree(m.returnType.toString) + + val aFreezable = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) + val aUnfreezable = m.annotations.find(_.tree.tpe =:= typeOf[CannotFreeze]) + + val hasAnnotation = aFreezable.nonEmpty || aUnfreezable.nonEmpty + if (hasAnnotation && m.isFinal) c.abort( + c.enclosingPosition, + s"Inherited $methodName is marked as final and cannot be overridden!" + ) + if (!hasAnnotation && m.isAbstract) c.abort( + c.enclosingPosition, + Seq( + s"Inherited $methodName has no implementation and", + "is not marked as @CanFreeze or @CannotFreeze!" + ).mkString(" ") + ) + + val methodTree = if (aFreezable.nonEmpty) { + val name = TermName(s"$$$tname") + q"override def $tname[..$tparams](...$paramss): $tpt = this.$name.get" + } else if (aUnfreezable.nonEmpty) { + q"""override def $tname[..$tparams](...$paramss): $tpt = + throw new IllegalStateException("Method not frozen!")""" + } else { + null + } + + //println("GENERATING METHOD FOR " + m.name + " OF " + m.owner.name) + Option(methodTree) + }) + val frozenParents = parentTypes.map(t => - M.fqcnToTree(t.typeSymbol.fullName + ".Frozen") + M.classNameToTree(t.typeSymbol.fullName + ".Frozen") ) val parents = frozenParents ++ List( typeOf[java.io.Serializable] ).map(t => TypeTree(t)) - val interface = q""" - trait Frozen extends $traitTypeName with ..$parents { - ..$cParams + val klass = q""" + final class Frozen private[$traitTypeName](..$cParams) extends $traitTypeName { ..$newFreezableMethods ..$newUnfreezableMethods + ..$newInheritedMethods } """ - val klass = q""" - final class FrozenImpl(..$cParams) extends Frozen - """ - val method = q""" - def freeze($freezeObjName: $traitTypeName): $traitTypeName = new FrozenImpl(..$cArgs) + def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) """ object Q { @@ -382,7 +430,7 @@ import org.scaladebugger.macros.MacroUtils val x: Q.Test = null val y: Q.Pants = null - List(interface, klass, method) + List(klass, method) } } From d91bb049f9971d3f9b4528fdbbfd577877819aa7 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Thu, 17 Aug 2017 00:24:02 -0700 Subject: [PATCH 32/36] Still working on it --- .../api/profiles/traits/info/ArrayInfo.scala | 2 +- .../profiles/traits/info/ArrayTypeInfo.scala | 2 +- .../traits/info/ClassLoaderInfo.scala | 2 +- .../traits/info/ClassObjectInfo.scala | 2 +- .../profiles/traits/info/ClassTypeInfo.scala | 2 +- .../api/profiles/traits/info/CommonInfo.scala | 2 +- .../api/profiles/traits/info/CreateInfo.scala | 2 +- .../traits/info/FieldVariableInfo.scala | 2 +- .../api/profiles/traits/info/FrameInfo.scala | 2 +- .../traits/info/IndexedVariableInfo.scala | 2 +- .../traits/info/InterfaceTypeInfo.scala | 2 +- .../api/profiles/traits/info/JavaInfo.scala | 2 +- .../profiles/traits/info/LocationInfo.scala | 2 +- .../api/profiles/traits/info/MethodInfo.scala | 2 +- .../api/profiles/traits/info/ObjectInfo.scala | 2 +- .../profiles/traits/info/PrimitiveInfo.scala | 2 +- .../traits/info/ReferenceTypeInfo.scala | 2 +- .../api/profiles/traits/info/StringInfo.scala | 2 +- .../traits/info/ThreadGroupInfo.scala | 2 +- .../api/profiles/traits/info/ThreadInfo.scala | 2 +- .../traits/info/ThreadStatusInfo.scala | 2 +- .../profiles/traits/info/VariableInfo.scala | 2 +- .../org/scaladebugger/macros/MacroUtils.scala | 4 +- .../macros/freeze/FreezableMacro.scala | 120 +++++++----------- 24 files changed, 73 insertions(+), 95 deletions(-) diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index 9676b9df..bd30404d 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -21,7 +21,7 @@ object ArrayInfo { /** * Represents the interface for array-based interaction. */ -@Freezable +//@Freezable trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { import scala.reflect.runtime.universe.{TypeTag, typeOf} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index f3182fe9..e03edf6c 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -@Freezable +//@Freezable trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index b8ec04dd..50d46a83 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class loader"-based interaction. */ -@Freezable +//@Freezable trait ClassLoaderInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 8e9848d3..1b941987 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class object"-based interaction. */ -@Freezable +//@Freezable trait ClassObjectInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 81764288..7b7692f6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for retrieving class type-based information. */ -@Freezable +//@Freezable trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 395c38fa..8a6bd488 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -@Freezable +//@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 8bc68919..494529de 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -8,7 +8,7 @@ import scala.util.Try * Represents the interface that needs to be implemented to provide * ability to create data using a specific debug profile. */ -@Freezable +//@Freezable trait CreateInfo { /** * Creates the provided value on the remote JVM. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index 94441dad..b73de387 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -11,7 +11,7 @@ import scala.util.Try * Represents the interface for variable-based interaction with field-specific * information. */ -@Freezable +//@Freezable trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 1c9928cd..4d532a5a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for frame-based interaction. */ -@Freezable +//@Freezable trait FrameInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index 99b62489..f2593185 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents the interface for variable-based interaction with indexed * location information. */ -@Freezable +//@Freezable trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index 2b7ff13e..cc5afea9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -@Freezable +//@Freezable trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index 44947979..6ed12a82 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -@Freezable +//@Freezable trait JavaInfo extends java.io.Serializable { /** * Returns whether or not this info profile represents the low-level Java diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index 188c91eb..c83fd2c3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for location-based interaction. */ -@Freezable +//@Freezable trait LocationInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index e7d24563..1ad3ad7f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for method-based interaction. */ -@Freezable +//@Freezable trait MethodInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index a6d11395..f60e9a3e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for object-based interaction. */ -@Freezable +//@Freezable trait ObjectInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala index 7f02b8ec..cdddccaa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala @@ -10,7 +10,7 @@ import scala.util.{Failure, Success, Try} /** * Represents information about a primitive value. */ -@Freezable +//@Freezable trait PrimitiveInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 3c14a96e..4916841f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for "reference type"-based interaction. */ -@Freezable +//@Freezable trait ReferenceTypeInfo extends CommonInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index b4657a4a..499a30aa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for string-based interaction. */ -@Freezable +//@Freezable trait StringInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index b5762dc6..746d5b1b 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for thread-based interaction. */ -@Freezable +//@Freezable trait ThreadGroupInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index cdadfaec..50576856 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for thread-based interaction. */ -@Freezable +//@Freezable trait ThreadInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index cedb0e1f..cef33537 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} /** * Represents information about a thread's status. */ -@Freezable +//@Freezable trait ThreadStatusInfo { /** * Represents the status code for the thread. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 67419f38..1950709f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for variable-based interaction. */ -@Freezable +//@Freezable trait VariableInfo extends CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index 15d68607..040faf21 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -132,9 +132,9 @@ import macrocompat.bundle } def classNameToTree(fqcn: String): Tree = { - val tokens = fqcn.split('.') + val tokens = fqcn.split('.').filter(_.nonEmpty) - val packageName = tokens.take(tokens.length - 1) + val packageName = tokens.take(tokens.length - 1).toList val pTermNames = packageName.map(TermName.apply) val className = tokens.last diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 3cec90ac..93315751 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -8,6 +8,9 @@ import org.scaladebugger.macros.MacroUtils @bundle class FreezableMacro(val c: whitebox.Context) { import c.universe._ + val FreezeMethodName = TermName("freeze") + val FrozenClassName = TypeName("Frozen") + val M = new MacroUtils[c.type](c) // NOTE: Stuck with c.Expr[Any] instead of c.Tree for now; @@ -27,8 +30,8 @@ import org.scaladebugger.macros.MacroUtils //println("INPUT CLASS ONLY :: " + classDef) val results = processTrait(classDef) //println("RESULTS :: " + results) - if (classDef.name.decodedName.toString == "ValueInfo") - println("RESULTS :: " + results) + //println("RESULTS :: " + results.map(r => showCode(r))) + println("RESULTS :: " + results) println("DONE -- " + id) (EmptyTree, results) case _ => @@ -97,10 +100,10 @@ import org.scaladebugger.macros.MacroUtils // TODO: Find better way to know when to mark as overriden val o = TermName(tpname.toString()) val freezeMethod = - if (inheritedMethods.exists(_.name.toString == "freeze")) - q"override def freeze(): $tpname = $o.freeze(this)" + if (inheritedMethods.exists(_.name.toString == FreezeMethodName.toString)) + q"override def $FreezeMethodName(): $tpname = $o.$FreezeMethodName(this)" else - q"def freeze(): $tpname = $o.freeze(this)" + q"def $FreezeMethodName(): $tpname = $o.$FreezeMethodName(this)" val tree = q""" $mods trait $tpname[..$tparams] extends { @@ -167,49 +170,19 @@ import org.scaladebugger.macros.MacroUtils q"""scala.util.Try.apply($freezeObjName.$methodName) .asInstanceOf[scala.util.Try[$returnType]]""" case ReturnType.FreezeObject => - q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.freeze()) - .asInstanceOf[scala.util.Try[$returnType]]""" - case ReturnType.FreezeCollection => - q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$returnType]]""" - case ReturnType.FreezeOption => - q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) - .asInstanceOf[scala.util.Try[$returnType]]""" - case ReturnType.FreezeEither => - q""" - scala.util.Try.apply($freezeObjName.$methodName).map(r => r match { - case scala.util.Left(o) => scala.util.Left(o.freeze()) - case scala.util.Right(o) => scala.util.Right(o.freeze()) - }).asInstanceOf[scala.util.Try[$returnType]] - """ - } - } - - private def generateFreezeMethodBody( - r: org.scaladebugger.macros.freeze.CanFreeze.ReturnType.ReturnType, - freezeObjName: TermName, - methodName: TermName, - returnType: TypeName - ): Tree = { - import org.scaladebugger.macros.freeze.CanFreeze.ReturnType - r match { - case ReturnType.Normal => - q"""scala.util.Try.apply($freezeObjName.$methodName) - .asInstanceOf[scala.util.Try[$returnType]]""" - case ReturnType.FreezeObject => - q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.freeze()) + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.$FreezeMethodName()) .asInstanceOf[scala.util.Try[$returnType]]""" case ReturnType.FreezeCollection => - q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.$FreezeMethodName())) .asInstanceOf[scala.util.Try[$returnType]]""" case ReturnType.FreezeOption => - q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.freeze())) + q"""scala.util.Try.apply($freezeObjName.$methodName).map(_.map(_.$FreezeMethodName())) .asInstanceOf[scala.util.Try[$returnType]]""" case ReturnType.FreezeEither => q""" scala.util.Try.apply($freezeObjName.$methodName).map(r => r match { - case scala.util.Left(o) => scala.util.Left(o.freeze()) - case scala.util.Right(o) => scala.util.Right(o.freeze()) + case scala.util.Left(o) => scala.util.Left(o.$FreezeMethodName()) + case scala.util.Right(o) => scala.util.Right(o.$FreezeMethodName()) }).asInstanceOf[scala.util.Try[$returnType]] """ } @@ -233,18 +206,10 @@ import org.scaladebugger.macros.MacroUtils val unfreezableMethods = internalGroups.getOrElse("CannotFreeze", Nil) val otherMethods = internalGroups.getOrElse("Other", Nil) - // Validate that we don't have a method left behind without an implementation - otherMethods.foreach { - case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => - if (expr.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as @CanFreeze or @CannotFreeze!" - ) - } - // TODO: Figure out why multiple of method symbol show up here, // resulting in us using distinct val filteredInheritedMethods = inheritedMethods.distinct.filterNot(m => { + m.name.decodedName.toString == FreezeMethodName.toString || internalMethodTrees.exists(t => t.name.decodedName.toString == m.name.decodedName.toString && t.vparamss.size == m.paramLists.size && @@ -272,9 +237,12 @@ import org.scaladebugger.macros.MacroUtils // TODO: This is a hack to get around appearing when method // returns type of trait we are currently inspecting + val retTypeStr = m.returnType.toString val tpt = - if (m.returnType.toString == "") traitTypeName - else TypeName(m.returnType.toString) + if (retTypeStr == "" || retTypeStr == "...") + M.classNameToTree(traitTypeName.decodedName.toString) + else + M.classNameToTree(retTypeStr) q"protected val $name: scala.util.Try[$tpt]" }) @@ -303,9 +271,12 @@ import org.scaladebugger.macros.MacroUtils // TODO: This is a hack to get around appearing when method // returns type of trait we are currently inspecting + val retTypeStr = m.returnType.toString val tpt = - if (m.returnType.toString == "") traitTypeName - else TypeName(m.returnType.toString) + if (retTypeStr == "" || retTypeStr == "...") + M.classNameToTree(traitTypeName.decodedName.toString) + else + M.classNameToTree(retTypeStr) val a = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) if (a.isEmpty) c.abort( @@ -349,7 +320,23 @@ import org.scaladebugger.macros.MacroUtils throw new IllegalStateException("Method not frozen!")""" } - val newInheritedMethods = filteredInheritedMethods.flatMap(m => { + // Validate that we don't have a method left behind without an implementation + val newSuperMethods = otherMethods.map { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + if (expr.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as @CanFreeze or @CannotFreeze!" + ) + + val newMods: Modifiers = markModifiersOverride(mods match { + case m: Modifiers => m + }) + + q"""$newMods def $tname[..$tparams](...$paramss): $tpt = + super.$tname[..$tparams](...$paramss)""" + } + + val newInheritedMethods = filteredInheritedMethods.map(m => { val methodName = m.name.decodedName.toString val mods = m.annotations.map(_.tree) val tname = TermName(methodName) @@ -365,11 +352,12 @@ import org.scaladebugger.macros.MacroUtils // TODO: This is a hack to get around appearing when method // returns type of trait we are currently inspecting + val retTypeStr = m.returnType.toString val tpt = - if (m.returnType.toString == "") + if (retTypeStr == "" || retTypeStr == "...") M.classNameToTree(traitTypeName.decodedName.toString) else - M.classNameToTree(m.returnType.toString) + M.classNameToTree(retTypeStr) val aFreezable = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) val aUnfreezable = m.annotations.find(_.tree.tpe =:= typeOf[CannotFreeze]) @@ -387,30 +375,20 @@ import org.scaladebugger.macros.MacroUtils ).mkString(" ") ) - val methodTree = if (aFreezable.nonEmpty) { + if (aFreezable.nonEmpty) { val name = TermName(s"$$$tname") q"override def $tname[..$tparams](...$paramss): $tpt = this.$name.get" } else if (aUnfreezable.nonEmpty) { q"""override def $tname[..$tparams](...$paramss): $tpt = throw new IllegalStateException("Method not frozen!")""" } else { - null + q"""override def $tname[..$tparams](...$paramss): $tpt = + super.$tname[..$tparams](...$paramss)""" } - - //println("GENERATING METHOD FOR " + m.name + " OF " + m.owner.name) - Option(methodTree) }) - val frozenParents = parentTypes.map(t => - M.classNameToTree(t.typeSymbol.fullName + ".Frozen") - ) - - val parents = frozenParents ++ List( - typeOf[java.io.Serializable] - ).map(t => TypeTree(t)) - val klass = q""" - final class Frozen private[$traitTypeName](..$cParams) extends $traitTypeName { + final class $FrozenClassName private[$traitTypeName](..$cParams) extends $traitTypeName { ..$newFreezableMethods ..$newUnfreezableMethods ..$newInheritedMethods @@ -418,7 +396,7 @@ import org.scaladebugger.macros.MacroUtils """ val method = q""" - def freeze($freezeObjName: $traitTypeName): $traitTypeName = new Frozen(..$cArgs) + def $FreezeMethodName($freezeObjName: $traitTypeName): $traitTypeName = new $FrozenClassName(..$cArgs) """ object Q { From cedd06232b30befaa3488912059809a2f0a03f36 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Thu, 17 Aug 2017 00:27:11 -0700 Subject: [PATCH 33/36] Still working on it -- recursive type is still an issue --- .../macros/freeze/FreezableMacro.scala | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 93315751..77ad8acd 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -206,6 +206,15 @@ import org.scaladebugger.macros.MacroUtils val unfreezableMethods = internalGroups.getOrElse("CannotFreeze", Nil) val otherMethods = internalGroups.getOrElse("Other", Nil) + // Validate that we don't have a method left behind without an implementation + otherMethods.foreach { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + if (expr.isEmpty) c.abort( + c.enclosingPosition, + s"$tname has no implementation and is not marked as @CanFreeze or @CannotFreeze!" + ) + } + // TODO: Figure out why multiple of method symbol show up here, // resulting in us using distinct val filteredInheritedMethods = inheritedMethods.distinct.filterNot(m => { @@ -320,23 +329,7 @@ import org.scaladebugger.macros.MacroUtils throw new IllegalStateException("Method not frozen!")""" } - // Validate that we don't have a method left behind without an implementation - val newSuperMethods = otherMethods.map { - case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => - if (expr.isEmpty) c.abort( - c.enclosingPosition, - s"$tname has no implementation and is not marked as @CanFreeze or @CannotFreeze!" - ) - - val newMods: Modifiers = markModifiersOverride(mods match { - case m: Modifiers => m - }) - - q"""$newMods def $tname[..$tparams](...$paramss): $tpt = - super.$tname[..$tparams](...$paramss)""" - } - - val newInheritedMethods = filteredInheritedMethods.map(m => { + val newInheritedMethods = filteredInheritedMethods.flatMap(m => { val methodName = m.name.decodedName.toString val mods = m.annotations.map(_.tree) val tname = TermName(methodName) @@ -375,16 +368,17 @@ import org.scaladebugger.macros.MacroUtils ).mkString(" ") ) - if (aFreezable.nonEmpty) { + val methodTree = if (aFreezable.nonEmpty) { val name = TermName(s"$$$tname") q"override def $tname[..$tparams](...$paramss): $tpt = this.$name.get" } else if (aUnfreezable.nonEmpty) { q"""override def $tname[..$tparams](...$paramss): $tpt = throw new IllegalStateException("Method not frozen!")""" } else { - q"""override def $tname[..$tparams](...$paramss): $tpt = - super.$tname[..$tparams](...$paramss)""" + null } + + Option(methodTree) }) val klass = q""" @@ -399,15 +393,6 @@ import org.scaladebugger.macros.MacroUtils def $FreezeMethodName($freezeObjName: $traitTypeName): $traitTypeName = new $FrozenClassName(..$cArgs) """ - object Q { - object Y - type T = Test - class Test extends scala.AnyRef - trait Pants - } - val x: Q.Test = null - val y: Q.Pants = null - List(klass, method) } } From bdf4acd7d3b05108757ade7fefdb62d0f7f865d0 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 20 Aug 2017 13:23:59 -0700 Subject: [PATCH 34/36] Where am I? --- project/Macros.scala | 1 + .../api/profiles/traits/info/ArrayInfo.scala | 2 +- .../profiles/traits/info/ArrayTypeInfo.scala | 2 +- .../traits/info/ClassLoaderInfo.scala | 2 +- .../traits/info/ClassObjectInfo.scala | 2 +- .../profiles/traits/info/ClassTypeInfo.scala | 2 +- .../api/profiles/traits/info/CommonInfo.scala | 2 +- .../api/profiles/traits/info/CreateInfo.scala | 2 +- .../traits/info/FieldVariableInfo.scala | 2 +- .../api/profiles/traits/info/FrameInfo.scala | 2 +- .../traits/info/IndexedVariableInfo.scala | 2 +- .../traits/info/InterfaceTypeInfo.scala | 2 +- .../api/profiles/traits/info/JavaInfo.scala | 2 +- .../profiles/traits/info/LocationInfo.scala | 2 +- .../api/profiles/traits/info/MethodInfo.scala | 2 +- .../api/profiles/traits/info/ObjectInfo.scala | 2 +- .../profiles/traits/info/PrimitiveInfo.scala | 2 +- .../traits/info/ReferenceTypeInfo.scala | 2 +- .../api/profiles/traits/info/StringInfo.scala | 2 +- .../traits/info/ThreadGroupInfo.scala | 2 +- .../api/profiles/traits/info/ThreadInfo.scala | 2 +- .../traits/info/ThreadStatusInfo.scala | 2 +- .../profiles/traits/info/VariableInfo.scala | 2 +- .../org/scaladebugger/macros/MacroUtils.scala | 17 +++++++ .../macros/freeze/FreezableMacro.scala | 51 +++++++++---------- 25 files changed, 64 insertions(+), 49 deletions(-) diff --git a/project/Macros.scala b/project/Macros.scala index c7cdd217..7186341a 100644 --- a/project/Macros.scala +++ b/project/Macros.scala @@ -16,6 +16,7 @@ object Macros { val settings: Seq[Setting[_]] = pluginSettings ++ Seq( libraryDependencies ++= Seq( "org.typelevel" %% "macro-compat" % "1.1.1", + "com.lihaoyi" %% "scalaparse" % "0.4.4", "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided", scalaVersion("org.scala-lang" % "scala-reflect" % _).value, "org.scalatest" %% "scalatest" % "3.0.0" % "test,it" diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index bd30404d..9676b9df 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -21,7 +21,7 @@ object ArrayInfo { /** * Represents the interface for array-based interaction. */ -//@Freezable +@Freezable trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { import scala.reflect.runtime.universe.{TypeTag, typeOf} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index e03edf6c..f3182fe9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -//@Freezable +@Freezable trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index 50d46a83..b8ec04dd 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class loader"-based interaction. */ -//@Freezable +@Freezable trait ClassLoaderInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 1b941987..8e9848d3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class object"-based interaction. */ -//@Freezable +@Freezable trait ClassObjectInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 7b7692f6..81764288 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for retrieving class type-based information. */ -//@Freezable +@Freezable trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 8a6bd488..395c38fa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -//@Freezable +@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 494529de..8bc68919 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -8,7 +8,7 @@ import scala.util.Try * Represents the interface that needs to be implemented to provide * ability to create data using a specific debug profile. */ -//@Freezable +@Freezable trait CreateInfo { /** * Creates the provided value on the remote JVM. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index b73de387..94441dad 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -11,7 +11,7 @@ import scala.util.Try * Represents the interface for variable-based interaction with field-specific * information. */ -//@Freezable +@Freezable trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 4d532a5a..1c9928cd 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for frame-based interaction. */ -//@Freezable +@Freezable trait FrameInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index f2593185..99b62489 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents the interface for variable-based interaction with indexed * location information. */ -//@Freezable +@Freezable trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index cc5afea9..2b7ff13e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -//@Freezable +@Freezable trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index 6ed12a82..44947979 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -//@Freezable +@Freezable trait JavaInfo extends java.io.Serializable { /** * Returns whether or not this info profile represents the low-level Java diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index c83fd2c3..188c91eb 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for location-based interaction. */ -//@Freezable +@Freezable trait LocationInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index 1ad3ad7f..e7d24563 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for method-based interaction. */ -//@Freezable +@Freezable trait MethodInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index f60e9a3e..a6d11395 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for object-based interaction. */ -//@Freezable +@Freezable trait ObjectInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala index cdddccaa..7f02b8ec 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala @@ -10,7 +10,7 @@ import scala.util.{Failure, Success, Try} /** * Represents information about a primitive value. */ -//@Freezable +@Freezable trait PrimitiveInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 4916841f..3c14a96e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for "reference type"-based interaction. */ -//@Freezable +@Freezable trait ReferenceTypeInfo extends CommonInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index 499a30aa..b4657a4a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for string-based interaction. */ -//@Freezable +@Freezable trait StringInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index 746d5b1b..b5762dc6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for thread-based interaction. */ -//@Freezable +@Freezable trait ThreadGroupInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index 50576856..cdadfaec 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for thread-based interaction. */ -//@Freezable +@Freezable trait ThreadInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index cef33537..cedb0e1f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} /** * Represents information about a thread's status. */ -//@Freezable +@Freezable trait ThreadStatusInfo { /** * Represents the status code for the thread. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 1950709f..67419f38 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for variable-based interaction. */ -//@Freezable +@Freezable trait VariableInfo extends CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index 040faf21..5c8098dd 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -123,6 +123,23 @@ import macrocompat.bundle } } + def currentPackage(): String = { + val typeName = TypeName("Dummy" + c.freshName()) + val dummyType = c.typecheck(q"class $typeName").tpe + dummyType.typeConstructor + val ownerSymbol = dummyType.typeSymbol.owner + println("TYPE SYMBOL OF " + typeName + " IS " + dummyType.typeSymbol) + println("TERM SYMBOL OF " + typeName + " IS " + dummyType.termSymbol) + println("OWNER OF " + typeName + " IS " + ownerSymbol) + + @tailrec def buildPackage(owner: Symbol, tokens: List[String]): String = { + if (owner == NoSymbol) tokens.mkString(".") + else buildPackage(owner.owner, owner.name.decodedName.toString +: tokens) + } + + buildPackage(ownerSymbol, Nil) + } + def newEmptyObject(name: String): ModuleDef = { val oName = TermName(name) val moduleDef: ModuleDef = q"object $oName {}" match { diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 77ad8acd..51e049ea 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -19,20 +19,10 @@ import org.scaladebugger.macros.MacroUtils val id = java.util.UUID.randomUUID().toString val (annottee, expandees) = annottees.map(_.tree) match { case (classDef: ClassDef) :: (moduleDef: ModuleDef) :: Nil if M.isTrait(classDef) => - println("PROCESSING -- " + classDef.name.decodedName.toString + " -- " + id) - //println("INPUT CLASS AND MODULE :: " + classDef + " :: " + moduleDef) val results = processTraitAndObj(classDef, moduleDef) - //println("RESULTS :: " + results) - println("DONE -- " + id) (EmptyTree, results) case (classDef: ClassDef) :: Nil if M.isTrait(classDef) => - println("PROCESSING -- " + classDef.name.decodedName.toString + " -- " + id) - //println("INPUT CLASS ONLY :: " + classDef) val results = processTrait(classDef) - //println("RESULTS :: " + results) - //println("RESULTS :: " + results.map(r => showCode(r))) - println("RESULTS :: " + results) - println("DONE -- " + id) (EmptyTree, results) case _ => c.abort( @@ -42,6 +32,16 @@ import org.scaladebugger.macros.MacroUtils } val outputs = expandees + val fileName = c.enclosingPosition.source.file.name + val fileContent = outputs.map(o => showRaw(o)) + val f = new java.io.File("/tmp/tmp/" + fileName) + Console.out.print("Writing out " + f.getPath + "... ") + Console.out.flush() + val pw = new java.io.PrintWriter(f) + pw.write(fileContent.mkString(System.getProperty("line.separator"))) + pw.close() + Console.out.println("done") + c.Expr[Any]( Block(outputs, Literal(Constant(()))) ) @@ -97,7 +97,7 @@ import org.scaladebugger.macros.MacroUtils case l: List[Tree] => l } - // TODO: Find better way to know when to mark as overriden + // TODO: Find better way to know when to mark as overridden val o = TermName(tpname.toString()) val freezeMethod = if (inheritedMethods.exists(_.name.toString == FreezeMethodName.toString)) @@ -140,7 +140,7 @@ import org.scaladebugger.macros.MacroUtils newObjDef match { case m: ModuleDef => m } } - List(newClassDef, newModuleDef) + List(classDef, newModuleDef) } private def markModifiersOverride(modifiers: Modifiers): Modifiers = { @@ -244,14 +244,13 @@ import org.scaladebugger.macros.MacroUtils } ++ iFreezableMethods.map(m => { val name = TermName(s"$$${m.name.decodedName.toString}") - // TODO: This is a hack to get around appearing when method - // returns type of trait we are currently inspecting val retTypeStr = m.returnType.toString val tpt = - if (retTypeStr == "" || retTypeStr == "...") - M.classNameToTree(traitTypeName.decodedName.toString) - else + if (retTypeStr == "" || retTypeStr == "...") { + tq"" + } else { M.classNameToTree(retTypeStr) + } q"protected val $name: scala.util.Try[$tpt]" }) @@ -278,14 +277,13 @@ import org.scaladebugger.macros.MacroUtils } ++ iFreezableMethods.map(m => { val tname = TermName(m.name.decodedName.toString) - // TODO: This is a hack to get around appearing when method - // returns type of trait we are currently inspecting val retTypeStr = m.returnType.toString val tpt = - if (retTypeStr == "" || retTypeStr == "...") - M.classNameToTree(traitTypeName.decodedName.toString) - else + if (retTypeStr == "" || retTypeStr == "...") { + tq"" + } else { M.classNameToTree(retTypeStr) + } val a = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) if (a.isEmpty) c.abort( @@ -343,14 +341,13 @@ import org.scaladebugger.macros.MacroUtils q"val $name: $typeName" })) - // TODO: This is a hack to get around appearing when method - // returns type of trait we are currently inspecting val retTypeStr = m.returnType.toString val tpt = - if (retTypeStr == "" || retTypeStr == "...") - M.classNameToTree(traitTypeName.decodedName.toString) - else + if (retTypeStr == "" || retTypeStr == "...") { + tq"" + } else { M.classNameToTree(retTypeStr) + } val aFreezable = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) val aUnfreezable = m.annotations.find(_.tree.tpe =:= typeOf[CannotFreeze]) From 2f1b59dace2b54c6ee02b1d109e328e771442ab2 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sun, 20 Aug 2017 15:07:47 -0700 Subject: [PATCH 35/36] Stopping again --- scala-debugger-api/project/build.properties | 1 + .../api/profiles/traits/info/ArrayInfo.scala | 2 +- .../profiles/traits/info/ArrayTypeInfo.scala | 2 +- .../traits/info/ClassLoaderInfo.scala | 2 +- .../traits/info/ClassObjectInfo.scala | 2 +- .../profiles/traits/info/ClassTypeInfo.scala | 2 +- .../api/profiles/traits/info/CreateInfo.scala | 2 +- .../traits/info/FieldVariableInfo.scala | 2 +- .../api/profiles/traits/info/FrameInfo.scala | 2 +- .../traits/info/IndexedVariableInfo.scala | 2 +- .../traits/info/InterfaceTypeInfo.scala | 2 +- .../profiles/traits/info/LocationInfo.scala | 3 +- .../api/profiles/traits/info/MethodInfo.scala | 2 +- .../api/profiles/traits/info/ObjectInfo.scala | 2 +- .../traits/info/PrimitiveTypeInfo.scala | 2 +- .../traits/info/ReferenceTypeInfo.scala | 2 +- .../api/profiles/traits/info/StringInfo.scala | 2 +- .../traits/info/ThreadGroupInfo.scala | 2 +- .../api/profiles/traits/info/ThreadInfo.scala | 2 +- .../traits/info/ThreadStatusInfo.scala | 2 +- .../profiles/traits/info/VariableInfo.scala | 2 +- .../org/scaladebugger/macros/MacroUtils.scala | 17 ++++ .../macros/freeze/FreezableMacro.scala | 95 +++++++++++++++---- 23 files changed, 118 insertions(+), 36 deletions(-) create mode 100644 scala-debugger-api/project/build.properties diff --git a/scala-debugger-api/project/build.properties b/scala-debugger-api/project/build.properties new file mode 100644 index 00000000..c091b86c --- /dev/null +++ b/scala-debugger-api/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.16 diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index 9676b9df..bd30404d 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -21,7 +21,7 @@ object ArrayInfo { /** * Represents the interface for array-based interaction. */ -@Freezable +//@Freezable trait ArrayInfo extends ObjectInfo with CreateInfo with CommonInfo { import scala.reflect.runtime.universe.{TypeTag, typeOf} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index f3182fe9..e03edf6c 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -@Freezable +//@Freezable trait ArrayTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index b8ec04dd..50d46a83 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class loader"-based interaction. */ -@Freezable +//@Freezable trait ClassLoaderInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 8e9848d3..1b941987 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -7,7 +7,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for "class object"-based interaction. */ -@Freezable +//@Freezable trait ClassObjectInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 81764288..7b7692f6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for retrieving class type-based information. */ -@Freezable +//@Freezable trait ClassTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 8bc68919..494529de 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -8,7 +8,7 @@ import scala.util.Try * Represents the interface that needs to be implemented to provide * ability to create data using a specific debug profile. */ -@Freezable +//@Freezable trait CreateInfo { /** * Creates the provided value on the remote JVM. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index 94441dad..b73de387 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -11,7 +11,7 @@ import scala.util.Try * Represents the interface for variable-based interaction with field-specific * information. */ -@Freezable +//@Freezable trait FieldVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 1c9928cd..4d532a5a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for frame-based interaction. */ -@Freezable +//@Freezable trait FrameInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index 99b62489..f2593185 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} * Represents the interface for variable-based interaction with indexed * location information. */ -@Freezable +//@Freezable trait IndexedVariableInfo extends VariableInfo with CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index 2b7ff13e..cc5afea9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving interface type-based information. */ -@Freezable +//@Freezable trait InterfaceTypeInfo extends ReferenceTypeInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index 188c91eb..d4908eb4 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -1,6 +1,7 @@ package org.scaladebugger.api.profiles.traits.info import com.sun.jdi.Location +import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} @@ -9,7 +10,7 @@ import scala.util.Try /** * Represents the interface for location-based interaction. */ -@Freezable +//@Freezable trait LocationInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index e7d24563..1ad3ad7f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for method-based interaction. */ -@Freezable +//@Freezable trait MethodInfo extends CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index a6d11395..f60e9a3e 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -10,7 +10,7 @@ import scala.util.Try /** * Represents the interface for object-based interaction. */ -@Freezable +//@Freezable trait ObjectInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala index e22bbb32..0c07c8b0 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for retrieving primitive type-based information. */ -@Freezable +//@Freezable trait PrimitiveTypeInfo extends TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 3c14a96e..4916841f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for "reference type"-based interaction. */ -@Freezable +//@Freezable trait ReferenceTypeInfo extends CommonInfo with TypeInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index b4657a4a..499a30aa 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -6,7 +6,7 @@ import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** * Represents the interface for string-based interaction. */ -@Freezable +//@Freezable trait StringInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index b5762dc6..746d5b1b 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -8,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents the interface for thread-based interaction. */ -@Freezable +//@Freezable trait ThreadGroupInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index cdadfaec..50576856 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for thread-based interaction. */ -@Freezable +//@Freezable trait ThreadInfo extends ObjectInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index cedb0e1f..cef33537 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -5,7 +5,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} /** * Represents information about a thread's status. */ -@Freezable +//@Freezable trait ThreadStatusInfo { /** * Represents the status code for the thread. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 67419f38..1950709f 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for variable-based interaction. */ -@Freezable +//@Freezable trait VariableInfo extends CreateInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index 5c8098dd..876e4b3f 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -149,6 +149,23 @@ import macrocompat.bundle } def classNameToTree(fqcn: String): Tree = { + if (fqcn == "...") { + tq"" + } else { + val classNames = fqcn.split("\\[|\\]").filter(_.nonEmpty) + if (classNames.length <= 1) singleClassNameToTree(classNames.head) + else { + // NOTE: Assuming type param is only one, not more than one + AppliedTypeTree( + classNameToTree(classNames.head), + classNames.tail.map(classNameToTree).toList + ) + } + } + } + + // Only converts my.class.Name, not my.class.Name[my.TypeA, my.TypeB] + private def singleClassNameToTree(fqcn: String): Tree = { val tokens = fqcn.split('.').filter(_.nonEmpty) val packageName = tokens.take(tokens.length - 1).toList diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 51e049ea..95b672df 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -8,8 +8,10 @@ import org.scaladebugger.macros.MacroUtils @bundle class FreezableMacro(val c: whitebox.Context) { import c.universe._ + val InternalConstructorName = "$init$" val FreezeMethodName = TermName("freeze") - val FrozenClassName = TypeName("Frozen") + val FrozenTraitName = TypeName("Frozen") + val FrozenClassName = TypeName("FrozenImpl") val M = new MacroUtils[c.type](c) @@ -32,15 +34,9 @@ import org.scaladebugger.macros.MacroUtils } val outputs = expandees - val fileName = c.enclosingPosition.source.file.name - val fileContent = outputs.map(o => showRaw(o)) - val f = new java.io.File("/tmp/tmp/" + fileName) - Console.out.print("Writing out " + f.getPath + "... ") - Console.out.flush() - val pw = new java.io.PrintWriter(f) - pw.write(fileContent.mkString(System.getProperty("line.separator"))) - pw.close() - Console.out.println("done") + println(outputs) + //println(showRaw(q"val x: scala.util.Try[Seq[java.lang.String]]")) + //println(showRaw(q"val x: scala.util.Try[Seq[_]]")) c.Expr[Any]( Block(outputs, Literal(Constant(()))) @@ -140,7 +136,7 @@ import org.scaladebugger.macros.MacroUtils newObjDef match { case m: ModuleDef => m } } - List(classDef, newModuleDef) + List(newClassDef, newModuleDef) } private def markModifiersOverride(modifiers: Modifiers): Modifiers = { @@ -197,7 +193,11 @@ import org.scaladebugger.macros.MacroUtils val freezeObjName = TermName("valueToFreeze") val internalMethodTrees = body.collect { case d: DefDef => d } - val internalGroups = internalMethodTrees.groupBy(d => { + val internalGroups = internalMethodTrees.filterNot { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + val name = tname.toString() + name == InternalConstructorName.toString + }.groupBy(d => { if (M.containsAnnotation(d, "CanFreeze")) "CanFreeze" else if (M.containsAnnotation(d, "CannotFreeze")) "CannotFreeze" else "Other" @@ -218,6 +218,7 @@ import org.scaladebugger.macros.MacroUtils // TODO: Figure out why multiple of method symbol show up here, // resulting in us using distinct val filteredInheritedMethods = inheritedMethods.distinct.filterNot(m => { + m.name.decodedName.toString == InternalConstructorName.toString || m.name.decodedName.toString == FreezeMethodName.toString || internalMethodTrees.exists(t => t.name.decodedName.toString == m.name.decodedName.toString && @@ -235,6 +236,50 @@ import org.scaladebugger.macros.MacroUtils val iFreezableMethods = filteredInheritedMethods.filter( _.annotations.exists(_.tree.tpe =:= typeOf[CanFreeze]) ) + val iOtherMethods = filteredInheritedMethods.filterNot( + _.annotations.map(_.tree.tpe).exists(t => + t =:= typeOf[CanFreeze] || t =:= typeOf[CannotFreeze]) + ) + + // Build up dependencies for frozen trait + val cDeps = freezableMethods.map { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + val name = TermName(s"$$$tname") + q"protected val $name: scala.util.Try[$tpt]" + } ++ iFreezableMethods.map(m => { + val name = TermName(s"$$${m.name.decodedName.toString}") + + val retTypeStr = m.returnType.toString + val tpt = + if (retTypeStr == "" || retTypeStr == "...") { + tq"" + } else { + M.classNameToTree(retTypeStr) + } + + q"protected val $name: scala.util.Try[$tpt]" + }) ++ otherMethods.flatMap { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + val name = TermName(s"$$$tname") + + if (paramss.nonEmpty) None + else Some(q"override protected val $name: scala.util.Try[$tpt] = scala.util.Try.apply(this.$tname)") + } ++ iOtherMethods.flatMap(m => { + val mname = TermName(m.name.decodedName.toString) + val name = TermName(s"$$${m.name.decodedName.toString}") + + val retTypeStr = m.returnType.toString + val tpt = + if (retTypeStr == "" || retTypeStr == "...") { + tq"" + } else { + M.classNameToTree(retTypeStr) + } + + if (m.paramLists.nonEmpty) None + else Some(q"override protected val $name: scala.util.Try[$tpt] = scala.util.Try.apply(this.$mname)") + + }) // Build up constructor parameters for frozen class val cParams = freezableMethods.map { @@ -327,6 +372,16 @@ import org.scaladebugger.macros.MacroUtils throw new IllegalStateException("Method not frozen!")""" } + val newSuperMethods = otherMethods.map { + case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => + val newMods: Modifiers = markModifiersOverride(mods match { + case m: Modifiers => m + }) + + q"""$newMods def $tname[..$tparams](...$paramss): $tpt = + super.$tname[..$tparams](...$paramss)""" + } + val newInheritedMethods = filteredInheritedMethods.flatMap(m => { val methodName = m.name.decodedName.toString val mods = m.annotations.map(_.tree) @@ -378,19 +433,27 @@ import org.scaladebugger.macros.MacroUtils Option(methodTree) }) - val klass = q""" - final class $FrozenClassName private[$traitTypeName](..$cParams) extends $traitTypeName { + val parents = parentTypes + .map(_.typeSymbol.fullName + "." + FrozenTraitName) + .map(M.classNameToTree) + + val interface = q""" + trait $FrozenTraitName extends $traitTypeName with ..$parents { + ..$cDeps ..$newFreezableMethods ..$newUnfreezableMethods - ..$newInheritedMethods } """ + val klass = q""" + final class $FrozenClassName private[$traitTypeName](..$cParams) extends $FrozenTraitName + """ + val method = q""" def $FreezeMethodName($freezeObjName: $traitTypeName): $traitTypeName = new $FrozenClassName(..$cArgs) """ - List(klass, method) + List(interface, klass, method) } } From 61a8f2d89cbd8565f9aa86c2c3fa0cfed1fdd938 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Wed, 23 Aug 2017 07:27:12 -0700 Subject: [PATCH 36/36] Unfinished refactor --- project/Acyclic.scala | 18 ++ project/Common.scala | 2 +- .../profiles/java/info/JavaInfoProducer.scala | 2 +- .../profiles/java/info/JavaThreadInfo.scala | 3 + .../java/info/JavaTypeConverter.scala | 146 ++++++++++++++ .../api/profiles/java/info/JavaTypeInfo.scala | 104 +--------- .../java/info/JavaValueConverter.scala | 181 ++++++++++++++++++ .../profiles/java/info/JavaValueInfo.scala | 122 +----------- .../api/profiles/traits/info/ArrayInfo.scala | 1 + .../profiles/traits/info/ArrayTypeInfo.scala | 1 + .../info/CastNotPossibleException.scala | 1 + .../traits/info/ClassLoaderInfo.scala | 1 + .../traits/info/ClassObjectInfo.scala | 1 + .../profiles/traits/info/ClassTypeInfo.scala | 1 + .../api/profiles/traits/info/CommonInfo.scala | 3 +- .../api/profiles/traits/info/CreateInfo.scala | 1 + .../traits/info/FieldVariableInfo.scala | 1 + .../api/profiles/traits/info/FrameInfo.scala | 1 + .../traits/info/GrabInfoProfile.scala | 1 + .../traits/info/IndexedVariableInfo.scala | 1 + .../profiles/traits/info/InfoProducer.scala | 1 + .../traits/info/InterfaceTypeInfo.scala | 1 + .../api/profiles/traits/info/JavaInfo.scala | 3 +- .../profiles/traits/info/LocationInfo.scala | 1 + .../api/profiles/traits/info/MethodInfo.scala | 1 + .../api/profiles/traits/info/MiscInfo.scala | 1 + .../api/profiles/traits/info/ObjectInfo.scala | 1 + .../profiles/traits/info/PrimitiveInfo.scala | 3 +- .../traits/info/PrimitiveTypeInfo.scala | 1 + .../traits/info/ReferenceTypeInfo.scala | 1 + .../api/profiles/traits/info/StringInfo.scala | 1 + .../traits/info/ThreadGroupInfo.scala | 1 + .../api/profiles/traits/info/ThreadInfo.scala | 1 + .../traits/info/ThreadStatusInfo.scala | 1 + .../profiles/traits/info/TypeChecker.scala | 1 + .../profiles/traits/info/TypeConverter.scala | 88 +++++++++ .../api/profiles/traits/info/TypeInfo.scala | 84 +------- .../info/UnsupportedTypeException.scala | 1 + .../profiles/traits/info/ValueConverter.scala | 144 ++++++++++++++ .../api/profiles/traits/info/ValueInfo.scala | 155 +-------------- .../profiles/traits/info/VariableInfo.scala | 1 + .../org/scaladebugger/macros/MacroUtils.scala | 12 +- .../macros/freeze/FreezableMacro.scala | 42 ++-- 43 files changed, 649 insertions(+), 489 deletions(-) create mode 100644 project/Acyclic.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeConverter.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueConverter.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeConverter.scala create mode 100644 scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueConverter.scala diff --git a/project/Acyclic.scala b/project/Acyclic.scala new file mode 100644 index 00000000..2beafd4c --- /dev/null +++ b/project/Acyclic.scala @@ -0,0 +1,18 @@ +import sbt.Keys._ +import sbt._ + +import scala.util.Try + +object Acyclic { + def settings: Seq[Setting[_]] = Seq( + libraryDependencies += "com.lihaoyi" %% "acyclic" % "0.1.7" % "provided", + libraryDependencies ++= ( + if (scalaVersion.value.startsWith("2.10")) Seq( + "org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided" + ) else Nil + ), + autoCompilerPlugins := true, + addCompilerPlugin("com.lihaoyi" %% "acyclic" % "0.1.7") + ) +} + diff --git a/project/Common.scala b/project/Common.scala index 1afbd9c3..18f768b4 100644 --- a/project/Common.scala +++ b/project/Common.scala @@ -135,6 +135,6 @@ object Common { else Some("releases" at nexus + "service/local/staging/deploy/maven2") } - ) ++ Macros.pluginSettings + ) ++ Macros.pluginSettings ++ Acyclic.settings } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaInfoProducer.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaInfoProducer.scala index 932a5914..06eef3cb 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaInfoProducer.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaInfoProducer.scala @@ -27,7 +27,7 @@ class JavaInfoProducer extends InfoProducer { * @return The profile instance providing an implementation corresponding * to Java */ - override def toJavaInfo: InfoProducer = new JavaInfoProducer + override def toJavaInfo: InfoProducer = this /** * Retrieves the event info producer tied to this info producer. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaThreadInfo.scala index ee341075..427365e6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaThreadInfo.scala @@ -147,6 +147,9 @@ class JavaThreadInfo( */ override def totalFrames: Int = _threadReference.frameCount() + protected def newValueConverter(value: Value): ValueConverter = + JavaValueConverter.from() + protected def newFrameProfile( stackFrame: StackFrame, index: Int diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeConverter.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeConverter.scala new file mode 100644 index 00000000..cffcd683 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeConverter.scala @@ -0,0 +1,146 @@ +package org.scaladebugger.api.profiles.java.info + +import com.sun.jdi._ +import org.scaladebugger.api.profiles.traits.info._ +import JavaTypeConverter._ + +object JavaTypeConverter { + val DefaultNewReferenceTypeProfile: JavaTypeInfo => ReferenceType => ReferenceTypeInfo = + `type` => `type`.infoProducer.newReferenceTypeInfo( + `type`.scalaVirtualMachine, + _: ReferenceType + ) + val DefaultNewArrayTypeProfile: JavaTypeInfo => ArrayType => ArrayTypeInfo = + `type` => `type`.infoProducer.newArrayTypeInfo( + `type`.scalaVirtualMachine, + _: ArrayType + ) + val DefaultNewClassTypeProfile: JavaTypeInfo => ClassType => ClassTypeInfo = + `type` => `type`.infoProducer.newClassTypeInfo( + `type`.scalaVirtualMachine, + _: ClassType + ) + val DefaultNewInterfaceTypeProfile: JavaTypeInfo => InterfaceType => InterfaceTypeInfo = + `type` => `type`.infoProducer.newInterfaceTypeInfo( + `type`.scalaVirtualMachine, + _: InterfaceType + ) + val DefaultNewPrimitiveTypeProfile: JavaTypeInfo => PrimitiveType => PrimitiveTypeInfo = + `type` => `type`.infoProducer.newPrimitiveTypeInfo( + `type`.scalaVirtualMachine, + _: PrimitiveType + ) + val DefaultNewVoidTypeProfile: JavaTypeInfo => VoidType => PrimitiveTypeInfo = + `type` => `type`.infoProducer.newPrimitiveTypeInfo( + `type`.scalaVirtualMachine, + _: VoidType + ) + + /** + * Creates a new converter from the provided type. + * @param `type` The type to convert + * @return The converter capable of converting the provided type + */ + def from(`type`: JavaTypeInfo): JavaTypeConverter = + new JavaTypeConverter(`type`)() +} + +class JavaTypeConverter private(private val `type`: JavaTypeInfo)( + private val newReferenceTypeProfile: ReferenceType => ReferenceTypeInfo = + DefaultNewReferenceTypeProfile(`type`), + private val newArrayTypeProfile: ArrayType => ArrayTypeInfo = + DefaultNewArrayTypeProfile(`type`), + private val newClassTypeProfile: ClassType => ClassTypeInfo = + DefaultNewClassTypeProfile(`type`), + private val newInterfaceTypeProfile: InterfaceType => InterfaceTypeInfo = + DefaultNewInterfaceTypeProfile(`type`), + private val newPrimitiveTypeProfile: PrimitiveType => PrimitiveTypeInfo = + DefaultNewPrimitiveTypeProfile(`type`), + private val newVoidTypeProfile: VoidType => PrimitiveTypeInfo = + DefaultNewVoidTypeProfile(`type`) +) extends TypeConverter { + /** + * Creates a copy of the converter that will use the specified converter + * functions over the current instances. + * @param newReferenceTypeProfile + * @param newArrayTypeProfile + * @param newClassTypeProfile + * @param newInterfaceTypeProfile + * @param newPrimitiveTypeProfile + * @param newVoidTypeProfile + * @return The new converter instance + */ + def using( + newReferenceTypeProfile: ReferenceType => ReferenceTypeInfo = newReferenceTypeProfile, + newArrayTypeProfile: ArrayType => ArrayTypeInfo = newArrayTypeProfile, + newClassTypeProfile: ClassType => ClassTypeInfo = newClassTypeProfile, + newInterfaceTypeProfile: InterfaceType => InterfaceTypeInfo = newInterfaceTypeProfile, + newPrimitiveTypeProfile: PrimitiveType => PrimitiveTypeInfo = newPrimitiveTypeProfile, + newVoidTypeProfile: VoidType => PrimitiveTypeInfo = newVoidTypeProfile + ): JavaTypeConverter = new JavaTypeConverter(`type`)( + newReferenceTypeProfile = newReferenceTypeProfile, + newArrayTypeProfile = newArrayTypeProfile, + newClassTypeProfile = newClassTypeProfile, + newInterfaceTypeProfile = newInterfaceTypeProfile, + newPrimitiveTypeProfile = newPrimitiveTypeProfile, + newVoidTypeProfile = newVoidTypeProfile + ) + + /** + * Returns the type as an array type (profile). + * + * @return The array type profile wrapping this type + */ + @throws[AssertionError] + override def toArrayType: ArrayTypeInfo = { + assert(`type`.isArrayType, "Type must be an array type!") + newArrayTypeProfile(`type`._type.asInstanceOf[ArrayType]) + } + + /** + * Returns the type as an class type (profile). + * + * @return The class type profile wrapping this type + */ + @throws[AssertionError] + override def toClassType: ClassTypeInfo = { + assert(`type`.isClassType, "Type must be a class type!") + newClassTypeProfile(`type`._type.asInstanceOf[ClassType]) + } + + /** + * Returns the type as an interface type (profile). + * + * @return The interface type profile wrapping this type + */ + @throws[AssertionError] + override def toInterfaceType: InterfaceTypeInfo = { + assert(`type`.isInterfaceType, "Type must be an interface type!") + newInterfaceTypeProfile(`type`._type.asInstanceOf[InterfaceType]) + } + + /** + * Returns the type as an reference type (profile). + * + * @return The reference type profile wrapping this type + */ + @throws[AssertionError] + override def toReferenceType: ReferenceTypeInfo = { + assert(`type`.isReferenceType, "Type must be a reference type!") + newReferenceTypeProfile(`type`._type.asInstanceOf[ReferenceType]) + } + + /** + * Returns the type as an primitive type (profile). + * + * @return The primitive type profile wrapping this type + */ + @throws[AssertionError] + override def toPrimitiveType: PrimitiveTypeInfo = { + assert(`type`.isPrimitiveType, "Type must be a primitive type!") + `type`._type match { + case p: PrimitiveType => newPrimitiveTypeProfile(p) + case v: VoidType => newPrimitiveTypeProfile(v) + } + } +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeInfo.scala index caf8c95c..7fd9bbd1 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaTypeInfo.scala @@ -22,8 +22,8 @@ object JavaTypeInfo { */ class JavaTypeInfo( val scalaVirtualMachine: ScalaVirtualMachine, - protected val infoProducer: InfoProducer, - private val _type: Type + protected[info] val infoProducer: InfoProducer, + private[info] val _type: Type ) extends TypeInfo { /** * Returns whether or not this info profile represents the low-level Java @@ -121,106 +121,6 @@ class JavaTypeInfo( */ override def isNullType: Boolean = _type == null - /** - * Returns the type as an array type (profile). - * - * @return The array type profile wrapping this type - */ - @throws[AssertionError] - override def toArrayType: ArrayTypeInfo = { - assert(isArrayType, "Type must be an array type!") - newArrayTypeProfile(_type.asInstanceOf[ArrayType]) - } - - /** - * Returns the type as an class type (profile). - * - * @return The class type profile wrapping this type - */ - @throws[AssertionError] - override def toClassType: ClassTypeInfo = { - assert(isClassType, "Type must be a class type!") - newClassTypeProfile(_type.asInstanceOf[ClassType]) - } - - /** - * Returns the type as an interface type (profile). - * - * @return The interface type profile wrapping this type - */ - @throws[AssertionError] - override def toInterfaceType: InterfaceTypeInfo = { - assert(isInterfaceType, "Type must be an interface type!") - newInterfaceTypeProfile(_type.asInstanceOf[InterfaceType]) - } - - /** - * Returns the type as an reference type (profile). - * - * @return The reference type profile wrapping this type - */ - @throws[AssertionError] - override def toReferenceType: ReferenceTypeInfo = { - assert(isReferenceType, "Type must be a reference type!") - newReferenceTypeProfile(_type.asInstanceOf[ReferenceType]) - } - - /** - * Returns the type as an primitive type (profile). - * - * @return The primitive type profile wrapping this type - */ - @throws[AssertionError] - override def toPrimitiveType: PrimitiveTypeInfo = { - assert(isPrimitiveType, "Type must be a primitive type!") - _type match { - case p: PrimitiveType => newPrimitiveTypeProfile(p) - case v: VoidType => newPrimitiveTypeProfile(v) - } - } - protected def newTypeProfile(_type: Type): TypeInfo = infoProducer.newTypeInfo(scalaVirtualMachine, _type) - - protected def newReferenceTypeProfile( - referenceType: ReferenceType - ): ReferenceTypeInfo = infoProducer.newReferenceTypeInfo( - scalaVirtualMachine, - referenceType - ) - - protected def newArrayTypeProfile( - arrayType: ArrayType - ): ArrayTypeInfo = infoProducer.newArrayTypeInfo( - scalaVirtualMachine, - arrayType - ) - - protected def newClassTypeProfile( - classType: ClassType - ): ClassTypeInfo = infoProducer.newClassTypeInfo( - scalaVirtualMachine, - classType - ) - - protected def newInterfaceTypeProfile( - interfaceType: InterfaceType - ): InterfaceTypeInfo = infoProducer.newInterfaceTypeInfo( - scalaVirtualMachine, - interfaceType - ) - - protected def newPrimitiveTypeProfile( - primitiveType: PrimitiveType - ): PrimitiveTypeInfo = infoProducer.newPrimitiveTypeInfo( - scalaVirtualMachine, - primitiveType - ) - - protected def newPrimitiveTypeProfile( - voidType: VoidType - ): PrimitiveTypeInfo = infoProducer.newPrimitiveTypeInfo( - scalaVirtualMachine, - voidType - ) } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueConverter.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueConverter.scala new file mode 100644 index 00000000..57347fc8 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueConverter.scala @@ -0,0 +1,181 @@ +package org.scaladebugger.api.profiles.java.info + +import com.sun.jdi._ +import org.scaladebugger.api.profiles.traits.info._ +import JavaValueConverter._ + +object JavaValueConverter { + val DefaultNewPrimitiveInfo: JavaValueInfo => PrimitiveValue => PrimitiveInfo = + value => value.infoProducer.newPrimitiveInfo(value.scalaVirtualMachine, _: PrimitiveValue) + val DefaultNewVoidInfo: JavaValueInfo => VoidValue => PrimitiveInfo = + value => value.infoProducer.newPrimitiveInfo(value.scalaVirtualMachine, _: VoidValue) + val DefaultNewObjectInfo: JavaValueInfo => ObjectReference => ObjectInfo = + value => value.infoProducer.newObjectInfo(value.scalaVirtualMachine, _: ObjectReference)() + val DefaultNewStringInfo: JavaValueInfo => StringReference => StringInfo = + value => value.infoProducer.newStringInfo(value.scalaVirtualMachine, _: StringReference)() + val DefaultNewArrayInfo: JavaValueInfo => ArrayReference => ArrayInfo = + value => value.infoProducer.newArrayInfo(value.scalaVirtualMachine, _: ArrayReference)() + val DefaultNewClassLoaderInfo: JavaValueInfo => ClassLoaderReference => ClassLoaderInfo = + value => value.infoProducer.newClassLoaderInfo(value.scalaVirtualMachine, _: ClassLoaderReference)() + val DefaultNewClassObjectInfo: JavaValueInfo => ClassObjectReference => ClassObjectInfo = + value => value.infoProducer.newClassObjectInfo(value.scalaVirtualMachine, _: ClassObjectReference)() + val DefaultNewThreadGroupInfo: JavaValueInfo => ThreadGroupReference => ThreadGroupInfo = + value => value.infoProducer.newThreadGroupInfo(value.scalaVirtualMachine, _: ThreadGroupReference)() + val DefaultNewThreadInfo: JavaValueInfo => ThreadReference => ThreadInfo = + value => value.infoProducer.newThreadInfo(value.scalaVirtualMachine, _: ThreadReference)() + + /** + * Creates a new converter from the provided value. + * @param value The value to convert + * @return The converter capable of converting the provided value + */ + def from(value: JavaValueInfo): JavaValueConverter = + new JavaValueConverter(value)() +} + +class JavaValueConverter private(private val value: JavaValueInfo)( + private val newPrimitiveInfo: PrimitiveValue => PrimitiveInfo = + DefaultNewPrimitiveInfo(value), + private val newVoidInfo: VoidValue => PrimitiveInfo = + DefaultNewVoidInfo(value), + private val newObjectInfo: ObjectReference => ObjectInfo = + DefaultNewObjectInfo(value), + private val newStringInfo: StringReference => StringInfo = + DefaultNewStringInfo(value), + private val newArrayInfo: ArrayReference => ArrayInfo = + DefaultNewArrayInfo(value), + private val newClassLoaderInfo: ClassLoaderReference => ClassLoaderInfo = + DefaultNewClassLoaderInfo(value), + private val newClassObjectInfo: ClassObjectReference => ClassObjectInfo = + DefaultNewClassObjectInfo(value), + private val newThreadGroupInfo: ThreadGroupReference => ThreadGroupInfo = + DefaultNewThreadGroupInfo(value), + private val newThreadInfo: ThreadReference => ThreadInfo = + DefaultNewThreadInfo(value) +) extends ValueConverter { + /** + * Creates a copy of the converter that will use the specified converter + * functions over the current instances. + * @param newPrimitiveInfo + * @param newVoidInfo + * @param newObjectInfo + * @param newStringInfo + * @param newArrayInfo + * @param newClassLoaderInfo + * @param newClassObjectInfo + * @param newThreadGroupInfo + * @param newThreadInfo + * @return The new converter instance + */ + def using( + newPrimitiveInfo: PrimitiveValue => PrimitiveInfo = newPrimitiveInfo, + newVoidInfo: VoidValue => PrimitiveInfo = newVoidInfo, + newObjectInfo: ObjectReference => ObjectInfo = newObjectInfo, + newStringInfo: StringReference => StringInfo = newStringInfo, + newArrayInfo: ArrayReference => ArrayInfo = newArrayInfo, + newClassLoaderInfo: ClassLoaderReference => ClassLoaderInfo = newClassLoaderInfo, + newClassObjectInfo: ClassObjectReference => ClassObjectInfo = newClassObjectInfo, + newThreadGroupInfo: ThreadGroupReference => ThreadGroupInfo = newThreadGroupInfo, + newThreadInfo: ThreadReference => ThreadInfo = newThreadInfo + ): JavaValueConverter = new JavaValueConverter(value)( + newPrimitiveInfo = newPrimitiveInfo, + newVoidInfo = newVoidInfo, + newObjectInfo = newObjectInfo, + newStringInfo = newStringInfo, + newArrayInfo = newArrayInfo, + newClassLoaderInfo = newClassLoaderInfo, + newClassObjectInfo = newClassObjectInfo, + newThreadGroupInfo = newThreadGroupInfo + ) + + /** + * Returns the value as an array (profile). + * + * @return The array profile wrapping this value + */ + @throws[AssertionError] + override def toArrayInfo: ArrayInfo = { + assert(value.isArray, "Value must be an array!") + newArrayInfo(value._value.asInstanceOf[ArrayReference]) + } + + /** + * Returns the value as a class loader (profile). + * + * @return The class loader profile wrapping this value + */ + @throws[AssertionError] + override def toClassLoaderInfo: ClassLoaderInfo = { + assert(value.isClassLoader, "Value must be a class loader!") + newClassLoaderInfo(value._value.asInstanceOf[ClassLoaderReference]) + } + + /** + * Returns the value as a class object (profile). + * + * @return The class object profile wrapping this value + */ + @throws[AssertionError] + override def toClassObjectInfo: ClassObjectInfo = { + assert(value.isClassObject, "Value must be a class object!") + newClassObjectInfo(value._value.asInstanceOf[ClassObjectReference]) + } + + /** + * Returns the value as a thread (profile). + * + * @return The thread profile wrapping this value + */ + @throws[AssertionError] + override def toThreadInfo: ThreadInfo = { + assert(value.isThread, "Value must be a thread!") + newThreadInfo(value._value.asInstanceOf[ThreadReference]) + } + + /** + * Returns the value as a thread group (profile). + * + * @return The thread group profile wrapping this value + */ + @throws[AssertionError] + override def toThreadGroupInfo: ThreadGroupInfo = { + assert(value.isThreadGroup, "Value must be a thread group!") + newThreadGroupInfo(value._value.asInstanceOf[ThreadGroupReference]) + } + + /** + * Returns the value as an object (profile). + * + * @return The object profile wrapping this value + */ + @throws[AssertionError] + override def toObjectInfo: ObjectInfo = { + assert(value.isObject, "Value must be an object!") + newObjectInfo(value._value.asInstanceOf[ObjectReference]) + } + + /** + * Returns the value as a string (profile). + * + * @return The string profile wrapping this value + */ + @throws[AssertionError] + override def toStringInfo: StringInfo = { + assert(value.isString, "Value must be a string!") + newStringInfo(value._value.asInstanceOf[StringReference]) + } + + /** + * Returns the value as a primitive (profile). + * + * @return The primitive profile wrapping this value + */ + @throws[AssertionError] + override def toPrimitiveInfo: PrimitiveInfo = { + assert(value.isPrimitive, "Value must be a primitive!") + value._value match { + case p: PrimitiveValue => newPrimitiveInfo(p) + case v: VoidValue => newVoidInfo(v) + } + } +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueInfo.scala index bb3758f5..249da893 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/java/info/JavaValueInfo.scala @@ -21,8 +21,8 @@ object JavaValueInfo { */ class JavaValueInfo( val scalaVirtualMachine: ScalaVirtualMachine, - protected val infoProducer: InfoProducer, - private val _value: Value + protected[info] val infoProducer: InfoProducer, + private[info] val _value: Value ) extends ValueInfo { /** * Returns whether or not this info profile represents the low-level Java @@ -74,97 +74,6 @@ class JavaValueInfo( else null } - /** - * Returns the value as an array (profile). - * - * @return The array profile wrapping this value - */ - @throws[AssertionError] - override def toArrayInfo: ArrayInfo = { - assert(isArray, "Value must be an array!") - newArrayProfile(_value.asInstanceOf[ArrayReference]) - } - - /** - * Returns the value as a class loader (profile). - * - * @return The class loader profile wrapping this value - */ - @throws[AssertionError] - override def toClassLoaderInfo: ClassLoaderInfo = { - assert(isClassLoader, "Value must be a class loader!") - newClassLoaderProfile(_value.asInstanceOf[ClassLoaderReference]) - } - - /** - * Returns the value as a class object (profile). - * - * @return The class object profile wrapping this value - */ - @throws[AssertionError] - override def toClassObjectInfo: ClassObjectInfo = { - assert(isClassObject, "Value must be a class object!") - newClassObjectProfile(_value.asInstanceOf[ClassObjectReference]) - } - - /** - * Returns the value as a thread (profile). - * - * @return The thread profile wrapping this value - */ - @throws[AssertionError] - override def toThreadInfo: ThreadInfo = { - assert(isThread, "Value must be a thread!") - newThreadProfile(_value.asInstanceOf[ThreadReference]) - } - - /** - * Returns the value as a thread group (profile). - * - * @return The thread group profile wrapping this value - */ - @throws[AssertionError] - override def toThreadGroupInfo: ThreadGroupInfo = { - assert(isThreadGroup, "Value must be a thread group!") - newThreadGroupProfile(_value.asInstanceOf[ThreadGroupReference]) - } - - /** - * Returns the value as an object (profile). - * - * @return The object profile wrapping this value - */ - @throws[AssertionError] - override def toObjectInfo: ObjectInfo = { - assert(isObject, "Value must be an object!") - newObjectProfile(_value.asInstanceOf[ObjectReference]) - } - - /** - * Returns the value as a string (profile). - * - * @return The string profile wrapping this value - */ - @throws[AssertionError] - override def toStringInfo: StringInfo = { - assert(isString, "Value must be a string!") - newStringProfile(_value.asInstanceOf[StringReference]) - } - - /** - * Returns the value as a primitive (profile). - * - * @return The primitive profile wrapping this value - */ - @throws[AssertionError] - override def toPrimitiveInfo: PrimitiveInfo = { - assert(isPrimitive, "Value must be a primitive!") - _value match { - case p: PrimitiveValue => newPrimitiveProfile(p) - case v: VoidValue => newPrimitiveProfile(v) - } - } - /** * Returns whether or not this value represents a primitive. * @@ -243,33 +152,6 @@ class JavaValueInfo( */ override def isNull: Boolean = _value == null - protected def newPrimitiveProfile(primitiveValue: PrimitiveValue): PrimitiveInfo = - infoProducer.newPrimitiveInfo(scalaVirtualMachine, primitiveValue) - - protected def newPrimitiveProfile(voidValue: VoidValue): PrimitiveInfo = - infoProducer.newPrimitiveInfo(scalaVirtualMachine, voidValue) - - protected def newObjectProfile(objectReference: ObjectReference): ObjectInfo = - infoProducer.newObjectInfo(scalaVirtualMachine, objectReference)() - - protected def newStringProfile(stringReference: StringReference): StringInfo = - infoProducer.newStringInfo(scalaVirtualMachine, stringReference)() - - protected def newArrayProfile(arrayReference: ArrayReference): ArrayInfo = - infoProducer.newArrayInfo(scalaVirtualMachine, arrayReference)() - - protected def newClassLoaderProfile(classLoaderReference: ClassLoaderReference): ClassLoaderInfo = - infoProducer.newClassLoaderInfo(scalaVirtualMachine, classLoaderReference)() - - protected def newClassObjectProfile(classObjectReference: ClassObjectReference): ClassObjectInfo = - infoProducer.newClassObjectInfo(scalaVirtualMachine, classObjectReference)() - - protected def newThreadGroupProfile(threadGroupReference: ThreadGroupReference): ThreadGroupInfo = - infoProducer.newThreadGroupInfo(scalaVirtualMachine, threadGroupReference)() - - protected def newThreadProfile(threadReference: ThreadReference): ThreadInfo = - infoProducer.newThreadInfo(scalaVirtualMachine, threadReference)() - protected def newTypeProfile(_type: Type): TypeInfo = infoProducer.newTypeInfo(scalaVirtualMachine, _type) } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala index bd30404d..5ff8b5ad 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ArrayReference import org.scaladebugger.api.profiles.traits.info.ArrayInfo._ import org.scaladebugger.macros.freeze.CanFreeze.ReturnType diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala index e03edf6c..4eafb320 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ArrayTypeInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ArrayType import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CastNotPossibleException.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CastNotPossibleException.scala index 6933f5b5..b5ce0cc3 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CastNotPossibleException.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CastNotPossibleException.scala @@ -1,4 +1,5 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file /** * Represents an exception that occurs when a local value is trying to be diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala index 50d46a83..e6427587 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassLoaderInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ClassLoaderReference import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala index 1b941987..157bdee1 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassObjectInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ClassObjectReference import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala index 7b7692f6..491321dc 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ClassTypeInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ClassType import org.scaladebugger.api.lowlevel.JDIArgument import org.scaladebugger.macros.freeze.CanFreeze.ReturnType diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala index 395c38fa..378b6a43 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CommonInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Mirror import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} @@ -7,7 +8,7 @@ import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents common methods between information-gathering profiles. */ -@Freezable +//@Freezable trait CommonInfo extends JavaInfo { /** * Returns the Scala virtual machine containing this instance. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala index 494529de..21b7e926 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/CreateInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} import scala.util.Try diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala index b73de387..dd0db463 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FieldVariableInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Field import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala index 4d532a5a..3cb94105 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/FrameInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.StackFrame import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala index fcb8166e..c201b985 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/GrabInfoProfile.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import java.util.NoSuchElementException import com.sun.jdi._ diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala index f2593185..0e2a1045 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/IndexedVariableInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InfoProducer.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InfoProducer.scala index 41918453..2f05bf7c 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InfoProducer.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InfoProducer.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi._ import org.scaladebugger.api.profiles.traits.info.events.EventInfoProducer import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala index cc5afea9..c9753983 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/InterfaceTypeInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.InterfaceType import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala index 44947979..24b438f2 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala @@ -1,12 +1,13 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} /** * Represents a profile that provides common methods to convert info profiles * to their low-level Java equivalents. */ -@Freezable +//@Freezable trait JavaInfo extends java.io.Serializable { /** * Returns whether or not this info profile represents the low-level Java diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala index d4908eb4..12e292a0 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/LocationInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Location import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine import org.scaladebugger.macros.freeze.CanFreeze.ReturnType diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala index 1ad3ad7f..82beb870 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MethodInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Method import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MiscInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MiscInfo.scala index 1b3ca160..1cfc51e9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MiscInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/MiscInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import org.scaladebugger.api.virtualmachines.ScalaVirtualMachine /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala index f60e9a3e..34d26676 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ObjectInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ObjectReference import org.scaladebugger.api.lowlevel.JDIArgument import org.scaladebugger.macros.freeze.CanFreeze.ReturnType diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala index 7f02b8ec..eac8f021 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveInfo.scala @@ -1,6 +1,7 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Value import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} @@ -10,7 +11,7 @@ import scala.util.{Failure, Success, Try} /** * Represents information about a primitive value. */ -@Freezable +//@Freezable trait PrimitiveInfo extends ValueInfo with CommonInfo { /** * Converts the current profile instance to a representation of diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala index 0c07c8b0..645b8f15 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/PrimitiveTypeInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala index 4916841f..855a9462 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ReferenceTypeInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ReferenceType import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala index 499a30aa..b72b751a 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/StringInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.StringReference import org.scaladebugger.macros.freeze.{CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala index 746d5b1b..66850ed4 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadGroupInfo.scala @@ -1,6 +1,7 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ThreadGroupReference import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala index 50576856..0b907eb6 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.ThreadReference import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala index cef33537..012f52d9 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ThreadStatusInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import org.scaladebugger.macros.freeze.{CanFreeze, Freezable} /** diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeChecker.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeChecker.scala index 6e84b03a..adb2b398 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeChecker.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeChecker.scala @@ -1,4 +1,5 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file /** * Represents the interface for type-checking based interactions. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeConverter.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeConverter.scala new file mode 100644 index 00000000..316b3730 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeConverter.scala @@ -0,0 +1,88 @@ +package org.scaladebugger.api.profiles.traits.info + +import org.scaladebugger.macros.freeze.CanFreeze +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + +import scala.util.Try + +trait TypeConverter { + /** + * Returns the type as an array type (profile). + * + * @return The array type profile wrapping this type + */ + @CanFreeze(ReturnType.FreezeObject) + def toArrayType: ArrayTypeInfo + + /** + * Returns the type as an array type (profile). + * + * @return Success containing the array type profile wrapping this type, + * otherwise a failure + */ + def tryToArrayType: Try[ArrayTypeInfo] = Try(toArrayType) + + /** + * Returns the type as an class type (profile). + * + * @return The class type profile wrapping this type + */ + @CanFreeze(ReturnType.FreezeObject) + def toClassType: ClassTypeInfo + + /** + * Returns the type as an class type (profile). + * + * @return Success containing the class type profile wrapping this type, + * otherwise a failure + */ + def tryToClassType: Try[ClassTypeInfo] = Try(toClassType) + + /** + * Returns the type as an interface type (profile). + * + * @return The interface type profile wrapping this type + */ + @CanFreeze(ReturnType.FreezeObject) + def toInterfaceType: InterfaceTypeInfo + + /** + * Returns the type as an interface type (profile). + * + * @return Success containing the interface type profile wrapping this type, + * otherwise a failure + */ + def tryToInterfaceType: Try[InterfaceTypeInfo] = Try(toInterfaceType) + + /** + * Returns the type as an reference type (profile). + * + * @return The reference type profile wrapping this type + */ + @CanFreeze(ReturnType.FreezeObject) + def toReferenceType: ReferenceTypeInfo + + /** + * Returns the type as an reference type (profile). + * + * @return Success containing the reference type profile wrapping this type, + * otherwise a failure + */ + def tryToReferenceType: Try[ReferenceTypeInfo] = Try(toReferenceType) + + /** + * Returns the type as an primitive type (profile). + * + * @return The primitive type profile wrapping this type + */ + @CanFreeze(ReturnType.FreezeObject) + def toPrimitiveType: PrimitiveTypeInfo + + /** + * Returns the type as an primitive type (profile). + * + * @return Success containing the primitive type profile wrapping this type, + * otherwise a failure + */ + def tryToPrimitiveType: Try[PrimitiveTypeInfo] = Try(toPrimitiveType) +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala index d988f003..0f1b2b4b 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/TypeInfo.scala @@ -1,7 +1,7 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Type -import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} import scala.util.Try @@ -9,7 +9,7 @@ import scala.util.Try /** * Represents the interface for retrieving type-based information. */ -@Freezable +//@Freezable trait TypeInfo extends CommonInfo { /** * Converts the current profile instance to a representation of @@ -158,86 +158,6 @@ trait TypeInfo extends CommonInfo { @CanFreeze def isNullType: Boolean - /** - * Returns the type as an array type (profile). - * - * @return The array type profile wrapping this type - */ - @CanFreeze(ReturnType.FreezeObject) - def toArrayType: ArrayTypeInfo - - /** - * Returns the type as an array type (profile). - * - * @return Success containing the array type profile wrapping this type, - * otherwise a failure - */ - def tryToArrayType: Try[ArrayTypeInfo] = Try(toArrayType) - - /** - * Returns the type as an class type (profile). - * - * @return The class type profile wrapping this type - */ - @CanFreeze(ReturnType.FreezeObject) - def toClassType: ClassTypeInfo - - /** - * Returns the type as an class type (profile). - * - * @return Success containing the class type profile wrapping this type, - * otherwise a failure - */ - def tryToClassType: Try[ClassTypeInfo] = Try(toClassType) - - /** - * Returns the type as an interface type (profile). - * - * @return The interface type profile wrapping this type - */ - @CanFreeze(ReturnType.FreezeObject) - def toInterfaceType: InterfaceTypeInfo - - /** - * Returns the type as an interface type (profile). - * - * @return Success containing the interface type profile wrapping this type, - * otherwise a failure - */ - def tryToInterfaceType: Try[InterfaceTypeInfo] = Try(toInterfaceType) - - /** - * Returns the type as an reference type (profile). - * - * @return The reference type profile wrapping this type - */ - @CanFreeze(ReturnType.FreezeObject) - def toReferenceType: ReferenceTypeInfo - - /** - * Returns the type as an reference type (profile). - * - * @return Success containing the reference type profile wrapping this type, - * otherwise a failure - */ - def tryToReferenceType: Try[ReferenceTypeInfo] = Try(toReferenceType) - - /** - * Returns the type as an primitive type (profile). - * - * @return The primitive type profile wrapping this type - */ - @CanFreeze(ReturnType.FreezeObject) - def toPrimitiveType: PrimitiveTypeInfo - - /** - * Returns the type as an primitive type (profile). - * - * @return Success containing the primitive type profile wrapping this type, - * otherwise a failure - */ - def tryToPrimitiveType: Try[PrimitiveTypeInfo] = Try(toPrimitiveType) - /** * Attempts to cast the provided primitive to this type, performing any * necessary data conversions. diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/UnsupportedTypeException.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/UnsupportedTypeException.scala index 1a0289e8..702ac879 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/UnsupportedTypeException.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/UnsupportedTypeException.scala @@ -1,4 +1,5 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file /** * Represents an exception that occurs when a local value is trying to be diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueConverter.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueConverter.scala new file mode 100644 index 00000000..6f8f0498 --- /dev/null +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueConverter.scala @@ -0,0 +1,144 @@ +package org.scaladebugger.api.profiles.traits.info + +import org.scaladebugger.macros.freeze.CanFreeze +import org.scaladebugger.macros.freeze.CanFreeze.ReturnType + +import scala.util.Try + +trait ValueConverter { + /** + * Returns the value as a primitive (profile). + * + * @return Success containing the primitive profile wrapping this value, + * otherwise a failure + */ + def tryToPrimitiveInfo: Try[PrimitiveInfo] = Try(toPrimitiveInfo) + + /** + * Returns the value as a primitive (profile). + * + * @return The primitive profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toPrimitiveInfo: PrimitiveInfo + + /** + * Returns the value as a class loader (profile). + * + * @return Success containing the class loader profile wrapping this value, + * otherwise a failure + */ + def tryToClassLoaderInfo: Try[ClassLoaderInfo] = Try(toClassLoaderInfo) + + /** + * Returns the value as a class loader (profile). + * + * @return The class loader profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toClassLoaderInfo: ClassLoaderInfo + + /** + * Returns the value as a class object (profile). + * + * @return Success containing the class object profile wrapping this value, + * otherwise a failure + */ + def tryToClassObjectInfo: Try[ClassObjectInfo] = Try(toClassObjectInfo) + + /** + * Returns the value as a class object (profile). + * + * @return The class object profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toClassObjectInfo: ClassObjectInfo + + /** + * Returns the value as a thread group (profile). + * + * @return Success containing the thread group profile wrapping this value, + * otherwise a failure + */ + def tryToThreadGroupInfo: Try[ThreadGroupInfo] = Try(toThreadGroupInfo) + + /** + * Returns the value as a thread group (profile). + * + * @return The thread group profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toThreadGroupInfo: ThreadGroupInfo + + /** + * Returns the value as a thread (profile). + * + * @return Success containing the thread profile wrapping this value, + * otherwise a failure + */ + def tryToThreadInfo: Try[ThreadInfo] = Try(toThreadInfo) + + /** + * Returns the value as a thread (profile). + * + * @return The thread profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toThreadInfo: ThreadInfo + + /** + * Returns the value as an object (profile). + * + * @return Success containing the object profile wrapping this value, + * otherwise a failure + */ + def tryToObjectInfo: Try[ObjectInfo] = Try(toObjectInfo) + + /** + * Returns the value as an object (profile). + * + * @return The object profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toObjectInfo: ObjectInfo + + /** + * Returns the value as a string (profile). + * + * @return Success containing the string profile wrapping this value, + * otherwise a failure + */ + def tryToStringInfo: Try[StringInfo] = Try(toStringInfo) + + /** + * Returns the value as an string (profile). + * + * @return The string profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toStringInfo: StringInfo + + /** + * Returns the value as an array (profile). + * + * @return Success containing the array profile wrapping this value, + * otherwise a failure + */ + def tryToArrayInfo: Try[ArrayInfo] = Try(toArrayInfo) + + /** + * Returns the value as an array (profile). + * + * @return The array profile wrapping this value + */ + @throws[AssertionError] + @CanFreeze(ReturnType.FreezeObject) + def toArrayInfo: ArrayInfo +} diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala index a2f28192..d10826d2 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/ValueInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Value import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} @@ -9,7 +10,7 @@ import scala.util.Try /** * Represents information about a value. */ -@Freezable +//@Freezable trait ValueInfo extends CommonInfo { /** * Converts the current profile instance to a representation of @@ -141,142 +142,6 @@ trait ValueInfo extends CommonInfo { @CanFreeze def isVoid: Boolean - /** - * Returns the value as a primitive (profile). - * - * @return Success containing the primitive profile wrapping this value, - * otherwise a failure - */ - def tryToPrimitiveInfo: Try[PrimitiveInfo] = Try(toPrimitiveInfo) - - /** - * Returns the value as a primitive (profile). - * - * @return The primitive profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toPrimitiveInfo: PrimitiveInfo - - /** - * Returns the value as a class loader (profile). - * - * @return Success containing the class loader profile wrapping this value, - * otherwise a failure - */ - def tryToClassLoaderInfo: Try[ClassLoaderInfo] = Try(toClassLoaderInfo) - - /** - * Returns the value as a class loader (profile). - * - * @return The class loader profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toClassLoaderInfo: ClassLoaderInfo - - /** - * Returns the value as a class object (profile). - * - * @return Success containing the class object profile wrapping this value, - * otherwise a failure - */ - def tryToClassObjectInfo: Try[ClassObjectInfo] = Try(toClassObjectInfo) - - /** - * Returns the value as a class object (profile). - * - * @return The class object profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toClassObjectInfo: ClassObjectInfo - - /** - * Returns the value as a thread group (profile). - * - * @return Success containing the thread group profile wrapping this value, - * otherwise a failure - */ - def tryToThreadGroupInfo: Try[ThreadGroupInfo] = Try(toThreadGroupInfo) - - /** - * Returns the value as a thread group (profile). - * - * @return The thread group profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toThreadGroupInfo: ThreadGroupInfo - - /** - * Returns the value as a thread (profile). - * - * @return Success containing the thread profile wrapping this value, - * otherwise a failure - */ - def tryToThreadInfo: Try[ThreadInfo] = Try(toThreadInfo) - - /** - * Returns the value as a thread (profile). - * - * @return The thread profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toThreadInfo: ThreadInfo - - /** - * Returns the value as an object (profile). - * - * @return Success containing the object profile wrapping this value, - * otherwise a failure - */ - def tryToObjectInfo: Try[ObjectInfo] = Try(toObjectInfo) - - /** - * Returns the value as an object (profile). - * - * @return The object profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toObjectInfo: ObjectInfo - - /** - * Returns the value as a string (profile). - * - * @return Success containing the string profile wrapping this value, - * otherwise a failure - */ - def tryToStringInfo: Try[StringInfo] = Try(toStringInfo) - - /** - * Returns the value as an string (profile). - * - * @return The string profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toStringInfo: StringInfo - - /** - * Returns the value as an array (profile). - * - * @return Success containing the array profile wrapping this value, - * otherwise a failure - */ - def tryToArrayInfo: Try[ArrayInfo] = Try(toArrayInfo) - - /** - * Returns the value as an array (profile). - * - * @return The array profile wrapping this value - */ - @throws[AssertionError] - @CanFreeze(ReturnType.FreezeObject) - def toArrayInfo: ArrayInfo - /** * Returns a string presenting a better human-readable description of * the JDI instance. @@ -287,14 +152,14 @@ trait ValueInfo extends CommonInfo { Try { if (this.isNull) "null" else if (this.isVoid) "void" - else if (this.isArray) this.toArrayInfo.toPrettyString - else if (this.isString) this.toStringInfo.toPrettyString - else if (this.isClassLoader) this.toClassLoaderInfo.toPrettyString - else if (this.isClassObject) this.toClassObjectInfo.toPrettyString - else if (this.isThreadGroup) this.toThreadGroupInfo.toPrettyString - else if (this.isThread) this.toThreadInfo.toPrettyString - else if (this.isObject) this.toObjectInfo.toPrettyString - else if (this.isPrimitive) this.toPrimitiveInfo.toPrettyString + else if (this.isArray) "ARRAY TODO"//this.toArrayInfo.toPrettyString + else if (this.isString) "STRING TODO"//this.toStringInfo.toPrettyString + else if (this.isClassLoader) "CLASS LOADER TODO"//this.toClassLoaderInfo.toPrettyString + else if (this.isClassObject) "CLASS OBJECT TODO"//this.toClassObjectInfo.toPrettyString + else if (this.isThreadGroup) "THREAD GROUP TODO"//this.toThreadGroupInfo.toPrettyString + else if (this.isThread) "THREAD TODO"//this.toThreadInfo.toPrettyString + else if (this.isObject) "OBJECT TODO"//this.toObjectInfo.toPrettyString + else if (this.isPrimitive) "PRIMITIVE TODO"//this.toPrimitiveInfo.toPrettyString else "???" }.getOrElse("") } diff --git a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala index 1950709f..b6a11648 100644 --- a/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala +++ b/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/VariableInfo.scala @@ -1,5 +1,6 @@ package org.scaladebugger.api.profiles.traits.info +import acyclic.file import com.sun.jdi.Mirror import org.scaladebugger.macros.freeze.CanFreeze.ReturnType import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable} diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala index 876e4b3f..cbd00513 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/MacroUtils.scala @@ -149,16 +149,20 @@ import macrocompat.bundle } def classNameToTree(fqcn: String): Tree = { - if (fqcn == "...") { - tq"" + classNameToTree(fqcn, fallback = None) + } + + def classNameToTree(fqcn: String, fallback: Option[String]): Tree = { + if (fqcn == "..." || fqcn == "" || fqcn == "") { + fallback.map(f => classNameToTree(f)).getOrElse(tq"") } else { val classNames = fqcn.split("\\[|\\]").filter(_.nonEmpty) if (classNames.length <= 1) singleClassNameToTree(classNames.head) else { // NOTE: Assuming type param is only one, not more than one AppliedTypeTree( - classNameToTree(classNames.head), - classNames.tail.map(classNameToTree).toList + classNameToTree(classNames.head, fallback), + classNames.tail.map(n => classNameToTree(n, fallback)).toList ) } } diff --git a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala index 95b672df..031ae951 100644 --- a/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala +++ b/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala @@ -250,31 +250,26 @@ import org.scaladebugger.macros.MacroUtils val name = TermName(s"$$${m.name.decodedName.toString}") val retTypeStr = m.returnType.toString - val tpt = - if (retTypeStr == "" || retTypeStr == "...") { - tq"" - } else { - M.classNameToTree(retTypeStr) - } + val tpt = M.classNameToTree(retTypeStr, Some(traitTypeName.toString)) + println("FOR METHOD: " + name + " TYPE IS " + tpt) q"protected val $name: scala.util.Try[$tpt]" }) ++ otherMethods.flatMap { case q"$mods def $tname[..$tparams](...$paramss): $tpt = $expr" => val name = TermName(s"$$$tname") + val m = mods match { case mm: Modifiers => mm } if (paramss.nonEmpty) None - else Some(q"override protected val $name: scala.util.Try[$tpt] = scala.util.Try.apply(this.$tname)") + else if (m.hasFlag(Flag.OVERRIDE)) + Some(q"override protected val $name: scala.util.Try[$tpt] = scala.util.Try.apply(this.$tname)") + else + Some(q"protected val $name: scala.util.Try[$tpt] = scala.util.Try.apply(this.$tname)") } ++ iOtherMethods.flatMap(m => { val mname = TermName(m.name.decodedName.toString) val name = TermName(s"$$${m.name.decodedName.toString}") val retTypeStr = m.returnType.toString - val tpt = - if (retTypeStr == "" || retTypeStr == "...") { - tq"" - } else { - M.classNameToTree(retTypeStr) - } + val tpt = M.classNameToTree(retTypeStr, Some(traitTypeName.toString)) if (m.paramLists.nonEmpty) None else Some(q"override protected val $name: scala.util.Try[$tpt] = scala.util.Try.apply(this.$mname)") @@ -290,12 +285,7 @@ import org.scaladebugger.macros.MacroUtils val name = TermName(s"$$${m.name.decodedName.toString}") val retTypeStr = m.returnType.toString - val tpt = - if (retTypeStr == "" || retTypeStr == "...") { - tq"" - } else { - M.classNameToTree(retTypeStr) - } + val tpt = M.classNameToTree(retTypeStr, Some(traitTypeName.toString)) q"protected val $name: scala.util.Try[$tpt]" }) @@ -323,12 +313,7 @@ import org.scaladebugger.macros.MacroUtils val tname = TermName(m.name.decodedName.toString) val retTypeStr = m.returnType.toString - val tpt = - if (retTypeStr == "" || retTypeStr == "...") { - tq"" - } else { - M.classNameToTree(retTypeStr) - } + val tpt = M.classNameToTree(retTypeStr, Some(traitTypeName.toString)) val a = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) if (a.isEmpty) c.abort( @@ -397,12 +382,7 @@ import org.scaladebugger.macros.MacroUtils })) val retTypeStr = m.returnType.toString - val tpt = - if (retTypeStr == "" || retTypeStr == "...") { - tq"" - } else { - M.classNameToTree(retTypeStr) - } + val tpt = M.classNameToTree(retTypeStr, Some(traitTypeName.toString)) val aFreezable = m.annotations.find(_.tree.tpe =:= typeOf[CanFreeze]) val aUnfreezable = m.annotations.find(_.tree.tpe =:= typeOf[CannotFreeze])