From 5f531163b7264c04f60f5ba48ba14282debc316c Mon Sep 17 00:00:00 2001 From: Ben Lickly Date: Thu, 30 May 2024 15:25:00 -0700 Subject: [PATCH 1/3] Improve the performance of isolatedDeclarations quickfix It turns out that `typeChecker.getEmitResolver()` can be expensive, so avoid calling it unless necessary. Hopefully this fixes the performance issue (bullet #1) of https://github.com/microsoft/TypeScript/issues/58426 --- src/services/codefixes/fixMissingTypeAnnotationOnExports.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts b/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts index 1b2f93d06c78d..6c870687349d1 100644 --- a/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts +++ b/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts @@ -237,7 +237,6 @@ function withContext( const sourceFile: SourceFile = context.sourceFile; const program = context.program; const typeChecker: TypeChecker = program.getTypeChecker(); - const emitResolver = typeChecker.getEmitResolver(); const scriptTarget = getEmitScriptTarget(program.getCompilerOptions()); const importAdder = createImportAdder(context.sourceFile, context.program, context.preferences, context.host); const fixedNodes = new Set(); @@ -887,7 +886,7 @@ function withContext( type = widenedType; } - if (isParameter(node) && emitResolver.requiresAddingImplicitUndefined(node)) { + if (isParameter(node) && typeChecker.getEmitResolver().requiresAddingImplicitUndefined(node)) { type = typeChecker.getUnionType([typeChecker.getUndefinedType(), type], UnionReduction.None); } const flags = ( From 3acfe50e88769102d9c7e442df57b38cb1e79694 Mon Sep 17 00:00:00 2001 From: Ben Lickly Date: Thu, 30 May 2024 15:47:20 -0700 Subject: [PATCH 2/3] A few code simplificiations / corrections. These are not related to the perf issue, but I noticed them while editing this file --- .../fixMissingTypeAnnotationOnExports.ts | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts b/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts index 6c870687349d1..8fe5906f8acab 100644 --- a/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts +++ b/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts @@ -183,7 +183,7 @@ registerCodeFix({ addCodeAction(addInlineTypeAssertion, fixes, context, TypePrintMode.Full, f => f.addInlineAssertion(context.span)); addCodeAction(addInlineTypeAssertion, fixes, context, TypePrintMode.Relative, f => f.addInlineAssertion(context.span)); - addCodeAction(addAnnotationFix, fixes, context, TypePrintMode.Widened, f => f.addInlineAssertion(context.span)); + addCodeAction(addInlineTypeAssertion, fixes, context, TypePrintMode.Widened, f => f.addInlineAssertion(context.span)); addCodeAction(extractExpression, fixes, context, TypePrintMode.Full, f => f.extractAsVariable(context.span)); @@ -1107,26 +1107,26 @@ function withContext( setEmitFlags(node, EmitFlags.None); return result; } -} -// Some --isolatedDeclarations errors are not present on the node that directly needs type annotation, so look in the -// ancestors to look for node that needs type annotation. This function can return undefined if the AST is ill-formed. -function findAncestorWithMissingType(node: Node): Node | undefined { - return findAncestor(node, n => { - return canHaveTypeAnnotation.has(n.kind) && - ((!isObjectBindingPattern(n) && !isArrayBindingPattern(n)) || isVariableDeclaration(n.parent)); - }); -} - -function findBestFittingNode(node: Node, span: TextSpan) { - while (node && node.end < span.start + span.length) { - node = node.parent; - } - while (node.parent.pos === node.pos && node.parent.end === node.end) { - node = node.parent; + // Some --isolatedDeclarations errors are not present on the node that directly needs type annotation, so look in the + // ancestors to look for node that needs type annotation. This function can return undefined if the AST is ill-formed. + function findAncestorWithMissingType(node: Node): Node | undefined { + return findAncestor(node, n => { + return canHaveTypeAnnotation.has(n.kind) && + ((!isObjectBindingPattern(n) && !isArrayBindingPattern(n)) || isVariableDeclaration(n.parent)); + }); } - if (isIdentifier(node) && hasInitializer(node.parent) && node.parent.initializer) { - return node.parent.initializer; + + function findBestFittingNode(node: Node, span: TextSpan) { + while (node && node.end < span.start + span.length) { + node = node.parent; + } + while (node.parent.pos === node.pos && node.parent.end === node.end) { + node = node.parent; + } + if (isIdentifier(node) && hasInitializer(node.parent) && node.parent.initializer) { + return node.parent.initializer; + } + return node; } - return node; } From 30b84f20ae1436366e5ffaf61907915942dbcd39 Mon Sep 17 00:00:00 2001 From: Ben Lickly Date: Thu, 30 May 2024 16:07:55 -0700 Subject: [PATCH 3/3] Add missing method to checker --- src/compiler/checker.ts | 1 + src/compiler/types.ts | 1 + src/services/codefixes/fixMissingTypeAnnotationOnExports.ts | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18c3b6e1ec685..35d54c3468774 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1763,6 +1763,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { getImmediateAliasedSymbol, getAliasedSymbol: resolveAlias, getEmitResolver, + requiresAddingImplicitUndefined, getExportsOfModule: getExportsOfModuleAsArray, getExportsAndPropertiesOfModule, forEachExportAndPropertyOfModule, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4994322657070..9df1b4a8e7f31 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5265,6 +5265,7 @@ export interface TypeChecker { /** @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[]; /** @internal */ getGlobalDiagnostics(): Diagnostic[]; /** @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken, forceDts?: boolean): EmitResolver; + /** @internal */ requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag): boolean; /** @internal */ getNodeCount(): number; /** @internal */ getIdentifierCount(): number; diff --git a/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts b/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts index 8fe5906f8acab..70ceb0c31eba3 100644 --- a/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts +++ b/src/services/codefixes/fixMissingTypeAnnotationOnExports.ts @@ -886,7 +886,7 @@ function withContext( type = widenedType; } - if (isParameter(node) && typeChecker.getEmitResolver().requiresAddingImplicitUndefined(node)) { + if (isParameter(node) && typeChecker.requiresAddingImplicitUndefined(node)) { type = typeChecker.getUnionType([typeChecker.getUndefinedType(), type], UnionReduction.None); } const flags = (