diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9f77641faf5cc..1aea0c180e432 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -111,7 +111,7 @@ import { createGetCanonicalFileName, createGetSymbolWalker, createModeAwareCacheKey, - createPrinter, + createOrReusePrinter, createPropertyNameNodeForIdentifierOrLiteral, createSymbolTable, createTextWriter, @@ -6123,7 +6123,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function symbolToStringWorker(writer: EmitTextWriter) { const entity = builder(symbol, meaning!, enclosingDeclaration, nodeFlags)!; // TODO: GH#18217 // add neverAsciiEscape for GH#39027 - const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? createPrinter({ removeComments: true, neverAsciiEscape: true }) : createPrinter({ removeComments: true }); + const printer = enclosingDeclaration?.kind === SyntaxKind.SourceFile ? createOrReusePrinter({ removeComments: true, neverAsciiEscape: true }) : createOrReusePrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, entity, /*sourceFile*/ sourceFile, writer); return writer; @@ -6142,7 +6142,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { sigOutput = kind === SignatureKind.Construct ? SyntaxKind.ConstructSignature : SyntaxKind.CallSignature; } const sig = nodeBuilder.signatureToSignatureDeclaration(signature, sigOutput, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName); - const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); + const printer = createOrReusePrinter({ removeComments: true, omitTrailingSemicolon: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, sig!, /*sourceFile*/ sourceFile, getTrailingSemicolonDeferringWriter(writer)); // TODO: GH#18217 return writer; @@ -6156,7 +6156,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The unresolved type gets a synthesized comment on `any` to hint to users that it's not a plain `any`. // Otherwise, we always strip comments out. const options = { removeComments: type !== unresolvedType }; - const printer = createPrinter(options); + const printer = createOrReusePrinter(options); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); @@ -9636,7 +9636,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { typePredicate.kind === TypePredicateKind.Identifier || typePredicate.kind === TypePredicateKind.AssertsIdentifier ? factory.createIdentifier(typePredicate.parameterName) : factory.createThisTypeNode(), typePredicate.type && nodeBuilder.typeToTypeNode(typePredicate.type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.WriteTypeParametersInQualifiedName)! // TODO: GH#18217 ); - const printer = createPrinter({ removeComments: true }); + const printer = createOrReusePrinter({ removeComments: true }); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, predicate, /*sourceFile*/ sourceFile, writer); return writer; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 170ad79e7d587..d9317f267b27c 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1343,19 +1343,44 @@ const enum PipelinePhase { Emit, } +const printerCache = new Map(); + +// If updating this, make sure the cache key is updated too. +/** @internal */ +export type ReusablePrinterOptions = Pick; + +/** @internal */ +export function createOrReusePrinter(o: ReusablePrinterOptions = {}) { + const key = `${keyBool(o.removeComments)}|${keyBool(o.neverAsciiEscape)}|${keyBool(o.omitTrailingSemicolon)}|${keyNum(o.module)}|${keyNum(o.target)}|${keyNum(o.newLine)}|${keyBool(o.preserveSourceNewlines)}|${keyBool(o.terminateUnterminatedLiterals)}`; + let printer = printerCache.get(key); + if (!printer) { + printerCache.set(key, printer = createPrinter(o)); + } + return printer; + + function keyBool(value: boolean | undefined) { + return value === undefined ? "u" : value ? 1 : 0; + } + + function keyNum(value: number | undefined) { + return value === undefined ? "u" : `${value}`; + } +} + export function createPrinter(printerOptions: PrinterOptions = {}, handlers: PrintHandlers = {}): Printer { - const { - hasGlobalName, - onEmitNode = noEmitNotification, - isEmitNotificationEnabled, - substituteNode = noEmitSubstitution, - onBeforeEmitNode, - onAfterEmitNode, - onBeforeEmitNodeArray, - onAfterEmitNodeArray, - onBeforeEmitToken, - onAfterEmitToken - } = handlers; + let theHandlers!: PrintHandlers & Required>; + + function setHandlers(newHandlers?: PrintHandlers) { + if (newHandlers) { + theHandlers = { + onEmitNode: noEmitNotification, + substituteNode: noEmitSubstitution, + ...newHandlers, + }; + } + } + + setHandlers(handlers); const extendedDiagnostics = !!printerOptions.extendedDiagnostics; const newLine = getNewLineCharacter(printerOptions); @@ -1475,18 +1500,23 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri /** * If `sourceFile` is `undefined`, `node` must be a synthesized `TypeNode`. */ - function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter): void; - function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter): void; - function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter) { + function writeNode(hint: EmitHint, node: TypeNode, sourceFile: undefined, output: EmitTextWriter, handlers?: PrintHandlers): void; + function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile, output: EmitTextWriter, handlers?: PrintHandlers): void; + function writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, output: EmitTextWriter, handlers?: PrintHandlers) { const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, /*_sourceMapGenerator*/ undefined); print(hint, node, sourceFile); reset(); writer = previousWriter; + theHandlers = previousHandlers; } - function writeList(format: ListFormat, nodes: NodeArray, sourceFile: SourceFile | undefined, output: EmitTextWriter) { + function writeList(format: ListFormat, nodes: NodeArray, sourceFile: SourceFile | undefined, output: EmitTextWriter, handlers?: PrintHandlers) { const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, /*_sourceMapGenerator*/ undefined); if (sourceFile) { setSourceFile(sourceFile); @@ -1494,6 +1524,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitList(/*parentNode*/ undefined, nodes, format); reset(); writer = previousWriter; + theHandlers = previousHandlers; } function getTextPosWithWriteLine() { @@ -1542,9 +1573,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return false; } - function writeBundle(bundle: Bundle, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeBundle(bundle: Bundle, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers) { isOwnFileEmit = false; const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, sourceMapGenerator); emitShebangIfNeeded(bundle); emitPrologueDirectivesIfNeeded(bundle); @@ -1599,6 +1632,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri reset(); writer = previousWriter; + theHandlers = previousHandlers; } function writeUnparsedSource(unparsed: UnparsedSource, output: EmitTextWriter) { @@ -1609,15 +1643,18 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri writer = previousWriter; } - function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined) { + function writeFile(sourceFile: SourceFile, output: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers) { isOwnFileEmit = true; const previousWriter = writer; + const previousHandlers = theHandlers; + setHandlers(handlers); setWriter(output, sourceMapGenerator); emitShebangIfNeeded(sourceFile); emitPrologueDirectivesIfNeeded(sourceFile); print(EmitHint.SourceFile, sourceFile, sourceFile); reset(); writer = previousWriter; + theHandlers = previousHandlers; } function beginPrint() { @@ -1741,12 +1778,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function getPipelinePhase(phase: PipelinePhase, emitHint: EmitHint, node: Node) { switch (phase) { case PipelinePhase.Notification: - if (onEmitNode !== noEmitNotification && (!isEmitNotificationEnabled || isEmitNotificationEnabled(node))) { + if (theHandlers.onEmitNode !== noEmitNotification && (!theHandlers.isEmitNotificationEnabled || theHandlers.isEmitNotificationEnabled(node))) { return pipelineEmitWithNotification; } // falls through case PipelinePhase.Substitution: - if (substituteNode !== noEmitSubstitution && (lastSubstitution = substituteNode(emitHint, node) || node) !== node) { + if (theHandlers.substituteNode !== noEmitSubstitution && (lastSubstitution = theHandlers.substituteNode(emitHint, node) || node) !== node) { if (currentParenthesizerRule) { lastSubstitution = currentParenthesizerRule(lastSubstitution); } @@ -1776,11 +1813,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function pipelineEmitWithNotification(hint: EmitHint, node: Node) { const pipelinePhase = getNextPipelinePhase(PipelinePhase.Notification, hint, node); - onEmitNode(hint, node, pipelinePhase); + theHandlers.onEmitNode(hint, node, pipelinePhase); } function pipelineEmitWithHint(hint: EmitHint, node: Node): void { - onBeforeEmitNode?.(node); + theHandlers.onBeforeEmitNode?.(node); if (preserveSourceNewlines) { const savedPreserveSourceNewlines = preserveSourceNewlines; beforeEmitNode(node); @@ -1790,7 +1827,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri else { pipelineEmitWithHintWorker(hint, node); } - onAfterEmitNode?.(node); + theHandlers.onAfterEmitNode?.(node); // clear the parenthesizer rule as we ascend currentParenthesizerRule = undefined; } @@ -2161,8 +2198,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } if (isExpression(node)) { hint = EmitHint.Expression; - if (substituteNode !== noEmitSubstitution) { - const substitute = substituteNode(hint, node) || node; + if (theHandlers.substituteNode !== noEmitSubstitution) { + const substitute = theHandlers.substituteNode(hint, node) || node; if (substitute !== node) { node = substitute; if (currentParenthesizerRule) { @@ -3203,7 +3240,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri state.declarationListContainerEndStack[state.stackIndex] = declarationListContainerEnd; const emitComments = state.shouldEmitCommentsStack[state.stackIndex] = shouldEmitComments(node); const emitSourceMaps = state.shouldEmitSourceMapsStack[state.stackIndex] = shouldEmitSourceMaps(node); - onBeforeEmitNode?.(node); + theHandlers.onBeforeEmitNode?.(node); if (emitComments) emitCommentsBeforeNode(node); if (emitSourceMaps) emitSourceMapsBeforeNode(node); beforeEmitNode(node); @@ -3255,7 +3292,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri afterEmitNode(savedPreserveSourceNewlines); if (shouldEmitSourceMaps) emitSourceMapsAfterNode(node); if (shouldEmitComments) emitCommentsAfterNode(node, savedContainerPos, savedContainerEnd, savedDeclarationListContainerEnd); - onAfterEmitNode?.(node); + theHandlers.onAfterEmitNode?.(node); state.stackIndex--; } } @@ -3756,7 +3793,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function emitBlockFunctionBody(body: Block) { - onBeforeEmitNode?.(body); + theHandlers.onBeforeEmitNode?.(body); writeSpace(); writePunctuation("{"); increaseIndent(); @@ -3769,7 +3806,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri decreaseIndent(); writeToken(SyntaxKind.CloseBraceToken, body.statements.end, writePunctuation, body); - onAfterEmitNode?.(body); + theHandlers.onAfterEmitNode?.(body); } function emitBlockFunctionBodyOnSingleLine(body: Block) { @@ -4737,7 +4774,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return node.pos; } - onBeforeEmitNodeArray?.(modifiers); + theHandlers.onBeforeEmitNodeArray?.(modifiers); // partition modifiers into contiguous chunks of `Modifier` or `Decorator` let lastMode: "modifiers" | "decorators" | undefined; @@ -4779,7 +4816,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri pos++; } - onAfterEmitNodeArray?.(modifiers); + theHandlers.onAfterEmitNodeArray?.(modifiers); if (lastModifier && !positionIsSynthesized(lastModifier.end)) { return lastModifier.end; @@ -4954,8 +4991,8 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri const isEmpty = children === undefined || start >= children.length || count === 0; if (isEmpty && format & ListFormat.OptionalIfEmpty) { - onBeforeEmitNodeArray?.(children); - onAfterEmitNodeArray?.(children); + theHandlers.onBeforeEmitNodeArray?.(children); + theHandlers.onAfterEmitNodeArray?.(children); return; } @@ -4966,7 +5003,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - onBeforeEmitNodeArray?.(children); + theHandlers.onBeforeEmitNodeArray?.(children); if (isEmpty) { // Write a line terminator if the parent node was multi-line @@ -4981,7 +5018,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitNodeListItems(emit, parentNode, children, format, parenthesizerRule, start, count, children.hasTrailingComma, children); } - onAfterEmitNodeArray?.(children); + theHandlers.onAfterEmitNodeArray?.(children); if (format & ListFormat.BracketsMask) { if (isEmpty && children) { @@ -5207,12 +5244,12 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } function writeTokenNode(node: Node, writer: (s: string) => void) { - if (onBeforeEmitToken) { - onBeforeEmitToken(node); + if (theHandlers.onBeforeEmitToken) { + theHandlers.onBeforeEmitToken(node); } writer(tokenToString(node.kind)!); - if (onAfterEmitToken) { - onAfterEmitToken(node); + if (theHandlers.onAfterEmitToken) { + theHandlers.onAfterEmitToken(node); } } @@ -5754,7 +5791,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * when `isfileLevelUniqueName` is passed as a callback to `makeUniqueName`. */ function isFileLevelUniqueName(name: string, _isPrivate: boolean) { - return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, hasGlobalName) : true; + return currentSourceFile ? ts.isFileLevelUniqueName(currentSourceFile, name, theHandlers.hasGlobalName) : true; } /** diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a43afe978ea4..702969fc1183e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9160,10 +9160,10 @@ export interface Printer { * Prints a bundle of source files as-is, without any emit transformations. */ printBundle(bundle: Bundle): string; - /** @internal */ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /** @internal */ writeList(format: ListFormat, list: NodeArray | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter): void; - /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; - /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined): void; + /** @internal */ writeNode(hint: EmitHint, node: Node, sourceFile: SourceFile | undefined, writer: EmitTextWriter, handlers?: PrintHandlers): void; + /** @internal */ writeList(format: ListFormat, list: NodeArray | undefined, sourceFile: SourceFile | undefined, writer: EmitTextWriter, handlers?: PrintHandlers): void; + /** @internal */ writeFile(sourceFile: SourceFile, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers): void; + /** @internal */ writeBundle(bundle: Bundle, writer: EmitTextWriter, sourceMapGenerator: SourceMapGenerator | undefined, handlers?: PrintHandlers): void; /** @deprecated @internal */ bundleFileInfo?: BundleFileInfo; } diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index fc4280802ee6d..fafa979780fbf 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -14,7 +14,7 @@ import { ClassLikeDeclaration, ClassStaticBlockDeclaration, compareStringsCaseSensitive, - createPrinter, + createOrReusePrinter, createTextRangeFromNode, createTextSpanFromBounds, createTextSpanFromRange, @@ -245,7 +245,7 @@ function getCallHierarchyItemName(program: Program, node: CallHierarchyDeclarati } if (text === undefined) { // get the text from printing the node on a single line without comments... - const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); + const printer = createOrReusePrinter({ removeComments: true, omitTrailingSemicolon: true }); text = usingSingleLineStringWriter(writer => printer.writeNode(EmitHint.Unspecified, node, node.getSourceFile(), writer)); } return { text, pos: declName.getStart(), end: declName.getEnd() }; diff --git a/src/services/completions.ts b/src/services/completions.ts index 4193e651a037f..1c312a57dcd7f 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -34,8 +34,8 @@ import { ConstructorDeclaration, ContextFlags, createModuleSpecifierResolutionHost, + createOrReusePrinter, createPackageJsonImportFilter, - createPrinter, createSortedArray, createTextRangeFromSpan, createTextSpanFromBounds, @@ -291,7 +291,6 @@ import { positionBelongsToNode, positionIsASICandidate, positionsAreOnSameLine, - PrinterOptions, probablyUsesSemicolons, Program, programContainsModules, @@ -307,6 +306,7 @@ import { rangeContainsPosition, rangeContainsPositionExclusive, rangeIsOnSingleLine, + ReusablePrinterOptions, ScriptElementKind, ScriptElementKindModifier, ScriptTarget, @@ -1747,7 +1747,7 @@ function getEntryForObjectLiteralMethodCompletion( insertText = printer.printSnippetList(ListFormat.CommaDelimited | ListFormat.AllowTrailingComma, factory.createNodeArray([method], /*hasTrailingComma*/ true), sourceFile); } - const signaturePrinter = createPrinter({ + const signaturePrinter = createOrReusePrinter({ removeComments: true, module: options.module, target: options.target, @@ -1850,11 +1850,11 @@ function createObjectLiteralMethod( } function createSnippetPrinter( - printerOptions: PrinterOptions, + printerOptions: ReusablePrinterOptions, ) { let escapes: TextChange[] | undefined; const baseWriter = textChanges.createWriter(getNewLineCharacter(printerOptions)); - const printer = createPrinter(printerOptions, baseWriter); + const printer = createOrReusePrinter(printerOptions); const writer: EmitTextWriter = { ...baseWriter, write: s => escapingWrite(s, () => baseWriter.write(s)), @@ -1908,7 +1908,7 @@ function createSnippetPrinter( ): string { escapes = undefined; writer.clear(); - printer.writeList(format, list, sourceFile, writer); + printer.writeList(format, list, sourceFile, writer, baseWriter); return writer.getText(); } @@ -1955,7 +1955,7 @@ function createSnippetPrinter( function printUnescapedNode(hint: EmitHint, node: Node, sourceFile: SourceFile): string { escapes = undefined; writer.clear(); - printer.writeNode(hint, node, sourceFile, writer); + printer.writeNode(hint, node, sourceFile, writer, baseWriter); return writer.getText(); } diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index 5544aaa920c02..5f8d9ab7810af 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -2,7 +2,7 @@ import { __String, ArrowFunction, CallExpression, - createPrinter, + createOrReusePrinter, Debug, EmitHint, EnumMember, @@ -53,7 +53,6 @@ import { NodeBuilderFlags, ParameterDeclaration, PrefixUnaryExpression, - PrinterOptions, PropertyDeclaration, Signature, skipParentheses, @@ -383,8 +382,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { function printTypeInSingleLine(type: Type) { const flags = NodeBuilderFlags.IgnoreErrors | TypeFormatFlags.AllowUniqueESSymbolType | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope; - const options: PrinterOptions = { removeComments: true }; - const printer = createPrinter(options); + const printer = createOrReusePrinter({ removeComments: true }); return usingSingleLineStringWriter(writer => { const typeNode = checker.typeToTypeNode(type, /*enclosingDeclaration*/ undefined, flags); diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index f662021481c4c..745756503ce21 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -7,7 +7,7 @@ import { CheckFlags, contains, countWhere, - createPrinter, + createOrReusePrinter, createTextSpan, createTextSpanFromBounds, createTextSpanFromNode, @@ -659,7 +659,7 @@ function createTypeHelpItems( function getTypeHelpItem(symbol: Symbol, typeParameters: readonly TypeParameter[], checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem { const typeSymbolDisplay = symbolToDisplayParts(checker, symbol); - const printer = createPrinter({ removeComments: true }); + const printer = createOrReusePrinter({ removeComments: true }); const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); const documentation = symbol.getDocumentationComment(checker); @@ -699,7 +699,7 @@ interface SignatureHelpItemInfo { readonly isVariadic: boolean; readonly paramet function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { const typeParameters = (candidateSignature.target || candidateSignature).typeParameters; - const printer = createPrinter({ removeComments: true }); + const printer = createOrReusePrinter({ removeComments: true }); const parameters = (typeParameters || emptyArray).map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer)); const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : []; @@ -713,7 +713,7 @@ function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeC } function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] { - const printer = createPrinter({ removeComments: true }); + const printer = createOrReusePrinter({ removeComments: true }); const typeParameterParts = mapToDisplayParts(writer => { if (candidateSignature.typeParameters && candidateSignature.typeParameters.length) { const args = factory.createNodeArray(candidateSignature.typeParameters.map(p => checker.typeParameterToDeclaration(p, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)); diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index bda7ba595090c..a0a9059379d62 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -5,7 +5,7 @@ import { CallExpression, CheckFlags, contains, - createPrinter, + createOrReusePrinter, Debug, displayPart, EmitHint, @@ -75,7 +75,6 @@ import { NodeBuilderFlags, ObjectFlags, operatorPart, - Printer, PropertyAccessExpression, PropertyDeclaration, punctuationPart, @@ -259,7 +258,6 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ let hasAddedSymbolInfo = false; const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) || isThisInTypeQuery(location); let type: Type | undefined; - let printer: Printer; let documentationFromAlias: SymbolDisplayPart[] | undefined; let tagsFromAlias: JSDocTagInfo[] | undefined; let hasMultipleSignatures = false; @@ -730,10 +728,7 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ return { displayParts, documentation, symbolKind, tags: tags.length === 0 ? undefined : tags }; function getPrinter() { - if (!printer) { - printer = createPrinter({ removeComments: true }); - } - return printer; + return createOrReusePrinter({ removeComments: true }); } function prefixNextMeaning() { diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 50621f641601d..d4fea865d443d 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -11,7 +11,7 @@ import { ConstructorDeclaration, contains, createNodeFactory, - createPrinter, + createOrReusePrinter, createRange, createSourceFile, createTextChange, @@ -1301,12 +1301,12 @@ namespace changesToText { export function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } { const writer = createWriter(newLineCharacter); const newLine = getNewLineKind(newLineCharacter); - createPrinter({ + createOrReusePrinter({ newLine, neverAsciiEscape: true, preserveSourceNewlines: true, terminateUnterminatedLiterals: true - }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer); + }).writeNode(EmitHint.Unspecified, node, sourceFile, writer, writer); return { text: writer.getText(), node: assignPositionsToNode(node) }; } } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index e3de3b3014744..1a53d38f9dfea 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -30,7 +30,7 @@ import { ConditionalExpression, contains, ContextFlags, - createPrinter, + createOrReusePrinter, createRange, createScanner, createTextSpan, @@ -2984,7 +2984,7 @@ export function signatureToDisplayParts(typechecker: TypeChecker, signature: Sig export function nodeToDisplayParts(node: Node, enclosingDeclaration: Node): SymbolDisplayPart[] { const file = enclosingDeclaration.getSourceFile(); return mapToDisplayParts(writer => { - const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: true }); + const printer = createOrReusePrinter({ removeComments: true, omitTrailingSemicolon: true }); printer.writeNode(EmitHint.Unspecified, node, file, writer); }); }