fix(41818): use last JSDoc comment related to host (#41858)

This commit is contained in:
Oleksandr T 2020-12-18 23:24:58 +02:00 committed by GitHub
parent c3ff0d4c17
commit a763600cc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 367 additions and 15 deletions

View file

@ -2147,8 +2147,8 @@ namespace ts {
const saveCurrentFlow = currentFlow;
for (const typeAlias of delayedTypeAliases) {
const host = getJSDocHost(typeAlias);
container = findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer)) || file;
blockScopeContainer = getEnclosingBlockScopeContainer(host) || file;
container = (host && findAncestor(host.parent, n => !!(getContainerFlags(n) & ContainerFlags.IsContainer))) || file;
blockScopeContainer = (host && getEnclosingBlockScopeContainer(host)) || file;
currentFlow = initFlowNode({ flags: FlowFlags.Start });
parent = typeAlias;
bind(typeAlias.typeExpression);

View file

@ -1948,7 +1948,10 @@ namespace ts {
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.JSDocEnumTag:
// js type aliases do not resolve names from their host, so skip past it
location = getJSDocHost(location);
const root = getJSDocRoot(location);
if (root) {
location = root.parent;
}
break;
case SyntaxKind.Parameter:
if (lastLocation && (
@ -3160,7 +3163,8 @@ namespace ts {
return;
}
const host = getJSDocHost(node);
if (isExpressionStatement(host) &&
if (host &&
isExpressionStatement(host) &&
isBinaryExpression(host.expression) &&
getAssignmentDeclarationKind(host.expression) === AssignmentDeclarationKind.PrototypeProperty) {
// X.prototype.m = /** @param {K} p */ function () { } <-- look for K on X's declaration
@ -3169,7 +3173,7 @@ namespace ts {
return getDeclarationOfJSPrototypeContainer(symbol);
}
}
if ((isObjectLiteralMethod(host) || isPropertyAssignment(host)) &&
if (host && (isObjectLiteralMethod(host) || isPropertyAssignment(host)) &&
isBinaryExpression(host.parent.parent) &&
getAssignmentDeclarationKind(host.parent.parent) === AssignmentDeclarationKind.Prototype) {
// X.prototype = { /** @param {K} p */m() { } } <-- look for K on X's declaration

View file

@ -2622,18 +2622,31 @@ namespace ts {
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;
if (host) {
return getSourceOfDefaultedAssignment(host)
|| getSourceOfAssignment(host)
|| getSingleInitializerOfVariableStatementOrPropertyDeclaration(host)
|| getSingleVariableOfVariableStatement(host)
|| getNestedModuleDeclaration(host)
|| host;
}
}
/** 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;
/** Use getEffectiveJSDocHost if you additionally need to look for jsdoc on parent nodes, like assignments. */
export function getJSDocHost(node: Node): HasJSDoc | undefined {
const jsDoc = getJSDocRoot(node);
if (!jsDoc) {
return undefined;
}
const host = jsDoc.parent;
if (host && host.jsDoc && jsDoc === lastOrUndefined(host.jsDoc)) {
return host;
}
}
export function getJSDocRoot(node: Node): JSDoc | undefined {
return findAncestor(node.parent, isJSDoc);
}
export function getTypeParameterFromJsDoc(node: TypeParameterDeclaration & { parent: JSDocTemplateTag }): TypeParameterDeclaration | undefined {

View file

@ -0,0 +1,25 @@
error TS8022: JSDoc '@extends' is not attached to a class.
!!! error TS8022: JSDoc '@extends' is not attached to a class.
==== tests/cases/conformance/jsdoc/foo.js (0 errors) ====
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
*/
/**
* @constructor
*/
class B extends A {
constructor() {
super();
}
}

View file

@ -0,0 +1,40 @@
//// [foo.js]
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
*/
/**
* @constructor
*/
class B extends A {
constructor() {
super();
}
}
//// [foo.js]
/**
* @constructor
*/
class A {
constructor() { }
}
/**
* @extends {A}
*/
/**
* @constructor
*/
class B extends A {
constructor() {
super();
}
}

View file

@ -0,0 +1,27 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @constructor
*/
class A {
>A : Symbol(A, Decl(foo.js, 0, 0))
constructor() {}
}
/**
* @extends {A}
*/
/**
* @constructor
*/
class B extends A {
>B : Symbol(B, Decl(foo.js, 5, 1))
>A : Symbol(A, Decl(foo.js, 0, 0))
constructor() {
super();
>super : Symbol(A, Decl(foo.js, 0, 0))
}
}

View file

@ -0,0 +1,28 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @constructor
*/
class A {
>A : A
constructor() {}
}
/**
* @extends {A}
*/
/**
* @constructor
*/
class B extends A {
>B : B
>A : A
constructor() {
super();
>super() : void
>super : typeof A
}
}

View file

@ -0,0 +1,35 @@
//// [foo.js]
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
* @constructor
*/
class B extends A {
constructor() {
super();
}
}
//// [foo.js]
/**
* @constructor
*/
class A {
constructor() { }
}
/**
* @extends {A}
* @constructor
*/
class B extends A {
constructor() {
super();
}
}

View file

@ -0,0 +1,24 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @constructor
*/
class A {
>A : Symbol(A, Decl(foo.js, 0, 0))
constructor() {}
}
/**
* @extends {A}
* @constructor
*/
class B extends A {
>B : Symbol(B, Decl(foo.js, 5, 1))
>A : Symbol(A, Decl(foo.js, 0, 0))
constructor() {
super();
>super : Symbol(A, Decl(foo.js, 0, 0))
}
}

View file

@ -0,0 +1,25 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @constructor
*/
class A {
>A : A
constructor() {}
}
/**
* @extends {A}
* @constructor
*/
class B extends A {
>B : B
>A : A
constructor() {
super();
>super() : void
>super : typeof A
}
}

View file

@ -0,0 +1,17 @@
tests/cases/conformance/jsdoc/foo.js(11,1): error TS8022: JSDoc '@extends' is not attached to a class.
==== tests/cases/conformance/jsdoc/foo.js (1 errors) ====
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
*/
!!! error TS8022: JSDoc '@extends' is not attached to a class.

View file

@ -0,0 +1,23 @@
//// [foo.js]
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
*/
//// [foo.js]
/**
* @constructor
*/
class A {
constructor() { }
}
/**
* @extends {A}
*/

View file

@ -0,0 +1,14 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @constructor
*/
class A {
>A : Symbol(A, Decl(foo.js, 0, 0))
constructor() {}
}
/**
* @extends {A}
*/

View file

@ -0,0 +1,14 @@
=== tests/cases/conformance/jsdoc/foo.js ===
/**
* @constructor
*/
class A {
>A : A
constructor() {}
}
/**
* @extends {A}
*/

View file

@ -0,0 +1,25 @@
// @allowJs: true
// @checkJs: true
// @target: esnext
// @outDir: out
// @Filename: foo.js
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
*/
/**
* @constructor
*/
class B extends A {
constructor() {
super();
}
}

View file

@ -0,0 +1,22 @@
// @allowJs: true
// @checkJs: true
// @target: esnext
// @outDir: out
// @Filename: foo.js
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
* @constructor
*/
class B extends A {
constructor() {
super();
}
}

View file

@ -0,0 +1,16 @@
// @allowJs: true
// @checkJs: true
// @target: esnext
// @outDir: out
// @Filename: foo.js
/**
* @constructor
*/
class A {
constructor() {}
}
/**
* @extends {A}
*/