Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6cafe22

Browse files
authored
Merge pull request #1013 from asger-semmle/closure-string-ops
Approved by esben-semmle
2 parents a6f3305 + 8dfec58 commit 6cafe22

7 files changed

Lines changed: 55 additions & 27 deletions

File tree

javascript/ql/src/semmle/javascript/StringOps.qll

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,14 +112,18 @@ module StringOps {
112112
}
113113

114114
/**
115-
* A call of form `_.startsWith(A, B)` or `ramda.startsWith(A, B)`.
115+
* A call of form `_.startsWith(A, B)` or `ramda.startsWith(A, B)` or `goog.string.startsWith(A, B)`.
116116
*/
117117
private class StartsWith_Library extends Range, DataFlow::CallNode {
118118
StartsWith_Library() {
119119
getNumArgument() = 2 and
120120
exists(DataFlow::SourceNode callee | this = callee.getACall() |
121121
callee = LodashUnderscore::member("startsWith") or
122-
callee = DataFlow::moduleMember("ramda", "startsWith")
122+
callee = DataFlow::moduleMember("ramda", "startsWith") or
123+
exists(string name |
124+
callee = Closure::moduleImport("goog.string." + name) and
125+
(name = "startsWith" or name = "caseInsensitiveStartsWith")
126+
)
123127
)
124128
}
125129

@@ -250,6 +254,9 @@ module StringOps {
250254
exists(string name |
251255
this = LodashUnderscore::member(name).getACall() and
252256
(name = "includes" or name = "include" or name = "contains")
257+
or
258+
this = Closure::moduleImport("goog.string." + name).getACall() and
259+
(name = "contains" or name = "caseInsensitiveContains")
253260
)
254261
}
255262

@@ -416,7 +423,11 @@ module StringOps {
416423
getNumArgument() = 2 and
417424
exists(DataFlow::SourceNode callee | this = callee.getACall() |
418425
callee = LodashUnderscore::member("endsWith") or
419-
callee = DataFlow::moduleMember("ramda", "endsWith")
426+
callee = DataFlow::moduleMember("ramda", "endsWith") or
427+
exists(string name |
428+
callee = Closure::moduleImport("goog.string." + name) and
429+
(name = "endsWith" or name = "caseInsensitiveEndsWith")
430+
)
420431
)
421432
}
422433

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
| tst.js:5:7:5:19 | A.endsWith(B) | tst.js:5:7:5:7 | A | tst.js:5:18:5:18 | B | true |
2-
| tst.js:6:7:6:22 | _.endsWith(A, B) | tst.js:6:18:6:18 | A | tst.js:6:21:6:21 | B | true |
3-
| tst.js:7:7:7:22 | R.endsWith(A, B) | tst.js:7:18:7:18 | A | tst.js:7:21:7:21 | B | true |
1+
| tst.js:6:7:6:19 | A.endsWith(B) | tst.js:6:7:6:7 | A | tst.js:6:18:6:18 | B | true |
2+
| tst.js:7:7:7:22 | _.endsWith(A, B) | tst.js:7:18:7:18 | A | tst.js:7:21:7:21 | B | true |
3+
| tst.js:8:7:8:22 | R.endsWith(A, B) | tst.js:8:18:8:18 | A | tst.js:8:21:8:21 | B | true |
4+
| tst.js:9:7:9:28 | strings ... h(A, B) | tst.js:9:24:9:24 | A | tst.js:9:27:9:27 | B | true |
5+
| tst.js:10:7:10:43 | strings ... h(A, B) | tst.js:10:39:10:39 | A | tst.js:10:42:10:42 | B | true |
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import * as _ from 'underscore';
22
import * as R from 'ramda';
3+
let strings = goog.require('goog.string');
34

45
function test() {
56
if (A.endsWith(B)) {}
67
if (_.endsWith(A, B)) {}
78
if (R.endsWith(A, B)) {}
9+
if (strings.endsWith(A, B)) {}
10+
if (strings.caseInsensitiveEndsWith(A, B)) {}
811
}
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
| tst.js:4:7:4:19 | A.includes(B) | tst.js:4:7:4:7 | A | tst.js:4:18:4:18 | B | true |
2-
| tst.js:5:7:5:22 | _.includes(A, B) | tst.js:5:18:5:18 | A | tst.js:5:21:5:21 | B | true |
3-
| tst.js:6:7:6:25 | A.indexOf(B) !== -1 | tst.js:6:7:6:7 | A | tst.js:6:17:6:17 | B | true |
4-
| tst.js:7:7:7:23 | A.indexOf(B) >= 0 | tst.js:7:7:7:7 | A | tst.js:7:17:7:17 | B | true |
5-
| tst.js:8:7:8:19 | ~A.indexOf(B) | tst.js:8:8:8:8 | A | tst.js:8:18:8:18 | B | true |
6-
| tst.js:11:7:11:25 | A.indexOf(B) === -1 | tst.js:11:7:11:7 | A | tst.js:11:17:11:17 | B | false |
7-
| tst.js:12:7:12:22 | A.indexOf(B) < 0 | tst.js:12:7:12:7 | A | tst.js:12:17:12:17 | B | false |
1+
| tst.js:5:7:5:19 | A.includes(B) | tst.js:5:7:5:7 | A | tst.js:5:18:5:18 | B | true |
2+
| tst.js:6:7:6:22 | _.includes(A, B) | tst.js:6:18:6:18 | A | tst.js:6:21:6:21 | B | true |
3+
| tst.js:7:7:7:25 | A.indexOf(B) !== -1 | tst.js:7:7:7:7 | A | tst.js:7:17:7:17 | B | true |
4+
| tst.js:8:7:8:23 | A.indexOf(B) >= 0 | tst.js:8:7:8:7 | A | tst.js:8:17:8:17 | B | true |
5+
| tst.js:9:7:9:19 | ~A.indexOf(B) | tst.js:9:8:9:8 | A | tst.js:9:18:9:18 | B | true |
6+
| tst.js:12:7:12:25 | A.indexOf(B) === -1 | tst.js:12:7:12:7 | A | tst.js:12:17:12:17 | B | false |
7+
| tst.js:13:7:13:22 | A.indexOf(B) < 0 | tst.js:13:7:13:7 | A | tst.js:13:17:13:17 | B | false |
8+
| tst.js:20:7:20:28 | strings ... s(A, B) | tst.js:20:24:20:24 | A | tst.js:20:27:20:27 | B | true |
9+
| tst.js:21:7:21:43 | strings ... s(A, B) | tst.js:21:39:21:39 | A | tst.js:21:42:21:42 | B | true |

javascript/ql/test/library-tests/StringOps/Includes/tst.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as _ from 'lodash';
2+
let strings = goog.require('goog.string');
23

34
function test() {
45
if (A.includes(B)) {}
@@ -15,4 +16,7 @@ function test() {
1516
if (A.indexOf(B) === 0) {}
1617
if (A.indexOf(B) !== 0) {}
1718
if (A.indexOf(B) > 0) {}
19+
20+
if (strings.contains(A, B)) {}
21+
if (strings.caseInsensitiveContains(A, B)) {}
1822
}
Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
| tst.js:5:9:5:23 | A.startsWith(B) | tst.js:5:9:5:9 | A | tst.js:5:22:5:22 | B | true |
2-
| tst.js:6:9:6:26 | _.startsWith(A, B) | tst.js:6:22:6:22 | A | tst.js:6:25:6:25 | B | true |
3-
| tst.js:7:9:7:26 | R.startsWith(A, B) | tst.js:7:22:7:22 | A | tst.js:7:25:7:25 | B | true |
4-
| tst.js:8:9:8:26 | A.indexOf(B) === 0 | tst.js:8:9:8:9 | A | tst.js:8:19:8:19 | B | true |
5-
| tst.js:9:9:9:26 | A.indexOf(B) !== 0 | tst.js:9:9:9:9 | A | tst.js:9:19:9:19 | B | false |
6-
| tst.js:10:9:10:26 | 0 !== A.indexOf(B) | tst.js:10:15:10:15 | A | tst.js:10:25:10:25 | B | false |
7-
| tst.js:11:9:11:25 | 0 != A.indexOf(B) | tst.js:11:14:11:14 | A | tst.js:11:24:11:24 | B | false |
8-
| tst.js:12:9:12:20 | A.indexOf(B) | tst.js:12:9:12:9 | A | tst.js:12:19:12:19 | B | false |
9-
| tst.js:13:10:13:21 | A.indexOf(B) | tst.js:13:10:13:10 | A | tst.js:13:20:13:20 | B | false |
10-
| tst.js:14:11:14:22 | A.indexOf(B) | tst.js:14:11:14:11 | A | tst.js:14:21:14:21 | B | false |
11-
| tst.js:15:9:15:38 | A.subst ... ) === B | tst.js:15:9:15:9 | A | tst.js:15:38:15:38 | B | true |
12-
| tst.js:16:9:16:38 | A.subst ... ) !== B | tst.js:16:9:16:9 | A | tst.js:16:38:16:38 | B | false |
13-
| tst.js:17:9:17:35 | A.subst ... ) === B | tst.js:17:9:17:9 | A | tst.js:17:35:17:35 | B | true |
14-
| tst.js:18:9:18:36 | A.subst ... "web/" | tst.js:18:9:18:9 | A | tst.js:18:31:18:36 | "web/" | true |
1+
| tst.js:6:9:6:23 | A.startsWith(B) | tst.js:6:9:6:9 | A | tst.js:6:22:6:22 | B | true |
2+
| tst.js:7:9:7:26 | _.startsWith(A, B) | tst.js:7:22:7:22 | A | tst.js:7:25:7:25 | B | true |
3+
| tst.js:8:9:8:26 | R.startsWith(A, B) | tst.js:8:22:8:22 | A | tst.js:8:25:8:25 | B | true |
4+
| tst.js:9:9:9:26 | A.indexOf(B) === 0 | tst.js:9:9:9:9 | A | tst.js:9:19:9:19 | B | true |
5+
| tst.js:10:9:10:26 | A.indexOf(B) !== 0 | tst.js:10:9:10:9 | A | tst.js:10:19:10:19 | B | false |
6+
| tst.js:11:9:11:26 | 0 !== A.indexOf(B) | tst.js:11:15:11:15 | A | tst.js:11:25:11:25 | B | false |
7+
| tst.js:12:9:12:25 | 0 != A.indexOf(B) | tst.js:12:14:12:14 | A | tst.js:12:24:12:24 | B | false |
8+
| tst.js:13:9:13:20 | A.indexOf(B) | tst.js:13:9:13:9 | A | tst.js:13:19:13:19 | B | false |
9+
| tst.js:14:10:14:21 | A.indexOf(B) | tst.js:14:10:14:10 | A | tst.js:14:20:14:20 | B | false |
10+
| tst.js:15:11:15:22 | A.indexOf(B) | tst.js:15:11:15:11 | A | tst.js:15:21:15:21 | B | false |
11+
| tst.js:16:9:16:38 | A.subst ... ) === B | tst.js:16:9:16:9 | A | tst.js:16:38:16:38 | B | true |
12+
| tst.js:17:9:17:38 | A.subst ... ) !== B | tst.js:17:9:17:9 | A | tst.js:17:38:17:38 | B | false |
13+
| tst.js:18:9:18:35 | A.subst ... ) === B | tst.js:18:9:18:9 | A | tst.js:18:35:18:35 | B | true |
14+
| tst.js:19:9:19:36 | A.subst ... "web/" | tst.js:19:9:19:9 | A | tst.js:19:31:19:36 | "web/" | true |
15+
| tst.js:32:9:32:32 | strings ... h(A, B) | tst.js:32:28:32:28 | A | tst.js:32:31:32:31 | B | true |
16+
| tst.js:33:9:33:47 | strings ... h(A, B) | tst.js:33:43:33:43 | A | tst.js:33:46:33:46 | B | true |

javascript/ql/test/library-tests/StringOps/StartsWith/tst.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as _ from 'lodash';
22
import * as R from 'ramda';
3+
let strings = goog.require('goog.string');
34

45
function f(A, B) {
56
if (A.startsWith(B)) {}
@@ -27,4 +28,7 @@ function f(A, B) {
2728
if (A.indexOf(B, 2)) {}
2829
if (~A.indexOf(B)) {} // checks for existence, not startsWith
2930
if (A.substring(B.length) === 0) {}
31+
32+
if (strings.startsWith(A, B)) {}
33+
if (strings.caseInsensitiveStartsWith(A, B)) {}
3034
}

0 commit comments

Comments
 (0)