mirror of
https://github.com/github/codeql.git
synced 2026-04-28 10:15:14 +02:00
Merge pull request #424 from esben-semmle/js/syntactic-nullOrUndefined
Approved by asger-semmle
This commit is contained in:
@@ -27,12 +27,12 @@ predicate acceptableRedefinition(Identifier id) {
|
||||
// Date = global.Date
|
||||
exists (AssignExpr assgn |
|
||||
id = assgn.getTarget() and
|
||||
id.getName() = assgn.getRhs().stripParens().(PropAccess).getPropertyName()
|
||||
id.getName() = assgn.getRhs().getUnderlyingValue().(PropAccess).getPropertyName()
|
||||
) or
|
||||
// var Date = global.Date
|
||||
exists (VariableDeclarator decl |
|
||||
id = decl.getBindingPattern() and
|
||||
id.getName() = decl.getInit().stripParens().(PropAccess).getPropertyName()
|
||||
id.getName() = decl.getInit().getUnderlyingValue().(PropAccess).getPropertyName()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import javascript
|
||||
* Holds if `e` is an expression whose value is invoked as a function.
|
||||
*/
|
||||
private predicate isCallee(Expr e) {
|
||||
exists (InvokeExpr invk | e = invk.getCallee().stripParens())
|
||||
exists (InvokeExpr invk | e = invk.getCallee().getUnderlyingValue())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,7 +65,7 @@ predicate maybeNegativeVar(Variable v) {
|
||||
// is v ever assigned a potentially negative value?
|
||||
maybeNegative(v.getAnAssignedExpr()) or
|
||||
// is v ever decremented?
|
||||
exists (DecExpr dec | dec.getOperand().stripParens() = v.getAnAccess()) or
|
||||
exists (DecExpr dec | dec.getOperand().getUnderlyingReference() = v.getAnAccess()) or
|
||||
// is v ever subject to a compound assignment other than +=, or to
|
||||
// += with potentially negative rhs?
|
||||
exists (CompoundAssignExpr assgn | assgn.getTarget() = v.getAnAccess() |
|
||||
|
||||
@@ -37,13 +37,13 @@ predicate acceptableSignCheck(BitwiseExpr b) {
|
||||
* is sign-preserving, we shouldn't flag it (and we allow arbitrary shifts, not just 16-bit ones)
|
||||
*/
|
||||
exists (RShiftExpr rsh, LShiftExpr lsh |
|
||||
rsh = b and lsh = rsh.getLeftOperand().stripParens() and
|
||||
rsh = b and lsh = rsh.getLeftOperand().getUnderlyingValue() and
|
||||
lsh.getRightOperand().getIntValue() = rsh.getRightOperand().getIntValue()
|
||||
)
|
||||
}
|
||||
|
||||
from Comparison e, BitwiseExpr b
|
||||
where b = e.getLeftOperand().stripParens() and
|
||||
where b = e.getLeftOperand().getUnderlyingValue() and
|
||||
not e instanceof EqualityTest and
|
||||
e.getRightOperand().getIntValue() = 0 and
|
||||
not acceptableSignCheck(b)
|
||||
|
||||
@@ -58,7 +58,7 @@ class RedundantIdemnecantOperand extends RedundantOperand {
|
||||
exists (IdemnecantExpr parent |
|
||||
parent = getParent() and
|
||||
// exclude trivial cases like `1-1`
|
||||
not parent.getRightOperand().stripParens() instanceof Literal
|
||||
not parent.getRightOperand().getUnderlyingValue() instanceof Literal
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class RedundantIdempotentOperand extends RedundantOperand {
|
||||
*/
|
||||
class AverageExpr extends DivExpr {
|
||||
AverageExpr() {
|
||||
getLeftOperand().stripParens() instanceof AddExpr and
|
||||
getLeftOperand().getUnderlyingValue() instanceof AddExpr and
|
||||
getRightOperand().getIntValue() = 2
|
||||
}
|
||||
}
|
||||
@@ -91,12 +91,12 @@ class AverageExpr extends DivExpr {
|
||||
class RedundantAverageOperand extends RedundantOperand {
|
||||
RedundantAverageOperand() {
|
||||
exists (AverageExpr aver |
|
||||
(AddExpr)getParent() = aver.getLeftOperand().stripParens()
|
||||
(AddExpr)getParent() = aver.getLeftOperand().getUnderlyingValue()
|
||||
)
|
||||
}
|
||||
|
||||
override AverageExpr toReport() {
|
||||
getParent() = result.getLeftOperand().stripParens()
|
||||
getParent() = result.getLeftOperand().getUnderlyingValue()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class EqOrSwitch extends ASTNode {
|
||||
}
|
||||
|
||||
from EqOrSwitch et, TypeofExpr typeof, ConstantString str
|
||||
where typeof = et.getAnOperand().stripParens() and
|
||||
str = et.getAnOperand().stripParens() and
|
||||
where typeof = et.getAnOperand().getUnderlyingValue() and
|
||||
str = et.getAnOperand().getUnderlyingValue() and
|
||||
not str.getStringValue().regexpMatch("undefined|boolean|number|string|object|function|symbol|unknown|date|bigint")
|
||||
select typeof, "The result of this 'typeof' expression is compared to '$@', but the two can never be equal.", str, str.getStringValue()
|
||||
|
||||
@@ -56,7 +56,7 @@ int numRet(Function f) {
|
||||
predicate isDualUseConstructor(Function f) {
|
||||
numRet(f) = 1 and
|
||||
exists (ReturnStmt ret, DataFlow::NewNode new | ret.getContainer() = f |
|
||||
new.asExpr() = ret.getExpr().stripParens() and
|
||||
new.asExpr() = ret.getExpr().getUnderlyingValue() and
|
||||
new.getACallee() = f
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class IncrementExpr extends Expr {
|
||||
// x = x + e
|
||||
exists (AssignExpr assgn, Variable v | assgn = this |
|
||||
assgn.getTarget() = v.getAnAccess() and
|
||||
assgn.getRhs().(AddExpr).getAnOperand().stripParens() = v.getAnAccess()
|
||||
assgn.getRhs().(AddExpr).getAnOperand().getUnderlyingReference() = v.getAnAccess()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ import semmle.javascript.dataflow.Refinements
|
||||
*/
|
||||
predicate isDefensiveInit(VarAccess va) {
|
||||
exists (LogOrExpr o, VarRef va2 |
|
||||
va = o.getLeftOperand().stripParens() and va2.getVariable() = va.getVariable() |
|
||||
va = o.getLeftOperand().getUnderlyingReference() and va2.getVariable() = va.getVariable() |
|
||||
exists (AssignExpr assgn | va2 = assgn.getTarget() |
|
||||
assgn = o.getRightOperand().stripParens() or
|
||||
o = assgn.getRhs().stripParens()
|
||||
o = assgn.getRhs().getUnderlyingValue()
|
||||
) or
|
||||
exists (VariableDeclarator vd | va2 = vd.getBindingPattern() |
|
||||
o = vd.getInit().stripParens()
|
||||
o = vd.getInit().getUnderlyingValue()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ private import Declarations.Declarations
|
||||
* `x` has kind `"V"`.
|
||||
*/
|
||||
string refKind(RefExpr r) {
|
||||
if exists(InvokeExpr invk | r = invk.getCallee().stripParens()) then
|
||||
if exists(InvokeExpr invk | r = invk.getCallee().getUnderlyingReference()) then
|
||||
result = "M"
|
||||
else
|
||||
result = "V"
|
||||
@@ -143,7 +143,7 @@ predicate typedInvokeLookup(ASTNode ref, ASTNode decl, string kind) {
|
||||
not variableDefLookup(ref, decl, _) and
|
||||
not propertyLookup(ref, decl, _) and
|
||||
exists (InvokeExpr invoke, Expr callee |
|
||||
callee = invoke.getCallee().stripParens() and
|
||||
callee = invoke.getCallee().getUnderlyingReference() and
|
||||
(ref = callee.(Identifier) or ref = callee.(DotExpr).getPropertyNameExpr()) and
|
||||
decl = invoke.getResolvedCallee() and
|
||||
kind = "M")
|
||||
|
||||
@@ -172,7 +172,7 @@ class AMDModuleDefinition extends CallExpr {
|
||||
* Gets a call to `require` inside this module.
|
||||
*/
|
||||
CallExpr getARequireCall() {
|
||||
result.getCallee().stripParens() = getRequireVariable().getAnAccess()
|
||||
result.getCallee().getUnderlyingValue() = getRequireVariable().getAnAccess()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -291,7 +291,7 @@ class SuperExpr extends @superexpr, Expr {
|
||||
*/
|
||||
class SuperCall extends CallExpr {
|
||||
SuperCall() {
|
||||
getCallee().stripParens() instanceof SuperExpr
|
||||
getCallee().getUnderlyingValue() instanceof SuperExpr
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,7 +299,7 @@ class SuperCall extends CallExpr {
|
||||
* which is the nearest enclosing non-arrow function.
|
||||
*/
|
||||
Function getBinder() {
|
||||
result = getCallee().stripParens().(SuperExpr).getBinder()
|
||||
result = getCallee().getUnderlyingValue().(SuperExpr).getBinder()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ class SuperCall extends CallExpr {
|
||||
*/
|
||||
class SuperPropAccess extends PropAccess {
|
||||
SuperPropAccess() {
|
||||
getBase().stripParens() instanceof SuperExpr
|
||||
getBase().getUnderlyingValue() instanceof SuperExpr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ private predicate defn(ControlFlowNode def, Expr lhs, AST::ValueNode rhs) {
|
||||
private predicate defn(ControlFlowNode def, Expr lhs) {
|
||||
defn(def, lhs, _) or
|
||||
lhs = def.(CompoundAssignExpr).getTarget() or
|
||||
lhs = def.(UpdateExpr).getOperand().stripParens() or
|
||||
lhs = def.(UpdateExpr).getOperand().getUnderlyingReference() or
|
||||
lhs = def.(ImportSpecifier).getLocal() or
|
||||
exists (EnhancedForLoop efl | def = efl.getIteratorExpr() |
|
||||
lhs = def.(Expr).stripParens() or
|
||||
@@ -143,7 +143,7 @@ class RValue extends RefExpr {
|
||||
not this instanceof LValue and not this instanceof VarDecl or
|
||||
// in `x++` and `x += 1`, `x` is both RValue and LValue
|
||||
this = any(CompoundAssignExpr a).getTarget() or
|
||||
this = any(UpdateExpr u).getOperand().stripParens() or
|
||||
this = any(UpdateExpr u).getOperand().getUnderlyingReference() or
|
||||
this = any(NamespaceDeclaration decl).getId()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,7 +710,7 @@ class InvokeExpr extends @invokeexpr, Expr {
|
||||
|
||||
/** Gets the name of the function or method being invoked, if it can be determined. */
|
||||
string getCalleeName() {
|
||||
exists (Expr callee | callee = getCallee().stripParens() |
|
||||
exists (Expr callee | callee = getCallee().getUnderlyingValue() |
|
||||
result = ((Identifier)callee).getName() or
|
||||
result = ((PropAccess)callee).getPropertyName()
|
||||
)
|
||||
@@ -1690,10 +1690,10 @@ class ImmediatelyInvokedFunctionExpr extends Function {
|
||||
|
||||
ImmediatelyInvokedFunctionExpr() {
|
||||
// direct call
|
||||
this = invk.getCallee().stripParens() and kind = "direct" or
|
||||
this = invk.getCallee().getUnderlyingValue() and kind = "direct" or
|
||||
// reflective call
|
||||
exists (MethodCallExpr mce | mce = invk |
|
||||
this = mce.getReceiver().stripParens() and
|
||||
this = mce.getReceiver().getUnderlyingValue() and
|
||||
kind = mce.getMethodName() and
|
||||
(kind = "call" or kind = "apply")
|
||||
)
|
||||
|
||||
@@ -319,7 +319,7 @@ class VarAccess extends @varaccess, VarRef, LexicalAccess {
|
||||
|
||||
override predicate isLValue() {
|
||||
exists (Assignment assgn | assgn.getTarget() = this) or
|
||||
exists (UpdateExpr upd | upd.getOperand().stripParens() = this) or
|
||||
exists (UpdateExpr upd | upd.getOperand().getUnderlyingReference() = this) or
|
||||
exists (EnhancedForLoop efl | efl.getIterator() = this) or
|
||||
exists (BindingPattern p | this = p.getABindingVarRef() and p.isLValue())
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ abstract class SourceNode extends DataFlow::Node {
|
||||
*/
|
||||
DataFlow::CallNode getAMethodCall(string methodName) {
|
||||
exists (PropAccess pacc |
|
||||
pacc = result.getCalleeNode().asExpr().stripParens() and
|
||||
pacc = result.getCalleeNode().asExpr().getUnderlyingReference() and
|
||||
flowsToExpr(pacc.getBase()) and
|
||||
pacc.getPropertyName() = methodName
|
||||
)
|
||||
|
||||
@@ -159,7 +159,7 @@ private class AnalyzedJSXEmptyExpression extends DataFlow::AnalyzedValueNode{
|
||||
*/
|
||||
private class AnalyzedSuperCall extends DataFlow::AnalyzedValueNode {
|
||||
AnalyzedSuperCall() {
|
||||
astNode = any(SuperCall sc).getCallee().stripParens()
|
||||
astNode = any(SuperCall sc).getCallee().getUnderlyingValue()
|
||||
}
|
||||
|
||||
override AbstractValue getALocalValue() {
|
||||
|
||||
@@ -36,7 +36,7 @@ predicate isBrowserifyBundle(ObjectExpr oe) {
|
||||
isBrowserifyBundledModule(p)
|
||||
) and
|
||||
// the whole object must be passed to the module loader function
|
||||
exists (CallExpr ce | ce.getCallee().stripParens() instanceof Function |
|
||||
exists (CallExpr ce | ce.getCallee().getUnderlyingValue() instanceof Function |
|
||||
// the module loader function always has three arguments
|
||||
ce.getNumArgument() = 3 and
|
||||
// the first of which is the bundle
|
||||
@@ -140,10 +140,10 @@ private predicate isWebpackModule(FunctionExpr m) {
|
||||
*/
|
||||
predicate isWebpackBundle(ArrayExpr ae) {
|
||||
// ensure that there is at least one bundled module
|
||||
isWebpackModule(ae.getAnElement().stripParens())
|
||||
isWebpackModule(ae.getAnElement().getUnderlyingValue())
|
||||
and
|
||||
// furthermore, every element is either
|
||||
forall (Expr elt | elt = ae.getAnElement().stripParens() |
|
||||
forall (Expr elt | elt = ae.getAnElement().getUnderlyingValue() |
|
||||
// (1) a module
|
||||
isWebpackModule(elt)
|
||||
or
|
||||
@@ -158,7 +158,7 @@ predicate isWebpackBundle(ArrayExpr ae) {
|
||||
)
|
||||
and
|
||||
// the whole array must be passed to a module loader function
|
||||
exists (CallExpr ce | ce.getCallee().stripParens() instanceof Function |
|
||||
exists (CallExpr ce | ce.getCallee().getUnderlyingValue() instanceof Function |
|
||||
// which is the bundle
|
||||
ce.getArgument(0) = ae
|
||||
)
|
||||
|
||||
@@ -16,10 +16,10 @@ import javascript
|
||||
bindingset[regexp]
|
||||
predicate isReadFrom(DataFlow::Node read, string regexp) {
|
||||
exists (DataFlow::Node actualRead |
|
||||
actualRead = read.asExpr().stripParens().(LogOrExpr).getAnOperand().flow() or // unfold `x || y` once
|
||||
actualRead = read.asExpr().getUnderlyingValue().(LogOrExpr).getAnOperand().flow() or // unfold `x || y` once
|
||||
actualRead = read |
|
||||
exists (string name | name.regexpMatch(regexp) |
|
||||
actualRead.asExpr().stripParens().(VarAccess).getName() = name or
|
||||
actualRead.asExpr().getUnderlyingValue().(VarAccess).getName() = name or
|
||||
actualRead.(DataFlow::PropRead).getPropertyName() = name or
|
||||
actualRead.(DataFlow::InvokeNode).getCalleeName() = "get" + name
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user