Skip to content

Commit 392fd0a

Browse files
authored
Remove bogus @implements errors (#37114)
* Remove bogus @implements errors Make the search for the actual host more comprehensive by reusing the code that previously only searched for functions. I don't know what to call this function now, since the old name wasn't accurate either. * undo gratuitous name change * Improve name and make calling more uniform It's slightly less efficient but I think worthwhile for readability.
1 parent 1e46185 commit 392fd0a

File tree

7 files changed

+284
-10
lines changed

7 files changed

+284
-10
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,8 +2910,8 @@ namespace ts {
29102910
return getDeclarationOfJSPrototypeContainer(symbol);
29112911
}
29122912
}
2913-
const sig = getHostSignatureFromJSDocHost(host);
2914-
if (sig) {
2913+
const sig = getEffectiveJSDocHost(node);
2914+
if (sig && isFunctionLike(sig)) {
29152915
const symbol = getSymbolOfNode(sig);
29162916
return symbol && symbol.valueDeclaration;
29172917
}
@@ -30444,15 +30444,14 @@ namespace ts {
3044430444
}
3044530445

3044630446
function checkJSDocImplementsTag(node: JSDocImplementsTag): void {
30447-
const classLike = getJSDocHost(node);
30448-
if (!isClassDeclaration(classLike) && !isClassExpression(classLike)) {
30447+
const classLike = getEffectiveJSDocHost(node);
30448+
if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) {
3044930449
error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName));
30450-
return;
3045130450
}
3045230451
}
3045330452
function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void {
30454-
const classLike = getJSDocHost(node);
30455-
if (!isClassDeclaration(classLike) && !isClassExpression(classLike)) {
30453+
const classLike = getEffectiveJSDocHost(node);
30454+
if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) {
3045630455
error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName));
3045730456
return;
3045830457
}

src/compiler/utilities.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,19 +2466,22 @@ namespace ts {
24662466
}
24672467

24682468
export function getHostSignatureFromJSDoc(node: Node): SignatureDeclaration | undefined {
2469-
return getHostSignatureFromJSDocHost(getJSDocHost(node));
2469+
const host = getEffectiveJSDocHost(node);
2470+
return host && isFunctionLike(host) ? host : undefined;
24702471
}
24712472

2472-
export function getHostSignatureFromJSDocHost(host: HasJSDoc): SignatureDeclaration | undefined {
2473+
export function getEffectiveJSDocHost(node: Node): Node | undefined {
2474+
const host = getJSDocHost(node);
24732475
const decl = getSourceOfDefaultedAssignment(host) ||
24742476
getSourceOfAssignment(host) ||
24752477
getSingleInitializerOfVariableStatementOrPropertyDeclaration(host) ||
24762478
getSingleVariableOfVariableStatement(host) ||
24772479
getNestedModuleDeclaration(host) ||
24782480
host;
2479-
return decl && isFunctionLike(decl) ? decl : undefined;
2481+
return decl;
24802482
}
24812483

2484+
/** Use getEffectiveJSDocHost if you additionally need to look for jsdoc on parent nodes, like assignments. */
24822485
export function getJSDocHost(node: Node): HasJSDoc {
24832486
return Debug.checkDefined(findAncestor(node.parent, isJSDoc)).parent;
24842487
}

tests/baselines/reference/jsdocImplements_class.errors.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,37 @@
3232
!!! error TS2720: Property 'method' is missing in type 'B3' but required in type 'A'.
3333
!!! related TS2728 /a.js:3:5: 'method' is declared here.
3434
}
35+
36+
37+
var Ns = {};
38+
/** @implements {A} */
39+
Ns.C1 = class {
40+
method() { return 11; }
41+
}
42+
/** @implements {A} */
43+
var C2 = class {
44+
method() { return 12; }
45+
}
46+
var o = {
47+
/** @implements {A} */
48+
C3: class {
49+
method() { return 13; }
50+
}
51+
}
52+
class CC {
53+
/** @implements {A} */
54+
C4 = class {
55+
method() {
56+
return 14;
57+
}
58+
}
59+
}
60+
61+
var C5;
62+
/** @implements {A} */
63+
Ns.C5 = C5 || class {
64+
method() {
65+
return 15;
66+
}
67+
}
3568

