mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
JS: Track types of classes in data flow
This commit is contained in:
@@ -558,15 +558,19 @@ DataFlowCallable nodeGetEnclosingCallable(Node node) {
|
||||
|
||||
newtype TDataFlowType =
|
||||
TFunctionType(Function f) or
|
||||
TInstanceType(DataFlow::ClassNode cls) or
|
||||
TAnyType()
|
||||
|
||||
class DataFlowType extends TDataFlowType {
|
||||
string toDebugString() {
|
||||
this instanceof TFunctionType and
|
||||
result =
|
||||
"TFunctionType(" + this.asFunction().toString() + ") at line " +
|
||||
this.asFunction().getLocation().getStartLine()
|
||||
or
|
||||
result =
|
||||
"TInstanceType(" + this.asInstanceOfClass().toString() + ") at line " +
|
||||
this.asInstanceOfClass().getLocation().getStartLine()
|
||||
or
|
||||
this instanceof TAnyType and result = "TAnyType"
|
||||
}
|
||||
|
||||
@@ -575,13 +579,25 @@ class DataFlowType extends TDataFlowType {
|
||||
}
|
||||
|
||||
Function asFunction() { this = TFunctionType(result) }
|
||||
|
||||
DataFlow::ClassNode asInstanceOfClass() { this = TInstanceType(result) }
|
||||
}
|
||||
|
||||
private predicate typeStrongerThan1(DataFlowType t1, DataFlowType t2) {
|
||||
// 't1' is a subclass of 't2'
|
||||
t1.asInstanceOfClass() = t2.asInstanceOfClass().getADirectSubClass()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t1` is strictly stronger than `t2`.
|
||||
*/
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
|
||||
t1 instanceof TFunctionType and t2 = TAnyType()
|
||||
typeStrongerThan1(t1, t2)
|
||||
or
|
||||
// Ensure all types are transitively stronger than 'any'
|
||||
not typeStrongerThan1(t1, _) and
|
||||
not t1 = TAnyType() and
|
||||
t2 = TAnyType()
|
||||
}
|
||||
|
||||
private DataFlowType getPreciseType(Node node) {
|
||||
@@ -590,6 +606,9 @@ private DataFlowType getPreciseType(Node node) {
|
||||
result = TFunctionType(f)
|
||||
)
|
||||
or
|
||||
result.asInstanceOfClass() =
|
||||
unique(DataFlow::ClassNode cls | cls.getAnInstanceReference().getALocalUse() = node)
|
||||
or
|
||||
result = getPreciseType(node.getImmediatePredecessor())
|
||||
or
|
||||
result = getPreciseType(node.(PostUpdateNode).getPreUpdateNode())
|
||||
@@ -683,18 +702,27 @@ predicate neverSkipInPathGraph(Node node) {
|
||||
string ppReprType(DataFlowType t) { none() }
|
||||
|
||||
pragma[inline]
|
||||
private predicate compatibleTypesNonSymRefl(DataFlowType t1, DataFlowType t2) {
|
||||
private predicate compatibleTypesWithAny(DataFlowType t1, DataFlowType t2) {
|
||||
t1 != TAnyType() and
|
||||
t2 = TAnyType()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate compatibleTypes1(DataFlowType t1, DataFlowType t2) {
|
||||
t1.asInstanceOfClass().getADirectSubClass+() = t2.asInstanceOfClass()
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
|
||||
t1 = t2
|
||||
or
|
||||
compatibleTypesNonSymRefl(t1, t2)
|
||||
compatibleTypesWithAny(t1, t2)
|
||||
or
|
||||
compatibleTypesNonSymRefl(t2, t1)
|
||||
compatibleTypesWithAny(t2, t1)
|
||||
or
|
||||
compatibleTypes1(t1, t2)
|
||||
or
|
||||
compatibleTypes1(t2, t1)
|
||||
}
|
||||
|
||||
predicate forceHighPrecision(Content c) { none() }
|
||||
|
||||
@@ -29,6 +29,6 @@ class Subclass3 extends Base {
|
||||
this.baseMethod("safe");
|
||||
}
|
||||
subclassMethod(x) {
|
||||
sink(x); // $ SPURIOUS: hasValueFlow=sub1 hasValueFlow=sub2
|
||||
sink(x);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user