@@ -258,36 +258,30 @@ predicate isRelevantFullPath(string package, string type, string path) {
258
258
}
259
259
260
260
/**
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.
262
263
*/
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 )
277
267
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
+ }
282
273
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 ) ) ) }
291
285
}
292
286
293
287
/**
@@ -344,124 +338,104 @@ private predicate invocationMatchesCallSiteFilter(API::InvokeNode invoke, Access
344
338
}
345
339
346
340
/**
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.
348
342
*/
349
343
pragma [ 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
352
346
(
353
347
type = "" and
354
- path = "" and
348
+ n = 0 and
355
349
result = API:: moduleImport ( package )
356
350
or
357
- path = "" and
358
- exists ( string package2 , string type2 , string path2 |
351
+ n = 0 and
352
+ exists ( string package2 , string type2 , AccessPath path2 |
359
353
typeModel ( package , type , package2 , type2 , path2 ) and
360
- result = getNodeFromPath ( package2 , type2 , path2 )
354
+ result = getNodeFromPath ( package2 , type2 , path2 , path2 . getNumToken ( ) )
361
355
)
362
356
or
363
357
// Language-specific cases, such as handling of global variables
364
- result = Impl:: getExtraNodeFromPath ( package , type , path )
358
+ result = Impl:: getExtraNodeFromPath ( package , type , path , n )
365
359
)
366
360
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 ) )
371
362
or
372
363
// 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 ( ) )
377
371
}
378
372
379
373
/**
380
374
* Gets an invocation identified by the given `(package, type, path)` tuple.
381
375
*
382
376
* Unlike `getNodeFromPath`, the `path` may end with one or more call-site filters.
383
377
*/
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 ( )
386
380
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 ( ) )
392
388
}
393
389
394
390
/**
395
391
* Holds if a summary edge with the given `input, output, kind` columns have a `package, type, path` tuple
396
392
* that resolves to `baseNode`.
397
393
*/
398
394
private predicate resolvedSummaryBase (
399
- API:: InvokeNode baseNode , string input , string output , string kind
395
+ API:: InvokeNode baseNode , AccessPath input , AccessPath output , string kind
400
396
) {
401
- exists ( string package , string type , string path |
397
+ exists ( string package , string type , AccessPath path |
402
398
summaryModel ( package , type , path , input , output , kind ) and
403
399
baseNode = getInvocationFromPath ( package , type , path )
404
400
)
405
401
}
406
402
407
403
/**
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.
410
405
*/
411
406
pragma [ 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 , _)
426
411
}
427
412
428
413
/**
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`.
430
415
*/
431
- private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , string path ) {
416
+ private API:: Node getNodeFromInputOutputPath ( API:: InvokeNode baseNode , AccessPath path , int n ) {
432
417
relevantInputOutputPath ( baseNode , path ) and
433
418
(
434
- result = getSuccessorFromInvoke ( baseNode , path )
419
+ n = 1 and
420
+ result = getSuccessorFromInvoke ( baseNode , path .getToken ( 0 ) )
435
421
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 ) )
440
424
)
441
425
}
442
426
443
427
/**
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`.
446
429
*/
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 ( ) )
458
432
}
459
433
460
434
/**
461
435
* An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
462
436
*/
463
437
class AccessPathToken extends string {
464
- AccessPathToken ( ) { isAccessPathToken ( this ) }
438
+ AccessPathToken ( ) { this = any ( AccessPath path ) . getRawToken ( _ ) }
465
439
466
440
/** Gets the name of the token, such as `Member` from `Member[x]` */
467
441
string getName ( ) { result = this .regexpCapture ( "(.+?)(?:\\[.*?\\])?" , 1 ) }
@@ -593,7 +567,7 @@ module ModelOutput {
593
567
* Holds if a CSV summary contributed the step `pred -> succ` of the given `kind`.
594
568
*/
595
569
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 |
597
571
resolvedSummaryBase ( base , input , output , kind ) and
598
572
pred = getNodeFromInputOutputPath ( base , input ) and
599
573
succ = getNodeFromInputOutputPath ( base , output )
@@ -605,7 +579,7 @@ module ModelOutput {
605
579
* contributed by a CSV model.
606
580
*/
607
581
API:: Node getATypeNode ( string package , string type ) {
608
- exists ( string package2 , string type2 , string path |
582
+ exists ( string package2 , string type2 , AccessPath path |
609
583
typeModel ( package , type , package2 , type2 , path ) and
610
584
result = getNodeFromPath ( package2 , type2 , path )
611
585
)
0 commit comments