
org.opalj.br.VirtualSourceElement.scala Maven / Gradle / Ivy
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
import scala.math.Ordered
/**
* A `VirtualSourceElement` is the representation of some source element that may be
* detached from the concrete source element that represents the implementation; that is,
* the virtual source element may not have a reference to the concrete element.
*
* @author Michael Eichberg
* @author Marco Torsello
*/
sealed abstract class VirtualSourceElement
extends SourceElement
with Ordered[VirtualSourceElement] {
override def attributes: Attributes = NoAttributes
final override def isVirtual = true
/**
* The "natural order" is VirtualClasses < VirtualFields < VirtualMethods.
*/
override def compare(that: VirtualSourceElement): Int
/**
* Returns the declared/declaring class type of this `VirtualSourceElement`.
* If this `VirtualSourceElement` is a [[VirtualClass]], the returned type is the
* declared class else it is the declaring class.
*/
def classType: ReferenceType
def toJava: String
/**
* Returns the best line number information available.
*/
def getLineNumber(project: ClassFileRepository): Option[Int]
}
/**
* Defines common helper functions related to [[VirtualSourceElement]]s.
*/
object VirtualSourceElement {
def asVirtualSourceElements(
classFiles: Iterable[ClassFile],
includeMethods: Boolean = true,
includeFields: Boolean = true
): Set[VirtualSourceElement] = {
var sourceElements: Set[VirtualSourceElement] = Set.empty
classFiles foreach { classFile =>
val classType = classFile.thisType
sourceElements += classFile.asVirtualClass
if (includeMethods)
classFile.methods.foreach(sourceElements += _.asVirtualMethod(classType))
if (includeFields)
classFile.fields.foreach(sourceElements += _.asVirtualField(classType))
}
sourceElements
}
}
/**
* Represents a class for which we have found some references but have not analyzed
* any class file or do not want to keep the reference to the underlying class file.
*
* @author Michael Eichberg
*/
final case class VirtualClass(thisType: ObjectType) extends VirtualSourceElement {
override def isClass: Boolean = true
override def classType: ObjectType = thisType
override def toJava: String = thisType.toJava
// Recall that the class may not be the only one defined in a source file!
override def getLineNumber(project: ClassFileRepository): Option[Int] = None
override def compare(that: VirtualSourceElement): Int = {
//x < 0 when this < that; x == 0 when this == that; x > 0 when this > that
that match {
case VirtualClass(thatType) => thisType.compare(thatType)
case _ => -1
}
}
override def hashCode: Int = thisType.id
/**
* Two objects of type `VirtualClass` are considered equal if they represent
* the same type.
*/
override def equals(other: Any): Boolean = {
other match {
case that: VirtualClass => this.thisType eq that.thisType
case _ => false
}
}
}
/**
* @author Michael Eichberg
*/
sealed abstract class VirtualClassMember extends VirtualSourceElement
/**
* Represents a field of a virtual class.
*
* @author Michael Eichberg
*/
final case class VirtualField(
declaringClassType: ObjectType,
name: String,
fieldType: FieldType
) extends VirtualClassMember {
override def isField: Boolean = true
override def classType: ObjectType = declaringClassType
override def toJava: String = declaringClassType.toJava+"{ "+fieldType.toJava+" "+name+"; }"
override def getLineNumber(project: ClassFileRepository): Option[Int] = None
override def compare(that: VirtualSourceElement): Int = {
// x < 0 when this < that; x == 0 when this == that; x > 0 when this > that
that match {
case _: VirtualClass =>
1
case that: VirtualField =>
if (this.declaringClassType eq that.declaringClassType) {
this.name.compareTo(that.name) match {
case 0 => this.fieldType.compare(that.fieldType)
case x => x
}
} else {
if (this.declaringClassType.id < that.declaringClassType.id)
-1
else
1
}
case _ /*VirtualMethod*/ =>
-1
}
}
override def hashCode: Int = {
(((declaringClassType.id * 41) + name.hashCode()) * 41) + fieldType.id
}
override def equals(other: Any): Boolean = {
other match {
case that: VirtualField =>
(this.declaringClassType eq that.declaringClassType) &&
(this.fieldType eq that.fieldType) &&
this.name == that.name
case _ => false
}
}
}
/**
* Represents a method of a virtual class.
*
* @author Michael Eichberg
*/
sealed class VirtualMethod(
val declaringClassType: ReferenceType,
val name: String,
val descriptor: MethodDescriptor
) extends VirtualClassMember {
override def isMethod: Boolean = true
override def classType: ReferenceType = declaringClassType
override def toJava: String = declaringClassType.toJava+"{ "+descriptor.toJava(name)+"; }"
override def getLineNumber(project: ClassFileRepository): Option[Int] = {
if (declaringClassType.isArrayType)
return None;
project.classFile(declaringClassType.asObjectType).flatMap { cf =>
cf.findMethod(name, descriptor).flatMap(m => m.body.flatMap(b => b.firstLineNumber))
}
}
override def compare(that: VirtualSourceElement): Int = {
// x < 0 when this < that; x == 0 when this == that; x > 0 when this > that
that match {
case that: VirtualMethod =>
if (this.declaringClassType eq that.declaringClassType) {
this.name.compareTo(that.name) match {
case 0 => this.descriptor.compare(that.descriptor)
case x => x
}
} else {
if (this.declaringClassType.id < that.declaringClassType.id)
-1
else
1
}
case _ =>
1
}
}
override def hashCode: Int = {
(((declaringClassType.id * 41) + name.hashCode()) * 41) + descriptor.hashCode()
}
override def equals(other: Any): Boolean = {
other match {
case that: VirtualMethod =>
(this.declaringClassType eq that.declaringClassType) &&
this.descriptor == that.descriptor &&
this.name == that.name
case _ => false
}
}
override def toString: String = {
s"VirtualMethod($declaringClassType,$name,$descriptor)"
}
}
object VirtualMethod {
def apply(
declaringClassType: ReferenceType,
name: String,
descriptor: MethodDescriptor
): VirtualMethod = {
new VirtualMethod(declaringClassType, name, descriptor)
}
def unapply(virtualMethod: VirtualMethod): Option[(ReferenceType, String, MethodDescriptor)] = {
Some((
virtualMethod.declaringClassType,
virtualMethod.name,
virtualMethod.descriptor
))
}
}
final case class VirtualForwardingMethod(
override val declaringClassType: ReferenceType,
override val name: String,
override val descriptor: MethodDescriptor,
target: Method
) extends VirtualMethod(declaringClassType, name, descriptor) {
override def toJava: String = declaringClassType.toJava+"{ "+descriptor.toJava(name)+" }"
override def hashCode: Opcode = (target.hashCode() * 41) + super.hashCode
override def equals(other: Any): Boolean = other match {
case that: VirtualForwardingMethod =>
(this.target eq that.target) &&
super.equals(other)
case _ => false
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy