Merge pull request #395 from esben-semmle/js/useless-defensive-code

JS: add query: js/useless-defensive-code
This commit is contained in:
Max Schaefer
2018-11-13 16:55:59 +00:00
committed by GitHub
21 changed files with 905 additions and 24 deletions

View File

@@ -23,6 +23,7 @@
| Replacement of a substring with itself (`js/identity-replacement`) | correctness, security, external/cwe/cwe-116 | Highlights string replacements that replace a string with itself, which usually indicates a mistake. Results shown on LGTM by default. |
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
| Unclear precedence of nested operators (`js/unclear-operator-precedence`) | maintainability, correctness, external/cwe/cwe-783 | Highlights nested binary operators whose relative precedence is easy to misunderstand. Results shown on LGTM by default. |
| Unneeded defensive code | correctness, external/cwe/cwe-570, external/cwe/cwe-571 | Highlights locations where defensive code is not needed. Results are shown on LGTM by default. |
| Useless assignment to property | maintainability | Highlights property assignments whose value is always overwritten. Results are shown on LGTM by default. |
| User-controlled data in file | security, external/cwe/cwe-912 | Highlights locations where user-controlled data is written to a file. Results are not shown on LGTM by default. |

View File

@@ -6,6 +6,7 @@
+ semmlecode-javascript-queries/Declarations/DuplicateVarDecl.ql: /Maintainability/Declarations
+ semmlecode-javascript-queries/Declarations/UnusedParameter.ql: /Maintainability/Declarations
+ semmlecode-javascript-queries/Declarations/UnusedVariable.ql: /Maintainability/Declarations
+ semmlecode-javascript-queries/Expressions/UselessDefensiveProgramming.ql: /Maintainability/Expressions
+ semmlecode-javascript-queries/LanguageFeatures/ArgumentsCallerCallee.ql: /Maintainability/Language Features
+ semmlecode-javascript-queries/LanguageFeatures/ConditionalComments.ql: /Maintainability/Language Features
+ semmlecode-javascript-queries/LanguageFeatures/Eval.ql: /Maintainability/Language Features

View File

@@ -15,6 +15,7 @@
import javascript
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.DefensiveProgramming
/**
* Holds if `left` and `right` are the left and right operands, respectively, of `nd`, which is
@@ -198,6 +199,7 @@ from ASTNode cmp,
int leftTypeCount, int rightTypeCount ,
string leftTypeDescription, string rightTypeDescription
where isHeterogeneousComparison(cmp, left, right, leftTypes, rightTypes) and
not exists (cmp.(Expr).flow().(DefensiveExpressionTest).getTheTestResult()) and
not whitelist(left.asExpr()) and
not whitelist(right.asExpr()) and
leftExprDescription = capitalize(getDescription(left.asExpr(), "this expression")) and

View File

@@ -0,0 +1,91 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Defensive code can prevent unforeseen circumstances from
causing fatal program behaviors.
A common defensive code pattern is to guard
against dereferencing the values <code>null</code> or
<code>undefined</code>.
However, if the situation that some defensive code guards
against never can occur, then the defensive code serves no purpose and
can safely be removed.
</p>
</overview>
<recommendation>
<p>
Examine the surrounding code to determine if the defensive
code is worth keeping despite providing no practical use. If it is no
longer needed, remove it.
</p>
</recommendation>
<example>
<p>
The following example shows a <code>cleanupLater</code>
function that asynchronously will perform a cleanup task after some
delay. When the cleanup task completes, the function invokes the
provided callback parameter <code>cb</code>.
To prevent a crash by invoking <code>cb</code> when it
has the value <code>undefined</code>, defensive code guards
the invocation by checking if <code>cb</code> is truthy.
</p>
<sample src="examples/UnneededDefensiveProgramming1_bad.js" />
<p>
However, the <code>cleanupLater</code> function is always
invoked with a callback argument, so the defensive code condition
always holds, and it is therefore not
required. The function can therefore be simplified to:
</p>
<sample src="examples/UnneededDefensiveProgramming1_good.js" />
<p>
Guarding against the same situation multiple times is
another example of defensive code that provides no practical use. The
example below shows a function that assigns a value to a property of
an object, where defensive code ensures that the assigned value is not
<code>undefined</code> or <code>null</code>.
</p>
<sample src="examples/UnneededDefensiveProgramming2_bad.js" />
<p>
However, due to coercion rules, <code>v ==
undefined</code> holds for both the situation where <code>v</code>
is<code>undefined</code> and the situation where <code>v</code>
is<code>null</code>, so the <code>v == null</code>
guard serves no purpose, and can be removed:
</p>
<sample src="examples/UnneededDefensiveProgramming2_good.js" />
</example>
<references>
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/Defensive_programming">Defensive programming</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,31 @@
/**
* @name Unneeded defensive code
* @description Defensive code that guards against a situation that never happens is not needed.
* @kind problem
* @problem.severity recommendation
* @id js/unneeded-defensive-code
* @tags correctness
* external/cwe/cwe-570
* external/cwe/cwe-571
* @precision very-high
*/
import javascript
import semmle.javascript.DefensiveProgramming
from DefensiveExpressionTest e, boolean cv
where e.getTheTestResult() = cv and
// whitelist
not (
// module environment detection
exists (VarAccess access, string name |
name = "exports" or name = "module" |
e.asExpr().(Internal::TypeofUndefinedTest).getOperand() = access and
access.getName() = name and
not exists (access.getVariable().getADeclaration())
)
or
// too benign in practice
e instanceof Internal::DefensiveInit
)
select e, "This guard always evaluates to " + cv + "."

