Skip to content

Commit d7839fe

Browse files
Fixed code review issues for @implements, added some more tests.
1 parent 5a7fdd5 commit d7839fe

18 files changed

+235
-52
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29853,14 +29853,14 @@ namespace ts {
2985329853
checkSignatureDeclaration(node);
2985429854
}
2985529855

29856-
function checkJSDocImplementsTag(node: JSDocHeritageTag): void {
29856+
function checkJSDocImplementsTag(node: JSDocImplementsTag): void {
2985729857
const classLike = getJSDocHost(node);
2985829858
if (!isClassDeclaration(classLike) && !isClassExpression(classLike)) {
2985929859
error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName));
2986029860
return;
2986129861
}
2986229862
}
29863-
function checkJSDocAugmentsTag(node: JSDocHeritageTag): void {
29863+
function checkJSDocAugmentsTag(node: JSDocAugmentsTag): void {
2986429864
const classLike = getJSDocHost(node);
2986529865
if (!isClassDeclaration(classLike) && !isClassExpression(classLike)) {
2986629866
error(classLike, Diagnostics.JSDoc_0_is_not_attached_to_a_class, idText(node.tagName));
@@ -33338,9 +33338,9 @@ namespace ts {
3333833338
case SyntaxKind.ImportType:
3333933339
return checkImportType(<ImportTypeNode>node);
3334033340
case SyntaxKind.JSDocAugmentsTag:
33341-
return checkJSDocAugmentsTag(node as JSDocHeritageTag);
33341+
return checkJSDocAugmentsTag(node as JSDocAugmentsTag);
3334233342
case SyntaxKind.JSDocImplementsTag:
33343-
return checkJSDocImplementsTag(node as JSDocHeritageTag);
33343+
return checkJSDocImplementsTag(node as JSDocImplementsTag);
3334433344
case SyntaxKind.JSDocTypedefTag:
3334533345
case SyntaxKind.JSDocCallbackTag:
3334633346
case SyntaxKind.JSDocEnumTag:

src/compiler/emitter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,7 @@ namespace ts {
15131513
return emitJSDocSimpleTypedTag(node as JSDocTypeTag);
15141514
case SyntaxKind.JSDocImplementsTag:
15151515
case SyntaxKind.JSDocAugmentsTag:
1516-
return emitJSDocHeritageTag(node as JSDocHeritageTag);
1516+
return emitJSDocHeritageTag(node as JSDocImplementsTag | JSDocAugmentsTag);
15171517
case SyntaxKind.JSDocTemplateTag:
15181518
return emitJSDocTemplateTag(node as JSDocTemplateTag);
15191519
case SyntaxKind.JSDocTypedefTag:
@@ -3397,7 +3397,7 @@ namespace ts {
33973397
emitJSDocComment(tag.comment);
33983398
}
33993399

3400-
function emitJSDocHeritageTag(tag: JSDocHeritageTag) {
3400+
function emitJSDocHeritageTag(tag: JSDocImplementsTag | JSDocAugmentsTag) {
34013401
emitJSDocTagName(tag.tagName);
34023402
writeSpace();
34033403
writePunctuation("{");

src/compiler/parser.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,11 @@ namespace ts {
480480
case SyntaxKind.JSDocAuthorTag:
481481
return visitNode(cbNode, (node as JSDocTag).tagName);
482482
case SyntaxKind.JSDocImplementsTag:
483+
return visitNode(cbNode, (node as JSDocTag).tagName) ||
484+
visitNode(cbNode, (<JSDocImplementsTag>node).class);
483485
case SyntaxKind.JSDocAugmentsTag:
484486
return visitNode(cbNode, (node as JSDocTag).tagName) ||
485-
visitNode(cbNode, (<JSDocHeritageTag>node).class);
487+
visitNode(cbNode, (<JSDocAugmentsTag>node).class);
486488
case SyntaxKind.JSDocTemplateTag:
487489
return visitNode(cbNode, (node as JSDocTag).tagName) ||
488490
visitNode(cbNode, (<JSDocTemplateTag>node).constraint) ||
@@ -6924,11 +6926,11 @@ namespace ts {
69246926
tag = parseAuthorTag(start, tagName, margin);
69256927
break;
69266928
case "implements":
6927-
tag = parseHeritageTag(start, tagName, SyntaxKind.JSDocImplementsTag);
6929+
tag = parseImplementsTag(start, tagName);
69286930
break;
69296931
case "augments":
69306932
case "extends":
6931-
tag = parseHeritageTag(start, tagName, SyntaxKind.JSDocAugmentsTag);
6933+
tag = parseAugmentsTag(start, tagName);
69326934
break;
69336935
case "class":
69346936
case "constructor":
@@ -7280,8 +7282,15 @@ namespace ts {
72807282
}
72817283
}
72827284

7283-
function parseHeritageTag(start: number, tagName: Identifier, kind: SyntaxKind.JSDocAugmentsTag | SyntaxKind.JSDocImplementsTag): JSDocHeritageTag {
7284-
const result = <JSDocHeritageTag>createNode(kind, start);
7285+
function parseImplementsTag(start: number, tagName: Identifier): JSDocImplementsTag {
7286+
const result = <JSDocImplementsTag>createNode(SyntaxKind.JSDocImplementsTag, start);
7287+
result.tagName = tagName;
7288+
result.class = parseExpressionWithTypeArgumentsForAugments();
7289+
return finishNode(result);
7290+
}
7291+
7292+
function parseAugmentsTag(start: number, tagName: Identifier): JSDocAugmentsTag {
7293+
const result = <JSDocAugmentsTag>createNode(SyntaxKind.JSDocAugmentsTag, start);
72857294
result.tagName = tagName;
72867295
result.class = parseExpressionWithTypeArgumentsForAugments();
72877296
return finishNode(result);

src/compiler/types.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,7 +1974,7 @@ namespace ts {
19741974

19751975
export interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
19761976
kind: SyntaxKind.ExpressionWithTypeArguments;
1977-
parent: HeritageClause | JSDocHeritageTag;
1977+
parent: HeritageClause | JSDocAugmentsTag | JSDocImplementsTag;
19781978
expression: LeftHandSideExpression;
19791979
}
19801980

@@ -2639,11 +2639,16 @@ namespace ts {
26392639
}
26402640

26412641
/**
2642-
* Represents @augments @extends and @implements
26432642
* Note that `@extends` is a synonym of `@augments`.
2643+
* Both tags are represented by this interface.
26442644
*/
2645-
export interface JSDocHeritageTag extends JSDocTag {
2646-
kind: SyntaxKind.JSDocAugmentsTag | SyntaxKind.JSDocImplementsTag;
2645+
export interface JSDocAugmentsTag extends JSDocTag {
2646+
kind: SyntaxKind.JSDocAugmentsTag;
2647+
class: ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
2648+
}
2649+
2650+
export interface JSDocImplementsTag extends JSDocTag {
2651+
kind: SyntaxKind.JSDocImplementsTag;
26472652
class: ExpressionWithTypeArguments & { expression: Identifier | PropertyAccessEntityNameExpression };
26482653
}
26492654

src/compiler/utilities.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2774,18 +2774,15 @@ namespace ts {
27742774
return getJSDocImplementsTags(node).map(n => n.class);
27752775
}
27762776
else {
2777-
return getClassImplementsHeritageClauseElements(node);
2777+
const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
2778+
return heritageClause ? heritageClause.types : undefined;
27782779
}
27792780
}
2780-
export function getClassImplementsHeritageClauseElements(node: ClassLikeDeclaration) {
2781-
const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
2782-
return heritageClause ? heritageClause.types : undefined;
2783-
}
27842781

27852782
/** Returns the node in an `extends` or `implements` clause of a class or interface. */
27862783
export function getAllSuperTypeNodes(node: Node): readonly TypeNode[] {
27872784
return isInterfaceDeclaration(node) ? getInterfaceBaseTypeNodes(node) || emptyArray :
2788-
isClassLike(node) ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getClassImplementsHeritageClauseElements(node)) || emptyArray :
2785+
isClassLike(node) ? concatenate(singleElementArray(getEffectiveBaseTypeNode(node)), getEffectiveImplementsTypeNodes(node)) || emptyArray :
27892786
emptyArray;
27902787
}
27912788

src/compiler/utilitiesPublic.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -667,12 +667,12 @@ namespace ts {
667667
}
668668

669669
/** Gets the JSDoc augments tag for the node if present */
670-
export function getJSDocAugmentsTag(node: Node): JSDocHeritageTag | undefined {
670+
export function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined {
671671
return getFirstJSDocTag(node, isJSDocAugmentsTag);
672672
}
673673

674674
/** Gets the JSDoc implements tags for the node if present */
675-
export function getJSDocImplementsTags(node: Node): readonly JSDocHeritageTag[] {
675+
export function getJSDocImplementsTags(node: Node): readonly JSDocImplementsTag[] {
676676
return getAllJSDocTags(node, isJSDocImplementsTag);
677677
}
678678

@@ -1588,11 +1588,11 @@ namespace ts {
15881588
return node.kind === SyntaxKind.JSDocAuthorTag;
15891589
}
15901590

1591-
export function isJSDocAugmentsTag(node: Node): node is JSDocHeritageTag {
1591+
export function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag {
15921592
return node.kind === SyntaxKind.JSDocAugmentsTag;
15931593
}
15941594

1595-
export function isJSDocImplementsTag(node: Node): node is JSDocHeritageTag {
1595+
export function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag {
15961596
return node.kind === SyntaxKind.JSDocImplementsTag;
15971597
}
15981598

src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace ts.codefix {
1010
getCodeActions(context) {
1111
const { sourceFile, span } = context;
1212
const classDeclaration = getClass(sourceFile, span.start);
13-
return mapDefined<ExpressionWithTypeArguments, CodeFixAction>(getClassImplementsHeritageClauseElements(classDeclaration), implementedTypeNode => {
13+
return mapDefined<ExpressionWithTypeArguments, CodeFixAction>(getEffectiveImplementsTypeNodes(classDeclaration), implementedTypeNode => {
1414
const changes = textChanges.ChangeTracker.with(context, t => addMissingDeclarations(context, implementedTypeNode, sourceFile, classDeclaration, t, context.preferences));
1515
return changes.length === 0 ? undefined : createCodeFixAction(fixId, changes, [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], fixId, Diagnostics.Implement_all_unimplemented_interfaces);
1616
});
@@ -21,7 +21,7 @@ namespace ts.codefix {
2121
return codeFixAll(context, errorCodes, (changes, diag) => {
2222
const classDeclaration = getClass(diag.file, diag.start);
2323
if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) {
24-
for (const implementedTypeNode of getClassImplementsHeritageClauseElements(classDeclaration)!) {
24+
for (const implementedTypeNode of getEffectiveImplementsTypeNodes(classDeclaration)!) {
2525
addMissingDeclarations(context, implementedTypeNode, diag.file, classDeclaration, changes, context.preferences);
2626
}
2727
}

src/services/jsDoc.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,9 @@ namespace ts.JsDoc {
130130
const { comment } = tag;
131131
switch (tag.kind) {
132132
case SyntaxKind.JSDocImplementsTag:
133+
return withNode((tag as JSDocImplementsTag).class);
133134
case SyntaxKind.JSDocAugmentsTag:
134-
return withNode((tag as JSDocHeritageTag).class);
135+
return withNode((tag as JSDocAugmentsTag).class);
135136
case SyntaxKind.JSDocTemplateTag:
136137
return withList((tag as JSDocTemplateTag).typeParameters);
137138
case SyntaxKind.JSDocTypeTag:

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,7 @@ declare namespace ts {
11461146
}
11471147
export interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
11481148
kind: SyntaxKind.ExpressionWithTypeArguments;
1149-
parent: HeritageClause | JSDocHeritageTag;
1149+
parent: HeritageClause | JSDocAugmentsTag | JSDocImplementsTag;
11501150
expression: LeftHandSideExpression;
11511151
}
11521152
export interface NewExpression extends PrimaryExpression, Declaration {
@@ -1626,11 +1626,17 @@ declare namespace ts {
16261626
kind: SyntaxKind.JSDocTag;
16271627
}
16281628
/**
1629-
* Represents @augments @extends and @implements
16301629
* Note that `@extends` is a synonym of `@augments`.
1630+
* Both tags are represented by this interface.
16311631
*/
1632-
export interface JSDocHeritageTag extends JSDocTag {
1633-
kind: SyntaxKind.JSDocAugmentsTag | SyntaxKind.JSDocImplementsTag;
1632+
export interface JSDocAugmentsTag extends JSDocTag {
1633+
kind: SyntaxKind.JSDocAugmentsTag;
1634+
class: ExpressionWithTypeArguments & {
1635+
expression: Identifier | PropertyAccessEntityNameExpression;
1636+
};
1637+
}
1638+
export interface JSDocImplementsTag extends JSDocTag {
1639+
kind: SyntaxKind.JSDocImplementsTag;
16341640
class: ExpressionWithTypeArguments & {
16351641
expression: Identifier | PropertyAccessEntityNameExpression;
16361642
};
@@ -3494,9 +3500,9 @@ declare namespace ts {
34943500
*/
34953501
function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean;
34963502
/** Gets the JSDoc augments tag for the node if present */
3497-
function getJSDocAugmentsTag(node: Node): JSDocHeritageTag | undefined;
3503+
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
34983504
/** Gets the JSDoc implements tags for the node if present */
3499-
function getJSDocImplementsTags(node: Node): readonly JSDocHeritageTag[];
3505+
function getJSDocImplementsTags(node: Node): readonly JSDocImplementsTag[];
35003506
/** Gets the JSDoc class tag for the node if present */
35013507
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
35023508
/** Gets the JSDoc public tag for the node if present */
@@ -3715,8 +3721,8 @@ declare namespace ts {
37153721
function isJSDocVariadicType(node: Node): node is JSDocVariadicType;
37163722
function isJSDoc(node: Node): node is JSDoc;
37173723
function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag;
3718-
function isJSDocAugmentsTag(node: Node): node is JSDocHeritageTag;
3719-
function isJSDocImplementsTag(node: Node): node is JSDocHeritageTag;
3724+
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
3725+
function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag;
37203726
function isJSDocClassTag(node: Node): node is JSDocClassTag;
37213727
function isJSDocPublicTag(node: Node): node is JSDocPublicTag;
37223728
function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag;

tests/baselines/reference/api/typescript.d.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,7 @@ declare namespace ts {
11461146
}
11471147
export interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
11481148
kind: SyntaxKind.ExpressionWithTypeArguments;
1149-
parent: HeritageClause | JSDocHeritageTag;
1149+
parent: HeritageClause | JSDocAugmentsTag | JSDocImplementsTag;
11501150
expression: LeftHandSideExpression;
11511151
}
11521152
export interface NewExpression extends PrimaryExpression, Declaration {
@@ -1626,11 +1626,17 @@ declare namespace ts {
16261626
kind: SyntaxKind.JSDocTag;
16271627
}
16281628
/**
1629-
* Represents @augments @extends and @implements
16301629
* Note that `@extends` is a synonym of `@augments`.
1630+
* Both tags are represented by this interface.
16311631
*/
1632-
export interface JSDocHeritageTag extends JSDocTag {
1633-
kind: SyntaxKind.JSDocAugmentsTag | SyntaxKind.JSDocImplementsTag;
1632+
export interface JSDocAugmentsTag extends JSDocTag {
1633+
kind: SyntaxKind.JSDocAugmentsTag;
1634+
class: ExpressionWithTypeArguments & {
1635+
expression: Identifier | PropertyAccessEntityNameExpression;
1636+
};
1637+
}
1638+
export interface JSDocImplementsTag extends JSDocTag {
1639+
kind: SyntaxKind.JSDocImplementsTag;
16341640
class: ExpressionWithTypeArguments & {
16351641
expression: Identifier | PropertyAccessEntityNameExpression;
16361642
};
@@ -3494,9 +3500,9 @@ declare namespace ts {
34943500
*/
34953501
function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean;
34963502
/** Gets the JSDoc augments tag for the node if present */
3497-
function getJSDocAugmentsTag(node: Node): JSDocHeritageTag | undefined;
3503+
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
34983504
/** Gets the JSDoc implements tags for the node if present */
3499-
function getJSDocImplementsTags(node: Node): readonly JSDocHeritageTag[];
3505+
function getJSDocImplementsTags(node: Node): readonly JSDocImplementsTag[];
35003506
/** Gets the JSDoc class tag for the node if present */
35013507
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
35023508
/** Gets the JSDoc public tag for the node if present */
@@ -3715,8 +3721,8 @@ declare namespace ts {
37153721
function isJSDocVariadicType(node: Node): node is JSDocVariadicType;
37163722
function isJSDoc(node: Node): node is JSDoc;
37173723
function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag;
3718-
function isJSDocAugmentsTag(node: Node): node is JSDocHeritageTag;
3719-
function isJSDocImplementsTag(node: Node): node is JSDocHeritageTag;
3724+
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
3725+
function isJSDocImplementsTag(node: Node): node is JSDocImplementsTag;
37203726
function isJSDocClassTag(node: Node): node is JSDocClassTag;
37213727
function isJSDocPublicTag(node: Node): node is JSDocPublicTag;
37223728
function isJSDocPrivateTag(node: Node): node is JSDocPrivateTag;

tests/baselines/reference/jsdocImplements_class.errors.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
/a.js(2,18): error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
21
/a.js(13,5): error TS2416: Property 'method' in type 'B2' is not assignable to the same property in base type 'A'.
32
Type '() => string' is not assignable to type '() => number'.
43
Type 'string' is not assignable to type 'number'.
54
/a.js(17,7): error TS2720: Class 'B3' incorrectly implements class 'A'. Did you mean to extend 'A' and inherit its members as a subclass?
65
Property 'method' is missing in type 'B3' but required in type 'A'.
76

87

9-
==== /a.js (3 errors) ====
8+
==== /a.js (2 errors) ====
109
class A {
1110
/** @return {number} */
12-
~~~~~~
13-
!!! error TS2355: A function whose declared type is neither 'void' nor 'any' must return a value.
14-
method() { }
11+
method() { throw new Error(); }
1512
}
1613
/** @implements A */
1714
class B {

tests/baselines/reference/jsdocImplements_class.symbols

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ class A {
33
>A : Symbol(A, Decl(a.js, 0, 0))
44

55
/** @return {number} */
6-
method() { }
6+
method() { throw new Error(); }
77
>method : Symbol(A.method, Decl(a.js, 0, 9))
8+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
89
}
910
/** @implements A */
1011
class B {

tests/baselines/reference/jsdocImplements_class.types

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ class A {
33
>A : A
44

55
/** @return {number} */
6-
method() { }
6+
method() { throw new Error(); }
77
>method : () => number
8+
>new Error() : Error
9+
>Error : ErrorConstructor
810
}
911
/** @implements A */
1012
class B {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/a.js(17,7): error TS2420: Class 'BadSquare' incorrectly implements interface 'Drawable'.
2+
Property 'draw' is missing in type 'BadSquare' but required in type 'Drawable'.
3+
4+
5+
==== /defs.d.ts (0 errors) ====
6+
interface Drawable {
7+
draw(): number;
8+
}
9+
interface Sizable {
10+
size(): number;
11+
}
12+
==== /a.js (1 errors) ====
13+
/**
14+
* @implements Drawable
15+
* @implements Sizable
16+
**/
17+
class Square {
18+
draw() {
19+
return 0;
20+
}
21+
size() {
22+
return 0;
23+
}
24+
}
25+
/**
26+
* @implements Drawable
27+
* @implements Sizable
28+
**/
29+
class BadSquare {
30+
~~~~~~~~~
31+
!!! error TS2420: Class 'BadSquare' incorrectly implements interface 'Drawable'.
32+
!!! error TS2420: Property 'draw' is missing in type 'BadSquare' but required in type 'Drawable'.
33+
!!! related TS2728 /defs.d.ts:2:5: 'draw' is declared here.
34+
size() {
35+
return 0;
36+
}
37+
}

0 commit comments

Comments
 (0)