From d1ae0e85c8d3ffe4464cadbae69d8f6cdfad6756 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 15 Apr 2024 17:09:16 -0400 Subject: [PATCH] Avoid mutating SymbolObject.prototype in services --- src/compiler/objectConstructors.ts | 25 +++---- src/compiler/symbolObjectInternals.ts | 27 +++++++ src/services/services.ts | 104 ++++++++++++++------------ 3 files changed, 91 insertions(+), 65 deletions(-) create mode 100644 src/compiler/symbolObjectInternals.ts diff --git a/src/compiler/objectConstructors.ts b/src/compiler/objectConstructors.ts index 1efe240e29a..4e78bd788fd 100644 --- a/src/compiler/objectConstructors.ts +++ b/src/compiler/objectConstructors.ts @@ -42,6 +42,7 @@ import { UnionOrIntersectionType, UnionType, } from "./_namespaces/ts"; +import { SymbolObjectInternals } from "./symbolObjectInternals"; /** @internal */ export class SymbolObject implements Symbol { @@ -76,14 +77,6 @@ export class SymbolObject implements Symbol { declare assignmentDeclarationMembers?: Map; declare globalExports?: SymbolTable; - // TODO: Added by services, review for migration/polymorphism: - // documentationComment?: SymbolDisplayPart[]; - // tags?: JSDocTagInfo[]; // same - // contextualGetAccessorDocumentationComment?: SymbolDisplayPart[]; - // contextualSetAccessorDocumentationComment?: SymbolDisplayPart[]; - // contextualGetAccessorTags?: JSDocTagInfo[]; - // contextualSetAccessorTags?: JSDocTagInfo[]; - constructor(flags: SymbolFlags, name: __String) { this.flags = flags; this.escapedName = name; @@ -109,20 +102,20 @@ export class SymbolObject implements Symbol { return this.declarations; } - getDocumentationComment(_checker: TypeChecker | undefined): SymbolDisplayPart[] { - throw new TypeError("Not implemented."); + getDocumentationComment(checker: TypeChecker | undefined): SymbolDisplayPart[] { + return SymbolObjectInternals.internals.getDocumentationComment(this, checker); } - getContextualDocumentationComment(_context: Node | undefined, _checker: TypeChecker | undefined): SymbolDisplayPart[] { - throw new TypeError("Not implemented."); + getContextualDocumentationComment(context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { + return SymbolObjectInternals.internals.getContextualDocumentationComment(this, context, checker); } - getJsDocTags(_checker?: TypeChecker): JSDocTagInfo[] { - throw new TypeError("Not implemented."); + getJsDocTags(checker?: TypeChecker): JSDocTagInfo[] { + return SymbolObjectInternals.internals.getJsDocTags(this, checker); } - getContextualJsDocTags(_context: Node | undefined, _checker: TypeChecker | undefined): JSDocTagInfo[] { - throw new TypeError("Not implemented."); + getContextualJsDocTags(context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] { + return SymbolObjectInternals.internals.getContextualJsDocTags(this, context, checker); } } diff --git a/src/compiler/symbolObjectInternals.ts b/src/compiler/symbolObjectInternals.ts new file mode 100644 index 00000000000..90022d68977 --- /dev/null +++ b/src/compiler/symbolObjectInternals.ts @@ -0,0 +1,27 @@ +import { SymbolObject } from "./objectConstructors"; +import { JSDocTagInfo, Node, SymbolDisplayPart, TypeChecker } from "./types"; + +/** @internal */ +export class SymbolObjectInternals { + static internals = new SymbolObjectInternals(); + + getDocumentationComment(symbol: SymbolObject, typeChecker: TypeChecker | undefined): SymbolDisplayPart[]; + getDocumentationComment(_symbol: SymbolObject, _typeChecker: TypeChecker | undefined): SymbolDisplayPart[] { + throw new TypeError("Not implemented."); + } + + getContextualDocumentationComment(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[]; + getContextualDocumentationComment(_symbol: SymbolObject, _context: Node | undefined, _checker: TypeChecker | undefined): SymbolDisplayPart[] { + throw new TypeError("Not implemented."); + } + + getJsDocTags(symbol: SymbolObject, checker?: TypeChecker): JSDocTagInfo[]; + getJsDocTags(_symbol: SymbolObject, _checker?: TypeChecker): JSDocTagInfo[] { + throw new TypeError("Not implemented."); + } + + getContextualJsDocTags(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[]; + getContextualJsDocTags(_symbol: SymbolObject, _context: Node | undefined, _checker: TypeChecker | undefined): JSDocTagInfo[] { + throw new TypeError("Not implemented."); + } +} diff --git a/src/services/services.ts b/src/services/services.ts index f500b65c88a..c1207c1e3fc 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2,6 +2,7 @@ import { SignatureObject, SymbolObject, } from "../compiler/objectConstructors"; +import { SymbolObjectInternals } from "../compiler/symbolObjectInternals"; import { __String, ApplicableRefactorInfo, @@ -290,64 +291,69 @@ function ensureSymbolExtraFields(symbol: Symbol) { return extra; } -SymbolObject.prototype.getDocumentationComment = function (this: Symbol | TransientSymbol, checker: TypeChecker | undefined): SymbolDisplayPart[] { - const extra = ensureSymbolExtraFields(this); - if (!extra.documentationComment) { - extra.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs +class ServicesSymbolObjectInternals extends SymbolObjectInternals { + override getDocumentationComment(symbol: SymbolObject, checker: TypeChecker | undefined): SymbolDisplayPart[] { + const extra = ensureSymbolExtraFields(symbol); + if (!extra.documentationComment) { + extra.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs - if (!this.declarations && isTransientSymbol(this) && this.links.target && isTransientSymbol(this.links.target) && this.links.target.links.tupleLabelDeclaration) { - const labelDecl = this.links.target.links.tupleLabelDeclaration; - extra.documentationComment = getDocumentationComment([labelDecl], checker); - } - else { - extra.documentationComment = getDocumentationComment(this.declarations, checker); + if (!symbol.declarations && isTransientSymbol(symbol) && symbol.links.target && isTransientSymbol(symbol.links.target) && symbol.links.target.links.tupleLabelDeclaration) { + const labelDecl = symbol.links.target.links.tupleLabelDeclaration; + extra.documentationComment = getDocumentationComment([labelDecl], checker); + } + else { + extra.documentationComment = getDocumentationComment(symbol.declarations, checker); + } } + return extra.documentationComment; } - return extra.documentationComment; -}; -SymbolObject.prototype.getContextualDocumentationComment = function (this: Symbol, context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { - if (context) { - const extra = ensureSymbolExtraFields(this); - if (isGetAccessor(context)) { - extra.contextualGetAccessorDocumentationComment ??= getDocumentationComment(filter(this.declarations, isGetAccessor), checker); - if (length(extra.contextualGetAccessorDocumentationComment)) { - return extra.contextualGetAccessorDocumentationComment; - } - } - else if (isSetAccessor(context)) { - extra.contextualSetAccessorDocumentationComment ??= getDocumentationComment(filter(this.declarations, isSetAccessor), checker); - if (length(extra.contextualSetAccessorDocumentationComment)) { - return extra.contextualSetAccessorDocumentationComment; + override getContextualDocumentationComment(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] { + if (context) { + const extra = ensureSymbolExtraFields(symbol); + if (isGetAccessor(context)) { + extra.contextualGetAccessorDocumentationComment ??= getDocumentationComment(filter(symbol.declarations, isGetAccessor), checker); + if (length(extra.contextualGetAccessorDocumentationComment)) { + return extra.contextualGetAccessorDocumentationComment; + } + } + else if (isSetAccessor(context)) { + extra.contextualSetAccessorDocumentationComment ??= getDocumentationComment(filter(symbol.declarations, isSetAccessor), checker); + if (length(extra.contextualSetAccessorDocumentationComment)) { + return extra.contextualSetAccessorDocumentationComment; + } } } + return this.getDocumentationComment(symbol, checker); } - return this.getDocumentationComment(checker); -}; -SymbolObject.prototype.getJsDocTags = function (this: Symbol, checker?: TypeChecker): JSDocTagInfo[] { - const extra = ensureSymbolExtraFields(this); - return extra.tags ??= getJsDocTagsOfDeclarations(this.declarations, checker); -}; - -SymbolObject.prototype.getContextualJsDocTags = function (this: Symbol, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] { - if (context) { - const extra = ensureSymbolExtraFields(this); - if (isGetAccessor(context)) { - extra.contextualGetAccessorTags ??= getJsDocTagsOfDeclarations(filter(this.declarations, isGetAccessor), checker); - if (length(extra.contextualGetAccessorTags)) { - return extra.contextualGetAccessorTags; - } - } - else if (isSetAccessor(context)) { - extra.contextualSetAccessorTags ??= getJsDocTagsOfDeclarations(filter(this.declarations, isSetAccessor), checker); - if (length(extra.contextualSetAccessorTags)) { - return extra.contextualSetAccessorTags; - } - } + override getJsDocTags(symbol: SymbolObject, checker?: TypeChecker): JSDocTagInfo[] { + const extra = ensureSymbolExtraFields(symbol); + return extra.tags ??= getJsDocTagsOfDeclarations(symbol.declarations, checker); } - return this.getJsDocTags(checker); -}; + + override getContextualJsDocTags(symbol: SymbolObject, context: Node | undefined, checker: TypeChecker | undefined): JSDocTagInfo[] { + if (context) { + const extra = ensureSymbolExtraFields(symbol); + if (isGetAccessor(context)) { + extra.contextualGetAccessorTags ??= getJsDocTagsOfDeclarations(filter(symbol.declarations, isGetAccessor), checker); + if (length(extra.contextualGetAccessorTags)) { + return extra.contextualGetAccessorTags; + } + } + else if (isSetAccessor(context)) { + extra.contextualSetAccessorTags ??= getJsDocTagsOfDeclarations(filter(symbol.declarations, isSetAccessor), checker); + if (length(extra.contextualSetAccessorTags)) { + return extra.contextualSetAccessorTags; + } + } + } + return this.getJsDocTags(symbol, checker); + } +} + +// Override the internals for symbols +SymbolObjectInternals.internals = new ServicesSymbolObjectInternals(); interface SignatureExtraFields { // Undefined is used to indicate the value has not been computed. If, after computing, the