SemmleCode Default Definitions

/**
 *  Standard library of SemmleCode queries
 *  Author: Semmle limited
 *  Version: 0.4.0
 */

/** -------- Predicates on AST elements -------- */

/** is X immediately above Y in the syntax tree? */
predicate hasChild(@element X, @element Y) {
  cus(Y,_,_,X,_,_) or
  not(enclInReftype(Y,_,_)) and classes(Y,_,X,_,_) or
  enclInReftype(Y,X,_) or
  not(enclInReftype(Y,_,_)) and interfaces(Y,_,X,_,_) or
  methods(Y,_,_,_,X,_,_) or
  constrs(Y,_,_,_,X,_,_) or
  params(Y,_,_,_,X,_,_) or
  fields(Y,_,_,X,_,_) or
  annots(Y,X,_,_) or
  typeVars(Y,_,_,X,_,_)
}

/** is X somewhere in package P?
*   put differently, is P an ancestor of X in the syntax tree? */
predicate isInPackage(@element X, @package P) {
  hasChild+(P,X)
}

/** does X have name Name? */
predicate hasName(@element X, string Name) {
	classes(X,Name,_,_,_) or
  interfaces(X,Name,_,_,_) or
  primitives(X,Name) or
  constrs(X,Name,_,_,_,_,_) or
  methods(X,Name,_,_,_,_,_) or
  fields(X,Name,_,_,_,_) or
  packages(X,Name) or
  cus(X,Name,_,_,_,_) or
  params(X,Name,_,_,_,_,_) or
  typeVars(X,Name,_,_,_,_) or
  arrays(X,Name,_,_,_,_) or
  modifiers(X,Name)
}

/** does X belong to compilation unit C? */
predicate inCompilationUnit(@element X, @cu C) {
  classes(X,_,_,C,_) or
  interfaces(X,_,_,C,_) or
  constrs(X,_,_,_,_,C,_) or
  methods(X,_,_,_,_,C,_) or
  fields(X,_,_,_,C,_) or
  params(X,_,_,_,_,C,_) or
  typeVars(X,_,_,_,C,_) or
  arrays(X,_,_,_,C,_)  or
  X = C
}

/** does X have location L? */
predicate hasLocation(@element X, @location L) {
  classes(X,_,_,_,L) or
  interfaces(X,_,_,_,L) or
  constrs(X,_,_,_,_,_,L) or
  methods(X,_,_,_,_,_,L) or
  fields(X,_,_,_,_,L) or
  cus(X,_,_,_,_,L) or
  exceptions(X,_,_,_,L) or
  params(X,_,_,_,_,_,L)
}

/** does expression X have location L? */
predicate exprHasLocation(@expression X, @location L) {
	readsField(X,_,_,_,L) or 
	writesField(X,_,_,_,L) or
	callsMethod(X,_,_,_,_,L) or
	callsConstr(X,_,_,_,_,L)
}

/** is accessor the callable that accesses the field in fieldAccess?*/
predicate hasAccessor(@fieldAccessExpr fieldAccess, @callable accessor) {
	readsField(fieldAccess,accessor,_,_,_) or
	writesField(fieldAccess,accessor,_,_,_)
}
/** is the accessee the field in fieldAccess?*/
predicate hasAccessee(@fieldAccessExpr fieldAccess, @field accessee) {
	readsField(fieldAccess,_,accessee,_,_) or
	writesField(fieldAccess,_,accessee,_,_)
}

/** does X have a modifier named Str?
*   example: (@method(M) and hasStrModifier(m,"private"))
*            selects private methods */
predicate hasStrModifier(@element X, string Str) {
  exists(@modifier Mod | hasModifier(X,Mod,_) and modifiers(Mod,Str))
}

/** -------- Predicates on types -------- */

/** is T a non-nested type in package P? */
predicate isTopLevelType(@reftype T, @package P) {
  classes(T,_,P,_,_) and not(enclInReftype(T,_,_)) or
  interfaces(T,_,P,_,_) and not(enclInReftype(T,_,_))
}

