mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Merge pull request #750 from aschackmull/javascript/autoformat
Approved by xiemaisi
This commit is contained in:
@@ -67,31 +67,25 @@ predicate isCompatibleRequestedService(InjectableFunctionServiceRequest request,
|
||||
isWildcardKind(kind)
|
||||
or
|
||||
(
|
||||
(
|
||||
isServiceDirectiveOrFilterFunction(request) or
|
||||
isRunMethod(request) or
|
||||
isControllerFunction(request)
|
||||
) and
|
||||
(
|
||||
kind = "value" or
|
||||
kind = "service" or
|
||||
kind = "factory" or
|
||||
kind = "constant" or
|
||||
kind = "provider-value"
|
||||
)
|
||||
isServiceDirectiveOrFilterFunction(request) or
|
||||
isRunMethod(request) or
|
||||
isControllerFunction(request)
|
||||
) and
|
||||
(
|
||||
kind = "value" or
|
||||
kind = "service" or
|
||||
kind = "factory" or
|
||||
kind = "constant" or
|
||||
kind = "provider-value"
|
||||
)
|
||||
or
|
||||
(
|
||||
isControllerFunction(request) and
|
||||
kind = "controller-only"
|
||||
)
|
||||
isControllerFunction(request) and
|
||||
kind = "controller-only"
|
||||
or
|
||||
isConfigMethod(request) and
|
||||
(
|
||||
isConfigMethod(request) and
|
||||
(
|
||||
kind = "constant" or
|
||||
kind = "provider"
|
||||
)
|
||||
kind = "constant" or
|
||||
kind = "provider"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -105,19 +99,19 @@ string getServiceKind(InjectableFunctionServiceRequest request, string serviceNa
|
||||
exists(CustomServiceDefinition custom |
|
||||
id = custom.getServiceReference() and
|
||||
(
|
||||
(custom instanceof ValueRecipeDefinition and result = "value")
|
||||
custom instanceof ValueRecipeDefinition and result = "value"
|
||||
or
|
||||
(custom instanceof ServiceRecipeDefinition and result = "service")
|
||||
custom instanceof ServiceRecipeDefinition and result = "service"
|
||||
or
|
||||
(custom instanceof FactoryRecipeDefinition and result = "factory")
|
||||
custom instanceof FactoryRecipeDefinition and result = "factory"
|
||||
or
|
||||
(custom instanceof DecoratorRecipeDefinition and result = "decorator")
|
||||
custom instanceof DecoratorRecipeDefinition and result = "decorator"
|
||||
or
|
||||
(custom instanceof ConstantRecipeDefinition and result = "constant")
|
||||
custom instanceof ConstantRecipeDefinition and result = "constant"
|
||||
or
|
||||
(
|
||||
custom instanceof ProviderRecipeDefinition and
|
||||
if (serviceName.matches("%Provider"))
|
||||
if serviceName.matches("%Provider")
|
||||
then result = "provider"
|
||||
else result = "provider-value"
|
||||
)
|
||||
@@ -145,25 +139,17 @@ where
|
||||
compatibleKind
|
||||
).regexpReplaceAll(",(?=[^,]+$)", " or") and
|
||||
(
|
||||
(
|
||||
isServiceDirectiveOrFilterFunction(request) and
|
||||
componentDescriptionString = "Components such as services, directives, filters, and animations"
|
||||
)
|
||||
isServiceDirectiveOrFilterFunction(request) and
|
||||
componentDescriptionString = "Components such as services, directives, filters, and animations"
|
||||
or
|
||||
(
|
||||
isControllerFunction(request) and
|
||||
componentDescriptionString = "Controllers"
|
||||
)
|
||||
isControllerFunction(request) and
|
||||
componentDescriptionString = "Controllers"
|
||||
or
|
||||
(
|
||||
isRunMethod(request) and
|
||||
componentDescriptionString = "Run methods"
|
||||
)
|
||||
isRunMethod(request) and
|
||||
componentDescriptionString = "Run methods"
|
||||
or
|
||||
(
|
||||
isConfigMethod(request) and
|
||||
componentDescriptionString = "Config methods"
|
||||
)
|
||||
isConfigMethod(request) and
|
||||
componentDescriptionString = "Config methods"
|
||||
)
|
||||
select request,
|
||||
"'" + name + "' is a dependency of kind '" + kind + "', and cannot be injected here. " +
|
||||
|
||||
@@ -6,22 +6,26 @@ import semmle.javascript.Comments
|
||||
private string getALineOfCommentedOutCode(Comment c) {
|
||||
result = c.getLine(_) and
|
||||
// line ends with ';', '{', or '}', optionally followed by a comma,
|
||||
((result.regexpMatch(".*[;{}],?\\s*") and
|
||||
(
|
||||
result.regexpMatch(".*[;{}],?\\s*") and
|
||||
// but it doesn't look like a JSDoc-like annotation
|
||||
not result.regexpMatch(".*@\\w+\\s*\\{.*\\}\\s*") and
|
||||
// and it does not contain three consecutive words (which is uncommon in code)
|
||||
not result.regexpMatch("[^'\\\"]*\\w\\s++\\w++\\s++\\w[^'\\\"]*")) or
|
||||
// line is part of a block comment and ends with something that looks
|
||||
// like a line comment; character before '//' must not be ':' to
|
||||
// avoid matching URLs
|
||||
(not c instanceof SlashSlashComment and
|
||||
result.regexpMatch("(.*[^:]|^)//.*[^/].*")) or
|
||||
// similar, but don't be fooled by '//// this kind of comment' and
|
||||
// '//// this kind of comment ////'
|
||||
(c instanceof SlashSlashComment and
|
||||
result.regexpMatch("/*([^/].*[^:]|[^:/])//.*[^/].*") and
|
||||
// exclude externalization comments
|
||||
not result.regexpMatch(".*\\$NON-NLS-\\d+\\$.*")))
|
||||
not result.regexpMatch("[^'\\\"]*\\w\\s++\\w++\\s++\\w[^'\\\"]*")
|
||||
or
|
||||
// line is part of a block comment and ends with something that looks
|
||||
// like a line comment; character before '//' must not be ':' to
|
||||
// avoid matching URLs
|
||||
not c instanceof SlashSlashComment and
|
||||
result.regexpMatch("(.*[^:]|^)//.*[^/].*")
|
||||
or
|
||||
// similar, but don't be fooled by '//// this kind of comment' and
|
||||
// '//// this kind of comment ////'
|
||||
c instanceof SlashSlashComment and
|
||||
result.regexpMatch("/*([^/].*[^:]|[^:/])//.*[^/].*") and
|
||||
// exclude externalization comments
|
||||
not result.regexpMatch(".*\\$NON-NLS-\\d+\\$.*")
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,7 +33,7 @@ private string getALineOfCommentedOutCode(Comment c) {
|
||||
* disregarded when looking for commented-out code.
|
||||
*/
|
||||
private predicate containsCodeExample(Comment c) {
|
||||
exists (string text | text = c.getText() |
|
||||
exists(string text | text = c.getText() |
|
||||
text.matches("%<pre>%</pre>%") or
|
||||
text.matches("%<code>%</code>%") or
|
||||
text.matches("%@example%") or
|
||||
@@ -43,19 +47,19 @@ private predicate containsCodeExample(Comment c) {
|
||||
* preceding it, if any, does not.
|
||||
*/
|
||||
private Comment getCommentInRun(File f, Comment c) {
|
||||
exists (int n |
|
||||
exists(int n |
|
||||
c.onLines(f, n, _) and
|
||||
countCommentedOutLines(c) > 0 and
|
||||
not exists (Comment d | d.onLines(f, _, n-1) |
|
||||
countCommentedOutLines(d) > 0
|
||||
)
|
||||
not exists(Comment d | d.onLines(f, _, n - 1) | countCommentedOutLines(d) > 0)
|
||||
) and
|
||||
(result = c or
|
||||
exists (Comment prev, int n |
|
||||
prev = getCommentInRun(f, c) and
|
||||
prev.onLines(f, _, n) and
|
||||
result.onLines(f, n+1, _)
|
||||
)
|
||||
(
|
||||
result = c
|
||||
or
|
||||
exists(Comment prev, int n |
|
||||
prev = getCommentInRun(f, c) and
|
||||
prev.onLines(f, _, n) and
|
||||
result.onLines(f, n + 1, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -68,9 +72,7 @@ private Comment getRelevantCommentInRun(Comment c) {
|
||||
}
|
||||
|
||||
/** Gets the number of lines in comment `c` that look like commented-out code. */
|
||||
private int countCommentedOutLines(Comment c) {
|
||||
result = count(getALineOfCommentedOutCode(c))
|
||||
}
|
||||
private int countCommentedOutLines(Comment c) { result = count(getALineOfCommentedOutCode(c)) }
|
||||
|
||||
/** Gets the number of non-blank lines in comment `c`. */
|
||||
private int countNonBlankLines(Comment c) {
|
||||
@@ -98,14 +100,14 @@ private int countNonBlankLinesInRun(Comment c) {
|
||||
* `hasLocationInfo` implementation that assigns it the entire run as its location.
|
||||
*/
|
||||
class CommentedOutCode extends Comment {
|
||||
CommentedOutCode(){
|
||||
CommentedOutCode() {
|
||||
exists(int codeLines, int nonBlankLines |
|
||||
countCommentedOutLines(this) > 0 and
|
||||
not exists(Comment prev | this = getCommentInRun(_, prev) and this != prev) and
|
||||
nonBlankLines = countNonBlankLinesInRun(this) and
|
||||
codeLines = countCommentedOutLinesInRun(this) and
|
||||
nonBlankLines > 0 and
|
||||
2*codeLines > nonBlankLines
|
||||
2 * codeLines > nonBlankLines
|
||||
)
|
||||
}
|
||||
|
||||
@@ -113,16 +115,12 @@ class CommentedOutCode extends Comment {
|
||||
* Gets the number of lines in this run of comments
|
||||
* that look like they contain commented-out code.
|
||||
*/
|
||||
int getNumCodeLines() {
|
||||
result = countCommentedOutLinesInRun(this)
|
||||
}
|
||||
int getNumCodeLines() { result = countCommentedOutLinesInRun(this) }
|
||||
|
||||
/**
|
||||
* Gets the number of non-blank lines in this run of comments.
|
||||
*/
|
||||
int getNumNonBlankLines() {
|
||||
result = countNonBlankLinesInRun(this)
|
||||
}
|
||||
int getNumNonBlankLines() { result = countNonBlankLinesInRun(this) }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
@@ -131,18 +129,20 @@ class CommentedOutCode extends Comment {
|
||||
* For more information, see
|
||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
|
||||
exists (Location loc, File f | loc = getLocation() and f = loc.getFile() |
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
exists(Location loc, File f | loc = getLocation() and f = loc.getFile() |
|
||||
filepath = f.getAbsolutePath() and
|
||||
startline = loc.getStartLine() and
|
||||
startcolumn = loc.getStartColumn() and
|
||||
exists(Location last |
|
||||
last = getCommentInRun(f, this).getLocation() and
|
||||
last.getEndLine() = max(getCommentInRun(f, this).getLocation().getEndLine()) |
|
||||
last.getEndLine() = max(getCommentInRun(f, this).getLocation().getEndLine())
|
||||
|
|
||||
endline = last.getEndLine() and
|
||||
endcolumn = last.getEndColumn()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,4 +23,4 @@ predicate isFlowAnnotation(SlashStarComment c) {
|
||||
|
||||
from CommentedOutCode c
|
||||
where not isFlowAnnotation(c)
|
||||
select c, "This comment appears to contain commented-out code."
|
||||
select c, "This comment appears to contain commented-out code."
|
||||
|
||||
@@ -13,6 +13,4 @@
|
||||
import CommentedOut
|
||||
|
||||
from File f
|
||||
select f, sum(CommentedOutCode comment |
|
||||
comment.getFile() = f |
|
||||
comment.getNumCodeLines())
|
||||
select f, sum(CommentedOutCode comment | comment.getFile() = f | comment.getNumCodeLines())
|
||||
|
||||
@@ -14,4 +14,4 @@ import javascript
|
||||
|
||||
from Comment c
|
||||
where c.getText().regexpMatch("(?s).*FIXME.*|.*TODO.*|.*(?<!=)\\s*XXX.*")
|
||||
select c, "TODO comments should be addressed."
|
||||
select c, "TODO comments should be addressed."
|
||||
|
||||
@@ -57,7 +57,7 @@ predicate postDominatedPropWrite(
|
||||
*/
|
||||
bindingset[name]
|
||||
predicate maybeAccessesProperty(Expr e, string name) {
|
||||
(e.(PropAccess).getPropertyName() = name and e instanceof RValue)
|
||||
e.(PropAccess).getPropertyName() = name and e instanceof RValue
|
||||
or
|
||||
// conservatively reject all side-effects
|
||||
e.isImpure()
|
||||
|
||||
@@ -92,18 +92,14 @@ where
|
||||
me.getRightOperand().getIntValue() = 2 and
|
||||
maybeNegative(me.getLeftOperand()) and
|
||||
(
|
||||
(
|
||||
(cmp instanceof EqExpr or cmp instanceof StrictEqExpr) and
|
||||
num = 1 and
|
||||
parity = "oddness"
|
||||
)
|
||||
(cmp instanceof EqExpr or cmp instanceof StrictEqExpr) and
|
||||
num = 1 and
|
||||
parity = "oddness"
|
||||
or
|
||||
(
|
||||
(cmp instanceof NEqExpr or cmp instanceof StrictNEqExpr) and
|
||||
num = 1 and
|
||||
parity = "evenness"
|
||||
)
|
||||
(cmp instanceof NEqExpr or cmp instanceof StrictNEqExpr) and
|
||||
num = 1 and
|
||||
parity = "evenness"
|
||||
or
|
||||
(cmp instanceof GTExpr and num = 0 and parity = "oddness")
|
||||
cmp instanceof GTExpr and num = 0 and parity = "oddness"
|
||||
)
|
||||
select cmp, "Test for " + parity + " does not take negative numbers into account."
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
import javascript
|
||||
|
||||
from Comparison cmp
|
||||
where (cmp.getAnOperand().(GlobalVarAccess)).getName() = "NaN"
|
||||
where cmp.getAnOperand().(GlobalVarAccess).getName() = "NaN"
|
||||
select cmp, "Useless comparison with NaN."
|
||||
|
||||
@@ -30,7 +30,7 @@ predicate inVoidContext(Expr e) {
|
||||
or
|
||||
// if the toplevel in its entirety is of the form `({ ... })`,
|
||||
// it is probably a configuration object (e.g., a require.js build configuration)
|
||||
(tl.getNumChildStmt() = 1 and e.stripParens() instanceof ObjectExpr)
|
||||
tl.getNumChildStmt() = 1 and e.stripParens() instanceof ObjectExpr
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -36,7 +36,7 @@ abstract class Hapax extends @expr {
|
||||
abstract string getName();
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = (this.(Expr)).toString() }
|
||||
string toString() { result = this.(Expr).toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class ImplicitConversionWithWhitelist extends ImplicitConversion {
|
||||
|
||||
override string getAnImplicitConversionTarget(AbstractValue v) {
|
||||
v = getAValue() and
|
||||
not (v.getType() = getAWhitelistedType()) and
|
||||
not v.getType() = getAWhitelistedType() and
|
||||
result = getConversionTarget()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,10 @@ predicate isStringSplitOrReplace(MethodCallExpr mce) {
|
||||
mce.getMethodName() = name and
|
||||
mce.getNumArgument() = arity
|
||||
|
|
||||
(name = "replace" and arity = 2)
|
||||
name = "replace" and arity = 2
|
||||
or
|
||||
(
|
||||
name = "split" and
|
||||
(arity = 1 or arity = 2)
|
||||
)
|
||||
name = "split" and
|
||||
(arity = 1 or arity = 2)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,5 +14,5 @@ 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)
|
||||
not d.getParent() instanceof CodeInAttribute
|
||||
select d, "Unknown directive: '" + truncate(d.getDirectiveText(), 20, " ... (truncated)") + "'."
|
||||
|
||||
@@ -27,23 +27,21 @@ class AssocNestedExpr extends BinaryExpr {
|
||||
exists(BinaryExpr parent, int idx | this = parent.getChildExpr(idx) |
|
||||
// +, *, &&, || and the bitwise operations are associative
|
||||
(
|
||||
(
|
||||
this instanceof AddExpr or
|
||||
this instanceof MulExpr or
|
||||
this instanceof BitwiseExpr or
|
||||
this instanceof LogicalBinaryExpr
|
||||
) and
|
||||
parent.getOperator() = this.getOperator()
|
||||
)
|
||||
this instanceof AddExpr or
|
||||
this instanceof MulExpr or
|
||||
this instanceof BitwiseExpr or
|
||||
this instanceof LogicalBinaryExpr
|
||||
) and
|
||||
parent.getOperator() = this.getOperator()
|
||||
or
|
||||
// (x*y)/z = x*(y/z)
|
||||
(this instanceof MulExpr and parent instanceof DivExpr and idx = 0)
|
||||
this instanceof MulExpr and parent instanceof DivExpr and idx = 0
|
||||
or
|
||||
// (x/y)%z = x/(y%z)
|
||||
(this instanceof DivExpr and parent instanceof ModExpr and idx = 0)
|
||||
this instanceof DivExpr and parent instanceof ModExpr and idx = 0
|
||||
or
|
||||
// (x+y)-z = x+(y-z)
|
||||
(this instanceof AddExpr and parent instanceof SubExpr and idx = 0)
|
||||
this instanceof AddExpr and parent instanceof SubExpr and idx = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -55,12 +53,10 @@ class AssocNestedExpr extends BinaryExpr {
|
||||
class HarmlessNestedExpr extends BinaryExpr {
|
||||
HarmlessNestedExpr() {
|
||||
exists(BinaryExpr parent | this = parent.getAChildExpr() |
|
||||
(
|
||||
parent instanceof Comparison and
|
||||
(this instanceof ArithmeticExpr or this instanceof ShiftExpr)
|
||||
)
|
||||
parent instanceof Comparison and
|
||||
(this instanceof ArithmeticExpr or this instanceof ShiftExpr)
|
||||
or
|
||||
(parent instanceof LogicalExpr and this instanceof Comparison)
|
||||
parent instanceof LogicalExpr and this instanceof Comparison
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class EqOrSwitch extends ASTNode {
|
||||
* of `case 1:` in `switch (y) { case 1: ... }` are `y` and `1`.
|
||||
*/
|
||||
Expr getAnOperand() {
|
||||
result = (this.(EqualityTest)).getAnOperand()
|
||||
result = this.(EqualityTest).getAnOperand()
|
||||
or
|
||||
exists(Case c | c = this |
|
||||
result = c.getSwitch().getExpr() or
|
||||
|
||||
@@ -25,8 +25,8 @@ class Jump extends Stmt {
|
||||
|
||||
/** Gets the target to which this jump refers. */
|
||||
Stmt getTarget() {
|
||||
result = (this.(BreakOrContinueStmt)).getTarget() or
|
||||
result = ((this.(ReturnStmt)).getContainer().(Function)).getBody()
|
||||
result = this.(BreakOrContinueStmt).getTarget() or
|
||||
result = this.(ReturnStmt).getContainer().(Function).getBody()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ class SpuriousArguments extends Expr {
|
||||
from SpuriousArguments args, Function f, string arguments
|
||||
where
|
||||
f = args.getCall().getACallee() and
|
||||
if args.getCount() = 1 then arguments = "argument" else arguments = "arguments" and
|
||||
(if args.getCount() = 1 then arguments = "argument" else arguments = "arguments") and
|
||||
(
|
||||
// exclude empty functions, they are probably commented out debug utilities ...
|
||||
exists(f.getABodyStmt()) or
|
||||
|
||||
@@ -22,8 +22,8 @@ class ArrayOrObjectExpr extends Expr {
|
||||
|
||||
/** Holds if this array or object expression has a trailing comma. */
|
||||
predicate hasTrailingComma() {
|
||||
(this.(ArrayExpr)).hasTrailingComma() or
|
||||
(this.(ObjectExpr)).hasTrailingComma()
|
||||
this.(ArrayExpr).hasTrailingComma() or
|
||||
this.(ObjectExpr).hasTrailingComma()
|
||||
}
|
||||
|
||||
/** Gets a short description of this expression. */
|
||||
|
||||
@@ -69,10 +69,10 @@ where
|
||||
r = m.getAnImport() and
|
||||
imported = r.getImportedModule() and
|
||||
if imported = m
|
||||
then (
|
||||
then
|
||||
// set linktarget and linktext to dummy values in this case
|
||||
msg = "directly imports itself" and linktarget = m and linktext = ""
|
||||
) else
|
||||
else
|
||||
// find an import in `imported` that (directly or indirectly) imports `m`
|
||||
exists(Require r2, Module imported2 |
|
||||
r2 = imported.getAnImport() and imported2 = r2.getImportedModule()
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import javascript
|
||||
|
||||
from RegExpBackRef rebr
|
||||
where rebr.getLocation().getStartColumn() < rebr.getGroup().getLocation().getEndColumn() and
|
||||
not rebr.isInBackwardMatchingContext()
|
||||
select rebr, "This back reference precedes its capture group."
|
||||
where
|
||||
rebr.getLocation().getStartColumn() < rebr.getGroup().getLocation().getEndColumn() and
|
||||
not rebr.isInBackwardMatchingContext()
|
||||
select rebr, "This back reference precedes its capture group."
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
import javascript
|
||||
|
||||
from RegExpNegativeLookahead neg, RegExpGroup grp, RegExpBackRef back
|
||||
where grp.getParent+() = neg and
|
||||
grp = back.getGroup() and
|
||||
not back.getParent+() = neg
|
||||
select back, "This back reference always matches the empty string, since it refers to $@, which is contained in $@.",
|
||||
grp, "this capture group",
|
||||
neg, "a negative lookahead assertion"
|
||||
where
|
||||
grp.getParent+() = neg and
|
||||
grp = back.getGroup() and
|
||||
not back.getParent+() = neg
|
||||
select back,
|
||||
"This back reference always matches the empty string, since it refers to $@, which is contained in $@.",
|
||||
grp, "this capture group", neg, "a negative lookahead assertion"
|
||||
|
||||
@@ -15,4 +15,4 @@ import javascript
|
||||
|
||||
from RegExpCharEscape rece
|
||||
where rece.toString() = "\\b"
|
||||
select rece, "Backspace escape in regular expression."
|
||||
select rece, "Backspace escape in regular expression."
|
||||
|
||||
@@ -19,11 +19,18 @@ import javascript
|
||||
*/
|
||||
predicate constantInCharacterClass(RegExpCharacterClass recc, int i, RegExpConstant cc, string val) {
|
||||
cc = rank[i](RegExpConstant cc2, int j |
|
||||
cc2 = recc.getChild(j) and cc2.isCharacter() and cc2.getValue() = val | cc2 order by j
|
||||
)
|
||||
cc2 = recc.getChild(j) and cc2.isCharacter() and cc2.getValue() = val
|
||||
|
|
||||
cc2
|
||||
order by
|
||||
j
|
||||
)
|
||||
}
|
||||
|
||||
from RegExpCharacterClass recc, RegExpConstant first, RegExpConstant repeat, int rnk, string val
|
||||
where constantInCharacterClass(recc, 1, first, val) and
|
||||
constantInCharacterClass(recc, rnk, repeat, val) and rnk > 1
|
||||
select first, "Character '" + first + "' is repeated $@ in the same character class.", repeat, "here"
|
||||
where
|
||||
constantInCharacterClass(recc, 1, first, val) and
|
||||
constantInCharacterClass(recc, rnk, repeat, val) and
|
||||
rnk > 1
|
||||
select first, "Character '" + first + "' is repeated $@ in the same character class.", repeat,
|
||||
"here"
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import javascript
|
||||
|
||||
from RegExpCharacterClass recc
|
||||
where not exists(recc.getAChild()) and
|
||||
not recc.isInverted()
|
||||
select recc, "Empty character class."
|
||||
where
|
||||
not exists(recc.getAChild()) and
|
||||
not recc.isInverted()
|
||||
select recc, "Empty character class."
|
||||
|
||||
@@ -17,7 +17,7 @@ import javascript
|
||||
* `s` and nothing else.
|
||||
*/
|
||||
predicate matchesString(Expr e, string s) {
|
||||
exists (RegExpLiteral rl |
|
||||
exists(RegExpLiteral rl |
|
||||
rl = e and
|
||||
not rl.isIgnoreCase() and
|
||||
regExpMatchesString(rl.getRoot(), s)
|
||||
@@ -35,34 +35,41 @@ predicate regExpMatchesString(RegExpTerm t, string s) {
|
||||
s = t.(RegExpConstant).getValue()
|
||||
or
|
||||
// assertions match the empty string
|
||||
(t instanceof RegExpCaret or
|
||||
t instanceof RegExpDollar or
|
||||
t instanceof RegExpWordBoundary or
|
||||
t instanceof RegExpNonWordBoundary or
|
||||
t instanceof RegExpLookahead or
|
||||
t instanceof RegExpLookbehind) and
|
||||
(
|
||||
t instanceof RegExpCaret or
|
||||
t instanceof RegExpDollar or
|
||||
t instanceof RegExpWordBoundary or
|
||||
t instanceof RegExpNonWordBoundary or
|
||||
t instanceof RegExpLookahead or
|
||||
t instanceof RegExpLookbehind
|
||||
) and
|
||||
s = ""
|
||||
or
|
||||
// groups match their content
|
||||
regExpMatchesString(t.(RegExpGroup).getAChild(), s)
|
||||
or
|
||||
// single-character classes match that character
|
||||
exists (RegExpCharacterClass recc | recc = t and not recc.isInverted() |
|
||||
exists(RegExpCharacterClass recc | recc = t and not recc.isInverted() |
|
||||
recc.getNumChild() = 1 and
|
||||
regExpMatchesString(recc.getChild(0), s)
|
||||
)
|
||||
or
|
||||
// sequences match the concatenation of their elements
|
||||
exists (RegExpSequence seq | seq = t |
|
||||
s = concat(int i, RegExpTerm child | child = seq.getChild(i) |
|
||||
any(string subs | regExpMatchesString(child, subs)) order by i
|
||||
)
|
||||
exists(RegExpSequence seq | seq = t |
|
||||
s = concat(int i, RegExpTerm child |
|
||||
child = seq.getChild(i)
|
||||
|
|
||||
any(string subs | regExpMatchesString(child, subs))
|
||||
order by
|
||||
i
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
from MethodCallExpr repl, string s, string friendly
|
||||
where repl.getMethodName() = "replace" and
|
||||
matchesString(repl.getArgument(0), s) and
|
||||
repl.getArgument(1).getStringValue() = s and
|
||||
(if s = "" then friendly = "the empty string" else friendly = "'" + s + "'")
|
||||
where
|
||||
repl.getMethodName() = "replace" and
|
||||
matchesString(repl.getArgument(0), s) and
|
||||
repl.getArgument(1).getStringValue() = s and
|
||||
(if s = "" then friendly = "the empty string" else friendly = "'" + s + "'")
|
||||
select repl.getArgument(0), "This replaces " + friendly + " with itself."
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
import javascript
|
||||
|
||||
from RegExpParseError repe
|
||||
select repe, "Malformed regular expression: " + repe + "."
|
||||
select repe, "Malformed regular expression: " + repe + "."
|
||||
|
||||
@@ -15,10 +15,11 @@
|
||||
import javascript
|
||||
|
||||
from RegExpBackRef rebr, string ref
|
||||
where not exists(rebr.getGroup()) and
|
||||
(
|
||||
ref = rebr.getNumber().toString()
|
||||
or
|
||||
ref = "named '" + rebr.getName() + "'"
|
||||
)
|
||||
where
|
||||
not exists(rebr.getGroup()) and
|
||||
(
|
||||
ref = rebr.getNumber().toString()
|
||||
or
|
||||
ref = "named '" + rebr.getName() + "'"
|
||||
)
|
||||
select rebr, "There is no capture group " + ref + " in this regular expression."
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
import javascript
|
||||
|
||||
from RegExpCaret caret, RegExpTerm t
|
||||
where t = caret.getPredecessor+() and
|
||||
not t.isNullable() and
|
||||
// conservative handling of multi-line regular expressions
|
||||
not caret.getLiteral().isMultiline()
|
||||
select caret, "This assertion can never match."
|
||||
where
|
||||
t = caret.getPredecessor+() and
|
||||
not t.isNullable() and
|
||||
// conservative handling of multi-line regular expressions
|
||||
not caret.getLiteral().isMultiline()
|
||||
select caret, "This assertion can never match."
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
import javascript
|
||||
|
||||
from RegExpDollar dollar, RegExpTerm t
|
||||
where t = dollar.getSuccessor+() and
|
||||
not t.isNullable() and
|
||||
// conservative handling of multi-line regular expressions
|
||||
not dollar.getLiteral().isMultiline()
|
||||
select dollar, "This assertion can never match."
|
||||
where
|
||||
t = dollar.getSuccessor+() and
|
||||
not t.isNullable() and
|
||||
// conservative handling of multi-line regular expressions
|
||||
not dollar.getLiteral().isMultiline()
|
||||
select dollar, "This assertion can never match."
|
||||
|
||||
@@ -17,11 +17,9 @@ from DifferentKindsComparison cmp, DataFlow::Node lSource, DataFlow::Node rSourc
|
||||
where
|
||||
lSource = cmp.getLSource() and
|
||||
rSource = cmp.getRSource() and
|
||||
not (
|
||||
// Standard names for the double submit cookie pattern (CSRF protection)
|
||||
exists(DataFlow::PropRead s | s = lSource or s = rSource |
|
||||
s.getPropertyName().regexpMatch("(?i).*(csrf|state|token).*")
|
||||
)
|
||||
// Standard names for the double submit cookie pattern (CSRF protection)
|
||||
not exists(DataFlow::PropRead s | s = lSource or s = rSource |
|
||||
s.getPropertyName().regexpMatch("(?i).*(csrf|state|token).*")
|
||||
)
|
||||
select cmp,
|
||||
"This comparison of $@ and $@ is a potential security risk since it is controlled by the user.",
|
||||
|
||||
@@ -17,7 +17,7 @@ import semmle.javascript.RestrictedLocations
|
||||
from ReturnStmt r, AssignExpr assgn, Variable v
|
||||
where
|
||||
assgn = r.getExpr().stripParens() and
|
||||
v = (r.getContainer().(Function)).getScope().getAVariable() and
|
||||
v = r.getContainer().(Function).getScope().getAVariable() and
|
||||
not v.isCaptured() and
|
||||
assgn.getLhs() = v.getAnAccess()
|
||||
select r.(FirstLineOf),
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
* Provides classes for working with JavaScript programs, as well as JSON, YAML and HTML.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import javascript
|
||||
|
||||
204
javascript/ql/src/external/CodeDuplication.qll
vendored
204
javascript/ql/src/external/CodeDuplication.qll
vendored
@@ -3,10 +3,7 @@
|
||||
import semmle.javascript.Files
|
||||
|
||||
/** Gets the relative path of `file`, with backslashes replaced by forward slashes. */
|
||||
private
|
||||
string relativePath(File file) {
|
||||
result = file.getRelativePath().replaceAll("\\", "/")
|
||||
}
|
||||
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
|
||||
|
||||
/**
|
||||
* Holds if the `index`-th token of block `copy` is in file `file`, spanning
|
||||
@@ -23,9 +20,7 @@ private predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy
|
||||
/** A token block used for detection of duplicate and similar code. */
|
||||
class Copy extends @duplication_or_similarity {
|
||||
/** Gets the index of the last token in this block. */
|
||||
private int lastToken() {
|
||||
result = max(int i | tokens(this, i, _, _, _, _) | i)
|
||||
}
|
||||
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
|
||||
|
||||
/** Gets the index of the token in this block starting at the location `loc`, if any. */
|
||||
int tokenStartingAt(Location loc) {
|
||||
@@ -38,39 +33,26 @@ class Copy extends @duplication_or_similarity {
|
||||
}
|
||||
|
||||
/** Gets the line on which the first token in this block starts. */
|
||||
int sourceStartLine() {
|
||||
tokens(this, 0, result, _, _, _)
|
||||
}
|
||||
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
|
||||
|
||||
/** Gets the column on which the first token in this block starts. */
|
||||
int sourceStartColumn() {
|
||||
tokens(this, 0, _, result, _, _)
|
||||
}
|
||||
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
|
||||
|
||||
/** Gets the line on which the last token in this block ends. */
|
||||
int sourceEndLine() {
|
||||
tokens(this, this.lastToken(), _, _, result, _)
|
||||
}
|
||||
int sourceEndLine() { tokens(this, this.lastToken(), _, _, result, _) }
|
||||
|
||||
/** Gets the column on which the last token in this block ends. */
|
||||
int sourceEndColumn() {
|
||||
tokens(this, this.lastToken(), _, _, _, result)
|
||||
}
|
||||
int sourceEndColumn() { tokens(this, this.lastToken(), _, _, _, result) }
|
||||
|
||||
/** Gets the number of lines containing at least (part of) one token in this block. */
|
||||
int sourceLines() {
|
||||
result = this.sourceEndLine() + 1 - this.sourceStartLine()
|
||||
}
|
||||
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
|
||||
|
||||
/** Gets an opaque identifier for the equivalence class of this block. */
|
||||
int getEquivalenceClass() {
|
||||
duplicateCode(this, _, result) or similarCode(this, _, result)
|
||||
}
|
||||
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
|
||||
|
||||
/** Gets the source file in which this block appears. */
|
||||
File sourceFile() {
|
||||
exists(string name |
|
||||
duplicateCode(this, name, _) or similarCode(this, name, _) |
|
||||
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
|
||||
name.replaceAll("\\", "/") = relativePath(result)
|
||||
)
|
||||
}
|
||||
@@ -82,13 +64,14 @@ class Copy extends @duplication_or_similarity {
|
||||
* For more information, see
|
||||
* [LGTM locations](https://lgtm.com/help/ql/locations).
|
||||
*/
|
||||
predicate hasLocationInfo(string filepath, int startline, int startcolumn,
|
||||
int endline, int endcolumn) {
|
||||
sourceFile().getAbsolutePath() = filepath and
|
||||
startline = sourceStartLine() and
|
||||
startcolumn = sourceStartColumn() and
|
||||
endline = sourceEndLine() and
|
||||
endcolumn = sourceEndColumn()
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
sourceFile().getAbsolutePath() = filepath and
|
||||
startline = sourceStartLine() and
|
||||
startcolumn = sourceStartColumn() and
|
||||
endline = sourceEndLine() and
|
||||
endcolumn = sourceEndColumn()
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
@@ -99,7 +82,7 @@ class Copy extends @duplication_or_similarity {
|
||||
* covered by this block, but they are not the same block.
|
||||
*/
|
||||
Copy extendingBlock() {
|
||||
exists (File file, int sl, int sc, int ec, int el |
|
||||
exists(File file, int sl, int sc, int ec, int el |
|
||||
tokenLocation(file, sl, sc, ec, el, this, _) and
|
||||
tokenLocation(file, sl, sc, ec, el, result, 0)
|
||||
) and
|
||||
@@ -113,16 +96,19 @@ class Copy extends @duplication_or_similarity {
|
||||
* have the same equivalence class, with `start` being the equivalence class of `start1` and
|
||||
* `start2`, and `end` the equivalence class of `end1` and `end2`.
|
||||
*/
|
||||
predicate similar_extension(SimilarBlock start1, SimilarBlock start2,
|
||||
SimilarBlock end1, SimilarBlock end2, int start, int end) {
|
||||
start1.getEquivalenceClass() = start and
|
||||
start2.getEquivalenceClass() = start and
|
||||
end1.getEquivalenceClass() = end and
|
||||
end2.getEquivalenceClass() = end and
|
||||
start1 != start2 and
|
||||
(end1 = start1 and end2 = start2 or
|
||||
similar_extension(start1.extendingBlock(), start2.extendingBlock(), end1, end2, _, end)
|
||||
)
|
||||
predicate similar_extension(
|
||||
SimilarBlock start1, SimilarBlock start2, SimilarBlock end1, SimilarBlock end2, int start, int end
|
||||
) {
|
||||
start1.getEquivalenceClass() = start and
|
||||
start2.getEquivalenceClass() = start and
|
||||
end1.getEquivalenceClass() = end and
|
||||
end2.getEquivalenceClass() = end and
|
||||
start1 != start2 and
|
||||
(
|
||||
end1 = start1 and end2 = start2
|
||||
or
|
||||
similar_extension(start1.extendingBlock(), start2.extendingBlock(), end1, end2, _, end)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,23 +117,25 @@ predicate similar_extension(SimilarBlock start1, SimilarBlock start2,
|
||||
* have the same equivalence class, with `start` being the equivalence class of `start1` and
|
||||
* `start2`, and `end` the equivalence class of `end1` and `end2`.
|
||||
*/
|
||||
predicate duplicate_extension(DuplicateBlock start1, DuplicateBlock start2,
|
||||
DuplicateBlock end1, DuplicateBlock end2, int start, int end) {
|
||||
start1.getEquivalenceClass() = start and
|
||||
start2.getEquivalenceClass() = start and
|
||||
end1.getEquivalenceClass() = end and
|
||||
end2.getEquivalenceClass() = end and
|
||||
start1 != start2 and
|
||||
(end1 = start1 and end2 = start2 or
|
||||
duplicate_extension(start1.extendingBlock(), start2.extendingBlock(), end1, end2, _, end)
|
||||
)
|
||||
predicate duplicate_extension(
|
||||
DuplicateBlock start1, DuplicateBlock start2, DuplicateBlock end1, DuplicateBlock end2, int start,
|
||||
int end
|
||||
) {
|
||||
start1.getEquivalenceClass() = start and
|
||||
start2.getEquivalenceClass() = start and
|
||||
end1.getEquivalenceClass() = end and
|
||||
end2.getEquivalenceClass() = end and
|
||||
start1 != start2 and
|
||||
(
|
||||
end1 = start1 and end2 = start2
|
||||
or
|
||||
duplicate_extension(start1.extendingBlock(), start2.extendingBlock(), end1, end2, _, end)
|
||||
)
|
||||
}
|
||||
|
||||
/** A block of duplicated code. */
|
||||
class DuplicateBlock extends Copy, @duplication {
|
||||
override string toString() {
|
||||
result = "Duplicate code: " + sourceLines() + " duplicated lines."
|
||||
}
|
||||
override string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
|
||||
}
|
||||
|
||||
/** A block of similar code. */
|
||||
@@ -168,7 +156,7 @@ private predicate stmtInContainer(Stmt s, StmtContainer sc) {
|
||||
* respectively, where `sc1` and `sc2` are not the same.
|
||||
*/
|
||||
predicate duplicateStatement(StmtContainer sc1, StmtContainer sc2, Stmt stmt1, Stmt stmt2) {
|
||||
exists(int equivstart, int equivend, int first, int last |
|
||||
exists(int equivstart, int equivend, int first, int last |
|
||||
stmtInContainer(stmt1, sc1) and
|
||||
stmtInContainer(stmt2, sc2) and
|
||||
duplicateCoversStatement(equivstart, equivend, first, last, stmt1) and
|
||||
@@ -185,8 +173,9 @@ predicate duplicateStatement(StmtContainer sc1, StmtContainer sc2, Stmt stmt1, S
|
||||
* and `equivstart` and `equivend` are the equivalence classes of the first and the last
|
||||
* block, respectively.
|
||||
*/
|
||||
private
|
||||
predicate duplicateCoversStatement(int equivstart, int equivend, int first, int last, Stmt stmt) {
|
||||
private predicate duplicateCoversStatement(
|
||||
int equivstart, int equivend, int first, int last, Stmt stmt
|
||||
) {
|
||||
exists(DuplicateBlock b1, DuplicateBlock b2, Location loc |
|
||||
stmt.getLocation() = loc and
|
||||
first = b1.tokenStartingAt(loc) and
|
||||
@@ -201,8 +190,7 @@ predicate duplicateCoversStatement(int equivstart, int equivend, int first, int
|
||||
* Holds if `sc1` is a function or toplevel with `total` lines, and `sc2` is a function or
|
||||
* toplevel that has `duplicate` lines in common with `sc1`.
|
||||
*/
|
||||
private
|
||||
predicate duplicateStatements(StmtContainer sc1, StmtContainer sc2, int duplicate, int total) {
|
||||
private predicate duplicateStatements(StmtContainer sc1, StmtContainer sc2, int duplicate, int total) {
|
||||
duplicate = strictcount(Stmt stmt | duplicateStatement(sc1, sc2, stmt, _)) and
|
||||
total = strictcount(Stmt stmt | stmtInContainer(stmt, sc1))
|
||||
}
|
||||
@@ -212,11 +200,10 @@ predicate duplicateStatements(StmtContainer sc1, StmtContainer sc2, int duplicat
|
||||
* of lines they have in common, which is greater than 90%.
|
||||
*/
|
||||
predicate duplicateContainers(StmtContainer sc, StmtContainer other, float percent) {
|
||||
exists(int total, int duplicate |
|
||||
duplicateStatements(sc, other, duplicate, total) |
|
||||
percent = 100.0*duplicate/total and
|
||||
exists(int total, int duplicate | duplicateStatements(sc, other, duplicate, total) |
|
||||
percent = 100.0 * duplicate / total and
|
||||
percent > 90.0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,7 +211,7 @@ predicate duplicateContainers(StmtContainer sc, StmtContainer other, float perce
|
||||
* respectively, where `sc1` and `sc2` are not the same.
|
||||
*/
|
||||
private predicate similarStatement(StmtContainer sc1, StmtContainer sc2, Stmt stmt1, Stmt stmt2) {
|
||||
exists(int start, int end, int first, int last |
|
||||
exists(int start, int end, int first, int last |
|
||||
stmtInContainer(stmt1, sc1) and
|
||||
stmtInContainer(stmt2, sc2) and
|
||||
similarCoversStatement(start, end, first, last, stmt1) and
|
||||
@@ -241,8 +228,9 @@ private predicate similarStatement(StmtContainer sc1, StmtContainer sc2, Stmt st
|
||||
* and `equivstart` and `equivend` are the equivalence classes of the first and the last
|
||||
* block, respectively.
|
||||
*/
|
||||
private predicate similarCoversStatement(int equivstart, int equivend, int first, int last,
|
||||
Stmt stmt) {
|
||||
private predicate similarCoversStatement(
|
||||
int equivstart, int equivend, int first, int last, Stmt stmt
|
||||
) {
|
||||
exists(SimilarBlock b1, SimilarBlock b2, Location loc |
|
||||
stmt.getLocation() = loc and
|
||||
first = b1.tokenStartingAt(loc) and
|
||||
@@ -267,41 +255,37 @@ private predicate similarStatements(StmtContainer sc1, StmtContainer sc2, int si
|
||||
* of similar lines between the two, which is greater than 90%.
|
||||
*/
|
||||
predicate similarContainers(StmtContainer sc, StmtContainer other, float percent) {
|
||||
exists(int total, int similar |
|
||||
similarStatements(sc, other, similar, total) |
|
||||
percent = 100.0*similar/total and
|
||||
exists(int total, int similar | similarStatements(sc, other, similar, total) |
|
||||
percent = 100.0 * similar / total and
|
||||
percent > 90.0
|
||||
)
|
||||
}
|
||||
|
||||
predicate similarLines(File f, int line) {
|
||||
exists(SimilarBlock b |
|
||||
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
|
||||
)
|
||||
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
|
||||
}
|
||||
|
||||
private
|
||||
predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f)
|
||||
{
|
||||
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines = strictsum(SimilarBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and (toSum = b.sourceLines()) | toSum)
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
private pragma[noopt]
|
||||
predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
pragma[noopt]
|
||||
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox = strictsum(int num |
|
||||
exists(int equivClass |
|
||||
similarLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
exists(int n, int product |
|
||||
product = coveredApprox * 100 and n = product / numLines |
|
||||
n > 75
|
||||
)
|
||||
coveredApprox = strictsum(int num |
|
||||
exists(int equivClass |
|
||||
similarLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
|
||||
) and
|
||||
exists(int notCovered |
|
||||
notCovered = count(int j | j in [1 .. numLines] and not similarLines(f, j)) and
|
||||
@@ -311,30 +295,32 @@ predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
}
|
||||
|
||||
predicate duplicateLines(File f, int line) {
|
||||
exists(DuplicateBlock b |
|
||||
exists(DuplicateBlock b |
|
||||
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
|
||||
)
|
||||
}
|
||||
|
||||
private
|
||||
predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f)
|
||||
{
|
||||
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines = strictsum(DuplicateBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and (toSum = b.sourceLines()) | toSum)
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
private pragma[noopt]
|
||||
predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
pragma[noopt]
|
||||
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox = strictsum(int num |
|
||||
exists(int equivClass |
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
exists (int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
|
||||
coveredApprox = strictsum(int num |
|
||||
exists(int equivClass |
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
|
||||
) and
|
||||
exists(int notCovered |
|
||||
notCovered = count(int j | j in [1 .. numLines] and not duplicateLines(f, j)) and
|
||||
@@ -360,4 +346,4 @@ predicate duplicateFiles(File f, File other, int percent) {
|
||||
covered * 100 / total = percent and
|
||||
percent > 70
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
15
javascript/ql/src/external/DefectFilter.qll
vendored
15
javascript/ql/src/external/DefectFilter.qll
vendored
@@ -10,9 +10,10 @@ import semmle.javascript.Files
|
||||
*
|
||||
* For more information, see [LGTM locations](https://lgtm.com/help/ql/locations).
|
||||
*/
|
||||
external predicate defectResults(int id, string queryPath,
|
||||
string file, int startline, int startcol, int endline, int endcol,
|
||||
string message);
|
||||
external predicate defectResults(
|
||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||
string message
|
||||
);
|
||||
|
||||
/**
|
||||
* A defect query result stored in a dashboard database.
|
||||
@@ -25,7 +26,9 @@ class DefectResult extends int {
|
||||
|
||||
/** Gets the file in which this query result was reported. */
|
||||
File getFile() {
|
||||
exists(string path | defectResults(this, _, path, _, _, _, _, _) | result.getAbsolutePath() = path)
|
||||
exists(string path | defectResults(this, _, path, _, _, _, _, _) |
|
||||
result.getAbsolutePath() = path
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the line on which the location of this query result starts. */
|
||||
@@ -45,7 +48,7 @@ class DefectResult extends int {
|
||||
|
||||
/** Gets the URL corresponding to the location of this query result. */
|
||||
string getURL() {
|
||||
result = "file://" + getFile().getAbsolutePath() + ":" +
|
||||
getStartLine() + ":" + getStartColumn() + ":" + getEndLine() + ":" + getEndColumn()
|
||||
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
|
||||
+ ":" + getEndLine() + ":" + getEndColumn()
|
||||
}
|
||||
}
|
||||
|
||||
13
javascript/ql/src/external/DuplicateFunction.ql
vendored
13
javascript/ql/src/external/DuplicateFunction.ql
vendored
@@ -19,8 +19,11 @@ import CodeDuplication
|
||||
import semmle.javascript.RestrictedLocations
|
||||
|
||||
from Function f, Function g, float percent
|
||||
where duplicateContainers(f, g, percent) and
|
||||
f.getNumBodyStmt() > 5 and
|
||||
not duplicateContainers(f.getEnclosingStmt().getContainer(), g.getEnclosingStmt().getContainer(), _)
|
||||
select (FirstLineOf)f, percent.floor() + "% of statements in " + f.describe() +
|
||||
" are duplicated in $@.", (FirstLineOf)g, g.describe()
|
||||
where
|
||||
duplicateContainers(f, g, percent) and
|
||||
f.getNumBodyStmt() > 5 and
|
||||
not duplicateContainers(f.getEnclosingStmt().getContainer(), g.getEnclosingStmt().getContainer(),
|
||||
_)
|
||||
select f.(FirstLineOf),
|
||||
percent.floor() + "% of statements in " + f.describe() + " are duplicated in $@.",
|
||||
g.(FirstLineOf), g.describe()
|
||||
|
||||
@@ -19,6 +19,8 @@ import CodeDuplication
|
||||
import semmle.javascript.RestrictedLocations
|
||||
|
||||
from TopLevel one, TopLevel another, float percent
|
||||
where duplicateContainers(one, another, percent) and
|
||||
one.getNumLines() > 5
|
||||
select (FirstLineOf)one, percent + "% of statements in this script are duplicated in $@.", (FirstLineOf)another, "another script"
|
||||
where
|
||||
duplicateContainers(one, another, percent) and
|
||||
one.getNumLines() > 5
|
||||
select one.(FirstLineOf), percent + "% of statements in this script are duplicated in $@.",
|
||||
another.(FirstLineOf), "another script"
|
||||
|
||||
65
javascript/ql/src/external/ExternalArtifact.qll
vendored
65
javascript/ql/src/external/ExternalArtifact.qll
vendored
@@ -9,55 +9,38 @@ import semmle.javascript.Locations
|
||||
*/
|
||||
class ExternalData extends @externalDataElement {
|
||||
/** Gets the path of the file this data was loaded from. */
|
||||
string getDataPath() {
|
||||
externalData(this, result, _, _)
|
||||
}
|
||||
string getDataPath() { externalData(this, result, _, _) }
|
||||
|
||||
/**
|
||||
* Gets the path of the file this data was loaded from, with its
|
||||
* extension replaced by `.ql`.
|
||||
*/
|
||||
string getQueryPath() {
|
||||
result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql")
|
||||
}
|
||||
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
|
||||
|
||||
/** Gets the number of fields in this data item. */
|
||||
int getNumFields() {
|
||||
result = 1 + max(int i | externalData(this, _, i, _) | i)
|
||||
}
|
||||
int getNumFields() { result = 1 + max(int i | externalData(this, _, i, _) | i) }
|
||||
|
||||
/** Gets the value of the `i`th field of this data item. */
|
||||
string getField(int i) {
|
||||
externalData(this, _, i, result)
|
||||
}
|
||||
string getField(int i) { externalData(this, _, i, result) }
|
||||
|
||||
/** Gets the integer value of the `i`th field of this data item. */
|
||||
int getFieldAsInt(int i) {
|
||||
result = getField(i).toInt()
|
||||
}
|
||||
int getFieldAsInt(int i) { result = getField(i).toInt() }
|
||||
|
||||
/** Gets the floating-point value of the `i`th field of this data item. */
|
||||
float getFieldAsFloat(int i) {
|
||||
result = getField(i).toFloat()
|
||||
}
|
||||
float getFieldAsFloat(int i) { result = getField(i).toFloat() }
|
||||
|
||||
/** Gets the value of the `i`th field of this data item, interpreted as a date. */
|
||||
date getFieldAsDate(int i) {
|
||||
result = getField(i).toDate()
|
||||
}
|
||||
date getFieldAsDate(int i) { result = getField(i).toDate() }
|
||||
|
||||
/** Gets a textual representation of this data item. */
|
||||
string toString() {
|
||||
result = getQueryPath() + ": " + buildTupleString(0)
|
||||
}
|
||||
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
|
||||
|
||||
/** Gets a textual representation of this data item, starting with the `n`th field. */
|
||||
private string buildTupleString(int n) {
|
||||
(n = getNumFields() - 1 and result = getField(n))
|
||||
n = getNumFields() - 1 and result = getField(n)
|
||||
or
|
||||
(n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n+1))
|
||||
n < getNumFields() - 1 and result = getField(n) + "," + buildTupleString(n + 1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,43 +48,29 @@ class ExternalData extends @externalDataElement {
|
||||
*/
|
||||
class ExternalError extends ExternalData {
|
||||
/** Gets the name of the tool that reported the error. */
|
||||
string getReporter() {
|
||||
result = getField(0)
|
||||
}
|
||||
string getReporter() { result = getField(0) }
|
||||
|
||||
/** Gets the absolute path of the file in which the error occurs. */
|
||||
string getPath() {
|
||||
result = getField(1)
|
||||
}
|
||||
string getPath() { result = getField(1) }
|
||||
|
||||
/** Gets the reported line of the error. */
|
||||
int getLine() {
|
||||
result = getFieldAsInt(2)
|
||||
}
|
||||
int getLine() { result = getFieldAsInt(2) }
|
||||
|
||||
/** Gets the reported column of the error. */
|
||||
int getColumn() {
|
||||
result = getFieldAsInt(3)
|
||||
}
|
||||
int getColumn() { result = getFieldAsInt(3) }
|
||||
|
||||
/**
|
||||
* Gets the error type.
|
||||
*
|
||||
* This is tool-specific, but usually either "warning" or "error".
|
||||
*/
|
||||
string getType() {
|
||||
result = getField(4)
|
||||
}
|
||||
string getType() { result = getField(4) }
|
||||
|
||||
/** Gets the error message. */
|
||||
string getMessage() {
|
||||
result = getField(5)
|
||||
}
|
||||
string getMessage() { result = getField(5) }
|
||||
|
||||
/** Gets the file associated with this error. */
|
||||
File getFile() {
|
||||
result.getAbsolutePath() = this.getPath()
|
||||
}
|
||||
File getFile() { result.getAbsolutePath() = this.getPath() }
|
||||
|
||||
/** Gets the URL associated with this error. */
|
||||
string getURL() {
|
||||
|
||||
18
javascript/ql/src/external/MetricFilter.qll
vendored
18
javascript/ql/src/external/MetricFilter.qll
vendored
@@ -10,9 +10,10 @@ import javascript
|
||||
*
|
||||
* For more information, see [LGTM locations](https://lgtm.com/help/ql/locations).
|
||||
*/
|
||||
external predicate metricResults(int id, string queryPath,
|
||||
string file, int startline, int startcol, int endline, int endcol,
|
||||
float value);
|
||||
external predicate metricResults(
|
||||
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
|
||||
float value
|
||||
);
|
||||
|
||||
/**
|
||||
* A metric query result stored in a dashboard database.
|
||||
@@ -25,7 +26,9 @@ class MetricResult extends int {
|
||||
|
||||
/** Gets the file in which this query result was reported. */
|
||||
File getFile() {
|
||||
exists(string path | metricResults(this, _, path, _, _, _, _, _) | result.getAbsolutePath() = path)
|
||||
exists(string path | metricResults(this, _, path, _, _, _, _, _) |
|
||||
result.getAbsolutePath() = path
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the line on which the location of this query result starts. */
|
||||
@@ -63,8 +66,7 @@ class MetricResult extends int {
|
||||
|
||||
/** Gets the URL corresponding to the location of this query result. */
|
||||
string getURL() {
|
||||
result = "file://" + getFile().getAbsolutePath() + ":" +
|
||||
getStartLine() + ":" + getStartColumn() + ":" + getEndLine() + ":" + getEndColumn()
|
||||
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
|
||||
+ ":" + getEndLine() + ":" + getEndColumn()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
15
javascript/ql/src/external/SimilarFunction.ql
vendored
15
javascript/ql/src/external/SimilarFunction.ql
vendored
@@ -19,9 +19,12 @@ import CodeDuplication
|
||||
import semmle.javascript.RestrictedLocations
|
||||
|
||||
from Function f, Function g, float percent
|
||||
where similarContainers(f, g, percent) and
|
||||
f.getNumBodyStmt() > 5 and
|
||||
not duplicateContainers(f, g, _) and
|
||||
not duplicateContainers(f.getEnclosingStmt().getContainer(), g.getEnclosingStmt().getContainer(), _)
|
||||
select (FirstLineOf)f, percent.floor() + "% of statements in " + f.describe() +
|
||||
" are similar to statements in $@.", (FirstLineOf)g, g.describe()
|
||||
where
|
||||
similarContainers(f, g, percent) and
|
||||
f.getNumBodyStmt() > 5 and
|
||||
not duplicateContainers(f, g, _) and
|
||||
not duplicateContainers(f.getEnclosingStmt().getContainer(), g.getEnclosingStmt().getContainer(),
|
||||
_)
|
||||
select f.(FirstLineOf),
|
||||
percent.floor() + "% of statements in " + f.describe() + " are similar to statements in $@.",
|
||||
g.(FirstLineOf), g.describe()
|
||||
|
||||
13
javascript/ql/src/external/SimilarToplevel.ql
vendored
13
javascript/ql/src/external/SimilarToplevel.ql
vendored
@@ -19,9 +19,10 @@ import CodeDuplication
|
||||
import semmle.javascript.RestrictedLocations
|
||||
|
||||
from TopLevel one, TopLevel another, float percent
|
||||
where similarContainers(one, another, percent) and
|
||||
one.getNumChildStmt() > 5 and
|
||||
not duplicateContainers(one, another, _)
|
||||
select (FirstLineOf)one, percent.floor() + "% of statements in this script are similar to statements in $@.",
|
||||
(FirstLineOf)another,
|
||||
"another script"
|
||||
where
|
||||
similarContainers(one, another, percent) and
|
||||
one.getNumChildStmt() > 5 and
|
||||
not duplicateContainers(one, another, _)
|
||||
select one.(FirstLineOf),
|
||||
percent.floor() + "% of statements in this script are similar to statements in $@.",
|
||||
another.(FirstLineOf), "another script"
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
import javascript
|
||||
|
||||
from SsaVariable d
|
||||
where not exists (d.getAUse()) and
|
||||
not d = any(SsaPseudoDefinition phi).getAnInput() and
|
||||
d.getSourceVariable() instanceof PurelyLocalVariable
|
||||
where
|
||||
not exists(d.getAUse()) and
|
||||
not d = any(SsaPseudoDefinition phi).getAnInput() and
|
||||
d.getSourceVariable() instanceof PurelyLocalVariable
|
||||
select d, "Dead SSA definition " + d + "."
|
||||
|
||||
@@ -15,18 +15,22 @@ import javascript
|
||||
* which is a use of the same variable.
|
||||
*/
|
||||
predicate dominates(SsaDefinition def, VarUse use) {
|
||||
exists (SsaSourceVariable v,
|
||||
ReachableBasicBlock defbb, int defidx,
|
||||
ReachableBasicBlock usebb, int useidx |
|
||||
def.definesAt(defbb, defidx, v) and usebb.useAt(useidx, v, use) |
|
||||
defbb = usebb and defidx <= useidx or
|
||||
exists(
|
||||
SsaSourceVariable v, ReachableBasicBlock defbb, int defidx, ReachableBasicBlock usebb,
|
||||
int useidx
|
||||
|
|
||||
def.definesAt(defbb, defidx, v) and usebb.useAt(useidx, v, use)
|
||||
|
|
||||
defbb = usebb and defidx <= useidx
|
||||
or
|
||||
defbb.strictlyDominates(usebb)
|
||||
)
|
||||
}
|
||||
|
||||
from VarUse u, SsaDefinition d
|
||||
where u.getVariable() instanceof SsaSourceVariable and
|
||||
exists (ReachableBasicBlock bb | u = bb.getANode()) and
|
||||
u = d.getVariable().getAUse() and
|
||||
not dominates(d, u)
|
||||
select u, "Variable use is not dominated by its definition $@.", d, d.toString()
|
||||
where
|
||||
u.getVariable() instanceof SsaSourceVariable and
|
||||
exists(ReachableBasicBlock bb | u = bb.getANode()) and
|
||||
u = d.getVariable().getAUse() and
|
||||
not dominates(d, u)
|
||||
select u, "Variable use is not dominated by its definition $@.", d, d.toString()
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
import javascript
|
||||
|
||||
from VarUse u, int n, SsaVariable v
|
||||
where u.getVariable() instanceof SsaSourceVariable and
|
||||
exists (ReachableBasicBlock bb | u = bb.getANode()) and
|
||||
n = count(u.getSsaVariable()) and
|
||||
n > 1 and
|
||||
v = u.getSsaVariable()
|
||||
select u, "Variable use has " + n + " corresponding SSA variables: $@.", v, v.toString()
|
||||
where
|
||||
u.getVariable() instanceof SsaSourceVariable and
|
||||
exists(ReachableBasicBlock bb | u = bb.getANode()) and
|
||||
n = count(u.getSsaVariable()) and
|
||||
n > 1 and
|
||||
v = u.getSsaVariable()
|
||||
select u, "Variable use has " + n + " corresponding SSA variables: $@.", v, v.toString()
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
import javascript
|
||||
|
||||
from SsaRefinementNode ref, int n, SsaDefinition input
|
||||
where n = count(ref.getAnInput()) and
|
||||
n > 1 and
|
||||
input = ref.getAnInput()
|
||||
where
|
||||
n = count(ref.getAnInput()) and
|
||||
n > 1 and
|
||||
input = ref.getAnInput()
|
||||
select ref, "Refinement node has " + n + " inputs: $@.", input, input.toString()
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
import javascript
|
||||
|
||||
from VarUse u
|
||||
where u.getVariable() instanceof SsaSourceVariable and
|
||||
exists (ReachableBasicBlock bb | u = bb.getANode()) and
|
||||
not exists(u.getSsaVariable())
|
||||
select u, "Variable use has no corresponding SSA variable."
|
||||
where
|
||||
u.getVariable() instanceof SsaSourceVariable and
|
||||
exists(ReachableBasicBlock bb | u = bb.getANode()) and
|
||||
not exists(u.getSsaVariable())
|
||||
select u, "Variable use has no corresponding SSA variable."
|
||||
|
||||
@@ -16,10 +16,10 @@ import javascript
|
||||
*/
|
||||
predicate exprWithoutEnclosingStmt(Expr e) {
|
||||
// Function names, parameters, default values and bodies do not have an enclosing statement.
|
||||
exists (Function f | e = f.getAChild()) or
|
||||
exists (Parameter p | e = p.getDefault()) or
|
||||
exists(Function f | e = f.getAChild()) or
|
||||
exists(Parameter p | e = p.getDefault()) or
|
||||
// Class members do not have enclosing statements.
|
||||
exists (MemberDefinition md | e = md.getAChild()) or
|
||||
exists(MemberDefinition md | e = md.getAChild()) or
|
||||
// If an expression's parent has no enclosing statement, then neither does the expression itself.
|
||||
exprWithoutEnclosingStmt(e.getParent()) or
|
||||
// Some expressions have non-expression parents that we want to skip over.
|
||||
@@ -38,14 +38,27 @@ predicate exprWithoutEnclosingStmt(Expr e) {
|
||||
* `"3 results for toString()"`.
|
||||
*/
|
||||
predicate uniqueness_error(int number, string what, string problem) {
|
||||
(what = "toString" or what = "getLocation" or
|
||||
what = "getTopLevel" or what = "getEnclosingStmt" or what = "getContainer" or what = "getEnclosingContainer" or
|
||||
what = "getEntry" or what = "getExit" or what = "getFirstControlFlowNode" or
|
||||
what = "getOuterScope" or what = "getScopeElement" or
|
||||
what = "getBaseName" or what = "getOperator" or what = "getTest") and
|
||||
(number = 0 and problem = "no results for " + what + "()"
|
||||
or
|
||||
number in [2 .. 10] and problem = number.toString() + " results for " + what + "()")
|
||||
(
|
||||
what = "toString" or
|
||||
what = "getLocation" or
|
||||
what = "getTopLevel" or
|
||||
what = "getEnclosingStmt" or
|
||||
what = "getContainer" or
|
||||
what = "getEnclosingContainer" or
|
||||
what = "getEntry" or
|
||||
what = "getExit" or
|
||||
what = "getFirstControlFlowNode" or
|
||||
what = "getOuterScope" or
|
||||
what = "getScopeElement" or
|
||||
what = "getBaseName" or
|
||||
what = "getOperator" or
|
||||
what = "getTest"
|
||||
) and
|
||||
(
|
||||
number = 0 and problem = "no results for " + what + "()"
|
||||
or
|
||||
number in [2 .. 10] and problem = number.toString() + " results for " + what + "()"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,33 +67,52 @@ predicate uniqueness_error(int number, string what, string problem) {
|
||||
* the violation, and `what` gives location information where possible.
|
||||
*/
|
||||
predicate ast_sanity(string clsname, string problem, string what) {
|
||||
exists (Locatable l | clsname = l.getAQlClass() |
|
||||
uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.getLocation() or
|
||||
uniqueness_error(strictcount(l.getLocation()), "getLocation", problem) and what = l.getLocation().toString() or
|
||||
exists(Locatable l | clsname = l.getAQlClass() |
|
||||
uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l.getLocation()
|
||||
or
|
||||
uniqueness_error(strictcount(l.getLocation()), "getLocation", problem) and
|
||||
what = l.getLocation().toString()
|
||||
or
|
||||
not exists(l.getLocation()) and problem = "no location" and what = l.toString()
|
||||
) or
|
||||
exists (ASTNode nd | clsname = nd.getAQlClass() |
|
||||
uniqueness_error(count(nd.getTopLevel()), "getTopLevel", problem) and what = "at " + nd.getLocation()
|
||||
) or
|
||||
exists (Expr e | clsname = e.getAQlClass() |
|
||||
uniqueness_error(count(e.getContainer()), "getContainer", problem) and what = "at " + e.getLocation() or
|
||||
(not exprWithoutEnclosingStmt(e) and
|
||||
uniqueness_error(count(e.getEnclosingStmt()), "getEnclosingStmt", problem) and what = "at " + e.getLocation())
|
||||
) or
|
||||
exists (Stmt s | clsname = s.getAQlClass() |
|
||||
uniqueness_error(count(s.getContainer()), "getContainer", problem) and what = "at " + s.getLocation()
|
||||
) or
|
||||
exists (StmtContainer cont | not cont instanceof TopLevel and clsname = cont.getAQlClass() |
|
||||
uniqueness_error(count(cont.getEnclosingContainer()), "getEnclosingContainer", problem) and what = "at " + cont.getLocation()
|
||||
) or
|
||||
exists (UnaryExpr ue | clsname = ue.getAQlClass() |
|
||||
uniqueness_error(count(ue.getOperator()), "getOperator", problem) and what = "at " + ue.getLocation()
|
||||
) or
|
||||
exists (UpdateExpr ue | clsname = ue.getAQlClass() |
|
||||
uniqueness_error(count(ue.getOperator()), "getOperator", problem) and what = "at " + ue.getLocation()
|
||||
) or
|
||||
exists (BinaryExpr be | clsname = be.getAQlClass() |
|
||||
uniqueness_error(count(be.getOperator()), "getOperator", problem) and what = "at " + be.getLocation()
|
||||
)
|
||||
or
|
||||
exists(ASTNode nd | clsname = nd.getAQlClass() |
|
||||
uniqueness_error(count(nd.getTopLevel()), "getTopLevel", problem) and
|
||||
what = "at " + nd.getLocation()
|
||||
)
|
||||
or
|
||||
exists(Expr e | clsname = e.getAQlClass() |
|
||||
uniqueness_error(count(e.getContainer()), "getContainer", problem) and
|
||||
what = "at " + e.getLocation()
|
||||
or
|
||||
not exprWithoutEnclosingStmt(e) and
|
||||
uniqueness_error(count(e.getEnclosingStmt()), "getEnclosingStmt", problem) and
|
||||
what = "at " + e.getLocation()
|
||||
)
|
||||
or
|
||||
exists(Stmt s | clsname = s.getAQlClass() |
|
||||
uniqueness_error(count(s.getContainer()), "getContainer", problem) and
|
||||
what = "at " + s.getLocation()
|
||||
)
|
||||
or
|
||||
exists(StmtContainer cont | not cont instanceof TopLevel and clsname = cont.getAQlClass() |
|
||||
uniqueness_error(count(cont.getEnclosingContainer()), "getEnclosingContainer", problem) and
|
||||
what = "at " + cont.getLocation()
|
||||
)
|
||||
or
|
||||
exists(UnaryExpr ue | clsname = ue.getAQlClass() |
|
||||
uniqueness_error(count(ue.getOperator()), "getOperator", problem) and
|
||||
what = "at " + ue.getLocation()
|
||||
)
|
||||
or
|
||||
exists(UpdateExpr ue | clsname = ue.getAQlClass() |
|
||||
uniqueness_error(count(ue.getOperator()), "getOperator", problem) and
|
||||
what = "at " + ue.getLocation()
|
||||
)
|
||||
or
|
||||
exists(BinaryExpr be | clsname = be.getAQlClass() |
|
||||
uniqueness_error(count(be.getOperator()), "getOperator", problem) and
|
||||
what = "at " + be.getLocation()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -89,8 +121,9 @@ predicate ast_sanity(string clsname, string problem, string what) {
|
||||
* where `problem` describes the problem and `what` gives location information where possible.
|
||||
*/
|
||||
predicate location_sanity(string clsname, string problem, string what) {
|
||||
exists (Location l | clsname = l.getAQlClass() |
|
||||
uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l or
|
||||
exists(Location l | clsname = l.getAQlClass() |
|
||||
uniqueness_error(count(l.toString()), "toString", problem) and what = "at " + l
|
||||
or
|
||||
not exists(l.toString()) and problem = "no toString" and what = "a location"
|
||||
)
|
||||
}
|
||||
@@ -98,9 +131,7 @@ predicate location_sanity(string clsname, string problem, string what) {
|
||||
/**
|
||||
* Holds if function or toplevel `sc` is expected to have an associated control flow graph.
|
||||
*/
|
||||
predicate hasCFG(StmtContainer sc) {
|
||||
not exists (Error err | err.getFile() = sc.getFile())
|
||||
}
|
||||
predicate hasCFG(StmtContainer sc) { not exists(Error err | err.getFile() = sc.getFile()) }
|
||||
|
||||
/**
|
||||
* Holds if a contract involving the CFG structure is violated, where `clsname`
|
||||
@@ -108,12 +139,15 @@ predicate hasCFG(StmtContainer sc) {
|
||||
* the violation, and `what` gives location information.
|
||||
*/
|
||||
predicate cfg_sanity(string clsname, string problem, string what) {
|
||||
exists (StmtContainer cont | clsname = cont.getAQlClass() and hasCFG(cont) |
|
||||
uniqueness_error(count(cont.getEntry()), "getEntry", problem) and what = "at " + cont.getLocation() or
|
||||
uniqueness_error(count(cont.getExit()), "getExit", problem) and what = "at " + cont.getLocation()
|
||||
exists(StmtContainer cont | clsname = cont.getAQlClass() and hasCFG(cont) |
|
||||
uniqueness_error(count(cont.getEntry()), "getEntry", problem) and
|
||||
what = "at " + cont.getLocation()
|
||||
or
|
||||
uniqueness_error(count(cont.getExit()), "getExit", problem) and
|
||||
what = "at " + cont.getLocation()
|
||||
)
|
||||
or
|
||||
exists (ASTNode nd | clsname = nd.getAQlClass() and hasCFG(nd.getTopLevel()) |
|
||||
exists(ASTNode nd | clsname = nd.getAQlClass() and hasCFG(nd.getTopLevel()) |
|
||||
uniqueness_error(count(nd.getFirstControlFlowNode()), "getFirstControlFlowNode", problem) and
|
||||
what = "at " + nd.getLocation()
|
||||
)
|
||||
@@ -125,13 +159,19 @@ predicate cfg_sanity(string clsname, string problem, string what) {
|
||||
* the violation, and `what` gives location information.
|
||||
*/
|
||||
predicate scope_sanity(string clsname, string problem, string what) {
|
||||
exists (Scope s | clsname = s.getAQlClass() |
|
||||
uniqueness_error(count(s.toString()), "toString", problem) and what = "a scope" or
|
||||
exists(Scope s | clsname = s.getAQlClass() |
|
||||
uniqueness_error(count(s.toString()), "toString", problem) and what = "a scope"
|
||||
or
|
||||
not s instanceof GlobalScope and
|
||||
(uniqueness_error(count(s.getOuterScope()), "getOuterScope", problem) and what = s.toString() or
|
||||
uniqueness_error(count(s.getScopeElement()), "getScopeElement", problem) and what = s.toString())
|
||||
) or
|
||||
exists (int n | n = count(GlobalScope g) and n != 1 |
|
||||
(
|
||||
uniqueness_error(count(s.getOuterScope()), "getOuterScope", problem) and what = s.toString()
|
||||
or
|
||||
uniqueness_error(count(s.getScopeElement()), "getScopeElement", problem) and
|
||||
what = s.toString()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(int n | n = count(GlobalScope g) and n != 1 |
|
||||
clsname = "GlobalScope" and what = "" and problem = n + " instances"
|
||||
)
|
||||
}
|
||||
@@ -141,7 +181,7 @@ predicate scope_sanity(string clsname, string problem, string what) {
|
||||
* where `problem` describes the problem and `what` is the empty string.
|
||||
*/
|
||||
predicate jsdoc_sanity(string clsname, string problem, string what) {
|
||||
exists (JSDocTypeExprParent jsdtep | clsname = jsdtep.getAQlClass() |
|
||||
exists(JSDocTypeExprParent jsdtep | clsname = jsdtep.getAQlClass() |
|
||||
uniqueness_error(count(jsdtep.toString()), "toString", problem) and what = ""
|
||||
)
|
||||
}
|
||||
@@ -151,7 +191,7 @@ predicate jsdoc_sanity(string clsname, string problem, string what) {
|
||||
* where `problem` describes the problem and `what` is the name of the variable.
|
||||
*/
|
||||
predicate varref_sanity(string clsname, string problem, string what) {
|
||||
exists (VarRef vr, int n | n = count(vr.getVariable()) and n != 1 |
|
||||
exists(VarRef vr, int n | n = count(vr.getVariable()) and n != 1 |
|
||||
clsname = vr.getAQlClass() and
|
||||
what = vr.getName() and
|
||||
problem = n + " target variables instead of one"
|
||||
@@ -159,10 +199,11 @@ predicate varref_sanity(string clsname, string problem, string what) {
|
||||
}
|
||||
|
||||
from string clsname, string problem, string what
|
||||
where ast_sanity(clsname, problem, what) or
|
||||
location_sanity(clsname, problem, what) or
|
||||
scope_sanity(clsname, problem, what) or
|
||||
cfg_sanity(clsname, problem, what) or
|
||||
jsdoc_sanity(clsname, problem, what) or
|
||||
varref_sanity(clsname, problem, what)
|
||||
where
|
||||
ast_sanity(clsname, problem, what) or
|
||||
location_sanity(clsname, problem, what) or
|
||||
scope_sanity(clsname, problem, what) or
|
||||
cfg_sanity(clsname, problem, what) or
|
||||
jsdoc_sanity(clsname, problem, what) or
|
||||
varref_sanity(clsname, problem, what)
|
||||
select clsname + " " + what + " has " + problem
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
* @id js/unpromoted-route-handler-candidate
|
||||
* @tags analysis-quality
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
from HTTP::RouteHandlerCandidate rh
|
||||
where not rh instanceof HTTP::RouteHandler and
|
||||
not exists (HTTP::RouteSetupCandidate setup |
|
||||
rh.(DataFlow::TrackedNode).flowsTo(setup.getARouteHandlerArg())
|
||||
)
|
||||
select rh, "A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`."
|
||||
where
|
||||
not rh instanceof HTTP::RouteHandler and
|
||||
not exists(HTTP::RouteSetupCandidate setup |
|
||||
rh.(DataFlow::TrackedNode).flowsTo(setup.getARouteHandlerArg())
|
||||
)
|
||||
select rh,
|
||||
"A `RouteHandlerCandidate` that did not get promoted to `RouteHandler`, and it is not used in a `RouteSetupCandidate`."
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
* @id js/unpromoted-route-setup-candidate
|
||||
* @tags analysis-quality
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
from HTTP::RouteSetupCandidate setup
|
||||
where not setup.asExpr() instanceof HTTP::RouteSetup and
|
||||
exists (HTTP::RouteHandlerCandidate rh |
|
||||
rh.(DataFlow::TrackedNode).flowsTo(setup.getARouteHandlerArg())
|
||||
)
|
||||
select setup, "A `RouteSetupCandidate` that did not get promoted to `RouteSetup`, and it is using at least one `RouteHandlerCandidate`."
|
||||
where
|
||||
not setup.asExpr() instanceof HTTP::RouteSetup and
|
||||
exists(HTTP::RouteHandlerCandidate rh |
|
||||
rh.(DataFlow::TrackedNode).flowsTo(setup.getARouteHandlerArg())
|
||||
)
|
||||
select setup,
|
||||
"A `RouteSetupCandidate` that did not get promoted to `RouteSetup`, and it is using at least one `RouteHandlerCandidate`."
|
||||
|
||||
@@ -47,12 +47,12 @@ class ASTNode extends @ast_node, Locatable {
|
||||
(
|
||||
sl < tksl
|
||||
or
|
||||
(sl = tksl and sc <= tksc)
|
||||
sl = tksl and sc <= tksc
|
||||
) and
|
||||
(
|
||||
tkel < el
|
||||
or
|
||||
(tkel = el and tkec <= ec)
|
||||
tkel = el and tkec <= ec
|
||||
)
|
||||
) and
|
||||
// exclude empty EOF token
|
||||
@@ -236,7 +236,7 @@ class StmtContainer extends @stmt_container, ASTNode {
|
||||
* function boundaries. In plain JavaScript, all containers are function boundaries.
|
||||
*/
|
||||
StmtContainer getFunctionBoundary() {
|
||||
if (this instanceof Function or this instanceof TopLevel)
|
||||
if this instanceof Function or this instanceof TopLevel
|
||||
then result = this
|
||||
else result = getEnclosingContainer().getFunctionBoundary()
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import javascript
|
||||
* Holds if `nd` starts a new basic block.
|
||||
*/
|
||||
private predicate startsBB(ControlFlowNode nd) {
|
||||
(not exists(nd.getAPredecessor()) and exists(nd.getASuccessor()))
|
||||
not exists(nd.getAPredecessor()) and exists(nd.getASuccessor())
|
||||
or
|
||||
nd.isJoin()
|
||||
or
|
||||
@@ -194,7 +194,7 @@ class BasicBlock extends @cfg_node, Locatable {
|
||||
predicate isLiveAtEntry(Variable v) {
|
||||
isLocallyLiveAtEntry(v, _)
|
||||
or
|
||||
(not this.defAt(_, v, _) and getASuccessor().isLiveAtEntry(v))
|
||||
not this.defAt(_, v, _) and getASuccessor().isLiveAtEntry(v)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,7 +204,7 @@ class BasicBlock extends @cfg_node, Locatable {
|
||||
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
|
||||
isLocallyLiveAtEntry(v, u)
|
||||
or
|
||||
(not this.defAt(_, v, _) and getASuccessor().localIsLiveAtEntry(v, u))
|
||||
not this.defAt(_, v, _) and getASuccessor().localIsLiveAtEntry(v, u)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +213,7 @@ class BasicBlock extends @cfg_node, Locatable {
|
||||
predicate localIsLiveAtEntry(LocalVariable v) {
|
||||
isLocallyLiveAtEntry(v, _)
|
||||
or
|
||||
(not this.defAt(_, v, _) and getASuccessor().localIsLiveAtEntry(v))
|
||||
not this.defAt(_, v, _) and getASuccessor().localIsLiveAtEntry(v)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +223,7 @@ class BasicBlock extends @cfg_node, Locatable {
|
||||
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
|
||||
isLocallyOverwritten(v, d)
|
||||
or
|
||||
(not defAt(_, v, _) and getASuccessor().localMayBeOverwritten(v, d))
|
||||
not defAt(_, v, _) and getASuccessor().localMayBeOverwritten(v, d)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,9 +55,8 @@ module Internal {
|
||||
private Expr stripNotsAndParens(Expr e, boolean polarity) {
|
||||
exists(Expr inner | inner = e.getUnderlyingValue() |
|
||||
if inner instanceof LogNotExpr
|
||||
then (
|
||||
result = stripNotsAndParens(inner.(LogNotExpr).getOperand(), polarity.booleanNot())
|
||||
) else (
|
||||
then result = stripNotsAndParens(inner.(LogNotExpr).getOperand(), polarity.booleanNot())
|
||||
else (
|
||||
result = inner and polarity = true
|
||||
)
|
||||
)
|
||||
|
||||
@@ -386,7 +386,7 @@ class Property extends @property, Documentable {
|
||||
* its initializer expression could have side effects.
|
||||
*/
|
||||
predicate isImpure() {
|
||||
(isComputed() and getNameExpr().isImpure())
|
||||
isComputed() and getNameExpr().isImpure()
|
||||
or
|
||||
getInit().isImpure()
|
||||
}
|
||||
@@ -530,8 +530,8 @@ 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().getUnderlyingValue() |
|
||||
result = (callee.(Identifier)).getName() or
|
||||
result = (callee.(PropAccess)).getPropertyName()
|
||||
result = callee.(Identifier).getName() or
|
||||
result = callee.(PropAccess).getPropertyName()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -710,7 +710,7 @@ class IndexExpr extends @indexexpr, PropAccess {
|
||||
/** Gets the expression specifying the name of the accessed property. */
|
||||
Expr getIndex() { result = getChildExpr(1) }
|
||||
|
||||
override string getPropertyName() { result = (getIndex().(Literal)).getValue() }
|
||||
override string getPropertyName() { result = getIndex().(Literal).getValue() }
|
||||
|
||||
override predicate isImpure() {
|
||||
getBase().isImpure() or
|
||||
|
||||
@@ -55,15 +55,15 @@ class PackageJSON extends JSONObject {
|
||||
|
||||
/** Gets the path of a command defined for this package. */
|
||||
string getBin(string cmd) {
|
||||
(cmd = getPackageName() and result = getPropStringValue("bin"))
|
||||
cmd = getPackageName() and result = getPropStringValue("bin")
|
||||
or
|
||||
result = (getPropValue("bin").(JSONObject)).getPropStringValue(cmd)
|
||||
result = getPropValue("bin").(JSONObject).getPropStringValue(cmd)
|
||||
}
|
||||
|
||||
/** Gets a manual page for this package. */
|
||||
string getAManFile() {
|
||||
result = getPropStringValue("man") or
|
||||
result = (getPropValue("man").(JSONArray)).getElementStringValue(_)
|
||||
result = getPropValue("man").(JSONArray).getElementStringValue(_)
|
||||
}
|
||||
|
||||
/** Gets information about the directories of this package. */
|
||||
@@ -129,7 +129,7 @@ class PackageJSON extends JSONObject {
|
||||
PackageDependencies getEngines() { result = getPropValue("engines") }
|
||||
|
||||
/** Holds if this package has strict engine requirements. */
|
||||
predicate isEngineStrict() { (getPropValue("engineStrict").(JSONBoolean)).getValue() = "true" }
|
||||
predicate isEngineStrict() { getPropValue("engineStrict").(JSONBoolean).getValue() = "true" }
|
||||
|
||||
/** Gets information about operating systems supported by this package. */
|
||||
JSONArray getOSs() { result = getPropValue("os") }
|
||||
@@ -191,12 +191,12 @@ class BugTrackerInfo extends JSONValue {
|
||||
|
||||
/** Gets the bug tracker URL. */
|
||||
string getURL() {
|
||||
result = (this.(JSONObject)).getPropStringValue("url") or
|
||||
result = (this.(JSONString)).getValue()
|
||||
result = this.(JSONObject).getPropStringValue("url") or
|
||||
result = this.(JSONString).getValue()
|
||||
}
|
||||
|
||||
/** Gets the bug reporting email address. */
|
||||
string getEmail() { result = (this.(JSONObject)).getPropStringValue("email") }
|
||||
string getEmail() { result = this.(JSONObject).getPropStringValue("email") }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,26 +217,24 @@ class ContributorInfo extends JSONValue {
|
||||
* homepage URL.
|
||||
*/
|
||||
private string parseInfo(int group) {
|
||||
result = (this.(JSONString))
|
||||
.getValue()
|
||||
.regexpCapture("(.*?)(?: <(.*?)>)?(?: \\((.*)?\\))", group)
|
||||
result = this.(JSONString).getValue().regexpCapture("(.*?)(?: <(.*?)>)?(?: \\((.*)?\\))", group)
|
||||
}
|
||||
|
||||
/** Gets the contributor's name. */
|
||||
string getName() {
|
||||
result = (this.(JSONObject)).getPropStringValue("name") or
|
||||
result = this.(JSONObject).getPropStringValue("name") or
|
||||
result = parseInfo(1)
|
||||
}
|
||||
|
||||
/** Gets the contributor's email address. */
|
||||
string getEmail() {
|
||||
result = (this.(JSONObject)).getPropStringValue("email") or
|
||||
result = this.(JSONObject).getPropStringValue("email") or
|
||||
result = parseInfo(2)
|
||||
}
|
||||
|
||||
/** Gets the contributor's homepage URL. */
|
||||
string getURL() {
|
||||
result = (this.(JSONObject)).getPropStringValue("url") or
|
||||
result = this.(JSONObject).getPropStringValue("url") or
|
||||
result = parseInfo(3)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,16 +373,14 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
|
||||
mce.getReceiver().analyze().getAType() = TTString() and
|
||||
mce.getMethodName() = methodName
|
||||
|
|
||||
(methodName = "match" and source.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1)
|
||||
methodName = "match" and source.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1
|
||||
or
|
||||
(
|
||||
methodName = "search" and
|
||||
source.asExpr() = mce.getArgument(0) and
|
||||
mce.getNumArgument() = 1 and
|
||||
// "search" is a common method name, and so we exclude chained accesses
|
||||
// because `String.prototype.search` returns a number
|
||||
not exists(PropAccess p | p.getBase() = mce)
|
||||
)
|
||||
methodName = "search" and
|
||||
source.asExpr() = mce.getArgument(0) and
|
||||
mce.getNumArgument() = 1 and
|
||||
// "search" is a common method name, and so we exclude chained accesses
|
||||
// because `String.prototype.search` returns a number
|
||||
not exists(PropAccess p | p.getBase() = mce)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@ abstract class JumpStmt extends Stmt {
|
||||
/** A break or continue statement. */
|
||||
abstract class BreakOrContinueStmt extends JumpStmt {
|
||||
/** Gets the label this statement refers to, if any. */
|
||||
string getTargetLabel() { result = (getChildExpr(0).(Identifier)).getName() }
|
||||
string getTargetLabel() { result = getChildExpr(0).(Identifier).getName() }
|
||||
|
||||
/** Holds if this statement has an explicit target label. */
|
||||
predicate hasTargetLabel() { exists(getTargetLabel()) }
|
||||
@@ -355,10 +355,10 @@ class ThrowStmt extends @throwstmt, JumpStmt {
|
||||
*/
|
||||
override ASTNode getTarget() {
|
||||
if exists(TryStmt ts | getParentStmt+() = ts.getBody())
|
||||
then (
|
||||
getParentStmt+() = (result.(TryStmt)).getBody() and
|
||||
then
|
||||
getParentStmt+() = result.(TryStmt).getBody() and
|
||||
not exists(TryStmt mid | getParentStmt+() = mid.getBody() and mid.getParentStmt+() = result)
|
||||
) else result = getContainer()
|
||||
else result = getContainer()
|
||||
}
|
||||
|
||||
override ControlFlowNode getFirstControlFlowNode() {
|
||||
|
||||
@@ -456,12 +456,10 @@ class PropertyPattern extends @property, ASTNode {
|
||||
|
||||
/** Gets the name of the property matched by this pattern. */
|
||||
string getName() {
|
||||
(
|
||||
not isComputed() and
|
||||
result = (getNameExpr().(Identifier)).getName()
|
||||
)
|
||||
not isComputed() and
|
||||
result = getNameExpr().(Identifier).getName()
|
||||
or
|
||||
result = (getNameExpr().(Literal)).getValue()
|
||||
result = getNameExpr().(Literal).getValue()
|
||||
}
|
||||
|
||||
/** Gets the object pattern this property pattern belongs to. */
|
||||
@@ -472,7 +470,7 @@ class PropertyPattern extends @property, ASTNode {
|
||||
|
||||
/** Holds if this pattern is impure, that is, if its evaluation could have side effects. */
|
||||
predicate isImpure() {
|
||||
(isComputed() and getNameExpr().isImpure())
|
||||
isComputed() and getNameExpr().isImpure()
|
||||
or
|
||||
getValuePattern().isImpure()
|
||||
}
|
||||
|
||||
@@ -74,13 +74,11 @@ class XMLParent extends @xmlparent {
|
||||
* up to a specified (zero-based) index.
|
||||
*/
|
||||
deprecated string charsSetUpTo(int n) {
|
||||
(n = 0 and xmlChars(_, result, this, 0, _, _))
|
||||
n = 0 and xmlChars(_, result, this, 0, _, _)
|
||||
or
|
||||
(
|
||||
n > 0 and
|
||||
exists(string chars | xmlChars(_, chars, this, n, _, _) |
|
||||
result = this.charsSetUpTo(n - 1) + " " + chars
|
||||
)
|
||||
n > 0 and
|
||||
exists(string chars | xmlChars(_, chars, this, n, _, _) |
|
||||
result = this.charsSetUpTo(n - 1) + " " + chars
|
||||
)
|
||||
}
|
||||
|
||||
@@ -144,15 +142,11 @@ class XMLDTD extends @xmldtd {
|
||||
|
||||
/** Gets a printable representation of this DTD. */
|
||||
string toString() {
|
||||
(
|
||||
this.isPublic() and
|
||||
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
|
||||
)
|
||||
this.isPublic() and
|
||||
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
|
||||
or
|
||||
(
|
||||
not this.isPublic() and
|
||||
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
|
||||
)
|
||||
not this.isPublic() and
|
||||
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,9 +229,9 @@ class XMLNamespace extends @xmlnamespace {
|
||||
|
||||
/** Gets a printable representation of this XML namespace. */
|
||||
string toString() {
|
||||
(this.isDefault() and result = this.getURI())
|
||||
this.isDefault() and result = this.getURI()
|
||||
or
|
||||
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
|
||||
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,9 +33,8 @@ private predicate partiallyCalls(
|
||||
invk.isPartialArgument(callback, _, _) and
|
||||
exists(AbstractFunction callee | callee = callback.getAValue() |
|
||||
if callback.getAValue().isIndefinite("global")
|
||||
then (
|
||||
f = callee.getFunction() and f.getFile() = invk.getFile()
|
||||
) else f = callee.getFunction()
|
||||
then f = callee.getFunction() and f.getFile() = invk.getFile()
|
||||
else f = callee.getFunction()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -137,11 +137,9 @@ private class AnalyzedParameter extends AnalyzedVarDef, @vardecl {
|
||||
override predicate isIncomplete(DataFlow::Incompleteness cause) {
|
||||
getFunction().isIncomplete(cause)
|
||||
or
|
||||
(
|
||||
not getFunction().argumentPassing(this, _) and
|
||||
getFunction().mayReceiveArgument(this) and
|
||||
cause = "call"
|
||||
)
|
||||
not getFunction().argumentPassing(this, _) and
|
||||
getFunction().mayReceiveArgument(this) and
|
||||
cause = "call"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -398,10 +398,8 @@ class GeneralDirective extends CustomDirective, MkCustomDirective {
|
||||
result = getMember("link")
|
||||
or
|
||||
// { link: { pre: function preLink() { ... }, post: function postLink() { ... } } }
|
||||
(
|
||||
(kind = "pre" or kind = "post") and
|
||||
result = getMember("link").getAPropertySource(kind)
|
||||
)
|
||||
(kind = "pre" or kind = "post") and
|
||||
result = getMember("link").getAPropertySource(kind)
|
||||
or
|
||||
// { compile: function() { ... return link; } }
|
||||
exists(Expr compileReturn, DataFlow::SourceNode compileReturnSrc |
|
||||
@@ -413,10 +411,8 @@ class GeneralDirective extends CustomDirective, MkCustomDirective {
|
||||
result = compileReturnSrc
|
||||
or
|
||||
// link = { pre: function preLink() { ... }, post: function postLink() { ... } }
|
||||
(
|
||||
(kind = "pre" or kind = "post") and
|
||||
result = compileReturnSrc.getAPropertySource(kind)
|
||||
)
|
||||
(kind = "pre" or kind = "post") and
|
||||
result = compileReturnSrc.getAPropertySource(kind)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -732,20 +728,16 @@ private class ServiceMethodCall extends AngularJSCall {
|
||||
service.getName() = "$sce" and
|
||||
mce = service.getAMethodCall(methodName)
|
||||
|
|
||||
(
|
||||
// specialized call
|
||||
(methodName = "trustAsHtml" or methodName = "trustAsCss") and
|
||||
e = mce.getArgument(0)
|
||||
)
|
||||
// specialized call
|
||||
(methodName = "trustAsHtml" or methodName = "trustAsCss") and
|
||||
e = mce.getArgument(0)
|
||||
or
|
||||
(
|
||||
// generic call with enum argument
|
||||
methodName = "trustAs" and
|
||||
exists(DataFlow::PropRead prn |
|
||||
prn.asExpr() = mce.getArgument(0) and
|
||||
(prn = service.getAPropertyAccess("HTML") or prn = service.getAPropertyAccess("CSS")) and
|
||||
e = mce.getArgument(1)
|
||||
)
|
||||
// generic call with enum argument
|
||||
methodName = "trustAs" and
|
||||
exists(DataFlow::PropRead prn |
|
||||
prn.asExpr() = mce.getArgument(0) and
|
||||
(prn = service.getAPropertyAccess("HTML") or prn = service.getAPropertyAccess("CSS")) and
|
||||
e = mce.getArgument(1)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -755,18 +747,14 @@ private class ServiceMethodCall extends AngularJSCall {
|
||||
service.getName() = serviceName and
|
||||
mce = service.getAMethodCall(methodName)
|
||||
|
|
||||
(
|
||||
// AngularJS caches (only available during runtime, so similar to sessionStorage)
|
||||
(serviceName = "$cacheFactory" or serviceName = "$templateCache") and
|
||||
methodName = "put" and
|
||||
e = mce.getArgument(1)
|
||||
)
|
||||
// AngularJS caches (only available during runtime, so similar to sessionStorage)
|
||||
(serviceName = "$cacheFactory" or serviceName = "$templateCache") and
|
||||
methodName = "put" and
|
||||
e = mce.getArgument(1)
|
||||
or
|
||||
(
|
||||
serviceName = "$cookies" and
|
||||
(methodName = "put" or methodName = "putObject") and
|
||||
e = mce.getArgument(1)
|
||||
)
|
||||
serviceName = "$cookies" and
|
||||
(methodName = "put" or methodName = "putObject") and
|
||||
e = mce.getArgument(1)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -450,9 +450,9 @@ class NgFilterChain extends TNgFilterChain, NgAstNode {
|
||||
override string pp() { result = "(NgFilterChain: " + ppChildren() + ")" }
|
||||
|
||||
override NgAstNode getChild(int n) {
|
||||
(n = 0 and result = getExpr())
|
||||
n = 0 and result = getExpr()
|
||||
or
|
||||
(n = 1 and result = getFilter())
|
||||
n = 1 and result = getFilter()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -482,9 +482,9 @@ class NgFilter extends TNgFilter, NgMaybeFilter {
|
||||
override string pp() { result = "(NgFilter: " + ppChildren() + ")" }
|
||||
|
||||
override NgAstNode getChild(int n) {
|
||||
(n = 0 and result = getHeadFilter())
|
||||
n = 0 and result = getHeadFilter()
|
||||
or
|
||||
(n = 1 and result = getTailFilter())
|
||||
n = 1 and result = getTailFilter()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -585,9 +585,9 @@ class NgCallExpr extends TNgCallExpr, NgExpr {
|
||||
override string pp() { result = "(NgCallExpr: " + ppChildren() + ")" }
|
||||
|
||||
override NgAstNode getChild(int n) {
|
||||
(n = 0 and this = TNgCallExpr(_, _, result, _))
|
||||
n = 0 and this = TNgCallExpr(_, _, result, _)
|
||||
or
|
||||
(n = 1 and this = TNgCallExpr(_, _, _, result))
|
||||
n = 1 and this = TNgCallExpr(_, _, _, result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,9 +660,9 @@ class NgFilterArgument extends TNgFilterArgument, NgMaybeFilterArgument {
|
||||
override string pp() { result = "(NgFilterArgument: " + ppChildren() + ")" }
|
||||
|
||||
override NgAstNode getChild(int n) {
|
||||
(n = 0 and this = TNgFilterArgument(_, _, result, _))
|
||||
n = 0 and this = TNgFilterArgument(_, _, result, _)
|
||||
or
|
||||
(n = 1 and this = TNgFilterArgument(_, _, _, result))
|
||||
n = 1 and this = TNgFilterArgument(_, _, _, result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -689,9 +689,9 @@ class NgConsCallArgument extends TNgConsCallArgument, NgCallArguments {
|
||||
override string pp() { result = "(NgConsCallArgument: " + ppChildren() + ")" }
|
||||
|
||||
override NgAstNode getChild(int n) {
|
||||
(n = 0 and this = TNgConsCallArgument(_, _, result, _))
|
||||
n = 0 and this = TNgConsCallArgument(_, _, result, _)
|
||||
or
|
||||
(n = 1 and this = TNgConsCallArgument(_, _, _, result))
|
||||
n = 1 and this = TNgConsCallArgument(_, _, _, result)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -761,7 +761,7 @@ private module Parser {
|
||||
not exists(start.pre()) and
|
||||
not exists(end.succ()) and
|
||||
exists(NgToken stmtStart |
|
||||
if (start.(NgOtherToken).is(":") and start.succ().(NgOtherToken).is(":"))
|
||||
if start.(NgOtherToken).is(":") and start.succ().(NgOtherToken).is(":")
|
||||
then (
|
||||
stmtStart = start.succ().succ() and oneTime = true
|
||||
) else (
|
||||
|
||||
@@ -116,121 +116,115 @@ private string getBuiltinKind(string name) {
|
||||
// according to https://docs.angularjs.org/api
|
||||
result = "controller-only" and name = "$scope"
|
||||
or
|
||||
result = "service" and
|
||||
(
|
||||
result = "service" and
|
||||
(
|
||||
// ng
|
||||
name = "$anchorScroll" or
|
||||
name = "$animate" or
|
||||
name = "$animateCss" or
|
||||
name = "$cacheFactory" or
|
||||
name = "$controller" or
|
||||
name = "$document" or
|
||||
name = "$exceptionHandler" or
|
||||
name = "$filter" or
|
||||
name = "$http" or
|
||||
name = "$httpBackend" or
|
||||
name = "$httpParamSerializer" or
|
||||
name = "$httpParamSerializerJQLike" or
|
||||
name = "$interpolate" or
|
||||
name = "$interval" or
|
||||
name = "$jsonpCallbacks" or
|
||||
name = "$locale" or
|
||||
name = "$location" or
|
||||
name = "$log" or
|
||||
name = "$parse" or
|
||||
name = "$q" or
|
||||
name = "$rootElement" or
|
||||
name = "$rootScope" or
|
||||
name = "$sce" or
|
||||
name = "$sceDelegate" or
|
||||
name = "$templateCache" or
|
||||
name = "$templateRequest" or
|
||||
name = "$timeout" or
|
||||
name = "$window" or
|
||||
name = "$xhrFactory" or
|
||||
// auto
|
||||
name = "$injector" or
|
||||
name = "$provide" or
|
||||
// ngAnimate
|
||||
name = "$animate" or
|
||||
name = "$animateCss" or
|
||||
// ngAria
|
||||
name = "$aria" or
|
||||
// ngComponentRouter
|
||||
name = "$rootRouter" or
|
||||
name = "$routerRootComponent" or
|
||||
// ngCookies
|
||||
name = "$cookieStore" or
|
||||
name = "$cookies" or
|
||||
//ngMock
|
||||
name = "$animate" or
|
||||
name = "$componentController" or
|
||||
name = "$controller" or
|
||||
name = "$exceptionHandler" or
|
||||
name = "$httpBackend" or
|
||||
name = "$interval" or
|
||||
name = "$log" or
|
||||
name = "$timeout" or
|
||||
//ngMockE2E
|
||||
name = "$httpBackend" or
|
||||
// ngResource
|
||||
name = "$resource" or
|
||||
// ngRoute
|
||||
name = "$route" or
|
||||
name = "$routeParams" or
|
||||
// ngSanitize
|
||||
name = "$sanitize" or
|
||||
// ngTouch
|
||||
name = "$swipe"
|
||||
)
|
||||
// ng
|
||||
name = "$anchorScroll" or
|
||||
name = "$animate" or
|
||||
name = "$animateCss" or
|
||||
name = "$cacheFactory" or
|
||||
name = "$controller" or
|
||||
name = "$document" or
|
||||
name = "$exceptionHandler" or
|
||||
name = "$filter" or
|
||||
name = "$http" or
|
||||
name = "$httpBackend" or
|
||||
name = "$httpParamSerializer" or
|
||||
name = "$httpParamSerializerJQLike" or
|
||||
name = "$interpolate" or
|
||||
name = "$interval" or
|
||||
name = "$jsonpCallbacks" or
|
||||
name = "$locale" or
|
||||
name = "$location" or
|
||||
name = "$log" or
|
||||
name = "$parse" or
|
||||
name = "$q" or
|
||||
name = "$rootElement" or
|
||||
name = "$rootScope" or
|
||||
name = "$sce" or
|
||||
name = "$sceDelegate" or
|
||||
name = "$templateCache" or
|
||||
name = "$templateRequest" or
|
||||
name = "$timeout" or
|
||||
name = "$window" or
|
||||
name = "$xhrFactory" or
|
||||
// auto
|
||||
name = "$injector" or
|
||||
name = "$provide" or
|
||||
// ngAnimate
|
||||
name = "$animate" or
|
||||
name = "$animateCss" or
|
||||
// ngAria
|
||||
name = "$aria" or
|
||||
// ngComponentRouter
|
||||
name = "$rootRouter" or
|
||||
name = "$routerRootComponent" or
|
||||
// ngCookies
|
||||
name = "$cookieStore" or
|
||||
name = "$cookies" or
|
||||
//ngMock
|
||||
name = "$animate" or
|
||||
name = "$componentController" or
|
||||
name = "$controller" or
|
||||
name = "$exceptionHandler" or
|
||||
name = "$httpBackend" or
|
||||
name = "$interval" or
|
||||
name = "$log" or
|
||||
name = "$timeout" or
|
||||
//ngMockE2E
|
||||
name = "$httpBackend" or
|
||||
// ngResource
|
||||
name = "$resource" or
|
||||
// ngRoute
|
||||
name = "$route" or
|
||||
name = "$routeParams" or
|
||||
// ngSanitize
|
||||
name = "$sanitize" or
|
||||
// ngTouch
|
||||
name = "$swipe"
|
||||
)
|
||||
or
|
||||
result = "provider" and
|
||||
(
|
||||
result = "provider" and
|
||||
(
|
||||
// ng
|
||||
name = "$anchorScrollProvider" or
|
||||
name = "$animateProvider" or
|
||||
name = "$compileProvider" or
|
||||
name = "$controllerProvider" or
|
||||
name = "$filterProvider" or
|
||||
name = "$httpProvider" or
|
||||
name = "$interpolateProvider" or
|
||||
name = "$locationProvider" or
|
||||
name = "$logProvider" or
|
||||
name = "$parseProvider" or
|
||||
name = "$provider" or
|
||||
name = "$qProvider" or
|
||||
name = "$rootScopeProvider" or
|
||||
name = "$sceDelegateProvider" or
|
||||
name = "$sceProvider" or
|
||||
name = "$templateRequestProvider" or
|
||||
// ngAria
|
||||
name = "$ariaProvider" or
|
||||
// ngCookies
|
||||
name = "$cookiesProvider" or
|
||||
// ngmock
|
||||
name = "$exceptionHandlerProvider" or
|
||||
// ngResource
|
||||
name = "$resourceProvider" or
|
||||
// ngRoute
|
||||
name = "$routeProvider" or
|
||||
// ngSanitize
|
||||
name = "$sanitizeProvider"
|
||||
)
|
||||
// ng
|
||||
name = "$anchorScrollProvider" or
|
||||
name = "$animateProvider" or
|
||||
name = "$compileProvider" or
|
||||
name = "$controllerProvider" or
|
||||
name = "$filterProvider" or
|
||||
name = "$httpProvider" or
|
||||
name = "$interpolateProvider" or
|
||||
name = "$locationProvider" or
|
||||
name = "$logProvider" or
|
||||
name = "$parseProvider" or
|
||||
name = "$provider" or
|
||||
name = "$qProvider" or
|
||||
name = "$rootScopeProvider" or
|
||||
name = "$sceDelegateProvider" or
|
||||
name = "$sceProvider" or
|
||||
name = "$templateRequestProvider" or
|
||||
// ngAria
|
||||
name = "$ariaProvider" or
|
||||
// ngCookies
|
||||
name = "$cookiesProvider" or
|
||||
// ngmock
|
||||
name = "$exceptionHandlerProvider" or
|
||||
// ngResource
|
||||
name = "$resourceProvider" or
|
||||
// ngRoute
|
||||
name = "$routeProvider" or
|
||||
// ngSanitize
|
||||
name = "$sanitizeProvider"
|
||||
)
|
||||
or
|
||||
result = "type" and
|
||||
(
|
||||
result = "type" and
|
||||
(
|
||||
// ng
|
||||
name = "$cacheFactory" or
|
||||
name = "$compile" or
|
||||
name = "$rootScope" or
|
||||
// ngMock
|
||||
name = "$rootScope"
|
||||
)
|
||||
// ng
|
||||
name = "$cacheFactory" or
|
||||
name = "$compile" or
|
||||
name = "$rootScope" or
|
||||
// ngMock
|
||||
name = "$rootScope"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -319,16 +313,12 @@ private predicate isCustomServiceDefinitionOnProvider(
|
||||
) {
|
||||
mce = builtinServiceRef(providerName).getAMethodCall(providerMethodName) and
|
||||
(
|
||||
(
|
||||
mce.getNumArgument() = 1 and
|
||||
factoryFunction.flowsTo(mce.getOptionArgument(0, serviceName))
|
||||
)
|
||||
mce.getNumArgument() = 1 and
|
||||
factoryFunction.flowsTo(mce.getOptionArgument(0, serviceName))
|
||||
or
|
||||
(
|
||||
mce.getNumArgument() = 2 and
|
||||
mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and
|
||||
factoryFunction.flowsTo(mce.getArgument(1))
|
||||
)
|
||||
mce.getNumArgument() = 2 and
|
||||
mce.getArgument(0).asExpr().mayHaveStringValue(serviceName) and
|
||||
factoryFunction.flowsTo(mce.getArgument(1))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -163,10 +163,8 @@ private class FetchUrlRequest extends CustomClientRequest {
|
||||
url = getArgument(0)
|
||||
)
|
||||
or
|
||||
(
|
||||
this = DataFlow::globalVarRef("fetch").getACall() and
|
||||
url = getArgument(0)
|
||||
)
|
||||
this = DataFlow::globalVarRef("fetch").getACall() and
|
||||
url = getArgument(0)
|
||||
}
|
||||
|
||||
override DataFlow::Node getUrl() { result = url }
|
||||
|
||||
@@ -37,7 +37,7 @@ module ConnectExpressShared {
|
||||
exists(string request, string response, string next, string error |
|
||||
(request = "request" or request = "req") and
|
||||
(response = "response" or response = "res") and
|
||||
(next = "next") and
|
||||
next = "next" and
|
||||
(error = "error" or error = "err")
|
||||
|
|
||||
// heuristic: parameter names match the documentation
|
||||
|
||||
@@ -88,19 +88,19 @@ private import AlgorithmNames
|
||||
*/
|
||||
private newtype TCryptographicAlgorithm =
|
||||
MkHashingAlgorithm(string name, boolean isWeak) {
|
||||
(isStrongHashingAlgorithm(name) and isWeak = false)
|
||||
isStrongHashingAlgorithm(name) and isWeak = false
|
||||
or
|
||||
(isWeakHashingAlgorithm(name) and isWeak = true)
|
||||
isWeakHashingAlgorithm(name) and isWeak = true
|
||||
} or
|
||||
MkEncryptionAlgorithm(string name, boolean isWeak) {
|
||||
(isStrongEncryptionAlgorithm(name) and isWeak = false)
|
||||
isStrongEncryptionAlgorithm(name) and isWeak = false
|
||||
or
|
||||
(isWeakEncryptionAlgorithm(name) and isWeak = true)
|
||||
isWeakEncryptionAlgorithm(name) and isWeak = true
|
||||
} or
|
||||
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
|
||||
(isStrongPasswordHashingAlgorithm(name) and isWeak = false)
|
||||
isStrongPasswordHashingAlgorithm(name) and isWeak = false
|
||||
or
|
||||
(isWeakPasswordHashingAlgorithm(name) and isWeak = true)
|
||||
isWeakPasswordHashingAlgorithm(name) and isWeak = true
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -213,10 +213,8 @@ module Hapi {
|
||||
astNode.getParameter(0).getName() = request and
|
||||
astNode.getParameter(1).getName() = responseToolkit
|
||||
|
|
||||
not (
|
||||
// heuristic: is not invoked (Hapi invokes this at a call site we cannot reason precisely about)
|
||||
exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
|
||||
)
|
||||
// heuristic: is not invoked (Hapi invokes this at a call site we cannot reason precisely about)
|
||||
not exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,101 +65,93 @@ private class AnalyzedThisInBoundCallback extends AnalyzedNode, DataFlow::ThisNo
|
||||
thisSource = bindingCall.getArgument(contextIndex)
|
||||
|
|
||||
(
|
||||
(
|
||||
binderName = "bind" or
|
||||
binderName = "callback" or
|
||||
binderName = "iteratee"
|
||||
) and
|
||||
callbackIndex = 0 and
|
||||
contextIndex = 1 and
|
||||
argumentCount = 2
|
||||
)
|
||||
binderName = "bind" or
|
||||
binderName = "callback" or
|
||||
binderName = "iteratee"
|
||||
) and
|
||||
callbackIndex = 0 and
|
||||
contextIndex = 1 and
|
||||
argumentCount = 2
|
||||
or
|
||||
(
|
||||
(
|
||||
binderName = "all" or
|
||||
binderName = "any" or
|
||||
binderName = "collect" or
|
||||
binderName = "countBy" or
|
||||
binderName = "detect" or
|
||||
binderName = "dropRightWhile" or
|
||||
binderName = "dropWhile" or
|
||||
binderName = "each" or
|
||||
binderName = "eachRight" or
|
||||
binderName = "every" or
|
||||
binderName = "filter" or
|
||||
binderName = "find" or
|
||||
binderName = "findIndex" or
|
||||
binderName = "findKey" or
|
||||
binderName = "findLast" or
|
||||
binderName = "findLastIndex" or
|
||||
binderName = "findLastKey" or
|
||||
binderName = "forEach" or
|
||||
binderName = "forEachRight" or
|
||||
binderName = "forIn" or
|
||||
binderName = "forInRight" or
|
||||
binderName = "groupBy" or
|
||||
binderName = "indexBy" or
|
||||
binderName = "map" or
|
||||
binderName = "mapKeys" or
|
||||
binderName = "mapValues" or
|
||||
binderName = "max" or
|
||||
binderName = "min" or
|
||||
binderName = "omit" or
|
||||
binderName = "partition" or
|
||||
binderName = "pick" or
|
||||
binderName = "reject" or
|
||||
binderName = "remove" or
|
||||
binderName = "select" or
|
||||
binderName = "some" or
|
||||
binderName = "sortBy" or
|
||||
binderName = "sum" or
|
||||
binderName = "takeRightWhile" or
|
||||
binderName = "takeWhile" or
|
||||
binderName = "tap" or
|
||||
binderName = "thru" or
|
||||
binderName = "times" or
|
||||
binderName = "unzipWith" or
|
||||
binderName = "zipWith"
|
||||
) and
|
||||
callbackIndex = 1 and
|
||||
contextIndex = 2 and
|
||||
argumentCount = 3
|
||||
)
|
||||
binderName = "all" or
|
||||
binderName = "any" or
|
||||
binderName = "collect" or
|
||||
binderName = "countBy" or
|
||||
binderName = "detect" or
|
||||
binderName = "dropRightWhile" or
|
||||
binderName = "dropWhile" or
|
||||
binderName = "each" or
|
||||
binderName = "eachRight" or
|
||||
binderName = "every" or
|
||||
binderName = "filter" or
|
||||
binderName = "find" or
|
||||
binderName = "findIndex" or
|
||||
binderName = "findKey" or
|
||||
binderName = "findLast" or
|
||||
binderName = "findLastIndex" or
|
||||
binderName = "findLastKey" or
|
||||
binderName = "forEach" or
|
||||
binderName = "forEachRight" or
|
||||
binderName = "forIn" or
|
||||
binderName = "forInRight" or
|
||||
binderName = "groupBy" or
|
||||
binderName = "indexBy" or
|
||||
binderName = "map" or
|
||||
binderName = "mapKeys" or
|
||||
binderName = "mapValues" or
|
||||
binderName = "max" or
|
||||
binderName = "min" or
|
||||
binderName = "omit" or
|
||||
binderName = "partition" or
|
||||
binderName = "pick" or
|
||||
binderName = "reject" or
|
||||
binderName = "remove" or
|
||||
binderName = "select" or
|
||||
binderName = "some" or
|
||||
binderName = "sortBy" or
|
||||
binderName = "sum" or
|
||||
binderName = "takeRightWhile" or
|
||||
binderName = "takeWhile" or
|
||||
binderName = "tap" or
|
||||
binderName = "thru" or
|
||||
binderName = "times" or
|
||||
binderName = "unzipWith" or
|
||||
binderName = "zipWith"
|
||||
) and
|
||||
callbackIndex = 1 and
|
||||
contextIndex = 2 and
|
||||
argumentCount = 3
|
||||
or
|
||||
(
|
||||
(
|
||||
binderName = "foldl" or
|
||||
binderName = "foldr" or
|
||||
binderName = "inject" or
|
||||
binderName = "reduce" or
|
||||
binderName = "reduceRight" or
|
||||
binderName = "transform"
|
||||
) and
|
||||
callbackIndex = 1 and
|
||||
contextIndex = 3 and
|
||||
argumentCount = 4
|
||||
)
|
||||
binderName = "foldl" or
|
||||
binderName = "foldr" or
|
||||
binderName = "inject" or
|
||||
binderName = "reduce" or
|
||||
binderName = "reduceRight" or
|
||||
binderName = "transform"
|
||||
) and
|
||||
callbackIndex = 1 and
|
||||
contextIndex = 3 and
|
||||
argumentCount = 4
|
||||
or
|
||||
(
|
||||
(
|
||||
binderName = "sortedlastIndex"
|
||||
or
|
||||
binderName = "assign"
|
||||
or
|
||||
binderName = "eq"
|
||||
or
|
||||
binderName = "extend"
|
||||
or
|
||||
binderName = "merge"
|
||||
or
|
||||
binderName = "sortedIndex" and
|
||||
binderName = "uniq"
|
||||
) and
|
||||
callbackIndex = 2 and
|
||||
contextIndex = 3 and
|
||||
argumentCount = 4
|
||||
)
|
||||
binderName = "sortedlastIndex"
|
||||
or
|
||||
binderName = "assign"
|
||||
or
|
||||
binderName = "eq"
|
||||
or
|
||||
binderName = "extend"
|
||||
or
|
||||
binderName = "merge"
|
||||
or
|
||||
binderName = "sortedIndex" and
|
||||
binderName = "uniq"
|
||||
) and
|
||||
callbackIndex = 2 and
|
||||
contextIndex = 3 and
|
||||
argumentCount = 4
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -243,22 +243,22 @@ module NodeJSLib {
|
||||
PathFlowTarget() {
|
||||
exists(string methodName | this = DataFlow::moduleMember("path", methodName).getACall() |
|
||||
// getters
|
||||
(methodName = "basename" and tainted = getArgument(0))
|
||||
methodName = "basename" and tainted = getArgument(0)
|
||||
or
|
||||
(methodName = "dirname" and tainted = getArgument(0))
|
||||
methodName = "dirname" and tainted = getArgument(0)
|
||||
or
|
||||
(methodName = "extname" and tainted = getArgument(0))
|
||||
methodName = "extname" and tainted = getArgument(0)
|
||||
or
|
||||
// transformers
|
||||
(methodName = "join" and tainted = getAnArgument())
|
||||
methodName = "join" and tainted = getAnArgument()
|
||||
or
|
||||
(methodName = "normalize" and tainted = getArgument(0))
|
||||
methodName = "normalize" and tainted = getArgument(0)
|
||||
or
|
||||
(methodName = "relative" and tainted = getArgument([0 .. 1]))
|
||||
methodName = "relative" and tainted = getArgument([0 .. 1])
|
||||
or
|
||||
(methodName = "resolve" and tainted = getAnArgument())
|
||||
methodName = "resolve" and tainted = getAnArgument()
|
||||
or
|
||||
(methodName = "toNamespacedPath" and tainted = getArgument(0))
|
||||
methodName = "toNamespacedPath" and tainted = getArgument(0)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -60,30 +60,24 @@ module PkgCloud {
|
||||
* - RedisToGo
|
||||
*/
|
||||
|
||||
kind = "user name" and
|
||||
(
|
||||
kind = "user name" and
|
||||
(
|
||||
propertyName = "account" or
|
||||
propertyName = "keyId" or
|
||||
propertyName = "storageAccount" or
|
||||
propertyName = "username"
|
||||
)
|
||||
propertyName = "account" or
|
||||
propertyName = "keyId" or
|
||||
propertyName = "storageAccount" or
|
||||
propertyName = "username"
|
||||
)
|
||||
or
|
||||
kind = "password" and
|
||||
(
|
||||
kind = "password" and
|
||||
(
|
||||
propertyName = "key" or
|
||||
propertyName = "apiKey" or
|
||||
propertyName = "storageAccessKey" or
|
||||
propertyName = "password"
|
||||
)
|
||||
propertyName = "key" or
|
||||
propertyName = "apiKey" or
|
||||
propertyName = "storageAccessKey" or
|
||||
propertyName = "password"
|
||||
)
|
||||
or
|
||||
(
|
||||
kind = "token" and
|
||||
(propertyName = "token")
|
||||
)
|
||||
kind = "token" and
|
||||
propertyName = "token"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -69,17 +69,13 @@ private class SimplePropertyProjection extends CustomPropertyProjection {
|
||||
exists(DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
singleton = false and
|
||||
(
|
||||
(
|
||||
callee = LodashUnderscore::member("pick") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = [1 .. getNumArgument()]
|
||||
)
|
||||
callee = LodashUnderscore::member("pick") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = [1 .. getNumArgument()]
|
||||
or
|
||||
(
|
||||
callee = LodashUnderscore::member("pickBy") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
callee = LodashUnderscore::member("pickBy") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
or
|
||||
exists(string name |
|
||||
name = "pick" or
|
||||
@@ -91,38 +87,28 @@ private class SimplePropertyProjection extends CustomPropertyProjection {
|
||||
selectorIndex = 0
|
||||
)
|
||||
or
|
||||
(
|
||||
callee = DataFlow::moduleMember("dotty", "search") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
callee = DataFlow::moduleMember("dotty", "search") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
or
|
||||
singleton = true and
|
||||
(
|
||||
(
|
||||
callee = LodashUnderscore::member("get") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
callee = LodashUnderscore::member("get") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
or
|
||||
(
|
||||
callee = DataFlow::moduleMember("ramda", "path") and
|
||||
objectIndex = 1 and
|
||||
selectorIndex = 0
|
||||
)
|
||||
callee = DataFlow::moduleMember("ramda", "path") and
|
||||
objectIndex = 1 and
|
||||
selectorIndex = 0
|
||||
or
|
||||
(
|
||||
callee = DataFlow::moduleMember("dottie", "get") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
callee = DataFlow::moduleMember("dottie", "get") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
or
|
||||
(
|
||||
callee = DataFlow::moduleMember("dotty", "get") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
callee = DataFlow::moduleMember("dotty", "get") and
|
||||
objectIndex = 0 and
|
||||
selectorIndex = 1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ module Request {
|
||||
auth = action.getAMemberCall("auth").asExpr() and
|
||||
this = auth.getArgument(argIndex)
|
||||
|
|
||||
(argIndex = 0 and kind = "user name")
|
||||
argIndex = 0 and kind = "user name"
|
||||
or
|
||||
(argIndex = 1 and kind = "password")
|
||||
argIndex = 1 and kind = "password"
|
||||
or
|
||||
(argIndex = 3 and kind = "token")
|
||||
argIndex = 3 and kind = "token"
|
||||
)
|
||||
or
|
||||
exists(DataFlow::ObjectLiteralNode auth, string propertyName |
|
||||
@@ -37,17 +37,13 @@ module Request {
|
||||
auth.flowsTo(action.getOptionArgument(1, "auth")) and
|
||||
auth.hasPropertyWrite(propertyName, DataFlow::valueNode(this))
|
||||
|
|
||||
(
|
||||
(propertyName = "user" or propertyName = "username") and
|
||||
kind = "user name"
|
||||
)
|
||||
(propertyName = "user" or propertyName = "username") and
|
||||
kind = "user name"
|
||||
or
|
||||
(
|
||||
(propertyName = "pass" or propertyName = "password") and
|
||||
kind = "password"
|
||||
)
|
||||
(propertyName = "pass" or propertyName = "password") and
|
||||
kind = "password"
|
||||
or
|
||||
(propertyName = "bearer" and kind = "token")
|
||||
propertyName = "bearer" and kind = "token"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -48,13 +48,13 @@ abstract class JSLintDirective extends SlashStarComment {
|
||||
(
|
||||
fsl < dsl
|
||||
or
|
||||
(fsl = dsl and fsc <= dsc)
|
||||
fsl = dsl and fsc <= dsc
|
||||
) and
|
||||
// and it ends after this directive
|
||||
(
|
||||
del < fel
|
||||
or
|
||||
(del = fel and dec <= fec)
|
||||
del = fel and dec <= fec
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -153,100 +153,90 @@ class JSLintOptions extends JSLintDirective {
|
||||
*/
|
||||
private string jsLintImplicitGlobal(string category) {
|
||||
// cf. http://www.jslint.com/help.html#global
|
||||
category = "browser" and
|
||||
(
|
||||
category = "browser" and
|
||||
(
|
||||
result = "clearInterval" or
|
||||
result = "clearTimeout" or
|
||||
result = "document" or
|
||||
result = "event" or
|
||||
result = "frames" or
|
||||
result = "history" or
|
||||
result = "Image" or
|
||||
result = "location" or
|
||||
result = "name" or
|
||||
result = "navigator" or
|
||||
result = "Option" or
|
||||
result = "parent" or
|
||||
result = "screen" or
|
||||
result = "setInterval" or
|
||||
result = "setTimeout" or
|
||||
result = "window" or
|
||||
result = "XMLHttpRequest"
|
||||
)
|
||||
result = "clearInterval" or
|
||||
result = "clearTimeout" or
|
||||
result = "document" or
|
||||
result = "event" or
|
||||
result = "frames" or
|
||||
result = "history" or
|
||||
result = "Image" or
|
||||
result = "location" or
|
||||
result = "name" or
|
||||
result = "navigator" or
|
||||
result = "Option" or
|
||||
result = "parent" or
|
||||
result = "screen" or
|
||||
result = "setInterval" or
|
||||
result = "setTimeout" or
|
||||
result = "window" or
|
||||
result = "XMLHttpRequest"
|
||||
)
|
||||
or
|
||||
category = "devel" and
|
||||
(
|
||||
category = "devel" and
|
||||
(
|
||||
result = "alert" or
|
||||
result = "confirm" or
|
||||
result = "console" or
|
||||
result = "Debug" or
|
||||
result = "opera" or
|
||||
result = "prompt" or
|
||||
result = "WSH"
|
||||
)
|
||||
result = "alert" or
|
||||
result = "confirm" or
|
||||
result = "console" or
|
||||
result = "Debug" or
|
||||
result = "opera" or
|
||||
result = "prompt" or
|
||||
result = "WSH"
|
||||
)
|
||||
or
|
||||
category = "node" and
|
||||
(
|
||||
category = "node" and
|
||||
(
|
||||
result = "Buffer" or
|
||||
result = "clearInterval" or
|
||||
result = "clearTimeout" or
|
||||
result = "console" or
|
||||
result = "exports" or
|
||||
result = "result" or
|
||||
result = "module" or
|
||||
result = "process" or
|
||||
result = "querystring" or
|
||||
result = "require" or
|
||||
result = "setInterval" or
|
||||
result = "setTimeout" or
|
||||
result = "__filename" or
|
||||
result = "__dirname"
|
||||
)
|
||||
result = "Buffer" or
|
||||
result = "clearInterval" or
|
||||
result = "clearTimeout" or
|
||||
result = "console" or
|
||||
result = "exports" or
|
||||
result = "result" or
|
||||
result = "module" or
|
||||
result = "process" or
|
||||
result = "querystring" or
|
||||
result = "require" or
|
||||
result = "setInterval" or
|
||||
result = "setTimeout" or
|
||||
result = "__filename" or
|
||||
result = "__dirname"
|
||||
)
|
||||
or
|
||||
category = "couch" and
|
||||
(
|
||||
category = "couch" and
|
||||
(
|
||||
result = "emit" or
|
||||
result = "getRow" or
|
||||
result = "isArray" or
|
||||
result = "log" or
|
||||
result = "provides" or
|
||||
result = "registerType" or
|
||||
result = "require" or
|
||||
result = "send" or
|
||||
result = "start" or
|
||||
result = "sum" or
|
||||
result = "toJSON"
|
||||
)
|
||||
result = "emit" or
|
||||
result = "getRow" or
|
||||
result = "isArray" or
|
||||
result = "log" or
|
||||
result = "provides" or
|
||||
result = "registerType" or
|
||||
result = "require" or
|
||||
result = "send" or
|
||||
result = "start" or
|
||||
result = "sum" or
|
||||
result = "toJSON"
|
||||
)
|
||||
or
|
||||
category = "rhino" and
|
||||
(
|
||||
category = "rhino" and
|
||||
(
|
||||
result = "defineClass" or
|
||||
result = "deserialize" or
|
||||
result = "gc" or
|
||||
result = "help" or
|
||||
result = "load" or
|
||||
result = "loadClass" or
|
||||
result = "print" or
|
||||
result = "quit" or
|
||||
result = "readFile" or
|
||||
result = "readUrl" or
|
||||
result = "runCommand" or
|
||||
result = "seal" or
|
||||
result = "serialize" or
|
||||
result = "spawn" or
|
||||
result = "sync" or
|
||||
result = "toint32" or
|
||||
result = "version"
|
||||
)
|
||||
result = "defineClass" or
|
||||
result = "deserialize" or
|
||||
result = "gc" or
|
||||
result = "help" or
|
||||
result = "load" or
|
||||
result = "loadClass" or
|
||||
result = "print" or
|
||||
result = "quit" or
|
||||
result = "readFile" or
|
||||
result = "readUrl" or
|
||||
result = "runCommand" or
|
||||
result = "seal" or
|
||||
result = "serialize" or
|
||||
result = "spawn" or
|
||||
result = "sync" or
|
||||
result = "toint32" or
|
||||
result = "version"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user