Files
codeql/javascript/ql/lib/semmle/javascript/dataflow/internal/AbstractPropertiesImpl.qll
Andrew Eisenberg 45d1fa7f01 Packaging: Rafactor Javascript core libraries
Extract the external facing `qll` files into the codeql/javascript-all
query pack.
2021-08-25 12:15:56 -07:00

93 lines
3.1 KiB
Plaintext

/**
* INTERNAL: Do not use directly; use `semmle.javascript.dataflow.TypeInference` instead.
*
* Provides the internal representation of abstract properties and related predicates.
*/
import javascript
private import AbstractValuesImpl
/**
* An abstract representation of a set of concrete properties, characterized
* by a base object (which is an abstract value for which properties are tracked)
* and a property name.
*/
newtype TAbstractProperty =
MkAbstractProperty(AbstractValue base, string prop) {
any(AnalyzedPropertyRead apr).reads(base, prop) and shouldTrackProperties(base)
or
any(AnalyzedPropertyWrite apw).writes(base, prop, _)
or
exists(getAnInitialPropertyValue(base, prop))
or
// make sure `__proto__` properties exist for all instance values
base instanceof AbstractInstance and
prop = "__proto__"
}
/**
* Holds if the result is known to be an initial value of property `propertyName` of one
* of the concrete objects represented by `baseVal`.
*/
AbstractValue getAnInitialPropertyValue(DefiniteAbstractValue baseVal, string propertyName) {
// initially, `module.exports === exports`
exists(Module m |
baseVal = TAbstractModuleObject(m) and
propertyName = "exports" and
result = TAbstractExportsObject(m)
)
or
// class members
result = getAnInitialMemberValue(getMember(baseVal, propertyName))
or
// object properties
exists(ValueProperty p |
baseVal.(AbstractObjectLiteral).getObjectExpr() = p.getObjectExpr() and
propertyName = p.getName() and
result = p.getInit().analyze().getALocalValue()
)
or
// `f.prototype` for functions `f`
propertyName = "prototype" and
result = TAbstractInstance(baseVal)
}
/**
* Gets a class member definition that we abstractly represent as a property of `baseVal`
* with the given `name`.
*/
private MemberDefinition getMember(DefiniteAbstractValue baseVal, string name) {
exists(ClassDefinition c | result = c.getMember(name) |
if result.isStatic() then baseVal = TAbstractClass(c) else baseVal = AbstractInstance::of(c)
)
}
/**
* Gets an abstract representation of the initial value of member definition `m`.
*
* For (non-accessor) methods, this is the abstract function corresponding to the
* method. For fields, it is an abstract representation of their initial value(s).
*/
private AbstractValue getAnInitialMemberValue(MemberDefinition m) {
not m instanceof AccessorMethodDefinition and
result = m.getInit().analyze().getALocalValue()
}
/**
* Holds if `baseVal` is an abstract value whose properties we track for the purposes
* of `getALocalValue`.
*/
predicate shouldAlwaysTrackProperties(AbstractValue baseVal) {
baseVal instanceof AbstractModuleObject or
baseVal instanceof AbstractExportsObject or
baseVal instanceof AbstractCallable
}
/** Holds if `baseVal` is an abstract value whose properties we track. */
predicate shouldTrackProperties(AbstractValue baseVal) {
shouldAlwaysTrackProperties(baseVal) or
baseVal instanceof AbstractObjectLiteral or
baseVal instanceof AbstractInstance or
baseVal.(CustomAbstractValueFromDefinition).shouldTrackProperties()
}