/** is T nested inside P? */
predicate isNestedType(@reftype T, @reftype P) {
  enclInReftype(T,P,_)
}

/** is T in package P? this also returns true when T is
*   a nested type in P */
predicate typeIsInPackage(@type T, @package P) {
  classes(T,_,P,_,_) or
  interfaces(T,_,P,_,_)
}

/** is T an outermost type? */
predicate outerType(@type T) {
  isTopLevelType(T,_)
}

/** is T in compilation unit CU? */
predicate typeIsInCU(@type T, @cu CU) {
  classes(T,_,_,CU,_) or
  interfaces(T,_,_,CU,_)
}

/** is T an immediate supertype of Sub?
*   use hasSubtype*(T,Sub) for "T is a supertype of Sub"
*   use hasSubtype+(T,Sub) for "T is a distinct supertype of Sub */
predicate hasSubtype(@reftype T, @type Sub) {
  extendsReftype(Sub,T,_) or
  implInterface(Sub,T,_)
}

/** does T declare member M? */
predicate declaresMember(@type T, @member M) {
  methods(M,_,_,_,T,_,_) or
  constrs(M,_,_,_,T,_,_) or
  fields(M,_,_,T,_,_) or
  enclInReftype(M,T,_)
}

/** does class C declare constructor M? */
predicate declaresConstructor(@class C, @constructor M) {
  constrs(M,_,_,_,C,_,_)
}

/** does T declare method M? */
predicate declaresMethod(@reftype T, @method M) {
  methods(M,_,_,_,T,_,_)
}

/** does T declare field F? */
predicate declaresField(@reftype T, @field F) {
  fields(F,_,_,T,_,_)
}

/** does T have method M, and if so, does it come from From */
predicate hasMethod(@reftype T, @method M, @reftype From) {
  ( declaresMethod(T,M) and From = T ) or
  ( exists(@reftype Super | hasSubtype(Super,T) and 
                            hasMethod(Super,M,From)) and
    exists(string S | methods(M,_,S,_,_,_,_) and
                      not methods(_,_,S,_,T,_,_) ) and
    inheritableMethod(M)
    )
}
/** -------- Predicates on fields -------- */

/** does field F have type T? */
predicate hasType(@field F, @type T) {
  fields(F,_,T,_,_,_)
}

/** does B read or write field F? */
predicate accesses(@callable B, @field F) {
  readsField(_,B,F,_,_) or
  writesField(_,B,F,_,_)
}

/** -------- Predicates on callables -------- */

/** does B have a parameter of type T at position Pos?
*   counting positions starts at 0.
*   example:  p(A x, B y) has a parameter of type B at position 1 */
predicate hasParam(@callable B, @type T, int Pos) {
  params(_,_,T,Pos,B,_,_)
}

/** does B have signature S?
*   S is a string where all types have been given their full Java
*   name, such as "java.lang.String" rather than just "String" */
predicate hasSignature(@callable B, string S) {
  constrs(B,_,S,_,_,_,_) or
  methods(B,_,S,_,_,_,_)
}

/** could method M be inherited? */
predicate inheritableMethod(@method M) {
  not hasStrModifier(M,"private") and
  not hasStrModifier(M,"static")
}

/** do methods M1 and M2 have the same signature? */
predicate hasSameSignature(@method M1, @method M2) {
  exists(string S | hasSignature(M1,S) and hasSignature(M2,S))
}

/** does method M1 override method M2? */
predicate overrides(@method M1, @method M2) {
  exists(string S | methods(M1,_,S,_,_,_,_) and methods(M2,_,S,_,_,_,_)) and
  inheritableMethod(M2) and
  exists (@reftype T1, @reftype T2 | declaresMethod(T1,M1) and
                                     declaresMethod(T2,M2) and
                                     hasSubtype+(T2,T1))
}