View File

@@ -0,0 +1,10 @@
function cleanupLater(delay, cb) {
setTimeout(function() {
cleanup();
if (cb) { // BAD: useless check, `cb` is always truthy
cb();
}
}, delay)
}
cleanupLater(1000, function(){console.log("Cleanup done")});

View File

@@ -0,0 +1,9 @@
function cleanupLater(delay, cb) {
setTimeout(function() {
cleanupNow();
// GOOD: no need to guard the invocation
cb();
}, delay)
}
cleanupLater(function(){console.log("Cleanup done")});

View File

@@ -0,0 +1,5 @@
function setSafeStringProp(o, prop, v) {
// BAD: `v == null` is useless
var safe = v == undefined || v == null? '': v;
o[prop] = safe;
}

View File

@@ -0,0 +1,5 @@
function setSafeStringProp(o, prop, v) {
// GOOD: `v == undefined` handles both `undefined` and `null`
var safe = v == undefined? '': v;
o[prop] = safe;
}

View File

@@ -15,29 +15,7 @@
import javascript
import semmle.javascript.RestrictedLocations
import semmle.javascript.dataflow.Refinements
/**
* Holds if `va` is a defensive truthiness check that may be worth keeping, even if it
* is strictly speaking useless.
*
* We currently recognize three patterns:
*
* - the first `x` in `x || (x = e)`
* - the second `x` in `x = (x || e)`
* - the second `x` in `var x = x || e`
*/
predicate isDefensiveInit(VarAccess va) {
exists (LogOrExpr o, VarRef va2 |
va = o.getLeftOperand().getUnderlyingReference() and va2.getVariable() = va.getVariable() |
exists (AssignExpr assgn | va2 = assgn.getTarget() |
assgn = o.getRightOperand().stripParens() or
o = assgn.getRhs().getUnderlyingValue()
) or
exists (VariableDeclarator vd | va2 = vd.getBindingPattern() |
o = vd.getInit().getUnderlyingValue()
)
)
}
import semmle.javascript.DefensiveProgramming
/**
* Holds if variable `v` looks like a symbolic constant, that is, it is assigned
@@ -95,6 +73,21 @@ predicate isConstantBooleanReturnValue(Expr e) {
isConstantBooleanReturnValue(e.(LogNotExpr).getOperand())
}
private Expr maybeStripLogNot(Expr e) {
result = maybeStripLogNot(e.(LogNotExpr).getOperand()) or
result = e
}
/**
* Holds if `e` is a defensive expression with a fixed outcome.
*/
predicate isConstantDefensive(Expr e) {
exists(DefensiveExpressionTest defensive |
maybeStripLogNot(defensive.asExpr()) = e and
exists(defensive.getTheTestResult())
)
}
/**
* Holds if `e` is an expression that should not be flagged as a useless condition.
*
@@ -109,7 +102,7 @@ predicate isConstantBooleanReturnValue(Expr e) {
predicate whitelist(Expr e) {
isConstant(e) or
isConstant(e.(LogNotExpr).getOperand()) or
isDefensiveInit(e) or
isConstantDefensive(e) or // flagged by js/useless-defensive-code
isInitialParameterUse(e) or
isConstantBooleanReturnValue(e)
}

View File

@@ -0,0 +1,436 @@
/**
* Provides classes for working with defensive programming patterns.
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
/**
* A test in a defensive programming pattern.
*/
abstract class DefensiveExpressionTest extends DataFlow::ValueNode {
/** Gets the unique Boolean value that this test evaluates to, if any. */
abstract boolean getTheTestResult();
}
/**
* INTERNAL: Do not use directly; use `DefensiveExpressionTest` instead.
*/
module Internal {
/**
* A defensive truthiness check that may be worth keeping, even if it
* is strictly speaking useless.
*
* We currently recognize three patterns:
*
* - the first `x` in `x || (x = e)`
* - the second `x` in `x = (x || e)`
* - the second `x` in `var x = x || e`
*/
class DefensiveInit extends DefensiveExpressionTest {
DefensiveInit() {
exists(VarAccess va, LogOrExpr o, VarRef va2 |
va = astNode and
va = o.getLeftOperand().stripParens() and va2.getVariable() = va.getVariable() |
exists(AssignExpr assgn | va2 = assgn.getTarget() |
assgn = o.getRightOperand().stripParens() or
o = assgn.getRhs().stripParens()
)
or
exists(VariableDeclarator vd | va2 = vd.getBindingPattern() | o = vd.getInit().stripParens())
)
}
override boolean getTheTestResult() {
result = analyze().getTheBooleanValue()
}
}
/**
* Gets the inner expression of `e`, with any surrounding parentheses and boolean nots removed.
* `polarity` is true iff the inner expression is nested in an even number of negations.
*/
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
(result = inner and polarity = true)
)
}
/**
* An equality test for `null` and `undefined`.
*
* Examples: `e === undefined` or `typeof e !== undefined`.
*/
private abstract class UndefinedNullTest extends EqualityTest {
/** Gets the unique Boolean value that this test evaluates to, if any. */
abstract boolean getTheTestResult();
/**
* Gets the expression that is tested for being `null` or `undefined`.
*/
abstract Expr getOperand();
}
/**
* A dis- or conjunction that tests if an expression is `null` or `undefined` in either branch.
*
* Example: a branch in `x === null || x === undefined`.
*/
private class CompositeUndefinedNullTestPart extends DefensiveExpressionTest {
UndefinedNullTest test;
boolean polarity;
CompositeUndefinedNullTestPart(){
exists (LogicalBinaryExpr composite, Variable v, Expr op, Expr opOther, UndefinedNullTest testOther |
composite.hasOperands(op, opOther) and
this = op.flow() and
test = stripNotsAndParens(op, polarity) and
testOther = stripNotsAndParens(opOther, _) and
test.getOperand().(VarRef).getVariable() = v and
testOther.getOperand().(VarRef).getVariable() = v
)
}
override boolean getTheTestResult() {
polarity = true and result = test.getTheTestResult()
or
polarity = false and result = test.getTheTestResult().booleanNot()
}
}
/**
* A test for `undefined` or `null` in an if-statement.
*
* Example: `if (x === null) ...`.
*/
private class SanityCheckingUndefinedNullGuard extends DefensiveExpressionTest {
UndefinedNullTest test;
boolean polarity;
SanityCheckingUndefinedNullGuard() {
exists (IfStmt c |
this = c.getCondition().flow() and
test = stripNotsAndParens(c.getCondition(), polarity) and
test.getOperand() instanceof VarRef
)
}
override boolean getTheTestResult() {
polarity = true and result = test.getTheTestResult()
or
polarity = false and result = test.getTheTestResult().booleanNot()
}
}
/**
* Holds if `t` is `null` or `undefined`.
*/
private predicate isNullOrUndefined(InferredType t) {
t = TTNull() or
t = TTUndefined()
}
/**
* Holds if `t` is not `null` or `undefined`.
*/
private predicate isNotNullOrUndefined(InferredType t) {
not isNullOrUndefined(t)
}
/**
* A value comparison for `null` and `undefined`.
*
* Examples: `x === null` or `x != undefined`.
*/
private class NullUndefinedComparison extends UndefinedNullTest {
Expr operand;
InferredType op2type;
NullUndefinedComparison() {
exists (Expr op2 |
hasOperands(operand, op2) |
op2type = TTNull() and SyntacticConstants::isNull(op2)
or
op2type = TTUndefined() and SyntacticConstants::isUndefined(op2)
)
}
override boolean getTheTestResult() {
result = getPolarity() and
(
if this instanceof StrictEqualityTest then
// case: `operand === null` or `operand === undefined`
operand.analyze().getTheType() = op2type
else
// case: `operand == null` or `operand == undefined`
not isNotNullOrUndefined(operand.analyze().getAType())
)
or
result = getPolarity().booleanNot() and
(
if this instanceof StrictEqualityTest then
// case: `operand !== null` or `operand !== undefined`
not operand.analyze().getAType() = op2type
else
// case: `operand != null` or `operand != undefined`
not isNullOrUndefined(operand.analyze().getAType())
)
}
override Expr getOperand() {
result = operand
}
}
/**
* An expression that throws an exception if one of its subexpressions evaluates to `null` or `undefined`.
*
* Examples: `sub.p` or `sub()`.
*/
private class UndefinedNullCrashUse extends Expr {
Expr target;
UndefinedNullCrashUse() {
this.(InvokeExpr).getCallee().getUnderlyingValue() = target
or
this.(PropAccess).getBase().getUnderlyingValue() = target
or
this.(MethodCallExpr).getReceiver().getUnderlyingValue() = target
}
/**
* Gets the subexpression that will cause an exception to be thrown if it is `null` or `undefined`.
*/
Expr getVulnerableSubexpression() {
result = target
}
}
/**
* An expression that throws an exception if one of its subexpressions is not a `function`.
*
* Example: `sub()`.
*/
private class NonFunctionCallCrashUse extends Expr {
Expr target;
NonFunctionCallCrashUse() {
this.(InvokeExpr).getCallee().getUnderlyingValue() = target
}
/**
* Gets the subexpression that will cause an exception to be thrown if it is not a `function`.
*/
Expr getVulnerableSubexpression() {
result = target
}
}
/**
* Gets the first expression that is guarded by `guard`.
*/
private Expr getAGuardedExpr(Expr guard) {
exists(LogicalBinaryExpr op |
op.getLeftOperand() = guard and
op.getRightOperand() = result
)
or
exists(IfStmt c, ExprStmt guardedStmt |
c.getCondition() = guard and
result = guardedStmt.getExpr() |
guardedStmt = c.getAControlledStmt() or
guardedStmt = c.getAControlledStmt().(BlockStmt).getStmt(0)
)
or
exists (ConditionalExpr c |
c.getCondition() = guard |
result = c.getABranch()
)
}
/**
* Holds if `t` is `string`, `number` or `boolean`.
*/
private predicate isStringOrNumOrBool(InferredType t) {
t = TTString() or
t = TTNumber() or
t = TTBoolean()
}
/**
* A defensive expression that tests for `undefined` and `null` using a truthiness test.
*
* Examples: The condition in `if(x) { x.p; }` or `!x || x.m()`.
*/
private class UndefinedNullTruthinessGuard extends DefensiveExpressionTest {
VarRef guardVar;
boolean polarity;
UndefinedNullTruthinessGuard() {
exists (VarRef useVar |
guardVar = stripNotsAndParens(this.asExpr(), polarity) and
guardVar.getVariable() = useVar.getVariable() |
getAGuardedExpr(this.asExpr()).getUnderlyingValue().(UndefinedNullCrashUse).getVulnerableSubexpression() = useVar and
// exclude types whose truthiness depend on the value
not isStringOrNumOrBool(guardVar.analyze().getAType())
)
}
override boolean getTheTestResult() {
exists (boolean testResult |
testResult = guardVar.analyze().getTheBooleanValue() |
if polarity = true then
result = testResult
else
result = testResult.booleanNot()
)
}
}
/**
* A defensive expression that tests for `undefined` and `null`.
*
* Example: the condition in `if(x !== null) { x.p; }`.
*/
private class UndefinedNullTypeGuard extends DefensiveExpressionTest {
UndefinedNullTest test;
boolean polarity;
UndefinedNullTypeGuard() {
exists (Expr guard, VarRef guardVar, VarRef useVar |
this = guard.flow() and
test = stripNotsAndParens(guard, polarity) and
test.getOperand() = guardVar and
guardVar.getVariable() = useVar.getVariable() |
getAGuardedExpr(guard).getUnderlyingValue().(UndefinedNullCrashUse).getVulnerableSubexpression() = useVar
)
}
override boolean getTheTestResult() {
polarity = true and result = test.getTheTestResult()
or
polarity = false and result = test.getTheTestResult().booleanNot()
}
}
/**
* A test for the value of a `typeof` expression.
*
* Example: `typeof x === 'undefined'`.
*/
private class TypeofTest extends EqualityTest {
Expr operand;
TypeofTag tag;
TypeofTest() {
exists (Expr op1, Expr op2 |
hasOperands(op1, op2) |
operand = op1.(TypeofExpr).getOperand() and
op2.mayHaveStringValue(tag)
)
}
boolean getTheTestResult() {
exists (boolean testResult |
testResult = true and operand.analyze().getTheType().getTypeofTag() = tag or
testResult = false and not operand.analyze().getAType().getTypeofTag() = tag |
if getPolarity() = true then
result = testResult
else
result = testResult.booleanNot()
)
}
/**
* Gets the operand used in the `typeof` expression.
*/
Expr getOperand() {
result = operand
}
/**
* Gets the `typeof` tag that is tested.
*/
TypeofTag getTag() {
result = tag
}
}
/**
* A defensive expression that tests if an expression has type `function`.
*
* Example: the condition in `if(typeof x === 'function') x()`.
*/
private class FunctionTypeGuard extends DefensiveExpressionTest {
TypeofTest test;
boolean polarity;
FunctionTypeGuard() {
exists (Expr guard, VarRef guardVar, VarRef useVar |
this = guard.flow() and
test = stripNotsAndParens(guard, polarity) and
test.getOperand() = guardVar and
guardVar.getVariable() = useVar.getVariable() |
getAGuardedExpr(guard).getUnderlyingValue().(NonFunctionCallCrashUse).getVulnerableSubexpression() = useVar
) and
test.getTag() = "function"
}
override boolean getTheTestResult() {
polarity = true and result = test.getTheTestResult()
or
polarity = false and result = test.getTheTestResult().booleanNot()
}
}
/**
* A test for `undefined` using a `typeof` expression.
*
* Example: `typeof x === undefined'.
*/
class TypeofUndefinedTest extends UndefinedNullTest {
TypeofTest test;
TypeofUndefinedTest() {
this = test and
test.getTag() = "undefined"
}
override boolean getTheTestResult() {
result = test.getTheTestResult()
}
override Expr getOperand() {
result = test.getOperand()
}
}
}

