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.
This commit is contained in:
Nathan Shively-Sanders 2020-03-02 09:48:53 -08:00 committed by GitHub
parent 1e46185506
commit 392fd0ac0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 284 additions and 10 deletions

View File

@ -2910,8 +2910,8 @@ namespace ts {
return getDeclarationOfJSPrototypeContainer(symbol);
}
}
const sig = getHostSignatureFromJSDocHost(host);
if (sig) {
const sig = getEffectiveJSDocHost(node);
if (sig && isFunctionLike(sig)) {
const symbol = getSymbolOfNode(sig);
return symbol && symbol.valueDeclaration;
}
@ -30444,15 +30444,14 @@ namespace ts {
}
function checkJSDocImplementsTag(node: JSDocImplementsTag): void {
const classLike = getJSDocHost(node);
if (!isClassDeclaration(classLike) && !isClassExpression(classLike)) {
const classLike = getEffectiveJSDocHost(node);
if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) {
error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName));
return;
}
}
function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void {
const classLike = getJSDocHost(node);
if (!isClassDeclaration(classLike) && !isClassExpression(classLike)) {
const classLike = getEffectiveJSDocHost(node);
if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) {
error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName));
return;
}

View File

@ -2466,19 +2466,22 @@ namespace ts {
}
export function getHostSignatureFromJSDoc(node: Node): SignatureDeclaration | undefined {
return getHostSignatureFromJSDocHost(getJSDocHost(node));
const host = getEffectiveJSDocHost(node);
return host && isFunctionLike(host) ? host : undefined;
}
export function getHostSignatureFromJSDocHost(host: HasJSDoc): SignatureDeclaration | undefined {
export function getEffectiveJSDocHost(node: Node): Node | undefined {
const host = getJSDocHost(node);
const decl = getSourceOfDefaultedAssignment(host) ||
getSourceOfAssignment(host) ||
getSingleInitializerOfVariableStatementOrPropertyDeclaration(host) ||
getSingleVariableOfVariableStatement(host) ||
getNestedModuleDeclaration(host) ||
host;
return decl && isFunctionLike(decl) ? decl : undefined;
return decl;
}
/** Use getEffectiveJSDocHost if you additionally need to look for jsdoc on parent nodes, like assignments. */
export function getJSDocHost(node: Node): HasJSDoc {
return Debug.checkDefined(findAncestor(node.parent, isJSDoc)).parent;
}

View File

@ -32,4 +32,37 @@
!!! error TS2720: Property 'method' is missing in type 'B3' but required in type 'A'.
!!! related TS2728 /a.js:3:5: 'method' is declared here.
}
var Ns = {};
/** @implements {A} */
Ns.C1 = class {
method() { return 11; }
}
/** @implements {A} */
var C2 = class {
method() { return 12; }
}
var o = {
/** @implements {A} */
C3: class {
method() { return 13; }
}
}
class CC {
/** @implements {A} */
C4 = class {
method() {
return 14;
}
}
}
var C5;
/** @implements {A} */
Ns.C5 = C5 || class {
method() {
return 15;
}
}

View File

