mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Merge master into next.
master as of dc3c5a684c
Version numbers resolved in favour of `next`.
C++ expected output file updated to accept test output.
This commit is contained in:
@@ -25,25 +25,6 @@ predicate deadStoreOfLocal(VarDef vd, PurelyLocalVariable v) {
|
||||
not exists (SsaExplicitDefinition ssa | ssa.defines(vd, v))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression evaluating to `null` or `undefined`.
|
||||
*
|
||||
* This includes not only direct references to `null` and `undefined`, but
|
||||
* also `void` expressions and assignments of the form `x = rhs`, where `rhs`
|
||||
* is itself an expression evaluating to `null` or `undefined`.
|
||||
*/
|
||||
predicate isNullOrUndef(Expr e) {
|
||||
exists (Expr inner |
|
||||
inner = e.stripParens() |
|
||||
// `null` or `undefined`
|
||||
inner instanceof NullLiteral or
|
||||
inner.(VarAccess).getName() = "undefined" or
|
||||
inner instanceof VoidExpr or
|
||||
// recursive case to catch multi-assignments of the form `x = y = null`
|
||||
isNullOrUndef(inner.(AssignExpr).getRhs())
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is an expression that may be used as a default initial value,
|
||||
* such as `0` or `-1`, or an empty object or array literal.
|
||||
@@ -57,9 +38,7 @@ predicate isDefaultInit(Expr e) {
|
||||
// initialising to an empty array or object literal, even if unnecessary,
|
||||
// can convey useful type information to the reader
|
||||
e.(ArrayExpr).getSize() = 0 or
|
||||
e.(ObjectExpr).getNumProperty() = 0 or
|
||||
// recursive case
|
||||
isDefaultInit(e.(AssignExpr).getRhs())
|
||||
e.(ObjectExpr).getNumProperty() = 0
|
||||
}
|
||||
|
||||
from VarDef dead, PurelyLocalVariable v // captured variables may be read by closures, so don't flag them
|
||||
@@ -77,9 +56,9 @@ where deadStoreOfLocal(dead, v) and
|
||||
not fd = outer.getBody().(BlockStmt).getAStmt()
|
||||
) and
|
||||
// don't flag overwrites with `null` or `undefined`
|
||||
not isNullOrUndef(dead.getSource()) and
|
||||
not SyntacticConstants::isNullOrUndefined(dead.getSource()) and
|
||||
// don't flag default inits that are later overwritten
|
||||
not (isDefaultInit(dead.getSource()) and dead.isOverwritten(v)) and
|
||||
not (isDefaultInit(dead.getSource().(Expr).getUnderlyingValue()) and dead.isOverwritten(v)) and
|
||||
// don't flag assignments in externs
|
||||
not dead.(ASTNode).inExternsFile() and
|
||||
// don't flag exported variables
|
||||
|
||||
@@ -56,10 +56,17 @@ predicate isPropertyFilter(UnusedLocal v) {
|
||||
predicate isReactImportForJSX(UnusedLocal v) {
|
||||
exists (ImportSpecifier is |
|
||||
is.getLocal() = v.getADeclaration() and
|
||||
exists (JSXNode jsx | jsx.getTopLevel() = is.getTopLevel()) |
|
||||
v.getName() = "React" or
|
||||
// also accept legacy `@jsx` pragmas
|
||||
exists (JSXNode jsx | jsx.getTopLevel() = is.getTopLevel())
|
||||
|
|
||||
v.getName() = "React"
|
||||
or
|
||||
// legacy `@jsx` pragmas
|
||||
exists (JSXPragma p | p.getTopLevel() = is.getTopLevel() | p.getDOMName() = v.getName())
|
||||
or
|
||||
// JSX pragma from a .babelrc file
|
||||
exists (Babel::TransformReactJsxConfig plugin |
|
||||
plugin.appliesTo(is.getTopLevel()) and
|
||||
plugin.getJsxFactoryVariableName() = v.getName())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,4 +14,4 @@ from Directive d
|
||||
where not d instanceof KnownDirective and
|
||||
// but exclude attribute top-levels: `<a href="javascript:'some-attribute-string'">`
|
||||
not (d.getParent() instanceof CodeInAttribute)
|
||||
select d, "Unknown directive: '" + d.getDirectiveText() + "'."
|
||||
select d, "Unknown directive: '" + truncate(d.getDirectiveText(), 20, " ... (truncated)") + "'."
|
||||
|
||||
@@ -67,7 +67,27 @@ private cached module Internal {
|
||||
}
|
||||
|
||||
cached predicate defAt(BasicBlock bb, int i, Variable v, VarDef d) {
|
||||
v = d.getAVariable() and bbIndex(bb, d, i)
|
||||
exists (VarRef lhs |
|
||||
lhs = d.getTarget().(BindingPattern).getABindingVarRef() and
|
||||
v = lhs.getVariable() |
|
||||
lhs = d.getTarget() and
|
||||
bbIndex(bb, d, i)
|
||||
or
|
||||
exists (PropertyPattern pp |
|
||||
lhs = pp.getValuePattern() and
|
||||
bbIndex(bb, pp, i)
|
||||
)
|
||||
or
|
||||
exists (ObjectPattern op |
|
||||
lhs = op.getRest() and
|
||||
bbIndex(bb, lhs, i)
|
||||
)
|
||||
or
|
||||
exists (ArrayPattern ap |
|
||||
lhs = ap.getAnElement() and
|
||||
bbIndex(bb, lhs, i)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate reachableBB(BasicBlock bb) {
|
||||
|
||||
@@ -127,14 +127,32 @@ module SyntacticConstants {
|
||||
class WrappedConstant extends SyntacticConstant {
|
||||
|
||||
WrappedConstant() {
|
||||
stripParens() instanceof SyntacticConstant or
|
||||
this.(SeqExpr).getLastOperand() instanceof SyntacticConstant or
|
||||
this.(TypeAssertion).getExpression() instanceof SyntacticConstant or
|
||||
this.(Assignment).getRhs() instanceof SyntacticConstant
|
||||
getUnderlyingValue() instanceof SyntacticConstant
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `c` evaluates to `undefined`.
|
||||
*/
|
||||
predicate isUndefined(SyntacticConstant c) {
|
||||
c.getUnderlyingValue() instanceof UndefinedConstant
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `c` evaluates to `null`.
|
||||
*/
|
||||
predicate isNull(SyntacticConstant c) {
|
||||
c.getUnderlyingValue() instanceof NullConstant
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `c` evaluates to `null` or `undefined`.
|
||||
*/
|
||||
predicate isNullOrUndefined(SyntacticConstant c) {
|
||||
isUndefined(c) or isNull(c)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,7 +98,8 @@ private predicate lvalAux(Expr l, ControlFlowNode def) {
|
||||
exists (ArrayPattern ap | lvalAux(ap, def) | l = ap.getAnElement().stripParens())
|
||||
or
|
||||
exists (ObjectPattern op | lvalAux(op, def) |
|
||||
l = op.getAPropertyPattern().getValuePattern().stripParens()
|
||||
l = op.getAPropertyPattern().getValuePattern().stripParens() or
|
||||
l = op.getRest().stripParens()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,45 @@ class ExprOrType extends @exprortype, Documentable {
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets this expression or type, with any surrounding parentheses removed. */
|
||||
/**
|
||||
* Gets this expression or type, with any surrounding parentheses removed.
|
||||
*
|
||||
* Also see `getUnderlyingValue` and `getUnderlyingReference`.
|
||||
*/
|
||||
ExprOrType stripParens() { result = this }
|
||||
|
||||
/**
|
||||
* Gets the innermost reference that this expression evaluates to, if any.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - a variable or property access: the access itself.
|
||||
* - a parenthesized expression `(e)`: the underlying reference of `e`.
|
||||
* - a TypeScript type assertion `e as T`: the underlying reference of `e`.
|
||||
*
|
||||
* Also see `getUnderlyingValue` and `stripParens`.
|
||||
*/
|
||||
Expr getUnderlyingReference() {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the innermost expression that this expression evaluates to.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - a parenthesised expression `(e)`: the underlying value of `e`.
|
||||
* - a sequence expression `e1, e2`: the underlying value of `e2`.
|
||||
* - an assignment expression `v = e`: the underlying value of `e`.
|
||||
* - a TypeScript type assertion `e as T`: the underlying value of `e`.
|
||||
* - any other expression: the expression itself.
|
||||
*
|
||||
* Also see `getUnderlyingReference` and `stripParens`.
|
||||
*/
|
||||
Expr getUnderlyingValue() {
|
||||
result = this
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** An expression. */
|
||||
@@ -210,6 +247,15 @@ class ParExpr extends @parexpr, Expr {
|
||||
override predicate isImpure() {
|
||||
getExpression().isImpure()
|
||||
}
|
||||
|
||||
override Expr getUnderlyingValue() {
|
||||
result = getExpression().getUnderlyingValue()
|
||||
}
|
||||
|
||||
override Expr getUnderlyingReference() {
|
||||
result = getExpression().getUnderlyingReference()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A `null` literal. */
|
||||
@@ -617,6 +663,11 @@ class SeqExpr extends @seqexpr, Expr {
|
||||
override string getStringValue() {
|
||||
result = getLastOperand().getStringValue()
|
||||
}
|
||||
|
||||
override Expr getUnderlyingValue() {
|
||||
result = getLastOperand().getUnderlyingValue()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A conditional expression. */
|
||||
@@ -862,6 +913,11 @@ class PropAccess extends @propaccess, Expr {
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
result = getBase().getFirstControlFlowNode()
|
||||
}
|
||||
|
||||
override Expr getUnderlyingReference() {
|
||||
result = this
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A dot expression. */
|
||||
@@ -1284,10 +1340,17 @@ class Assignment extends @assignment, Expr {
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
result = getLhs().getFirstControlFlowNode()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A simple assignment expression. */
|
||||
class AssignExpr extends @assignexpr, Assignment {}
|
||||
class AssignExpr extends @assignexpr, Assignment {
|
||||
|
||||
override Expr getUnderlyingValue() {
|
||||
result = getRhs().getUnderlyingValue()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A compound assign expression. */
|
||||
abstract class CompoundAssignExpr extends Assignment {}
|
||||
|
||||
@@ -122,10 +122,7 @@ private cached module Internal {
|
||||
}
|
||||
or TPhi(ReachableJoinBlock bb, SsaSourceVariable v) {
|
||||
liveAtEntry(bb, v) and
|
||||
exists (ReachableBasicBlock defbb, SsaDefinition def |
|
||||
def.definesAt(defbb, _, v) and
|
||||
bb.inDominanceFrontierOf(defbb)
|
||||
)
|
||||
inDefDominanceFrontier(bb, v)
|
||||
}
|
||||
or TRefinement(ReachableBasicBlock bb, int i, GuardControlFlowNode guard, SsaSourceVariable v) {
|
||||
bb.getNode(i) = guard and
|
||||
@@ -133,6 +130,17 @@ private cached module Internal {
|
||||
liveAtEntry(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a definition of `v`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate inDefDominanceFrontier(ReachableJoinBlock bb, SsaSourceVariable v) {
|
||||
exists (ReachableBasicBlock defbb, SsaDefinition def |
|
||||
def.definesAt(defbb, _, v) and
|
||||
bb.inDominanceFrontierOf(defbb)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is a captured variable which is declared in `declContainer` and read in
|
||||
* `useContainer`.
|
||||
@@ -216,6 +224,13 @@ private cached module Internal {
|
||||
ref(bb, i, v, tp)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum rank among all references to `v` in basic block `bb`.
|
||||
*/
|
||||
private int maxRefRank(ReachableBasicBlock bb, SsaSourceVariable v) {
|
||||
result = max(refRank(bb, _, v, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live after the `i`th node of basic block `bb`, where
|
||||
* `i` is the index of a node that may assign or capture `v`.
|
||||
@@ -230,8 +245,8 @@ private cached module Internal {
|
||||
or
|
||||
// this is the last reference to `v` inside `bb`, but `v` is live at entry
|
||||
// to a successor basic block of `bb`
|
||||
r = max(refRank(bb, _, v, _)) and
|
||||
liveAtEntry(bb.getASuccessor(), v)
|
||||
r = maxRefRank(bb, v) and
|
||||
liveAtSuccEntry(bb, v)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -248,6 +263,13 @@ private cached module Internal {
|
||||
// there is no reference to `v` inside `bb`, but `v` is live at entry
|
||||
// to a successor basic block of `bb`
|
||||
not exists(refRank(bb, _, v, _)) and
|
||||
liveAtSuccEntry(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is live at the beginning of any successor of basic block `bb`.
|
||||
*/
|
||||
private predicate liveAtSuccEntry(ReachableBasicBlock bb, SsaSourceVariable v) {
|
||||
liveAtEntry(bb.getASuccessor(), v)
|
||||
}
|
||||
|
||||
@@ -311,25 +333,32 @@ private cached module Internal {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an SSA definition of `v` that reaches the end of the immediate dominator of `bb`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private SsaDefinition getDefReachingEndOfImmediateDominator(ReachableBasicBlock bb, SsaSourceVariable v) {
|
||||
result = getDefReachingEndOf(bb.getImmediateDominator(), v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an SSA definition of `v` that reaches the end of basic block `bb`.
|
||||
*/
|
||||
cached SsaDefinition getDefReachingEndOf(ReachableBasicBlock bb, SsaSourceVariable v) {
|
||||
bb.getASuccessor().localIsLiveAtEntry(v) and
|
||||
(
|
||||
exists (int lastRef | lastRef = max(int i | ssaRef(bb, i, v, _)) |
|
||||
result = getLocalDefinition(bb, lastRef, v)
|
||||
or
|
||||
result.definesAt(bb, lastRef, v)
|
||||
)
|
||||
exists (int lastRef | lastRef = max(int i | ssaRef(bb, i, v, _)) |
|
||||
result = getLocalDefinition(bb, lastRef, v)
|
||||
or
|
||||
/* In SSA form, the (unique) reaching definition of a use is the closest
|
||||
* definition that dominates the use. If two definitions dominate a node
|
||||
* then one must dominate the other, so we can find the reaching definition
|
||||
* by following the idominance relation backwards. */
|
||||
result = getDefReachingEndOf(bb.getImmediateDominator(), v) and
|
||||
not exists (SsaDefinition ssa | ssa.definesAt(bb, _, v))
|
||||
result.definesAt(bb, lastRef, v) and
|
||||
liveAtSuccEntry(bb, v)
|
||||
)
|
||||
or
|
||||
/* In SSA form, the (unique) reaching definition of a use is the closest
|
||||
* definition that dominates the use. If two definitions dominate a node
|
||||
* then one must dominate the other, so we can find the reaching definition
|
||||
* by following the idominance relation backwards. */
|
||||
result = getDefReachingEndOfImmediateDominator(bb, v) and
|
||||
not exists (SsaDefinition ssa | ssa.definesAt(bb, _, v)) and
|
||||
liveAtSuccEntry(bb, v)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1315,6 +1315,15 @@ class TypeAssertion extends Expr, @typeassertion {
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
result = getExpression().getFirstControlFlowNode()
|
||||
}
|
||||
|
||||
override Expr getUnderlyingValue() {
|
||||
result = getExpression().getUnderlyingValue()
|
||||
}
|
||||
|
||||
override Expr getUnderlyingReference() {
|
||||
result = getExpression().getUnderlyingReference()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,15 +12,25 @@ string capitalize(string s) {
|
||||
result = s.charAt(0).toUpperCase() + s.suffix(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pluralization for `n` occurrences of `noun`.
|
||||
*
|
||||
* For example, the pluralization of `"function"` for `n = 2` is `"functions"`.
|
||||
*/
|
||||
/**
|
||||
* Gets the pluralization for `n` occurrences of `noun`.
|
||||
*
|
||||
* For example, the pluralization of `"function"` for `n = 2` is `"functions"`.
|
||||
*/
|
||||
bindingset[noun, n]
|
||||
string pluralize(string noun, int n) {
|
||||
if n = 1 then
|
||||
result = noun
|
||||
else
|
||||
result = noun + "s"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets `str` or a truncated version of `str` with `explanation` appended if its length exceeds `maxLength`.
|
||||
*
|
||||
* For example, the truncation of `"long_string"` for `maxLength = 5` and explanation `" ..."` is `"long_ ..."`.
|
||||
*/
|
||||
bindingset[str, maxLength, explanation]
|
||||
string truncate(string str, int maxLength, string explanation) {
|
||||
if str.length() > maxLength then result = str.prefix(maxLength) + explanation else result = str
|
||||
}
|
||||
|
||||
@@ -298,6 +298,11 @@ class VarRef extends @varref, Identifier, BindingPattern, LexicalRef {
|
||||
override VarRef getABindingVarRef() { result = this }
|
||||
|
||||
override predicate isImpure() { none() }
|
||||
|
||||
override Expr getUnderlyingReference() {
|
||||
result = this
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** An identifier that refers to a variable in a non-declaring position. */
|
||||
|
||||
@@ -28,6 +28,62 @@ module Babel {
|
||||
result.(JSONArray).getElementStringValue(0) = pluginName
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a file affected by this Babel configuration.
|
||||
*/
|
||||
Container getAContainerInScope() {
|
||||
result = getFile().getParentContainer()
|
||||
or
|
||||
result = getAContainerInScope().getAChildContainer() and
|
||||
// File-relative .babelrc search stops at any package.json or .babelrc file.
|
||||
not result.getAChildContainer() = any(PackageJSON pkg).getFile() and
|
||||
not result.getAChildContainer() = any(Config pkg).getFile()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this configuration applies to `tl`.
|
||||
*/
|
||||
predicate appliesTo(TopLevel tl) {
|
||||
tl.getFile() = getAContainerInScope()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration object for a Babel plugin.
|
||||
*/
|
||||
class Plugin extends JSONValue {
|
||||
Config cfg;
|
||||
string pluginName;
|
||||
|
||||
Plugin() {
|
||||
this = cfg.getPluginConfig(pluginName)
|
||||
}
|
||||
|
||||
/** Gets the name of the plugin being installed. */
|
||||
string getPluginName() {
|
||||
result = pluginName
|
||||
}
|
||||
|
||||
/** Gets the enclosing Babel configuration object. */
|
||||
Config getConfig() {
|
||||
result = cfg
|
||||
}
|
||||
|
||||
/** Gets the options value passed to the plugin, if any. */
|
||||
JSONValue getOptions() {
|
||||
result = this.(JSONArray).getElementValue(1)
|
||||
}
|
||||
|
||||
/** Gets a named option from the option object, if present. */
|
||||
JSONValue getOption(string name) {
|
||||
result = getOptions().(JSONObject).getPropValue(name)
|
||||
}
|
||||
|
||||
/** Holds if this plugin applies to `tl`. */
|
||||
predicate appliesTo(TopLevel tl) {
|
||||
cfg.appliesTo(tl)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,11 +94,9 @@ module Babel {
|
||||
* each path is of the form `{ "rootPathPrefix": "...", "rootPathSuffix": "..." }` and explicitly
|
||||
* specifies a mapping from a path prefix to a root.
|
||||
*/
|
||||
class RootImportConfig extends JSONArray {
|
||||
Config cfg;
|
||||
|
||||
class RootImportConfig extends Plugin {
|
||||
RootImportConfig() {
|
||||
this = cfg.getPluginConfig("babel-plugin-root-import")
|
||||
pluginName = "babel-plugin-root-import"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,15 +116,16 @@ module Babel {
|
||||
*/
|
||||
private JSONObject getARootPathSpec() {
|
||||
// ["babel-plugin-root-import", <spec>]
|
||||
result = getElementValue(1) and
|
||||
result = getOptions() and
|
||||
exists(result.getPropValue("rootPathSuffix"))
|
||||
or
|
||||
exists (JSONArray pathSpecs |
|
||||
// ["babel-plugin-root-import", [ <spec>... ] ]
|
||||
pathSpecs = getElementValue(1)
|
||||
pathSpecs = getOptions()
|
||||
or
|
||||
// ["babel-plugin-root-import", { "paths": [ <spec> ... ] }]
|
||||
pathSpecs = getElementValue(1).(JSONObject).getPropValue("paths") |
|
||||
pathSpecs = getOption("paths")
|
||||
|
|
||||
result = pathSpecs.getElementValue(_)
|
||||
)
|
||||
}
|
||||
@@ -95,20 +150,13 @@ module Babel {
|
||||
Folder getFolder() {
|
||||
result = getFile().getParentContainer()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this configuration applies to `tl`.
|
||||
*/
|
||||
predicate appliesTo(TopLevel tl) {
|
||||
tl.getFile().getParentContainer+() = getFolder()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An import path expression that may be transformed by `babel-plugin-root-import`.
|
||||
*/
|
||||
private class BabelRootTransformedPathExpr extends PathExpr, Expr {
|
||||
RootImportConfig cfg;
|
||||
RootImportConfig plugin;
|
||||
string rawPath;
|
||||
string prefix;
|
||||
string mappedPrefix;
|
||||
@@ -116,16 +164,16 @@ module Babel {
|
||||
|
||||
BabelRootTransformedPathExpr() {
|
||||
this instanceof PathExpr and
|
||||
cfg.appliesTo(getTopLevel()) and
|
||||
plugin.appliesTo(getTopLevel()) and
|
||||
rawPath = getStringValue() and
|
||||
prefix = rawPath.regexpCapture("(.)/(.*)", 1) and
|
||||
suffix = rawPath.regexpCapture("(.)/(.*)", 2) and
|
||||
mappedPrefix = cfg.getRoot(prefix)
|
||||
mappedPrefix = plugin.getRoot(prefix)
|
||||
}
|
||||
|
||||
/** Gets the configuration that applies to this path. */
|
||||
RootImportConfig getConfig() {
|
||||
result = cfg
|
||||
RootImportConfig getPlugin() {
|
||||
result = plugin
|
||||
}
|
||||
|
||||
override string getValue() {
|
||||
@@ -134,7 +182,7 @@ module Babel {
|
||||
|
||||
override Folder getSearchRoot(int priority) {
|
||||
priority = 0 and
|
||||
result = cfg.getFolder()
|
||||
result = plugin.getFolder()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +197,24 @@ module Babel {
|
||||
}
|
||||
|
||||
override Folder getARootFolder() {
|
||||
result = pathExpr.getConfig().getFolder()
|
||||
result = pathExpr.getPlugin().getFolder()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration object for the `transform-react-jsx` plugin.
|
||||
*
|
||||
* The plugin option `{"pragma": xxx}` specifies a variable name used to instantiate
|
||||
* JSX elements.
|
||||
*/
|
||||
class TransformReactJsxConfig extends Plugin {
|
||||
TransformReactJsxConfig() {
|
||||
pluginName = "transform-react-jsx"
|
||||
}
|
||||
|
||||
/** Gets the name of the variable used to create JSX elements. */
|
||||
string getJsxFactoryVariableName() {
|
||||
result = getOption("pragma").(JSONString).getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,20 +579,20 @@
|
||||
| destructuring | 3 | o | 4 | p |
|
||||
| destructuring | 4 | p | 5 | {\\n v ... = p;\\n} |
|
||||
| destructuring | 5 | {\\n v ... = p;\\n} | 6 | var\\n ... } = o; |
|
||||
| destructuring | 6 | var\\n ... } = o; | 7 | {\\n ... \\n } |
|
||||
| destructuring | 6 | var\\n ... } = o; | 10 | o |
|
||||
| destructuring | 7 | {\\n ... } = o | 11 | var\\n ... ] = p; |
|
||||
| destructuring | 7 | {\\n ... \\n } | 8 | x |
|
||||
| destructuring | 8 | x | 8 | x |
|
||||
| destructuring | 8 | x | 9 | y |
|
||||
| destructuring | 9 | y | 7 | {\\n ... } = o |
|
||||
| destructuring | 9 | y | 9 | y |
|
||||
| destructuring | 9 | y | 10 | o |
|
||||
| destructuring | 10 | o | 7 | {\\n ... } = o |
|
||||
| destructuring | 11 | var\\n ... ] = p; | 12 | [\\n ... \\n ] |
|
||||
| destructuring | 10 | o | 7 | {\\n ... \\n } |
|
||||
| destructuring | 11 | var\\n ... ] = p; | 16 | p |
|
||||
| destructuring | 12 | [\\n ... ] = p | 17 | exit node of functio ... = p;\\n} |
|
||||
| destructuring | 12 | [\\n ... \\n ] | 13 | a |
|
||||
| destructuring | 13 | a | 15 | c |
|
||||
| destructuring | 15 | c | 16 | p |
|
||||
| destructuring | 16 | p | 12 | [\\n ... ] = p |
|
||||
| destructuring | 15 | c | 12 | [\\n ... ] = p |
|
||||
| destructuring | 16 | p | 12 | [\\n ... \\n ] |
|
||||
| enum | 1 | 'value' | 1 | a = 'value' |
|
||||
| enum | 1 | E | 1 | a |
|
||||
| enum | 1 | a | 1 | 'value' |
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
| tst.js:47:5:47:5 | 1 |
|
||||
| tst.js:48:1:48:7 | x.p = 1 |
|
||||
| tst.js:48:7:48:7 | 1 |
|
||||
| tst.js:49:1:49:6 | x += 1 |
|
||||
| tst.js:49:6:49:6 | 1 |
|
||||
| tst.ts:1:13:1:21 | <number>1 |
|
||||
| tst.ts:1:21:1:21 | 1 |
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
| d.js:1:1:4:0 | exports object of module d |
|
||||
| d.js:1:1:4:0 | module object of module d |
|
||||
| d.js:1:18:3:1 | object literal |
|
||||
| destructuring.js:1:1:4:1 | function f |
|
||||
| destructuring.js:1:1:4:1 | instance of function f |
|
||||
| e.js:1:1:6:0 | exports object of module e |
|
||||
| e.js:1:1:6:0 | module object of module e |
|
||||
| es2015.js:1:1:50:0 | exports object of module es2015 |
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
| classAccessors.js:11:9:11:11 | myY | classAccessors.js:11:15:11:20 | this.y | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| classAccessors.js:12:9:12:11 | myZ | classAccessors.js:12:15:12:20 | this.z | file://:0:0:0:0 | indefinite value (call) |
|
||||
| classAccessors.js:12:9:12:11 | myZ | classAccessors.js:12:15:12:20 | this.z | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| destructuring.js:2:7:2:24 | { x, y = (z = x) } | destructuring.js:2:28:2:28 | o | file://:0:0:0:0 | indefinite value (call) |
|
||||
| destructuring.js:3:7:3:8 | z1 | destructuring.js:3:12:3:12 | z | file://:0:0:0:0 | indefinite value (heap) |
|
||||
| es2015.js:1:5:1:7 | Sup | es2015.js:1:11:6:1 | class { ... ;\\n }\\n} | es2015.js:1:11:6:1 | class Sup |
|
||||
| es2015.js:4:9:4:12 | ctor | es2015.js:4:16:4:25 | new.target | file://:0:0:0:0 | indefinite value (call) |
|
||||
| es2015.js:19:7:19:11 | _args | es2015.js:19:15:19:18 | args | file://:0:0:0:0 | object |
|
||||
|
||||
4
javascript/ql/test/library-tests/Flow/destructuring.js
Normal file
4
javascript/ql/test/library-tests/Flow/destructuring.js
Normal file
@@ -0,0 +1,4 @@
|
||||
function f(o) {
|
||||
var { x, y = (z = x) } = o, z;
|
||||
var z1 = z;
|
||||
}
|
||||
@@ -38,6 +38,8 @@
|
||||
| classAccessors.js:10:9:10:11 | myX | classAccessors.js:10:15:10:20 | this.x | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| classAccessors.js:11:9:11:11 | myY | classAccessors.js:11:15:11:20 | this.y | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| classAccessors.js:12:9:12:11 | myZ | classAccessors.js:12:15:12:20 | this.z | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| destructuring.js:2:7:2:24 | { x, y = (z = x) } | destructuring.js:2:28:2:28 | o | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| destructuring.js:3:7:3:8 | z1 | destructuring.js:3:12:3:12 | z | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| es2015.js:1:5:1:7 | Sup | es2015.js:1:11:6:1 | class { ... ;\\n }\\n} | class |
|
||||
| es2015.js:4:9:4:12 | ctor | es2015.js:4:16:4:25 | new.target | boolean, class, date, function, null, number, object, regular expression,string or undefined |
|
||||
| es2015.js:19:7:19:11 | _args | es2015.js:19:15:19:18 | args | object |
|
||||
|
||||
1
javascript/ql/test/library-tests/Util/truncate.expected
Normal file
1
javascript/ql/test/library-tests/Util/truncate.expected
Normal file
@@ -0,0 +1 @@
|
||||
| y | | X | XX | XXy |
|
||||
3
javascript/ql/test/library-tests/Util/truncate.ql
Normal file
3
javascript/ql/test/library-tests/Util/truncate.ql
Normal file
@@ -0,0 +1,3 @@
|
||||
import semmle.javascript.Util
|
||||
|
||||
select truncate("X", 0, "y"), truncate("", 2, "y"), truncate("X", 2, "y"), truncate("XX", 2, "y"), truncate("XXX", 2, "y")
|
||||
@@ -1,2 +1,4 @@
|
||||
| tst.js:3:5:3:13 | arguments | Redefinition of arguments. |
|
||||
| tst.js:7:7:7:15 | arguments | Redefinition of arguments. |
|
||||
| tst.js:11:11:11:19 | arguments | Redefinition of arguments. |
|
||||
| tst.js:12:11:12:19 | arguments | Redefinition of arguments. |
|
||||
|
||||
@@ -6,3 +6,8 @@ function f() {
|
||||
function g(x, y) {
|
||||
var arguments = [y, x]; // NOT OK
|
||||
}
|
||||
|
||||
(function (){
|
||||
for ([arguments] of o);
|
||||
for ([arguments = 4] of o);
|
||||
});
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
| tst.js:7:1:7:6 | y = 23 | Assignment to variable y, which is $@ constant. | tst.js:1:1:1:21 | const x ... y = 42; | declared |
|
||||
| tst.js:10:5:10:10 | y = -1 | Assignment to variable y, which is $@ constant. | tst.js:1:1:1:21 | const x ... y = 42; | declared |
|
||||
| tst.js:13:1:13:3 | ++x | Assignment to variable x, which is $@ constant. | tst.js:1:1:1:21 | const x ... y = 42; | declared |
|
||||
| tst.js:25:10:25:14 | [ c ] | Assignment to variable c, which is $@ constant. | tst.js:24:5:24:19 | const c = null; | declared |
|
||||
|
||||
@@ -18,4 +18,9 @@ var z = 56;
|
||||
z = 72;
|
||||
|
||||
// OK
|
||||
const s = "hi";
|
||||
const s = "hi";
|
||||
|
||||
(function (){
|
||||
const c = null;
|
||||
for ([ c ] of o);
|
||||
});
|
||||
|
||||
@@ -153,3 +153,7 @@ function v() {
|
||||
z2 = 42;
|
||||
return x + y + z1 + z2;
|
||||
});
|
||||
|
||||
(function() {
|
||||
for (var a = (x, -1) in v = a, o);
|
||||
});
|
||||
|
||||
@@ -4,3 +4,6 @@
|
||||
| test.js:54:10:54:10 | z | Variable z is used like a local variable, but is missing a declaration. |
|
||||
| test.js:60:6:60:6 | y | Variable y is used like a local variable, but is missing a declaration. |
|
||||
| test.js:66:2:66:2 | z | Variable z is used like a local variable, but is missing a declaration. |
|
||||
| test.js:72:9:72:20 | unresolvable | Variable unresolvable is used like a local variable, but is missing a declaration. |
|
||||
| tst3.js:7:10:7:10 | x | Variable x is used like a local variable, but is missing a declaration. |
|
||||
| tst3.js:7:16:7:19 | rest | Variable rest is used like a local variable, but is missing a declaration. |
|
||||
|
||||
@@ -66,4 +66,10 @@ function r() {
|
||||
z = {};
|
||||
for (var p in z)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
(function() {
|
||||
for ([ unresolvable ] of o) {
|
||||
unresolvable;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,3 +2,8 @@ function sc_alert(i) {
|
||||
for(;i;) ;
|
||||
foo;
|
||||
}
|
||||
|
||||
function f(o) {
|
||||
for({x, ...rest} of o)
|
||||
console.log(x in rest);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"plugins": [
|
||||
["transform-react-jsx", { "pragma": "h" }]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { h } from 'preact'; // OK - JSX element uses 'h' after babel compilation
|
||||
import { q } from 'preact'; // NOT OK - not used
|
||||
|
||||
export default (<div>Hello</div>);
|
||||
@@ -1,6 +1,8 @@
|
||||
| Babelrc/importPragma.jsx:2:1:2:27 | import ... react'; | Unused import q. |
|
||||
| decorated.ts:1:1:1:126 | import ... where'; | Unused import actionHandler. |
|
||||
| decorated.ts:4:10:4:12 | fun | Unused function fun. |
|
||||
| externs.js:6:5:6:13 | iAmUnused | Unused variable iAmUnused. |
|
||||
| importWithoutPragma.jsx:1:1:1:27 | import ... react'; | Unused import h. |
|
||||
| multi-imports.js:1:1:1:29 | import ... om 'x'; | Unused imports a, b, d. |
|
||||
| multi-imports.js:2:1:2:42 | import ... om 'x'; | Unused imports alphabetically, ordered. |
|
||||
| typeoftype.ts:9:7:9:7 | y | Unused variable y. |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import { h } from 'preact'; // NOT OK - not in scope of .babelrc file
|
||||
|
||||
export default (<div>Hello</div>);
|
||||
@@ -87,4 +87,11 @@ function l() {
|
||||
|
||||
1n + 1; // NOT OK, but not currently flagged
|
||||
|
||||
(function(){
|
||||
let sum = 0;
|
||||
for ({value} of async(o)) {
|
||||
sum += value;
|
||||
}
|
||||
});
|
||||
|
||||
// semmle-extractor-options: --experimental
|
||||
|
||||
@@ -15,3 +15,15 @@
|
||||
if (x !== undefined)
|
||||
x.p;
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var v0
|
||||
for({ v0 } of o) {
|
||||
v0.p;
|
||||
}
|
||||
|
||||
var v1;
|
||||
for({ v1 = x } of o) {
|
||||
v1.p;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -11,3 +11,5 @@
|
||||
| UnknownDirective.js:12:5:12:17 | "use struct;" | Unknown directive: 'use struct;'. |
|
||||
| UnknownDirective.js:13:5:13:17 | "Use Strict"; | Unknown directive: 'Use Strict'. |
|
||||
| UnknownDirective.js:14:5:14:14 | "use bar"; | Unknown directive: 'use bar'. |
|
||||
| UnknownDirective.js:38:5:38:17 | "[0, 0, 0];"; | Unknown directive: '[0, 0, 0];'. |
|
||||
| UnknownDirective.js:39:5:39:65 | "[0, 0, ... , 0];"; | Unknown directive: '[0, 0, 0, 0, 0, 0, 0 ... (truncated)'. |
|
||||
|
||||
@@ -33,3 +33,8 @@ function good() {
|
||||
"deps foo"; // OK
|
||||
"deps bar"; // OK
|
||||
}
|
||||
|
||||
function data() {
|
||||
"[0, 0, 0];"; // NOT OK
|
||||
"[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];"; // NOT OK
|
||||
}
|
||||
|
||||
@@ -127,3 +127,9 @@ function countOccurrencesDead(xs, p) {
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
(function(a) {
|
||||
for([a] of o) {
|
||||
a;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
| UselessConditional.js:65:5:65:5 | x | Variable 'x' always evaluates to true here. |
|
||||
| UselessConditional.js:76:13:76:13 | x | Variable 'x' always evaluates to true here. |
|
||||
| UselessConditional.js:82:13:82:13 | x | Variable 'x' always evaluates to true here. |
|
||||
| UselessConditional.js:89:10:89:16 | x, true | This expression always evaluates to true. |
|
||||
| UselessConditionalGood.js:58:12:58:13 | x2 | Variable 'x2' always evaluates to false here. |
|
||||
| UselessConditionalGood.js:69:12:69:13 | xy | Variable 'xy' always evaluates to false here. |
|
||||
| UselessConditionalGood.js:85:12:85:13 | xy | Variable 'xy' always evaluates to false here. |
|
||||
|
||||
@@ -84,4 +84,9 @@ async function awaitFlow(){
|
||||
}
|
||||
f3(true);
|
||||
});
|
||||
|
||||
(function() {
|
||||
if ((x, true));
|
||||
});
|
||||
|
||||
// semmle-extractor-options: --experimental
|
||||
|
||||
Reference in New Issue
Block a user