diff --git a/javascript/ql/src/Statements/UselessRangeCheck.qhelp b/javascript/ql/src/Statements/UselessRangeCheck.qhelp new file mode 100644 index 00000000000..74a6168dd72 --- /dev/null +++ b/javascript/ql/src/Statements/UselessRangeCheck.qhelp @@ -0,0 +1,47 @@ + + + +

+If a condition always evaluates to true or always evaluates to false, this often indicates +incomplete code or a latent bug and should be examined carefully. +

+ +
+ + +

+Examine the surrounding code to determine why the condition is useless. If it is no +longer needed, remove it. +

+ +

+If the check is needed to guard against NaN values, insert a comment explaning the possibility of NaN. +

+ +
+ + +

+The following example finds the index of an element in a given slice of the array: +

+ + + +

+The condition i < end at the end is always false, however. The code can be clarified if the +redundant condition is removed: +

+ + + +
+ + + +
  • Mozilla Developer Network: Truthy, +Falsy.
  • + +
    +
    diff --git a/javascript/ql/src/Statements/UselessRangeCheck.ql b/javascript/ql/src/Statements/UselessRangeCheck.ql new file mode 100644 index 00000000000..f737110442f --- /dev/null +++ b/javascript/ql/src/Statements/UselessRangeCheck.ql @@ -0,0 +1,28 @@ +/** + * @name Useless range check + * @description If a range check always fails or always succeeds it is indicative of a bug. + * @kind problem + * @problem.severity warning + * @id js/useless-range-check + * @tags correctness + * @precision high + */ + +import javascript + +/** + * Gets the guard node with the opposite outcome of `guard`. + */ +ConditionGuardNode getOppositeGuard(ConditionGuardNode guard) { + result.getTest() = guard.getTest() and + result.getOutcome() = guard.getOutcome().booleanNot() +} + +from ConditionGuardNode guard +where RangeAnalysis::isContradictoryGuardNode(guard) + + // Do not report conditions that themselves are unreachable because of + // a prior contradiction. + and not RangeAnalysis::isContradictoryGuardNode(getOppositeGuard(guard)) + +select guard.getTest(), "The condition '" + guard.getTest() + "' is always " + guard.getOutcome().booleanNot() diff --git a/javascript/ql/src/Statements/examples/UselessRangeCheck.js b/javascript/ql/src/Statements/examples/UselessRangeCheck.js new file mode 100644 index 00000000000..53496ce2e4e --- /dev/null +++ b/javascript/ql/src/Statements/examples/UselessRangeCheck.js @@ -0,0 +1,12 @@ +function findValue(values, x, start, end) { + let i; + for (i = start; i < end; ++i) { + if (values[i] === x) { + return i; + } + } + if (i < end) { + return i; + } + return -1; +} diff --git a/javascript/ql/src/Statements/examples/UselessRangeCheckGood.js b/javascript/ql/src/Statements/examples/UselessRangeCheckGood.js new file mode 100644 index 00000000000..6f86622c99b --- /dev/null +++ b/javascript/ql/src/Statements/examples/UselessRangeCheckGood.js @@ -0,0 +1,8 @@ +function findValue(values, x, start, end) { + for (let i = start; i < end; ++i) { + if (values[i] === x) { + return i; + } + } + return -1; +} diff --git a/javascript/ql/test/query-tests/Statements/UselessRangeCheck/UselessRangeCheck.expected b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/UselessRangeCheck.expected new file mode 100644 index 00000000000..bdf5055e767 --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/UselessRangeCheck.expected @@ -0,0 +1 @@ +| example.js:8:7:8:13 | i < end | The condition 'i < end' is always false | diff --git a/javascript/ql/test/query-tests/Statements/UselessRangeCheck/UselessRangeCheck.qlref b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/UselessRangeCheck.qlref new file mode 100644 index 00000000000..f5d7a1ee7a4 --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/UselessRangeCheck.qlref @@ -0,0 +1 @@ +Statements/UselessRangeCheck.ql diff --git a/javascript/ql/test/query-tests/Statements/UselessRangeCheck/example.js b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/example.js new file mode 100644 index 00000000000..53496ce2e4e --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/example.js @@ -0,0 +1,12 @@ +function findValue(values, x, start, end) { + let i; + for (i = start; i < end; ++i) { + if (values[i] === x) { + return i; + } + } + if (i < end) { + return i; + } + return -1; +} diff --git a/javascript/ql/test/query-tests/Statements/UselessRangeCheck/exampleGood.js b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/exampleGood.js new file mode 100644 index 00000000000..6f86622c99b --- /dev/null +++ b/javascript/ql/test/query-tests/Statements/UselessRangeCheck/exampleGood.js @@ -0,0 +1,8 @@ +function findValue(values, x, start, end) { + for (let i = start; i < end; ++i) { + if (values[i] === x) { + return i; + } + } + return -1; +}