@@ -305,7 +305,143 @@ module ActiveSupport {
305305 preservesValue = true
306306 }
307307 }
308- // TODO: index_with, pick, pluck (they require Hash dataflow)
308+
309+ private class IndexWithSummary extends SimpleSummarizedCallable {
310+ IndexWithSummary ( ) { this = "index_with" }
311+
312+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
313+ input = "Argument[self].Element[any]" and
314+ output = "Argument[block].Parameter[0]" and
315+ preservesValue = true
316+ or
317+ input = [ "Argument[0]" , "Argument[block].ReturnValue" ] and
318+ output = "ReturnValue.Element[?]" and
319+ preservesValue = true
320+ }
321+ }
322+
323+ private string getKeyArgument ( MethodCall mc , int i ) {
324+ mc .getMethodName ( ) = [ "pick" , "pluck" ] and
325+ result = DataFlow:: Content:: getKnownElementIndex ( mc .getArgument ( i ) ) .serialize ( )
326+ }
327+
328+ private class PickSingleSummary extends SummarizedCallable {
329+ private MethodCall mc ;
330+ private string key ;
331+
332+ PickSingleSummary ( ) {
333+ key = getKeyArgument ( mc , 0 ) and
334+ this = "Enumerable.pick(" + key + ")" and
335+ mc .getMethodName ( ) = "pick" and
336+ mc .getNumberOfArguments ( ) = 1
337+ }
338+
339+ override MethodCall getACall ( ) { result = mc }
340+
341+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
342+ input = "Argument[self].Element[0].Element[" + key + "]" and
343+ output = "ReturnValue" and
344+ preservesValue = true
345+ }
346+ }
347+
348+ private class PickMultipleSummary extends SummarizedCallable {
349+ private MethodCall mc ;
350+
351+ PickMultipleSummary ( ) {
352+ mc .getMethodName ( ) = "pick" and
353+ mc .getNumberOfArguments ( ) > 1 and
354+ exists ( int maxKey |
355+ maxKey = max ( int j | exists ( getKeyArgument ( mc , j ) ) ) and
356+ this =
357+ "Enumerable.pick(" +
358+ concat ( int i , string key |
359+ key = getKeyArgument ( mc , i )
360+ or
361+ key = "_" and
362+ not exists ( getKeyArgument ( mc , i ) ) and
363+ i in [ 0 .. maxKey ]
364+ |
365+ key , "," order by i
366+ ) + ")"
367+ )
368+ }
369+
370+ override MethodCall getACall ( ) { result = mc }
371+
372+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
373+ exists ( string s , int i |
374+ s = getKeyArgument ( mc , i ) and
375+ input = "Argument[self].Element[0].Element[" + s + "]" and
376+ output = "ReturnValue.Element[" + i + "]"
377+ ) and
378+ preservesValue = true
379+ }
380+ }
381+
382+ private class PluckSingleSummary extends SummarizedCallable {
383+ private MethodCall mc ;
384+ private string key ;
385+
386+ PluckSingleSummary ( ) {
387+ key = getKeyArgument ( mc , 0 ) and
388+ this = "Enumerable.pluck(" + key + ")" and
389+ mc .getMethodName ( ) = "pluck" and
390+ mc .getNumberOfArguments ( ) = 1
391+ }
392+
393+ override MethodCall getACall ( ) { result = mc }
394+
395+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
396+ input = "Argument[self].Element[any].Element[" + key + "]" and
397+ output = "ReturnValue.Element[any]" and
398+ preservesValue = true
399+ }
400+ }
401+
402+ private class PluckMultipleSummary extends SummarizedCallable {
403+ private MethodCall mc ;
404+
405+ PluckMultipleSummary ( ) {
406+ mc .getMethodName ( ) = "pluck" and
407+ mc .getNumberOfArguments ( ) > 1 and
408+ exists ( int maxKey |
409+ maxKey = max ( int j | exists ( getKeyArgument ( mc , j ) ) ) and
410+ this =
411+ "Enumerable.pluck(" +
412+ concat ( int i , string key |
413+ key = getKeyArgument ( mc , i )
414+ or
415+ key = "_" and
416+ not exists ( getKeyArgument ( mc , i ) ) and
417+ i in [ 0 .. maxKey ]
418+ |
419+ key , "," order by i
420+ ) + ")"
421+ )
422+ }
423+
424+ override MethodCall getACall ( ) { result = mc }
425+
426+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
427+ exists ( string s , int i |
428+ s = getKeyArgument ( mc , i ) and
429+ input = "Argument[self].Element[any].Element[" + s + "]" and
430+ output = "ReturnValue.Element[?].Element[" + i + "]"
431+ ) and
432+ preservesValue = true
433+ }
434+ }
435+
436+ private class SoleSummary extends SimpleSummarizedCallable {
437+ SoleSummary ( ) { this = "sole" }
438+
439+ override predicate propagatesFlowExt ( string input , string output , boolean preservesValue ) {
440+ input = "Argument[self].Element[0]" and
441+ output = "ReturnValue" and
442+ preservesValue = true
443+ }
444+ }
309445 }
310446 }
311447
0 commit comments