/** does B return a value of type T? */
predicate returnsType(@callable B, @type T) {
  methods(B,_,_,T,_,_,_) or
  constrs(B,_,_,T,_,_,_)
}


/** do M1 and M2 declared in the same type have the same parameter types? */
predicate sameParamTypes(Method M1, Method M2) {
   //M1 and M2 are different methods
   M1!=M2 and
   //M1 and M2 are declared in the same type
   M1.getDeclaringType() = M2.getDeclaringType() and
   //M1 and M2 are of the same arity
   M1.getNumberOfParameters() = M2.getNumberOfParameters() and
   //and there does not exists a pair of parameters that has different types
   not exists(Type T, int POS |  hasParam(M1, T, POS) and 
                                 not hasParam(M2, T, POS))
}

/* ========================================================================= */
/*                      JAVA LANGUAGE STRUCTURE                              */
/* ========================================================================= */

/** any node in the syntax tree that has a name */
class Element extends @element {
  predicate hasName(string name) { hasName(this,name) }
  string getName() { this.hasName(result) }
  string toString() { hasName(this,result) }
  /** does this element contain e, i.e., is this an ancestor of e? */
  predicate contains(Element e) { hasChild+(this,e) }
  /** is this element populated from source code?
      this is useful to filter source elements when using on-demand population */
  predicate fromSource() { 
    exists(CompilationUnit C | inCompilationUnit(this,C) and 
                               C.getExtension() == "java") 
  }
  /** is this element populated from a class file, e.g., in a jar file? */                                                      
  predicate fromLibrary() { 
    exists(CompilationUnit C | inCompilationUnit(this,C) and 
                               C.getExtension() == "class") }
  /** get the source location for this element */                                                       
  Location getLocation() { hasLocation(this,result) }
}

/** a location maps language elements to positions in source files */
class Location extends @location {
  /** return the number of lines that this location ranges over */
  int getNumberOfLines() { locations(this,_,_,_,_,_,result,_,_) }
  /** return the number of lines of code that this location ranges over */
  int getNumberOfLinesOfCode() { locations(this,_,_,_,_,_,_,result,_) }
  /** return the number of comment lines that this location ranges over */
  int getNumberOfCommentLines() { locations(this,_,_,_,_,_,_,_,result) }
  /** return a string representation containing the compilation unit and 
      range for this source location */
  string toString() {
    exists(CompilationUnit cu,
      int startline,
      int endline,
      int totallines |
      locations(this,_,cu,_,_,startline,totallines,_,_) and
      (totallines = 0 and endline = startline or
       totallines > 0 and endline = startline + totallines - 1) and
      result = cu.toString() + ":" + 
               startline.toString() + "-" + endline.toString())
  }
}

/** a package may be used to abstract over all members of a package,
    regardless in which compilation unit they are defined in */
class Package extends Element, Annotatable, @package {
  /** find top level types in this package */
  RefType getARefType() { isTopLevelType(result, this) }
  /** is there at least one reftype in this package that is populated 
      from source? */
  predicate fromSource() { 
    exists(RefType t | t.fromSource() and t.getPackage() = this) 
  }
  /** is there at least one reftype in this package that is populated 
      from bytecode? */
  predicate fromLibrary() { 
    exists(RefType t | t.fromLibrary() and t.getPackage() = this) 
  }
  /** select the icon to be used when displaying query results */ 
  string getIconPath() { result = "icons/package.png" }
}

/** a compilation unit for a type declaration, i.e., a .java or .class file */
class CompilationUnit extends Element, @cu {
  /** the number of lines of code in this compilation unit */
  int getNumberOfLinesOfCode() { 
    result = this.getLocation().getNumberOfLinesOfCode() 
  }
  /** the number of comment lines in this compilation unit */
  int getNumberOfCommentLines() { 
    result = this.getLocation().getNumberOfCommentLines() 
  }
  /** the total number of lines including everything */
  int getNumberOfLines() {
    result = this.getLocation().getNumberOfLines()
  }
  /** the full disk path to this compilation unit */
  string getPath() { cus(this,_,result,_,_,_) }
  /** the extension of a compiltation unit is either ".java" or ".class" */
  string getExtension() { cus(this,_,_,_,result,_) }
  /** the declared package of this compilation unit */
  Package getPackage() { cus(this,_,_,result,_,_) }
}

