Skip to content

Commit 41ec0d4

Browse files
Copilotweswigham
andauthored
Use semantic type identity for JSDoc augments checks (microsoft/typescript-go#4889)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: weswigham <2932786+weswigham@users.noreply.github.com> Co-authored-by: Wesley Wigham <wwigham@gmail.com>
1 parent 3a2dcd3 commit 41ec0d4

16 files changed

Lines changed: 162 additions & 72 deletions

tsc/internal/checker/checker.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4325,6 +4325,7 @@ func (c *Checker) checkClassLikeDeclaration(node *ast.Node) {
43254325
baseTypes := c.getBaseTypes(classType)
43264326
if len(baseTypes) != 0 {
43274327
baseType := baseTypes[0]
4328+
c.checkJSDocAugmentsTagMatchesExtends(node, baseTypeNode, baseType)
43284329
baseConstructorType := c.getBaseConstructorTypeOfClass(classType)
43294330
staticBaseType := c.getApparentType(baseConstructorType)
43304331
c.checkBaseTypeAccessibility(staticBaseType, baseTypeNode)
@@ -4400,6 +4401,32 @@ func (c *Checker) checkClassLikeDeclaration(node *ast.Node) {
44004401
c.checkPropertyInitialization(node)
44014402
}
44024403

4404+
func (c *Checker) checkJSDocAugmentsTagMatchesExtends(node *ast.Node, baseTypeNode *ast.ExpressionWithTypeArgumentsNode, baseType *Type) {
4405+
if !ast.IsInJSFile(node) {
4406+
return
4407+
}
4408+
file := ast.GetSourceFileOfNode(node)
4409+
for _, j := range node.EagerJSDoc(file) {
4410+
if j.AsJSDoc().Tags == nil {
4411+
continue
4412+
}
4413+
for _, tag := range j.AsJSDoc().Tags.Nodes {
4414+
if tag.Kind != ast.KindJSDocAugmentsTag {
4415+
continue
4416+
}
4417+
sourceTypeNode := tag.ClassName()
4418+
if c.isTypeIdenticalTo(c.getTypeFromTypeNode(sourceTypeNode), baseType) {
4419+
continue
4420+
}
4421+
targetName := getIdentifierFromEntityNameExpression(baseTypeNode.Expression())
4422+
sourceName := getIdentifierFromEntityNameExpression(sourceTypeNode.Expression())
4423+
if targetName != nil && sourceName != nil {
4424+
c.error(sourceName, diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, tag.TagName().Text(), sourceName.Text(), targetName.Text())
4425+
}
4426+
}
4427+
}
4428+
}
4429+
44034430
func (c *Checker) checkClassForStaticPropertyNameConflicts(node *ast.Node) {
44044431
if c.compilerOptions.GetUseDefineForClassFields() {
44054432
return

tsc/internal/checker/grammarchecks.go

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -912,24 +912,6 @@ func (c *Checker) checkGrammarClassDeclarationHeritageClauses(node *ast.ClassLik
912912
return c.grammarErrorOnFirstToken(typeNodes[1], diagnostics.Classes_can_only_extend_a_single_class)
913913
}
914914

915-
if len(typeNodes) > 0 {
916-
for _, j := range node.EagerJSDoc(file) {
917-
if j.AsJSDoc().Tags == nil {
918-
continue
919-
}
920-
for _, tag := range j.AsJSDoc().Tags.Nodes {
921-
if tag.Kind == ast.KindJSDocAugmentsTag {
922-
target := typeNodes[0].AsExpressionWithTypeArguments()
923-
source := tag.ClassName().AsExpressionWithTypeArguments()
924-
targetName := getIdentifierFromEntityNameExpression(target.Expression)
925-
sourceName := getIdentifierFromEntityNameExpression(source.Expression)
926-
if targetName != nil && sourceName != nil && targetName.Text() != sourceName.Text() {
927-
return c.grammarErrorOnNode(sourceName, diagnostics.JSDoc_0_1_does_not_match_the_extends_2_clause, tag.TagName().Text(), sourceName.Text(), targetName.Text())
928-
}
929-
}
930-
}
931-
}
932-
}
933915
seenExtendsClause = true
934916
} else {
935917
if heritageClause.Token != ast.KindImplementsKeyword {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [tests/cases/compiler/jsdocAugmentsAliasExtends.ts] ////
2+
3+
=== jsdocAugmentsAliasExtends.ts ===
4+
declare class Base {
5+
>Base : Symbol(Base, Decl(jsdocAugmentsAliasExtends.ts, 0, 0))
6+
}
7+
declare class Other {
8+
>Other : Symbol(Other, Decl(jsdocAugmentsAliasExtends.ts, 1, 1))
9+
}
10+
declare const StateDependencies_base: typeof Base;
11+
>StateDependencies_base : Symbol(StateDependencies_base, Decl(jsdocAugmentsAliasExtends.ts, 4, 13))
12+
>Base : Symbol(Base, Decl(jsdocAugmentsAliasExtends.ts, 0, 0))
13+
14+
/**
15+
* @augments {Base}
16+
*/
17+
export declare class StateDependencies extends StateDependencies_base {
18+
>StateDependencies : Symbol(StateDependencies, Decl(jsdocAugmentsAliasExtends.ts, 4, 50))
19+
>StateDependencies_base : Symbol(StateDependencies_base, Decl(jsdocAugmentsAliasExtends.ts, 4, 13))
20+
}
21+
/**
22+
* @augments {Base}
23+
*/
24+
export declare class TypeScriptStateDependencies extends Other {
25+
>TypeScriptStateDependencies : Symbol(TypeScriptStateDependencies, Decl(jsdocAugmentsAliasExtends.ts, 9, 1))
26+
>Other : Symbol(Other, Decl(jsdocAugmentsAliasExtends.ts, 1, 1))
27+
}
28+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [tests/cases/compiler/jsdocAugmentsAliasExtends.ts] ////
2+
3+
=== jsdocAugmentsAliasExtends.ts ===
4+
declare class Base {
5+
>Base : Base
6+
}
7+
declare class Other {
8+
>Other : Other
9+
}
10+
declare const StateDependencies_base: typeof Base;
11+
>StateDependencies_base : typeof Base
12+
>Base : typeof Base
13+
14+
/**
15+
* @augments {Base}
16+
*/
17+
export declare class StateDependencies extends StateDependencies_base {
18+
>StateDependencies : StateDependencies
19+
>StateDependencies_base : Base
20+
}
21+
/**
22+
* @augments {Base}
23+
*/
24+
export declare class TypeScriptStateDependencies extends Other {
25+
>TypeScriptStateDependencies : TypeScriptStateDependencies
26+
>Other : Other
27+
}
28+

tsc/testdata/baselines/reference/compiler/jsdocExtendsClauseMismatch.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ main.js(2,20): error TS8023: JSDoc '@extends Component' does not match the 'exte
33

44
==== react.d.ts (0 errors) ====
55
declare namespace React {
6-
class Component {}
7-
class PureComponent {}
6+
class Component { component: string }
7+
class PureComponent { pure: string }
88
}
99

1010
==== main.js (1 errors) ====

tsc/testdata/baselines/reference/compiler/jsdocExtendsClauseMismatch.symbols

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
declare namespace React {
55
>React : Symbol(React, Decl(react.d.ts, 0, 0))
66

7-
class Component {}
7+
class Component { component: string }
88
>Component : Symbol(Component, Decl(react.d.ts, 0, 25))
9+
>component : Symbol(Component.component, Decl(react.d.ts, 1, 21))
910

10-
class PureComponent {}
11-
>PureComponent : Symbol(PureComponent, Decl(react.d.ts, 1, 22))
11+
class PureComponent { pure: string }
12+
>PureComponent : Symbol(PureComponent, Decl(react.d.ts, 1, 41))
13+
>pure : Symbol(PureComponent.pure, Decl(react.d.ts, 2, 25))
1214
}
1315

1416
=== main.js ===
@@ -17,9 +19,9 @@ declare namespace React {
1719
*/
1820
class C extends React.PureComponent {}
1921
>C : Symbol(C, Decl(main.js, 0, 0))
20-
>React.PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 1, 22))
22+
>React.PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 1, 41))
2123
>React : Symbol(React, Decl(react.d.ts, 0, 0))
22-
>PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 1, 22))
24+
>PureComponent : Symbol(React.PureComponent, Decl(react.d.ts, 1, 41))
2325

2426
/**
2527
* @extends {React.Component}

tsc/testdata/baselines/reference/compiler/jsdocExtendsClauseMismatch.types

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
declare namespace React {
55
>React : typeof React
66

7-
class Component {}
7+
class Component { component: string }
88
>Component : Component
9+
>component : string
910

10-
class PureComponent {}
11+
class PureComponent { pure: string }
1112
>PureComponent : PureComponent
13+
>pure : string
1214
}
1315

1416
=== main.js ===

tsc/testdata/baselines/reference/compiler/superCallInJSWithWrongBaseTypeArgumentCount2(strict=true).errors.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
error TS5055: Cannot write file 'b.js' because it would overwrite input file.
22
Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.
3+
b.js(3,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
34
b.js(4,25): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
5+
b.js(17,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
46
b.js(18,25): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
57

68

@@ -9,10 +11,12 @@ b.js(18,25): error TS8026: Expected A<T> type arguments; provide these with an '
911
==== a.ts (0 errors) ====
1012
export class A<T> {}
1113

12-
==== b.js (2 errors) ====
14+
==== b.js (4 errors) ====
1315
import { A } from './a.js';
1416

1517
/** @extends {A} */
18+
~
19+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
1620
export class B1 extends A {
1721
~
1822
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
@@ -29,6 +33,8 @@ b.js(18,25): error TS8026: Expected A<T> type arguments; provide these with an '
2933
}
3034

3135
/** @extends {A<string, string>} */
36+
~~~~~~~~~~~~~~~~~
37+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
3238
export class B3 extends A {
3339
~
3440
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.

tsc/testdata/baselines/reference/submodule/compiler/jsExtendsImplicitAny.errors.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
/b.js(1,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
2+
/b.js(4,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
23
/b.js(5,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
4+
/b.js(8,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
35
/b.js(9,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
46

57

68
==== /a.d.ts (0 errors) ====
79
declare class A<T> { x: T; }
810

9-
==== /b.js (3 errors) ====
11+
==== /b.js (5 errors) ====
1012
class B extends A {}
1113
~
1214
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
1315
new B().x;
1416

1517
/** @augments A */
18+
~
19+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
1620
class C extends A { }
1721
~
1822
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
1923
new C().x;
2024

2125
/** @augments A<number, number, number> */
26+
~~~~~~~~~~~~~~~~~~~~~~~~~
27+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
2228
class D extends A {}
2329
~
2430
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.

tsc/testdata/baselines/reference/submodule/compiler/jsExtendsImplicitAny.errors.txt.diff

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,31 @@
22
+++ new.jsExtendsImplicitAny.errors.txt
33
@@= skipped -0, +0 lines =@@
44
/b.js(1,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
5-
-/b.js(4,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
6-
-/b.js(8,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
5+
/b.js(4,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
76
+/b.js(5,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
7+
/b.js(8,15): error TS2314: Generic type 'A<T>' requires 1 type argument(s).
88
+/b.js(9,17): error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
99

1010

1111
==== /a.d.ts (0 errors) ====
12-
@@= skipped -12, +12 lines =@@
13-
new B().x;
12+
declare class A<T> { x: T; }
1413

15-
/** @augments A */
16-
- ~
17-
-!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
14+
-==== /b.js (3 errors) ====
15+
+==== /b.js (5 errors) ====
16+
class B extends A {}
17+
~
18+
!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
19+
@@= skipped -15, +17 lines =@@
20+
~
21+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
1822
class C extends A { }
1923
+ ~
2024
+!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.
2125
new C().x;
2226

2327
/** @augments A<number, number, number> */
24-
- ~~~~~~~~~~~~~~~~~~~~~~~~~
25-
-!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
28+
~~~~~~~~~~~~~~~~~~~~~~~~~
29+
!!! error TS2314: Generic type 'A<T>' requires 1 type argument(s).
2630
class D extends A {}
2731
+ ~
2832
+!!! error TS8026: Expected A<T> type arguments; provide these with an '@extends' tag.

0 commit comments

Comments
 (0)