Skip to content

Commit a5aee9e

Browse files
authored
Merge pull request #833 from esben-semmle/js/sharpen-cond
Approved by xiemaisi
2 parents 1d28c63 + 239fe6e commit a5aee9e

File tree

4 files changed

+50
-8
lines changed

4 files changed

+50
-8
lines changed

change-notes/1.20/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
| Useless assignment to property. | Fewer false-positive results | This rule now treats assignments with complex right-hand sides correctly. |
3838
| Unsafe dynamic method access | Fewer false-positive results | This rule no longer flags concatenated strings as unsafe method names. |
3939
| Unvalidated dynamic method call | More true-positive results | This rule now flags concatenated strings as unvalidated method names in more cases. |
40+
| Useless conditional | More true-positive results | This rule now flags additional uses of function call values. |
4041

4142
## Changes to QL libraries
4243

javascript/ql/src/Statements/UselessConditional.ql

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,24 @@ predicate isInitialParameterUse(Expr e) {
6565
}
6666

6767
/**
68-
* Holds if `e` directly uses the returned value from a function call that returns a constant boolean value.
68+
* Holds if `e` directly uses the returned value from functions that return constant boolean values.
6969
*/
7070
predicate isConstantBooleanReturnValue(Expr e) {
7171
// unlike `SourceNode.flowsTo` this will not include uses we have refinement information for
72-
exists(DataFlow::CallNode call | exists(call.analyze().getTheBooleanValue()) |
73-
e = call.asExpr()
74-
or
75-
// also support return values that are assigned to variables
76-
exists(SsaExplicitDefinition ssa |
77-
ssa.getDef().getSource() = call.asExpr() and
78-
ssa.getVariable().getAUse() = e
72+
exists(string b | (b = "true" or b = "false") |
73+
forex(DataFlow::CallNode call, Expr ret |
74+
ret = call.getACallee().getAReturnedExpr() and
75+
(
76+
e = call.asExpr()
77+
or
78+
// also support return values that are assigned to variables
79+
exists(SsaExplicitDefinition ssa |
80+
ssa.getDef().getSource() = call.asExpr() and
81+
ssa.getVariable().getAUse() = e
82+
)
83+
)
84+
|
85+
ret.(BooleanLiteral).getValue() = b
7986
)
8087
)
8188
or

javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
| UselessConditional.js:102:19:102:19 | x | This use of variable 'x' always evaluates to false. |
2323
| UselessConditional.js:103:23:103:23 | x | This use of variable 'x' always evaluates to false. |
2424
| UselessConditional.js:109:15:109:16 | {} | This expression always evaluates to true. |
25+
| UselessConditional.js:129:6:129:24 | constantUndefined() | This call to constantUndefined always evaluates to false. |
26+
| UselessConditional.js:135:6:135:32 | constan ... ined1() | This call to constantFalseOrUndefined1 always evaluates to false. |
27+
| UselessConditional.js:139:6:139:32 | constan ... ined2() | This call to constantFalseOrUndefined2 always evaluates to false. |
2528
| UselessConditionalGood.js:58:12:58:13 | x2 | This use of variable 'x2' always evaluates to false. |
2629
| UselessConditionalGood.js:69:12:69:13 | xy | This use of variable 'xy' always evaluates to false. |
2730
| UselessConditionalGood.js:85:12:85:13 | xy | This use of variable 'xy' always evaluates to false. |

javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,35 @@ async function awaitFlow(){
109109
if ((x && {}) || y) {} // NOT OK
110110
});
111111

112+
(function(){
113+
function constantFalse1() {
114+
return false;
115+
}
116+
if (constantFalse1()) // OK
117+
return;
118+
119+
function constantFalse2() {
120+
return false;
121+
}
122+
let constantFalse = unknown? constantFalse1 : constantFalse2;
123+
if (constantFalse2()) // OK
124+
return;
125+
126+
function constantUndefined() {
127+
return undefined;
128+
}
129+
if (constantUndefined()) // NOT OK
130+
return;
131+
132+
function constantFalseOrUndefined1() {
133+
return unknown? false: undefined;
134+
}
135+
if (constantFalseOrUndefined1()) // NOT OK
136+
return;
137+
138+
let constantFalseOrUndefined2 = unknown? constantFalse1 : constantUndefined;
139+
if (constantFalseOrUndefined2()) // NOT OK
140+
return;
141+
142+
});
112143
// semmle-extractor-options: --experimental

0 commit comments

Comments
 (0)