Skip to content

Commit 2eb9ec4

Browse files
committed
check usage before declaration for decorators
1 parent 1f0f7c8 commit 2eb9ec4

6 files changed

+910
-1
lines changed

src/compiler/checker.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1672,7 +1672,11 @@ namespace ts {
16721672
return isForInOrOfStatement(grandparent) && isSameScopeDescendentOf(usage, grandparent.expression, declContainer);
16731673
}
16741674

1675-
function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node): boolean {
1675+
function isUsedInFunctionOrInstanceProperty(usage: Node, declaration: Node) {
1676+
return isUsedInFunctionOrInstancePropertyWorker(usage, declaration);
1677+
}
1678+
1679+
function isUsedInFunctionOrInstancePropertyWorker(usage: Node, declaration: Node): boolean {
16761680
return !!findAncestor(usage, current => {
16771681
if (current === declContainer) {
16781682
return "quit";
@@ -1711,6 +1715,17 @@ namespace ts {
17111715
}
17121716
}
17131717
}
1718+
1719+
const decorator = tryCast(current.parent, isDecorator);
1720+
if (decorator && decorator.expression === current) {
1721+
if (isParameter(decorator.parent)) {
1722+
return isUsedInFunctionOrInstancePropertyWorker(decorator.parent.parent.parent, declaration) ? true : "quit";
1723+
}
1724+
if (isMethodDeclaration(decorator.parent)) {
1725+
return isUsedInFunctionOrInstancePropertyWorker(decorator.parent.parent, declaration) ? true : "quit";
1726+
}
1727+
}
1728+
17141729
return false;
17151730
});
17161731
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(1,2): error TS2448: Block-scoped variable 'lambda' used before its declaration.
2+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(1,9): error TS2450: Enum 'Enum' used before its declaration.
3+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(2,7): error TS2450: Enum 'Enum' used before its declaration.
4+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(4,4): error TS2448: Block-scoped variable 'lambda' used before its declaration.
5+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(4,11): error TS2450: Enum 'Enum' used before its declaration.
6+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(5,9): error TS2450: Enum 'Enum' used before its declaration.
7+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(12,4): error TS2448: Block-scoped variable 'lambda' used before its declaration.
8+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(12,11): error TS2450: Enum 'Enum' used before its declaration.
9+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(13,9): error TS2450: Enum 'Enum' used before its declaration.
10+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(18,4): error TS2448: Block-scoped variable 'lambda' used before its declaration.
11+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(24,11): error TS2448: Block-scoped variable 'lambda' used before its declaration.
12+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(24,18): error TS2450: Enum 'Enum' used before its declaration.
13+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(24,33): error TS2450: Enum 'Enum' used before its declaration.
14+
tests/cases/compiler/decoratorUsedBeforeDeclaration.ts(28,11): error TS2448: Block-scoped variable 'lambda' used before its declaration.
15+
16+
17+
==== tests/cases/compiler/decoratorUsedBeforeDeclaration.ts (14 errors) ====
18+
@lambda(Enum.No)
19+
~~~~~~
20+
!!! error TS2448: Block-scoped variable 'lambda' used before its declaration.
21+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here.
22+
~~~~
23+
!!! error TS2450: Enum 'Enum' used before its declaration.
24+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
25+
@deco(Enum.No)
26+
~~~~
27+
!!! error TS2450: Enum 'Enum' used before its declaration.
28+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
29+
class Greeter {
30+
@lambda(Enum.No)
31+
~~~~~~
32+
!!! error TS2448: Block-scoped variable 'lambda' used before its declaration.
33+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here.
34+
~~~~
35+
!!! error TS2450: Enum 'Enum' used before its declaration.
36+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
37+
@deco(Enum.No)
38+
~~~~
39+
!!! error TS2450: Enum 'Enum' used before its declaration.
40+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
41+
greeting: string;
42+
43+
constructor(message: string) {
44+
this.greeting = message;
45+
}
46+
47+
@lambda(Enum.No)
48+
~~~~~~
49+
!!! error TS2448: Block-scoped variable 'lambda' used before its declaration.
50+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here.
51+
~~~~
52+
!!! error TS2450: Enum 'Enum' used before its declaration.
53+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
54+
@deco(Enum.No)
55+
~~~~
56+
!!! error TS2450: Enum 'Enum' used before its declaration.
57+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
58+
greet() {
59+
return "Hello, " + this.greeting;
60+
}
61+
62+
@lambda
63+
~~~~~~
64+
!!! error TS2448: Block-scoped variable 'lambda' used before its declaration.
65+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here.
66+
@deco
67+
greet1() {
68+
return "Hello, " + this.greeting;
69+
}
70+
71+
greet2(@lambda(Enum.No) @deco(Enum.No) param) {
72+
~~~~~~
73+
!!! error TS2448: Block-scoped variable 'lambda' used before its declaration.
74+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here.
75+
~~~~
76+
!!! error TS2450: Enum 'Enum' used before its declaration.
77+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
78+
~~~~
79+
!!! error TS2450: Enum 'Enum' used before its declaration.
80+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here.
81+
return "Hello, " + this.greeting;
82+
}
83+
84+
greet3(@lambda @deco param) {
85+
~~~~~~
86+
!!! error TS2448: Block-scoped variable 'lambda' used before its declaration.
87+
!!! related TS2728 tests/cases/compiler/decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here.
88+
return "Hello, " + this.greeting;
89+
}
90+
}
91+
92+
function deco(...args: any[]): any {}
93+
94+
enum Enum {
95+
No = 0,
96+
Yes = 1,
97+
}
98+
99+
const lambda = (...args: any[]): any => {};
100+
101+
@lambda(Enum.No)
102+
@deco(Enum.No)
103+
class Greeter1 {
104+
@lambda(Enum.No)
105+
@deco(Enum.No)
106+
greeting: string;
107+
108+
constructor(message: string) {
109+
this.greeting = message;
110+
}
111+
112+
@lambda(Enum.No)
113+
@deco(Enum.No)
114+
greet() {
115+
return "Hello, " + this.greeting;
116+
}
117+
118+
@lambda
119+
@deco
120+
greet1() {
121+
return "Hello, " + this.greeting;
122+
}
123+
124+
greet2(@lambda(Enum.No) @deco(Enum.No) param) {
125+
return "Hello, " + this.greeting;
126+
}
127+
128+
greet3(@lambda @deco param) {
129+
return "Hello, " + this.greeting;
130+
}
131+
}
132+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//// [decoratorUsedBeforeDeclaration.ts]
2+
@lambda(Enum.No)
3+
@deco(Enum.No)
4+
class Greeter {
5+
@lambda(Enum.No)
6+
@deco(Enum.No)
7+
greeting: string;
8+
9+
constructor(message: string) {
10+
this.greeting = message;
11+
}
12+
13+
@lambda(Enum.No)
14+
@deco(Enum.No)
15+
greet() {
16+
return "Hello, " + this.greeting;
17+
}
18+
19+
@lambda
20+
@deco
21+
greet1() {
22+
return "Hello, " + this.greeting;
23+
}
24+
25+
greet2(@lambda(Enum.No) @deco(Enum.No) param) {
26+
return "Hello, " + this.greeting;
27+
}
28+
29+
greet3(@lambda @deco param) {
30+
return "Hello, " + this.greeting;
31+
}
32+
}
33+
34+
function deco(...args: any[]): any {}
35+
36+
enum Enum {
37+
No = 0,
38+
Yes = 1,
39+
}
40+
41+
const lambda = (...args: any[]): any => {};
42+
43+
@lambda(Enum.No)
44+
@deco(Enum.No)
45+
class Greeter1 {
46+
@lambda(Enum.No)
47+
@deco(Enum.No)
48+
greeting: string;
49+
50+
constructor(message: string) {
51+
this.greeting = message;
52+
}
53+
54+
@lambda(Enum.No)
55+
@deco(Enum.No)
56+
greet() {
57+
return "Hello, " + this.greeting;
58+
}
59+
60+
@lambda
61+
@deco
62+
greet1() {
63+
return "Hello, " + this.greeting;
64+
}
65+
66+
greet2(@lambda(Enum.No) @deco(Enum.No) param) {
67+
return "Hello, " + this.greeting;
68+
}
69+
70+
greet3(@lambda @deco param) {
71+
return "Hello, " + this.greeting;
72+
}
73+
}
74+
75+
76+
//// [decoratorUsedBeforeDeclaration.js]
77+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
78+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
79+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
80+
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;
81+
return c > 3 && r && Object.defineProperty(target, key, r), r;
82+
};
83+
var __param = (this && this.__param) || function (paramIndex, decorator) {
84+
return function (target, key) { decorator(target, key, paramIndex); }
85+
};
86+
var Greeter = /** @class */ (function () {
87+
function Greeter(message) {
88+
this.greeting = message;
89+
}
90+
Greeter.prototype.greet = function () {
91+
return "Hello, " + this.greeting;
92+
};
93+
Greeter.prototype.greet1 = function () {
94+
return "Hello, " + this.greeting;
95+
};
96+
Greeter.prototype.greet2 = function (param) {
97+
return "Hello, " + this.greeting;
98+
};
99+
Greeter.prototype.greet3 = function (param) {
100+
return "Hello, " + this.greeting;
101+
};
102+
__decorate([
103+
lambda(Enum.No),
104+
deco(Enum.No)
105+
], Greeter.prototype, "greeting");
106+
__decorate([
107+
lambda(Enum.No),
108+
deco(Enum.No)
109+
], Greeter.prototype, "greet");
110+
__decorate([
111+
lambda,
112+
deco
113+
], Greeter.prototype, "greet1");
114+
__decorate([
115+
__param(0, lambda(Enum.No)),
116+
__param(0, deco(Enum.No))
117+
], Greeter.prototype, "greet2");
118+
__decorate([
119+
__param(0, lambda),
120+
__param(0, deco)
121+
], Greeter.prototype, "greet3");
122+
Greeter = __decorate([
123+
lambda(Enum.No),
124+
deco(Enum.No)
125+
], Greeter);
126+
return Greeter;
127+
}());
128+
function deco() {
129+
var args = [];
130+
for (var _i = 0; _i < arguments.length; _i++) {
131+
args[_i] = arguments[_i];
132+
}
133+
}
134+
var Enum;
135+
(function (Enum) {
136+
Enum[Enum["No"] = 0] = "No";
137+
Enum[Enum["Yes"] = 1] = "Yes";
138+
})(Enum || (Enum = {}));
139+
var lambda = function () {
140+
var args = [];
141+
for (var _i = 0; _i < arguments.length; _i++) {
142+
args[_i] = arguments[_i];
143+
}
144+
};
145+
var Greeter1 = /** @class */ (function () {
146+
function Greeter1(message) {
147+
this.greeting = message;
148+
}
149+
Greeter1.prototype.greet = function () {
150+
return "Hello, " + this.greeting;
151+
};
152+
Greeter1.prototype.greet1 = function () {
153+
return "Hello, " + this.greeting;
154+
};
155+
Greeter1.prototype.greet2 = function (param) {
156+
return "Hello, " + this.greeting;
157+
};
158+
Greeter1.prototype.greet3 = function (param) {
159+
return "Hello, " + this.greeting;
160+
};
161+
__decorate([
162+
lambda(Enum.No),
163+
deco(Enum.No)
164+
], Greeter1.prototype, "greeting");
165+
__decorate([
166+
lambda(Enum.No),
167+
deco(Enum.No)
168+
], Greeter1.prototype, "greet");
169+
__decorate([
170+
lambda,
171+
deco
172+
], Greeter1.prototype, "greet1");
173+
__decorate([
174+
__param(0, lambda(Enum.No)),
175+
__param(0, deco(Enum.No))
176+
], Greeter1.prototype, "greet2");
177+
__decorate([
178+
__param(0, lambda),
179+
__param(0, deco)
180+
], Greeter1.prototype, "greet3");
181+
Greeter1 = __decorate([
182+
lambda(Enum.No),
183+
deco(Enum.No)
184+
], Greeter1);
185+
return Greeter1;
186+
}());

0 commit comments

Comments
 (0)