Skip to content

JS: Rename Vue::Instance to Vue::Component #6511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
lgtm,codescanning
* The class `Vue::Instance` has been renamed to `Vue::Component`.
2 changes: 1 addition & 1 deletion javascript/ql/src/Vue/ArrowMethodOnVueInstance.ql
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import javascript

from Vue::Instance instance, DataFlow::Node def, DataFlow::FunctionNode arrow, ThisExpr dis
from Vue::Component instance, DataFlow::Node def, DataFlow::FunctionNode arrow, ThisExpr dis
where
instance.getABoundFunction() = def and
arrow.flowsTo(def) and
Expand Down
103 changes: 56 additions & 47 deletions javascript/ql/src/semmle/javascript/frameworks/Vue.qll
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ module Vue {
VueExtend() { this = vue().getAMemberCall("extend") }
}

private newtype TInstance =
private newtype TComponent =
MkVueInstance(DataFlow::NewNode def) { def = vue().getAnInstantiation() } or
MkExtendedVue(VueExtend extend) or
MkExtendedInstance(VueExtend extend, DataFlow::NewNode sub) {
sub = extend.getAnInstantiation()
} or
MkComponent(DataFlow::CallNode def) { def = vue().getAMemberCall("component") } or
MkComponentRegistration(DataFlow::CallNode def) { def = vue().getAMemberCall("component") } or
MkSingleFileComponent(VueFile file)

/** Gets the name of a lifecycle hook method. */
Expand Down Expand Up @@ -82,22 +82,31 @@ module Vue {
}

/**
* A Vue instance definition.
* DEPRECATED. This class has been renamed to `Vue::Component`.
*/
deprecated class Instance = Component;

