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

Skip to content

Commit f9951f6

Browse files
committed
JS: add simple variants of StringOps::EndsWith
1 parent b662699 commit f9951f6

4 files changed

Lines changed: 80 additions & 2 deletions

File tree

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

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,14 @@ module StringOps {
188188
}
189189

190190
/**
191-
* A call to `_.includes`, assumed to operate on strings.
191+
* A call to `_.includes` or similar, assumed to operate on strings.
192192
*/
193193
private class Includes_Library extends Includes, DataFlow::CallNode {
194194
Includes_Library() {
195-
this = LodashUnderscore::member("includes").getACall()
195+
exists (string name |
196+
this = LodashUnderscore::member(name).getACall() and
197+
(name = "includes" or name = "include" or name = "contains")
198+
)
196199
}
197200

198201
override DataFlow::Node getBaseString() {
@@ -299,4 +302,66 @@ module StringOps {
299302
}
300303
}
301304

305+
/**
306+
* An expression that appears to be part of an `endsWith`-check, that is,
307+
* roughly equivalent to `A.endsWith(B)` or `!A.endsWith(B)`.
308+
*/
309+
abstract class EndsWith extends DataFlow::Node {
310+
/**
311+
* Gets the `A` in `A.startsWith(B)`.
312+
*/
313+
abstract DataFlow::Node getBaseString();
314+
315+
/**
316+
* Gets the `B` in `A.startsWith(B)`.
317+
*/
318+
abstract DataFlow::Node getSubstring();
319+
320+
/**
321+
* Gets the polarity if the check.
322+
*
323+
* If the polarity is `false` the check returns `true` if the string does not start
324+
* with the given substring.
325+
*/
326+
boolean getPolarity() { result = true }
327+
}
328+
329+
/**
330+
* A call of form `A.endsWith(B)`.
331+
*/
332+
private class EndsWith_Native extends EndsWith, DataFlow::MethodCallNode {
333+
EndsWith_Native() {
334+
getMethodName() = "endsWith" and
335+
getNumArgument() = 1
336+
}
337+
338+
override DataFlow::Node getBaseString() {
339+
result = getReceiver()
340+
}
341+
342+
override DataFlow::Node getSubstring() {
343+
result = getArgument(0)
344+
}
345+
}
346+
347+
/**
348+
* A call of form `_.endsWith(A, B)` or `ramda.endsWith(A, B)`.
349+
*/
350+
private class EndsWith_Library extends StartsWith, DataFlow::CallNode {
351+
EndsWith_Library() {
352+
getNumArgument() = 2 and
353+
exists (DataFlow::SourceNode callee | this = callee.getACall() |
354+
callee = LodashUnderscore::member("endsWith") or
355+
callee = DataFlow::moduleMember("ramda", "endsWith")
356+
)
357+
}
358+
359+
override DataFlow::Node getBaseString() {
360+
result = getArgument(0)
361+
}
362+
363+
override DataFlow::Node getSubstring() {
364+
result = getArgument(1)
365+
}
366+
}
302367
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
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 |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import javascript
2+
3+
from StringOps::EndsWith endsWith
4+
select endsWith, endsWith.getBaseString(), endsWith.getSubstring(), endsWith.getPolarity()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as _ from 'underscore';
2+
import * as R from 'ramda';
3+
4+
function test() {
5+
if (A.endsWith(B)) {}
6+
if (_.endsWith(A, B)) {}
7+
if (R.endsWith(A, B)) {}
8+
}

0 commit comments

Comments
 (0)