@@ -30,6 +30,54 @@ module Vue {
3030 MkComponent ( DataFlow:: CallNode def ) { def = vue ( ) .getAMemberCall ( "component" ) } or
3131 MkSingleFileComponent ( VueFile file )
3232
33+ /** Gets the name of a lifecycle hook method. */
34+ private string lifecycleHookName ( ) {
35+ result =
36+ [ "beforeCreate" , "created" , "beforeMount" , "mounted" , "beforeUpdate" , "updated" , "activated" ,
37+ "deactivated" , "beforeDestroy" , "destroyed" , "errorCaptured" ]
38+ }
39+
40+ /** Gets a value that can be used as a `@Component` decorator. */
41+ private DataFlow:: SourceNode componentDecorator ( ) {
42+ result = DataFlow:: moduleImport ( "vue-class-component" )
43+ or
44+ result = DataFlow:: moduleMember ( "vue-property-decorator" , "Component" )
45+ }
46+
47+ /**
48+ * A class with a `@Component` decorator, making it usable as an "options" object in Vue.
49+ */
50+ private class ClassComponent extends DataFlow:: ClassNode {
51+ DataFlow:: Node decorator ;
52+
53+ ClassComponent ( ) {
54+ exists ( ClassDefinition cls |
55+ this = cls .flow ( ) and
56+ cls .getADecorator ( ) .getExpression ( ) = decorator .asExpr ( ) and
57+ (
58+ componentDecorator ( ) .flowsTo ( decorator )
59+ or
60+ componentDecorator ( ) .getACall ( ) = decorator
61+ )
62+ )
63+ }
64+
65+ /**
66+ * Gets an option passed to the `@Component` decorator.
67+ *
68+ * These options correspond to the options one would pass to `new Vue({...})` or similar.
69+ */
70+ DataFlow:: Node getDecoratorOption ( string name ) {
71+ result = decorator .( DataFlow:: CallNode ) .getOptionArgument ( 0 , name )
72+ }
73+ }
74+
75+ private string memberKindVerb ( DataFlow:: MemberKind kind ) {
76+ kind = DataFlow:: MemberKind:: getter ( ) and result = "get"
77+ or
78+ kind = DataFlow:: MemberKind:: setter ( ) and result = "set"
79+ }
80+
3381 /**
3482 * A Vue instance definition.
3583 *
@@ -65,11 +113,27 @@ module Vue {
65113 endcolumn = 0
66114 }
67115
116+ /**
117+ * Gets the options passed to the Vue object, such as the object literal `{...}` in `new Vue{{...})`
118+ * or the default export of a single-file component.
119+ */
120+ abstract DataFlow:: Node getOwnOptionsObject ( ) ;
121+
122+ /**
123+ * Gets the class component implementing this Vue instance, if any.
124+ *
125+ * Specifically, this is a class annotated with `@Component` which flows to the options
126+ * object of this Vue instance.
127+ */
128+ ClassComponent getAsClassComponent ( ) { result .flowsTo ( getOwnOptionsObject ( ) ) }
129+
68130 /**
69131 * Gets the node for option `name` for this instance, this does not include
70132 * those from extended objects and mixins.
71133 */
72- abstract DataFlow:: Node getOwnOption ( string name ) ;
134+ DataFlow:: Node getOwnOption ( string name ) {
135+ result = getOwnOptionsObject ( ) .getALocalSource ( ) .getAPropertyWrite ( name ) .getRhs ( )
136+ }
73137
74138 /**
75139 * Gets the node for option `name` for this instance, including those from
@@ -92,6 +156,8 @@ module Vue {
92156 mixin .flowsTo ( mixins .getAnElement ( ) ) and
93157 result = mixin .getAPropertyWrite ( name ) .getRhs ( )
94158 )
159+ or
160+ result = getAsClassComponent ( ) .getDecoratorOption ( name )
95161 }
96162
97163 /**
@@ -112,6 +178,10 @@ module Vue {
112178 result = f .getAReturn ( )
113179 )
114180 )
181+ or
182+ result = getAsClassComponent ( ) .getAReceiverNode ( )
183+ or
184+ result = getAsClassComponent ( ) .getInstanceMethod ( "data" ) .getAReturn ( )
115185 }
116186
117187 /**
@@ -122,7 +192,11 @@ module Vue {
122192 /**
123193 * Gets the node for the `render` option of this instance.
124194 */
125- DataFlow:: Node getRender ( ) { result = getOption ( "render" ) }
195+ DataFlow:: Node getRender ( ) {
196+ result = getOption ( "render" )
197+ or
198+ result = getAsClassComponent ( ) .getInstanceMethod ( "render" )
199+ }
126200
127201 /**
128202 * Gets the node for the `methods` option of this instance.
@@ -143,62 +217,63 @@ module Vue {
143217 methods .flowsTo ( getMethods ( ) ) and
144218 result = methods .getAPropertyWrite ( ) .getRhs ( )
145219 )
220+ or
221+ result = getAsClassComponent ( ) .getAnInstanceMethod ( ) and
222+ not result = getAsClassComponent ( ) .getInstanceMethod ( [ lifecycleHookName ( ) , "render" , "data" ] )
146223 }
147224
148225 /**
149- * Gets a node for a member of the `computed` option of this instance that matches `kind` ("get" or "set") .
226+ * Gets a node for a member of the `computed` option of this instance that matches `kind`.
150227 */
151228 pragma [ noinline]
152- private DataFlow:: Node getAnAccessor ( string kind ) {
229+ private DataFlow:: Node getAnAccessor ( DataFlow :: MemberKind kind ) {
153230 exists ( DataFlow:: ObjectLiteralNode computedObj , DataFlow:: Node accessorObjOrGetter |
154231 computedObj .flowsTo ( getComputed ( ) ) and
155232 computedObj .getAPropertyWrite ( ) .getRhs ( ) = accessorObjOrGetter
156233 |
157- result = accessorObjOrGetter and kind = "get"
234+ result = accessorObjOrGetter and kind = DataFlow :: MemberKind :: getter ( )
158235 or
159236 exists ( DataFlow:: ObjectLiteralNode accessorObj |
160237 accessorObj .flowsTo ( accessorObjOrGetter ) and
161- result = accessorObj .getAPropertyWrite ( kind ) .getRhs ( )
238+ result = accessorObj .getAPropertyWrite ( memberKindVerb ( kind ) ) .getRhs ( )
162239 )
163240 )
241+ or
242+ result = getAsClassComponent ( ) .getAnInstanceMember ( kind ) and
243+ kind .isAccessor ( )
164244 }
165245
166246 /**
167- * Gets a node for a member `name` of the `computed` option of this instance that matches `kind` ("get" or "set") .
247+ * Gets a node for a member `name` of the `computed` option of this instance that matches `kind`.
168248 */
169- private DataFlow:: Node getAccessor ( string name , string kind ) {
249+ private DataFlow:: Node getAccessor ( string name , DataFlow :: MemberKind kind ) {
170250 exists ( DataFlow:: ObjectLiteralNode computedObj , DataFlow:: SourceNode accessorObjOrGetter |
171251 computedObj .flowsTo ( getComputed ( ) ) and
172252 accessorObjOrGetter .flowsTo ( computedObj .getAPropertyWrite ( name ) .getRhs ( ) )
173253 |
174- result = accessorObjOrGetter and kind = "get"
254+ result = accessorObjOrGetter and kind = DataFlow :: MemberKind :: getter ( )
175255 or
176256 exists ( DataFlow:: ObjectLiteralNode accessorObj |
177257 accessorObj .flowsTo ( accessorObjOrGetter ) and
178- result = accessorObj .getAPropertyWrite ( kind ) .getRhs ( )
258+ result = accessorObj .getAPropertyWrite ( memberKindVerb ( kind ) ) .getRhs ( )
179259 )
180260 )
261+ or
262+ result = getAsClassComponent ( ) .getInstanceMember ( name , kind ) and
263+ kind .isAccessor ( )
181264 }
182265
183266 /**
184267 * Gets the node for the life cycle hook of the `hookName` option of this instance.
185268 */
186269 pragma [ noinline]
187270 private DataFlow:: Node getALifecycleHook ( string hookName ) {
271+ hookName = lifecycleHookName ( ) and
188272 (
189- hookName = "beforeCreate" or
190- hookName = "created" or
191- hookName = "beforeMount" or
192- hookName = "mounted" or
193- hookName = "beforeUpdate" or
194- hookName = "updated" or
195- hookName = "activated" or
196- hookName = "deactivated" or
197- hookName = "beforeDestroy" or
198- hookName = "destroyed" or
199- hookName = "errorCaptured"
200- ) and
201- result = getOption ( hookName )
273+ result = getOption ( hookName )
274+ or
275+ result = getAsClassComponent ( ) .getInstanceMethod ( hookName )
276+ )
202277 }
203278
204279 /**
@@ -227,7 +302,7 @@ module Vue {
227302 )
228303 or
229304 exists ( DataFlow:: FunctionNode getter |
230- getter .flowsTo ( getAccessor ( name , "get" ) ) and
305+ getter .flowsTo ( getAccessor ( name , DataFlow :: MemberKind :: getter ( ) ) ) and
231306 result = getter .getAReturn ( )
232307 )
233308 }
@@ -249,7 +324,7 @@ module Vue {
249324 def .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
250325 }
251326
252- override DataFlow:: Node getOwnOption ( string name ) { result = def .getOptionArgument ( 0 , name ) }
327+ override DataFlow:: Node getOwnOptionsObject ( ) { result = def .getArgument ( 0 ) }
253328
254329 override Template:: Element getTemplateElement ( ) { none ( ) }
255330 }
@@ -270,7 +345,7 @@ module Vue {
270345 extend .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
271346 }
272347
273- override DataFlow:: Node getOwnOption ( string name ) { result = extend .getOptionArgument ( 0 , name ) }
348+ override DataFlow:: Node getOwnOptionsObject ( ) { result = extend .getArgument ( 0 ) }
274349
275350 override Template:: Element getTemplateElement ( ) { none ( ) }
276351 }
@@ -292,7 +367,7 @@ module Vue {
292367 sub .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
293368 }
294369
295- override DataFlow:: Node getOwnOption ( string name ) { result = sub .getOptionArgument ( 0 , name ) }
370+ override DataFlow:: Node getOwnOptionsObject ( ) { result = sub .getArgument ( 0 ) }
296371
297372 override DataFlow:: Node getOption ( string name ) {
298373 result = Instance .super .getOption ( name )
@@ -319,7 +394,7 @@ module Vue {
319394 def .hasLocationInfo ( filepath , startline , startcolumn , endline , endcolumn )
320395 }
321396
322- override DataFlow:: Node getOwnOption ( string name ) { result = def .getOptionArgument ( 1 , name ) }
397+ override DataFlow:: Node getOwnOptionsObject ( ) { result = def .getArgument ( 1 ) }
323398
324399 override Template:: Element getTemplateElement ( ) { none ( ) }
325400 }
@@ -357,6 +432,13 @@ module Vue {
357432 )
358433 }
359434
435+ override DataFlow:: Node getOwnOptionsObject ( ) {
436+ exists ( ExportDefaultDeclaration decl |
437+ decl .getTopLevel ( ) = getModule ( ) and
438+ result = DataFlow:: valueNode ( decl .getOperand ( ) )
439+ )
440+ }
441+
360442 override DataFlow:: Node getOwnOption ( string name ) {
361443 // The options of a single file component are defined by the exported object of the script element.
362444 // Our current module model does not support reads on this object very well, so we use custom steps for the common cases for now.
0 commit comments