@@ -258,36 +258,30 @@ predicate isRelevantFullPath(string package, string type, string path) {
258258}
259259
260260/**
261- * Holds if `path` or some suffix thereof is used with the `package,type` combination in some CSV row.
261+ * A string that occurs as an access path (either identifying or input/output spec)
262+ * which might be relevant for this database.
262263 */
263- pragma [ nomagic]
264- predicate isRelevantPath ( string package , string type , string path ) {
265- exists ( string fullPath |
266- isRelevantFullPath ( package , type , fullPath ) and
267- path = fullPath .prefix ( [ 0 , fullPath .indexOf ( "." ) , fullPath .length ( ) ] )
268- )
269- }
270-
271- /** Holds if `path` has the form `basePath.token` where `token` is a single token. */
272- bindingset [ path]
273- private predicate decomposePath ( string path , string basePath , string token ) {
274- token = max ( int n | | path .splitAt ( "." , n ) order by n ) and
275- (
276- basePath = path .prefix ( path .length ( ) - token .length ( ) - 1 )
264+ class AccessPath extends string {
265+ AccessPath ( ) {
266+ isRelevantFullPath ( _, _, this )
277267 or
278- token = path and
279- basePath = ""
280- )
281- }
268+ exists ( string package | isRelevantPackage ( package ) |
269+ summaryModel ( package , _, _, this , _, _) or
270+ summaryModel ( package , _, _, _, this , _)
271+ )
272+ }
282273
283- /**
284- * Gets the result of appending `token` onto `path`.
285- *
286- * Only has a result for identifying access paths relevant for `package;type`.
287- */
288- private string appendToken ( string package , string type , string path , string token ) {
289- isRelevantPath ( package , type , result ) and
290- decomposePath ( result , path , token )
274+ /** Gets the `n`th token on the access path as a string. */
275+ string getRawToken ( int n ) {
276+ this != "" and // The empty path should have zero tokens, not a single empty token
277+ result = this .splitAt ( "." , n )
278+ }
279+
280+ /** Gets the `n`th token on the access path. */
281+ AccessPathToken getToken ( int n ) { result = getRawToken ( n ) }
282+
283+ /** Gets the number of tokens on the path. */
284+ int getNumToken ( ) { result = count ( int n | exists ( getRawToken ( n ) ) ) }
291285}
292286
293287/**
@@ -344,124 +338,104 @@ private predicate invocationMatchesCallSiteFilter(API::InvokeNode invoke, Access
344338}
345339
346340/**
347- * Gets the API node identified by the given `(package, type, path)` tuple.
341+ * Gets the API node identified by the first `n` tokens of `path` in the given `(package, type, path)` tuple.
348342 */
349343pragma [ nomagic]
350- API:: Node getNodeFromPath ( string package , string type , string path ) {
351- isRelevantPath ( package , type , path ) and
344+ API:: Node getNodeFromPath ( string package , string type , AccessPath path , int n ) {
345+ isRelevantFullPath ( package , type , path ) and
352346 (
353347 type = "" and
354- path = "" and
348+ n = 0 and
355349 result = API:: moduleImport ( package )
356350 or
357- path = "" and
358- exists ( string package2 , string type2 , string path2 |
351+ n = 0 and
352+ exists ( string package2 , string type2 , AccessPath path2 |
359353 typeModel ( package , type , package2 , type2 , path2 ) and
360- result = getNodeFromPath ( package2 , type2 , path2 )
354+ result = getNodeFromPath ( package2 , type2 , path2 , path2 . getNumToken ( ) )
361355 )
362356 or
363357 // Language-specific cases, such as handling of global variables
364- result = Impl:: getExtraNodeFromPath ( package , type , path )
358+ result = Impl:: getExtraNodeFromPath ( package , type , path , n )
365359 )
366360 or
367- exists ( string basePath , AccessPathToken token |
368- result = getSuccessorFromNode ( getNodeFromPath ( package , type , basePath ) , token ) and
369- path = appendToken ( package , type , basePath , token )
370- )
361+ result = getSuccessorFromNode ( getNodeFromPath ( package , type , path , n - 1 ) , path .getToken ( n - 1 ) )
371362 or
372363 // Similar to the other recursive case, but where the path may have stepped through one or more call-site filters
373- exists ( string basePath , AccessPathToken token |
374- result = getSuccessorFromInvoke ( getInvocationFromPath ( package , type , basePath ) , token ) and
375- path = appendToken ( package , type , basePath , token )
376- )
364+ result =
365+ getSuccessorFromInvoke ( getInvocationFromPath ( package , type , path , n - 1 ) , path .getToken ( n - 1 ) )
366+ }
367+
368+ /** Gets the node identified by the given `(package, type, path)` tuple. */
369+ API:: Node getNodeFromPath ( string package , string type , AccessPath path ) {
370+ result = getNodeFromPath ( package , type , path , path .getNumToken ( ) )
377371}
378372
379373/**
380374 * Gets an invocation identified by the given `(package, type, path)` tuple.
381375 *
382376 * Unlike `getNodeFromPath`, the `path` may end with one or more call-site filters.
383377 */
384- API:: InvokeNode getInvocationFromPath ( string package , string type , string path ) {
385- result = getNodeFromPath ( package , type , path ) .getAnInvocation ( )
378+ API:: InvokeNode getInvocationFromPath ( string package , string type , AccessPath path , int n ) {
379+ result = getNodeFromPath ( package , type , path , n ) .getAnInvocation ( )
386380 or
387- exists ( string basePath , AccessPathToken token |
388- result = getInvocationFromPath ( package , type , basePath ) and
389- path = appendToken ( package , type , basePath , token ) and
390- invocationMatchesCallSiteFilter ( result , token )
391- )
381+ result = getInvocationFromPath ( package , type , path , n - 1 ) and
382+ invocationMatchesCallSiteFilter ( result , path .getToken ( n - 1 ) )
383+ }
384+
385+ /** Gets an invocation identified by the given `(package, type, path)` tuple. */
386+ API:: InvokeNode getInvocationFromPath ( string package , string type , AccessPath path ) {
387+ result = getInvocationFromPath ( package , type , path , path .getNumToken ( ) )
392388}
393389
394390/**
395391 * Holds if a summary edge with the given `input, output, kind` columns have a `package, type, path` tuple
396392 * that resolves to `baseNode`.
397393 */
398394private predicate resolvedSummaryBase (
399- API:: InvokeNode baseNode , string input , string output , string kind
395+ API:: InvokeNode baseNode , AccessPath input , AccessPath output , string kind
400396) {
401- exists ( string package , string type , string path |
397+ exists ( string package , string type , AccessPath path |
402398 summaryModel ( package , type , path , input , output , kind ) and
403399 baseNode = getInvocationFromPath ( package , type , path )
404400 )
405401}
406402
407403/**
408- * Holds if `inputOrOutput` or some suffix thereof is used as the input or output part
409- * of a summary edge using `base` as the base node.
404+ * Holds if `path` is an input or output spec for a summary with the given `base` node.
410405 */
411406pragma [ nomagic]
412- private predicate relevantInputOutputPath ( API:: InvokeNode base , string inputOrOutput ) {
413- exists ( string baseIo | inputOrOutput = baseIo .prefix ( [ 0 , baseIo .indexOf ( "." ) , baseIo .length ( ) ] ) |
414- resolvedSummaryBase ( base , baseIo , _, _) or
415- resolvedSummaryBase ( base , _, baseIo , _)
416- )
417- }
418-
419- /**
420- * Gets the result of appending `token` onto `path`, if the resulting path is relevant for
421- * a summary of `invoke`.
422- */
423- private string appendToken ( API:: InvokeNode invoke , string path , string token ) {
424- relevantInputOutputPath ( invoke , result ) and
425- decomposePath ( result , path , token )
407+ private predicate relevantInputOutputPath ( API:: InvokeNode base , AccessPath path ) {
408+ resolvedSummaryBase ( base , path , _, _)
409+ or
410+ resolvedSummaryBase ( base , _, path , _)
426411}
427412
428413/**
429- * Gets the API node for the given input/output path, evaluated relative to `baseNode`, which corresponds to `package,type,path `.
414+ * Gets the API node for the first `n` tokens of the given input/output path, evaluated relative to `baseNode`.
430415 */
431- private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , string path ) {
416+ private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , AccessPath path , int n ) {
432417 relevantInputOutputPath ( baseNode , path ) and
433418 (
434- result = getSuccessorFromInvoke ( baseNode , path )
419+ n = 1 and
420+ result = getSuccessorFromInvoke ( baseNode , path .getToken ( 0 ) )
435421 or
436- exists ( string basePath , string token |
437- result = getSuccessorFromNode ( getNodeFromInputOutputPath ( baseNode , basePath ) , token ) and
438- path = appendToken ( baseNode , basePath , token )
439- )
422+ result =
423+ getSuccessorFromNode ( getNodeFromInputOutputPath ( baseNode , path , n - 1 ) , path .getToken ( n - 1 ) )
440424 )
441425}
442426
443427/**
444- * Holds if `token` is a token used in an access path, that is,
445- * either the `path`, `input`, or `output` part of a CSV row.
428+ * Gets the API node for the given input/output path, evaluated relative to `baseNode`.
446429 */
447- private predicate isAccessPathToken ( string token ) {
448- exists ( string path |
449- isRelevantFullPath ( _, _, path )
450- or
451- exists ( string package | isRelevantPackage ( package ) |
452- summaryModel ( _, _, _, path , _, _) or
453- summaryModel ( _, _, _, _, path , _)
454- )
455- |
456- token = path .splitAt ( "." )
457- )
430+ private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , AccessPath path ) {
431+ result = getNodeFromInputOutputPath ( baseNode , path , path .getNumToken ( ) )
458432}
459433
460434/**
461435 * An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
462436 */
463437class AccessPathToken extends string {
464- AccessPathToken ( ) { isAccessPathToken ( this ) }
438+ AccessPathToken ( ) { this = any ( AccessPath path ) . getRawToken ( _ ) }
465439
466440 /** Gets the name of the token, such as `Member` from `Member[x]` */
467441 string getName ( ) { result = this .regexpCapture ( "(.+?)(?:\\[.*?\\])?" , 1 ) }
@@ -593,7 +567,7 @@ module ModelOutput {
593567 * Holds if a CSV summary contributed the step `pred -> succ` of the given `kind`.
594568 */
595569 predicate summaryStep ( API:: Node pred , API:: Node succ , string kind ) {
596- exists ( API:: InvokeNode base , string input , string output |
570+ exists ( API:: InvokeNode base , AccessPath input , AccessPath output |
597571 resolvedSummaryBase ( base , input , output , kind ) and
598572 pred = getNodeFromInputOutputPath ( base , input ) and
599573 succ = getNodeFromInputOutputPath ( base , output )
@@ -605,7 +579,7 @@ module ModelOutput {
605579 * contributed by a CSV model.
606580 */
607581 API:: Node getATypeNode ( string package , string type ) {
608- exists ( string package2 , string type2 , string path |
582+ exists ( string package2 , string type2 , AccessPath path |
609583 typeModel ( package , type , package2 , type2 , path ) and
610584 result = getNodeFromPath ( package2 , type2 , path )
611585 )
0 commit comments