From 8031bd3bb82c77256810e826b2c92418970bff69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 4 Oct 2025 11:35:56 +0200 Subject: [PATCH] Port "check usage before declaration for decorators" Co-authored-by: Zzzen --- internal/checker/checker.go | 11 ++- ...lockScopedVariablesUseBeforeDef.errors.txt | 14 +++- ...copedVariablesUseBeforeDef.errors.txt.diff | 44 ------------ .../decoratorUsedBeforeDeclaration.errors.txt | 34 ++++++++- ...ratorUsedBeforeDeclaration.errors.txt.diff | 72 +++---------------- 5 files changed, 66 insertions(+), 109 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt.diff diff --git a/internal/checker/checker.go b/internal/checker/checker.go index f0323ed53d..2e1a8fcb7d 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -1906,7 +1906,7 @@ func (c *Checker) isBlockScopedNameDeclaredBeforeUse(declaration *ast.Node, usag func (c *Checker) isUsedInFunctionOrInstanceProperty(usage *ast.Node, declaration *ast.Node, declContainer *ast.Node) bool { for current := usage; current != nil && current != declContainer; current = current.Parent { if ast.IsFunctionLike(current) { - return true + return ast.GetImmediatelyInvokedFunctionExpression(current) == nil } if ast.IsClassStaticBlockDeclaration(current) { return declaration.Pos() < usage.Pos() @@ -1933,6 +1933,15 @@ func (c *Checker) isUsedInFunctionOrInstanceProperty(usage *ast.Node, declaratio } } } + if current.Parent != nil && ast.IsDecorator(current.Parent) && current.Parent.AsDecorator().Expression == current { + decorator := current.Parent.AsDecorator() + if ast.IsParameter(decorator.Parent) { + return c.isUsedInFunctionOrInstanceProperty(decorator.Parent.Parent.Parent, declaration, declContainer) + } + if ast.IsMethodDeclaration(decorator.Parent) { + return c.isUsedInFunctionOrInstanceProperty(decorator.Parent.Parent, declaration, declContainer) + } + } } return false } diff --git a/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt b/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt index 8995ac009c..7beb2b37b9 100644 --- a/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt @@ -5,9 +5,12 @@ blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448: Block-scoped variable blockScopedVariablesUseBeforeDef.ts(111,28): error TS2448: Block-scoped variable 'a' used before its declaration. blockScopedVariablesUseBeforeDef.ts(112,21): error TS2448: Block-scoped variable 'a' used before its declaration. blockScopedVariablesUseBeforeDef.ts(122,22): error TS2448: Block-scoped variable 'a' used before its declaration. +blockScopedVariablesUseBeforeDef.ts(128,9): error TS2448: Block-scoped variable 'foo' used before its declaration. +blockScopedVariablesUseBeforeDef.ts(131,9): error TS2448: Block-scoped variable 'foo' used before its declaration. +blockScopedVariablesUseBeforeDef.ts(153,20): error TS2450: Enum 'Enum' used before its declaration. -==== blockScopedVariablesUseBeforeDef.ts (7 errors) ==== +==== blockScopedVariablesUseBeforeDef.ts (10 errors) ==== function foo0() { let a = x; ~ @@ -157,9 +160,15 @@ blockScopedVariablesUseBeforeDef.ts(122,22): error TS2448: Block-scoped variable const promise = (async () => { promise foo + ~~~ +!!! error TS2448: Block-scoped variable 'foo' used before its declaration. +!!! related TS2728 blockScopedVariablesUseBeforeDef.ts:134:11: 'foo' is declared here. await null promise foo + ~~~ +!!! error TS2448: Block-scoped variable 'foo' used before its declaration. +!!! related TS2728 blockScopedVariablesUseBeforeDef.ts:134:11: 'foo' is declared here. })() const foo = 1; @@ -182,6 +191,9 @@ blockScopedVariablesUseBeforeDef.ts(122,22): error TS2448: Block-scoped variable function foo18() { let a = (() => Enum.Yes)(); + ~~~~ +!!! error TS2450: Enum 'Enum' used before its declaration. +!!! related TS2728 blockScopedVariablesUseBeforeDef.ts:154:10: 'Enum' is declared here. enum Enum { No = 0, Yes = 1, diff --git a/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt.diff deleted file mode 100644 index b610dff2c5..0000000000 --- a/testdata/baselines/reference/submodule/compiler/blockScopedVariablesUseBeforeDef.errors.txt.diff +++ /dev/null @@ -1,44 +0,0 @@ ---- old.blockScopedVariablesUseBeforeDef.errors.txt -+++ new.blockScopedVariablesUseBeforeDef.errors.txt -@@= skipped -4, +4 lines =@@ - blockScopedVariablesUseBeforeDef.ts(111,28): error TS2448: Block-scoped variable 'a' used before its declaration. - blockScopedVariablesUseBeforeDef.ts(112,21): error TS2448: Block-scoped variable 'a' used before its declaration. - blockScopedVariablesUseBeforeDef.ts(122,22): error TS2448: Block-scoped variable 'a' used before its declaration. --blockScopedVariablesUseBeforeDef.ts(128,9): error TS2448: Block-scoped variable 'foo' used before its declaration. --blockScopedVariablesUseBeforeDef.ts(131,9): error TS2448: Block-scoped variable 'foo' used before its declaration. --blockScopedVariablesUseBeforeDef.ts(153,20): error TS2450: Enum 'Enum' used before its declaration. -- -- --==== blockScopedVariablesUseBeforeDef.ts (10 errors) ==== -+ -+ -+==== blockScopedVariablesUseBeforeDef.ts (7 errors) ==== - function foo0() { - let a = x; - ~ -@@= skipped -155, +152 lines =@@ - const promise = (async () => { - promise - foo -- ~~~ --!!! error TS2448: Block-scoped variable 'foo' used before its declaration. --!!! related TS2728 blockScopedVariablesUseBeforeDef.ts:134:11: 'foo' is declared here. - await null - promise - foo -- ~~~ --!!! error TS2448: Block-scoped variable 'foo' used before its declaration. --!!! related TS2728 blockScopedVariablesUseBeforeDef.ts:134:11: 'foo' is declared here. - })() - - const foo = 1; -@@= skipped -31, +25 lines =@@ - - function foo18() { - let a = (() => Enum.Yes)(); -- ~~~~ --!!! error TS2450: Enum 'Enum' used before its declaration. --!!! related TS2728 blockScopedVariablesUseBeforeDef.ts:154:10: 'Enum' is declared here. - enum Enum { - No = 0, - Yes = 1, \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt b/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt index a5829d2097..d687b88bab 100644 --- a/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt @@ -4,9 +4,17 @@ decoratorUsedBeforeDeclaration.ts(2,7): error TS2450: Enum 'Enum' used before it decoratorUsedBeforeDeclaration.ts(4,4): error TS2448: Block-scoped variable 'lambda' used before its declaration. decoratorUsedBeforeDeclaration.ts(4,11): error TS2450: Enum 'Enum' used before its declaration. decoratorUsedBeforeDeclaration.ts(5,9): error TS2450: Enum 'Enum' used before its declaration. +decoratorUsedBeforeDeclaration.ts(12,4): error TS2448: Block-scoped variable 'lambda' used before its declaration. +decoratorUsedBeforeDeclaration.ts(12,11): error TS2450: Enum 'Enum' used before its declaration. +decoratorUsedBeforeDeclaration.ts(13,9): error TS2450: Enum 'Enum' used before its declaration. +decoratorUsedBeforeDeclaration.ts(18,4): error TS2448: Block-scoped variable 'lambda' used before its declaration. +decoratorUsedBeforeDeclaration.ts(24,11): error TS2448: Block-scoped variable 'lambda' used before its declaration. +decoratorUsedBeforeDeclaration.ts(24,18): error TS2450: Enum 'Enum' used before its declaration. +decoratorUsedBeforeDeclaration.ts(24,33): error TS2450: Enum 'Enum' used before its declaration. +decoratorUsedBeforeDeclaration.ts(28,11): error TS2448: Block-scoped variable 'lambda' used before its declaration. -==== decoratorUsedBeforeDeclaration.ts (6 errors) ==== +==== decoratorUsedBeforeDeclaration.ts (14 errors) ==== @lambda(Enum.No) ~~~~~~ !!! error TS2448: Block-scoped variable 'lambda' used before its declaration. @@ -37,22 +45,46 @@ decoratorUsedBeforeDeclaration.ts(5,9): error TS2450: Enum 'Enum' used before it } @lambda(Enum.No) + ~~~~~~ +!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. + ~~~~ +!!! error TS2450: Enum 'Enum' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. @deco(Enum.No) + ~~~~ +!!! error TS2450: Enum 'Enum' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. greet() { return "Hello, " + this.greeting; } @lambda + ~~~~~~ +!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. @deco greet1() { return "Hello, " + this.greeting; } greet2(@lambda(Enum.No) @deco(Enum.No) param) { + ~~~~~~ +!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. + ~~~~ +!!! error TS2450: Enum 'Enum' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. + ~~~~ +!!! error TS2450: Enum 'Enum' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. return "Hello, " + this.greeting; } greet3(@lambda @deco param) { + ~~~~~~ +!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. +!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. return "Hello, " + this.greeting; } } diff --git a/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt.diff index 56dfc89192..9df18b5ead 100644 --- a/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt.diff +++ b/testdata/baselines/reference/submodule/compiler/decoratorUsedBeforeDeclaration.errors.txt.diff @@ -7,24 +7,19 @@ -decoratorUsedBeforeDeclaration.ts(4,16): error TS2729: Property 'No' is used before its initialization. decoratorUsedBeforeDeclaration.ts(5,9): error TS2450: Enum 'Enum' used before its declaration. -decoratorUsedBeforeDeclaration.ts(5,14): error TS2729: Property 'No' is used before its initialization. --decoratorUsedBeforeDeclaration.ts(12,4): error TS2448: Block-scoped variable 'lambda' used before its declaration. --decoratorUsedBeforeDeclaration.ts(12,11): error TS2450: Enum 'Enum' used before its declaration. --decoratorUsedBeforeDeclaration.ts(13,9): error TS2450: Enum 'Enum' used before its declaration. --decoratorUsedBeforeDeclaration.ts(18,4): error TS2448: Block-scoped variable 'lambda' used before its declaration. --decoratorUsedBeforeDeclaration.ts(24,11): error TS2448: Block-scoped variable 'lambda' used before its declaration. --decoratorUsedBeforeDeclaration.ts(24,18): error TS2450: Enum 'Enum' used before its declaration. --decoratorUsedBeforeDeclaration.ts(24,33): error TS2450: Enum 'Enum' used before its declaration. --decoratorUsedBeforeDeclaration.ts(28,11): error TS2448: Block-scoped variable 'lambda' used before its declaration. -- -- + decoratorUsedBeforeDeclaration.ts(12,4): error TS2448: Block-scoped variable 'lambda' used before its declaration. + decoratorUsedBeforeDeclaration.ts(12,11): error TS2450: Enum 'Enum' used before its declaration. + decoratorUsedBeforeDeclaration.ts(13,9): error TS2450: Enum 'Enum' used before its declaration. +@@= skipped -13, +11 lines =@@ + decoratorUsedBeforeDeclaration.ts(28,11): error TS2448: Block-scoped variable 'lambda' used before its declaration. + + -==== decoratorUsedBeforeDeclaration.ts (16 errors) ==== -+ -+ -+==== decoratorUsedBeforeDeclaration.ts (6 errors) ==== ++==== decoratorUsedBeforeDeclaration.ts (14 errors) ==== @lambda(Enum.No) ~~~~~~ !!! error TS2448: Block-scoped variable 'lambda' used before its declaration. -@@= skipped -33, +23 lines =@@ +@@= skipped -20, +20 lines =@@ ~~~~ !!! error TS2450: Enum 'Enum' used before its declaration. !!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. @@ -40,51 +35,4 @@ -!!! related TS2728 decoratorUsedBeforeDeclaration.ts:36:3: 'No' is declared here. greeting: string; - constructor(message: string) { -@@= skipped -17, +11 lines =@@ - } - - @lambda(Enum.No) -- ~~~~~~ --!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. -- ~~~~ --!!! error TS2450: Enum 'Enum' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. - @deco(Enum.No) -- ~~~~ --!!! error TS2450: Enum 'Enum' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. - greet() { - return "Hello, " + this.greeting; - } - - @lambda -- ~~~~~~ --!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. - @deco - greet1() { - return "Hello, " + this.greeting; - } - - greet2(@lambda(Enum.No) @deco(Enum.No) param) { -- ~~~~~~ --!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. -- ~~~~ --!!! error TS2450: Enum 'Enum' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. -- ~~~~ --!!! error TS2450: Enum 'Enum' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:35:6: 'Enum' is declared here. - return "Hello, " + this.greeting; - } - - greet3(@lambda @deco param) { -- ~~~~~~ --!!! error TS2448: Block-scoped variable 'lambda' used before its declaration. --!!! related TS2728 decoratorUsedBeforeDeclaration.ts:40:7: 'lambda' is declared here. - return "Hello, " + this.greeting; - } - } \ No newline at end of file + constructor(message: string) { \ No newline at end of file