diff --git a/javascript/ql/lib/semmle/javascript/AST.qll b/javascript/ql/lib/semmle/javascript/AST.qll index 0467847a9a0..0e6330605ba 100644 --- a/javascript/ql/lib/semmle/javascript/AST.qll +++ b/javascript/ql/lib/semmle/javascript/AST.qll @@ -477,6 +477,8 @@ module AST { DataFlow::AnalyzedNode analyze() { result = DataFlow::valueNode(this).analyze() } /** Gets the data flow node associated with this program element. */ + overlay[caller] + pragma[inline] DataFlow::ValueNode flow() { result = DataFlow::valueNode(this) } /** diff --git a/javascript/ql/lib/semmle/javascript/Regexp.qll b/javascript/ql/lib/semmle/javascript/Regexp.qll index dba2c853008..db779e600d6 100644 --- a/javascript/ql/lib/semmle/javascript/Regexp.qll +++ b/javascript/ql/lib/semmle/javascript/Regexp.qll @@ -1016,7 +1016,7 @@ overlay[global] pragma[inline] private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) { any(Comparison compare) - .hasOperands(value.getALocalUse().asExpr(), any(Expr e | e.analyze().getAType() = TTNumber())) + .hasOperands(value.getALocalUse().asExpr(), any(Expr e | canBeNumber(e.analyze()))) or value.flowsToExpr(any(ArithmeticExpr e).getAnOperand()) or @@ -1031,6 +1031,16 @@ private predicate isUsedAsNumber(DataFlow::LocalSourceNode value) { ) } +bindingset[node] +overlay[global] +pragma[inline_late] +private predicate canBeString(DataFlow::AnalyzedNode node) { node.getAType() = TTString() } + +bindingset[node] +overlay[global] +pragma[inline_late] +private predicate canBeNumber(DataFlow::AnalyzedNode node) { node.getAType() = TTNumber() } + /** * Holds if `source` may be interpreted as a regular expression. */ @@ -1038,14 +1048,14 @@ overlay[global] cached predicate isInterpretedAsRegExp(DataFlow::Node source) { Stages::Taint::ref() and - source.analyze().getAType() = TTString() and + canBeString(source) and ( // The first argument to an invocation of `RegExp` (with or without `new`). source = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0) or // The argument of a call that coerces the argument to a regular expression. exists(DataFlow::MethodCallNode mce, string methodName | - mce.getReceiver().analyze().getAType() = TTString() and + canBeString(mce.getReceiver()) and mce.getMethodName() = methodName and not exists(Function func | func = mce.getACallee() | not isNativeStringMethod(func, methodName) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll index 9d4bda428b5..a5fb31df57e 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/DataFlow.qll @@ -1431,6 +1431,7 @@ module DataFlow { * This predicate is only defined for expressions, properties, and for statements that declare * a function, a class, or a TypeScript namespace or enum. */ + pragma[nomagic] ValueNode valueNode(AstNode nd) { result.getAstNode() = nd } /** diff --git a/javascript/ql/lib/semmle/javascript/frameworks/LazyCache.qll b/javascript/ql/lib/semmle/javascript/frameworks/LazyCache.qll index aec8c82247f..e8b389e91ad 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/LazyCache.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/LazyCache.qll @@ -45,7 +45,7 @@ module LazyCache { pragma[noopt] override DataFlow::Node getImportedModuleNode() { this instanceof LazyCacheImport and - result = this.flow() + result = DataFlow::valueNode(this) or exists(LazyCacheVariable variable, Expr base, PropAccess access, string localName | // To avoid recursion, this should not depend on `SourceNode`. @@ -54,7 +54,7 @@ module LazyCache { access.getBase() = base and localName = this.getLocalAlias() and access.getPropertyName() = localName and - result = access.flow() + result = DataFlow::valueNode(access) ) } } diff --git a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll index 68298c3fb55..d8460f7d729 100644 --- a/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll +++ b/javascript/ql/lib/semmle/javascript/internal/flow_summaries/ForOfLoops.qll @@ -50,12 +50,18 @@ class ForOfLoopStep extends AdditionalFlowInternal { ) { exists(ForOfStmt stmt | pred = getSynthesizedNode(stmt, "for-of-map-key") and - contents.asSingleton().asArrayIndex() = 0 + contents = arrayIndex0() or pred = getSynthesizedNode(stmt, "for-of-map-value") and - contents.asSingleton().asArrayIndex() = 1 + contents = arrayIndex1() | succ = DataFlow::lvalueNode(stmt.getLValue()) ) } } + +pragma[nomagic] +private DataFlow::ContentSet arrayIndex0() { result.asSingleton().asArrayIndex() = 0 } + +pragma[nomagic] +private DataFlow::ContentSet arrayIndex1() { result.asSingleton().asArrayIndex() = 1 }