@ -17,6 +17,39 @@ class B2 {
/** @implements {A} */
class B3 {
}
var Ns = {};
/** @implements {A} */
Ns.C1 = class {
method() { return 11; }
}
/** @implements {A} */
var C2 = class {
method() { return 12; }
}
var o = {
/** @implements {A} */
C3: class {
method() { return 13; }
}
}
class CC {
/** @implements {A} */
C4 = class {
method() {
return 14;
}
}
}
var C5;
/** @implements {A} */
Ns.C5 = C5 || class {
method() {
return 15;
}
}
@ -38,3 +71,35 @@ declare class B2 implements A {
/** @implements {A} */
declare class B3 implements A {
}
declare namespace Ns {
export { C1 };
const C5: {
new (): {
method(): number;
};
};
}
/** @implements {A} */
declare var C2: {
new (): {
method(): number;
};
};
declare namespace o {
export { C3 };
}
declare class CC {
/** @implements {A} */
C4: {
new (): {
method(): number;
};
};
}
declare var C5: any;
declare class C1 implements A {
method(): number;
}
declare class C3 implements A {
method(): number;
}

View File

@ -29,3 +29,66 @@ class B3 {
>B3 : Symbol(B3, Decl(a.js, 13, 1))
}
var Ns = {};
>Ns : Symbol(Ns, Decl(a.js, 20, 3), Decl(a.js, 20, 12), Decl(a.js, 44, 7))
/** @implements {A} */
Ns.C1 = class {
>Ns.C1 : Symbol(Ns.C1, Decl(a.js, 20, 12))
>Ns : Symbol(Ns, Decl(a.js, 20, 3), Decl(a.js, 20, 12), Decl(a.js, 44, 7))
>C1 : Symbol(Ns.C1, Decl(a.js, 20, 12))
method() { return 11; }
>method : Symbol(C1.method, Decl(a.js, 22, 15))
}
/** @implements {A} */
var C2 = class {
>C2 : Symbol(C2, Decl(a.js, 26, 3))
method() { return 12; }
>method : Symbol(C2.method, Decl(a.js, 26, 16))
}
var o = {
>o : Symbol(o, Decl(a.js, 29, 3))
/** @implements {A} */
C3: class {
>C3 : Symbol(C3, Decl(a.js, 29, 9))
method() { return 13; }
>method : Symbol(C3.method, Decl(a.js, 31, 15))
}
}
class CC {
>CC : Symbol(CC, Decl(a.js, 34, 1))
/** @implements {A} */
C4 = class {
>C4 : Symbol(CC.C4, Decl(a.js, 35, 10))
method() {
>method : Symbol((Anonymous class).method, Decl(a.js, 37, 16))
return 14;
}
}
}
var C5;
>C5 : Symbol(C5, Decl(a.js, 44, 3))
/** @implements {A} */
Ns.C5 = C5 || class {
>Ns.C5 : Symbol(Ns.C5, Decl(a.js, 44, 7))
>Ns : Symbol(Ns, Decl(a.js, 20, 3), Decl(a.js, 20, 12), Decl(a.js, 44, 7))
>C5 : Symbol(Ns.C5, Decl(a.js, 44, 7))
>C5 : Symbol(C5, Decl(a.js, 44, 3))
method() {
>method : Symbol(C5.method, Decl(a.js, 46, 21))
return 15;
}
}

View File

@ -32,3 +32,81 @@ class B3 {
>B3 : B3
}
var Ns = {};
>Ns : typeof Ns
>{} : {}
/** @implements {A} */
Ns.C1 = class {
>Ns.C1 = class { method() { return 11; }} : typeof C1
>Ns.C1 : typeof C1
>Ns : typeof Ns
>C1 : typeof C1
>class { method() { return 11; }} : typeof C1
method() { return 11; }
>method : () => number
>11 : 11
}
/** @implements {A} */
var C2 = class {
>C2 : typeof C2
>class { method() { return 12; }} : typeof C2
method() { return 12; }
>method : () => number
>12 : 12
}
var o = {
>o : { C3: typeof C3; }
>{ /** @implements {A} */ C3: class { method() { return 13; } }} : { C3: typeof C3; }
/** @implements {A} */
C3: class {
>C3 : typeof C3
>class { method() { return 13; } } : typeof C3
method() { return 13; }
>method : () => number
>13 : 13
}
}
class CC {
>CC : CC
/** @implements {A} */
C4 = class {
>C4 : typeof (Anonymous class)
>class { method() { return 14; } } : typeof (Anonymous class)
method() {
>method : () => number
return 14;
>14 : 14
}
}
}
var C5;
>C5 : any
/** @implements {A} */
Ns.C5 = C5 || class {
>Ns.C5 = C5 || class { method() { return 15; }} : typeof C5
>Ns.C5 : typeof C5
>Ns : typeof Ns
>C5 : typeof C5
>C5 || class { method() { return 15; }} : typeof C5
>C5 : undefined
>class { method() { return 15; }} : typeof C5
method() {
>method : () => number
return 15;
>15 : 15
}
}

View File

@ -23,3 +23,36 @@ class B2 {
/** @implements {A} */
class B3 {
}
var Ns = {};
/** @implements {A} */
Ns.C1 = class {
method() { return 11; }
}
/** @implements {A} */
var C2 = class {
method() { return 12; }
}
var o = {
/** @implements {A} */
C3: class {
method() { return 13; }
}
}
class CC {
/** @implements {A} */
C4 = class {
method() {
return 14;
}
}
}
var C5;
/** @implements {A} */
Ns.C5 = C5 || class {
method() {
return 15;
}
}