@@ -228,6 +228,7 @@ module Public {
228228 */
229229module Private {
230230 private import Public
231+ import AccessPathSyntax
231232
232233 newtype TSummaryComponent =
233234 TContentSummaryComponent ( Content c ) or
@@ -811,69 +812,46 @@ module Private {
811812 sinkElement ( _, spec , _)
812813 }
813814
814- /** Holds if the `n`th component of specification `s` is `c`. */
815- predicate specSplit ( string s , string c , int n ) { relevantSpec ( s ) and s .splitAt ( " of " , n ) = c }
816-
817- /** Holds if specification `s` has length `len`. */
818- predicate specLength ( string s , int len ) { len = 1 + max ( int n | specSplit ( s , _, n ) ) }
819-
820- /** Gets the last component of specification `s`. */
821- string specLast ( string s ) {
822- exists ( int len |
823- specLength ( s , len ) and
824- specSplit ( s , result , len - 1 )
825- )
815+ private class AccessPathRange extends AccessPath:: Range {
816+ AccessPathRange ( ) { relevantSpec ( this ) }
826817 }
827818
828819 /** Holds if specification component `c` parses as parameter `n`. */
829- predicate parseParam ( string c , ArgumentPosition pos ) {
830- specSplit ( _, c , _) and
831- exists ( string body |
832- body = c .regexpCapture ( "Parameter\\[([^\\]]*)\\]" , 1 ) and
833- pos = parseParamBody ( body )
834- )
820+ predicate parseParam ( AccessPathToken token , ArgumentPosition pos ) {
821+ token .getName ( ) = "Parameter" and
822+ pos = parseParamBody ( token .getAnArgument ( ) )
835823 }
836824
837825 /** Holds if specification component `c` parses as argument `n`. */
838- predicate parseArg ( string c , ParameterPosition pos ) {
839- specSplit ( _, c , _) and
840- exists ( string body |
841- body = c .regexpCapture ( "Argument\\[([^\\]]*)\\]" , 1 ) and
842- pos = parseArgBody ( body )
843- )
826+ predicate parseArg ( AccessPathToken token , ParameterPosition pos ) {
827+ token .getName ( ) = "Argument" and
828+ pos = parseArgBody ( token .getAnArgument ( ) )
844829 }
845830
846- private SummaryComponent interpretComponent ( string c ) {
847- specSplit ( _, c , _) and
848- (
849- exists ( ParameterPosition pos |
850- parseArg ( c , pos ) and result = SummaryComponent:: argument ( pos )
851- )
852- or
853- exists ( ArgumentPosition pos |
854- parseParam ( c , pos ) and result = SummaryComponent:: parameter ( pos )
855- )
856- or
857- c = "ReturnValue" and result = SummaryComponent:: return ( getReturnValueKind ( ) )
858- or
859- result = interpretComponentSpecific ( c )
831+ private SummaryComponent interpretComponent ( AccessPathToken token ) {
832+ exists ( ParameterPosition pos |
833+ parseArg ( token , pos ) and result = SummaryComponent:: argument ( pos )
860834 )
835+ or
836+ exists ( ArgumentPosition pos |
837+ parseParam ( token , pos ) and result = SummaryComponent:: parameter ( pos )
838+ )
839+ or
840+ token = "ReturnValue" and result = SummaryComponent:: return ( getReturnValueKind ( ) )
841+ or
842+ result = interpretComponentSpecific ( token )
861843 }
862844
863845 /**
864846 * Holds if `spec` specifies summary component stack `stack`.
865847 */
866- predicate interpretSpec ( string spec , SummaryComponentStack stack ) {
848+ predicate interpretSpec ( AccessPath spec , SummaryComponentStack stack ) {
867849 interpretSpec ( spec , 0 , stack )
868850 }
869851
870- private predicate interpretSpec ( string spec , int idx , SummaryComponentStack stack ) {
871- exists ( string c |
872- relevantSpec ( spec ) and
873- specLength ( spec , idx + 1 ) and
874- specSplit ( spec , c , idx ) and
875- stack = SummaryComponentStack:: singleton ( interpretComponent ( c ) )
876- )
852+ private predicate interpretSpec ( AccessPath spec , int idx , SummaryComponentStack stack ) {
853+ idx = spec .getNumToken ( ) - 1 and
854+ stack = SummaryComponentStack:: singleton ( interpretComponent ( spec .getLastToken ( idx ) ) )
877855 or
878856 exists ( SummaryComponent head , SummaryComponentStack tail |
879857 interpretSpec ( spec , idx , head , tail ) and
@@ -882,13 +860,10 @@ module Private {
882860 }
883861
884862 private predicate interpretSpec (
885- string output , int idx , SummaryComponent head , SummaryComponentStack tail
863+ AccessPath output , int idx , SummaryComponent head , SummaryComponentStack tail
886864 ) {
887- exists ( string c |
888- interpretSpec ( output , idx + 1 , tail ) and
889- specSplit ( output , c , idx ) and
890- head = interpretComponent ( c )
891- )
865+ interpretSpec ( output , idx + 1 , tail ) and
866+ head = interpretComponent ( output .getLastToken ( idx ) )
892867 }
893868
894869 private class MkStack extends RequiredSummaryComponentStack {
@@ -903,7 +878,7 @@ module Private {
903878 override predicate propagatesFlow (
904879 SummaryComponentStack input , SummaryComponentStack output , boolean preservesValue
905880 ) {
906- exists ( string inSpec , string outSpec , string kind |
881+ exists ( AccessPath inSpec , AccessPath outSpec , string kind |
907882 summaryElement ( this , inSpec , outSpec , kind ) and
908883 interpretSpec ( inSpec , input ) and
909884 interpretSpec ( outSpec , output )
@@ -916,50 +891,55 @@ module Private {
916891 }
917892
918893 /** Holds if component `c` of specification `spec` cannot be parsed. */
919- predicate invalidSpecComponent ( string spec , string c ) {
920- specSplit ( spec , c , _) and
894+ predicate invalidSpecComponent ( AccessPath spec , string c ) {
895+ c = spec . getRawToken ( _) and
921896 not exists ( interpretComponent ( c ) )
922897 }
923898
924- private predicate inputNeedsReference ( string c ) {
925- c = "Argument" or
926- parseArg ( c , _) or
899+ private predicate inputNeedsReference ( AccessPathToken c ) {
900+ c .getName ( ) = "Argument" or
927901 inputNeedsReferenceSpecific ( c )
928902 }
929903
930- private predicate outputNeedsReference ( string c ) {
931- c = "Argument" or
932- parseArg ( c , _) or
933- c = "ReturnValue" or
904+ private predicate outputNeedsReference ( AccessPathToken c ) {
905+ c .getName ( ) = [ "Argument" , "ReturnValue" ] or
934906 outputNeedsReferenceSpecific ( c )
935907 }
936908
937- private predicate sourceElementRef ( InterpretNode ref , string output , string kind ) {
909+ private predicate sourceElementRef ( InterpretNode ref , AccessPath output , string kind ) {
938910 exists ( SourceOrSinkElement e |
939911 sourceElement ( e , output , kind ) and
940- if outputNeedsReference ( specLast ( output ) )
912+ if outputNeedsReference ( output . getToken ( 0 ) )
941913 then e = ref .getCallTarget ( )
942914 else e = ref .asElement ( )
943915 )
944916 }
945917
946- private predicate sinkElementRef ( InterpretNode ref , string input , string kind ) {
918+ private predicate sinkElementRef ( InterpretNode ref , AccessPath input , string kind ) {
947919 exists ( SourceOrSinkElement e |
948920 sinkElement ( e , input , kind ) and
949- if inputNeedsReference ( specLast ( input ) )
921+ if inputNeedsReference ( input . getToken ( 0 ) )
950922 then e = ref .getCallTarget ( )
951923 else e = ref .asElement ( )
952924 )
953925 }
954926
955- private predicate interpretOutput ( string output , int idx , InterpretNode ref , InterpretNode node ) {
927+ private predicate interpretOutput (
928+ AccessPath output , int idx , InterpretNode ref , InterpretNode node
929+ ) {
956930 sourceElementRef ( ref , output , _) and
957- specLength ( output , idx ) and
958- node = ref
931+ idx = output .getNumToken ( ) and
932+ (
933+ if output = ""
934+ then
935+ // Allow language-specific interpretation of the empty access path
936+ interpretOutputSpecific ( "" , ref , node )
937+ else node = ref
938+ )
959939 or
960- exists ( InterpretNode mid , string c |
940+ exists ( InterpretNode mid , AccessPathToken c |
961941 interpretOutput ( output , idx + 1 , ref , mid ) and
962- specSplit ( output , c , idx )
942+ c = output . getLastToken ( idx )
963943 |
964944 exists ( ArgumentPosition apos , ParameterPosition ppos |
965945 node .asNode ( ) .( PostUpdateNode ) .getPreUpdateNode ( ) .( ArgNode ) .argumentOf ( mid .asCall ( ) , apos ) and
@@ -982,14 +962,22 @@ module Private {
982962 )
983963 }
984964
985- private predicate interpretInput ( string input , int idx , InterpretNode ref , InterpretNode node ) {
965+ private predicate interpretInput (
966+ AccessPath input , int idx , InterpretNode ref , InterpretNode node
967+ ) {
986968 sinkElementRef ( ref , input , _) and
987- specLength ( input , idx ) and
988- node = ref
969+ idx = input .getNumToken ( ) and
970+ (
971+ if input = ""
972+ then
973+ // Allow language-specific interpretation of the empty access path
974+ interpretInputSpecific ( "" , ref , node )
975+ else node = ref
976+ )
989977 or
990- exists ( InterpretNode mid , string c |
978+ exists ( InterpretNode mid , AccessPathToken c |
991979 interpretInput ( input , idx + 1 , ref , mid ) and
992- specSplit ( input , c , idx )
980+ c = input . getLastToken ( idx )
993981 |
994982 exists ( ArgumentPosition apos , ParameterPosition ppos |
995983 node .asNode ( ) .( ArgNode ) .argumentOf ( mid .asCall ( ) , apos ) and
0 commit comments