diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b9e6c0c8f2175..db8a5b2ff7c96 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7083,6 +7083,7 @@ namespace ts { ...!length(baseTypes) ? [] : [factory.createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))], ...!length(implementsExpressions) ? [] : [factory.createHeritageClause(SyntaxKind.ImplementsKeyword, implementsExpressions)] ]; + const modifiers = originalDecl && hasEffectiveModifier(originalDecl, ModifierFlags.Abstract) ? factory.createModifiersFromModifierFlags(ModifierFlags.Abstract) : undefined; const symbolProps = getNonInterhitedProperties(classType, baseTypes, getPropertiesOfType(classType)); const publicSymbolProps = filter(symbolProps, s => { // `valueDeclaration` could be undefined if inherited from @@ -7129,7 +7130,7 @@ namespace ts { context.enclosingDeclaration = oldEnclosing; addResult(setTextRange(factory.createClassDeclaration( /*decorators*/ undefined, - /*modifiers*/ undefined, + modifiers, localName, typeParamDecls, heritageClauses, @@ -7470,20 +7471,11 @@ namespace ts { initializer: Expression | undefined ) => T, methodKind: SignatureDeclaration["kind"], useAccessors: boolean): (p: Symbol, isStatic: boolean, baseType: Type | undefined) => (T | AccessorDeclaration | (T | AccessorDeclaration)[]) { return function serializePropertySymbol(p: Symbol, isStatic: boolean, baseType: Type | undefined): (T | AccessorDeclaration | (T | AccessorDeclaration)[]) { - const modifierFlags = getDeclarationModifierFlagsFromSymbol(p); - const isPrivate = !!(modifierFlags & ModifierFlags.Private); - if (isStatic && (p.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias))) { - // Only value-only-meaning symbols can be correctly encoded as class statics, type/namespace/alias meaning symbols - // need to be merged namespace members - return []; - } - if (p.flags & SymbolFlags.Prototype || - (baseType && getPropertyOfType(baseType, p.escapedName) - && isReadonlySymbol(getPropertyOfType(baseType, p.escapedName)!) === isReadonlySymbol(p) - && (p.flags & SymbolFlags.Optional) === (getPropertyOfType(baseType, p.escapedName)!.flags & SymbolFlags.Optional) - && isTypeIdenticalTo(getTypeOfSymbol(p), getTypeOfPropertyOfType(baseType, p.escapedName)!))) { + if (isOmittedSerializationProperty(p, isStatic, baseType)) { return []; } + const modifierFlags = getDeclarationModifierFlagsFromSymbol(p); + const isPrivate = !!(modifierFlags & ModifierFlags.Private); const flag = (modifierFlags & ~ModifierFlags.Async) | (isStatic ? ModifierFlags.Static : 0); const name = getPropertyNameNodeForSymbol(p, context); const firstPropertyLikeDecl = p.declarations?.find(or(isPropertyDeclaration, isAccessor, isVariableDeclaration, isPropertySignature, isBinaryExpression, isPropertyAccessExpression)); @@ -7569,6 +7561,29 @@ namespace ts { }; } + function isOmittedSerializationProperty(prop: Symbol, isStatic: boolean, type: Type | undefined) { + // Only value-only-meaning symbols can be correctly encoded as class statics, type/namespace/alias meaning symbols + // need to be merged namespace members + if (isStatic && (prop.flags & (SymbolFlags.Type | SymbolFlags.Namespace | SymbolFlags.Alias)) || (prop.flags & SymbolFlags.Prototype)) { + return true; + } + if (type) { + const baseProp = getPropertyOfType(type, prop.escapedName); + const basePropType = getTypeOfPropertyOfType(type, prop.escapedName); + if (baseProp && basePropType) { + if (getDeclarationModifierFlagsFromSymbol(baseProp) & ModifierFlags.Abstract) { + return prop === baseProp; + } + return ( + (prop.flags & SymbolFlags.Optional) === (baseProp.flags & SymbolFlags.Optional) && + isReadonlySymbol(baseProp) === isReadonlySymbol(prop) && + isTypeIdenticalTo(getTypeOfSymbol(prop), basePropType) + ); + } + } + return false; + } + function serializePropertySymbolForInterface(p: Symbol, baseType: Type | undefined) { return serializePropertySymbolForInterfaceWorker(p, /*isStatic*/ false, baseType); } @@ -29639,7 +29654,7 @@ namespace ts { return resolveErrorCall(node); } const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol); - if (valueDecl && hasSyntacticModifier(valueDecl, ModifierFlags.Abstract)) { + if (valueDecl && hasEffectiveModifier(valueDecl, ModifierFlags.Abstract)) { error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class); return resolveErrorCall(node); } @@ -31180,7 +31195,7 @@ namespace ts { if (type && type.flags & TypeFlags.Never) { error(errorNode, Diagnostics.A_function_returning_never_cannot_have_a_reachable_end_point); } - else if (type && !hasExplicitReturn) { + else if (type && !hasExplicitReturn && !hasEffectiveModifier(func, ModifierFlags.Abstract)) { // minimal check: function has syntactic return type annotation and no explicit return statements in the body // this function does not conform to the specification. error(errorNode, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value); @@ -33645,8 +33660,9 @@ namespace ts { // Grammar checking for modifiers is done inside the function checkGrammarFunctionLikeDeclaration checkFunctionOrMethodDeclaration(node); - // method signatures already report "implementation not allowed in ambient context" elsewhere - if (hasSyntacticModifier(node, ModifierFlags.Abstract) && node.kind === SyntaxKind.MethodDeclaration && node.body) { + // Abstract methods cannot have an implementation. + // Extra checks are to avoid reporting multiple errors relating to the "abstractness" of the node. + if (isMethodDeclaration(node) && hasAbstractDeclarationBody(node)) { error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); } @@ -33775,7 +33791,7 @@ namespace ts { checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { - if (!(node.flags & NodeFlags.HasExplicitReturn)) { + if (!(node.flags & NodeFlags.HasExplicitReturn) && !(isInJSFile(node) && hasEffectiveModifier(node, ModifierFlags.Abstract))) { error(node.name, Diagnostics.A_get_accessor_must_return_a_value); } } @@ -37766,7 +37782,7 @@ namespace ts { // It is an error to inherit an abstract member without implementing it or being declared abstract. // If there is no declaration for the derived class (as in the case of class expressions), // then the class cannot be declared abstract. - if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasSyntacticModifier(derivedClassDecl, ModifierFlags.Abstract))) { + if (baseDeclarationFlags & ModifierFlags.Abstract && (!derivedClassDecl || !hasEffectiveModifier(derivedClassDecl, ModifierFlags.Abstract))) { // Searches other base types for a declaration that would satisfy the inherited abstract member. // (The class may have more than one base type via declaration merging with an interface with the // same name.) @@ -37874,7 +37890,7 @@ namespace ts { const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType)); for (const prop of properties) { const existing = seen.get(prop.escapedName); - if (existing && !isPropertyIdenticalTo(existing, prop)) { + if (existing && !isPropertyIdenticalTo(existing, prop) && !(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.Abstract)) { seen.delete(prop.escapedName); } } @@ -42004,13 +42020,11 @@ namespace ts { return grammarErrorAtPos(accessor, accessor.end - 1, ";".length, Diagnostics._0_expected, "{"); } } - if (accessor.body) { - if (hasSyntacticModifier(accessor, ModifierFlags.Abstract)) { - return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); - } - if (accessor.parent.kind === SyntaxKind.TypeLiteral || accessor.parent.kind === SyntaxKind.InterfaceDeclaration) { - return grammarErrorOnNode(accessor.body, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); - } + if (hasAbstractDeclarationBody(accessor)) { + return grammarErrorOnNode(accessor, Diagnostics.An_abstract_accessor_cannot_have_an_implementation); + } + if (accessor.body && (accessor.parent.kind === SyntaxKind.TypeLiteral || accessor.parent.kind === SyntaxKind.InterfaceDeclaration)) { + return grammarErrorOnNode(accessor.body, Diagnostics.An_implementation_cannot_be_declared_in_ambient_contexts); } if (accessor.typeParameters) { return grammarErrorOnNode(accessor.name, Diagnostics.An_accessor_cannot_have_type_parameters); @@ -42039,6 +42053,23 @@ namespace ts { return false; } + function hasAbstractDeclarationBody(node: MethodDeclaration | AccessorDeclaration) { + if (hasEffectiveModifier(node, ModifierFlags.Abstract) && node.body) { + if (isInJSFile(node)) { + const statement = singleOrUndefined(node.body.statements); + if (statement && isThrowStatement(statement)) { + return false; + } + const returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(node)); + if (returnType === neverType) { + return false; + } + return !!length(node.body.statements); + } + return true; + } + } + /** Does the accessor have the right number of parameters? * A get accessor has no parameters or a single `this` parameter. * A set accessor has one parameter or a `this` parameter and one more parameter. diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index b5151fd3d6122..2e48f0b88c434 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -364,6 +364,8 @@ namespace ts { get updateJSDocThisTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocThisTag); }, get createJSDocEnumTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocEnumTag); }, get updateJSDocEnumTag() { return getJSDocTypeLikeTagUpdateFunction(SyntaxKind.JSDocEnumTag); }, + get createJSDocAbstractTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAbstractTag); }, + get updateJSDocAbstractTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAbstractTag); }, get createJSDocAuthorTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocAuthorTag); }, get updateJSDocAuthorTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocAuthorTag); }, get createJSDocClassTag() { return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocClassTag); }, @@ -6104,6 +6106,7 @@ namespace ts { case SyntaxKind.JSDocReturnTag: return "returns"; case SyntaxKind.JSDocThisTag: return "this"; case SyntaxKind.JSDocEnumTag: return "enum"; + case SyntaxKind.JSDocAbstractTag: return "abstract"; case SyntaxKind.JSDocAuthorTag: return "author"; case SyntaxKind.JSDocClassTag: return "class"; case SyntaxKind.JSDocPublicTag: return "public"; diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 270fded5c920b..504d6463e1b7e 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -840,6 +840,10 @@ namespace ts { return node.kind === SyntaxKind.JSDocAugmentsTag; } + export function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag { + return node.kind === SyntaxKind.JSDocAbstractTag; + } + export function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag { return node.kind === SyntaxKind.JSDocAuthorTag; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0b508151064c4..c2d4f86c043a0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -555,6 +555,7 @@ namespace ts { case SyntaxKind.JSDocTypeLiteral: return forEach((node as JSDocTypeLiteral).jsDocPropertyTags, cbNode); case SyntaxKind.JSDocTag: + case SyntaxKind.JSDocAbstractTag: case SyntaxKind.JSDocClassTag: case SyntaxKind.JSDocPublicTag: case SyntaxKind.JSDocPrivateTag: @@ -7793,6 +7794,9 @@ namespace ts { let tag: JSDocTag | undefined; switch (tagName.escapedText) { + case "abstract": + tag = parseSimpleTag(start, factory.createJSDocAbstractTag, tagName, margin, indentText); + break; case "author": tag = parseAuthorTag(start, tagName, margin, indentText); break; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index cea584d3e9802..2280a470dd55e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -384,6 +384,7 @@ namespace ts { JSDocTag, JSDocAugmentsTag, JSDocImplementsTag, + JSDocAbstractTag, JSDocAuthorTag, JSDocDeprecatedTag, JSDocClassTag, @@ -3259,6 +3260,10 @@ namespace ts { readonly class: ExpressionWithTypeArguments & { readonly expression: Identifier | PropertyAccessEntityNameExpression }; } + export interface JSDocAbstractTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAbstractTag; + } + export interface JSDocAuthorTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAuthorTag; } @@ -7379,6 +7384,8 @@ namespace ts { updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag; createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag; updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag; + createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAbstractTag; + updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocAbstractTag; createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag; updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAuthorTag; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index ab8bc3edfcb4b..359ed47e55c9c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4813,6 +4813,7 @@ namespace ts { if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.Protected; if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.Readonly; if (getJSDocOverrideTagNoCache(node)) flags |= ModifierFlags.Override; + if (getJSDocAbstractTagNoCache(node)) flags |= ModifierFlags.Abstract; } if (getJSDocDeprecatedTagNoCache(node)) flags |= ModifierFlags.Deprecated; } diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index b9236521cba67..759f857475568 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -777,6 +777,10 @@ namespace ts { return getFirstJSDocTag(node, isJSDocOverrideTag, /*noCache*/ true); } + export function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined { + return getFirstJSDocTag(node, isJSDocAbstractTag, /*noCache*/ true); + } + /** Gets the JSDoc deprecated tag for the node if present */ export function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined { return getFirstJSDocTag(node, isJSDocDeprecatedTag); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 8b537d952f339..bcdfba95525b9 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -430,32 +430,33 @@ declare namespace ts { JSDocTag = 322, JSDocAugmentsTag = 323, JSDocImplementsTag = 324, - JSDocAuthorTag = 325, - JSDocDeprecatedTag = 326, - JSDocClassTag = 327, - JSDocPublicTag = 328, - JSDocPrivateTag = 329, - JSDocProtectedTag = 330, - JSDocReadonlyTag = 331, - JSDocOverrideTag = 332, - JSDocCallbackTag = 333, - JSDocEnumTag = 334, - JSDocParameterTag = 335, - JSDocReturnTag = 336, - JSDocThisTag = 337, - JSDocTypeTag = 338, - JSDocTemplateTag = 339, - JSDocTypedefTag = 340, - JSDocSeeTag = 341, - JSDocPropertyTag = 342, - SyntaxList = 343, - NotEmittedStatement = 344, - PartiallyEmittedExpression = 345, - CommaListExpression = 346, - MergeDeclarationMarker = 347, - EndOfDeclarationMarker = 348, - SyntheticReferenceExpression = 349, - Count = 350, + JSDocAbstractTag = 325, + JSDocAuthorTag = 326, + JSDocDeprecatedTag = 327, + JSDocClassTag = 328, + JSDocPublicTag = 329, + JSDocPrivateTag = 330, + JSDocProtectedTag = 331, + JSDocReadonlyTag = 332, + JSDocOverrideTag = 333, + JSDocCallbackTag = 334, + JSDocEnumTag = 335, + JSDocParameterTag = 336, + JSDocReturnTag = 337, + JSDocThisTag = 338, + JSDocTypeTag = 339, + JSDocTemplateTag = 340, + JSDocTypedefTag = 341, + JSDocSeeTag = 342, + JSDocPropertyTag = 343, + SyntaxList = 344, + NotEmittedStatement = 345, + PartiallyEmittedExpression = 346, + CommaListExpression = 347, + MergeDeclarationMarker = 348, + EndOfDeclarationMarker = 349, + SyntheticReferenceExpression = 350, + Count = 351, FirstAssignment = 63, LastAssignment = 78, FirstCompoundAssignment = 64, @@ -484,9 +485,9 @@ declare namespace ts { LastStatement = 251, FirstNode = 159, FirstJSDocNode = 304, - LastJSDocNode = 342, + LastJSDocNode = 343, FirstJSDocTagNode = 322, - LastJSDocTagNode = 342, + LastJSDocTagNode = 343, } export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -1812,6 +1813,9 @@ declare namespace ts { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; } + export interface JSDocAbstractTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAbstractTag; + } export interface JSDocAuthorTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAuthorTag; } @@ -3565,6 +3569,8 @@ declare namespace ts { updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag; createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag; updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag; + createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAbstractTag; + updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocAbstractTag; createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag; updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAuthorTag; @@ -4240,6 +4246,7 @@ declare namespace ts { /** Gets the JSDoc protected tag for the node if present */ function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined; function getJSDocOverrideTagNoCache(node: Node): JSDocOverrideTag | undefined; + function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined; /** Gets the JSDoc deprecated tag for the node if present */ function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined; /** Gets the JSDoc enum tag for the node if present */ @@ -4616,6 +4623,7 @@ declare namespace ts { function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral; function isJSDocSignature(node: Node): node is JSDocSignature; function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag; + function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag; function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag; function isJSDocClassTag(node: Node): node is JSDocClassTag; function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e81307d6ecb72..1ef8d081f780b 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -430,32 +430,33 @@ declare namespace ts { JSDocTag = 322, JSDocAugmentsTag = 323, JSDocImplementsTag = 324, - JSDocAuthorTag = 325, - JSDocDeprecatedTag = 326, - JSDocClassTag = 327, - JSDocPublicTag = 328, - JSDocPrivateTag = 329, - JSDocProtectedTag = 330, - JSDocReadonlyTag = 331, - JSDocOverrideTag = 332, - JSDocCallbackTag = 333, - JSDocEnumTag = 334, - JSDocParameterTag = 335, - JSDocReturnTag = 336, - JSDocThisTag = 337, - JSDocTypeTag = 338, - JSDocTemplateTag = 339, - JSDocTypedefTag = 340, - JSDocSeeTag = 341, - JSDocPropertyTag = 342, - SyntaxList = 343, - NotEmittedStatement = 344, - PartiallyEmittedExpression = 345, - CommaListExpression = 346, - MergeDeclarationMarker = 347, - EndOfDeclarationMarker = 348, - SyntheticReferenceExpression = 349, - Count = 350, + JSDocAbstractTag = 325, + JSDocAuthorTag = 326, + JSDocDeprecatedTag = 327, + JSDocClassTag = 328, + JSDocPublicTag = 329, + JSDocPrivateTag = 330, + JSDocProtectedTag = 331, + JSDocReadonlyTag = 332, + JSDocOverrideTag = 333, + JSDocCallbackTag = 334, + JSDocEnumTag = 335, + JSDocParameterTag = 336, + JSDocReturnTag = 337, + JSDocThisTag = 338, + JSDocTypeTag = 339, + JSDocTemplateTag = 340, + JSDocTypedefTag = 341, + JSDocSeeTag = 342, + JSDocPropertyTag = 343, + SyntaxList = 344, + NotEmittedStatement = 345, + PartiallyEmittedExpression = 346, + CommaListExpression = 347, + MergeDeclarationMarker = 348, + EndOfDeclarationMarker = 349, + SyntheticReferenceExpression = 350, + Count = 351, FirstAssignment = 63, LastAssignment = 78, FirstCompoundAssignment = 64, @@ -484,9 +485,9 @@ declare namespace ts { LastStatement = 251, FirstNode = 159, FirstJSDocNode = 304, - LastJSDocNode = 342, + LastJSDocNode = 343, FirstJSDocTagNode = 322, - LastJSDocTagNode = 342, + LastJSDocTagNode = 343, } export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -1812,6 +1813,9 @@ declare namespace ts { readonly expression: Identifier | PropertyAccessEntityNameExpression; }; } + export interface JSDocAbstractTag extends JSDocTag { + readonly kind: SyntaxKind.JSDocAbstractTag; + } export interface JSDocAuthorTag extends JSDocTag { readonly kind: SyntaxKind.JSDocAuthorTag; } @@ -3565,6 +3569,8 @@ declare namespace ts { updateJSDocCallbackTag(node: JSDocCallbackTag, tagName: Identifier | undefined, typeExpression: JSDocSignature, fullName: Identifier | JSDocNamespaceDeclaration | undefined, comment: string | NodeArray | undefined): JSDocCallbackTag; createJSDocAugmentsTag(tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment?: string | NodeArray): JSDocAugmentsTag; updateJSDocAugmentsTag(node: JSDocAugmentsTag, tagName: Identifier | undefined, className: JSDocAugmentsTag["class"], comment: string | NodeArray | undefined): JSDocAugmentsTag; + createJSDocAbstractTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAbstractTag; + updateJSDocAbstractTag(node: JSDocAbstractTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocAbstractTag; createJSDocImplementsTag(tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment?: string | NodeArray): JSDocImplementsTag; updateJSDocImplementsTag(node: JSDocImplementsTag, tagName: Identifier | undefined, className: JSDocImplementsTag["class"], comment: string | NodeArray | undefined): JSDocImplementsTag; createJSDocAuthorTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocAuthorTag; @@ -4240,6 +4246,7 @@ declare namespace ts { /** Gets the JSDoc protected tag for the node if present */ function getJSDocReadonlyTag(node: Node): JSDocReadonlyTag | undefined; function getJSDocOverrideTagNoCache(node: Node): JSDocOverrideTag | undefined; + function getJSDocAbstractTagNoCache(node: Node): JSDocAbstractTag | undefined; /** Gets the JSDoc deprecated tag for the node if present */ function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined; /** Gets the JSDoc enum tag for the node if present */ @@ -4616,6 +4623,7 @@ declare namespace ts { function isJSDocTypeLiteral(node: Node): node is JSDocTypeLiteral; function isJSDocSignature(node: Node): node is JSDocSignature; function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag; + function isJSDocAbstractTag(node: Node): node is JSDocAbstractTag; function isJSDocAuthorTag(node: Node): node is JSDocAuthorTag; function isJSDocClassTag(node: Node): node is JSDocClassTag; function isJSDocCallbackTag(node: Node): node is JSDocCallbackTag; diff --git a/tests/baselines/reference/jsdocAbstract1.errors.txt b/tests/baselines/reference/jsdocAbstract1.errors.txt new file mode 100644 index 0000000000000..a4f6aeb282df9 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.errors.txt @@ -0,0 +1,11 @@ +tests/cases/conformance/jsdoc/jsdocAbstract1.js(4,1): error TS2511: Cannot create an instance of an abstract class. + + +==== tests/cases/conformance/jsdoc/jsdocAbstract1.js (1 errors) ==== + /** @abstract */ + class A { + } + new A() + ~~~~~~~ +!!! error TS2511: Cannot create an instance of an abstract class. + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract1.js b/tests/baselines/reference/jsdocAbstract1.js new file mode 100644 index 0000000000000..adbf50ae82943 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.js @@ -0,0 +1,18 @@ +//// [jsdocAbstract1.js] +/** @abstract */ +class A { +} +new A() + + +//// [jsdocAbstract1.js] +/** @abstract */ +class A { +} +new A(); + + +//// [jsdocAbstract1.d.ts] +/** @abstract */ +declare abstract class A { +} diff --git a/tests/baselines/reference/jsdocAbstract1.symbols b/tests/baselines/reference/jsdocAbstract1.symbols new file mode 100644 index 0000000000000..e7f7a3f13f832 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.symbols @@ -0,0 +1,8 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract1.js === +/** @abstract */ +class A { +>A : Symbol(A, Decl(jsdocAbstract1.js, 0, 0)) +} +new A() +>A : Symbol(A, Decl(jsdocAbstract1.js, 0, 0)) + diff --git a/tests/baselines/reference/jsdocAbstract1.types b/tests/baselines/reference/jsdocAbstract1.types new file mode 100644 index 0000000000000..507cbe62409a3 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract1.types @@ -0,0 +1,9 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract1.js === +/** @abstract */ +class A { +>A : A +} +new A() +>new A() : any +>A : typeof A + diff --git a/tests/baselines/reference/jsdocAbstract2.errors.txt b/tests/baselines/reference/jsdocAbstract2.errors.txt new file mode 100644 index 0000000000000..44e3e4a3f2954 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.errors.txt @@ -0,0 +1,29 @@ +tests/cases/conformance/jsdoc/jsdocAbstract2.js(18,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'foo' from class 'A'. + + +==== tests/cases/conformance/jsdoc/jsdocAbstract2.js (1 errors) ==== + /** @abstract */ + class A { + /** + * @abstract + * @returns {number} + */ + foo() {} + } + + // ok + class B extends A { + foo() { + return 1; + } + } + + // error + class C extends A {} + ~ +!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'foo' from class 'A'. + + // ok + /** @abstract */ + class D extends A {} + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract2.js b/tests/baselines/reference/jsdocAbstract2.js new file mode 100644 index 0000000000000..d0115e7a59bd8 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.js @@ -0,0 +1,66 @@ +//// [jsdocAbstract2.js] +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() {} +} + +// ok +class B extends A { + foo() { + return 1; + } +} + +// error +class C extends A {} + +// ok +/** @abstract */ +class D extends A {} + + +//// [jsdocAbstract2.js] +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() { } +} +// ok +class B extends A { + foo() { + return 1; + } +} +// error +class C extends A { +} +// ok +/** @abstract */ +class D extends A { +} + + +//// [jsdocAbstract2.d.ts] +/** @abstract */ +declare abstract class A { + /** + * @abstract + * @returns {number} + */ + abstract foo(): number; +} +declare class B extends A { + foo(): number; +} +declare class C extends A { +} +/** @abstract */ +declare abstract class D extends A { +} diff --git a/tests/baselines/reference/jsdocAbstract2.symbols b/tests/baselines/reference/jsdocAbstract2.symbols new file mode 100644 index 0000000000000..53f7da92b0d8e --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.symbols @@ -0,0 +1,36 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract2.js === +/** @abstract */ +class A { +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + + /** + * @abstract + * @returns {number} + */ + foo() {} +>foo : Symbol(A.foo, Decl(jsdocAbstract2.js, 1, 9)) +} + +// ok +class B extends A { +>B : Symbol(B, Decl(jsdocAbstract2.js, 7, 1)) +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + + foo() { +>foo : Symbol(B.foo, Decl(jsdocAbstract2.js, 10, 19)) + + return 1; + } +} + +// error +class C extends A {} +>C : Symbol(C, Decl(jsdocAbstract2.js, 14, 1)) +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + +// ok +/** @abstract */ +class D extends A {} +>D : Symbol(D, Decl(jsdocAbstract2.js, 17, 20)) +>A : Symbol(A, Decl(jsdocAbstract2.js, 0, 0)) + diff --git a/tests/baselines/reference/jsdocAbstract2.types b/tests/baselines/reference/jsdocAbstract2.types new file mode 100644 index 0000000000000..ad8a2ce0124c4 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract2.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract2.js === +/** @abstract */ +class A { +>A : A + + /** + * @abstract + * @returns {number} + */ + foo() {} +>foo : () => number +} + +// ok +class B extends A { +>B : B +>A : A + + foo() { +>foo : () => number + + return 1; +>1 : 1 + } +} + +// error +class C extends A {} +>C : C +>A : A + +// ok +/** @abstract */ +class D extends A {} +>D : D +>A : A + diff --git a/tests/baselines/reference/jsdocAbstract3.js b/tests/baselines/reference/jsdocAbstract3.js new file mode 100644 index 0000000000000..1f9886e94426f --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.js @@ -0,0 +1,83 @@ +//// [jsdocAbstract3.js] +class Foo { + /** @abstract */ + m1() {} + + /** @abstract */ + static m2() {} + + /** @abstract */ + p1; + + /** @abstract */ + get p2() {} + + /** @abstract */ + set p2(value) {} +} + + +//// [jsdocAbstract3.js] +class Foo { + /** @abstract */ + m1() { } + /** @abstract */ + static m2() { } + /** @abstract */ + p1; + /** @abstract */ + get p2() { } + /** @abstract */ + set p2(value) { } +} + + +//// [jsdocAbstract3.d.ts] +declare class Foo { + /** @abstract */ + abstract static m2(): void; + /** @abstract */ + abstract m1(): void; + /** @abstract */ + abstract p1: any; + /** @abstract */ + abstract set p2(arg: void); + /** @abstract */ + abstract get p2(): void; +} + + +//// [DtsFileErrors] + + +out/jsdocAbstract3.d.ts(3,5): error TS1244: Abstract methods can only appear within an abstract class. +out/jsdocAbstract3.d.ts(5,5): error TS1244: Abstract methods can only appear within an abstract class. +out/jsdocAbstract3.d.ts(7,5): error TS1244: Abstract methods can only appear within an abstract class. +out/jsdocAbstract3.d.ts(9,5): error TS1244: Abstract methods can only appear within an abstract class. +out/jsdocAbstract3.d.ts(11,5): error TS1244: Abstract methods can only appear within an abstract class. + + +==== out/jsdocAbstract3.d.ts (5 errors) ==== + declare class Foo { + /** @abstract */ + abstract static m2(): void; + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + /** @abstract */ + abstract m1(): void; + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + /** @abstract */ + abstract p1: any; + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + /** @abstract */ + abstract set p2(arg: void); + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + /** @abstract */ + abstract get p2(): void; + ~~~~~~~~ +!!! error TS1244: Abstract methods can only appear within an abstract class. + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract3.symbols b/tests/baselines/reference/jsdocAbstract3.symbols new file mode 100644 index 0000000000000..dfb73970dfd8a --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.symbols @@ -0,0 +1,26 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract3.js === +class Foo { +>Foo : Symbol(Foo, Decl(jsdocAbstract3.js, 0, 0)) + + /** @abstract */ + m1() {} +>m1 : Symbol(Foo.m1, Decl(jsdocAbstract3.js, 0, 11)) + + /** @abstract */ + static m2() {} +>m2 : Symbol(Foo.m2, Decl(jsdocAbstract3.js, 2, 11)) + + /** @abstract */ + p1; +>p1 : Symbol(Foo.p1, Decl(jsdocAbstract3.js, 5, 18)) + + /** @abstract */ + get p2() {} +>p2 : Symbol(Foo.p2, Decl(jsdocAbstract3.js, 8, 7), Decl(jsdocAbstract3.js, 11, 15)) + + /** @abstract */ + set p2(value) {} +>p2 : Symbol(Foo.p2, Decl(jsdocAbstract3.js, 8, 7), Decl(jsdocAbstract3.js, 11, 15)) +>value : Symbol(value, Decl(jsdocAbstract3.js, 14, 11)) +} + diff --git a/tests/baselines/reference/jsdocAbstract3.types b/tests/baselines/reference/jsdocAbstract3.types new file mode 100644 index 0000000000000..e28cca361dbe0 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract3.types @@ -0,0 +1,26 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract3.js === +class Foo { +>Foo : Foo + + /** @abstract */ + m1() {} +>m1 : () => void + + /** @abstract */ + static m2() {} +>m2 : () => void + + /** @abstract */ + p1; +>p1 : any + + /** @abstract */ + get p2() {} +>p2 : void + + /** @abstract */ + set p2(value) {} +>p2 : void +>value : void +} + diff --git a/tests/baselines/reference/jsdocAbstract4.errors.txt b/tests/baselines/reference/jsdocAbstract4.errors.txt new file mode 100644 index 0000000000000..c7017f96ebb50 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.errors.txt @@ -0,0 +1,112 @@ +tests/cases/conformance/jsdoc/jsdocAbstract4.js(51,5): error TS1245: Method 'm' cannot have an implementation because it is marked abstract. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(58,9): error TS1318: An abstract accessor cannot have an implementation. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(65,9): error TS1318: An abstract accessor cannot have an implementation. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(73,5): error TS1245: Method 'm' cannot have an implementation because it is marked abstract. +tests/cases/conformance/jsdoc/jsdocAbstract4.js(84,9): error TS1318: An abstract accessor cannot have an implementation. + + +==== tests/cases/conformance/jsdoc/jsdocAbstract4.js (5 errors) ==== + /** @abstract */ + class C1 { + /** @abstract */ + m() {} + + /** @abstract */ + set p1(value) {} + + /** @abstract */ + get p1() {} + } + + /** @abstract */ + class C2 { + /** @abstract */ + m() { + throw new Error("Method not implemented.") + } + + /** @abstract */ + set p1(value) { + throw new Error("Method not implemented.") + } + + /** @abstract */ + get p1() { + throw new Error("Method not implemented.") + } + } + + /** @abstract */ + class C3 { + /** @abstract */ + m() { + /** @type {never} */ + let x; + return x; + } + + /** @abstract */ + get p1() { + /** @type {never} */ + let x; + return x; + } + } + + /** @abstract */ + class C4 { + /** @abstract */ + m() { + ~ +!!! error TS1245: Method 'm' cannot have an implementation because it is marked abstract. + const x = 1; + const y = 1; + return x + y; + } + + /** @abstract */ + get p1() { + ~~ +!!! error TS1318: An abstract accessor cannot have an implementation. + const x = 1; + const y = 1; + return x + y; + } + + /** @abstract */ + set p1(value) { + ~~ +!!! error TS1318: An abstract accessor cannot have an implementation. + this.p1 = value; + } + } + + /** @abstract */ + class C5 { + /** @abstract */ + m() { + ~ +!!! error TS1245: Method 'm' cannot have an implementation because it is marked abstract. + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } + + /** @abstract */ + get p1() { + ~~ +!!! error TS1318: An abstract accessor cannot have an implementation. + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocAbstract4.js b/tests/baselines/reference/jsdocAbstract4.js new file mode 100644 index 0000000000000..7432a3482096b --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.js @@ -0,0 +1,222 @@ +//// [jsdocAbstract4.js] +/** @abstract */ +class C1 { + /** @abstract */ + m() {} + + /** @abstract */ + set p1(value) {} + + /** @abstract */ + get p1() {} +} + +/** @abstract */ +class C2 { + /** @abstract */ + m() { + throw new Error("Method not implemented.") + } + + /** @abstract */ + set p1(value) { + throw new Error("Method not implemented.") + } + + /** @abstract */ + get p1() { + throw new Error("Method not implemented.") + } +} + +/** @abstract */ +class C3 { + /** @abstract */ + m() { + /** @type {never} */ + let x; + return x; + } + + /** @abstract */ + get p1() { + /** @type {never} */ + let x; + return x; + } +} + +/** @abstract */ +class C4 { + /** @abstract */ + m() { + const x = 1; + const y = 1; + return x + y; + } + + /** @abstract */ + get p1() { + const x = 1; + const y = 1; + return x + y; + } + + /** @abstract */ + set p1(value) { + this.p1 = value; + } +} + +/** @abstract */ +class C5 { + /** @abstract */ + m() { + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } + + /** @abstract */ + get p1() { + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } +} + + +//// [jsdocAbstract4.js] +/** @abstract */ +class C1 { + /** @abstract */ + m() { } + /** @abstract */ + set p1(value) { } + /** @abstract */ + get p1() { } +} +/** @abstract */ +class C2 { + /** @abstract */ + m() { + throw new Error("Method not implemented."); + } + /** @abstract */ + set p1(value) { + throw new Error("Method not implemented."); + } + /** @abstract */ + get p1() { + throw new Error("Method not implemented."); + } +} +/** @abstract */ +class C3 { + /** @abstract */ + m() { + /** @type {never} */ + let x; + return x; + } + /** @abstract */ + get p1() { + /** @type {never} */ + let x; + return x; + } +} +/** @abstract */ +class C4 { + /** @abstract */ + m() { + const x = 1; + const y = 1; + return x + y; + } + /** @abstract */ + get p1() { + const x = 1; + const y = 1; + return x + y; + } + /** @abstract */ + set p1(value) { + this.p1 = value; + } +} +/** @abstract */ +class C5 { + /** @abstract */ + m() { + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } + /** @abstract */ + get p1() { + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } +} + + +//// [jsdocAbstract4.d.ts] +/** @abstract */ +declare abstract class C1 { + /** @abstract */ + abstract m(): void; + /** @abstract */ + abstract set p1(arg: void); + /** @abstract */ + abstract get p1(): void; +} +/** @abstract */ +declare abstract class C2 { + /** @abstract */ + abstract m(): void; + /** @abstract */ + abstract set p1(arg: void); + /** @abstract */ + abstract get p1(): void; +} +/** @abstract */ +declare abstract class C3 { + /** @abstract */ + abstract m(): never; + /** @abstract */ + abstract get p1(): never; +} +/** @abstract */ +declare abstract class C4 { + /** @abstract */ + abstract m(): number; + /** @abstract */ + abstract set p1(arg: number); + /** @abstract */ + abstract get p1(): number; +} +/** @abstract */ +declare abstract class C5 { + /** @abstract */ + abstract m(): number; + /** @abstract */ + abstract get p1(): number; +} diff --git a/tests/baselines/reference/jsdocAbstract4.symbols b/tests/baselines/reference/jsdocAbstract4.symbols new file mode 100644 index 0000000000000..d35318dada3d9 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.symbols @@ -0,0 +1,172 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract4.js === +/** @abstract */ +class C1 { +>C1 : Symbol(C1, Decl(jsdocAbstract4.js, 0, 0)) + + /** @abstract */ + m() {} +>m : Symbol(C1.m, Decl(jsdocAbstract4.js, 1, 10)) + + /** @abstract */ + set p1(value) {} +>p1 : Symbol(C1.p1, Decl(jsdocAbstract4.js, 3, 10), Decl(jsdocAbstract4.js, 6, 20)) +>value : Symbol(value, Decl(jsdocAbstract4.js, 6, 11)) + + /** @abstract */ + get p1() {} +>p1 : Symbol(C1.p1, Decl(jsdocAbstract4.js, 3, 10), Decl(jsdocAbstract4.js, 6, 20)) +} + +/** @abstract */ +class C2 { +>C2 : Symbol(C2, Decl(jsdocAbstract4.js, 10, 1)) + + /** @abstract */ + m() { +>m : Symbol(C2.m, Decl(jsdocAbstract4.js, 13, 10)) + + throw new Error("Method not implemented.") +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + + /** @abstract */ + set p1(value) { +>p1 : Symbol(C2.p1, Decl(jsdocAbstract4.js, 17, 5), Decl(jsdocAbstract4.js, 22, 5)) +>value : Symbol(value, Decl(jsdocAbstract4.js, 20, 11)) + + throw new Error("Method not implemented.") +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } + + /** @abstract */ + get p1() { +>p1 : Symbol(C2.p1, Decl(jsdocAbstract4.js, 17, 5), Decl(jsdocAbstract4.js, 22, 5)) + + throw new Error("Method not implemented.") +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } +} + +/** @abstract */ +class C3 { +>C3 : Symbol(C3, Decl(jsdocAbstract4.js, 28, 1)) + + /** @abstract */ + m() { +>m : Symbol(C3.m, Decl(jsdocAbstract4.js, 31, 10)) + + /** @type {never} */ + let x; +>x : Symbol(x, Decl(jsdocAbstract4.js, 35, 11)) + + return x; +>x : Symbol(x, Decl(jsdocAbstract4.js, 35, 11)) + } + + /** @abstract */ + get p1() { +>p1 : Symbol(C3.p1, Decl(jsdocAbstract4.js, 37, 5)) + + /** @type {never} */ + let x; +>x : Symbol(x, Decl(jsdocAbstract4.js, 42, 11)) + + return x; +>x : Symbol(x, Decl(jsdocAbstract4.js, 42, 11)) + } +} + +/** @abstract */ +class C4 { +>C4 : Symbol(C4, Decl(jsdocAbstract4.js, 45, 1)) + + /** @abstract */ + m() { +>m : Symbol(C4.m, Decl(jsdocAbstract4.js, 48, 10)) + + const x = 1; +>x : Symbol(x, Decl(jsdocAbstract4.js, 51, 13)) + + const y = 1; +>y : Symbol(y, Decl(jsdocAbstract4.js, 52, 13)) + + return x + y; +>x : Symbol(x, Decl(jsdocAbstract4.js, 51, 13)) +>y : Symbol(y, Decl(jsdocAbstract4.js, 52, 13)) + } + + /** @abstract */ + get p1() { +>p1 : Symbol(C4.p1, Decl(jsdocAbstract4.js, 54, 5), Decl(jsdocAbstract4.js, 61, 5)) + + const x = 1; +>x : Symbol(x, Decl(jsdocAbstract4.js, 58, 13)) + + const y = 1; +>y : Symbol(y, Decl(jsdocAbstract4.js, 59, 13)) + + return x + y; +>x : Symbol(x, Decl(jsdocAbstract4.js, 58, 13)) +>y : Symbol(y, Decl(jsdocAbstract4.js, 59, 13)) + } + + /** @abstract */ + set p1(value) { +>p1 : Symbol(C4.p1, Decl(jsdocAbstract4.js, 54, 5), Decl(jsdocAbstract4.js, 61, 5)) +>value : Symbol(value, Decl(jsdocAbstract4.js, 64, 11)) + + this.p1 = value; +>this.p1 : Symbol(C4.p1, Decl(jsdocAbstract4.js, 54, 5), Decl(jsdocAbstract4.js, 61, 5)) +>this : Symbol(C4, Decl(jsdocAbstract4.js, 45, 1)) +>p1 : Symbol(C4.p1, Decl(jsdocAbstract4.js, 54, 5), Decl(jsdocAbstract4.js, 61, 5)) +>value : Symbol(value, Decl(jsdocAbstract4.js, 64, 11)) + } +} + +/** @abstract */ +class C5 { +>C5 : Symbol(C5, Decl(jsdocAbstract4.js, 67, 1)) + + /** @abstract */ + m() { +>m : Symbol(C5.m, Decl(jsdocAbstract4.js, 70, 10)) + + const x = 1; +>x : Symbol(x, Decl(jsdocAbstract4.js, 73, 13)) + + /** @type {never} */ + let y; +>y : Symbol(y, Decl(jsdocAbstract4.js, 75, 11)) + + if (x) { +>x : Symbol(x, Decl(jsdocAbstract4.js, 73, 13)) + + return x; +>x : Symbol(x, Decl(jsdocAbstract4.js, 73, 13)) + } + return y; +>y : Symbol(y, Decl(jsdocAbstract4.js, 75, 11)) + } + + /** @abstract */ + get p1() { +>p1 : Symbol(C5.p1, Decl(jsdocAbstract4.js, 80, 5)) + + const x = 1; +>x : Symbol(x, Decl(jsdocAbstract4.js, 84, 13)) + + /** @type {never} */ + let y; +>y : Symbol(y, Decl(jsdocAbstract4.js, 86, 11)) + + if (x) { +>x : Symbol(x, Decl(jsdocAbstract4.js, 84, 13)) + + return x; +>x : Symbol(x, Decl(jsdocAbstract4.js, 84, 13)) + } + return y; +>y : Symbol(y, Decl(jsdocAbstract4.js, 86, 11)) + } +} + diff --git a/tests/baselines/reference/jsdocAbstract4.types b/tests/baselines/reference/jsdocAbstract4.types new file mode 100644 index 0000000000000..ef4ed326edda3 --- /dev/null +++ b/tests/baselines/reference/jsdocAbstract4.types @@ -0,0 +1,187 @@ +=== tests/cases/conformance/jsdoc/jsdocAbstract4.js === +/** @abstract */ +class C1 { +>C1 : C1 + + /** @abstract */ + m() {} +>m : () => void + + /** @abstract */ + set p1(value) {} +>p1 : void +>value : void + + /** @abstract */ + get p1() {} +>p1 : void +} + +/** @abstract */ +class C2 { +>C2 : C2 + + /** @abstract */ + m() { +>m : () => void + + throw new Error("Method not implemented.") +>new Error("Method not implemented.") : Error +>Error : ErrorConstructor +>"Method not implemented." : "Method not implemented." + } + + /** @abstract */ + set p1(value) { +>p1 : void +>value : void + + throw new Error("Method not implemented.") +>new Error("Method not implemented.") : Error +>Error : ErrorConstructor +>"Method not implemented." : "Method not implemented." + } + + /** @abstract */ + get p1() { +>p1 : void + + throw new Error("Method not implemented.") +>new Error("Method not implemented.") : Error +>Error : ErrorConstructor +>"Method not implemented." : "Method not implemented." + } +} + +/** @abstract */ +class C3 { +>C3 : C3 + + /** @abstract */ + m() { +>m : () => never + + /** @type {never} */ + let x; +>x : never + + return x; +>x : never + } + + /** @abstract */ + get p1() { +>p1 : never + + /** @type {never} */ + let x; +>x : never + + return x; +>x : never + } +} + +/** @abstract */ +class C4 { +>C4 : C4 + + /** @abstract */ + m() { +>m : () => number + + const x = 1; +>x : 1 +>1 : 1 + + const y = 1; +>y : 1 +>1 : 1 + + return x + y; +>x + y : number +>x : 1 +>y : 1 + } + + /** @abstract */ + get p1() { +>p1 : number + + const x = 1; +>x : 1 +>1 : 1 + + const y = 1; +>y : 1 +>1 : 1 + + return x + y; +>x + y : number +>x : 1 +>y : 1 + } + + /** @abstract */ + set p1(value) { +>p1 : number +>value : number + + this.p1 = value; +>this.p1 = value : number +>this.p1 : number +>this : this +>p1 : number +>value : number + } +} + +/** @abstract */ +class C5 { +>C5 : C5 + + /** @abstract */ + m() { +>m : () => number + + const x = 1; +>x : 1 +>1 : 1 + + /** @type {never} */ + let y; +>y : never + + if (x) { +>x : 1 + + return x; +>x : 1 + } + return y; +>y : never + } + + /** @abstract */ + get p1() { +>p1 : number + + const x = 1; +>x : 1 +>1 : 1 + + /** @type {never} */ + let y; +>y : never + + if (x) { +>x : 1 + + return x; +>x : 1 + } + return y; +>y : never + } +} + diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract1.ts b/tests/cases/conformance/jsdoc/jsdocAbstract1.ts new file mode 100644 index 0000000000000..ba97f26ce5f79 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract1.ts @@ -0,0 +1,11 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @outDir: out +// @Filename: jsdocAbstract1.js + +/** @abstract */ +class A { +} +new A() diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract2.ts b/tests/cases/conformance/jsdoc/jsdocAbstract2.ts new file mode 100644 index 0000000000000..51a7f63356db2 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract2.ts @@ -0,0 +1,29 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @outDir: out +// @Filename: jsdocAbstract2.js + +/** @abstract */ +class A { + /** + * @abstract + * @returns {number} + */ + foo() {} +} + +// ok +class B extends A { + foo() { + return 1; + } +} + +// error +class C extends A {} + +// ok +/** @abstract */ +class D extends A {} diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract3.ts b/tests/cases/conformance/jsdoc/jsdocAbstract3.ts new file mode 100644 index 0000000000000..58bb234fb26fe --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract3.ts @@ -0,0 +1,23 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @outDir: out +// @Filename: jsdocAbstract3.js + +class Foo { + /** @abstract */ + m1() {} + + /** @abstract */ + static m2() {} + + /** @abstract */ + p1; + + /** @abstract */ + get p2() {} + + /** @abstract */ + set p2(value) {} +} diff --git a/tests/cases/conformance/jsdoc/jsdocAbstract4.ts b/tests/cases/conformance/jsdoc/jsdocAbstract4.ts new file mode 100644 index 0000000000000..c10a73fb79fb4 --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocAbstract4.ts @@ -0,0 +1,100 @@ +// @allowJs: true +// @checkJs: true +// @target: esnext +// @declaration: true +// @outDir: out +// @Filename: jsdocAbstract4.js + +/** @abstract */ +class C1 { + /** @abstract */ + m() {} + + /** @abstract */ + set p1(value) {} + + /** @abstract */ + get p1() {} +} + +/** @abstract */ +class C2 { + /** @abstract */ + m() { + throw new Error("Method not implemented.") + } + + /** @abstract */ + set p1(value) { + throw new Error("Method not implemented.") + } + + /** @abstract */ + get p1() { + throw new Error("Method not implemented.") + } +} + +/** @abstract */ +class C3 { + /** @abstract */ + m() { + /** @type {never} */ + let x; + return x; + } + + /** @abstract */ + get p1() { + /** @type {never} */ + let x; + return x; + } +} + +/** @abstract */ +class C4 { + /** @abstract */ + m() { + const x = 1; + const y = 1; + return x + y; + } + + /** @abstract */ + get p1() { + const x = 1; + const y = 1; + return x + y; + } + + /** @abstract */ + set p1(value) { + this.p1 = value; + } +} + +/** @abstract */ +class C5 { + /** @abstract */ + m() { + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } + + /** @abstract */ + get p1() { + const x = 1; + /** @type {never} */ + let y; + if (x) { + return x; + } + return y; + } +}