mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
677 lines
21 KiB
Plaintext
677 lines
21 KiB
Plaintext
/**
|
|
* Provides classes for working with abstract values.
|
|
*
|
|
* Abstract values are a finite representation of the potentially
|
|
* infinite set of concrete values observed at runtime.
|
|
*
|
|
* Some abstract values directly correspond to concrete values:
|
|
* for example, there is an abstract `null` value that represents
|
|
* the concrete `null` value.
|
|
*
|
|
* Most abstract values, however, represent a set of concrete
|
|
* values: for example, there is an abstract value `nonzero`
|
|
* representing the set of all non-zero numbers.
|
|
*
|
|
* The flow analysis uses abstract values of the latter kind to
|
|
* finitely overapproximate the infinite set of potential program
|
|
* executions. This entails imprecision of two kinds:
|
|
*
|
|
* - sometimes we deliberately forget information about a
|
|
* concrete value because we are not interested in it: for
|
|
* example, the concrete value `42` is mapped to the abstract
|
|
* value `nonzero`;
|
|
*
|
|
* - at other times, the analysis does not have enough information
|
|
* to precisely model the behavior of certain program elements:
|
|
* for example, the current flow analysis is intra-procedural,
|
|
* so it does not model parameter passing or return values, and
|
|
* hence has to make worst-case assumptions about the possible
|
|
* values of parameters or function calls.
|
|
*
|
|
* We use two categories of abstract values to represent these
|
|
* different sources of imprecision: _definite_ abstract values
|
|
* are deliberate overapproximations, while _indefinite_ abstract
|
|
* values are overapproximations arising from incompleteness.
|
|
*
|
|
* Both kinds of abstract values keep track of which concrete objects
|
|
* they represent; additionally, indefinite abstract values record
|
|
* the source of imprecision that caused them to arise.
|
|
*/
|
|
overlay[local]
|
|
module;
|
|
|
|
private import javascript
|
|
private import semmle.javascript.dataflow.internal.AbstractValuesImpl
|
|
private import InferredTypes
|
|
|
|
/**
|
|
* An abstract value inferred by the flow analysis, representing
|
|
* a set of concrete values.
|
|
*/
|
|
class AbstractValue extends TAbstractValue {
|
|
/**
|
|
* Gets the type of some concrete value represented by this
|
|
* abstract value.
|
|
*/
|
|
abstract InferredType getType();
|
|
|
|
/**
|
|
* Gets the Boolean value some concrete value represented by this
|
|
* abstract value coerces to.
|
|
*/
|
|
pragma[nomagic]
|
|
abstract boolean getBooleanValue();
|
|
|
|
/**
|
|
* Gets an abstract primitive value this abstract value coerces to.
|
|
*
|
|
* This abstractly models the `ToPrimitive` coercion described in the
|
|
* ECMAScript language specification.
|
|
*/
|
|
abstract PrimitiveAbstractValue toPrimitive();
|
|
|
|
/**
|
|
* Holds if this abstract value is coercible to a number, that is, it
|
|
* represents at least one concrete value for which the `ToNumber`
|
|
* conversion does not yield `NaN`.
|
|
*/
|
|
abstract predicate isCoercibleToNumber();
|
|
|
|
/**
|
|
* Holds if this abstract value is an indefinite value arising from the
|
|
* incompleteness `cause`.
|
|
*/
|
|
predicate isIndefinite(DataFlow::Incompleteness cause) { none() }
|
|
|
|
/**
|
|
* Gets an abstract value that represents a prototype object of this value.
|
|
*
|
|
* We currently model three sources of prototypes:
|
|
*
|
|
* - direct assignments to `o.__proto__` are tracked;
|
|
*
|
|
* - for an instance `o` of a function `f`, any value that can be shown to flow into
|
|
* `f.prototype` is considered a prototype object of `o`;
|
|
*
|
|
* - for an instance of a class `C`, any instance of a function or class that can be
|
|
* shown to flow into the `extends` clause of `C` is considered a prototype object
|
|
* of `o`.
|
|
*
|
|
* In all cases, purely local flow tracking is used to find prototype objects, so
|
|
* this predicate cannot be relied on to compute all possible prototype objects.
|
|
*/
|
|
overlay[global]
|
|
DefiniteAbstractValue getAPrototype() {
|
|
exists(AbstractProtoProperty proto |
|
|
proto.getBase() = this and
|
|
result = proto.getAValue()
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Holds if this element is at the specified location.
|
|
* The location spans column `startcolumn` of line `startline` to
|
|
* column `endcolumn` of line `endline` in file `f`.
|
|
* For more information, see
|
|
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
*/
|
|
predicate hasLocationInfo(string f, int startline, int startcolumn, int endline, int endcolumn) {
|
|
f = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
|
}
|
|
|
|
/** Gets a textual representation of this element. */
|
|
abstract string toString();
|
|
}
|
|
|
|
/**
|
|
* A definite abstract value, that is, an abstract value that is not
|
|
* affected by analysis incompleteness.
|
|
*/
|
|
abstract class DefiniteAbstractValue extends AbstractValue { }
|
|
|
|
/**
|
|
* A definite abstract value that represents only primitive concrete values.
|
|
*/
|
|
abstract class PrimitiveAbstractValue extends DefiniteAbstractValue {
|
|
override PrimitiveAbstractValue toPrimitive() { result = this }
|
|
|
|
abstract override PrimitiveType getType();
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing `null`.
|
|
*/
|
|
class AbstractNull extends PrimitiveAbstractValue, TAbstractNull {
|
|
override boolean getBooleanValue() { result = false }
|
|
|
|
override PrimitiveType getType() { result = TTNull() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override string toString() { result = "null" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing `undefined`.
|
|
*/
|
|
class AbstractUndefined extends PrimitiveAbstractValue, TAbstractUndefined {
|
|
override boolean getBooleanValue() { result = false }
|
|
|
|
override PrimitiveType getType() { result = TTUndefined() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override string toString() { result = "undefined" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a Boolean value.
|
|
*/
|
|
class AbstractBoolean extends PrimitiveAbstractValue, TAbstractBoolean {
|
|
override boolean getBooleanValue() { this = TAbstractBoolean(result) }
|
|
|
|
override PrimitiveType getType() { result = TTBoolean() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override string toString() { result = this.getBooleanValue().toString() }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing the number zero.
|
|
*/
|
|
class AbstractZero extends PrimitiveAbstractValue, TAbstractZero {
|
|
override boolean getBooleanValue() { result = false }
|
|
|
|
override PrimitiveType getType() { result = TTNumber() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override string toString() { result = "0" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a non-zero number.
|
|
*/
|
|
class AbstractNonZero extends PrimitiveAbstractValue, TAbstractNonZero {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override PrimitiveType getType() { result = TTNumber() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override string toString() { result = "non-zero value" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing the empty string.
|
|
*/
|
|
class AbstractEmpty extends PrimitiveAbstractValue, TAbstractEmpty {
|
|
override boolean getBooleanValue() { result = false }
|
|
|
|
override PrimitiveType getType() { result = TTString() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override string toString() { result = "\"\"" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a numeric string, that is, a string `s`
|
|
* such that `+s` is not `NaN`.
|
|
*/
|
|
class AbstractNumString extends PrimitiveAbstractValue, TAbstractNumString {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override PrimitiveType getType() { result = TTString() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override string toString() { result = "numeric string" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a non-empty, non-numeric string.
|
|
*/
|
|
class AbstractOtherString extends PrimitiveAbstractValue, TAbstractOtherString {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override PrimitiveType getType() { result = TTString() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override string toString() { result = "non-empty, non-numeric string" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a regular expression.
|
|
*/
|
|
class AbstractRegExp extends DefiniteAbstractValue, TAbstractRegExp {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTRegExp() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override string toString() { result = "regular expression" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a function or class.
|
|
*/
|
|
abstract class AbstractCallable extends DefiniteAbstractValue {
|
|
/**
|
|
* Gets the function represented by this abstract value.
|
|
*
|
|
* For abstract class values, this is the constructor method of the class.
|
|
*/
|
|
abstract Function getFunction();
|
|
|
|
/**
|
|
* Gets the definition of the function or class represented by this abstract value.
|
|
*
|
|
* For abstract class values, this is the definition of the class itself (and not
|
|
* its constructor).
|
|
*/
|
|
abstract AST::ValueNode getDefinition();
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing an individual function.
|
|
*/
|
|
class AbstractFunction extends AbstractCallable, TAbstractFunction {
|
|
override Function getFunction() { this = TAbstractFunction(result) }
|
|
|
|
override AST::ValueNode getDefinition() { result = this.getFunction() }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTFunction() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getFunction()
|
|
.getLocation()
|
|
.hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = this.getFunction().describe() }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing an individual class.
|
|
*/
|
|
class AbstractClass extends AbstractCallable, TAbstractClass {
|
|
/**
|
|
* Gets the class represented by this abstract value.
|
|
*/
|
|
ClassDefinition getClass() { this = TAbstractClass(result) }
|
|
|
|
override Function getFunction() { result = this.getClass().getConstructor().getBody() }
|
|
|
|
override AST::ValueNode getDefinition() { result = this.getClass() }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTClass() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getClass().getLocation().hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = this.getClass().describe() }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a `Date` object.
|
|
*/
|
|
class AbstractDate extends DefiniteAbstractValue, TAbstractDate {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTDate() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result.getType() = TTNumber() }
|
|
|
|
override string toString() { result = "date" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing an `arguments` object.
|
|
*/
|
|
class AbstractArguments extends DefiniteAbstractValue, TAbstractArguments {
|
|
/** Gets the function whose `arguments` object this is an abstraction of. */
|
|
Function getFunction() { this = TAbstractArguments(result) }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getFunction()
|
|
.getLocation()
|
|
.hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = "arguments object of " + this.getFunction().describe() }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing the global object.
|
|
*/
|
|
class AbstractGlobalObject extends DefiniteAbstractValue, TAbstractGlobalObject {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override string toString() { result = "global" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a CommonJS `module` object.
|
|
*/
|
|
class AbstractModuleObject extends DefiniteAbstractValue, TAbstractModuleObject {
|
|
/** Gets the module whose `module` object this abstract value represents. */
|
|
Module getModule() { this = TAbstractModuleObject(result) }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getModule().getLocation().hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = "module object of module " + this.getModule().getName() }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing a CommonJS `exports` object.
|
|
*/
|
|
class AbstractExportsObject extends DefiniteAbstractValue, TAbstractExportsObject {
|
|
/** Gets the module whose `exports` object this abstract value represents. */
|
|
Module getModule() { this = TAbstractExportsObject(result) }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getModule().getLocation().hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = "exports object of module " + this.getModule().getName() }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing all objects arising from an object literal expression
|
|
* (allocation site abstraction).
|
|
*/
|
|
class AbstractObjectLiteral extends DefiniteAbstractValue, TAbstractObjectLiteral {
|
|
/** Gets the object expression this abstract value represents. */
|
|
ObjectExpr getObjectExpr() { this = TAbstractObjectLiteral(result) }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result.getType() = TTString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getObjectExpr()
|
|
.getLocation()
|
|
.hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = "object literal" }
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing all instances of a class or function `F`,
|
|
* as well as the default prototype of `F` (that is, the initial value of
|
|
* `F.prototype`).
|
|
*/
|
|
class AbstractInstance extends DefiniteAbstractValue, TAbstractInstance {
|
|
/** Gets the constructor of this instance. */
|
|
AbstractCallable getConstructor() { this = TAbstractInstance(result) }
|
|
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result.getType() = TTString() }
|
|
|
|
override predicate hasLocationInfo(
|
|
string path, int startline, int startcolumn, int endline, int endcolumn
|
|
) {
|
|
this.getConstructor().hasLocationInfo(path, startline, startcolumn, endline, endcolumn)
|
|
}
|
|
|
|
override string toString() { result = "instance of " + this.getConstructor() }
|
|
}
|
|
|
|
module AbstractInstance {
|
|
/**
|
|
* Gets the abstract value representing instances of `f`, which is a function
|
|
* or a class.
|
|
*/
|
|
AbstractInstance of(AST::ValueNode f) {
|
|
result.getConstructor().getFunction() = f or
|
|
result.getConstructor() = TAbstractClass(f)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An abstract value representing an object not covered by the other abstract
|
|
* values.
|
|
*/
|
|
class AbstractOtherObject extends DefiniteAbstractValue, TAbstractOtherObject {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTObject() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result.getType() = TTString() }
|
|
|
|
override string toString() { result = "object" }
|
|
}
|
|
|
|
/**
|
|
* An indefinite abstract value representing an unknown function or class.
|
|
*/
|
|
class IndefiniteFunctionOrClass extends AbstractValue, TIndefiniteFunctionOrClass {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() { result = TTFunction() or result = TTClass() }
|
|
|
|
override predicate isCoercibleToNumber() { none() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = TAbstractOtherString() }
|
|
|
|
override predicate isIndefinite(DataFlow::Incompleteness cause) {
|
|
this = TIndefiniteFunctionOrClass(cause)
|
|
}
|
|
|
|
override string toString() {
|
|
exists(DataFlow::Incompleteness cause | this.isIndefinite(cause) |
|
|
result = "indefinite function or class (" + cause + ")"
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An indefinite abstract value representing an unknown object.
|
|
*/
|
|
class IndefiniteObject extends AbstractValue, TIndefiniteObject {
|
|
override boolean getBooleanValue() { result = true }
|
|
|
|
override InferredType getType() {
|
|
result = TTDate() or result = TTRegExp() or result = TTObject()
|
|
}
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() {
|
|
result.getType() = TTString() or result.getType() = TTNumber()
|
|
}
|
|
|
|
override predicate isIndefinite(DataFlow::Incompleteness cause) {
|
|
this = TIndefiniteObject(cause)
|
|
}
|
|
|
|
override string toString() {
|
|
exists(DataFlow::Incompleteness cause | this.isIndefinite(cause) |
|
|
result = "indefinite object (" + cause + ")"
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An indefinite abstract value representing an unknown value.
|
|
*/
|
|
class IndefiniteAbstractValue extends AbstractValue, TIndefiniteAbstractValue {
|
|
override boolean getBooleanValue() { result = true or result = false }
|
|
|
|
override InferredType getType() { any() }
|
|
|
|
override predicate isCoercibleToNumber() { any() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { any() }
|
|
|
|
override predicate isIndefinite(DataFlow::Incompleteness cause) {
|
|
this = TIndefiniteAbstractValue(cause)
|
|
}
|
|
|
|
override string toString() {
|
|
exists(DataFlow::Incompleteness cause | this.isIndefinite(cause) |
|
|
result = "indefinite value (" + cause + ")"
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets an abstract value representing a subset of the concrete values represented by
|
|
* this abstract value.
|
|
*
|
|
* Taken together, all results of this predicate taken together must cover the entire
|
|
* set of concrete values represented by this abstract value.
|
|
*/
|
|
AbstractValue split() {
|
|
exists(string cause | this.isIndefinite(cause) |
|
|
result = TIndefiniteFunctionOrClass(cause) or
|
|
result = TIndefiniteObject(cause) or
|
|
result = abstractValueOfType(any(PrimitiveType pt))
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A string tag corresponding to a custom abstract value.
|
|
*/
|
|
abstract class CustomAbstractValueTag extends string {
|
|
bindingset[this]
|
|
CustomAbstractValueTag() { any() }
|
|
|
|
/**
|
|
* Gets the type of some concrete value represented by this
|
|
* abstract value.
|
|
*/
|
|
abstract InferredType getType();
|
|
|
|
/**
|
|
* Gets the Boolean value some concrete value represented by this
|
|
* abstract value coerces to.
|
|
*/
|
|
abstract boolean getBooleanValue();
|
|
|
|
/**
|
|
* Gets an abstract primitive value this abstract value coerces to.
|
|
*
|
|
* This abstractly models the `ToPrimitive` coercion described in the
|
|
* ECMAScript language specification.
|
|
*/
|
|
abstract PrimitiveAbstractValue toPrimitive();
|
|
|
|
/**
|
|
* Holds if this abstract value is coercible to a number, that is, it
|
|
* represents at least one concrete value for which the `ToNumber`
|
|
* conversion does not yield `NaN`.
|
|
*/
|
|
abstract predicate isCoercibleToNumber();
|
|
|
|
/**
|
|
* Holds if this abstract value is an indefinite value arising from the
|
|
* incompleteness `cause`.
|
|
*/
|
|
predicate isIndefinite(DataFlow::Incompleteness cause) { none() }
|
|
|
|
/** Gets a textual representation of this abstract value. */
|
|
abstract string describe();
|
|
}
|
|
|
|
/**
|
|
* A custom abstract value corresponding to an abstract value tag.
|
|
*/
|
|
class CustomAbstractValue extends AbstractValue, TCustomAbstractValue {
|
|
CustomAbstractValueTag tag;
|
|
|
|
CustomAbstractValue() { this = TCustomAbstractValue(tag) }
|
|
|
|
/** Gets the tag that this abstract value corresponds to. */
|
|
CustomAbstractValueTag getTag() { result = tag }
|
|
|
|
override boolean getBooleanValue() { result = tag.getBooleanValue() }
|
|
|
|
override InferredType getType() { result = tag.getType() }
|
|
|
|
override predicate isCoercibleToNumber() { tag.isCoercibleToNumber() }
|
|
|
|
override PrimitiveAbstractValue toPrimitive() { result = tag.toPrimitive() }
|
|
|
|
override predicate isIndefinite(DataFlow::Incompleteness cause) { tag.isIndefinite(cause) }
|
|
|
|
override string toString() { result = tag.describe() }
|
|
}
|