88import javascript
99private import semmle.javascript.dataflow.internal.FlowSteps as FlowSteps
1010private import semmle.javascript.dataflow.internal.PreCallGraphStep
11+ private import semmle.javascript.dataflow.internal.StepSummary
12+ private import semmle.javascript.dataflow.internal.sharedlib.SummaryTypeTracker as SummaryTypeTracker
13+ private import semmle.javascript.dataflow.internal.Contents:: Private as ContentPrivate
14+ private import semmle.javascript.DynamicPropertyAccess
1115private import internal.CachedStages
1216
1317/**
@@ -220,15 +224,53 @@ module API {
220224 }
221225
222226 /**
223- * Gets a node representing a member of this API component where the name of the member is
224- * not known statically.
227+ * DEPRECATED. Use either `getArrayElement()` or `getAMember()` instead.
225228 */
229+ deprecated Node getUnknownMember ( ) { result = this .getArrayElement ( ) }
230+
231+ /**
232+ * Gets an array element of unknown index.
233+ */
234+ cached
235+ Node getUnknownArrayElement ( ) {
236+ Stages:: ApiStage:: ref ( ) and
237+ result = this .getASuccessor ( Label:: content ( ContentPrivate:: MkArrayElementUnknown ( ) ) )
238+ }
239+
226240 cached
227- Node getUnknownMember ( ) {
241+ private Node getContentRaw ( DataFlow :: Content content ) {
228242 Stages:: ApiStage:: ref ( ) and
229- result = this .getASuccessor ( Label:: unknownMember ( ) )
243+ result = this .getASuccessor ( Label:: content ( content ) )
230244 }
231245
246+ /**
247+ * Gets a representative for the `content` of this value.
248+ *
249+ * When possible, it is preferrable to use one of the specialized variants of this predicate, such as `getMember`.
250+ */
251+ pragma [ inline]
252+ Node getContent ( DataFlow:: Content content ) {
253+ result = this .getContentRaw ( content )
254+ or
255+ result = this .getMember ( content .asPropertyName ( ) )
256+ }
257+
258+ /**
259+ * Gets a representative for the `contents` of this value.
260+ */
261+ bindingset [ contents]
262+ pragma [ inline_late]
263+ private Node getContents ( DataFlow:: ContentSet contents ) {
264+ // We always use getAStoreContent when generating content edges, and we always use getAReadContent when querying the graph.
265+ result = this .getContent ( contents .getAReadContent ( ) )
266+ }
267+
268+ /**
269+ * Gets a node representing an arbitrary array element in the array represented by this node.
270+ */
271+ cached
272+ Node getArrayElement ( ) { result = this .getContents ( DataFlow:: ContentSet:: arrayElement ( ) ) }
273+
232274 /**
233275 * Gets a node representing a member of this API component where the name of the member may
234276 * or may not be known statically.
@@ -238,7 +280,7 @@ module API {
238280 Stages:: ApiStage:: ref ( ) and
239281 result = this .getMember ( _)
240282 or
241- result = this .getUnknownMember ( )
283+ result = this .getUnknownArrayElement ( )
242284 }
243285
244286 /**
@@ -790,6 +832,11 @@ module API {
790832 not DataFlow:: PseudoProperties:: isPseudoProperty ( prop )
791833 )
792834 or
835+ exists ( DataFlow:: ContentSet contents |
836+ SummaryTypeTracker:: basicStoreStep ( rhs , pred .getALocalUse ( ) , contents ) and
837+ lbl = Label:: content ( contents .getAStoreContent ( ) )
838+ )
839+ or
793840 exists ( DataFlow:: FunctionNode fn |
794841 fn = pred and
795842 lbl = Label:: return ( )
@@ -982,6 +1029,11 @@ module API {
9821029 // avoid generating member edges like "$arrayElement$"
9831030 not DataFlow:: PseudoProperties:: isPseudoProperty ( prop )
9841031 )
1032+ or
1033+ exists ( DataFlow:: ContentSet contents |
1034+ SummaryTypeTracker:: basicLoadStep ( pred .getALocalUse ( ) , ref , contents ) and
1035+ lbl = Label:: content ( contents .getAStoreContent ( ) )
1036+ )
9851037 )
9861038 or
9871039 exists ( DataFlow:: Node def , DataFlow:: FunctionNode fn |
@@ -1199,8 +1251,6 @@ module API {
11991251 t = useStep ( nd , promisified , boundArgs , prop , result )
12001252 }
12011253
1202- private import semmle.javascript.dataflow.internal.StepSummary
1203-
12041254 /**
12051255 * Holds if `nd`, which is a use of an API-graph node, flows in zero or more potentially
12061256 * inter-procedural steps to some intermediate node, and then from that intermediate node to
@@ -1458,8 +1508,21 @@ module API {
14581508 bindingset [ result ]
14591509 LabelMember member ( string m ) { result .getProperty ( ) = m }
14601510
1461- /** Gets the `member` edge label for the unknown member. */
1462- LabelUnknownMember unknownMember ( ) { any ( ) }
1511+ /** Gets the `content` edge label for content `c`. */
1512+ LabelContent content ( ContentPrivate:: Content c ) { result .getContent ( ) = c }
1513+
1514+ /**
1515+ * Gets the edge label for an unknown member.
1516+ *
1517+ * Currently this is represented the same way as an unknown array element, but this may
1518+ * change in the future.
1519+ */
1520+ ApiLabel unknownMember ( ) { result = arrayElement ( ) }
1521+
1522+ /**
1523+ * Gets the edge label for an unknown array element.
1524+ */
1525+ LabelContent arrayElement ( ) { result .getContent ( ) .isUnknownArrayElement ( ) }
14631526
14641527 /**
14651528 * Gets a property name referred to by the given dynamic property access,
@@ -1482,6 +1545,11 @@ module API {
14821545 result = unique( string s | s = getAnIndirectPropName ( ref ) )
14831546 }
14841547
1548+ pragma [ nomagic]
1549+ private predicate isEnumeratedPropName ( DataFlow:: Node node ) {
1550+ node .getAPredecessor * ( ) instanceof EnumeratedPropName
1551+ }
1552+
14851553 /** Gets the `member` edge label for the given property reference. */
14861554 ApiLabel memberFromRef ( DataFlow:: PropRef pr ) {
14871555 exists ( string pn | pn = pr .getPropertyName ( ) or pn = getIndirectPropName ( pr ) |
@@ -1493,7 +1561,9 @@ module API {
14931561 or
14941562 not exists ( pr .getPropertyName ( ) ) and
14951563 not exists ( getIndirectPropName ( pr ) ) and
1496- result = unknownMember ( )
1564+ // Avoid assignments in an extend-like pattern
1565+ not isEnumeratedPropName ( pr .getPropertyNameExpr ( ) .flow ( ) ) and
1566+ result = arrayElement ( )
14971567 }
14981568
14991569 /** Gets the `instance` edge label. */
@@ -1516,10 +1586,10 @@ module API {
15161586 LabelForwardingFunction forwardingFunction ( ) { any ( ) }
15171587
15181588 /** Gets the `promised` edge label connecting a promise to its contained value. */
1519- LabelPromised promised ( ) { any ( ) }
1589+ LabelContent promised ( ) { result . getContent ( ) = ContentPrivate :: MkPromiseValue ( ) }
15201590
15211591 /** Gets the `promisedError` edge label connecting a promise to its rejected value. */
1522- LabelPromisedError promisedError ( ) { any ( ) }
1592+ LabelContent promisedError ( ) { result . getContent ( ) = ContentPrivate :: MkPromiseError ( ) }
15231593
15241594 /** Gets the label for an edge leading from a value `D` to any class that has `D` as a decorator. */
15251595 LabelDecoratedClass decoratedClass ( ) { any ( ) }
@@ -1542,18 +1612,12 @@ module API {
15421612 exists ( Impl:: MkModuleImport ( mod ) )
15431613 } or
15441614 MkLabelInstance ( ) or
1545- MkLabelMember ( string prop ) {
1546- exports ( _, prop , _) or
1547- exists ( any ( DataFlow:: ClassNode c ) .getInstanceMethod ( prop ) ) or
1548- prop = "exports" or
1549- prop = any ( CanonicalName c ) .getName ( ) or
1550- prop = any ( DataFlow:: PropRef p ) .getPropertyName ( ) or
1551- exists ( Impl:: MkTypeUse ( _, prop ) ) or
1552- exists ( any ( Module m ) .getAnExportedValue ( prop ) ) or
1553- PreCallGraphStep:: loadStep ( _, _, prop ) or
1554- PreCallGraphStep:: storeStep ( _, _, prop )
1615+ MkLabelContent ( DataFlow:: Content content ) or
1616+ MkLabelMember ( string name ) {
1617+ name instanceof PropertyName
1618+ or
1619+ exists ( Impl:: MkTypeUse ( _, name ) )
15551620 } or
1556- MkLabelUnknownMember ( ) or
15571621 MkLabelParameter ( int i ) {
15581622 i =
15591623 [ 0 .. max ( int args |
@@ -1564,8 +1628,6 @@ module API {
15641628 } or
15651629 MkLabelReceiver ( ) or
15661630 MkLabelReturn ( ) or
1567- MkLabelPromised ( ) or
1568- MkLabelPromisedError ( ) or
15691631 MkLabelDecoratedClass ( ) or
15701632 MkLabelDecoratedMember ( ) or
15711633 MkLabelDecoratedParameter ( ) or
@@ -1585,13 +1647,13 @@ module API {
15851647 }
15861648
15871649 /** A label that gets a promised value. */
1588- class LabelPromised extends ApiLabel , MkLabelPromised {
1589- override string toString ( ) { result = "getPromised()" }
1650+ deprecated class LabelPromised extends ApiLabel {
1651+ LabelPromised ( ) { this = MkLabelContent ( ContentPrivate :: MkPromiseValue ( ) ) }
15901652 }
15911653
15921654 /** A label that gets a rejected promise. */
1593- class LabelPromisedError extends ApiLabel , MkLabelPromisedError {
1594- override string toString ( ) { result = "getPromisedError()" }
1655+ deprecated class LabelPromisedError extends ApiLabel {
1656+ LabelPromisedError ( ) { this = MkLabelContent ( ContentPrivate :: MkPromiseError ( ) ) }
15951657 }
15961658
15971659 /** A label that gets the return value of a function. */
@@ -1617,9 +1679,39 @@ module API {
16171679 override string toString ( ) { result = "getInstance()" }
16181680 }
16191681
1682+ /** A label for a content. */
1683+ class LabelContent extends ApiLabel , MkLabelContent {
1684+ private DataFlow:: Content content ;
1685+
1686+ LabelContent ( ) {
1687+ this = MkLabelContent ( content ) and
1688+ // Property names are represented by LabelMember to ensure additional property
1689+ // names from PreCallGraph step are included, as well as those from MkTypeUse.
1690+ not content instanceof ContentPrivate:: MkPropertyContent
1691+ }
1692+
1693+ /** Gets the content associated with this label. */
1694+ DataFlow:: Content getContent ( ) { result = content }
1695+
1696+ private string specialisedToString ( ) {
1697+ content instanceof ContentPrivate:: MkPromiseValue and result = "getPromised()"
1698+ or
1699+ content instanceof ContentPrivate:: MkPromiseError and result = "getPromisedError()"
1700+ or
1701+ content instanceof ContentPrivate:: MkArrayElementUnknown and result = "getArrayElement()"
1702+ }
1703+
1704+ override string toString ( ) {
1705+ result = this .specialisedToString ( )
1706+ or
1707+ not exists ( this .specialisedToString ( ) ) and
1708+ result = "getContent(" + content + ")"
1709+ }
1710+ }
1711+
16201712 /** A label for the member named `prop`. */
16211713 class LabelMember extends ApiLabel , MkLabelMember {
1622- string prop ;
1714+ private string prop ;
16231715
16241716 LabelMember ( ) { this = MkLabelMember ( prop ) }
16251717
@@ -1630,10 +1722,8 @@ module API {
16301722 }
16311723
16321724 /** A label for a member with an unknown name. */
1633- class LabelUnknownMember extends ApiLabel , MkLabelUnknownMember {
1634- LabelUnknownMember ( ) { this = MkLabelUnknownMember ( ) }
1635-
1636- override string toString ( ) { result = "getUnknownMember()" }
1725+ deprecated class LabelUnknownMember extends LabelContent {
1726+ LabelUnknownMember ( ) { this .getContent ( ) .isUnknownArrayElement ( ) }
16371727 }
16381728
16391729 /** A label for parameter `i`. */
0 commit comments