@@ -35,7 +35,8 @@ module Vue {
35
35
result =
36
36
[
37
37
"beforeCreate" , "created" , "beforeMount" , "mounted" , "beforeUpdate" , "updated" , "activated" ,
38
- "deactivated" , "beforeDestroy" , "destroyed" , "errorCaptured"
38
+ "deactivated" , "beforeDestroy" , "destroyed" , "errorCaptured" , "beforeRouteEnter" ,
39
+ "beforeRouteUpdate" , "beforeRouteLeave"
39
40
]
40
41
}
41
42
@@ -162,6 +163,13 @@ module Vue {
162
163
result = getAsClassComponent ( ) .getDecoratorOption ( name )
163
164
}
164
165
166
+ /**
167
+ * Gets a source node flowing into the option `name` of this instance, including those from
168
+ * extended objects and mixins.
169
+ */
170
+ pragma [ nomagic]
171
+ DataFlow:: SourceNode getOptionSource ( string name ) { result = getOption ( name ) .getALocalSource ( ) }
172
+
165
173
/**
166
174
* Gets the template element used by this instance, if any.
167
175
*/
@@ -189,36 +197,54 @@ module Vue {
189
197
/**
190
198
* Gets the node for the `template` option of this instance.
191
199
*/
192
- DataFlow:: Node getTemplate ( ) { result = getOption ( "template" ) }
200
+ pragma [ nomagic]
201
+ DataFlow:: SourceNode getTemplate ( ) { result = getOptionSource ( "template" ) }
193
202
194
203
/**
195
204
* Gets the node for the `render` option of this instance.
196
205
*/
197
- DataFlow:: Node getRender ( ) {
198
- result = getOption ( "render" )
206
+ pragma [ nomagic]
207
+ DataFlow:: SourceNode getRender ( ) {
208
+ result = getOptionSource ( "render" )
199
209
or
200
210
result = getAsClassComponent ( ) .getInstanceMethod ( "render" )
201
211
}
202
212
203
213
/**
204
214
* Gets the node for the `methods` option of this instance.
205
215
*/
206
- DataFlow:: Node getMethods ( ) { result = getOption ( "methods" ) }
216
+ pragma [ nomagic]
217
+ DataFlow:: SourceNode getMethods ( ) { result = getOptionSource ( "methods" ) }
207
218
208
219
/**
209
220
* Gets the node for the `computed` option of this instance.
210
221
*/
211
- DataFlow:: Node getComputed ( ) { result = getOption ( "computed" ) }
222
+ pragma [ nomagic]
223
+ DataFlow:: SourceNode getComputed ( ) { result = getOptionSource ( "computed" ) }
212
224
213
225
/**
214
- * Gets a node for a member of the `methods` option of this instance.
226
+ * Gets the node for the `watch` option of this instance.
227
+ */
228
+ pragma [ nomagic]
229
+ DataFlow:: SourceNode getWatch ( ) { result = getOptionSource ( "watch" ) }
230
+
231
+ /**
232
+ * Gets the function responding to changes to the given `propName`.
215
233
*/
216
- pragma [ noinline ]
217
- private DataFlow:: Node getAMethod ( ) {
218
- exists ( DataFlow :: ObjectLiteralNode methods |
219
- methods . flowsTo ( getMethods ( ) ) and
220
- result = methods . getAPropertyWrite ( ) . getRhs ( )
234
+ DataFlow :: FunctionNode getWatchHandler ( string propName ) {
235
+ exists ( DataFlow:: SourceNode watcher | watcher = getWatch ( ) . getAPropertySource ( propName ) |
236
+ result = watcher
237
+ or
238
+ result = watcher . getAPropertySource ( "handler" )
221
239
)
240
+ }
241
+
242
+ /**
243
+ * Gets a node for a member of the `methods` option of this instance.
244
+ */
245
+ pragma [ nomagic]
246
+ private DataFlow:: SourceNode getAMethod ( ) {
247
+ result = getMethods ( ) .getAPropertySource ( )
222
248
or
223
249
result = getAsClassComponent ( ) .getAnInstanceMethod ( ) and
224
250
not result = getAsClassComponent ( ) .getInstanceMethod ( [ lifecycleHookName ( ) , "render" , "data" ] )
@@ -227,19 +253,11 @@ module Vue {
227
253
/**
228
254
* Gets a node for a member of the `computed` option of this instance that matches `kind`.
229
255
*/
230
- pragma [ noinline]
231
- private DataFlow:: Node getAnAccessor ( DataFlow:: MemberKind kind ) {
232
- exists ( DataFlow:: ObjectLiteralNode computedObj , DataFlow:: Node accessorObjOrGetter |
233
- computedObj .flowsTo ( getComputed ( ) ) and
234
- computedObj .getAPropertyWrite ( ) .getRhs ( ) = accessorObjOrGetter
235
- |
236
- result = accessorObjOrGetter and kind = DataFlow:: MemberKind:: getter ( )
237
- or
238
- exists ( DataFlow:: ObjectLiteralNode accessorObj |
239
- accessorObj .flowsTo ( accessorObjOrGetter ) and
240
- result = accessorObj .getAPropertyWrite ( memberKindVerb ( kind ) ) .getRhs ( )
241
- )
242
- )
256
+ pragma [ nomagic]
257
+ private DataFlow:: SourceNode getAnAccessor ( DataFlow:: MemberKind kind ) {
258
+ result = getComputed ( ) .getAPropertySource ( ) and kind = DataFlow:: MemberKind:: getter ( )
259
+ or
260
+ result = getComputed ( ) .getAPropertySource ( ) .getAPropertySource ( memberKindVerb ( kind ) )
243
261
or
244
262
result = getAsClassComponent ( ) .getAnInstanceMember ( kind ) and
245
263
kind .isAccessor ( )
@@ -248,18 +266,10 @@ module Vue {
248
266
/**
249
267
* Gets a node for a member `name` of the `computed` option of this instance that matches `kind`.
250
268
*/
251
- private DataFlow:: Node getAccessor ( string name , DataFlow:: MemberKind kind ) {
252
- exists ( DataFlow:: ObjectLiteralNode computedObj , DataFlow:: SourceNode accessorObjOrGetter |
253
- computedObj .flowsTo ( getComputed ( ) ) and
254
- accessorObjOrGetter .flowsTo ( computedObj .getAPropertyWrite ( name ) .getRhs ( ) )
255
- |
256
- result = accessorObjOrGetter and kind = DataFlow:: MemberKind:: getter ( )
257
- or
258
- exists ( DataFlow:: ObjectLiteralNode accessorObj |
259
- accessorObj .flowsTo ( accessorObjOrGetter ) and
260
- result = accessorObj .getAPropertyWrite ( memberKindVerb ( kind ) ) .getRhs ( )
261
- )
262
- )
269
+ private DataFlow:: SourceNode getAccessor ( string name , DataFlow:: MemberKind kind ) {
270
+ result = getComputed ( ) .getAPropertySource ( name ) and kind = DataFlow:: MemberKind:: getter ( )
271
+ or
272
+ result = getComputed ( ) .getAPropertySource ( name ) .getAPropertySource ( memberKindVerb ( kind ) )
263
273
or
264
274
result = getAsClassComponent ( ) .getInstanceMember ( name , kind ) and
265
275
kind .isAccessor ( )
@@ -268,11 +278,11 @@ module Vue {
268
278
/**
269
279
* Gets the node for the life cycle hook of the `hookName` option of this instance.
270
280
*/
271
- pragma [ noinline ]
272
- private DataFlow:: Node getALifecycleHook ( string hookName ) {
281
+ pragma [ nomagic ]
282
+ DataFlow:: SourceNode getALifecycleHook ( string hookName ) {
273
283
hookName = lifecycleHookName ( ) and
274
284
(
275
- result = getOption ( hookName )
285
+ result = getOptionSource ( hookName )
276
286
or
277
287
result = getAsClassComponent ( ) .getInstanceMethod ( hookName )
278
288
)
@@ -281,16 +291,21 @@ module Vue {
281
291
/**
282
292
* Gets a node for a function that will be invoked with `this` bound to this instance.
283
293
*/
284
- DataFlow:: Node getABoundFunction ( ) {
294
+ DataFlow:: FunctionNode getABoundFunction ( ) {
285
295
result = getAMethod ( )
286
296
or
287
297
result = getAnAccessor ( _)
288
298
or
289
299
result = getALifecycleHook ( _)
300
+ or
301
+ result = getOptionSource ( _)
302
+ or
303
+ result = getOptionSource ( _) .getAPropertySource ( )
290
304
}
291
305
292
306
/**
293
- * Gets a node for the value for property `name` of this instance.
307
+ * Gets the data flow node that flows into the property `name` of this instance, or is
308
+ * returned form a getter defining that property.
294
309
*/
295
310
DataFlow:: Node getAPropertyValue ( string name ) {
296
311
exists ( DataFlow:: SourceNode obj | obj .getAPropertyWrite ( name ) .getRhs ( ) = result |
@@ -552,4 +567,67 @@ module Vue {
552
567
HTML:: Element getElement ( ) { result = elem }
553
568
}
554
569
}
570
+
571
+ /** An API node referring to a `RouteConfig` being passed to `vue-router`. */
572
+ private API:: Node routeConfig ( ) {
573
+ result = API:: moduleImport ( "vue-router" ) .getParameter ( 0 ) .getMember ( "routes" ) .getAMember ( )
574
+ or
575
+ result = routeConfig ( ) .getMember ( "children" ) .getAMember ( )
576
+ }
577
+
578
+ /** Gets a data flow node that refers to a `Route` object from `vue-router`. */
579
+ private DataFlow:: SourceNode routeObject ( DataFlow:: TypeTracker t ) {
580
+ t .start ( ) and
581
+ (
582
+ exists ( API:: Node router | router = API:: moduleImport ( "vue-router" ) |
583
+ result = router .getInstance ( ) .getMember ( "currentRoute" ) .getAnImmediateUse ( )
584
+ or
585
+ result =
586
+ router
587
+ .getInstance ( )
588
+ .getMember ( [ "beforeEach" , "beforeResolve" , "afterEach" ] )
589
+ .getParameter ( 0 )
590
+ .getParameter ( [ 0 , 1 ] )
591
+ .getAnImmediateUse ( )
592
+ or
593
+ result =
594
+ router
595
+ .getParameter ( 0 )
596
+ .getMember ( "scrollBehavior" )
597
+ .getParameter ( [ 0 , 1 ] )
598
+ .getAnImmediateUse ( )
599
+ )
600
+ or
601
+ result = routeConfig ( ) .getMember ( "beforeEnter" ) .getParameter ( [ 0 , 1 ] ) .getAnImmediateUse ( )
602
+ or
603
+ exists ( Instance i |
604
+ result = i .getABoundFunction ( ) .getAFunctionValue ( ) .getReceiver ( ) .getAPropertyRead ( "$route" )
605
+ or
606
+ result =
607
+ i .getALifecycleHook ( [ "beforeRouteEnter" , "beforeRouteUpdate" , "beforeRouteLeave" ] )
608
+ .getAFunctionValue ( )
609
+ .getParameter ( [ 0 , 1 ] )
610
+ or
611
+ result = i .getWatchHandler ( "$route" ) .getParameter ( [ 0 , 1 ] )
612
+ )
613
+ )
614
+ or
615
+ exists ( DataFlow:: TypeTracker t2 | result = routeObject ( t2 ) .track ( t2 , t ) )
616
+ }
617
+
618
+ /** Gets a data flow node that refers to a `Route` object from `vue-router`. */
619
+ DataFlow:: SourceNode routeObject ( ) { result = routeObject ( DataFlow:: TypeTracker:: end ( ) ) }
620
+
621
+ private class VueRouterFlowSource extends RemoteFlowSource {
622
+ VueRouterFlowSource ( ) {
623
+ this = routeObject ( ) .getAPropertyRead ( [ "params" , "query" , "hash" , "path" , "fullPath" ] )
624
+ or
625
+ exists ( Instance i , string prop |
626
+ this = i .getWatchHandler ( prop ) .getParameter ( [ 0 , 1 ] ) and
627
+ prop .regexpMatch ( "\\$route\\.(params|query|hash|path|fullPath)\\b.*" )
628
+ )
629
+ }
630
+
631
+ override string getSourceType ( ) { result = "Vue route parameter" }
632
+ }
555
633
}
0 commit comments