Skip to content

Commit a78dd42

Browse files
author
Esben Sparre Andreasen
committed
JS: add query js/vue/arrow-method-on-vue-instance
1 parent ea175b2 commit a78dd42

File tree

8 files changed

+111
-0
lines changed

8 files changed

+111
-0
lines changed

change-notes/1.20/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
| **Query** | **Tags** | **Purpose** |
1616
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
17+
| Arrow method on Vue instance (`js/vue/arrow-method-on-vue-instance`) | reliability, frameworks/vue | Highlights arrow functions that are used as methods on Vue instances. Results are shown on LGTM by default.|
1718
| Double escaping or unescaping (`js/double-escaping`) | correctness, security, external/cwe/cwe-116 | Highlights potential double escaping or unescaping of special characters, indicating a possible violation of [CWE-116](https://cwe.mitre.org/data/definitions/116.html). Results are shown on LGTM by default. |
1819
| Incomplete regular expression for hostnames (`js/incomplete-hostname-regexp`) | correctness, security, external/cwe/cwe-020 | Highlights hostname sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results are shown on LGTM by default.|
1920
| Incomplete URL substring sanitization | correctness, security, external/cwe/cwe-020 | Highlights URL sanitizers that are likely to be incomplete, indicating a violation of [CWE-020](https://cwe.mitre.org/data/definitions/20.html). Results shown on LGTM by default. |

javascript/config/suites/javascript/frameworks-more

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@
2323
+ semmlecode-javascript-queries/React/UnusedOrUndefinedStateProperty.ql: /Frameworks/React
2424
+ semmlecode-javascript-queries/Electron/DisablingWebSecurity.ql: /Frameworks/Electron
2525
+ semmlecode-javascript-queries/Electron/AllowRunningInsecureContent.ql: /Frameworks/Electron
26+
+ semmlecode-javascript-queries/Vue/ArrowMethodOnVueInstance.ql: /Frameworks/Vue
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
9+
The Vue framework invokes the methods of a Vue instance with
10+
the instance as the receiver. It is however impossible to perform
11+
this binding of instance and receiver for arrow functions, so the
12+
<code>this</code> variable in an arrow function on a Vue instance may
13+
not have the value that the programmer expects.
14+
15+
</p>
16+
</overview>
17+
18+
<recommendation>
19+
<p>
20+
Ensure that the methods on a Vue instance can have their receiver bound to the instance.
21+
</p>
22+
</recommendation>
23+
24+
<example>
25+
26+
<p>
27+
28+
The following example shows two similar Vue instances, the only
29+
difference is how the <code>created</code> life cycle hook
30+
callback is defined.
31+
32+
The first Vue instance uses an arrow function as the callback.
33+
This means that the <code>this</code> variable will have the global
34+
object as its value, causing <code>this.myProperty</code> to evaluate
35+
to <code>undefined</code>, which may not be intended.
36+
37+
Instead, the second Vue instance uses an ordinary function as the callback,
38+
causing <code>this.myProperty</code> to evaluate to <code>42</code>.
39+
40+
</p>
41+
42+
<sample src="examples/ArrowMethodOnVueInstance.js"/>
43+
44+
</example>
45+
46+
<references>
47+
<li>Vue documentation: <a href="https://vuejs.org/v2/guide/instance.html">The Vue Instance</a></li>
48+
</references>
49+
</qhelp>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @name Arrow method on Vue instance
3+
* @description An arrow method on a Vue instance doesn't have its `this` variable bound to the Vue instance.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id js/vue/arrow-method-on-vue-instance
7+
* @tags reliability
8+
* frameworks/vue
9+
* @precision high
10+
*/
11+
12+
import javascript
13+
14+
from Vue::Instance instance, DataFlow::Node def, DataFlow::FunctionNode arrow, ThisExpr dis
15+
where instance.getABoundFunction() = def and
16+
arrow.flowsTo(def) and
17+
arrow.asExpr() instanceof ArrowFunctionExpr and
18+
arrow.asExpr() = dis.getEnclosingFunction()
19+
select def, "The $@ of this $@ it will not be bound to the Vue instance.", dis, "`this` variable", arrow, "arrow function"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
new Vue({
2+
data: {
3+
myProperty: 42
4+
},
5+
created: () => {
6+
// BAD: prints: "myProperty is: undefined"
7+
console.log('myProperty is: ' + this.myProperty);
8+
}
9+
});
10+
11+
new Vue({
12+
data: {
13+
myProperty: 42
14+
},
15+
created: function () {
16+
// GOOD: prints: "myProperty is: 1"
17+
console.log('myProperty is: ' + this.myProperty);
18+
}
19+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| tst.js:4:11:4:20 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:4:17:4:20 | this | `this` variable | tst.js:4:11:4:20 | () => this | arrow function |
2+
| tst.js:6:6:6:15 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:6:12:6:15 | this | `this` variable | tst.js:6:6:6:15 | () => this | arrow function |
3+
| tst.js:7:13:7:22 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:7:19:7:22 | this | `this` variable | tst.js:7:13:7:22 | () => this | arrow function |
4+
| tst.js:8:13:8:22 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:8:19:8:22 | this | `this` variable | tst.js:8:13:8:22 | () => this | arrow function |
5+
| tst.js:11:10:11:19 | () => this | The $@ of this $@ it will not be bound to the Vue instance. | tst.js:11:16:11:19 | this | `this` variable | tst.js:11:10:11:19 | () => this | arrow function |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Vue/ArrowMethodOnVueInstance.ql
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
let Vue = require('vue');
2+
3+
new Vue( {
4+
created: () => this, // NOT OK
5+
computed: {
6+
x: () => this, // NOT OK
7+
y: { get: () => this }, // NOT OK
8+
z: { set: () => this } // NOT OK
9+
},
10+
methods: {
11+
arrow: () => this, // NOT OK
12+
nonArrow: function() { this; }, // OK
13+
arrowWithoutThis: () => 42, // OK
14+
arrowWithNestedThis: () => (() => this) // OK
15+
}
16+
});

0 commit comments

Comments
 (0)