View File

@@ -0,0 +1,3 @@
| tst.js:162:9:162:16 | typeof x | This expression is of type string, but it is compared to $@ of type undefined. | tst.js:162:22:162:30 | undefined | 'undefined' |
| tst.js:163:9:163:21 | typeof window | This expression is of type string, but it is compared to $@ of type undefined. | tst.js:163:27:163:35 | undefined | 'undefined' |
| tst.js:165:9:165:16 | typeof x | This expression is of type string, but it is compared to $@ of type undefined. | tst.js:165:22:165:22 | u | variable 'u' |

View File

@@ -0,0 +1 @@
Expressions/HeterogeneousComparison.ql

View File

@@ -0,0 +1,72 @@
| module-environment-detection.js:23:8:23:36 | typeof ... efined' | This guard always evaluates to true. |
| tst2.js:4:12:4:35 | typeof ... efined" | This guard always evaluates to true. |
| tst.js:18:5:18:5 | u | This guard always evaluates to false. |
| tst.js:19:5:19:5 | n | This guard always evaluates to false. |
| tst.js:20:5:20:5 | o | This guard always evaluates to true. |
| tst.js:23:5:23:5 | u | This guard always evaluates to false. |
| tst.js:24:5:24:5 | n | This guard always evaluates to false. |
| tst.js:25:5:25:5 | o | This guard always evaluates to true. |
| tst.js:28:5:28:6 | !u | This guard always evaluates to true. |
| tst.js:29:5:29:6 | !n | This guard always evaluates to true. |
| tst.js:30:5:30:6 | !o | This guard always evaluates to false. |
| tst.js:33:5:33:7 | !!u | This guard always evaluates to false. |
| tst.js:34:5:34:7 | !!n | This guard always evaluates to false. |
| tst.js:35:5:35:7 | !!o | This guard always evaluates to true. |
| tst.js:38:5:38:18 | u != undefined | This guard always evaluates to false. |
| tst.js:39:5:39:18 | n != undefined | This guard always evaluates to false. |
| tst.js:40:5:40:18 | o != undefined | This guard always evaluates to true. |
| tst.js:43:5:43:18 | u == undefined | This guard always evaluates to true. |
| tst.js:44:5:44:18 | n == undefined | This guard always evaluates to true. |
| tst.js:45:5:45:18 | o == undefined | This guard always evaluates to false. |
| tst.js:48:5:48:19 | u === undefined | This guard always evaluates to true. |
| tst.js:49:5:49:19 | n === undefined | This guard always evaluates to false. |
| tst.js:50:5:50:19 | o === undefined | This guard always evaluates to false. |
| tst.js:53:9:53:9 | u | This guard always evaluates to false. |
| tst.js:56:9:56:9 | n | This guard always evaluates to false. |
| tst.js:59:9:59:9 | o | This guard always evaluates to true. |
| tst.js:66:5:66:5 | u | This guard always evaluates to false. |
| tst.js:67:5:67:5 | n | This guard always evaluates to false. |
| tst.js:68:5:68:5 | o | This guard always evaluates to true. |
| tst.js:71:9:71:23 | u !== undefined | This guard always evaluates to false. |
| tst.js:74:9:74:23 | n !== undefined | This guard always evaluates to true. |
| tst.js:77:9:77:23 | o !== undefined | This guard always evaluates to true. |
| tst.js:84:9:84:22 | u == undefined | This guard always evaluates to true. |
| tst.js:85:9:85:22 | n == undefined | This guard always evaluates to true. |
| tst.js:86:9:86:22 | o == undefined | This guard always evaluates to false. |
| tst.js:89:9:89:22 | u != undefined | This guard always evaluates to false. |
| tst.js:90:9:90:22 | n != undefined | This guard always evaluates to false. |
| tst.js:91:9:91:22 | o != undefined | This guard always evaluates to true. |
| tst.js:94:9:94:32 | typeof ... efined" | This guard always evaluates to true. |
| tst.js:95:9:95:32 | typeof ... efined" | This guard always evaluates to false. |
| tst.js:96:9:96:32 | typeof ... efined" | This guard always evaluates to false. |
| tst.js:100:5:100:27 | typeof ... nction" | This guard always evaluates to true. |
| tst.js:101:5:101:27 | typeof ... nction" | This guard always evaluates to false. |
| tst.js:114:5:114:15 | empty_array | This guard always evaluates to true. |
| tst.js:115:5:115:22 | pseudo_empty_array | This guard always evaluates to true. |
| tst.js:116:5:116:19 | non_empty_array | This guard always evaluates to true. |
| tst.js:124:6:124:20 | u !== undefined | This guard always evaluates to false. |
| tst.js:124:25:124:34 | u !== null | This guard always evaluates to true. |
| tst.js:125:5:125:19 | u !== undefined | This guard always evaluates to false. |
| tst.js:125:24:125:33 | u !== null | This guard always evaluates to true. |
| tst.js:127:5:127:18 | u != undefined | This guard always evaluates to false. |
| tst.js:127:23:127:31 | u != null | This guard always evaluates to false. |
| tst.js:127:23:127:31 | u != null | This guard always evaluates to true. |
| tst.js:128:5:128:18 | u == undefined | This guard always evaluates to true. |
| tst.js:128:23:128:31 | u == null | This guard always evaluates to false. |
| tst.js:128:23:128:31 | u == null | This guard always evaluates to true. |
| tst.js:129:5:129:19 | u !== undefined | This guard always evaluates to false. |
| tst.js:129:24:129:33 | u !== null | This guard always evaluates to true. |
| tst.js:130:5:130:22 | !(u === undefined) | This guard always evaluates to false. |
| tst.js:130:27:130:39 | !(u === null) | This guard always evaluates to true. |
| tst.js:131:5:131:19 | u === undefined | This guard always evaluates to true. |
| tst.js:131:24:131:33 | u === null | This guard always evaluates to false. |
| tst.js:132:7:132:21 | u === undefined | This guard always evaluates to true. |
| tst.js:132:26:132:35 | u === null | This guard always evaluates to false. |
| tst.js:133:5:133:22 | !(u === undefined) | This guard always evaluates to false. |
| tst.js:133:27:133:36 | u !== null | This guard always evaluates to true. |
| tst.js:135:5:135:18 | u == undefined | This guard always evaluates to true. |
| tst.js:135:23:135:31 | u == null | This guard always evaluates to true. |
| tst.js:138:24:138:33 | x === null | This guard always evaluates to false. |
| tst.js:140:13:140:22 | x === null | This guard always evaluates to false. |
| tst.js:156:23:156:31 | x != null | This guard always evaluates to true. |
| tst.js:158:13:158:21 | x != null | This guard always evaluates to true. |

