biome complexity/noUselessThisAlias
labelled safe
Analysis Nemotron 3 Super
Flags unnecessary aliases to 'this' when used only within arrow functions that inherit the outer 'this'.
Fix: Removes the variable declaration and replaces all references to the aliased variable with 'this'.
10 hazards
- If the alias variable is reassigned after its initial assignment, replacing references with 'this' will use the current 'this' value instead of the captured value, changing behavior.
- If the alias variable is used in a nested function that is not an arrow function (e.g., regular function or eval), the replacement may break due to differing 'this' binding.
- If the alias variable is used outside the scope where it was declared (e.g., returned or closed over in a way that escapes), removing the declaration causes a ReferenceError.
- If the alias variable name conflicts with a variable in an inner scope, removing the outer declaration may cause inner references to resolve to a different variable.
- If the alias variable is used in a dynamic context like 'with' or indirect eval, static replacement cannot accurately determine usage, leading to incorrect refactoring.
- If the alias variable is declared with 'var' and hoisted, removing it may affect the temporal dead zone or hoisting behavior in ways that change execution if referenced before declaration.
- If the alias variable is part of a comma-separated declaration (e.g., 'const self = this, other = expr;'), the fix may incorrectly remove the entire declaration or mishandle the separator.
- If the alias variable is used in a type annotation or JSDoc comment (e.g., '/** @type {Any} */ const self = this;'), removing the declaration may strip useful type information.
- If the alias variable is used in a destructuring pattern or default parameter, the simple replacement fails to account for complex binding structures.
- If the alias variable is referenced in a string literal (e.g., for code generation or logging), textual replacement is not performed, leading to mismatches between code and strings.
Findings
| program | oracle | label | judge | status | summary |
|---|---|---|---|---|---|
| r1-p007 | fix-changes-behavior | labelled safe | real · high | related | The rule removed the variable declaration `var _this = this` and replaced the read of `_this` with `this`, but the read occurs before the declaration in the or… |
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | fix ok | Dynamic context via indirect eval | If the alias variable is used in a dynamic context like 'with' or indirect eval, static replacement cannot accurately determine usage, leading to incorrect refactoring. |
| r1-p002 | fix ok | Regex with global flag and lastIndex mutation | regular expressions: escapes, unicode flag, lastIndex with the g flag |
| r1-p004 | fix ok | Comments on removed declaration | comments attached to the removed or moved code |
| r1-p005 | fix ok | Escaped alias causing ReferenceError | If the alias variable is used outside the scope where it was declared (e.g., returned or closed over in a way that escapes), removing the declaration causes a ReferenceError. |
| r1-p006 | silent | Alias in destructuring parameter | If the alias variable is used in a destructuring pattern or default parameter, the simple replacement fails to account for complex binding structures. |
| r1-p007 | fix-changes-behavior | Var hoisting and TDZ interaction | If the alias variable is declared with 'var' and hoisted, removing it may affect the temporal dead zone or hoisting behavior in ways that change execution if referenced before declaration. |
| r1-p008 | fix ok | Sparse array with holes and lastIndex-like access | sparse arrays, holes, Array(n) vs [n], array-likes |
| r2-p001 | fix ok | Inner scope variable conflict | If the alias variable name conflicts with a variable in an inner scope, removing the outer declaration may cause inner references to resolve to a different variable. |
| r2-p002 | silent prediction off | __proto__ keys and prototype access | __proto__ keys, prototype access, Object.assign vs spread |
| r2-p003 | silent | Type annotation/JSDoc comment stripping | If the alias variable is used in a type annotation or JSDoc comment (e.g., '/** @type {Any} */ const self = this;'), removing the declaration may strip useful type information. |
| r2-p004 | silent prediction off | Var hoisting and re-declaration in loop | var hoisting and re-declaration inside loops or after use |
| r2-p005 | silent prediction off | Getter/setter/Object.defineProperty side effects | getters, setters and Object.defineProperty side effects |
| r2-p006 | fix ok | Comments attached to removed/moved code | comments attached to the removed or moved code |
| r2-p007 | silent prediction off | Nested non-arrow function usage | If the alias variable is used in a nested function that is not an arrow function (e.g., regular function or eval), the replacement may break due to differing 'this' binding. |
| r2-p008 | fix ok | Function declarations inside blocks/switch/labeled | function declarations inside blocks, switch cases, labeled statements |
Sources
r1-p001 · Dynamic context via indirect eval
1let that = this;
2const obj = { x: 1, y: 2 };
3(() => {
4 'use strict';
5 return Function('return that.x')();
6})();
--- orig.js 2026-10-17 16:08:33.184245752 -0400 +++ fixed.js 2026-10-17 16:08:33.474234810 -0400 @@ -1,4 +1,4 @@ -let that = this; + const obj = { x: 1, y: 2 }; (() => { 'use strict';
r1-p002 · Regex with global flag and lastIndex mutation
1let self = this;
2self.lastMatch = '';
3const str = 'a1b2';
4[...str].forEach(() => {
5 const match = /\d/g.exec(str);
6 self.lastMatch += match ? match[0] : '_';
7});
8console.log(self.lastMatch);
--- orig.js 2026-10-17 16:08:33.642228472 -0400 +++ fixed.js 2026-10-17 16:08:33.896218888 -0400 @@ -1,8 +1,8 @@ -let self = this; -self.lastMatch = ''; + +this.lastMatch = ''; const str = 'a1b2'; [...str].forEach(() => { const match = /\d/g.exec(str); - self.lastMatch += match ? match[0] : '_'; + this.lastMatch += match ? match[0] : '_'; }); -console.log(self.lastMatch); +console.log(this.lastMatch);
r1-p004 · Comments on removed declaration
1// important: capture this
2let me = this;
3// used in handler
4[1,2].forEach(() => console.log(me));
--- orig.js 2026-10-17 16:08:34.057212818 -0400 +++ fixed.js 2026-10-17 16:08:34.335202352 -0400 @@ -1,4 +1,3 @@ -// important: capture this -let me = this; + // used in handler -[1,2].forEach(() => console.log(me)); +[1,2].forEach(() => console.log(this));
undefined undefined
r1-p005 · Escaped alias causing ReferenceError
1function outer() {
2 var self = this;
3 return () => self;
4}
5const f = outer.call({x:1});
6try {
7 console.log(f().x);
8} catch (e) {
9 console.log(e.name + ': ' + e.message);
10}
--- orig.js 2026-10-17 16:08:34.512195688 -0400 +++ fixed.js 2026-10-17 16:08:34.780185598 -0400 @@ -1,6 +1,5 @@ function outer() { - var self = this; - return () => self; + return () => this; } const f = outer.call({x:1}); try {
1
r1-p006 · Alias in destructuring parameter
1function process({ data = this }) {
2 return data;
3}
4console.log(process.call({value: 42}, {}));
{ value: 42 }r1-p007 · Var hoisting and TDZ interaction
1function test() {
2 console.log(typeof _this);
3 var _this = this;
4 return _this.value;
5}
6try {
7 console.log(test.call({value: 'ok'}));
8} catch (e) {
9 console.log(e.name + ': ' + e.message);
10}
--- orig.js 2026-10-17 16:08:35.139172094 -0400 +++ fixed.js 2026-10-17 16:08:35.417161650 -0400 @@ -1,7 +1,6 @@ function test() { - console.log(typeof _this); - var _this = this; - return _this.value; + console.log(typeof this); + return this.value; } try { console.log(test.call({value: 'ok'}));
undefined ok
r1-p008 · Sparse array with holes and lastIndex-like access
1let self = this;
2self.data = [10, , 30];
3const result = Array.from({length: 3}, (_, i) => self.data[i] ?? -1);
4console.log(result.join(','));
--- orig.js 2026-10-17 16:08:35.576155676 -0400 +++ fixed.js 2026-10-17 16:08:35.832146059 -0400 @@ -1,4 +1,4 @@ -let self = this; -self.data = [10, , 30]; -const result = Array.from({length: 3}, (_, i) => self.data[i] ?? -1); + +this.data = [10, , 30]; +const result = Array.from({length: 3}, (_, i) => this.data[i] ?? -1); console.log(result.join(','));
r2-p001 · Inner scope variable conflict
1const self = 42;
2function outer() {
3 const self = this;
4 return () => {
5 console.log(self);
6 };
7}
8outer()(100);
--- orig.js 2026-10-17 16:08:39.410012256 -0400 +++ fixed.js 2026-10-17 16:08:39.687001939 -0400 @@ -1,8 +1,7 @@ const self = 42; function outer() { - const self = this; return () => { - console.log(self); + console.log(this); }; } outer()(100);
undefined
r2-p002 · __proto__ keys and prototype access
1const obj = { __proto__: { x: 1 }, y: 2 };
2const _this = obj;
3console.log(_this.__proto__.x + _this.y);
3
r2-p003 · Type annotation/JSDoc comment stripping
1/** @type {number} */
2const self = 42;
3console.log(typeof self);
number
r2-p004 · Var hoisting and re-declaration in loop
1for (let i = 0; i < 2; i++) {
2 var self = i;
3 (() => console.log(self))();
4}
0 1
r2-p005 · Getter/setter/Object.defineProperty side effects
1const obj = {};
2let _this = obj;
3Object.defineProperty(obj, 'prop', {
4 get() { return this.value || 0; },
5 set(v) { this.value = v * 2; }
6});
7obj.value = 5;
8console.log(_this.prop);
5
r2-p006 · Comments attached to removed/moved code
1// important note
2const self = this;
3// another comment
4(() => console.log(self))();
--- orig.js 2026-10-17 16:08:40.853958542 -0400 +++ fixed.js 2026-10-17 16:08:41.130948257 -0400 @@ -1,4 +1,3 @@ -// important note -const self = this; + // another comment -(() => console.log(self))(); +(() => console.log(this))();
undefined
r2-p007 · Nested non-arrow function usage
1const obj = { method() { return this.val; }, val: 10 };
2const self = obj;
3function inner() {
4 return self.method();
5}
6console.log(inner());
10
r2-p008 · Function declarations inside blocks/switch/labeled
1switch (1) {
2 case 1:
3 const self = this;
4 (() => self)();
5 break;
6}
--- orig.js 2026-10-17 16:08:41.554932533 -0400 +++ fixed.js 2026-10-17 16:08:41.792923707 -0400 @@ -1,6 +1,5 @@ switch (1) { case 1: - const self = this; - (() => self)(); + (() => this)(); break; }