/** ------ Modifiers ------- */

class Modifier extends Element, @modifier {
  /** the element which this modifier modifies */
  Element getElement() { hasModifier(result,this,_) }
}

/** -------- Types  -------- */

/** a common abstraction for all Java types, e.g., primitive, class, interface, 
*   and array types */
class Type extends Element, @type { }

/** primitive types include boolean, byte, short, char, int, long, float, 
*   and double */
class PrimitiveType extends Type, @primitive {
  PrimitiveType() { @primitive(this) }
}

/** any class or interface or type variable or array */
class RefType extends Type, Annotatable, @reftype {
  /** return the package in which this type is declared */
  Package getPackage() { typeIsInPackage(this,result) }
  /** return the compilation unit in which this type is declared */
  CompilationUnit getCompilationUnit() { typeIsInCU(this,result) }

  /** is t an immediate supertype of this type? */
  predicate hasSupertype(RefType t) { hasSubtype(t,this) }
  /** is t an immediate subtype of this type? */
  predicate hasSubtype(RefType t) { hasSubtype(this,t) }
  /** return a direct subtype of this type */
  RefType getASubtype() { hasSubtype(this,result) }
  /** return a direct supertype of this type */
  RefType getASupertype() { hasSubtype(result,this) }

  /** does this type declare any members? */
  predicate hasMember() { declaresMember(this, _) }
  /** return a member declared in this type */
  Member getAMember() { this = result.getDeclaringType() }
  /** return a method declared in this type */
  Method getAMethod() { this = result.getDeclaringType() }
  /** return a constructor declared in this type */
  Constructor getAConstructor() { this = result.getDeclaringType() }
  /** return a method or constructor declared in this type */
  Callable getACallable() { this = result.getDeclaringType() }
  /** return a field declared in this type */
  Field getAField() { this = result.getDeclaringType() }
  /** does this type declare a member method named name? */
  predicate declaresMethod(string name) { this.getAMethod().getName() = name }
  /** does this type declare a member field named name? */
  predicate declaresField(string name) { this.getAField().getName() = name }
  /** return the number of member methods declared in this type */
  int getNumberOfMethods() { result = count(Method m | declaresMember(this,m)) }
  /** does this type have a specific modifier? */
  predicate hasModifier(string modifier) { hasStrModifier(this,modifier) }
  /** does this type not have any modifiers? */
  predicate hasNoModifier() { not hasModifier(this,_,_) }
  /** return a modifier declared for this type */
  Modifier getAModifier() { this = result.getElement() }
  /** does this type inherit method m */
  predicate inherits(Method m) { hasMethod(this, m, _) }
  /** is this a top-level type? */
  predicate isTopLevel() { isTopLevelType(this,_) }

  /** is this type declared in package and have the name type */
  predicate hasQualifiedName(string package, string type) { 
    this.getPackage().hasName(package) and this.hasName(type) 
  }
  string getQualifiedName() {
    (this.getPackage().getName()=="" and result = this.nestedName()) or
    (this.getPackage().getName()!="" and result = this.getPackage().getName() 
                                                  + "." + this.nestedName())
  }
  string nestedName() {
     not (this instanceof NestedType) and result = this.getName()
     or
     ((this instanceof NestedType) and 
      ((NestedType)this).getEnclosingType().nestedName() + 
              "$" + this.getName() = result)
  }
}

/** any class declaration */
class Class extends RefType, @class {
  /** is this class an anonymous class in a method or constructor? */
  predicate isAnonymous() { isAnonymClass(this) }
  /** is this a local class declared within a method or constructor? */
  predicate isLocal() { isLocalClass(this) }
  /** select the icon to be used when displaying query results */
  string getIconPath() { result = "icons/class.png" }
}