tests/baselines/reference/jsdocImplements_class.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,39 @@ class B2 {
1717
/** @implements {A} */
1818
class B3 {
1919
}
20+
21+
22+
var Ns = {};
23+
/** @implements {A} */
24+
Ns.C1 = class {
25+
method() { return 11; }
26+
}
27+
/** @implements {A} */
28+
var C2 = class {
29+
method() { return 12; }
30+
}
31+
var o = {
32+
/** @implements {A} */
33+
C3: class {
34+
method() { return 13; }
35+
}
36+
}
37+
class CC {
38+
/** @implements {A} */
39+
C4 = class {
40+
method() {
41+
return 14;
42+
}
43+
}
44+
}
45+
46+
var C5;
47+
/** @implements {A} */
48+
Ns.C5 = C5 || class {
49+
method() {
50+
return 15;
51+
}
52+
}
2053

2154

2255

@@ -38,3 +71,35 @@ declare class B2 implements A {
3871
/** @implements {A} */
3972
declare class B3 implements A {
4073
}
74+
declare namespace Ns {
75+
export { C1 };
76+
const C5: {
77+
new (): {
78+
method(): number;
79+
};
80+
};
81+
}
82+
/** @implements {A} */
83+
declare var C2: {
84+
new (): {
85+
method(): number;
86+
};
87+
};
88+
declare namespace o {
89+
export { C3 };
90+
}
91+
declare class CC {
92+
/** @implements {A} */
93+
C4: {
94+
new (): {
95+
method(): number;
96+
};
97+
};
98+
}
99+
declare var C5: any;
100+
declare class C1 implements A {
101+
method(): number;
102+
}
103+
declare class C3 implements A {
104+
method(): number;
105+
}

tests/baselines/reference/jsdocImplements_class.symbols

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,66 @@ class B3 {
2929
>B3 : Symbol(B3, Decl(a.js, 13, 1))
3030
}
3131

32+
33+
var Ns = {};
34+
>Ns : Symbol(Ns, Decl(a.js, 20, 3), Decl(a.js, 20, 12), Decl(a.js, 44, 7))
35+
36+
/** @implements {A} */
37+
Ns.C1 = class {
38+
>Ns.C1 : Symbol(Ns.C1, Decl(a.js, 20, 12))
39+
>Ns : Symbol(Ns, Decl(a.js, 20, 3), Decl(a.js, 20, 12), Decl(a.js, 44, 7))
40+
>C1 : Symbol(Ns.C1, Decl(a.js, 20, 12))
41+
42+
method() { return 11; }
43+
>method : Symbol(C1.method, Decl(a.js, 22, 15))
44+
}
45+
/** @implements {A} */
46+
var C2 = class {
47+
>C2 : Symbol(C2, Decl(a.js, 26, 3))
48+
49+
method() { return 12; }
50+
>method : Symbol(C2.method, Decl(a.js, 26, 16))
51+
}
52+
var o = {
53+
>o : Symbol(o, Decl(a.js, 29, 3))
54+
55+
/** @implements {A} */
56+
C3: class {
57+
>C3 : Symbol(C3, Decl(a.js, 29, 9))
58+
59+
method() { return 13; }
60+
>method : Symbol(C3.method, Decl(a.js, 31, 15))
61+
}
62+
}
63+
class CC {
64+
>CC : Symbol(CC, Decl(a.js, 34, 1))
65+
66+
/** @implements {A} */
67+
C4 = class {
68+
>C4 : Symbol(CC.C4, Decl(a.js, 35, 10))
69+
70+
method() {
71+
>method : Symbol((Anonymous class).method, Decl(a.js, 37, 16))
72+
73+
return 14;
74+
}
75+
}
76+
}
77+
78+
var C5;
79+
>C5 : Symbol(C5, Decl(a.js, 44, 3))
80+
81+
/** @implements {A} */
82+
Ns.C5 = C5 || class {
83+
>Ns.C5 : Symbol(Ns.C5, Decl(a.js, 44, 7))
84+
>Ns : Symbol(Ns, Decl(a.js, 20, 3), Decl(a.js, 20, 12), Decl(a.js, 44, 7))
85+
>C5 : Symbol(Ns.C5, Decl(a.js, 44, 7))
86+
>C5 : Symbol(C5, Decl(a.js, 44, 3))
87+
88+
method() {
89+
>method : Symbol(C5.method, Decl(a.js, 46, 21))
90+
91+
return 15;
92+
}
93+
}
94+

tests/baselines/reference/jsdocImplements_class.types

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,81 @@ class B3 {
3232
>B3 : B3
3333
}
3434

35+
36+
var Ns = {};
37+
>Ns : typeof Ns
38+
>{} : {}
39+
40+
/** @implements {A} */
41+
Ns.C1 = class {
42+
>Ns.C1 = class { method() { return 11; }} : typeof C1
43+
>Ns.C1 : typeof C1
44+
>Ns : typeof Ns
45+
>C1 : typeof C1
46+
>class { method() { return 11; }} : typeof C1
47+
48+
method() { return 11; }
49+
>method : () => number
50+
>11 : 11
51+
}
52+
/** @implements {A} */
53+
var C2 = class {
54+
>C2 : typeof C2
55+
>class { method() { return 12; }} : typeof C2
56+
57+
method() { return 12; }
58+
>method : () => number
59+
>12 : 12
60+
}
61+
var o = {
62+
>o : { C3: typeof C3; }
63+
>{ /** @implements {A} */ C3: class { method() { return 13; } }} : { C3: typeof C3; }
64+
65+
/** @implements {A} */
66+
C3: class {
67+
>C3 : typeof C3
68+
>class { method() { return 13; } } : typeof C3
69+
70+
method() { return 13; }
71+
>method : () => number
72+
>13 : 13
73+
}
74+
}
75+
class CC {
76+
>CC : CC
77+
78+
/** @implements {A} */
79+
C4 = class {
80+
>C4 : typeof (Anonymous class)
81+
>class { method() { return 14; } } : typeof (Anonymous class)
82+
83+
method() {
84+
>method : () => number
85+
86+
return 14;
87+
>14 : 14
88+
}
89+
}
90+
}
91+
92+
var C5;
93+
>C5 : any
94+
95+
/** @implements {A} */
96+
Ns.C5 = C5 || class {
97+
>Ns.C5 = C5 || class { method() { return 15; }} : typeof C5
98+
>Ns.C5 : typeof C5
99+
>Ns : typeof Ns
100+
>C5 : typeof C5
101+
>C5 || class { method() { return 15; }} : typeof C5
102+
>C5 : undefined
103+
>class { method() { return 15; }} : typeof C5
104+
105+
method() {
106+
>method : () => number
107+
108+
return 15;
109+
>15 : 15
110+
}
111+
}
112+

tests/cases/conformance/jsdoc/jsdocImplements_class.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,36 @@ class B2 {
2323
/** @implements {A} */
2424
class B3 {
2525
}
26+
27+
28+
var Ns = {};
29+
/** @implements {A} */
30+
Ns.C1 = class {
31+
method() { return 11; }
32+
}
33+
/** @implements {A} */
34+
var C2 = class {
35+
method() { return 12; }
36+
}
37+
var o = {
38+
/** @implements {A} */
39+
C3: class {
40+
method() { return 13; }
41+
}
42+
}
43+
class CC {
44+
/** @implements {A} */
45+
C4 = class {
46+
method() {
47+
return 14;
48+
}
49+
}
50+
}
51+
52+
var C5;
53+
/** @implements {A} */
54+
Ns.C5 = C5 || class {
55+
method() {
56+
return 15;
57+
}
58+
}

0 commit comments

Comments
 (0)