@@ -10,6 +10,7 @@ private import semmle.code.powershell.dataflow.DataFlow
1010private import semmle.code.powershell.typetracking.ApiGraphShared
1111private import semmle.code.powershell.typetracking.internal.TypeTrackingImpl
1212private import semmle.code.powershell.controlflow.Cfg
13+ private import frameworks.data.internal.ApiGraphModels
1314private import frameworks.data.internal.ApiGraphModelsExtensions as Extensions
1415private import frameworks.data.internal.ApiGraphModelsSpecific as Specific
1516private import semmle.code.powershell.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -204,18 +205,6 @@ module API {
204205 Impl:: positionalParameterOrArgumentEdge ( this .getAnEpsilonSuccessor ( ) , n , result )
205206 }
206207
207- /**
208- * Gets the given keyword parameter of this callable, or keyword argument to this call.
209- *
210- * Note: for historical reasons, this predicate may refer to an argument of a call, but this may change in the future.
211- * When referring to an argument, it is recommended to use `getKeywordArgument(n)` instead.
212- */
213- pragma [ inline]
214- Node getKeywordParameter ( string name ) {
215- // This predicate is currently not 'inline_late' because 'name' can be an input or output
216- Impl:: keywordParameterOrArgumentEdge ( this .getAnEpsilonSuccessor ( ) , name , result )
217- }
218-
219208 /**
220209 * Gets the argument passed in argument position `pos` at this call.
221210 */
@@ -260,15 +249,6 @@ module API {
260249 result = this .getContent ( contents .getAReadContent ( ) )
261250 }
262251
263- /**
264- * Gets a representative for the instance field of the given `name`.
265- */
266- pragma [ inline]
267- Node getField ( string name ) {
268- // This predicate is currently not 'inline_late' because 'name' can be an input or output
269- Impl:: fieldEdge ( this .getAnEpsilonSuccessor ( ) , name , result )
270- }
271-
272252 /**
273253 * Gets a representative for an arbitrary element of this collection.
274254 */
@@ -283,8 +263,7 @@ module API {
283263 this = Impl:: MkMethodAccessNode ( result ) or
284264 this = Impl:: MkBackwardNode ( result , _) or
285265 this = Impl:: MkForwardNode ( result , _) or
286- this = Impl:: MkSinkNode ( result ) or
287- this = Impl:: MkNamespaceOfTypeNameNode ( result )
266+ this = Impl:: MkSinkNode ( result )
288267 }
289268
290269 /** Gets the location of this node. */
@@ -293,6 +272,10 @@ module API {
293272 or
294273 this instanceof RootNode and
295274 result instanceof EmptyLocation
275+ or
276+ not this instanceof RootNode and
277+ not exists ( this .getInducingNode ( ) ) and
278+ result instanceof EmptyLocation
296279 }
297280
298281 /**
@@ -352,20 +335,84 @@ module API {
352335 override string toString ( ) { result = "SinkNode(" + this .getInducingNode ( ) + ")" }
353336 }
354337
355- private class UsingNode extends Node , Impl:: MkUsingNode {
356- UsingStmt using ; // TODO: This should really be the cfg node, I think
338+ abstract private class AbstractTypeNameNode extends Node {
339+ string prefix ;
340+
341+ bindingset [ prefix]
342+ AbstractTypeNameNode ( ) { any ( ) }
343+
344+ override string toString ( ) { result = "TypeNameNode(" + this .getTypeName ( ) + ")" }
345+
346+ string getComponent ( ) {
347+ exists ( int n |
348+ result = prefix .splitAt ( "." , n ) and
349+ not exists ( prefix .splitAt ( "." , n + 1 ) )
350+ )
351+ }
352+
353+ string getTypeName ( ) { result = prefix }
354+
355+ abstract Node getSuccessor ( string name ) ;
356+
357+ Node memberEdge ( string name ) { none ( ) }
357358
358- UsingNode ( ) { this = Impl :: MkUsingNode ( using ) }
359+ Node methodEdge ( string name ) { none ( ) }
359360
360- override string toString ( ) { result = "UsingNode(" + using + ")" }
361+ final predicate isImplicit ( ) { not this .isExplicit ( _) }
362+
363+ predicate isExplicit ( DataFlow:: TypeNameNode typeName ) { none ( ) }
361364 }
362365
363- private class NamespaceOfTypeNameNode extends Node , Impl:: MkNamespaceOfTypeNameNode {
364- DataFlow:: QualifiedTypeNameNode typeName ;
366+ final class TypeNameNode = AbstractTypeNameNode ;
367+
368+ private class ExplicitTypeNameNode extends AbstractTypeNameNode , Impl:: MkExplicitTypeNameNode {
369+ ExplicitTypeNameNode ( ) { this = Impl:: MkExplicitTypeNameNode ( prefix ) }
370+
371+ final override Node getSuccessor ( string name ) {
372+ exists ( ExplicitTypeNameNode succ |
373+ succ = Impl:: MkExplicitTypeNameNode ( prefix + "." + name ) and
374+ result = succ
375+ )
376+ or
377+ exists ( DataFlow:: TypeNameNode typeName , int n , string lowerCaseName |
378+ Specific:: needsExplicitTypeNameNode ( typeName , prefix ) and
379+ lowerCaseName = typeName .getLowerCaseName ( ) and
380+ name = lowerCaseName .splitAt ( "." , n ) and
381+ not lowerCaseName .matches ( "%.%" ) and
382+ result = getForwardStartNode ( typeName )
383+ )
384+ }
385+
386+ final override predicate isExplicit ( DataFlow:: TypeNameNode typeName ) {
387+ Specific:: needsExplicitTypeNameNode ( typeName , prefix )
388+ }
389+ }
365390
366- NamespaceOfTypeNameNode ( ) { this = Impl :: MkNamespaceOfTypeNameNode ( typeName ) }
391+ private string getAnAlias ( string cmdlet ) { Specific :: aliasModel ( cmdlet , result ) }
367392
368- override string toString ( ) { result = "NamespaceOfTypeNameNode(" + typeName + ")" }
393+ predicate implicitCmdlet ( string mod , string cmdlet ) {
394+ exists ( string cmdlet0 |
395+ Specific:: cmdletModel ( mod , cmdlet0 ) and
396+ cmdlet = [ cmdlet0 , getAnAlias ( cmdlet0 ) ]
397+ )
398+ }
399+
400+ private class ImplicitTypeNameNode extends AbstractTypeNameNode , Impl:: MkImplicitTypeNameNode {
401+ ImplicitTypeNameNode ( ) { this = Impl:: MkImplicitTypeNameNode ( prefix ) }
402+
403+ final override Node getSuccessor ( string name ) {
404+ result = Impl:: MkImplicitTypeNameNode ( prefix + "." + name )
405+ }
406+
407+ final override Node memberEdge ( string name ) { result = this .methodEdge ( name ) }
408+
409+ final override Node methodEdge ( string name ) {
410+ exists ( DataFlow:: CallNode call |
411+ result = Impl:: MkMethodAccessNode ( call ) and
412+ name = call .getLowerCaseName ( ) and
413+ implicitCmdlet ( prefix , name )
414+ )
415+ }
369416 }
370417
371418 /**
@@ -405,13 +452,6 @@ module API {
405452 /** Gets the root node. */
406453 Node root ( ) { result instanceof RootNode }
407454
408- bindingset [ name]
409- pragma [ inline_late]
410- Node namespace ( string name ) {
411- // This predicate is currently not 'inline_late' because 'n' can be an input or output
412- Impl:: namespace ( name , result )
413- }
414-
415455 pragma [ inline]
416456 Node getTopLevelMember ( string name ) { Impl:: topLevelMember ( name , result ) }
417457
@@ -466,8 +506,8 @@ module API {
466506 MkRoot ( ) or
467507 /** The method accessed at `call`, synthetically treated as a separate object. */
468508 MkMethodAccessNode ( DataFlow:: CallNode call ) or
469- MkUsingNode ( UsingStmt using ) or
470- MkNamespaceOfTypeNameNode ( DataFlow :: QualifiedTypeNameNode typeName ) or
509+ MkExplicitTypeNameNode ( string prefix ) { Specific :: needsExplicitTypeNameNode ( _ , prefix ) } or
510+ MkImplicitTypeNameNode ( string prefix ) { Specific :: needsImplicitTypeNameNode ( prefix ) } or
471511 MkForwardNode ( DataFlow:: LocalSourceNode node , TypeTracker t ) { isReachable ( node , t ) } or
472512 /** Intermediate node for following backward data flow. */
473513 MkBackwardNode ( DataFlow:: LocalSourceNode node , TypeTracker t ) { isReachable ( node , t ) } or
@@ -483,27 +523,8 @@ module API {
483523 node = any ( EntryPoint e ) .getASink ( )
484524 }
485525
486- bindingset [ e]
487- pragma [ inline_late]
488- private DataFlow:: Node getNodeFromExpr ( Expr e ) { result .asExpr ( ) .getExpr ( ) = e }
489-
490526 private import frameworks.data.ModelsAsData
491527
492- cached
493- predicate namespace ( string name , Node node ) {
494- exists ( DataFlow:: QualifiedTypeNameNode typeName |
495- typeName .getNamespace ( ) = name and
496- node = MkNamespaceOfTypeNameNode ( typeName )
497- )
498- or
499- exists ( UsingStmt using |
500- using .getName ( ) .toLowerCase ( ) = name and
501- node = MkUsingNode ( using )
502- )
503- or
504- node = ModelOutput:: getATypeNode ( name )
505- }
506-
507528 cached
508529 predicate topLevelMember ( string name , Node node ) { memberEdge ( root ( ) , name , node ) }
509530
@@ -516,83 +537,55 @@ module API {
516537 )
517538 }
518539
519- cached
520- predicate callEdge ( Node pred , string name , Node succ ) {
521- exists ( DataFlow:: CallNode call |
522- // from receiver to method call node
523- pred = getForwardEndNode ( getALocalSourceStrict ( call .getQualifier ( ) ) ) and
524- succ = MkMethodAccessNode ( call ) and
525- name = call .getLowerCaseName ( )
526- )
527- }
528-
529- bindingset [ name]
530- private string memberOrMethodReturnValue ( string name ) {
531- // This predicate is a bit ad-hoc, but it's okay for now.
532- // We can delete it once we no longer use the typeModel and summaryModel
533- // tables to represent implicit root members.
534- result = "Method[" + name + "]"
535- or
536- result = "Method[" + name + "].ReturnValue"
537- or
538- result = "Member[" + name + "]"
539- }
540-
541- private Node getAnImplicitRootMember ( string name ) {
542- exists ( DataFlow:: CallNode call |
543- Extensions:: typeModel ( _, Specific:: getAnImplicitImport ( ) , memberOrMethodReturnValue ( name ) )
544- or
545- Extensions:: summaryModel ( Specific:: getAnImplicitImport ( ) , memberOrMethodReturnValue ( name ) ,
546- _, _, _, _)
547- or
548- Extensions:: sourceModel ( Specific:: getAnImplicitImport ( ) , memberOrMethodReturnValue ( name ) , _,
549- _)
550- |
551- result = MkMethodAccessNode ( call ) and
552- name = call .getLowerCaseName ( )
553- )
554- }
555-
556540 cached
557541 predicate memberEdge ( Node pred , string name , Node succ ) {
558542 pred = API:: root ( ) and
559543 (
560- exists ( StringConstExpr read |
561- succ = getForwardStartNode ( getNodeFromExpr ( read ) ) and
562- name = read .getValueString ( )
563- )
544+ succ .( TypeNameNode ) .getTypeName ( ) = name
564545 or
565546 exists ( DataFlow:: AutomaticVariableNode automatic |
566547 automatic .getLowerCaseName ( ) = name and
567548 succ = getForwardStartNode ( automatic )
568549 )
569- or
570- succ = getAnImplicitRootMember ( name )
571550 )
572551 or
573- exists ( DataFlow :: QualifiedTypeNameNode typeName |
574- typeName .getLowerCaseName ( ) = name and
575- pred = MkNamespaceOfTypeNameNode ( typeName ) and
576- succ = getForwardStartNode ( typeName )
552+ exists ( TypeNameNode typeName | pred = typeName |
553+ typeName .getSuccessor ( name ) = succ
554+ or
555+ typeName . memberEdge ( name ) = succ
577556 )
578557 or
579- exists ( MemberExprReadAccess read |
580- read .getLowerCaseMemberName ( ) .toLowerCase ( ) = name and
581- pred = getForwardEndNode ( getALocalSourceStrict ( getNodeFromExpr ( read .getQualifier ( ) ) ) ) and
582- succ = getForwardStartNode ( getNodeFromExpr ( read ) )
558+ exists ( DataFlow:: Node qualifier | pred = getForwardEndNode ( getALocalSourceStrict ( qualifier ) ) |
559+ exists ( CfgNodes:: ExprNodes:: MemberExprReadAccessCfgNode read |
560+ read .getQualifier ( ) = qualifier .asExpr ( ) and
561+ read .getLowerCaseMemberName ( ) = name and
562+ succ = getForwardStartNode ( DataFlow:: exprNode ( read ) )
563+ )
564+ or
565+ exists ( DataFlow:: CallNode call |
566+ call .getLowerCaseName ( ) = name and
567+ call .getQualifier ( ) = qualifier and
568+ succ = MkMethodAccessNode ( call )
569+ )
583570 )
584571 }
585572
586573 cached
587574 predicate methodEdge ( Node pred , string name , Node succ ) {
588575 exists ( DataFlow:: CallNode call |
589- succ = MkMethodAccessNode ( call ) and name = call . getLowerCaseName ( )
590- |
576+ succ = MkMethodAccessNode ( call ) and
577+ name = call . getLowerCaseName ( ) and
591578 pred = getForwardEndNode ( getALocalSourceStrict ( call .getQualifier ( ) ) )
592579 )
593580 or
581+ pred .( TypeNameNode ) .methodEdge ( name ) = succ
582+ or
594583 pred = API:: root ( ) and
595- succ = getAnImplicitRootMember ( name )
584+ exists ( DataFlow:: CallNode call |
585+ not exists ( call .getQualifier ( ) ) and
586+ succ = MkMethodAccessNode ( call ) and
587+ name = call .getLowerCaseName ( )
588+ )
596589 }
597590
598591 cached
@@ -617,11 +610,6 @@ module API {
617610 )
618611 }
619612
620- cached
621- predicate fieldEdge ( Node pred , string name , Node succ ) {
622- Impl:: contentEdge ( pred , DataFlowPrivate:: TFieldContent ( name ) , succ )
623- }
624-
625613 cached
626614 predicate elementEdge ( Node pred , Node succ ) {
627615 contentEdge ( pred , any ( DataFlow:: ContentSet set | set .isAnyElement ( ) ) .getAReadContent ( ) , succ )
@@ -665,24 +653,13 @@ module API {
665653 ) , succ )
666654 }
667655
668- private predicate keywordParameterEdge ( Node pred , string name , Node succ ) {
669- parameterEdge ( pred , any ( DataFlowDispatch:: ParameterPosition pos | pos .isKeyword ( name ) ) , succ )
670- }
671-
672656 cached
673657 predicate positionalParameterOrArgumentEdge ( Node pred , int n , Node succ ) {
674658 positionalArgumentEdge ( pred , n , succ )
675659 or
676660 positionalParameterEdge ( pred , n , succ )
677661 }
678662
679- cached
680- predicate keywordParameterOrArgumentEdge ( Node pred , string name , Node succ ) {
681- keywordArgumentEdge ( pred , name , succ )
682- or
683- keywordParameterEdge ( pred , name , succ )
684- }
685-
686663 cached
687664 predicate instanceEdge ( Node pred , Node succ ) {
688665 // TODO: Also model parameters with a given type here
0 commit comments