99private import FlowSummaryImplSpecific
1010private import DataFlowImplSpecific:: Private
1111private import DataFlowImplSpecific:: Public
12+ private import DataFlowImplCommon as DataFlowImplCommon
1213
1314/** Provides classes and predicates for defining flow summaries. */
1415module Public {
@@ -178,7 +179,6 @@ module Public {
178179 */
179180module Private {
180181 private import Public
181- private import DataFlowImplCommon as DataFlowImplCommon
182182
183183 newtype TSummaryComponent =
184184 TContentSummaryComponent ( Content c ) or
@@ -580,6 +580,14 @@ module Private {
580580 * summaries into a `SummarizedCallable`s.
581581 */
582582 module External {
583+ /** Holds if `spec` is a relevant external specification. */
584+ private predicate relevantSpec ( string spec ) {
585+ summaryElement ( _, spec , _, _) or
586+ summaryElement ( _, _, spec , _) or
587+ sourceElement ( _, spec , _) or
588+ sinkElement ( _, spec , _)
589+ }
590+
583591 /** Holds if the `n`th component of specification `s` is `c`. */
584592 predicate specSplit ( string s , string c , int n ) { relevantSpec ( s ) and s .splitAt ( " of " , n ) = c }
585593
@@ -629,6 +637,8 @@ module Private {
629637 or
630638 exists ( int pos | parseParam ( c , pos ) and result = SummaryComponent:: parameter ( pos ) )
631639 or
640+ c = "ReturnValue" and result = SummaryComponent:: return ( getReturnValueKind ( ) )
641+ or
632642 result = interpretComponentSpecific ( c )
633643 )
634644 }
@@ -664,13 +674,13 @@ module Private {
664674 }
665675
666676 private class SummarizedCallableExternal extends SummarizedCallable {
667- SummarizedCallableExternal ( ) { externalSummary ( this , _, _, _) }
677+ SummarizedCallableExternal ( ) { summaryElement ( this , _, _, _) }
668678
669679 override predicate propagatesFlow (
670680 SummaryComponentStack input , SummaryComponentStack output , boolean preservesValue
671681 ) {
672682 exists ( string inSpec , string outSpec , string kind |
673- externalSummary ( this , inSpec , outSpec , kind ) and
683+ summaryElement ( this , inSpec , outSpec , kind ) and
674684 interpretSpec ( inSpec , 0 , input ) and
675685 interpretSpec ( outSpec , 0 , output )
676686 |
@@ -686,6 +696,111 @@ module Private {
686696 specSplit ( spec , c , _) and
687697 not exists ( interpretComponent ( c ) )
688698 }
699+
700+ private predicate inputNeedsReference ( string c ) {
701+ c = "Argument" or
702+ parseArg ( c , _)
703+ }
704+
705+ private predicate outputNeedsReference ( string c ) {
706+ c = "Argument" or
707+ parseArg ( c , _) or
708+ c = "ReturnValue"
709+ }
710+
711+ private predicate sourceElementRef ( InterpretNode ref , string output , string kind ) {
712+ exists ( SourceOrSinkElement e |
713+ sourceElement ( e , output , kind ) and
714+ if outputNeedsReference ( specLast ( output ) )
715+ then e = ref .getCallTarget ( )
716+ else e = ref .asElement ( )
717+ )
718+ }
719+
720+ private predicate sinkElementRef ( InterpretNode ref , string input , string kind ) {
721+ exists ( SourceOrSinkElement e |
722+ sinkElement ( e , input , kind ) and
723+ if inputNeedsReference ( specLast ( input ) )
724+ then e = ref .getCallTarget ( )
725+ else e = ref .asElement ( )
726+ )
727+ }
728+
729+ private predicate interpretOutput ( string output , int idx , InterpretNode ref , InterpretNode node ) {
730+ sourceElementRef ( ref , output , _) and
731+ specLength ( output , idx ) and
732+ node = ref
733+ or
734+ exists ( InterpretNode mid , string c |
735+ interpretOutput ( output , idx + 1 , ref , mid ) and
736+ specSplit ( output , c , idx )
737+ |
738+ exists ( int pos |
739+ node .asNode ( )
740+ .( PostUpdateNode )
741+ .getPreUpdateNode ( )
742+ .( ArgumentNode )
743+ .argumentOf ( mid .asCall ( ) , pos )
744+ |
745+ c = "Argument" or parseArg ( c , pos )
746+ )
747+ or
748+ exists ( int pos | node .asNode ( ) .( ParameterNode ) .isParameterOf ( mid .asCallable ( ) , pos ) |
749+ c = "Parameter" or parseParam ( c , pos )
750+ )
751+ or
752+ c = "ReturnValue" and
753+ node .asNode ( ) = getAnOutNode ( mid .asCall ( ) , getReturnValueKind ( ) )
754+ or
755+ interpretOutputSpecific ( c , mid , node )
756+ )
757+ }
758+
759+ private predicate interpretInput ( string input , int idx , InterpretNode ref , InterpretNode node ) {
760+ sinkElementRef ( ref , input , _) and
761+ specLength ( input , idx ) and
762+ node = ref
763+ or
764+ exists ( InterpretNode mid , string c |
765+ interpretInput ( input , idx + 1 , ref , mid ) and
766+ specSplit ( input , c , idx )
767+ |
768+ exists ( int pos | node .asNode ( ) .( ArgumentNode ) .argumentOf ( mid .asCall ( ) , pos ) |
769+ c = "Argument" or parseArg ( c , pos )
770+ )
771+ or
772+ exists ( ReturnNode ret |
773+ c = "ReturnValue" and
774+ ret = node .asNode ( ) and
775+ ret .getKind ( ) = getReturnValueKind ( ) and
776+ mid .asCallable ( ) = DataFlowImplCommon:: getNodeEnclosingCallable ( ret )
777+ )
778+ or
779+ interpretInputSpecific ( c , mid , node )
780+ )
781+ }
782+
783+ /**
784+ * Holds if `node` is specified as a source with the given kind in a CSV flow
785+ * model.
786+ */
787+ predicate isSourceNode ( InterpretNode node , string kind ) {
788+ exists ( InterpretNode ref , string output |
789+ sourceElementRef ( ref , output , kind ) and
790+ interpretOutput ( output , 0 , ref , node )
791+ )
792+ }
793+
794+ /**
795+ * Holds if `node` is specified as a sink with the given kind in a CSV flow
796+ * model.
797+ */
798+ predicate isSinkNode ( InterpretNode node , string kind ) {
799+ exists ( InterpretNode ref , string input |
800+ sinkElementRef ( ref , input , kind ) and
801+ interpretInput ( input , 0 , ref , node )
802+ )
803+ }
689804 }
690805
691806 /** Provides a query predicate for outputting a set of relevant flow summaries. */
0 commit comments