/** any interface declaration */
class Interface extends RefType, @interface {
  /** select the icon to be used when displaying query results */
  string getIconPath() { result = "icons/interface.png" }
}

/** an anonymous class */
class AnonymousClass extends NestedClass {
  AnonymousClass() { this.isAnonymous() }
  string getQualifiedName() { result = "" }
}

/** a local class */
class LocalClass extends NestedClass {
  LocalClass() { this.isLocal() }
}

/** a non top-level type declared within another type */
class NestedType extends RefType {
  NestedType() { isNestedType(this,_) }
  /** get the type enclosing this nested type */
  RefType getEnclosingType() { isNestedType(this,result) }
}

/** a class declared within another type, e.g. a member class, local class, 
*   anonymous class */
class NestedClass extends NestedType, Class { }

/** any array type.
    these types are implicitly declared when being used, i.e., 
    there is an array declaration for each array type used in the system */
class Array extends RefType, @array {
  /** the element type of an array type is the base type used to construct the 
      array. the element type of Object[][] is for instance Object */
  Type getElementType() { arrays(this,_,result,_,_,_) }
  /** the arity of the array type. 
      the dimension of Object[][] is for instance 2 */
  int getDimension() { arrays(this,_,_,result,_,_) }
}

/** -------- Members of classes and interfaces  -------- */

/** a common abstraction for type member declarations, e.g., methods, fields, 
*   and nested types */
class Member extends Element, Annotatable, @member {
  /** the type this member is declared in */
  RefType getDeclaringType() { declaresMember(result, this) }
  /** members may have modifiers */
  predicate hasModifier(string modifier) { hasStrModifier(this,modifier) }
  predicate hasNoModifier() { not hasModifier(this,_,_) }
  /** return a modifier for this member */
  Modifier getAModifier() { this = result.getElement() }

}

/** any class or instance field */
class Field extends Member, @field {
  /** the declared type of this field */
  Type getType() { hasType(this,result) }
  /** the type this member is declared in */
  RefType getDeclaringType() { declaresField(result,this) }
  /** select the icon to be used when displaying query results */
  string getIconPath() { result = "icons/field.png" }
}

/** any method or constructor */
class Callable extends Member, @callable {
  /** get the declared type of this callable */
  Type getType() { returnsType(this,result) }
  /** select a callee that may be called from this callable */
  Callable getACall() { this.calls(result) }
  /** Gets the call site of a call from this callable to a callee*/
  Call getACallSite(Callable callee) {
    exists(Call c | c.getCaller() = this and c.getCallee() = callee
                    and c == result)
	}
  /** select a callee which is a constructor that may be called from this 
      callable */ 
  Constructor getAConstructorCall() {
    exists(ConstructorCall c | c.getConstructor() = result 
                               and c.getCaller() = this)
  }
  /** does this callable call target using any kind of call? */
  predicate calls(Callable target) {
    exists(Call c | c.getCaller() = this and c.getCallee() = target)
	}
  /** does this callable call c using a super constructor call? */
  predicate callsSuper(Constructor target) {
    exists(SuperConstructorCall c | 
      c.getConstructor() = target and c.getCaller() = this)
  }
  /** does this callable call c using a constructor calll? */
  predicate callsThis(Constructor target) { 
    exists(ThisConstructorCall c |
      c.getConstructor() = target and c.getCaller() = this)
  }
  /** does this callable call c using either a super constructor or a 
      constructor call */
  predicate callsConstructor(Constructor c) {
    this.callsSuper(c) or this.callsThis(c)
  }
  /** may this callable call c taking overriding into acount? */
  predicate polyCalls(Callable m) {
    //this.calls(m)
    exists(Call c | c.getCaller() = this and c.getCallee() = m)
    or
    exists(Method mSuper, VirtualMethodCall c | 
      c.getCaller() = this and c.getMethod() = mSuper and 
      ((Method)m).overrides(mSuper))
  }
  predicate callsSuper(Method target) {
    exists(SuperMethodCall c | 
      c.getMethod() = target and c.getCaller() = this)
  }
  /** may f be assigned within the body of this callable? */
  predicate writes(Field f) { writesField(_, this, f, _,_) }
  /** may f be read within the body of this callable */
  predicate reads(Field f) { readsField(_, this, f, _,_) }
  /** may f be either read or written within the body of this callable */
  predicate accesses(Field f) { this.writes(f) or this.reads(f) }
  /** get any field accessed in this callable */
  Field getAnAccess() { this.accesses(result) }
  /** get a formal parameter type */
  Type getAParamType() { hasParam(this,result,_) }
  /** does this callable not have any formal parameters */
  predicate hasNoParameters() { not params(_,_,_,_,this,_,_) }
  /** return the number of formal parameters of this callable */
  int getNumberOfParameters() { 
    result = count(int pos | params(_,_,_,pos,this,_,_)) 
  }
  /** return a formal paramater of this callable */
  Parameter getAParameter() { result.getCallable() = this }
  /** get an exception that may be thrown from this callable */
  Exception getAnException() { exceptions(result,_,this,_,_) }
  /** get a call site that references this callable */
  Call getAReference() {
    exists( Call c | c.getCallee() = this and c = result ) 
  }
  /** select the icon to be used when displaying query results */
  string getIconPath() { result = "icons/method.png" }
     // return a string for the type of parameter number n
     
