@@ -125,7 +125,7 @@ private class JQueryDomElementDefinition extends DOM::ElementDefinition, @callex
125125/**
126126 * An attribute defined using jQuery APIs.
127127 */
128- abstract private class JQueryAttributeDefinition extends DOM:: AttributeDefinition { }
128+ abstract private class JQueryAttributeDefinition extends DOM:: AttributeDefinition { }
129129
130130/**
131131 * An attribute definition supplied when constructing a DOM element using `$(...)`.
@@ -149,18 +149,20 @@ private class JQueryAttributeDefinitionInElement extends JQueryAttributeDefiniti
149149 override DOM:: ElementDefinition getElement ( ) { result = elt }
150150}
151151
152+ /** Gets the `attr` or `prop` string. */
153+ private string attrOrProp ( ) {
154+ result = "attr" or result = "prop"
155+ }
156+
152157/**
153158 * An attribute definition using `elt.attr(name, value)` or `elt.prop(name, value)`
154159 * where `elt` is a wrapped set.
155160 */
156161private class JQueryAttr2Call extends JQueryAttributeDefinition , @callexpr {
157- JQueryDomElementDefinition elt ;
158-
159162 JQueryAttr2Call ( ) {
160- exists ( MethodCallExpr mce | this = mce |
161- mce .getReceiver ( ) .( DOM:: Element ) .getDefinition ( ) = elt and
162- ( mce .getMethodName ( ) = "attr" or mce .getMethodName ( ) = "prop" ) and
163- mce .getNumArgument ( ) = 2
163+ exists ( DataFlow:: MethodCallNode call | this = call .asExpr ( ) |
164+ call = JQuery:: objectRef ( ) .getAMethodCall ( attrOrProp ( ) ) and
165+ call .getNumArgument ( ) = 2
164166 )
165167 }
166168
@@ -170,57 +172,63 @@ private class JQueryAttr2Call extends JQueryAttributeDefinition, @callexpr {
170172 result = DataFlow:: valueNode ( this .( CallExpr ) .getArgument ( 1 ) )
171173 }
172174
173- override DOM:: ElementDefinition getElement ( ) { result = elt }
175+ override DOM:: ElementDefinition getElement ( ) {
176+ exists ( DataFlow:: MethodCallNode call | this = call .asExpr ( ) |
177+ result = call .getReceiver ( ) .getALocalSource ( ) .asExpr ( ) .( DOM:: Element ) .getDefinition ( )
178+ )
179+ }
174180}
175181
176182/**
177183 * Holds if `mce` is a call to `elt.attr(attributes)` or `elt.prop(attributes)`.
178184 */
179- private predicate bulkAttributeInit (
180- MethodCallExpr mce , JQueryDomElementDefinition elt , DataFlow:: SourceNode attributes
181- ) {
182- mce .getReceiver ( ) .( DOM:: Element ) .getDefinition ( ) = elt and
183- ( mce .getMethodName ( ) = "attr" or mce .getMethodName ( ) = "prop" ) and
185+ private predicate bulkAttributeInit ( DataFlow:: MethodCallNode mce , DataFlow:: SourceNode attributes ) {
186+ mce = JQuery:: objectRef ( ) .getAMethodCall ( attrOrProp ( ) ) and
184187 mce .getNumArgument ( ) = 1 and
185- attributes .flowsToExpr ( mce .getArgument ( 0 ) )
188+ attributes .flowsTo ( mce .getArgument ( 0 ) )
186189}
187190
188191/**
189- * An attribute definition using `elt.attr(attributes)` or `elt.prop(attributes)`
190- * where `elt` is a wrapped set and `attributes` is an object of attribute-value pairs
191- * to set.
192+ * A property stored on an object flowing to `elt.attr(attributes)` or `elt.prop(attributes)`
193+ * where `elt` is a wrapped set.
194+ *
195+ * To avoid spurious combinations of `getName()` and `getValueNode()`,
196+ * this class is tied to an individual property write, as opposed to the call itself.
192197 */
193- private class JQueryAttrCall extends JQueryAttributeDefinition , @callexpr {
194- JQueryDomElementDefinition elt ;
198+ private class JQueryBulkAttributeProp extends JQueryAttributeDefinition {
195199 DataFlow:: PropWrite pwn ;
196200
197- JQueryAttrCall ( ) {
201+ JQueryBulkAttributeProp ( ) {
198202 exists ( DataFlow:: SourceNode attributes |
199- bulkAttributeInit ( this , elt , attributes ) and
200- attributes .flowsTo ( pwn .getBase ( ) )
203+ bulkAttributeInit ( _, attributes ) and
204+ pwn = attributes .getAPropertyWrite ( ) and
205+ this = pwn .getAstNode ( )
201206 )
202207 }
203208
204209 override string getName ( ) { result = pwn .getPropertyName ( ) }
205210
206211 override DataFlow:: Node getValueNode ( ) { result = pwn .getRhs ( ) }
207212
208- override DOM:: ElementDefinition getElement ( ) { result = elt }
213+ override DOM:: ElementDefinition getElement ( ) {
214+ exists ( DataFlow:: MethodCallNode mce |
215+ bulkAttributeInit ( mce , pwn .getBase ( ) .getALocalSource ( ) ) and
216+ result = mce .getReceiver ( ) .asExpr ( ) .( DOM:: Element ) .getDefinition ( )
217+ )
218+ }
209219}
210220
211221/**
212222 * An attribute definition using `jQuery.attr(elt, name, value)` or `jQuery.prop(elt, name, value)`
213223 * where `elt` is a wrapped set or a plain DOM element.
214224 */
215225private class JQueryAttr3Call extends JQueryAttributeDefinition , @callexpr {
216- DOM :: ElementDefinition elt ;
226+ MethodCallExpr mce ;
217227
218228 JQueryAttr3Call ( ) {
219- exists ( MethodCallExpr mce | this = mce |
220- mce = jquery ( ) .getAMemberCall ( any ( string m | m = "attr" or m = "prop" ) ) .asExpr ( ) and
221- mce .getArgument ( 0 ) .( DOM:: Element ) .getDefinition ( ) = elt and
222- mce .getNumArgument ( ) = 3
223- )
229+ this = mce and
230+ mce = jquery ( ) .getAMemberCall ( attrOrProp ( ) ) .asExpr ( ) and
231+ mce .getNumArgument ( ) = 3
224232 }
225233
226234 override string getName ( ) { result = this .( CallExpr ) .getArgument ( 1 ) .getStringValue ( ) }
@@ -229,7 +237,9 @@ private class JQueryAttr3Call extends JQueryAttributeDefinition, @callexpr {
229237 result = DataFlow:: valueNode ( this .( CallExpr ) .getArgument ( 2 ) )
230238 }
231239
232- override DOM:: ElementDefinition getElement ( ) { result = elt }
240+ override DOM:: ElementDefinition getElement ( ) {
241+ result = mce .getArgument ( 0 ) .( DOM:: Element ) .getDefinition ( )
242+ }
233243}
234244
235245/**
0 commit comments