/**
* A Vue component, such as a `new Vue({ ... })` call or a `.vue` file.
*
* Generally speaking, a component is always created by calling `Vue.extend()` or
* calling `extend` on another component.
* Often the `Vue.extend()` call is performed by the Vue
* framework, however, so the call is not always visible in the user code.
* For instance, `new Vue(obj)` is shorthand for `new (Vue.extend(obj))`.
*
* This includes both explicit instantiations of Vue objects, and
* implicit instantiations in the form of components or Vue
* extensions that have not yet been instantiated to a Vue instance.
* This class covers both the explicit `Vue.extend()` calls an those implicit in the framework.
*
* The following instances are recognized:
* The following types of components are recognized:
* - `new Vue({...})`
* - `Vue.extend({...})`
* - `new ExtendedVue({...})`
* - `Vue.component("my-component", {...})`
* - single file components in .vue files
*/
abstract class Instance extends TInstance {
class Component extends TComponent {
/** Gets a textual representation of this element. */
abstract string toString();
string toString() { none() } // overridden in subclasses

/**
* Holds if this element is at the specified location.
Expand All @@ -120,26 +129,26 @@ module Vue {
* Gets the options passed to the Vue object, such as the object literal `{...}` in `new Vue{{...})`
* or the default export of a single-file component.
*/
abstract DataFlow::Node getOwnOptionsObject();
DataFlow::Node getOwnOptionsObject() { none() } // overridden in subclasses

/**
* Gets the class component implementing this Vue instance, if any.
* Gets the class implementing this Vue component, if any.
*
* Specifically, this is a class annotated with `@Component` which flows to the options
* object of this Vue instance.
* object of this Vue component.
*/
ClassComponent getAsClassComponent() { result.flowsTo(getOwnOptionsObject()) }

/**
* Gets the node for option `name` for this instance, this does not include
* Gets the node for option `name` for this component, not including
* those from extended objects and mixins.
*/
DataFlow::Node getOwnOption(string name) {
result = getOwnOptionsObject().getALocalSource().getAPropertyWrite(name).getRhs()
}

/**
* Gets the node for option `name` for this instance, including those from
* Gets the node for option `name` for this component, including those from
* extended objects and mixins.
*/
DataFlow::Node getOption(string name) {
Expand All @@ -164,25 +173,25 @@ module Vue {
}

/**
* Gets a source node flowing into the option `name` of this instance, including those from
* Gets a source node flowing into the option `name` of this component, including those from
* extended objects and mixins.
*/
pragma[nomagic]
DataFlow::SourceNode getOptionSource(string name) { result = getOption(name).getALocalSource() }

/**
* Gets the template element used by this instance, if any.
* Gets the template element used by this component, if any.
*/
abstract Template::Element getTemplateElement();
Template::Element getTemplateElement() { none() } // overridden in subclasses

/**
* Gets the node for the `data` option object of this instance.
* Gets the node for the `data` option object of this component.
*/
DataFlow::Node getData() {
exists(DataFlow::Node data | data = getOption("data") |
result = data
or
// a constructor variant is available for all instance definitions
// a constructor variant is available for all component definitions
exists(DataFlow::FunctionNode f |
f.flowsTo(data) and
result = f.getAReturn()
Expand All @@ -195,13 +204,13 @@ module Vue {
}

/**
* Gets the node for the `template` option of this instance.
* Gets the node for the `template` option of this component.
*/
pragma[nomagic]
DataFlow::SourceNode getTemplate() { result = getOptionSource("template") }

/**
* Gets the node for the `render` option of this instance.
* Gets the node for the `render` option of this component.
*/
pragma[nomagic]
DataFlow::SourceNode getRender() {
Expand All @@ -211,19 +220,19 @@ module Vue {
}

/**
* Gets the node for the `methods` option of this instance.
* Gets the node for the `methods` option of this component.
*/
pragma[nomagic]
DataFlow::SourceNode getMethods() { result = getOptionSource("methods") }

/**
* Gets the node for the `computed` option of this instance.
* Gets the node for the `computed` option of this component.
*/
pragma[nomagic]
DataFlow::SourceNode getComputed() { result = getOptionSource("computed") }

/**
* Gets the node for the `watch` option of this instance.
* Gets the node for the `watch` option of this component.
*/
pragma[nomagic]
DataFlow::SourceNode getWatch() { result = getOptionSource("watch") }
Expand All @@ -240,7 +249,7 @@ module Vue {
}

/**
* Gets a node for a member of the `methods` option of this instance.
* Gets a node for a member of the `methods` option of this component.
*/
pragma[nomagic]
private DataFlow::SourceNode getAMethod() {
Expand All @@ -251,7 +260,7 @@ module Vue {
}

/**
* Gets a node for a member of the `computed` option of this instance that matches `kind`.
* Gets a node for a member of the `computed` option of this component that matches `kind`.
*/
pragma[nomagic]
private DataFlow::SourceNode getAnAccessor(DataFlow::MemberKind kind) {
Expand All @@ -264,7 +273,7 @@ module Vue {
}

/**
* Gets a node for a member `name` of the `computed` option of this instance that matches `kind`.
* Gets a node for a member `name` of the `computed` option of this component that matches `kind`.
*/
private DataFlow::SourceNode getAccessor(string name, DataFlow::MemberKind kind) {
result = getComputed().getAPropertySource(name) and kind = DataFlow::MemberKind::getter()
Expand All @@ -276,7 +285,7 @@ module Vue {
}

/**
* Gets the node for the life cycle hook of the `hookName` option of this instance.
* Gets the node for the life cycle hook of the `hookName` option of this component.
*/
pragma[nomagic]
DataFlow::SourceNode getALifecycleHook(string hookName) {
Expand All @@ -289,7 +298,7 @@ module Vue {
}

/**
* Gets a node for a function that will be invoked with `this` bound to this instance.
* Gets a node for a function that will be invoked with `this` bound to this component.
*/
DataFlow::FunctionNode getABoundFunction() {
result = getAMethod()
Expand All @@ -316,7 +325,7 @@ module Vue {
}

/**
* Gets the data flow node that flows into the property `name` of this instance, or is
* Gets the data flow node that flows into the property `name` of this component, or is
* returned form a getter defining that property.
*/
DataFlow::Node getAPropertyValue(string name) {
Expand All @@ -330,9 +339,9 @@ module Vue {
}

/**
* A Vue instance from `new Vue({...})`.
* A Vue component from `new Vue({...})`.
*/
class VueInstance extends Instance, MkVueInstance {
class VueInstance extends Component, MkVueInstance {
DataFlow::NewNode def;

VueInstance() { this = MkVueInstance(def) }
Expand All @@ -353,7 +362,7 @@ module Vue {
/**
* An extended Vue from `Vue.extend({...})`.
*/
class ExtendedVue extends Instance, MkExtendedVue {
class ExtendedVue extends Component, MkExtendedVue {
VueExtend extend;

ExtendedVue() { this = MkExtendedVue(extend) }
Expand All @@ -374,7 +383,7 @@ module Vue {
/**
* An instance of an extended Vue, for example `instance` of `var Ext = Vue.extend({...}); var instance = new Ext({...})`.
*/
class ExtendedInstance extends Instance, MkExtendedInstance {
class ExtendedInstance extends Component, MkExtendedInstance {
VueExtend extend;
DataFlow::NewNode sub;

Expand All @@ -391,7 +400,7 @@ module Vue {
override DataFlow::Node getOwnOptionsObject() { result = sub.getArgument(0) }

override DataFlow::Node getOption(string name) {
result = Instance.super.getOption(name)
result = Component.super.getOption(name)
or
result = MkExtendedVue(extend).(ExtendedVue).getOption(name)
}
Expand All @@ -402,10 +411,10 @@ module Vue {
/**
* A Vue component from `Vue.component("my-component", { ... })`.
*/
class Component extends Instance, MkComponent {
class ComponentRegistration extends Component, MkComponentRegistration {
DataFlow::CallNode def;

Component() { this = MkComponent(def) }
ComponentRegistration() { this = MkComponentRegistration(def) }

override string toString() { result = def.toString() }

Expand All @@ -423,7 +432,7 @@ module Vue {
/**
* A single file Vue component in a `.vue` file.
*/
class SingleFileComponent extends Instance, MkSingleFileComponent {
class SingleFileComponent extends Component, MkSingleFileComponent {
VueFile file;

SingleFileComponent() { this = MkSingleFileComponent(file) }
Expand Down Expand Up @@ -496,7 +505,7 @@ module Vue {
*/
class InstanceHeapStep extends TaintTracking::SharedTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(Instance i, string name, DataFlow::FunctionNode bound |
exists(Component i, string name, DataFlow::FunctionNode bound |
bound.flowsTo(i.getABoundFunction()) and
not bound.getFunction() instanceof ArrowFunctionExpr and
succ = bound.getReceiver().getAPropertyRead(name) and
Expand Down Expand Up @@ -531,13 +540,13 @@ module Vue {
*/
class VHtmlSourceWrite extends TaintTracking::SharedTaintStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(Vue::Instance instance, string expr, VHtmlAttribute attr |
exists(Vue::Component component, string expr, VHtmlAttribute attr |
attr.getAttr().getRoot() =
instance.getTemplateElement().(Vue::Template::HtmlElement).getElement() and
component.getTemplateElement().(Vue::Template::HtmlElement).getElement() and
expr = attr.getAttr().getValue() and
// only support for simple identifier expressions
expr.regexpMatch("(?i)[a-z0-9_]+") and
pred = instance.getAPropertyValue(expr) and
pred = component.getAPropertyValue(expr) and
succ = attr
)
}
Expand Down Expand Up @@ -638,15 +647,15 @@ module Vue {
or
result = routeConfig().getMember("beforeEnter").getParameter([0, 1]).getAnImmediateUse()
or
exists(Instance i |
result = i.getABoundFunction().getAFunctionValue().getReceiver().getAPropertyRead("$route")
exists(Component c |
result = c.getABoundFunction().getAFunctionValue().getReceiver().getAPropertyRead("$route")
or
result =
i.getALifecycleHook(["beforeRouteEnter", "beforeRouteUpdate", "beforeRouteLeave"])
c.getALifecycleHook(["beforeRouteEnter", "beforeRouteUpdate", "beforeRouteLeave"])
.getAFunctionValue()
.getParameter([0, 1])
or
result = i.getWatchHandler("$route").getParameter([0, 1])
result = c.getWatchHandler("$route").getParameter([0, 1])
)
)
or
Expand All @@ -664,7 +673,7 @@ module Vue {
this = routeObject().getAPropertyRead(name)
or
exists(string prop |
this = any(Instance i).getWatchHandler(prop).getParameter([0, 1]) and
this = any(Component c).getWatchHandler(prop).getParameter([0, 1]) and
name = prop.regexpCapture("\\$route\\.(params|query|hash|path|fullPath)\\b.*", 1)
)
|
Expand Down
2 changes: 1 addition & 1 deletion javascript/ql/src/semmle/javascript/frameworks/Vuex.qll
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private module VueAPI {
* or equivalent.
*/
class VueConfigObject extends API::Node {
VueConfigObject() { this.getARhs() = any(Vue::Instance i).getOwnOptionsObject() }
VueConfigObject() { this.getARhs() = any(Vue::Component c).getOwnOptionsObject() }

/** Gets an API node representing `this` in the Vue component. */
API::Node getAnInstanceRef() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,8 @@ module DomBasedXss {
*/
class VueTemplateSink extends DomBasedXss::Sink {
VueTemplateSink() {
// Note: don't use Vue::Instance#getTemplate as it includes an unwanted getALocalSource() step
this = any(Vue::Instance i).getOption("template")
// Note: don't use Vue::Component#getTemplate as it includes an unwanted getALocalSource() step
this = any(Vue::Component c).getOption("template")
}
}

Expand All @@ -357,8 +357,8 @@ module DomBasedXss {
*/
class VueCreateElementSink extends DomBasedXss::Sink {
VueCreateElementSink() {
exists(Vue::Instance i, DataFlow::FunctionNode f |
f.flowsTo(i.getRender()) and
exists(Vue::Component c, DataFlow::FunctionNode f |
f.flowsTo(c.getRender()) and
this = f.getParameter(0).getACall().getArgument(0)
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
instance_getAPropertyValue
component_getAPropertyValue
| compont-with-route.vue:0:0:0:0 | compont-with-route.vue | dataA | compont-with-route.vue:31:14:31:34 | this.$r ... ery.foo |
| compont-with-route.vue:0:0:0:0 | compont-with-route.vue | message | compont-with-route.vue:19:15:19:22 | 'Hello!' |
| single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue | dataA | single-component-file-1.vue:6:40:6:41 | 42 |
Expand Down Expand Up @@ -28,7 +28,7 @@ instance_getAPropertyValue
| tst.js:85:1:87:2 | new Vue ... e; }\\n}) | created | tst.js:86:38:86:41 | true |
| tst.js:94:2:96:3 | new Vue ... f,\\n\\t}) | dataA | tst.js:89:22:89:23 | 42 |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) | dataA | tst.js:100:18:100:19 | 42 |
instance_getOption
component_getOption
| compont-with-route.vue:0:0:0:0 | compont-with-route.vue | watch | compont-with-route.vue:10:12:16:5 | {\\n ... }\\n } |
| single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue | data | single-component-file-1.vue:6:11:6:45 | functio ... 42 } } |
| single-file-component-3.vue:0:0:0:0 | single-file-component-3.vue | data | single-file-component-3-script.js:4:8:4:42 | functio ... 42 } } |
Expand Down Expand Up @@ -58,7 +58,7 @@ instance_getOption
| tst.js:94:2:96:3 | new Vue ... f,\\n\\t}) | data | tst.js:95:9:95:9 | f |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) | data | tst.js:100:9:100:21 | { dataA: 42 } |
| tst.js:99:2:104:3 | new Vue ... \\t\\t}\\n\\t}) | methods | tst.js:101:12:103:3 | {\\n\\t\\t\\tm: ... ; }\\n\\t\\t} |
instance
component
| compont-with-route.vue:0:0:0:0 | compont-with-route.vue |
| single-component-file-1.vue:0:0:0:0 | single-component-file-1.vue |
| single-file-component-2.vue:0:0:0:0 | single-file-component-2.vue |
Expand Down
Loading