  string paramstr( int n) {
       exists (Type t | hasParam( this ,t,n) and result=t.toString())
  }

  // list the parameters from right to left
  string paramUpTo(int n) {
      (n =0 and result = this.paramstr(0))
      or
      (n > 0 and
       exists(Type t | 
          hasParam(this,t,n) and
          (result = this.paramUpTo(n-1) + ", " +t.toString())))
  }

  // produce the parenthesised string
  string paramsString() {
      exists(int n |
          this.getNumberOfParameters() = n 
          and
          ((n=0 and result = "()")
           or
           (n>0 and result = "("+this.paramUpTo(n-1)+")")))
  }

  /** readable signature of this Callable */
  string getStringSignature() {
      result = this.getName() + this.paramsString()
  }
}

/** callables may have paramaters */
class Parameter extends Element, @param {
  /** return the type of this formal parameter */
  Type getType() { params(this,_,result,_,_,_,_) }
  /** get the position of this formal parameter */
  int getPosition() { params(this,_,_,result,_,_,_) }
  /** get the callable in which this formal parameter is declared */
  Callable getCallable() { params(this,_,_,_,result,_,_) }
}

/** callables may throw exceptions, this element represent the actual 
*   throws clause and not the exception type, being the first X below
      void m() throws X;
      class X extends Exception { }
*/
class Exception extends Element, @exception {
  RefType getType() { exceptions(this,result,_,_,_) }
  /** return the callable that throws this exception */
  Callable getCallable() { exceptions(this,_,result,_,_) }
  /** return the name of this exception which is the same as its type */
  string getName() { result = this.getType().getName() }
  /** does this exception throw an exception named name? */
  predicate hasName(string name) { this.getType().hasName(name) }
  /** return the name if the exception as its string representation */
  string toString() { result = this.getType().toString() }
}

/** a method is a restricted kind of callable */ 
class Method extends Callable, @method {
  /** does this method override c? */
  predicate overrides(Callable c) { overrides(this,c) }
  string getSignature() { methods(this,_,result,_,_,_,_) }
  /** select the icon to be used when displaying query results, use 
      different icons for public, protected, and private methods */
  string getIconPath() {
    (this.hasModifier("private") and result = "icons/privatemethod.png") or
    (this.hasModifier("protected") and result = "icons/protectedmethod.png") or
    (this.hasModifier("public") and result = "icons/publicmethod.png") or
    (not(this.hasModifier("private") or 
         this.hasModifier("protected") or 
         this.hasModifier("public")) and 
       result = "icons/method.png")
  }
}