View File

@@ -0,0 +1 @@
Expressions/UnneededDefensiveProgramming.ql

View File

@@ -0,0 +1 @@
Statements/UselessConditional.ql

View File

@@ -0,0 +1,11 @@
var Mod1;
(function (Mod1) {
Mod1.p = 42;
})(Mod1 || (Mod1 = {}));
(function(){
var Mod2;
(function (Mod2) {
Mod2.p = 42;
})(Mod2 || (Mod2 = {})); // NOT OK
});

View File

@@ -0,0 +1,24 @@
var _ = (function() {
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
}
return {
define: function(name, factory) {
}
};
})(this);
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = emmet;
}
exports.emmet = emmet;
}
(function(){
var module;
if(typeof module === 'undefined'); // NOT OK
});

View File

@@ -0,0 +1,174 @@
(function(){
var v;
var u = undefined;
var n = null;
var o = {};
var x = functionWithUnknownReturnValue();
var u_ = u;
var n_ = n;
var o_ = o;
var x_ = x;
u_ = u_ || e; // NOT OK
n_ = n_ || e; // NOT OK
o_ = o_ || e; // NOT OK
x_ = x_ || e;
u && u.p; // NOT OK
n && n.p; // NOT OK
o && o.p; // NOT OK
x && x.p;
u && u(); // NOT OK
n && n(); // NOT OK
o && o(); // NOT OK
x && x();
!u || u.p; // NOT OK
!n || n.p; // NOT OK
!o || o.p; // NOT OK
!x || x.p;
!!u && u.p; // NOT OK
!!n && n.p; // NOT OK
!!o && o.p; // NOT OK
!!x && x.p;
u != undefined && u.p; // NOT OK
n != undefined && n.p; // NOT OK
o != undefined && o.p; // NOT OK
x != undefined && x.p;
u == undefined || u.p; // NOT OK
n == undefined || n.p; // NOT OK
o == undefined || o.p; // NOT OK
x == undefined || x.p;
u === undefined || u.p; // NOT OK
n === undefined || n.p; // NOT OK
o === undefined || o.p; // NOT OK
x === undefined || x.p;
if (u) { // NOT OK
u.p;
}
if (n) { // NOT OK
n.p;
}
if (o) { // NOT OK
o.p;
}
if (x) {
x.p;
}
u? u():_; // NOT OK
n? n(): _; // NOT OK
o? o(): _; // NOT OK
x? x(): _;
if (u !== undefined) { // NOT OK
u.p;
}
if (n !== undefined) { // NOT OK
n.p;
}
if (o !== undefined) { // NOT OK
o.p;
}
if (x !== undefined) {
x.p;
}
if (u == undefined){} // NOT OK
if (n == undefined){} // NOT OK
if (o == undefined){} // NOT OK
if (x == undefined){}
if (u != undefined){} // NOT OK
if (n != undefined){} // NOT OK
if (o != undefined){} // NOT OK
if (x != undefined){}
if (typeof u === "undefined"){} // NOT OK
if (typeof n === "undefined"){} // NOT OK
if (typeof o === "undefined"){} // NOT OK
if (typeof x === "undefined"){}
function f() { }
typeof f === "function" && f(); // NOT OK
typeof u === "function" && u(); // NOT OK
typeof x === "function" && x();
var empty_array = [];
var pseudo_empty_array = [''];
var non_empty_array = ['foo'];
var empty_string = "";
var non_empty_string = "foo";
var zero = 0;
var neg = -1;
var _true = true;
var _false = false;
empty_array && empty_array.pop(); // NOT OK
pseudo_empty_array && pseudo_empty_array.pop(); // NOT OK
non_empty_array && non_empty_array.pop(); // NOT OK
empty_string && empty_string.charAt(0);
non_empty_string && non_empty_string.charAt(0);
zero && zero();
neg && neg();
_true && _true();
_false && _false();
(u !== undefined && u !== null) && u.p; // NOT OK
u !== undefined && u !== null && u.p; // NOT OK
u != undefined && u != null; // NOT OK
u == undefined || u == null; // NOT OK
u !== undefined && u !== null; // NOT OK
!(u === undefined) && !(u === null); // NOT OK
u === undefined || u === null; // NOT OK
!(u === undefined || u === null); // NOT OK
!(u === undefined) && u !== null; // NOT OK
u !== undefined && n !== null;
u == undefined && u == null; // NOT OK
x == undefined && x == null;
x === undefined && x === null; // NOT OK
if (x === undefined) {
if (x === null) { // NOT OK
}
}
x !== undefined && x !== null;
if (x !== undefined) {
if (x !== null) {
}
}
x == undefined && x == null;
if (x == undefined) {
if (x == null) {
}
}
x != undefined && x != null; // NOT OK
if (x != undefined) {
if (x != null) { // NOT OK
}
}
if (typeof x !== undefined);
if (typeof window !== undefined);
if (typeof x !== x);
if (typeof x !== u); // NOT OK
if (typeof window !== "undefined");
if (typeof module !== "undefined");
if (typeof global !== "undefined");
if (typeof window !== "undefined" && window.document);
if (typeof module !== "undefined" && module.exports);
if (typeof global !== "undefined" && global.process);
});

View File

@@ -0,0 +1,10 @@
(function(){
var v;
(function(){
if(typeof v === "undefined"){ // NOT OK
v = 42;
}
for(var v in x){
}
});
});