@@ -231,6 +231,7 @@ private newtype TEndpointFeature =
231231 TCalleeAccessPathWithStructuralInfo ( ) or
232232 TEnclosingFunctionBody ( ) or
233233 TFileImports ( ) or
234+ TCalleeImports ( ) or
234235 TCalleeFlexibleAccessPath ( ) or
235236 TInputAccessPathFromCallee ( ) or
236237 TInputArgumentIndex ( )
@@ -411,7 +412,21 @@ class EnclosingFunctionBody extends EndpointFeature, TEnclosingFunctionBody {
411412 }
412413}
413414
414- /** The feature for the imports defined in the file containing an endpoint. */
415+ /**
416+ * The feature for the imports defined in the file containing an endpoint.
417+ *
418+ * ### Example
419+ *
420+ * ```javascript
421+ * import { findOne } from 'mongoose';
422+ * import * as _ from 'lodash';
423+ * const pg = require('pg');
424+ *
425+ * // ...
426+ * ```
427+ *
428+ * In this file, all endpoints will have the value `lodash mongoose pg` for the feature `fileImports`.
429+ */
415430class FileImports extends EndpointFeature , TFileImports {
416431 override string getName ( ) { result = "fileImports" }
417432
@@ -425,6 +440,28 @@ class FileImports extends EndpointFeature, TFileImports {
425440 }
426441}
427442
443+ class CalleeImports extends EndpointFeature , TCalleeImports {
444+ override string getName ( ) { result = "calleeImports" }
445+
446+ override string getValue ( DataFlow:: Node endpoint ) {
447+ not result = SyntacticUtilities:: getUnknownSymbol ( ) and
448+ exists ( DataFlow:: InvokeNode invk |
449+ (
450+ invk .getAnArgument ( ) = endpoint or
451+ SyntacticUtilities:: getANestedInitializerValue ( invk .getAnArgument ( )
452+ .asExpr ( )
453+ .getUnderlyingValue ( ) ) .flow ( ) = endpoint
454+ ) and
455+ result =
456+ concat ( string importPath |
457+ importPath = SyntacticUtilities:: getCalleeImportPath ( invk .getCalleeNode ( ) )
458+ |
459+ importPath , " " order by importPath
460+ )
461+ )
462+ }
463+ }
464+
428465/**
429466 * Syntactic utilities for feature value computation.
430467 */
@@ -476,6 +513,31 @@ private module SyntacticUtilities {
476513 else result = getUnknownSymbol ( )
477514 }
478515
516+ /**
517+ * Gets the imported package path that this node depends on, if any.
518+ *
519+ * Otherwise, returns '?'.
520+ *
521+ * XXX Be careful with using this in your features, as it might teach the model
522+ * a fixed list of "dangerous" libraries that could lead to bad generalization.
523+ */
524+ string getCalleeImportPath ( DataFlow:: Node node ) {
525+ exists ( DataFlow:: Node src | src = node .getALocalSource ( ) |
526+ if src instanceof DataFlow:: ModuleImportNode
527+ then result = src .( DataFlow:: ModuleImportNode ) .getPath ( )
528+ else
529+ if src instanceof DataFlow:: PropRead
530+ then result = getCalleeImportPath ( src .( DataFlow:: PropRead ) .getBase ( ) )
531+ else
532+ if src instanceof DataFlow:: InvokeNode
533+ then result = getCalleeImportPath ( src .( DataFlow:: InvokeNode ) .getCalleeNode ( ) )
534+ else
535+ if src .asExpr ( ) instanceof AwaitExpr
536+ then result = getCalleeImportPath ( src .asExpr ( ) .( AwaitExpr ) .getOperand ( ) .flow ( ) )
537+ else result = getUnknownSymbol ( )
538+ )
539+ }
540+
479541 /**
480542 * Computes a simple access path for a node.
481543 *
0 commit comments