/** a constructor is a restricted kind of callable */
class Constructor extends Callable, @constructor {
  /** default constructors are not explicitly declared in source code */
  predicate isDefaultConstructor() { isDefConstr(this) }
  /** select the icon to be used when displaying query results */
  string getIconPath() { result = "icons/constructor.png" }
}

/** -------- Generic types  -------- */

/** any generic type that has a type parameter, e.g., X in class X { } */
class GenericType extends RefType {
  GenericType() { typeVars(_,_,_,this,_,_) }
  /** get a parameterization of this generic type, e.g., X. each use of 
      a formal type parameter has been replaced by its argument. */
  ParameterizedType getAParameterizedType() { result.getErasure() = this }
  /** get the raw version of this generic type, i.e., the use of a generic type
      as if it was non-generic. this is for instance the case when legacy code
      not aware of generics uses collections in Java 5.*/
  RawType getRawType() { result.getErasure() = this }
}
class GenericClass extends GenericType, Class { }
class GenericInterface extends GenericType, Interface { }

/** a type variable used in the declaration of a generic type or method, e.g.,
*   T in class X { } or  void m() { }.*/
class TypeVariable extends RefType, @typevariable {
  /** return the generic type that is parameterized using this type variable */
  RefType getGenericType() { typeVars(this,_,_,result,_,_) }
  /** return the generic method that is parameterized using this type 
      variable */
  Method getGenericMethod() { typeVars(this,_,_,result,_,_) }
  /** return a type bound for this type variable */
  TypeBound getATypeBound() { result.getTypeVariable() = this }
}

/** each type variable may have zero or more type bounds, e.g.,
*   Number in class X { }. */
class TypeBound extends @typebound {
  /** get the type variable that this bound restricts, e.g., T in the example 
      above */
  TypeVariable getTypeVariable() { typeBounds(this,_,_,result,_,_) }
  /** get type type of this bound, e.g., Number in the example above */
  RefType getType() { typeBounds(this,result,_,_,_,_) }
  string toString() { result = this.getType().getName() }
}

/** -------- Parameterizations of generic types  -------- */

/** a parameterized type is a generic type where each formal type variable has 
*   been instantiated with a type argument */
class ParameterizedType extends RefType {
  ParameterizedType() { isParameterized(this) }
  /** the erasure of a parameterized type is its generic counterpart, i.e.,
      the erasure of X and X are both X */
  RefType getErasure() { erasure(this,result) }
	RefType getATypeArgument() { typeArgs(result,_,this,_) }
	RefType getTypeArgument(int pos) { typeArgs(result,pos,this,_) }
  int getNumberOfTypeArguments() { 
    result = count(int pos | typeArgs(_,pos,this,_)) 
  }
  // parameterized types are neither from source...
  predicate fromSource() { not any() }
  // ... nor from library
  predicate fromLibrary() { not any() }
}
class ParameterizedClass extends Class, ParameterizedType { 
  predicate fromSource() { ParameterizedType.super.fromSource() }
  predicate fromLibrary() { ParameterizedType.super.fromLibrary() }
}
class ParameterizedInterface extends Interface, ParameterizedType {
  predicate fromSource() { ParameterizedType.super.fromSource() }
  predicate fromLibrary() { ParameterizedType.super.fromLibrary() }
}

/** a raw type is a generic type that is used as if it was a non-generic type, 
*   e.g., from legacy code not aware of generics. */
class RawType extends RefType {
  RawType() { isRaw(this) }
  /** the erasure of a raw type is its generic counterpart, i.e.,
      the erasure of X is X */
  RefType getErasure() { erasure(this,result) }
  // raw types are neither from source...
  predicate fromSource() { not any() }
  // ... nor from library
  predicate fromLibrary() { not any() }
}