@@ -185,162 +185,15 @@ module StringOps {
185185 /**
186186 * A expression that is equivalent to `A.includes(B)` or `!A.includes(B)`.
187187 *
188- * Note that this also includes calls to the array method named `includes`.
188+ * Note that this class is equivalent to `InclusionTest`, which also matches
189+ * inclusion tests on array objects.
189190 */
190- class Includes extends DataFlow:: Node {
191- Includes:: Range range ;
192-
193- Includes ( ) { this = range }
194-
191+ class Includes extends InclusionTest {
195192 /** Gets the `A` in `A.includes(B)`. */
196- DataFlow:: Node getBaseString ( ) { result = range . getBaseString ( ) }
193+ DataFlow:: Node getBaseString ( ) { result = getContainerNode ( ) }
197194
198195 /** Gets the `B` in `A.includes(B)`. */
199- DataFlow:: Node getSubstring ( ) { result = range .getSubstring ( ) }
200-
201- /**
202- * Gets the polarity of the check.
203- *
204- * If the polarity is `false` the check returns `true` if the string does not contain
205- * the given substring.
206- */
207- boolean getPolarity ( ) { result = range .getPolarity ( ) }
208- }
209-
210- module Includes {
211- /**
212- * A expression that is equivalent to `A.includes(B)` or `!A.includes(B)`.
213- *
214- * Note that this also includes calls to the array method named `includes`.
215- */
216- abstract class Range extends DataFlow:: Node {
217- /** Gets the `A` in `A.includes(B)`. */
218- abstract DataFlow:: Node getBaseString ( ) ;
219-
220- /** Gets the `B` in `A.includes(B)`. */
221- abstract DataFlow:: Node getSubstring ( ) ;
222-
223- /**
224- * Gets the polarity of the check.
225- *
226- * If the polarity is `false` the check returns `true` if the string does not contain
227- * the given substring.
228- */
229- boolean getPolarity ( ) { result = true }
230- }
231-
232- /**
233- * A call to a method named `includes`, assumed to refer to `String.prototype.includes`.
234- */
235- private class Includes_Native extends Range , DataFlow:: MethodCallNode {
236- Includes_Native ( ) {
237- getMethodName ( ) = "includes" and
238- getNumArgument ( ) = 1
239- }
240-
241- override DataFlow:: Node getBaseString ( ) { result = getReceiver ( ) }
242-
243- override DataFlow:: Node getSubstring ( ) { result = getArgument ( 0 ) }
244- }
245-
246- /**
247- * A call to `_.includes` or similar, assumed to operate on strings.
248- */
249- private class Includes_Library extends Range , DataFlow:: CallNode {
250- Includes_Library ( ) {
251- exists ( string name |
252- this = LodashUnderscore:: member ( name ) .getACall ( ) and
253- ( name = "includes" or name = "include" or name = "contains" )
254- or
255- this = Closure:: moduleImport ( "goog.string." + name ) .getACall ( ) and
256- ( name = "contains" or name = "caseInsensitiveContains" )
257- )
258- }
259-
260- override DataFlow:: Node getBaseString ( ) { result = getArgument ( 0 ) }
261-
262- override DataFlow:: Node getSubstring ( ) { result = getArgument ( 1 ) }
263- }
264-
265- /**
266- * A check of form `A.indexOf(B) !== -1` or similar.
267- */
268- private class Includes_IndexOfEquals extends Range , DataFlow:: ValueNode {
269- MethodCallExpr indexOf ;
270- override EqualityTest astNode ;
271-
272- Includes_IndexOfEquals ( ) {
273- exists ( Expr index | astNode .hasOperands ( indexOf , index ) |
274- // one operand is of the form `whitelist.indexOf(x)`
275- indexOf .getMethodName ( ) = "indexOf" and
276- // and the other one is -1
277- index .getIntValue ( ) = - 1
278- )
279- }
280-
281- override DataFlow:: Node getBaseString ( ) { result = indexOf .getReceiver ( ) .flow ( ) }
282-
283- override DataFlow:: Node getSubstring ( ) { result = indexOf .getArgument ( 0 ) .flow ( ) }
284-
285- override boolean getPolarity ( ) { result = astNode .getPolarity ( ) .booleanNot ( ) }
286- }
287-
288- /**
289- * A check of form `A.indexOf(B) >= 0` or similar.
290- */
291- private class Includes_IndexOfRelational extends Range , DataFlow:: ValueNode {
292- MethodCallExpr indexOf ;
293- override RelationalComparison astNode ;
294- boolean polarity ;
295-
296- Includes_IndexOfRelational ( ) {
297- exists ( Expr lesser , Expr greater |
298- astNode .getLesserOperand ( ) = lesser and
299- astNode .getGreaterOperand ( ) = greater and
300- indexOf .getMethodName ( ) = "indexOf" and
301- indexOf .getNumArgument ( ) = 1
302- |
303- polarity = true and
304- greater = indexOf and
305- (
306- lesser .getIntValue ( ) = 0 and astNode .isInclusive ( )
307- or
308- lesser .getIntValue ( ) = - 1 and not astNode .isInclusive ( )
309- )
310- or
311- polarity = false and
312- lesser = indexOf and
313- (
314- greater .getIntValue ( ) = - 1 and astNode .isInclusive ( )
315- or
316- greater .getIntValue ( ) = 0 and not astNode .isInclusive ( )
317- )
318- )
319- }
320-
321- override DataFlow:: Node getBaseString ( ) { result = indexOf .getReceiver ( ) .flow ( ) }
322-
323- override DataFlow:: Node getSubstring ( ) { result = indexOf .getArgument ( 0 ) .flow ( ) }
324-
325- override boolean getPolarity ( ) { result = polarity }
326- }
327-
328- /**
329- * An expression of form `~A.indexOf(B)` which, when coerced to a boolean, is equivalent to `A.includes(B)`.
330- */
331- private class Includes_IndexOfBitwise extends Range , DataFlow:: ValueNode {
332- MethodCallExpr indexOf ;
333- override BitNotExpr astNode ;
334-
335- Includes_IndexOfBitwise ( ) {
336- astNode .getOperand ( ) = indexOf and
337- indexOf .getMethodName ( ) = "indexOf"
338- }
339-
340- override DataFlow:: Node getBaseString ( ) { result = indexOf .getReceiver ( ) .flow ( ) }
341-
342- override DataFlow:: Node getSubstring ( ) { result = indexOf .getArgument ( 0 ) .flow ( ) }
343- }
196+ DataFlow:: Node getSubstring ( ) { result = getContainedNode ( ) }
344197 }
345198
346199 /**
0 commit comments