Files
codeql/java/ql/lib/semmle/code/java/dataflow/InstanceAccess.qll
Andrew Eisenberg 8e750f18ad Packaging: Java refactoring
Split java pack into `codeql/java-all` and `codeql/java-queries`.
2021-08-19 14:09:35 -07:00

268 lines
9.2 KiB
Plaintext

/**
* Provides classes and predicates for reasoning about explicit and implicit
* instance accesses.
*/
import java
/**
* Holds if `cc` constructs an inner class that holds a reference to its
* enclosing class `t` and the enclosing instance is not given explicitly as a
* qualifier of the constructor.
*/
private predicate implicitSetEnclosingInstance(ConstructorCall cc, RefType t) {
exists(InnerClass ic |
ic = cc.getConstructedType().getSourceDeclaration() and
ic.hasEnclosingInstance() and
ic.getEnclosingType() = t and
not cc instanceof ThisConstructorInvocationStmt and
not exists(cc.getQualifier())
)
}
/**
* Holds if `cc` implicitly sets the enclosing instance of the constructed
* inner class to `this`.
*/
private predicate implicitSetEnclosingInstanceToThis(ConstructorCall cc) {
exists(RefType t |
implicitSetEnclosingInstance(cc, t) and
cc.getEnclosingCallable().getDeclaringType().getASourceSupertype*() = t
)
}
/**
* Gets the closest enclosing type of `ic` that is also a subtype of `t`.
*/
private RefType getEnclosing(InnerClass ic, RefType t) {
exists(RefType enclosing | enclosing = ic.getEnclosingType() |
if enclosing.getASourceSupertype*() = t
then result = enclosing
else result = getEnclosing(enclosing, t)
)
}
/**
* Holds if `cc` implicitly sets the enclosing instance of type `t2` of the
* constructed inner class to `t1.this`.
*/
private predicate implicitEnclosingThisCopy(ConstructorCall cc, RefType t1, RefType t2) {
implicitSetEnclosingInstance(cc, t2) and
not implicitSetEnclosingInstanceToThis(cc) and
t1 = getEnclosing(cc.getEnclosingCallable().getDeclaringType(), t2)
}
/**
* Holds if an enclosing instance of the form `t.this` is accessed by `e`.
*/
private predicate enclosingInstanceAccess(ExprParent e, RefType t) {
e.(InstanceAccess).isEnclosingInstanceAccess(t)
or
exists(MethodAccess ma |
ma.isEnclosingMethodAccess(t) and ma = e and not exists(ma.getQualifier())
)
or
exists(FieldAccess fa | fa.isEnclosingFieldAccess(t) and fa = e and not exists(fa.getQualifier()))
or
implicitEnclosingThisCopy(e, t, _)
}
/**
* Holds if an enclosing instance of the form `t2.this` is accessed by `e`, and
* this desugars into `this.enclosing.enclosing...enclosing`. The prefix of the
* desugared access with `i` enclosing instance field accesses has type `t1`.
*/
private predicate derivedInstanceAccess(ExprParent e, int i, RefType t1, RefType t2) {
enclosingInstanceAccess(e, t2) and
i = 0 and
exists(Callable c | c = e.(Expr).getEnclosingCallable() or c = e.(Stmt).getEnclosingCallable() |
t1 = c.getDeclaringType()
)
or
exists(InnerClass ic |
derivedInstanceAccess(e, i - 1, ic, t2) and
ic.getEnclosingType() = t1 and
ic != t2
)
}
cached
private newtype TInstanceAccessExt =
TExplicitInstanceAccess(InstanceAccess ia) or
TThisQualifier(FieldAccess fa) { fa.isOwnFieldAccess() and not exists(fa.getQualifier()) } or
TThisArgument(Call c) {
c instanceof ThisConstructorInvocationStmt
or
c instanceof SuperConstructorInvocationStmt
or
c.(MethodAccess).isOwnMethodAccess() and not exists(c.getQualifier())
} or
TThisEnclosingInstanceCapture(ConstructorCall cc) { implicitSetEnclosingInstanceToThis(cc) } or
TEnclosingInstanceAccess(ExprParent e, RefType t) {
enclosingInstanceAccess(e, t) and not e instanceof InstanceAccess
} or
TInstanceAccessQualifier(ExprParent e, int i, RefType t1, RefType t2) {
derivedInstanceAccess(e, i, t1, t2) and t1 != t2
}
/**
* A generalization of `InstanceAccess` that includes implicit accesses.
*
* The accesses can be divided into 6 kinds:
* - Explicit: Represented by an `InstanceAccess`.
* - Implicit field qualifier: The implicit access associated with an
* unqualified `FieldAccess` to a non-static field.
* - Implicit method qualifier: The implicit access associated with an
* unqualified `MethodAccess` to a non-static method.
* - Implicit this constructor argument: The implicit argument of the value of
* `this` to a constructor call of the form `this()` or `super()`.
* - Implicit enclosing instance capture: The implicit capture of the value of
* the directly enclosing instance of a constructed inner class. This is
* associated with an unqualified constructor call.
* - Implicit enclosing instance qualifier: The instance access that occurs as
* the implicit qualifier of a desugared enclosing instance access.
*
* Of these 6 kinds, the fourth (implicit this constructor argument) is always
* an `OwnInstanceAccess`, whereas the other 5 can be either `OwnInstanceAccess`
* or `EnclosingInstanceAccess`.
*/
class InstanceAccessExt extends TInstanceAccessExt {
private string ppBase() {
exists(EnclosingInstanceAccess enc | enc = this |
result = enc.getQualifier().toString() + "(" + enc.getType() + ")enclosing"
)
or
isOwnInstanceAccess() and result = "this"
}
private string ppKind() {
isExplicit(_) and result = " <" + getAssociatedExprOrStmt().toString() + ">"
or
isImplicitFieldQualifier(_) and result = " <.field>"
or
isImplicitMethodQualifier(_) and result = " <.method>"
or
isImplicitThisConstructorArgument(_) and result = " <constr(this)>"
or
isImplicitEnclosingInstanceCapture(_) and result = " <.new>"
or
isImplicitEnclosingInstanceQualifier(_) and result = "."
}
/** Gets a textual representation of this element. */
string toString() { result = ppBase() + ppKind() }
/** Gets the source location for this element. */
Location getLocation() { result = getAssociatedExprOrStmt().getLocation() }
private ExprParent getAssociatedExprOrStmt() {
this = TExplicitInstanceAccess(result) or
this = TThisQualifier(result) or
this = TThisArgument(result) or
this = TThisEnclosingInstanceCapture(result) or
this = TEnclosingInstanceAccess(result, _) or
this = TInstanceAccessQualifier(result, _, _, _)
}
/** Gets the callable in which this instance access occurs. */
Callable getEnclosingCallable() {
result = getAssociatedExprOrStmt().(Expr).getEnclosingCallable() or
result = getAssociatedExprOrStmt().(Stmt).getEnclosingCallable()
}
/** Holds if this is the explicit instance access `ia`. */
predicate isExplicit(InstanceAccess ia) { this = TExplicitInstanceAccess(ia) }
/** Holds if this is the implicit qualifier of `fa`. */
predicate isImplicitFieldQualifier(FieldAccess fa) {
this = TThisQualifier(fa) or
this = TEnclosingInstanceAccess(fa, _)
}
/** Holds if this is the implicit qualifier of `ma`. */
predicate isImplicitMethodQualifier(MethodAccess ma) {
this = TThisArgument(ma) or
this = TEnclosingInstanceAccess(ma, _)
}
/**
* Holds if this is the implicit `this` argument of `cc`, which is either a
* `ThisConstructorInvocationStmt` or a `SuperConstructorInvocationStmt`.
*/
predicate isImplicitThisConstructorArgument(ConstructorCall cc) { this = TThisArgument(cc) }
/** Holds if this is the implicit qualifier of `cc`. */
predicate isImplicitEnclosingInstanceCapture(ConstructorCall cc) {
this = TThisEnclosingInstanceCapture(cc) or
this = TEnclosingInstanceAccess(cc, _)
}
/**
* Holds if this is the implicit qualifier of the desugared enclosing
* instance access `enc`.
*/
predicate isImplicitEnclosingInstanceQualifier(EnclosingInstanceAccess enc) {
enc.getQualifier() = this
}
/** Holds if this is an access to an object's own instance. */
predicate isOwnInstanceAccess() { not isEnclosingInstanceAccess(_) }
/** Holds if this is an access to an enclosing instance. */
predicate isEnclosingInstanceAccess(RefType t) {
exists(InstanceAccess ia |
this = TExplicitInstanceAccess(ia) and ia.isEnclosingInstanceAccess(t)
)
or
this = TEnclosingInstanceAccess(_, t)
or
exists(int i | this = TInstanceAccessQualifier(_, i, t, _) and i > 0)
}
/** Gets the type of this instance access. */
RefType getType() {
isEnclosingInstanceAccess(result)
or
isOwnInstanceAccess() and result = getEnclosingCallable().getDeclaringType()
}
/** Gets the control flow node associated with this instance access. */
ControlFlowNode getCfgNode() {
exists(ExprParent e | e = getAssociatedExprOrStmt() |
e instanceof Call and result = e
or
e instanceof InstanceAccess and result = e
or
exists(FieldAccess fa | fa = e |
if fa instanceof RValue then fa = result else result.(AssignExpr).getDest() = fa
)
)
}
}
/**
* An access to an object's own instance.
*/
class OwnInstanceAccess extends InstanceAccessExt {
OwnInstanceAccess() { isOwnInstanceAccess() }
}
/**
* An access to an enclosing instance.
*/
class EnclosingInstanceAccess extends InstanceAccessExt {
EnclosingInstanceAccess() { isEnclosingInstanceAccess(_) }
/** Gets the implicit qualifier of this in the desugared representation. */
InstanceAccessExt getQualifier() {
exists(ExprParent e, int i | result = TInstanceAccessQualifier(e, i, _, _) |
this = TInstanceAccessQualifier(e, i + 1, _, _)
or
exists(RefType t | derivedInstanceAccess(e, i + 1, t, t) |
this = TEnclosingInstanceAccess(e, t) or
this = TExplicitInstanceAccess(e)
)
)
}
}