Skip to content

Commit 2932421

Browse files
authored
Merge pull request #30495 from Microsoft/fix29427
Adjust offset to account for 'this' parameter when emitting parameter decorators
2 parents 800f7a3 + 07bec28 commit 2932421

10 files changed

+154
-3
lines changed

src/compiler/transformers/ts.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,11 +1338,14 @@ namespace ts {
13381338
let decorators: (ReadonlyArray<Decorator> | undefined)[] | undefined;
13391339
if (node) {
13401340
const parameters = node.parameters;
1341-
for (let i = 0; i < parameters.length; i++) {
1342-
const parameter = parameters[i];
1341+
const firstParameterIsThis = parameters.length > 0 && parameterIsThisKeyword(parameters[0]);
1342+
const firstParameterOffset = firstParameterIsThis ? 1 : 0;
1343+
const numParameters = firstParameterIsThis ? parameters.length - 1 : parameters.length;
1344+
for (let i = 0; i < numParameters; i++) {
1345+
const parameter = parameters[i + firstParameterOffset];
13431346
if (decorators || parameter.decorators) {
13441347
if (!decorators) {
1345-
decorators = new Array(parameters.length);
1348+
decorators = new Array(numParameters);
13461349
}
13471350

13481351
decorators[i] = parameter.decorators;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [decoratorOnClassMethodParameter2.ts]
2+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
3+
4+
class C {
5+
method(this: C, @dec p: number) {}
6+
}
7+
8+
//// [decoratorOnClassMethodParameter2.js]
9+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
10+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
11+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
12+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
13+
return c > 3 && r && Object.defineProperty(target, key, r), r;
14+
};
15+
var __param = (this && this.__param) || function (paramIndex, decorator) {
16+
return function (target, key) { decorator(target, key, paramIndex); }
17+
};
18+
var C = /** @class */ (function () {
19+
function C() {
20+
}
21+
C.prototype.method = function (p) { };
22+
__decorate([
23+
__param(0, dec)
24+
], C.prototype, "method", null);
25+
return C;
26+
}());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter2.ts ===
2+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
3+
>dec : Symbol(dec, Decl(decoratorOnClassMethodParameter2.ts, 0, 0))
4+
>target : Symbol(target, Decl(decoratorOnClassMethodParameter2.ts, 0, 21))
5+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
6+
>propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethodParameter2.ts, 0, 36))
7+
>parameterIndex : Symbol(parameterIndex, Decl(decoratorOnClassMethodParameter2.ts, 0, 66))
8+
9+
class C {
10+
>C : Symbol(C, Decl(decoratorOnClassMethodParameter2.ts, 0, 97))
11+
12+
method(this: C, @dec p: number) {}
13+
>method : Symbol(C.method, Decl(decoratorOnClassMethodParameter2.ts, 2, 9))
14+
>this : Symbol(this, Decl(decoratorOnClassMethodParameter2.ts, 3, 11))
15+
>C : Symbol(C, Decl(decoratorOnClassMethodParameter2.ts, 0, 97))
16+
>dec : Symbol(dec, Decl(decoratorOnClassMethodParameter2.ts, 0, 0))
17+
>p : Symbol(p, Decl(decoratorOnClassMethodParameter2.ts, 3, 19))
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodParameter2.ts ===
2+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
3+
>dec : (target: Object, propertyKey: string | symbol, parameterIndex: number) => void
4+
>target : Object
5+
>propertyKey : string | symbol
6+
>parameterIndex : number
7+
8+
class C {
9+
>C : C
10+
11+
method(this: C, @dec p: number) {}
12+
>method : (this: C, p: number) => void
13+
>this : C
14+
>dec : (target: Object, propertyKey: string | symbol, parameterIndex: number) => void
15+
>p : number
16+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodThisParameter.ts(4,17): error TS1003: Identifier expected.
2+
tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodThisParameter.ts(4,17): error TS2680: A 'this' parameter must be the first parameter.
3+
4+
5+
==== tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodThisParameter.ts (2 errors) ====
6+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
7+
8+
class C {
9+
method(@dec this: C) {}
10+
~~~~
11+
!!! error TS1003: Identifier expected.
12+
~~~~~~~
13+
!!! error TS2680: A 'this' parameter must be the first parameter.
14+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [decoratorOnClassMethodThisParameter.ts]
2+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
3+
4+
class C {
5+
method(@dec this: C) {}
6+
}
7+
8+
//// [decoratorOnClassMethodThisParameter.js]
9+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
10+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
11+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
12+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
13+
return c > 3 && r && Object.defineProperty(target, key, r), r;
14+
};
15+
var __param = (this && this.__param) || function (paramIndex, decorator) {
16+
return function (target, key) { decorator(target, key, paramIndex); }
17+
};
18+
var C = /** @class */ (function () {
19+
function C() {
20+
}
21+
C.prototype.method = function () { };
22+
__decorate([
23+
__param(0, dec)
24+
], C.prototype, "method", null);
25+
return C;
26+
}());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodThisParameter.ts ===
2+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
3+
>dec : Symbol(dec, Decl(decoratorOnClassMethodThisParameter.ts, 0, 0))
4+
>target : Symbol(target, Decl(decoratorOnClassMethodThisParameter.ts, 0, 21))
5+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
6+
>propertyKey : Symbol(propertyKey, Decl(decoratorOnClassMethodThisParameter.ts, 0, 36))
7+
>parameterIndex : Symbol(parameterIndex, Decl(decoratorOnClassMethodThisParameter.ts, 0, 66))
8+
9+
class C {
10+
>C : Symbol(C, Decl(decoratorOnClassMethodThisParameter.ts, 0, 97))
11+
12+
method(@dec this: C) {}
13+
>method : Symbol(C.method, Decl(decoratorOnClassMethodThisParameter.ts, 2, 9))
14+
>dec : Symbol(dec, Decl(decoratorOnClassMethodThisParameter.ts, 0, 0))
15+
> : Symbol((Missing), Decl(decoratorOnClassMethodThisParameter.ts, 3, 11))
16+
>this : Symbol(this, Decl(decoratorOnClassMethodThisParameter.ts, 3, 15))
17+
>C : Symbol(C, Decl(decoratorOnClassMethodThisParameter.ts, 0, 97))
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/conformance/decorators/class/method/parameter/decoratorOnClassMethodThisParameter.ts ===
2+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
3+
>dec : (target: Object, propertyKey: string | symbol, parameterIndex: number) => void
4+
>target : Object
5+
>propertyKey : string | symbol
6+
>parameterIndex : number
7+
8+
class C {
9+
>C : C
10+
11+
method(@dec this: C) {}
12+
>method : (: any, this: C) => void
13+
>dec : (target: Object, propertyKey: string | symbol, parameterIndex: number) => void
14+
> : any
15+
>this : C
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @target:es5
2+
// @experimentaldecorators: true
3+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
4+
5+
class C {
6+
method(this: C, @dec p: number) {}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @target:es5
2+
// @experimentaldecorators: true
3+
declare function dec(target: Object, propertyKey: string | symbol, parameterIndex: number): void;
4+
5+
class C {
6+
method(@dec this: C) {}
7+
}

0 commit comments

Comments
 (0)