/* BSD 2-Clause License - see OPAL/LICENSE for details. */ package org.opalj package br /** * An element of a [[Signature]] used to encode generic type information. * * @author Michael Eichberg * @author Andre Pacak */ trait SignatureElement { // RECALL: Void and the BaseTypes are also subtypes! def accept[T](sv: SignatureVisitor[T]): T /** * Converts this signature into its JVM representation. (See the JVM 5 or later * specification for further details.) */ def toJVMSignature: String } trait ReturnTypeSignature extends SignatureElement trait TypeSignature extends ReturnTypeSignature sealed trait ThrowsSignature extends SignatureElement /** * An attribute-level signature as defined in the JVM specification. * * To match `Signature` objects the predefined matchers/extractors can be used. * * @example * ==Example 1== * {{{ * interface Processor extends Function { /*empty*/ } * }}} * '''ClassSignature''': * `Ljava/lang/Object;Ljava/util/function/Function;` * {{{ * ClassSignature( * typeParameters=List(), * superClass=ClassTypeSignature(Some(java/lang/),SimpleClassTypeSignature(Object,List()),List()), * superInterfaces=List( * ClassTypeSignature( * Some(java/util/function/), * SimpleClassTypeSignature(Function, * List(ProperTypeArgument( * None, * ClassTypeSignature( * Some(java/lang/), * SimpleClassTypeSignature(Object,List()), * List())), * ProperTypeArgument( * None, * ClassTypeSignature( * Some(java/lang/), * SimpleClassTypeSignature(Void,List()), * List())))), * List()))) * }}} * * ==Example 2== * {{{ * interface Col { /*empty*/ } * }}} * '''ClassSignature''': * `Ljava/lang/Object;` * {{{ * ClassSignature( * typeParameters= * List( * FormalTypeParameter( * C, * Some(ClassTypeSignature( * Some(java/lang/),SimpleClassTypeSignature(Object,List()),List())), * List())), * superClass=ClassTypeSignature( * Some(java/lang/),SimpleClassTypeSignature(Object,List()),List()), * superInterfaces=List()) * }}} * * ==Example 3== * {{{ * interface ColObject extends Col { /*empty*/ } * }}} * '''ClassSignature''': * `Ljava/lang/Object;LCol;` * {{{ * ClassSignature( * typeParameters=List(), * superClass=ClassTypeSignature(Some(java/lang/),SimpleClassTypeSignature(Object,List()),List()), * superInterfaces=List( * ClassTypeSignature( * None, * SimpleClassTypeSignature( * Col, * List(ProperTypeArgument( * variance=None, * signature=ClassTypeSignature(Some(java/lang/),SimpleClassTypeSignature(Object,List()),List())) * )), * List()))) * }}} * * ==Example 4== * {{{ * interface ColError extends Col{/*empty*/} * }}} * '''ClassSignature''': * `Ljava/lang/Object;LCol;` * {{{ * ClassSignature( * typeParameters=List( * FormalTypeParameter( * E, * Some(ClassTypeSignature(Some(java/lang/),SimpleClassTypeSignature(Error,List()),List())),List())), * superClass=ClassTypeSignature(Some(java/lang/),SimpleClassTypeSignature(Object,List()),List()), * superInterfaces=List( * ClassTypeSignature( * None, * SimpleClassTypeSignature( * Col, * List(ProperTypeArgument(variance=None,signature=TypeVariableSignature(E)))), * List()))) * }}} * * ==Example 5== * {{{ * class Use { * // The following fields all have "ClassTypeSignatures" * Col ce = null; // Signature: LCol<*>; * Col co = null; // Signature: LCol; * Col cs = null; // Signature: LCol<-Ljava/io/Serializable;>; * Col> cc = null; // Signature: LCol<+Ljava/lang/Comparable<*>;>; * * MyCol> mco = new MyCol<>(); * MyCol>.MyInnerCol>> mico = this.mco.new MyInnerCol>>(); * // Signature: LMyCol;>.MyInnerCol;>;>; * } * }}} * * AST of `mico`: * {{{ * ClassSignature( * typeParameters=List(), * superClass=ClassTypeSignature( * None, * SimpleClassTypeSignature( * MyCol, * List(ProperTypeArgument( * variance=None, * signature=ClassTypeSignature( * Some(java/util/), * SimpleClassTypeSignature( * List, * List(ProperTypeArgument( * variance=None, * signature=ClassTypeSignature( * Some(java/lang/), * SimpleClassTypeSignature(Object,List()), * List())))), * List())))), * /*suffic=*/List(SimpleClassTypeSignature( * MyInnerCol, * List(ProperTypeArgument( * variance=None, * signature=ClassTypeSignature( * Some(java/lang/), * SimpleClassTypeSignature( * Comparable, * List(ProperTypeArgument( * variance=None, * signature=ClassTypeSignature( * Some(java/util/), * SimpleClassTypeSignature( * List, * List(ProperTypeArgument( * variance=None, * signature=ClassTypeSignature( * Some(java/lang/), * SimpleClassTypeSignature(Object,List()), * List())))), * List())))), * List())))))), * superInterfaces=List()) * }}} * * ==Matching Signatures== * '''Scala REPL''': * {{{ * val SignatureParser = org.opalj.br.reader.SignatureParser * val GenericType = org.opalj.br.GenericType * val SimpleGenericType = org.opalj.br.SimpleGenericType * val BasicClassTypeSignature = org.opalj.br.BasicClassTypeSignature * * SignatureParser.parseClassSignature("Ljava/lang/Object;LCol;").superInterfacesSignature.head match { case BasicClassTypeSignature(ot) => ot.toJava; case _ => null} * // res: String = Col * * SignatureParser.parseClassSignature("Ljava/lang/Object;LCol;").superInterfacesSignature.head match { case SimpleGenericType(bt,gt) => bt.toJava+"<"+gt.toJava+">"; case _ => null} * //res11: String = null * * scala> SignatureParser.parseFieldTypeSignature("LCol;") match { case SimpleGenericType(bt,ta) => bt.toJava+"<"+ta+">"; case _ => null} * res1: String = Col * * scala> SignatureParser.parseFieldTypeSignature("LCol;") match { case GenericType(bt,ta) => bt.toJava+"<"+ta+">"; case _ => null} * res2: String = Col * }}} */ sealed abstract class Signature extends SignatureElement with Attribute { override def similar(other: Attribute, config: SimilarityTestConfiguration): Boolean = { this == other } } object Signature { private[br] def formalTypeParametersToJVMSignature( formalTypeParameters: List[FormalTypeParameter] ): String = { if (formalTypeParameters.isEmpty) { "" } else { formalTypeParameters.map(_.toJVMSignature).mkString("<", "", ">") } } def unapply(s: Signature): Some[String] = Some(s.toJVMSignature) } import Signature.formalTypeParametersToJVMSignature /** * @see For matching signatures see [[Signature]]. */ case class ClassSignature( formalTypeParameters: List[FormalTypeParameter], superClassSignature: ClassTypeSignature, superInterfacesSignature: List[ClassTypeSignature] ) extends Signature { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def kindId: Int = ClassSignature.KindId override def toJVMSignature: String = { formalTypeParametersToJVMSignature(formalTypeParameters) + superClassSignature.toJVMSignature + superInterfacesSignature.map(_.toJVMSignature).mkString("") } override def toString: String = { "ClassSignature("+ formalTypeParameters.mkString("typeParameters=List(", ",", ")")+ ",superClass="+superClassSignature.toString + superInterfacesSignature.mkString(",superInterfaces=List(", ",", "))") } } object ClassSignature { final val KindId = 12 } /** * @see For matching signatures see [[Signature]]. */ case class MethodTypeSignature( formalTypeParameters: List[FormalTypeParameter], parametersTypeSignatures: List[TypeSignature], returnTypeSignature: ReturnTypeSignature, throwsSignature: List[ThrowsSignature] ) extends Signature { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def kindId: Int = MethodTypeSignature.KindId override def toJVMSignature: String = formalTypeParametersToJVMSignature(formalTypeParameters) + parametersTypeSignatures.map(_.toJVMSignature).mkString("(", "", ")") + returnTypeSignature.toJVMSignature + throwsSignature.map(s => s"^${s.toJVMSignature}").mkString("") } object MethodTypeSignature { final val KindId = 13 } /** * @see For matching signatures see [[Signature]]. */ sealed trait FieldTypeSignature extends Signature with TypeSignature object FieldTypeSignature { def unapply(signature: AnyRef): Boolean = signature.isInstanceOf[FieldTypeSignature] } object FieldTypeJVMSignature { def unapply(signature: FieldTypeSignature): Some[String] = Some(signature.toJVMSignature) } /** * @see For matching signatures see [[Signature]]. */ case class ArrayTypeSignature(typeSignature: TypeSignature) extends FieldTypeSignature { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def kindId: Int = ArrayTypeSignature.KindId override def toJVMSignature: String = "["+typeSignature.toJVMSignature } object ArrayTypeSignature { final val KindId = 14 } /** * @see For matching signatures see [[Signature]]. */ case class ClassTypeSignature( packageIdentifier: Option[String], simpleClassTypeSignature: SimpleClassTypeSignature, classTypeSignatureSuffix: List[SimpleClassTypeSignature] ) extends FieldTypeSignature with ThrowsSignature { def objectType: ObjectType = { val className = if (packageIdentifier.isDefined) new java.lang.StringBuilder(packageIdentifier.get) else new java.lang.StringBuilder() className.append(simpleClassTypeSignature.simpleName) classTypeSignatureSuffix foreach { ctss => className.append('$') className.append(ctss.simpleName) } ObjectType(className.toString) } def accept[T](sv: SignatureVisitor[T]) = sv.visit(this) override def kindId: Int = ClassTypeSignature.KindId override def toJVMSignature: String = { val packageName = packageIdentifier.getOrElse("") "L"+ packageName + simpleClassTypeSignature.toJVMSignature + (classTypeSignatureSuffix match { case Nil => "" case l => l.map(_.toJVMSignature).mkString(".", ".", "") })+ ";" } } object ClassTypeSignature { final val KindId = 15 } /** * @see For matching signatures see [[Signature]]. */ case class TypeVariableSignature( identifier: String ) extends FieldTypeSignature with ThrowsSignature { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def kindId: Int = TypeVariableSignature.KindId override def toJVMSignature: String = "T"+identifier+";" } object TypeVariableSignature { final val KindId = 16 } /** * @see For matching signatures see [[Signature]]. */ case class SimpleClassTypeSignature( simpleName: String, typeArguments: List[TypeArgument] ) { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) def toJVMSignature: String = { simpleName + (typeArguments match { case Nil => "" case l => l.map(_.toJVMSignature).mkString("<", "", ">") }) } } /** * @see For matching signatures see [[Signature]]. */ case class FormalTypeParameter( identifier: String, classBound: Option[FieldTypeSignature], interfaceBound: List[FieldTypeSignature] ) { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) def toJVMSignature: String = { identifier + (classBound match { case Some(x) => ":"+x.toJVMSignature case None => ":" }) + (interfaceBound match { case Nil => "" case l => ":"+l.map(_.toJVMSignature).mkString(":") }) } } /** * @see For matching signatures see [[Signature]]. */ sealed abstract class TypeArgument extends SignatureElement /** * @see For matching signatures see [[Signature]]. */ case class ProperTypeArgument( varianceIndicator: Option[VarianceIndicator], fieldTypeSignature: FieldTypeSignature ) extends TypeArgument { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def toJVMSignature: String = { (varianceIndicator match { case Some(x) => x.toJVMSignature case None => "" }) + fieldTypeSignature.toJVMSignature } override def toString: String = { "ProperTypeArgument"+ "(variance="+varianceIndicator+ ",signature="+fieldTypeSignature+ ")" } } /** * Indicates a TypeArgument's variance. */ sealed abstract class VarianceIndicator extends SignatureElement /** * If you have a declaration such as <? extends Entry> then the "? extends" part * is represented by the `CovariantIndicator`. * * @see For matching signatures see [[Signature]]. */ sealed abstract class CovariantIndicator extends VarianceIndicator { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def toJVMSignature: String = "+" } case object CovariantIndicator extends CovariantIndicator /** * A declaration such as is represented in class file signatures * by the ContravariantIndicator ("? super") and a FieldTypeSignature. * * @see For matching signatures see [[Signature]]. */ sealed abstract class ContravariantIndicator extends VarianceIndicator { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def toJVMSignature: String = "-" } case object ContravariantIndicator extends ContravariantIndicator /** * If a type argument is not further specified (e.g., List l = …), then the * type argument "?" is represented by this object. * * * @see For matching signatures see [[Signature]]. */ sealed abstract class Wildcard extends TypeArgument { def accept[T](sv: SignatureVisitor[T]): T = sv.visit(this) override def toJVMSignature: String = "*" } case object Wildcard extends Wildcard /** * Extractor/Matcher of the (potentially erased) `ObjectType` that is defined by a * `ClassTypeSignature`; ignores all further potential type parameters. * * @see For matching signatures see [[Signature]]. */ object BasicClassTypeSignature { def unapply(cts: ClassTypeSignature): Option[ObjectType] = { Some(cts.objectType) } } /** * Matches a [[ClassTypeSignature]] with a [[SimpleClassTypeSignature]] that does not define * a generic type. For example, `java.lang.Object`. * * @see For matching signatures see [[Signature]]. */ object ConcreteType { def unapply(cts: ClassTypeSignature): Option[ObjectType] = { cts match { case ClassTypeSignature(cpn, SimpleClassTypeSignature(csn, Nil), Nil) => Some(ObjectType(cpn.getOrElse("") + csn)) case _ => None } } } /** * Facilitates matching [[ProperTypeArgument]]s that define a single concrete/invariant * type that is not a generic type on its own. E.g., it can be used to match the * type argument of `List` and to extract the concrete type `Integer`. It * cannot be used to match, e.g., `List>`. * * @see For matching signatures see [[Signature]]. */ object ConcreteTypeArgument { def unapply(pta: ProperTypeArgument): Option[ObjectType] = { pta match { case ProperTypeArgument(None, ConcreteType(ot)) => Some(ot) case _ => None } } } /** * Facilitates matching [[ProperTypeArgument]]s that define an upper type bound. E.g., * a type bound which uses a CovarianceIndicator (`? extends`) such as in * `List`. * * @example * {{{ * val scts : SimpleClassTypeSignature = ... * scts.typeArguments.head match { * case UpperTypeBound(objectType) => ... * case _ => ... * } * }}} * * * @see For matching signatures see [[Signature]]. */ object UpperTypeBound { def unapply(pta: ProperTypeArgument): Option[ObjectType] = pta match { case ProperTypeArgument(Some(CovariantIndicator), ConcreteType(ot)) => Some(ot) case _ => None } } /** * Facilitates matching [[ProperTypeArgument]]s that define a lower type bound. E.g., * a type bound which uses a ContravarianceIndicator (`? super`) such as in * `List`. * * @example * matches, e.g., `List` * {{{ * val scts : SimpleClassTypeSignature = ... * scts.typeArguments.head match { * case LowerTypeBound(objectType) => ... * case _ => ... * } * }}} * * @see For matching signatures see [[Signature]]. */ object LowerTypeBound { def unapply(pta: ProperTypeArgument): Option[ObjectType] = pta match { case ProperTypeArgument(Some(ContravariantIndicator), ConcreteType(ot)) => Some(ot) case _ => None } } /** * Facilitates matching the (`VarianceIndicator`, `ObjectType`) that is defined * within a `ProperTypeArgument`. It matches ProperTypeArguments which define * `TypeArgument`s in the inner ClassTypeSignature. * * @example * matches e.g.: `List>` * {{{ * val scts : SimpleClassTypeSignature = ... * scts.typeArguments match { * case GenericTypeArgument(varInd, objectType) => ... * case _ => ... * } * }}} * * @see For matching signatures see [[Signature]]. */ object GenericTypeArgument { def unapply( pta: ProperTypeArgument ): Option[(Option[VarianceIndicator], ClassTypeSignature)] = { pta match { case ProperTypeArgument(variance, cts: ClassTypeSignature) => Some((variance, cts)) case _ => None } } } /** * Matches all [[ClassTypeSignature]]s which consists of * a [[SimpleClassTypeSignature]] with a non-empty List of TypeArguments ( * which consists of [[Wildcard]]s or [[ProperTypeArgument]]s) * * @see For matching signatures see [[Signature]]. */ object GenericType { def unapply(cts: ClassTypeSignature): Option[(ObjectType, List[TypeArgument])] = { cts match { case ClassTypeSignature( _, SimpleClassTypeSignature(_, typeArgs), Nil) if typeArgs.nonEmpty => Some((cts.objectType, typeArgs)) case _ => None } } } /** * Matches all [[ClassTypeSignature]]s which consists of * a [[SimpleClassTypeSignature]] with an optional list of TypeArguments ( * which consists of [[Wildcard]]s or [[ProperTypeArgument]]s) and a non-empty list of * [[SimpleClassTypeSignature]] (which encodes the suffix of the [[ClassTypeSignature]] for * inner classes) * * @see For matching signatures see [[Signature]]. */ object GenericTypeWithClassSuffix { def unapply( cts: ClassTypeSignature ): Option[(ObjectType, List[TypeArgument], List[SimpleClassTypeSignature])] = { cts match { case ClassTypeSignature( _, SimpleClassTypeSignature(_, typeArgs), suffix) if suffix.nonEmpty => Some((cts.objectType, typeArgs, suffix)) case _ => None } } } /** * Facilitates matching [[ClassTypeSignature]]s that define a simple generic type that * has a single type argument with a concrete type. * * @example * The following can be used to match, e.g., `List`. * {{{ * val f : Field = ... * f.fieldTypeSignature match { * case SimpleGenericType(ContainerType,ElementType) => ... * case _ => ... * } * }}} * * @author Michael Eichberg */ object SimpleGenericType { def unapply(cts: ClassTypeSignature): Option[(ObjectType, ObjectType)] = { cts match { case ClassTypeSignature( cpn, SimpleClassTypeSignature( csn, List(ProperTypeArgument(None, ConcreteType(tp)))), Nil ) => Some((ObjectType(cpn.getOrElse("") + csn), tp)) case _ => None } } }