mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
JS: Avoid magic and improve a join in type resolution
This commit is contained in:
@@ -73,6 +73,7 @@ module NameResolution {
|
||||
*
|
||||
* May also include some type-specific steps in cases where this is harmless when tracking values.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate commonStep(Node node1, Node node2) {
|
||||
// Import paths are part of the graph and has an incoming edge from the imported module, if found.
|
||||
// This ensures we can also use the PathExpr as a source when working with external (unresolved) modules.
|
||||
@@ -187,6 +188,7 @@ module NameResolution {
|
||||
/**
|
||||
* Holds if there is a read from `node1` to `node2` that accesses the member `name`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate readStep(Node node1, string name, Node node2) {
|
||||
exists(QualifiedTypeAccess access |
|
||||
node1 = access.getQualifier() and
|
||||
@@ -321,6 +323,7 @@ module NameResolution {
|
||||
/**
|
||||
* Gets the exported member of `mod` named `name`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Node getModuleExport(ModuleLike mod, string name) {
|
||||
exists(ExportDeclaration exprt |
|
||||
mod = exprt.getContainer() and
|
||||
@@ -362,6 +365,7 @@ module NameResolution {
|
||||
* Holds if `value` is stored in `target.prop`. Only needs to recognise assignments
|
||||
* that are also recognised by JSDoc tooling such as the Closure compiler.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate storeToVariable(Expr value, string prop, LocalVariableLike target) {
|
||||
exists(AssignExpr assign |
|
||||
// target.name = value
|
||||
@@ -374,6 +378,7 @@ module NameResolution {
|
||||
}
|
||||
|
||||
/** Steps that only apply for this configuration. */
|
||||
pragma[nomagic]
|
||||
private predicate specificStep(Node node1, Node node2) {
|
||||
exists(LexicalName var | S::isRelevantVariable(var) |
|
||||
node1.(LexicalDecl).getALexicalName() = var and
|
||||
@@ -406,6 +411,7 @@ module NameResolution {
|
||||
/** Helps track flow from a particular set of source nodes. */
|
||||
module Track<nodeSig/1 isSource> {
|
||||
/** Gets the set of nodes reachable from `source`. */
|
||||
pragma[nomagic]
|
||||
Node track(Node source) {
|
||||
isSource(source) and
|
||||
result = source
|
||||
@@ -419,6 +425,7 @@ module NameResolution {
|
||||
/** Helps track flow from a particular set of source nodes. */
|
||||
module TrackNode<AstNodeSig Source> {
|
||||
/** Gets the set of nodes reachable from `source`. */
|
||||
pragma[nomagic]
|
||||
Node track(Source source) {
|
||||
result = source
|
||||
or
|
||||
@@ -482,6 +489,7 @@ module NameResolution {
|
||||
*
|
||||
* Unlike `trackModule`, this is intended to track uses of external packages.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate nodeRefersToModule(Node node, string mod, string qualifiedName) {
|
||||
exists(Expr path |
|
||||
path = any(Import imprt).getImportedPathExpr() or
|
||||
|
||||
@@ -12,6 +12,7 @@ module TypeResolution {
|
||||
* We track through underlying types as an approximate way to handle calls to a type
|
||||
* that is a union/intersection involving functions.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Node trackUnderlyingFunctionType(Function fun) {
|
||||
result = fun
|
||||
or
|
||||
@@ -139,6 +140,28 @@ module TypeResolution {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* `ContentSet.getAReadContent` restricted to the content sets and contents relevant for type resolution.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private DataFlow::Content getAReadContentRestricted(DataFlow::ContentSet cs) {
|
||||
valueReadStep(_, cs, _) and
|
||||
result = cs.getAReadContent() and
|
||||
typeMember(_, result, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* `valueReadStep` where the `ContentSet` has been mapped to the set of relevant read-contents.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate valueReadStepOnContent(Node object, DataFlow::Content content, Node member) {
|
||||
exists(DataFlow::ContentSet contents |
|
||||
valueReadStep(object, contents, member) and
|
||||
content = getAReadContentRestricted(contents)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate callTarget(InvokeExpr call, Function target) {
|
||||
exists(ClassDefinition cls |
|
||||
valueHasType(call.(NewExpr).getCallee(), trackClassValue(cls)) and
|
||||
@@ -198,6 +221,7 @@ module TypeResolution {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate contextualType(Node value, Node type) {
|
||||
exists(LocalVariableLike v |
|
||||
type = v.getADeclaration().getTypeAnnotation() and
|
||||
@@ -239,6 +263,7 @@ module TypeResolution {
|
||||
/**
|
||||
* Holds if `value` has the given `type`.
|
||||
*/
|
||||
cached
|
||||
predicate valueHasType(Node value, Node type) {
|
||||
value.(BindingPattern).getTypeAnnotation() = type
|
||||
or
|
||||
@@ -293,11 +318,18 @@ module TypeResolution {
|
||||
or
|
||||
exists(Node mid | valueHasType(mid, type) | ValueFlow::step(mid, value))
|
||||
or
|
||||
exists(Node mid, Node midType, DataFlow::ContentSet contents, Node host |
|
||||
valueReadStep(mid, contents, value) and
|
||||
exists(DataFlow::Content content, Node host |
|
||||
typeMemberHostRead(host, content, value) and
|
||||
typeMember(host, content, type)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeMemberHostRead(Node host, DataFlow::Content content, Node target) {
|
||||
exists(Node mid, Node midType |
|
||||
valueReadStepOnContent(mid, content, target) and
|
||||
valueHasType(mid, midType) and
|
||||
typeMemberHostReaches(host, midType) and
|
||||
typeMember(host, contents.getAReadContent(), type)
|
||||
typeMemberHostReaches(host, midType)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -309,6 +341,7 @@ module TypeResolution {
|
||||
* - a union type has the property if all its members have the property
|
||||
*/
|
||||
module TrackMustProp<nodeSig/1 directlyHasProperty> {
|
||||
pragma[nomagic]
|
||||
predicate hasProperty(Node node) {
|
||||
directlyHasProperty(node)
|
||||
or
|
||||
@@ -341,6 +374,7 @@ module TypeResolution {
|
||||
}
|
||||
|
||||
module ValueHasProperty<nodeSig/1 typeHasProperty> {
|
||||
pragma[nomagic]
|
||||
predicate valueHasProperty(Node value) {
|
||||
exists(Node type |
|
||||
valueHasType(value, type) and
|
||||
@@ -405,6 +439,7 @@ module TypeResolution {
|
||||
/**
|
||||
* Holds if `type` contains `string` or `any`, possibly wrapped in a promise.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate hasUnderlyingStringOrAnyType(Node type) {
|
||||
type.(TypeAnnotation).isStringy()
|
||||
or
|
||||
|
||||
Reference in New Issue
Block a user