@@ -35,7 +35,8 @@ module Vue {
3535 result =
3636 [
3737 "beforeCreate" , "created" , "beforeMount" , "mounted" , "beforeUpdate" , "updated" , "activated" ,
38- "deactivated" , "beforeDestroy" , "destroyed" , "errorCaptured"
38+ "deactivated" , "beforeDestroy" , "destroyed" , "errorCaptured" , "beforeRouteEnter" ,
39+ "beforeRouteUpdate" , "beforeRouteLeave"
3940 ]
4041 }
4142
@@ -162,6 +163,13 @@ module Vue {
162163 result = getAsClassComponent ( ) .getDecoratorOption ( name )
163164 }
164165
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+
165173 /**
166174 * Gets the template element used by this instance, if any.
167175 */
@@ -189,36 +197,54 @@ module Vue {
189197 /**
190198 * Gets the node for the `template` option of this instance.
191199 */
192- DataFlow:: Node getTemplate ( ) { result = getOption ( "template" ) }
200+ pragma [ nomagic]
201+ DataFlow:: SourceNode getTemplate ( ) { result = getOptionSource ( "template" ) }
193202
194203 /**
195204 * Gets the node for the `render` option of this instance.
196205 */
197- DataFlow:: Node getRender ( ) {
198- result = getOption ( "render" )
206+ pragma [ nomagic]
207+ DataFlow:: SourceNode getRender ( ) {
208+ result = getOptionSource ( "render" )
199209 or
200210 result = getAsClassComponent ( ) .getInstanceMethod ( "render" )
201211 }
202212
203213 /**
204214 * Gets the node for the `methods` option of this instance.
205215 */
206- DataFlow:: Node getMethods ( ) { result = getOption ( "methods" ) }
216+ pragma [ nomagic]
217+ DataFlow:: SourceNode getMethods ( ) { result = getOptionSource ( "methods" ) }
207218
208219 /**
209220 * Gets the node for the `computed` option of this instance.
210221 */
211- DataFlow:: Node getComputed ( ) { result = getOption ( "computed" ) }
222+ pragma [ nomagic]
223+ DataFlow:: SourceNode getComputed ( ) { result = getOptionSource ( "computed" ) }
212224
213225 /**
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`.
215233 */
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" )
221239 )
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 ( )
222248 or
223249 result = getAsClassComponent ( ) .getAnInstanceMethod ( ) and
224250 not result = getAsClassComponent ( ) .getInstanceMethod ( [ lifecycleHookName ( ) , "render" , "data" ] )
@@ -227,19 +253,11 @@ module Vue {
227253 /**
228254 * Gets a node for a member of the `computed` option of this instance that matches `kind`.
229255 */
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 ) )
243261 or
244262 result = getAsClassComponent ( ) .getAnInstanceMember ( kind ) and
245263 kind .isAccessor ( )
@@ -248,18 +266,10 @@ module Vue {
248266 /**
249267 * Gets a node for a member `name` of the `computed` option of this instance that matches `kind`.
250268 */
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 ) )
263273 or
264274 result = getAsClassComponent ( ) .getInstanceMember ( name , kind ) and
265275 kind .isAccessor ( )
@@ -268,11 +278,11 @@ module Vue {
268278 /**
269279 * Gets the node for the life cycle hook of the `hookName` option of this instance.
270280 */
271- pragma [ noinline ]
272- private DataFlow:: Node getALifecycleHook ( string hookName ) {
281+ pragma [ nomagic ]
282+ DataFlow:: SourceNode getALifecycleHook ( string hookName ) {
273283 hookName = lifecycleHookName ( ) and
274284 (
275- result = getOption ( hookName )
285+ result = getOptionSource ( hookName )
276286 or
277287 result = getAsClassComponent ( ) .getInstanceMethod ( hookName )
278288 )
@@ -281,16 +291,21 @@ module Vue {
281291 /**
282292 * Gets a node for a function that will be invoked with `this` bound to this instance.
283293 */
284- DataFlow:: Node getABoundFunction ( ) {
294+ DataFlow:: FunctionNode getABoundFunction ( ) {
285295 result = getAMethod ( )
286296 or
287297 result = getAnAccessor ( _)
288298 or
289299 result = getALifecycleHook ( _)
300+ or
301+ result = getOptionSource ( _)
302+ or
303+ result = getOptionSource ( _) .getAPropertySource ( )
290304 }
291305
292306 /**
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.
294309 */
295310 DataFlow:: Node getAPropertyValue ( string name ) {
296311 exists ( DataFlow:: SourceNode obj | obj .getAPropertyWrite ( name ) .getRhs ( ) = result |
@@ -552,4 +567,67 @@ module Vue {
552567 HTML:: Element getElement ( ) { result = elem }
553568 }
554569 }
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+ }
555633}
0 commit comments