From 21cfc897ea20c09894140216122229447d2b529e Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 9 Jan 2023 12:12:15 -0500 Subject: [PATCH 01/13] Move Identifier.typeArguments to EmitNode --- src/compiler/checker.ts | 51 ++++++++++++------- src/compiler/emitter.ts | 3 +- src/compiler/factory/emitNode.ts | 14 +++++ src/compiler/factory/nodeFactory.ts | 19 +++---- src/compiler/parser.ts | 6 +-- src/compiler/types.ts | 8 ++- src/compiler/visitorPublic.ts | 7 --- .../4.0/nodeFactoryTopLevelExports.ts | 2 +- 8 files changed, 64 insertions(+), 46 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8f1bf66fa63da..cac6465acabb3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -272,6 +272,7 @@ import { getFirstIdentifier, getFunctionFlags, getHostSignatureFromJSDoc, + getIdentifierTypeArguments, getImmediatelyInvokedFunctionExpression, getInitializerOfBinaryExpression, getInterfaceBaseTypeNodes, @@ -893,6 +894,7 @@ import { SetAccessorDeclaration, setCommentRange, setEmitFlags, + setIdentifierTypeArguments, setNodeFlags, setOriginalNode, setParent, @@ -6792,12 +6794,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let qualifier = root.qualifier; if (qualifier) { if (isIdentifier(qualifier)) { - qualifier = factory.updateIdentifier(qualifier, typeArguments); + if (typeArguments !== getIdentifierTypeArguments(qualifier)) { + qualifier = setIdentifierTypeArguments(factory.cloneNode(qualifier), typeArguments); + } } else { - qualifier = factory.updateQualifiedName(qualifier, - qualifier.left, - factory.updateIdentifier(qualifier.right, typeArguments)); + if (typeArguments !== getIdentifierTypeArguments(qualifier.right)) { + qualifier = factory.updateQualifiedName(qualifier, + qualifier.left, + setIdentifierTypeArguments(factory.cloneNode(qualifier.right), typeArguments)); + } } } typeArguments = ref.typeArguments; @@ -6819,12 +6825,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let typeArguments = root.typeArguments; let typeName = root.typeName; if (isIdentifier(typeName)) { - typeName = factory.updateIdentifier(typeName, typeArguments); + if (typeArguments !== getIdentifierTypeArguments(typeName)) { + typeName = setIdentifierTypeArguments(factory.cloneNode(typeName), typeArguments); + } } else { - typeName = factory.updateQualifiedName(typeName, - typeName.left, - factory.updateIdentifier(typeName.right, typeArguments)); + if (typeArguments !== getIdentifierTypeArguments(typeName.right)) { + typeName = factory.updateQualifiedName(typeName, + typeName.left, + setIdentifierTypeArguments(factory.cloneNode(typeName.right), typeArguments)); + } } typeArguments = ref.typeArguments; // then move qualifiers @@ -7542,7 +7552,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (!nonRootParts || isEntityName(nonRootParts)) { if (nonRootParts) { const lastId = isIdentifier(nonRootParts) ? nonRootParts : nonRootParts.right; - lastId.typeArguments = undefined; + setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined); } return factory.createImportTypeNode(lit, assertion, nonRootParts as EntityName, typeParameterNodes as readonly TypeNode[], isTypeOf); } @@ -7562,8 +7572,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } else { const lastId = isIdentifier(entityName) ? entityName : entityName.right; - const lastTypeArgs = lastId.typeArguments; - lastId.typeArguments = undefined; + const lastTypeArgs = getIdentifierTypeArguments(lastId); + setIdentifierTypeArguments(lastId, /*typeArguments*/ undefined); return factory.createTypeReferenceNode(entityName, lastTypeArgs as NodeArray); } @@ -7617,7 +7627,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); + if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); identifier.symbol = symbol; if (index > stopper) { @@ -7662,7 +7673,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { text = `${rawtext}_${i}`; } if (text !== rawtext) { - result = factory.createIdentifier(text, result.typeArguments); + const typeArguments = getIdentifierTypeArguments(result); + result = factory.createIdentifier(text); + setIdentifierTypeArguments(result, typeArguments); } // avoiding iterations of the above loop turns out to be worth it when `i` starts to get large, so we cache the max // `i` we've used thus far, to save work later @@ -7697,7 +7710,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.flags ^= NodeBuilderFlags.InInitialEntityName; } - const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); + if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); identifier.symbol = symbol; return index > 0 ? factory.createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; @@ -7726,7 +7740,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createStringLiteral(getSpecifierForModuleSymbol(symbol, context)); } if (index === 0 || canUsePropertyAccess(symbolName, languageVersion)) { - const identifier = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); + const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); + if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); identifier.symbol = symbol; return index > 0 ? factory.createPropertyAccessExpression(createExpressionFromSymbolChain(chain, index - 1), identifier) : identifier; @@ -7744,8 +7759,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { expression = factory.createNumericLiteral(+symbolName); } if (!expression) { - expression = setEmitFlags(factory.createIdentifier(symbolName, typeParameterNodes), EmitFlags.NoAsciiEscaping); - (expression as Identifier).symbol = symbol; + const identifier = setEmitFlags(factory.createIdentifier(symbolName), EmitFlags.NoAsciiEscaping); + if (typeParameterNodes) setIdentifierTypeArguments(identifier, factory.createNodeArray(typeParameterNodes)); + identifier.symbol = symbol; + expression = identifier; } return factory.createElementAccessExpression(createExpressionFromSymbolChain(chain, index - 1), expression); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 07474bbb2abee..a6b0476a149a4 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -148,6 +148,7 @@ import { getEmitModuleKind, getExternalHelpersModuleName, getExternalModuleName, + getIdentifierTypeArguments, getLeadingCommentRanges, getLineAndCharacterOfPosition, getLinesBetweenPositionAndNextNonWhitespaceCharacter, @@ -2478,7 +2479,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri function emitIdentifier(node: Identifier) { const writeText = node.symbol ? writeSymbol : write; writeText(getTextOfNode(node, /*includeTrivia*/ false), node.symbol); - emitList(node, node.typeArguments, ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments + emitList(node, getIdentifierTypeArguments(node), ListFormat.TypeParameters); // Call emitList directly since it could be an array of TypeParameterDeclarations _or_ type arguments } // diff --git a/src/compiler/factory/emitNode.ts b/src/compiler/factory/emitNode.ts index 1fa3027f660b4..89de601ad33cc 100644 --- a/src/compiler/factory/emitNode.ts +++ b/src/compiler/factory/emitNode.ts @@ -8,8 +8,10 @@ import { EmitNode, getParseTreeNode, getSourceFileOfNode, + Identifier, isParseTreeNode, Node, + NodeArray, orderedRemoveItem, SnippetElement, some, @@ -19,6 +21,7 @@ import { SynthesizedComment, TextRange, TypeNode, + TypeParameterDeclaration, } from "../_namespaces/ts"; /** @@ -318,3 +321,14 @@ export function setTypeNode(node: T, type: TypeNode): T { export function getTypeNode(node: T): TypeNode | undefined { return node.emitNode?.typeNode; } + +/** @internal */ +export function setIdentifierTypeArguments(node: T, typeArguments: NodeArray | undefined) { + getOrCreateEmitNode(node).identifierTypeArguments = typeArguments; + return node; +} + +/** @internal */ +export function getIdentifierTypeArguments(node: Identifier): NodeArray | undefined { + return node.emitNode?.identifierTypeArguments; +} \ No newline at end of file diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 99811f7a315f1..0ceb13ce7077d 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -116,6 +116,7 @@ import { getCommentRange, getElementsOfBindingOrAssignmentPattern, getEmitFlags, + getIdentifierTypeArguments, getJSDocTypeAliasName, getLineAndCharacterOfPosition, getNameOfDeclaration, @@ -390,6 +391,7 @@ import { SetAccessorDeclaration, setEachParent, setEmitFlags, + setIdentifierTypeArguments, setParent, setTextRange, setTextRangePosWidth, @@ -532,7 +534,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode createRegularExpressionLiteral, createLiteralLikeNode, createIdentifier, - updateIdentifier, createTempVariable, createLoopVariable, createUniqueName, @@ -1155,7 +1156,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.originalKeywordKind = originalKeywordKind; node.escapedText = escapedText; node.autoGenerate = undefined; - node.typeArguments = undefined; node.hasExtendedUnicodeEscape = undefined; node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) @@ -1177,7 +1177,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier { + function createIdentifier(text: string, originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier { if (originalKeywordKind === undefined && text) { originalKeywordKind = stringToToken(text); } @@ -1186,7 +1186,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } const node = createBaseIdentifier(escapeLeadingUnderscores(text), originalKeywordKind); - node.typeArguments = asNodeArray(typeArguments); node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape; // NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations @@ -1200,13 +1199,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode return node; } - // @api - function updateIdentifier(node: Identifier, typeArguments?: NodeArray | undefined): Identifier { - return node.typeArguments !== typeArguments - ? update(createIdentifier(idText(node), typeArguments), node) - : node; - } - // @api function createTempVariable(recordTempVariable: ((node: Identifier) => void) | undefined, reservedInNestedScopes?: boolean, prefix?: string | GeneratedNamePart, suffix?: string): GeneratedIdentifier { let flags = GeneratedIdentifierFlags.Auto; @@ -6389,7 +6381,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function cloneIdentifier(node: Identifier): Identifier { const clone = createBaseIdentifier(node.escapedText, node.originalKeywordKind); clone.flags |= node.flags & ~NodeFlags.Synthesized; - clone.typeArguments = node.typeArguments; clone.hasExtendedUnicodeEscape = node.hasExtendedUnicodeEscape; clone.jsDoc = node.jsDoc; clone.jsDocCache = node.jsDocCache; @@ -6397,6 +6388,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode clone.symbol = node.symbol; clone.transformFlags = node.transformFlags; setOriginalNode(clone, node); + + // clone type arguments for emitter/typeWriter + const typeArguments = getIdentifierTypeArguments(node); + if (typeArguments) setIdentifierTypeArguments(clone, typeArguments); return clone; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 25319bfba5bdd..f16902c69bd12 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2547,7 +2547,7 @@ namespace Parser { const pos = getNodePos(); const result = - kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*typeArguments*/ undefined, /*originalKeywordKind*/ undefined) : + kind === SyntaxKind.Identifier ? factory.createIdentifier("", /*originalKeywordKind*/ undefined) : isTemplateLiteralKind(kind) ? factory.createTemplateLiteralLikeNode(kind, "", "", /*templateFlags*/ undefined) : kind === SyntaxKind.NumericLiteral ? factory.createNumericLiteral("", /*numericLiteralFlags*/ undefined) : kind === SyntaxKind.StringLiteral ? factory.createStringLiteral("", /*isSingleQuote*/ undefined) : @@ -2576,7 +2576,7 @@ namespace Parser { const text = internIdentifier(scanner.getTokenValue()); const hasExtendedUnicodeEscape = scanner.hasExtendedUnicodeEscape(); nextTokenWithoutCheck(); - return finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind, hasExtendedUnicodeEscape), pos); + return finishNode(factory.createIdentifier(text, originalKeywordKind, hasExtendedUnicodeEscape), pos); } if (token() === SyntaxKind.PrivateIdentifier) { @@ -9477,7 +9477,7 @@ namespace Parser { const end = scanner.getTextPos(); const originalKeywordKind = token(); const text = internIdentifier(scanner.getTokenValue()); - const result = finishNode(factory.createIdentifier(text, /*typeArguments*/ undefined, originalKeywordKind), pos, end); + const result = finishNode(factory.createIdentifier(text, originalKeywordKind), pos, end); nextTokenJSDoc(); return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 44a716a516f7a..b1716f11f7719 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1008,7 +1008,6 @@ export type ForEachChildNodes = /** @internal */ export type VisitEachChildNodes = | HasChildren - | Identifier ; /** @internal */ @@ -1682,9 +1681,8 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain /** @internal */ readonly autoGenerate: AutoGenerateInfo | undefined; // Used for auto-generated identifiers. /** @internal */ generatedImportReference?: ImportSpecifier; // Reference to the generated import specifier this identifier refers to isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /** @internal */ typeArguments?: NodeArray; // Only defined on synthesized nodes. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. /** @internal */ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. - /**@internal*/ hasExtendedUnicodeEscape?: boolean; + /** @internal */ hasExtendedUnicodeEscape?: boolean; } // Transient identifier node (marked by id === -1) @@ -7828,6 +7826,7 @@ export interface EmitNode { startsOnNewLine?: boolean; // If the node should begin on a new line snippetElement?: SnippetElement; // Snippet element of the node typeNode?: TypeNode; // VariableDeclaration type + identifierTypeArguments?: NodeArray; // Only defined on synthesized identifiers. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. } /** @internal */ @@ -8126,8 +8125,7 @@ export interface NodeFactory { // createIdentifier(text: string): Identifier; - /** @internal */ createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures - /** @internal */ updateIdentifier(node: Identifier, typeArguments: NodeArray | undefined): Identifier; + /** @internal */ createIdentifier(text: string, originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier; // eslint-disable-line @typescript-eslint/unified-signatures /** * Create a unique temporary variable. diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index af0fd6e4db0ae..193fd4693f831 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -80,7 +80,6 @@ import { isToken, isTypeElement, isTypeNode, - isTypeNodeOrTypeParameterDeclaration, isTypeParameterDeclaration, isVariableDeclaration, isVariableDeclarationList, @@ -513,7 +512,6 @@ type VisitEachChildFunction = (node: T, visitor: Visitor, contex // This looks something like: // // { -// [SyntaxKind.Identifier]: VisitEachChildFunction; // [SyntaxKind.QualifiedName]: VisitEachChildFunction; // [SyntaxKind.ComputedPropertyName]: VisitEachChildFunction; // ... @@ -525,11 +523,6 @@ type VisitEachChildTable = { [TNode in VisitEachChildNodes as TNode["kind"]]: Vi // NOTE: Before you can add a new method to `visitEachChildTable`, you must first ensure the `Node` subtype you // wish to add is defined in the `HasChildren` union in types.ts. const visitEachChildTable: VisitEachChildTable = { - [SyntaxKind.Identifier]: function visitEachChildOfIdentifier(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { - return context.factory.updateIdentifier(node, - nodesVisitor(node.typeArguments, visitor, isTypeNodeOrTypeParameterDeclaration)); - }, - [SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateQualifiedName(node, nodeVisitor(node.left, visitor, isEntityName), diff --git a/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts b/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts index caca5fc914394..5b8efa635628e 100644 --- a/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts +++ b/src/deprecatedCompat/4.0/nodeFactoryTopLevelExports.ts @@ -988,7 +988,7 @@ export const createToken = deprecate(function createToken Date: Mon, 9 Jan 2023 12:44:18 -0500 Subject: [PATCH 02/13] Remove Identifier.hasExtendedUnicodeEscape --- src/compiler/binder.ts | 1 + src/compiler/factory/nodeFactory.ts | 6 ++---- src/compiler/transformers/es2015.ts | 2 +- src/compiler/types.ts | 3 ++- src/harness/harnessUtils.ts | 11 +++++++++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index fc23222eb520b..18e43e8b4b933 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1030,6 +1030,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { else if (containerFlags & ContainerFlags.IsInterface) { seenThisKeyword = false; bindChildren(node); + Debug.assertNotNode(node, isIdentifier); // ContainsThis cannot overlap with HasExtendedUnicodeEscape on Identifier node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis; } else { diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 0ceb13ce7077d..c3ff630c23478 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1156,7 +1156,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.originalKeywordKind = originalKeywordKind; node.escapedText = escapedText; node.autoGenerate = undefined; - node.hasExtendedUnicodeEscape = undefined; node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -1186,13 +1185,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } const node = createBaseIdentifier(escapeLeadingUnderscores(text), originalKeywordKind); - node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape; + if (hasExtendedUnicodeEscape) node.flags |= NodeFlags.HasExtendedUnicodeEscape; // NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) { node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait; } - if (node.hasExtendedUnicodeEscape) { + if (node.flags & NodeFlags.HasExtendedUnicodeEscape) { node.transformFlags |= TransformFlags.ContainsES2015; } @@ -6381,7 +6380,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function cloneIdentifier(node: Identifier): Identifier { const clone = createBaseIdentifier(node.escapedText, node.originalKeywordKind); clone.flags |= node.flags & ~NodeFlags.Synthesized; - clone.hasExtendedUnicodeEscape = node.hasExtendedUnicodeEscape; clone.jsDoc = node.jsDoc; clone.jsDocCache = node.jsDocCache; clone.flowNode = node.flowNode; diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index ab5ea56408a4c..558eadc829983 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -856,7 +856,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments")); } } - if (node.hasExtendedUnicodeEscape) { + if (node.flags & NodeFlags.HasExtendedUnicodeEscape) { return setOriginalNode(setTextRange( factory.createIdentifier(unescapeLeadingUnderscores(node.escapedText)), node diff --git a/src/compiler/types.ts b/src/compiler/types.ts index b1716f11f7719..afe5e7dd9e75f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -831,6 +831,8 @@ export const enum NodeFlags { // never cleared on SourceFiles which get re-used in between incremental parses. // See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`. /** @internal */ PermanentlySetIncrementalFlags = PossiblyContainsDynamicImport | PossiblyContainsImportMeta, + + /** @internal */ HasExtendedUnicodeEscape = ContainsThis, // Reuses ContainsThis value with a different meaning on Identifiers } export const enum ModifierFlags { @@ -1682,7 +1684,6 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain /** @internal */ generatedImportReference?: ImportSpecifier; // Reference to the generated import specifier this identifier refers to isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace /** @internal */ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. - /** @internal */ hasExtendedUnicodeEscape?: boolean; } // Transient identifier node (marked by id === -1) diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index 718d7de802937..5be7e3d1884c5 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -1,5 +1,6 @@ import * as ts from "./_namespaces/ts"; import * as Harness from "./_namespaces/Harness"; +import { isIdentifier } from "./_namespaces/ts"; export function encodeString(s: string): string { return ts.sys.bufferFrom!(s).toString("utf8"); @@ -189,7 +190,7 @@ export function sourceFileToJSON(file: ts.Node): string { o.containsParseError = true; } - for (const propertyName of Object.getOwnPropertyNames(n) as readonly (keyof ts.SourceFile | keyof ts.Identifier)[]) { + for (const propertyName of Object.getOwnPropertyNames(n) as readonly (keyof ts.SourceFile | keyof ts.Identifier | keyof ts.StringLiteral)[]) { switch (propertyName) { case "parent": case "symbol": @@ -219,7 +220,13 @@ export function sourceFileToJSON(file: ts.Node): string { // Clear the flags that are produced by aggregating child values. That is ephemeral // data we don't care about in the dump. We only care what the parser set directly // on the AST. - const flags = n.flags & ~(ts.NodeFlags.JavaScriptFile | ts.NodeFlags.HasAggregatedChildData); + let flags = n.flags & ~(ts.NodeFlags.JavaScriptFile | ts.NodeFlags.HasAggregatedChildData); + if (isIdentifier(n)) { + if (flags & ts.NodeFlags.HasExtendedUnicodeEscape) { + o.hasExtendedUnicodeEscape = true; + flags &= ~ts.NodeFlags.HasExtendedUnicodeEscape; + } + } if (flags) { o[propertyName] = getNodeFlagName(flags); } From a93401949baecbfe96307d54db635da474880a0b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 9 Jan 2023 13:16:05 -0500 Subject: [PATCH 03/13] Remove originalKeywordKind and jsDocCache from Identifier --- src/compiler/binder.ts | 10 ++- src/compiler/checker.ts | 23 +++--- src/compiler/factory/nodeFactory.ts | 80 ++----------------- src/compiler/parser.ts | 6 +- src/compiler/transformers/es5.ts | 4 +- src/compiler/types.ts | 8 +- src/compiler/utilities.ts | 12 ++- src/compiler/utilitiesPublic.ts | 5 +- src/services/codefixes/convertToEsModule.ts | 4 +- src/services/completions.ts | 11 ++- src/services/findAllReferences.ts | 4 +- src/services/refactors/extractSymbol.ts | 3 +- src/services/rename.ts | 2 +- src/services/textChanges.ts | 1 - ...Correctly.@@ does not start a new tag.json | 1 - ...ments.parsesCorrectly.leadingAsterisk.json | 1 - ...ly.no space before @ is not a new tag.json | 1 - ...nts.parsesCorrectly.noLeadingAsterisk.json | 1 - ...Comments.parsesCorrectly.noReturnType.json | 1 - ...ocComments.parsesCorrectly.returnTag1.json | 1 - ...ocComments.parsesCorrectly.returnTag2.json | 1 - .../DocComments.parsesCorrectly.typeTag.json | 1 - ...eExpressions.parsesCorrectly.keyword1.json | 1 - ...eExpressions.parsesCorrectly.newType1.json | 1 - ...pressions.parsesCorrectly.recordType8.json | 1 - ...Expressions.parsesCorrectly.thisType1.json | 1 - ...ssions.parsesCorrectly.typeReference3.json | 1 - 27 files changed, 62 insertions(+), 124 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 18e43e8b4b933..c9a90c4bfc141 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -283,6 +283,7 @@ import { SpreadElement, Statement, StringLiteral, + stringToToken, SuperExpression, SwitchStatement, Symbol, @@ -2421,13 +2422,14 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { !isIdentifierName(node)) { // strict mode identifiers + const originalKeywordKind = stringToToken(node.escapedText as string); if (inStrictMode && - node.originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord && - node.originalKeywordKind! <= SyntaxKind.LastFutureReservedWord) { + originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord && + originalKeywordKind! <= SyntaxKind.LastFutureReservedWord) { file.bindDiagnostics.push(createDiagnosticForNode(node, getStrictModeIdentifierMessage(node), declarationNameToString(node))); } - else if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) { + else if (originalKeywordKind === SyntaxKind.AwaitKeyword) { if (isExternalModule(file) && isInTopLevelContext(node)) { file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_at_the_top_level_of_a_module, @@ -2439,7 +2441,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { declarationNameToString(node))); } } - else if (node.originalKeywordKind === SyntaxKind.YieldKeyword && node.flags & NodeFlags.YieldContext) { + else if (originalKeywordKind === SyntaxKind.YieldKeyword && node.flags & NodeFlags.YieldContext) { file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, declarationNameToString(node))); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cac6465acabb3..85c574781018f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -925,6 +925,7 @@ import { StringLiteralLike, StringLiteralType, StringMappingType, + stringToToken, stripQuotes, StructuredType, SubstitutionType, @@ -23209,15 +23210,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { break; case SyntaxKind.Parameter: const param = declaration as ParameterDeclaration; - if (isIdentifier(param.name) && - (isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && - param.parent.parameters.indexOf(param) > -1 && - (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || - param.name.originalKeywordKind && isTypeNodeKind(param.name.originalKeywordKind))) { - const newName = "arg" + param.parent.parameters.indexOf(param); - const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); - errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); - return; + if (isIdentifier(param.name)) { + const originalKeywordKind = stringToToken(param.name.escapedText as string);1 + if ((isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && + param.parent.parameters.indexOf(param) > -1 && + (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || + originalKeywordKind && isTypeNodeKind(originalKeywordKind))) { + const newName = "arg" + param.parent.parameters.indexOf(param); + const typeName = declarationNameToString(param.name) + (param.dotDotDotToken ? "[]" : ""); + errorOrSuggestion(noImplicitAny, declaration, Diagnostics.Parameter_has_a_name_but_no_type_Did_you_mean_0_Colon_1, newName, typeName); + return; + } } diagnostic = (declaration as ParameterDeclaration).dotDotDotToken ? noImplicitAny ? Diagnostics.Rest_parameter_0_implicitly_has_an_any_type : Diagnostics.Rest_parameter_0_implicitly_has_an_any_type_but_a_better_type_may_be_inferred_from_usage : @@ -46867,7 +46870,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean { if (name.kind === SyntaxKind.Identifier) { - if (name.originalKeywordKind === SyntaxKind.LetKeyword) { + if (name.escapedText === "let") { return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations); } } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index c3ff630c23478..a1bbcf0d82d23 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1151,20 +1151,18 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode // Identifiers // - function createBaseIdentifier(escapedText: __String, originalKeywordKind: SyntaxKind | undefined) { + function createBaseIdentifier(escapedText: __String) { const node = baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as Mutable; - node.originalKeywordKind = originalKeywordKind; node.escapedText = escapedText; node.autoGenerate = undefined; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) node.symbol = undefined!; // initialized by checker return node; } function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { - const node = createBaseIdentifier(escapeLeadingUnderscores(text), /*originalKeywordKind*/ undefined) as Mutable; + const node = createBaseIdentifier(escapeLeadingUnderscores(text)) as Mutable; node.autoGenerate = { flags: autoGenerateFlags, id: nextAutoGenerateId, @@ -1184,11 +1182,11 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode originalKeywordKind = undefined; } - const node = createBaseIdentifier(escapeLeadingUnderscores(text), originalKeywordKind); + const node = createBaseIdentifier(escapeLeadingUnderscores(text)); if (hasExtendedUnicodeEscape) node.flags |= NodeFlags.HasExtendedUnicodeEscape; // NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations - if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) { + if (node.escapedText === "await") { node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait; } if (node.flags & NodeFlags.HasExtendedUnicodeEscape) { @@ -1481,7 +1479,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.expression = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -1528,7 +1525,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -1591,7 +1587,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.initializer = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -1646,7 +1641,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsClassFields; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -1688,7 +1682,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -1764,7 +1757,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -1815,7 +1807,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.modifiers = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.endFlowNode = undefined; @@ -1863,7 +1854,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.type = undefined; // initialized by parser for grammar errors node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.endFlowNode = undefined; @@ -1925,7 +1915,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeArguments = undefined; // used in quick info node.typeParameters = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -1988,7 +1977,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeParameters = undefined; // initialized by parser for grammar errors node.type = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -2034,7 +2022,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -2068,7 +2055,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -2103,7 +2089,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -2200,7 +2185,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.modifiers = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -2249,7 +2233,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -2369,7 +2352,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -2745,7 +2727,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildrenFlags(node.properties); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -2769,7 +2750,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.name) | TransformFlags.ContainsPrivateIdentifierInExpression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -2837,7 +2817,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.argumentExpression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -3046,7 +3025,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags = propagateChildFlags(node.expression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -3097,7 +3075,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3160,7 +3137,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3341,7 +3317,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -3579,7 +3554,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsES2015; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -3776,7 +3750,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildrenFlags(node.statements); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; @@ -3803,7 +3776,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -3820,7 +3792,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createEmptyStatement() { const node = createBaseNode(SyntaxKind.EmptyStatement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -3831,7 +3802,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildFlags(node.expression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -3855,7 +3825,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.elseStatement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -3879,7 +3848,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.expression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -3902,7 +3870,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -3929,7 +3896,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3958,7 +3924,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -3990,7 +3955,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode if (awaitModifier) node.transformFlags |= TransformFlags.ContainsES2018; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) @@ -4016,7 +3980,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsHoistedDeclarationOrCompletion; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4037,7 +4000,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsHoistedDeclarationOrCompletion; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4060,7 +4022,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsHoistedDeclarationOrCompletion; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4082,7 +4043,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4105,7 +4065,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.caseBlock); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) node.possiblyExhaustive = false; // initialized by binder return node; @@ -4129,7 +4088,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.statement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4149,7 +4107,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildFlags(node.expression); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4173,7 +4130,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildFlags(node.finallyBlock); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4192,7 +4148,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseNode(SyntaxKind.DebuggerStatement); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) return node; } @@ -4210,7 +4165,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode (node.exclamationToken ?? node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4294,7 +4248,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.typeArguments = undefined; // used in quick info node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.endFlowNode = undefined; @@ -4365,7 +4318,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4405,7 +4357,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4450,7 +4401,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; @@ -4498,7 +4448,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4548,7 +4497,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser for grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; @@ -4582,7 +4530,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags |= propagateChildrenFlags(node.statements); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4622,7 +4569,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser to report grammar errors node.modifiers = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4666,7 +4612,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4712,7 +4657,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4903,7 +4847,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -4948,7 +4891,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.illegalDecorators = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5005,7 +4947,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // always parsed in an Await context node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5023,7 +4964,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode const node = createBaseDeclaration(SyntaxKind.MissingDeclaration); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5109,7 +5049,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode (node.type ? TransformFlags.ContainsTypeScript : TransformFlags.None); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) node.typeArguments = undefined; // used in quick info @@ -5162,7 +5101,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.type = type; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) node.locals = undefined; // initialized by binder (LocalsContainer) node.nextContainer = undefined; // initialized by binder (LocalsContainer) return node; @@ -5799,7 +5737,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode propagateChildrenFlags(node.statements); node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5894,7 +5831,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.questionToken = undefined; // initialized by parser to report grammar errors node.exclamationToken = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5933,7 +5869,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode node.questionToken = undefined; // initialized by parser to report grammar errors node.exclamationToken = undefined; // initialized by parser to report grammar errors node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5967,7 +5902,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsObjectRestOrSpread; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -5993,7 +5927,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode TransformFlags.ContainsTypeScript; node.jsDoc = undefined; // initialized by parser (JsDocContainer) - node.jsDocCache = undefined; // initialized by parser (JsDocContainer) return node; } @@ -6369,7 +6302,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } function cloneGeneratedIdentifier(node: GeneratedIdentifier): GeneratedIdentifier { - const clone = createBaseIdentifier(node.escapedText, /*originalKeywordKind*/ undefined) as Mutable; + const clone = createBaseIdentifier(node.escapedText) as Mutable; clone.flags |= node.flags & ~NodeFlags.Synthesized; clone.autoGenerate = { ...node.autoGenerate }; clone.transformFlags = node.transformFlags; @@ -6378,10 +6311,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } function cloneIdentifier(node: Identifier): Identifier { - const clone = createBaseIdentifier(node.escapedText, node.originalKeywordKind); + const clone = createBaseIdentifier(node.escapedText); clone.flags |= node.flags & ~NodeFlags.Synthesized; clone.jsDoc = node.jsDoc; - clone.jsDocCache = node.jsDocCache; clone.flowNode = node.flowNode; clone.symbol = node.symbol; clone.transformFlags = node.transformFlags; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f16902c69bd12..9fce42ffb7fc0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3058,9 +3058,9 @@ namespace Parser { return undefined; } - if (canHaveJSDoc(node) && node.jsDocCache) { + if (canHaveJSDoc(node) && node.jsDoc?.jsDocCache) { // jsDocCache may include tags from parent nodes, which might have been modified. - node.jsDocCache = undefined; + node.jsDoc.jsDocCache = undefined; } return node; @@ -3185,7 +3185,7 @@ namespace Parser { // into an actual .ConstructorDeclaration. const methodDeclaration = node as MethodDeclaration; const nameIsConstructor = methodDeclaration.name.kind === SyntaxKind.Identifier && - methodDeclaration.name.originalKeywordKind === SyntaxKind.ConstructorKeyword; + methodDeclaration.name.escapedText === "constructor"; return !nameIsConstructor; } diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 199cfa582327e..25bc8fabb905d 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -5,7 +5,6 @@ import { Expression, getOriginalNodeId, Identifier, - idText, isIdentifier, isPrivateIdentifier, isPropertyAccessExpression, @@ -15,7 +14,6 @@ import { JsxOpeningElement, JsxSelfClosingElement, Node, - nodeIsSynthesized, PropertyAccessExpression, PropertyAssignment, setTextRange, @@ -139,7 +137,7 @@ export function transformES5(context: TransformationContext): (x: SourceFile | B * @param name An Identifier */ function trySubstituteReservedName(name: Identifier) { - const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined); + const token = stringToToken(name.escapedText as string); if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) { return setTextRange(factory.createStringLiteralFromNode(name), name); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index afe5e7dd9e75f..1413f8832a2b8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -910,8 +910,12 @@ export interface Node extends ReadonlyTextRange { export interface JSDocContainer extends Node { _jsdocContainerBrand: any; - /** @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node - /** @internal */ jsDocCache?: readonly JSDocTag[]; // Cache for getJSDocTags + /** @internal */ jsDoc?: JSDocArray; // JSDoc that directly precedes this node +} + +/** @internal */ +export interface JSDocArray extends Array { + jsDocCache?: readonly JSDocTag[]; // Cache for getJSDocTags } export interface LocalsContainer extends Node { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index d76ea0241da4c..f5cddb387787e 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4339,7 +4339,8 @@ export function isStringAKeyword(name: string) { } /** @internal */ -export function isIdentifierANonContextualKeyword({ originalKeywordKind }: Identifier): boolean { +export function isIdentifierANonContextualKeyword(node: Identifier): boolean { + const originalKeywordKind = stringToToken(node.escapedText as string); return !!originalKeywordKind && !isContextualKeyword(originalKeywordKind); } @@ -5707,7 +5708,7 @@ export function isThisInTypeQuery(node: Node): boolean { /** @internal */ export function identifierIsThisKeyword(id: Identifier): boolean { - return id.originalKeywordKind === SyntaxKind.ThisKeyword; + return id.escapedText === "this"; } /** @internal */ @@ -7325,9 +7326,14 @@ function Identifier(this: Mutable, kind: SyntaxKind, pos: number, end: num this.parent = undefined!; this.original = undefined; this.emitNode = undefined; - (this as Identifier).flowNode = undefined; } +Object.defineProperty(Identifier.prototype, "originalKeywordKind", { + get: function(this: Identifier) { + return stringToToken(this.escapedText as string); + } +}); + function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) { this.fileName = fileName; this.text = text; diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 7bb784a3a57bd..32f89790f6637 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1147,14 +1147,15 @@ export function getJSDocReturnType(node: Node): TypeNode | undefined { function getJSDocTagsWorker(node: Node, noCache?: boolean): readonly JSDocTag[] { if (!canHaveJSDoc(node)) return emptyArray; - let tags = node.jsDocCache; + let tags = node.jsDoc?.jsDocCache; // If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing. if (tags === undefined || noCache) { const comments = getJSDocCommentsAndTags(node, noCache); Debug.assert(comments.length < 2 || comments[0] !== comments[1]); tags = flatMap(comments, j => isJSDoc(j) ? j.tags : j); if (!noCache) { - node.jsDocCache = tags; + node.jsDoc ??= []; + node.jsDoc.jsDocCache = tags; } } return tags; diff --git a/src/services/codefixes/convertToEsModule.ts b/src/services/codefixes/convertToEsModule.ts index 959b9ea4538ad..cf9e673121342 100644 --- a/src/services/codefixes/convertToEsModule.ts +++ b/src/services/codefixes/convertToEsModule.ts @@ -75,6 +75,7 @@ import { SourceFile, Statement, StringLiteralLike, + stringToToken, SymbolFlags, SyntaxKind, textChanges, @@ -161,7 +162,8 @@ type ExportRenames = ReadonlyMap; function collectExportRenames(sourceFile: SourceFile, checker: TypeChecker, identifiers: Identifiers): ExportRenames { const res = new Map(); forEachExportReference(sourceFile, node => { - const { text, originalKeywordKind } = node.name; + const { text } = node.name; + const originalKeywordKind = stringToToken(text); if (!res.has(text) && (originalKeywordKind !== undefined && isNonContextualKeyword(originalKeywordKind) || checker.resolveName(text, node, SymbolFlags.Value, /*excludeGlobals*/ true))) { // Unconditionally add an underscore in case `text` is a keyword. diff --git a/src/services/completions.ts b/src/services/completions.ts index cec01139bef9d..6a64d414748c3 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -1690,8 +1690,11 @@ function isModifierLike(node: Node): ModifierSyntaxKind | undefined { if (isModifier(node)) { return node.kind; } - if (isIdentifier(node) && node.originalKeywordKind && isModifierKind(node.originalKeywordKind)) { - return node.originalKeywordKind; + if (isIdentifier(node)) { + const originalKeywordKind = stringToToken(node.escapedText as string); + if (originalKeywordKind && isModifierKind(originalKeywordKind)) { + return originalKeywordKind; + } } return undefined; } @@ -4720,7 +4723,7 @@ function isFunctionLikeBodyKeyword(kind: SyntaxKind) { } function keywordForNode(node: Node): SyntaxKind { - return isIdentifier(node) ? node.originalKeywordKind || SyntaxKind.Unknown : node.kind; + return isIdentifier(node) ? stringToToken(node.escapedText as string) || SyntaxKind.Unknown : node.kind; } function getContextualKeywords( @@ -4824,7 +4827,7 @@ function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, } break; case SyntaxKind.Identifier: { - const originalKeywordKind = (location as Identifier).originalKeywordKind; + const originalKeywordKind = stringToToken((location as Identifier).text); if (originalKeywordKind && isKeyword(originalKeywordKind)) { return undefined; } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index 01ad83b784169..e8fe0f2a71f03 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1940,8 +1940,8 @@ export namespace Core { // For `export { foo as bar }`, rename `foo`, but not `bar`. if (!isForRenameWithPrefixAndSuffixText(state.options) || alwaysGetReferences) { - const isDefaultExport = referenceLocation.originalKeywordKind === SyntaxKind.DefaultKeyword - || exportSpecifier.name.originalKeywordKind === SyntaxKind.DefaultKeyword; + const isDefaultExport = referenceLocation.escapedText === "default" + || exportSpecifier.name.escapedText === "default"; const exportKind = isDefaultExport ? ExportKind.Default : ExportKind.Named; const exportSymbol = Debug.checkDefined(exportSpecifier.symbol); const exportInfo = getExportInfo(exportSymbol, exportKind, state.checker); diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 367a685d484f1..0d53736a5f1c3 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -136,6 +136,7 @@ import { SourceFile, Statement, StringLiteral, + stringToToken, suppressLeadingAndTrailingTrivia, Symbol, SymbolFlags, @@ -1351,7 +1352,7 @@ function extractConstantInScope( // Make a unique name for the extracted variable const file = scope.getSourceFile(); - const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) && !isPrivateIdentifier(node.name) && !isKeyword(node.name.originalKeywordKind!) + const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) && !isPrivateIdentifier(node.name) && !isKeyword(stringToToken(node.name.escapedText as string) || SyntaxKind.Unknown) ? node.name.text : getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file); const isJS = isInJSFile(scope); diff --git a/src/services/rename.ts b/src/services/rename.ts index 52ee0b8a3f544..f8b6971e6b37d 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -97,7 +97,7 @@ function getRenameInfoForNode( } // Cannot rename `default` as in `import { default as foo } from "./someModule"; - if (isIdentifier(node) && node.originalKeywordKind === SyntaxKind.DefaultKeyword && symbol.parent && symbol.parent.flags & SymbolFlags.Module) { + if (isIdentifier(node) && node.escapedText === "default" && symbol.parent && symbol.parent.flags & SymbolFlags.Module) { return undefined; } diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 98a35af0fe3e0..63378707036bb 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -1147,7 +1147,6 @@ function updateJSDocHost(parent: HasJSDoc): HasJSDoc { parent.parent as HasJSDoc : parent.parent.parent as HasJSDoc; jsDocNode.jsDoc = parent.jsDoc; - jsDocNode.jsDocCache = parent.jsDocCache; return jsDocNode; } diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@@ does not start a new tag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@@ does not start a new tag.json index dca1bc102db2a..362e7f146a6ac 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@@ does not start a new tag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.@@ does not start a new tag.json @@ -27,7 +27,6 @@ "end": 18, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "ThisKeyword", "escapedText": "this" }, "isNameFirst": true, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json index 8d57b3d79ab77..3269bdc87fc04 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.leadingAsterisk.json @@ -18,7 +18,6 @@ "end": 13, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "TypeKeyword", "escapedText": "type" }, "typeExpression": { diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.no space before @ is not a new tag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.no space before @ is not a new tag.json index 64de20d9bef39..87597fad44e4c 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.no space before @ is not a new tag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.no space before @ is not a new tag.json @@ -27,7 +27,6 @@ "end": 18, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "ThisKeyword", "escapedText": "this" }, "isNameFirst": true, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json index 8d57b3d79ab77..3269bdc87fc04 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noLeadingAsterisk.json @@ -18,7 +18,6 @@ "end": 13, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "TypeKeyword", "escapedText": "type" }, "typeExpression": { diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json index ad2eea3f2d5c3..ab21f32ef9c61 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.noReturnType.json @@ -18,7 +18,6 @@ "end": 15, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "ReturnKeyword", "escapedText": "return" } }, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json index 00e574a12c499..a3abbded8b07a 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag1.json @@ -18,7 +18,6 @@ "end": 15, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "ReturnKeyword", "escapedText": "return" }, "typeExpression": { diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json index 7fb31fbd96d6a..474aa807f2be6 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.returnTag2.json @@ -18,7 +18,6 @@ "end": 15, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "ReturnKeyword", "escapedText": "return" }, "comment": "Description text follows", diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json index 8d57b3d79ab77..3269bdc87fc04 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typeTag.json @@ -18,7 +18,6 @@ "end": 13, "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "TypeKeyword", "escapedText": "type" }, "typeExpression": { diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json index 4dbd3f2959bf8..24e3d75cd7f88 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.keyword1.json @@ -12,7 +12,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "VarKeyword", "escapedText": "var" } } \ No newline at end of file diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json index 070cfdabde5dd..9e76619c596bd 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.newType1.json @@ -20,7 +20,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "NewKeyword", "escapedText": "new" }, "type": { diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json index 780a7289bd51c..5a970882d3d7f 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.recordType8.json @@ -20,7 +20,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "FunctionKeyword", "escapedText": "function" } }, diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json index 2f189e79ae3a0..a03b17581eb67 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.thisType1.json @@ -20,7 +20,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "ThisKeyword", "escapedText": "this" }, "type": { diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json index 5dde38b4c0b07..3c5435032afdb 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference3.json @@ -28,7 +28,6 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "originalKeywordKind": "FunctionKeyword", "escapedText": "function" } } From d60b06df2f5329c10e5583558fb5a994aa2a2b78 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 9 Jan 2023 13:48:22 -0500 Subject: [PATCH 04/13] Move Identifier.autoGenerate to EmitNode --- src/compiler/emitter.ts | 26 ++++++++++++---------- src/compiler/factory/emitNode.ts | 15 ++++++++++++- src/compiler/factory/nodeFactory.ts | 15 ++++++------- src/compiler/factory/utilities.ts | 13 ++++++----- src/compiler/transformers/classFields.ts | 2 +- src/compiler/transformers/module/module.ts | 2 +- src/compiler/types.ts | 7 +++--- src/compiler/utilities.ts | 2 +- src/compiler/utilitiesPublic.ts | 4 ++-- src/harness/harnessUtils.ts | 2 +- src/services/services.ts | 3 --- 11 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a6b0476a149a4..4e8bbe723efaa 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -5681,15 +5681,16 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * Generate the text for a generated identifier. */ function generateName(name: GeneratedIdentifier | GeneratedPrivateIdentifier) { - if ((name.autoGenerate.flags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) { + const autoGenerate = name.emitNode.autoGenerate; + if ((autoGenerate.flags & GeneratedIdentifierFlags.KindMask) === GeneratedIdentifierFlags.Node) { // Node names generate unique names based on their original node // and are cached based on that node's id. - return generateNameCached(getNodeForGeneratedName(name), isPrivateIdentifier(name), name.autoGenerate.flags, name.autoGenerate.prefix, name.autoGenerate.suffix); + return generateNameCached(getNodeForGeneratedName(name), isPrivateIdentifier(name), autoGenerate.flags, autoGenerate.prefix, autoGenerate.suffix); } else { // Auto, Loop, and Unique names are cached based on their unique // autoGenerateId. - const autoGenerateId = name.autoGenerate.id; + const autoGenerateId = autoGenerate.id; return autoGeneratedIdToGeneratedName[autoGenerateId] || (autoGeneratedIdToGeneratedName[autoGenerateId] = makeName(name)); } } @@ -5961,27 +5962,28 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * Generates a unique identifier for a node. */ function makeName(name: GeneratedIdentifier | GeneratedPrivateIdentifier) { - const prefix = formatGeneratedNamePart(name.autoGenerate.prefix, generateName); - const suffix = formatGeneratedNamePart (name.autoGenerate.suffix); - switch (name.autoGenerate.flags & GeneratedIdentifierFlags.KindMask) { + const autoGenerate = name.emitNode.autoGenerate; + const prefix = formatGeneratedNamePart(autoGenerate.prefix, generateName); + const suffix = formatGeneratedNamePart(autoGenerate.suffix); + switch (autoGenerate.flags & GeneratedIdentifierFlags.KindMask) { case GeneratedIdentifierFlags.Auto: - return makeTempVariableName(TempFlags.Auto, !!(name.autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, suffix); + return makeTempVariableName(TempFlags.Auto, !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, suffix); case GeneratedIdentifierFlags.Loop: Debug.assertNode(name, isIdentifier); - return makeTempVariableName(TempFlags._i, !!(name.autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), /*privateName*/ false, prefix, suffix); + return makeTempVariableName(TempFlags._i, !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), /*privateName*/ false, prefix, suffix); case GeneratedIdentifierFlags.Unique: return makeUniqueName( idText(name), - (name.autoGenerate.flags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueName : isUniqueName, - !!(name.autoGenerate.flags & GeneratedIdentifierFlags.Optimistic), - !!(name.autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), + (autoGenerate.flags & GeneratedIdentifierFlags.FileLevel) ? isFileLevelUniqueName : isUniqueName, + !!(autoGenerate.flags & GeneratedIdentifierFlags.Optimistic), + !!(autoGenerate.flags & GeneratedIdentifierFlags.ReservedInNestedScopes), isPrivateIdentifier(name), prefix, suffix ); } - return Debug.fail(`Unsupported GeneratedIdentifierKind: ${Debug.formatEnum(name.autoGenerate.flags & GeneratedIdentifierFlags.KindMask, (ts as any).GeneratedIdentifierFlags, /*isFlags*/ true)}.`); + return Debug.fail(`Unsupported GeneratedIdentifierKind: ${Debug.formatEnum(autoGenerate.flags & GeneratedIdentifierFlags.KindMask, (ts as any).GeneratedIdentifierFlags, /*isFlags*/ true)}.`); } // Comments diff --git a/src/compiler/factory/emitNode.ts b/src/compiler/factory/emitNode.ts index 89de601ad33cc..f1eaa500d497f 100644 --- a/src/compiler/factory/emitNode.ts +++ b/src/compiler/factory/emitNode.ts @@ -2,6 +2,7 @@ import { AccessExpression, append, appendIfUnique, + AutoGenerateInfo, Debug, EmitFlags, EmitHelper, @@ -13,6 +14,7 @@ import { Node, NodeArray, orderedRemoveItem, + PrivateIdentifier, SnippetElement, some, SourceFile, @@ -331,4 +333,15 @@ export function setIdentifierTypeArguments(node: T, typeAr /** @internal */ export function getIdentifierTypeArguments(node: Identifier): NodeArray | undefined { return node.emitNode?.identifierTypeArguments; -} \ No newline at end of file +} + +/** @internal */ +export function setIdentifierAutoGenerate(node: T, autoGenerate: AutoGenerateInfo | undefined) { + getOrCreateEmitNode(node).autoGenerate = autoGenerate; + return node; +} + +/** @internal */ +export function getIdentifierAutoGenerate(node: Identifier | PrivateIdentifier): AutoGenerateInfo | undefined { + return node.emitNode?.autoGenerate; +} diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index a1bbcf0d82d23..d5f58ec8348e9 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -391,6 +391,7 @@ import { SetAccessorDeclaration, setEachParent, setEmitFlags, + setIdentifierAutoGenerate, setIdentifierTypeArguments, setParent, setTextRange, @@ -1154,7 +1155,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createBaseIdentifier(escapedText: __String) { const node = baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as Mutable; node.escapedText = escapedText; - node.autoGenerate = undefined; node.jsDoc = undefined; // initialized by parser (JsDocContainer) node.flowNode = undefined; // initialized by binder (FlowContainer) node.symbol = undefined!; // initialized by checker @@ -1163,12 +1163,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { const node = createBaseIdentifier(escapeLeadingUnderscores(text)) as Mutable; - node.autoGenerate = { + setIdentifierAutoGenerate(node, { flags: autoGenerateFlags, id: nextAutoGenerateId, prefix, suffix - }; + }); nextAutoGenerateId++; return node; } @@ -1239,7 +1239,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createBasePrivateIdentifier(escapedText: __String) { const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable; node.escapedText = escapedText; - node.autoGenerate = undefined; node.transformFlags |= TransformFlags.ContainsClassFields; return node; } @@ -1252,12 +1251,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function createBaseGeneratedPrivateIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) { const node = createBasePrivateIdentifier(escapeLeadingUnderscores(text)); - node.autoGenerate = { + setIdentifierAutoGenerate(node, { flags: autoGenerateFlags, id: nextAutoGenerateId, prefix, suffix, - }; + }); nextAutoGenerateId++; return node; } @@ -6304,9 +6303,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function cloneGeneratedIdentifier(node: GeneratedIdentifier): GeneratedIdentifier { const clone = createBaseIdentifier(node.escapedText) as Mutable; clone.flags |= node.flags & ~NodeFlags.Synthesized; - clone.autoGenerate = { ...node.autoGenerate }; clone.transformFlags = node.transformFlags; setOriginalNode(clone, node); + setIdentifierAutoGenerate(clone, { ...node.emitNode.autoGenerate }); return clone; } @@ -6328,9 +6327,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode function cloneGeneratedPrivateIdentifier(node: GeneratedPrivateIdentifier): GeneratedPrivateIdentifier { const clone = createBasePrivateIdentifier(node.escapedText) as Mutable; clone.flags |= node.flags & ~NodeFlags.Synthesized; - clone.autoGenerate = { ...node.autoGenerate }; clone.transformFlags = node.transformFlags; setOriginalNode(clone, node); + setIdentifierAutoGenerate(clone, { ...node.emitNode.autoGenerate }); return clone; } diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 40075da95e036..91823cef7cc1b 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -1489,18 +1489,19 @@ export function elideNodes(factory: NodeFactory, nodes: NodeArra * @internal */ export function getNodeForGeneratedName(name: GeneratedIdentifier | GeneratedPrivateIdentifier) { - if (name.autoGenerate.flags & GeneratedIdentifierFlags.Node) { - const autoGenerateId = name.autoGenerate.id; + const autoGenerate = name.emitNode.autoGenerate; + if (autoGenerate.flags & GeneratedIdentifierFlags.Node) { + const autoGenerateId = autoGenerate.id; let node = name as Node; let original = node.original; while (original) { node = original; - + const autoGenerate = node.emitNode?.autoGenerate; // if "node" is a different generated name (having a different "autoGenerateId"), use it and stop traversing. if (isMemberName(node) && ( - node.autoGenerate === undefined || - !!(node.autoGenerate.flags & GeneratedIdentifierFlags.Node) && - node.autoGenerate.id !== autoGenerateId)) { + autoGenerate === undefined || + !!(autoGenerate.flags & GeneratedIdentifierFlags.Node) && + autoGenerate.id !== autoGenerateId)) { break; } diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index 9ef101538df6a..c299f16f2a24a 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -1553,7 +1553,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // record an alias as the class name is not in scope for statics. enableSubstitutionForClassAliases(); const alias = factory.cloneNode(temp) as GeneratedIdentifier; - alias.autoGenerate.flags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; + alias.emitNode.autoGenerate.flags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes; classAliases[getOriginalNodeId(node)] = alias; } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 0a0a1473ade2a..ac9fa5aa134d3 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -2064,7 +2064,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile } return node; } - else if (!(isGeneratedIdentifier(node) && !(node.autoGenerate.flags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) { + else if (!(isGeneratedIdentifier(node) && !(node.emitNode.autoGenerate.flags & GeneratedIdentifierFlags.AllowNameSubstitution)) && !isLocalName(node)) { const exportContainer = resolver.getReferencedExportContainer(node, isExportName(node)); if (exportContainer && exportContainer.kind === SyntaxKind.SourceFile) { return setTextRange( diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1413f8832a2b8..2ff3e0379bcb7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1684,7 +1684,6 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain */ readonly escapedText: __String; readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later - /** @internal */ readonly autoGenerate: AutoGenerateInfo | undefined; // Used for auto-generated identifiers. /** @internal */ generatedImportReference?: ImportSpecifier; // Reference to the generated import specifier this identifier refers to isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace /** @internal */ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. @@ -1705,7 +1704,7 @@ export interface AutoGenerateInfo { /** @internal */ export interface GeneratedIdentifier extends Identifier { - readonly autoGenerate: AutoGenerateInfo; + readonly emitNode: EmitNode & { autoGenerate: AutoGenerateInfo; }; } export interface QualifiedName extends Node, FlowContainer { @@ -1783,12 +1782,11 @@ export interface PrivateIdentifier extends PrimaryExpression { // escaping not strictly necessary // avoids gotchas in transforms and utils readonly escapedText: __String; - /** @internal */ readonly autoGenerate: AutoGenerateInfo | undefined; // Used for auto-generated identifiers. } /** @internal */ export interface GeneratedPrivateIdentifier extends PrivateIdentifier { - readonly autoGenerate: AutoGenerateInfo; + readonly emitNode: EmitNode & { autoGenerate: AutoGenerateInfo }; } /** @internal */ @@ -7832,6 +7830,7 @@ export interface EmitNode { snippetElement?: SnippetElement; // Snippet element of the node typeNode?: TypeNode; // VariableDeclaration type identifierTypeArguments?: NodeArray; // Only defined on synthesized identifiers. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. + autoGenerate: AutoGenerateInfo | undefined; // Used for auto-generated identifiers and private identifiers. } /** @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f5cddb387787e..5e751c6d24d20 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1649,7 +1649,7 @@ export function tryGetTextOfPropertyName(name: PropertyName | NoSubstitutionTemp switch (name.kind) { case SyntaxKind.Identifier: case SyntaxKind.PrivateIdentifier: - return name.autoGenerate ? undefined : name.escapedText; + return name.emitNode?.autoGenerate ? undefined : name.escapedText; case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 32f89790f6637..bfa53e8a93e48 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -1476,12 +1476,12 @@ export function isStringTextContainingNode(node: Node): node is StringLiteral | /** @internal */ export function isGeneratedIdentifier(node: Node): node is GeneratedIdentifier { - return isIdentifier(node) && node.autoGenerate !== undefined; + return isIdentifier(node) && node.emitNode?.autoGenerate !== undefined; } /** @internal */ export function isGeneratedPrivateIdentifier(node: Node): node is GeneratedPrivateIdentifier { - return isPrivateIdentifier(node) && node.autoGenerate !== undefined; + return isPrivateIdentifier(node) && node.emitNode?.autoGenerate !== undefined; } // Private Identifiers diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index 5be7e3d1884c5..7a15b4944e66a 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -202,7 +202,7 @@ export function sourceFileToJSON(file: ts.Node): string { case "symbolCount": case "identifierCount": case "scriptSnapshot": - case "autoGenerate": + case "emitNode": // Blocklist of items we never put in the baseline file. break; diff --git a/src/services/services.ts b/src/services/services.ts index e36785bc33ca1..f5d2f51cd3e98 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6,7 +6,6 @@ import { ApplicableRefactorInfo, ApplyCodeActionCommandResult, AssignmentDeclarationKind, - AutoGenerateInfo, BaseType, BinaryExpression, BreakpointResolver, @@ -734,7 +733,6 @@ class TokenObject extends TokenOrIdentifierObject impl class IdentifierObject extends TokenOrIdentifierObject implements Identifier { public kind: SyntaxKind.Identifier = SyntaxKind.Identifier; public escapedText!: __String; - public autoGenerate: AutoGenerateInfo | undefined; declare _primaryExpressionBrand: any; declare _memberExpressionBrand: any; declare _leftHandSideExpressionBrand: any; @@ -757,7 +755,6 @@ IdentifierObject.prototype.kind = SyntaxKind.Identifier; class PrivateIdentifierObject extends TokenOrIdentifierObject implements PrivateIdentifier { public kind: SyntaxKind.PrivateIdentifier = SyntaxKind.PrivateIdentifier; public escapedText!: __String; - public autoGenerate: AutoGenerateInfo | undefined; declare _primaryExpressionBrand: any; declare _memberExpressionBrand: any; declare _leftHandSideExpressionBrand: any; From 3a063120fe786f92aa76ef57a7c19e2a89fa3d21 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 9 Jan 2023 13:59:28 -0500 Subject: [PATCH 05/13] Fix lint errors --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85c574781018f..c581c6c6bc068 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23211,7 +23211,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Parameter: const param = declaration as ParameterDeclaration; if (isIdentifier(param.name)) { - const originalKeywordKind = stringToToken(param.name.escapedText as string);1 + const originalKeywordKind = stringToToken(param.name.escapedText as string); if ((isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && param.parent.parameters.indexOf(param) > -1 && (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 5e751c6d24d20..c3a85d888ea87 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7329,7 +7329,7 @@ function Identifier(this: Mutable, kind: SyntaxKind, pos: number, end: num } Object.defineProperty(Identifier.prototype, "originalKeywordKind", { - get: function(this: Identifier) { + get(this: Identifier) { return stringToToken(this.escapedText as string); } }); From 9f1f27f8bcbe7ecafd68eec268f40e867e6e3f8b Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Jan 2023 12:54:15 -0500 Subject: [PATCH 06/13] Move Identifier.generatedImportReference to EmitNode --- src/compiler/checker.ts | 6 ++++-- src/compiler/factory/emitNode.ts | 12 ++++++++++++ src/compiler/transformers/jsx.ts | 3 ++- src/compiler/types.ts | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c581c6c6bc068..c1e493a6154cf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -272,6 +272,7 @@ import { getFirstIdentifier, getFunctionFlags, getHostSignatureFromJSDoc, + getIdentifierGeneratedImportReference, getIdentifierTypeArguments, getImmediatelyInvokedFunctionExpression, getInitializerOfBinaryExpression, @@ -44598,8 +44599,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // When resolved as an expression identifier, if the given node references an import, return the declaration of // that import. Otherwise, return undefined. function getReferencedImportDeclaration(nodeIn: Identifier): Declaration | undefined { - if (nodeIn.generatedImportReference) { - return nodeIn.generatedImportReference; + const specifier = getIdentifierGeneratedImportReference(nodeIn); + if (specifier) { + return specifier; } const node = getParseTreeNode(nodeIn, isIdentifier); if (node) { diff --git a/src/compiler/factory/emitNode.ts b/src/compiler/factory/emitNode.ts index f1eaa500d497f..0a7964b1bd8ea 100644 --- a/src/compiler/factory/emitNode.ts +++ b/src/compiler/factory/emitNode.ts @@ -10,6 +10,7 @@ import { getParseTreeNode, getSourceFileOfNode, Identifier, + ImportSpecifier, isParseTreeNode, Node, NodeArray, @@ -345,3 +346,14 @@ export function setIdentifierAutoGenerate(node: T, value: ImportSpecifier | undefined) { + getOrCreateEmitNode(node).generatedImportReference = value; + return node; +} + +/** @internal */ +export function getIdentifierGeneratedImportReference(node: Identifier | PrivateIdentifier): ImportSpecifier | undefined { + return node.emitNode?.generatedImportReference; +} diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 572ed1c594eac..2dc169b2d9a4b 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -57,6 +57,7 @@ import { NodeFlags, PropertyAssignment, ScriptTarget, + setIdentifierGeneratedImportReference, setParentRecursive, setTextRange, singleOrUndefined, @@ -135,7 +136,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B } const generatedName = factory.createUniqueName(`_${name}`, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.AllowNameSubstitution); const specifier = factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier(name), generatedName); - generatedName.generatedImportReference = specifier; + setIdentifierGeneratedImportReference(generatedName, specifier); specifierSourceImports.set(name, specifier); return generatedName; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2ff3e0379bcb7..f86bd95f47640 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1684,7 +1684,6 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain */ readonly escapedText: __String; readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later - /** @internal */ generatedImportReference?: ImportSpecifier; // Reference to the generated import specifier this identifier refers to isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace /** @internal */ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. } @@ -7831,6 +7830,7 @@ export interface EmitNode { typeNode?: TypeNode; // VariableDeclaration type identifierTypeArguments?: NodeArray; // Only defined on synthesized identifiers. Though not syntactically valid, used in emitting diagnostics, quickinfo, and signature help. autoGenerate: AutoGenerateInfo | undefined; // Used for auto-generated identifiers and private identifiers. + generatedImportReference?: ImportSpecifier; // Reference to the generated import specifier this identifier refers to } /** @internal */ From 71eb941839af9ebb1fb81b1133d828e925f0a518 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Jan 2023 14:21:49 -0500 Subject: [PATCH 07/13] Remove jsdocDotPos --- src/compiler/checker.ts | 9 +++++++-- src/compiler/parser.ts | 6 ++---- src/compiler/types.ts | 2 -- src/compiler/utilities.ts | 7 +++++++ .../TypeExpressions.parsesCorrectly.typeReference1.json | 3 +-- .../TypeExpressions.parsesCorrectly.typeReference2.json | 3 +-- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c1e493a6154cf..bf3b1c2935bb8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -890,6 +890,7 @@ import { ReverseMappedType, sameMap, SatisfiesExpression, + scanTokenAtPosition, ScriptKind, ScriptTarget, SetAccessorDeclaration, @@ -37463,8 +37464,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) { checkGrammarTypeArguments(node, node.typeArguments); - if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) && !isInJSDoc(node)) { - grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); + if (node.kind === SyntaxKind.TypeReference && !isInJSFile(node) && !isInJSDoc(node) && node.typeArguments && node.typeName.end !== node.typeArguments.pos) { + // If there was a token between the type name and the type arguments, check if it was a DotToken + const sourceFile = getSourceFileOfNode(node); + if (scanTokenAtPosition(sourceFile, node.typeName.end) === SyntaxKind.DotToken) { + grammarErrorAtPos(node, skipTrivia(sourceFile.text, node.typeName.end), 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments); + } } forEach(node.typeArguments, checkSourceElement); const type = getTypeFromTypeReference(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 9fce42ffb7fc0..d554e145da38a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3452,14 +3452,12 @@ namespace Parser { function parseEntityName(allowReservedWords: boolean, diagnosticMessage?: DiagnosticMessage): EntityName { const pos = getNodePos(); let entity: EntityName = allowReservedWords ? parseIdentifierName(diagnosticMessage) : parseIdentifier(diagnosticMessage); - let dotPos = getNodePos(); while (parseOptional(SyntaxKind.DotToken)) { if (token() === SyntaxKind.LessThanToken) { - // the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting - entity.jsdocDotPos = dotPos; + // The entity is part of a JSDoc-style generic. We will use the gap between `typeName` and + // `typeArguments` to report it as a grammar error in the checker. break; } - dotPos = getNodePos(); entity = finishNode( factory.createQualifiedName( entity, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f86bd95f47640..001d7a2798633 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1685,7 +1685,6 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain readonly escapedText: __String; readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace - /** @internal */ jsdocDotPos?: number; // Identifier occurs in JSDoc-style generic: Id. } // Transient identifier node (marked by id === -1) @@ -1710,7 +1709,6 @@ export interface QualifiedName extends Node, FlowContainer { readonly kind: SyntaxKind.QualifiedName; readonly left: EntityName; readonly right: Identifier; - /** @internal */ jsdocDotPos?: number; // QualifiedName occurs in JSDoc-style generic: Id1.Id2. } export type EntityName = Identifier | QualifiedName; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c3a85d888ea87..c331b97f2c65c 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1783,6 +1783,13 @@ export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): T return createTextSpanFromBounds(start, scanner.getTextPos()); } +/** @internal */ +export function scanTokenAtPosition(sourceFile: SourceFile, pos: number) { + const scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.languageVariant, sourceFile.text, /*onError:*/ undefined, pos); + scanner.scan(); + return scanner.getToken(); +} + function getErrorSpanForArrowFunction(sourceFile: SourceFile, node: ArrowFunction): TextSpan { const pos = skipTrivia(sourceFile.text, node.pos); if (node.body && node.body.kind === SyntaxKind.Block) { diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json index cfbef060a8516..b1778ff786534 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference1.json @@ -12,8 +12,7 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "escapedText": "a", - "jsdocDotPos": 2 + "escapedText": "a" }, "typeArguments": { "0": { diff --git a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json index 3802cb3212932..8ac51a4783083 100644 --- a/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json +++ b/tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.typeReference2.json @@ -12,8 +12,7 @@ "flags": "JSDoc", "modifierFlagsCache": 0, "transformFlags": 0, - "escapedText": "a", - "jsdocDotPos": 2 + "escapedText": "a" }, "typeArguments": { "0": { From 0e60f983ffacdd8792c0670cb360a9d49bfbaf56 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Jan 2023 14:39:12 -0500 Subject: [PATCH 08/13] Remove 'Identifier.isInJSDocNamespace' --- src/compiler/binder.ts | 4 ++-- src/compiler/factory/nodeFactory.ts | 4 ++-- src/compiler/parser.ts | 2 +- src/compiler/transformers/es2015.ts | 2 +- src/compiler/types.ts | 7 +++++-- src/compiler/utilities.ts | 16 ++++++++++++---- src/harness/harnessUtils.ts | 4 ++-- .../baselines/reference/api/tsserverlibrary.d.ts | 2 +- tests/baselines/reference/api/typescript.d.ts | 2 +- 9 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c9a90c4bfc141..8b11dad3d197f 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -414,7 +414,7 @@ function getModuleInstanceStateWorker(node: Node, visited: Map void { // for typedef type names with namespaces, bind the new jsdoc type symbol here // because it requires all containing namespaces to be in effect, namely the // current "blockScopeContainer" needs to be set to its immediate namespace parent. - if ((node as Identifier).isInJSDocNamespace) { + if (node.flags & NodeFlags.IdentifierIsInJSDocNamespace) { let parentNode = node.parent; while (parentNode && !isJSDocTypeAlias(parentNode)) { parentNode = parentNode.parent; diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index d5f58ec8348e9..739d47e707a91 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1183,13 +1183,13 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } const node = createBaseIdentifier(escapeLeadingUnderscores(text)); - if (hasExtendedUnicodeEscape) node.flags |= NodeFlags.HasExtendedUnicodeEscape; + if (hasExtendedUnicodeEscape) node.flags |= NodeFlags.IdentifierHasExtendedUnicodeEscape; // NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations if (node.escapedText === "await") { node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait; } - if (node.flags & NodeFlags.HasExtendedUnicodeEscape) { + if (node.flags & NodeFlags.IdentifierHasExtendedUnicodeEscape) { node.transformFlags |= TransformFlags.ContainsES2015; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index d554e145da38a..cdaa764143a34 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9252,7 +9252,7 @@ namespace Parser { } if (nested) { - typeNameOrNamespaceName.isInJSDocNamespace = true; + (typeNameOrNamespaceName as Mutable).flags |= NodeFlags.IdentifierIsInJSDocNamespace; } return typeNameOrNamespaceName; } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 558eadc829983..85acbeb46ef0a 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -856,7 +856,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = factory.createUniqueName("arguments")); } } - if (node.flags & NodeFlags.HasExtendedUnicodeEscape) { + if (node.flags & NodeFlags.IdentifierHasExtendedUnicodeEscape) { return setOriginalNode(setTextRange( factory.createIdentifier(unescapeLeadingUnderscores(node.escapedText)), node diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 001d7a2798633..52c467ec67183 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -832,7 +832,9 @@ export const enum NodeFlags { // See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`. /** @internal */ PermanentlySetIncrementalFlags = PossiblyContainsDynamicImport | PossiblyContainsImportMeta, - /** @internal */ HasExtendedUnicodeEscape = ContainsThis, // Reuses ContainsThis value with a different meaning on Identifiers + // The following flags repurpose other NodeFlags as different meanings for Identifier nodes + /** @internal */ IdentifierHasExtendedUnicodeEscape = ContainsThis, // Indicates whether the identifier contains an extended unicode escape sequence + IdentifierIsInJSDocNamespace = HasAsyncFunctions, // Indicates whether the identifier is part of a JSDoc namespace } export const enum ModifierFlags { @@ -1684,7 +1686,8 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain */ readonly escapedText: __String; readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later - isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace + /** @deprecated Use `node.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ + readonly isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace. } // Transient identifier node (marked by id === -1) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c331b97f2c65c..cec1f6819c79d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -6200,7 +6200,7 @@ export function getEffectiveModifierFlagsNoCache(node: Node): ModifierFlags { */ export function getSyntacticModifierFlagsNoCache(node: Node): ModifierFlags { let flags = canHaveModifiers(node) ? modifiersToFlags(node.modifiers) : ModifierFlags.None; - if (node.flags & NodeFlags.NestedNamespace || (node.kind === SyntaxKind.Identifier && (node as Identifier).isInJSDocNamespace)) { + if (node.flags & NodeFlags.NestedNamespace || node.kind === SyntaxKind.Identifier && node.flags & NodeFlags.IdentifierIsInJSDocNamespace) { flags |= ModifierFlags.Export; } return flags; @@ -7335,9 +7335,17 @@ function Identifier(this: Mutable, kind: SyntaxKind, pos: number, end: num this.emitNode = undefined; } -Object.defineProperty(Identifier.prototype, "originalKeywordKind", { - get(this: Identifier) { - return stringToToken(this.escapedText as string); +Object.defineProperties(Identifier.prototype, { + originalKeywordKind: { + get(this: Identifier) { + return stringToToken(this.escapedText as string); + } + }, + isInJSDocNamespace: { + get(this: Identifier) { + // NOTE: Returns `true` or `undefined` to match previous possible values. + return this.flags & NodeFlags.IdentifierIsInJSDocNamespace ? true : undefined; + } } }); diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index 7a15b4944e66a..6f985e2ed552d 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -222,9 +222,9 @@ export function sourceFileToJSON(file: ts.Node): string { // on the AST. let flags = n.flags & ~(ts.NodeFlags.JavaScriptFile | ts.NodeFlags.HasAggregatedChildData); if (isIdentifier(n)) { - if (flags & ts.NodeFlags.HasExtendedUnicodeEscape) { + if (flags & ts.NodeFlags.IdentifierHasExtendedUnicodeEscape) { o.hasExtendedUnicodeEscape = true; - flags &= ~ts.NodeFlags.HasExtendedUnicodeEscape; + flags &= ~ts.NodeFlags.IdentifierHasExtendedUnicodeEscape; } } if (flags) { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 44e2e6143aba9..62c80606e7204 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4585,7 +4585,7 @@ declare namespace ts { */ readonly escapedText: __String; readonly originalKeywordKind?: SyntaxKind; - isInJSDocNamespace?: boolean; + /** @deprecated */ readonly isInJSDocNamespace?: boolean; } interface Identifier { readonly text: string; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e29bb395fe5f4..3ee7b5c34b039 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -650,7 +650,7 @@ declare namespace ts { */ readonly escapedText: __String; readonly originalKeywordKind?: SyntaxKind; - isInJSDocNamespace?: boolean; + /** @deprecated */ readonly isInJSDocNamespace?: boolean; } interface Identifier { readonly text: string; From a989cfdb4aee8c5e15f8bb4df84d104a404967ff Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Jan 2023 15:16:58 -0500 Subject: [PATCH 09/13] Deprecate originalKeywordKind and isInJSDocNamespace --- src/compiler/types.ts | 7 ++-- src/compiler/utilities.ts | 12 +++++++ src/compiler/utilitiesPublic.ts | 10 ++++++ .../5.0/identifierProperties.ts | 36 +++++++++++++++++++ src/deprecatedCompat/_namespaces/ts.ts | 1 + src/deprecatedCompat/deprecate.ts | 2 +- 6 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/deprecatedCompat/5.0/identifierProperties.ts diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 52c467ec67183..ac9f2352909da 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1685,9 +1685,10 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain * Text of identifier, but if the identifier begins with two underscores, this will begin with three. */ readonly escapedText: __String; - readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later - /** @deprecated Use `node.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ - readonly isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace. + /** @deprecated Use `idKeyword(identifier)` instead. */ + readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later + /** @deprecated Use `identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ + readonly isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace. } // Transient identifier node (marked by id === -1) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cec1f6819c79d..4c9319f4c100a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -7369,9 +7369,21 @@ export const objectAllocator: ObjectAllocator = { getSourceMapSourceConstructor: () => SourceMapSource as any, }; +const objectAllocatorPatchers: ((objectAllocator: ObjectAllocator) => void)[] = []; + +/** + * Used by `deprecatedCompat` to patch the object allocator to apply deprecations. + * @internal + */ +export function addObjectAllocatorPatcher(fn: (objectAllocator: ObjectAllocator) => void) { + objectAllocatorPatchers.push(fn); + fn(objectAllocator); +} + /** @internal */ export function setObjectAllocator(alloc: ObjectAllocator) { Object.assign(objectAllocator, alloc); + forEach(objectAllocatorPatchers, fn => fn(objectAllocator)); } /** @internal */ diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index bfa53e8a93e48..a12b5e5429028 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -249,6 +249,7 @@ import { Statement, StringLiteral, StringLiteralLike, + stringToToken, Symbol, SyntaxKind, TemplateLiteral, @@ -761,6 +762,15 @@ export function unescapeLeadingUnderscores(identifier: __String): string { export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string { return unescapeLeadingUnderscores(identifierOrPrivateName.escapedText); } + +/** + * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the + * SyntaxKind for the matching keyword. + */ +export function idKeyword(node: Identifier) { + return stringToToken(node.escapedText as string); +} + export function symbolName(symbol: Symbol): string { if (symbol.valueDeclaration && isPrivateIdentifierClassElementDeclaration(symbol.valueDeclaration)) { return idText(symbol.valueDeclaration.name); diff --git a/src/deprecatedCompat/5.0/identifierProperties.ts b/src/deprecatedCompat/5.0/identifierProperties.ts new file mode 100644 index 0000000000000..362955e10922a --- /dev/null +++ b/src/deprecatedCompat/5.0/identifierProperties.ts @@ -0,0 +1,36 @@ +import { Identifier, NodeFlags, addObjectAllocatorPatcher, idKeyword } from "../_namespaces/ts"; +import { deprecate } from "../deprecate"; + +addObjectAllocatorPatcher(objectAllocator => { + const Identifier = objectAllocator.getIdentifierConstructor(); + + const propertyNames = Object.getOwnPropertyNames(Identifier.prototype); + if (!propertyNames.includes("originalKeywordKind")) { + Object.defineProperty(Identifier.prototype, "originalKeywordKind", { + get: deprecate(function(this: Identifier) { + return idKeyword(this); + }, { + name: "originalKeywordKind", + since: "5.0", + warnAfter: "5.1", + errorAfter: "5.2", + message: "Use 'idKeyword(identifier)' instead." + }) + }); + } + + if (!propertyNames.includes("isInJSDocNamespace")) { + Object.defineProperty(Identifier.prototype, "isInJSDocNamespace", { + get: deprecate(function (this: Identifier) { + // NOTE: Returns `true` or `undefined` to match previous possible values. + return this.flags & NodeFlags.IdentifierIsInJSDocNamespace ? true : undefined; + }, { + name: "isInJSDocNamespace", + since: "5.0", + warnAfter: "5.1", + errorAfter: "5.2", + message: "Use 'identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace' instead." + }) + }); + } +}); diff --git a/src/deprecatedCompat/_namespaces/ts.ts b/src/deprecatedCompat/_namespaces/ts.ts index 89b1e1729cf21..e74bb6da37216 100644 --- a/src/deprecatedCompat/_namespaces/ts.ts +++ b/src/deprecatedCompat/_namespaces/ts.ts @@ -9,3 +9,4 @@ export * from "../4.2/abstractConstructorTypes"; export * from "../4.6/importTypeAssertions"; export * from "../4.7/typeParameterModifiers"; export * from "../4.8/mergeDecoratorsAndModifiers"; +export * from "../5.0/identifierProperties"; diff --git a/src/deprecatedCompat/deprecate.ts b/src/deprecatedCompat/deprecate.ts index c56abe2df1ef2..e7db9ef07f3cd 100644 --- a/src/deprecatedCompat/deprecate.ts +++ b/src/deprecatedCompat/deprecate.ts @@ -52,7 +52,7 @@ export function createDeprecation(name: string, options: DeprecationOptions = {} const errorAfter = typeof options.errorAfter === "string" ? new Version(options.errorAfter) : options.errorAfter; const warnAfter = typeof options.warnAfter === "string" ? new Version(options.warnAfter) : options.warnAfter; const since = typeof options.since === "string" ? new Version(options.since) : options.since ?? warnAfter; - const error = options.error || errorAfter && version.compareTo(errorAfter) <= 0; + const error = options.error || errorAfter && version.compareTo(errorAfter) >= 0; const warn = !warnAfter || version.compareTo(warnAfter) >= 0; return error ? createErrorDeprecation(name, errorAfter, since, options.message) : warn ? createWarningDeprecation(name, errorAfter, since, options.message) : From 65b9f7017c1be8426b42c0b53a4870183d719cf9 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Jan 2023 15:19:07 -0500 Subject: [PATCH 10/13] Update API baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 12 ++++++++++-- tests/baselines/reference/api/typescript.d.ts | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 62c80606e7204..a29297ef1590e 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4414,7 +4414,8 @@ declare namespace ts { ReachabilityCheckFlags = 768, ReachabilityAndEmitFlags = 2816, ContextFlags = 50720768, - TypeExcludesFlags = 40960 + TypeExcludesFlags = 40960, + IdentifierIsInJSDocNamespace = 2048 } enum ModifierFlags { None = 0, @@ -4584,8 +4585,10 @@ declare namespace ts { * Text of identifier, but if the identifier begins with two underscores, this will begin with three. */ readonly escapedText: __String; + /** @deprecated Use `idKeyword(identifier)` instead. */ readonly originalKeywordKind?: SyntaxKind; - /** @deprecated */ readonly isInJSDocNamespace?: boolean; + /** @deprecated Use `identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ + readonly isInJSDocNamespace?: boolean; } interface Identifier { readonly text: string; @@ -8598,6 +8601,11 @@ declare namespace ts { */ function unescapeLeadingUnderscores(identifier: __String): string; function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string; + /** + * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the + * SyntaxKind for the matching keyword. + */ + function idKeyword(node: Identifier): SyntaxKind | undefined; function symbolName(symbol: Symbol): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined; function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 3ee7b5c34b039..e014912161bff 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -479,7 +479,8 @@ declare namespace ts { ReachabilityCheckFlags = 768, ReachabilityAndEmitFlags = 2816, ContextFlags = 50720768, - TypeExcludesFlags = 40960 + TypeExcludesFlags = 40960, + IdentifierIsInJSDocNamespace = 2048 } enum ModifierFlags { None = 0, @@ -649,8 +650,10 @@ declare namespace ts { * Text of identifier, but if the identifier begins with two underscores, this will begin with three. */ readonly escapedText: __String; + /** @deprecated Use `idKeyword(identifier)` instead. */ readonly originalKeywordKind?: SyntaxKind; - /** @deprecated */ readonly isInJSDocNamespace?: boolean; + /** @deprecated Use `identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ + readonly isInJSDocNamespace?: boolean; } interface Identifier { readonly text: string; @@ -4663,6 +4666,11 @@ declare namespace ts { */ function unescapeLeadingUnderscores(identifier: __String): string; function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): string; + /** + * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the + * SyntaxKind for the matching keyword. + */ + function idKeyword(node: Identifier): SyntaxKind | undefined; function symbolName(symbol: Symbol): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined; function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined; From 45ebecfc8ff4f7f1ab845dd2d702eda5271129c6 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 10 Jan 2023 15:20:29 -0500 Subject: [PATCH 11/13] Lint fixes --- src/deprecatedCompat/5.0/identifierProperties.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/deprecatedCompat/5.0/identifierProperties.ts b/src/deprecatedCompat/5.0/identifierProperties.ts index 362955e10922a..78ba8009c004e 100644 --- a/src/deprecatedCompat/5.0/identifierProperties.ts +++ b/src/deprecatedCompat/5.0/identifierProperties.ts @@ -1,4 +1,9 @@ -import { Identifier, NodeFlags, addObjectAllocatorPatcher, idKeyword } from "../_namespaces/ts"; +import { + addObjectAllocatorPatcher, + Identifier, + idKeyword, + NodeFlags, +} from "../_namespaces/ts"; import { deprecate } from "../deprecate"; addObjectAllocatorPatcher(objectAllocator => { @@ -7,7 +12,7 @@ addObjectAllocatorPatcher(objectAllocator => { const propertyNames = Object.getOwnPropertyNames(Identifier.prototype); if (!propertyNames.includes("originalKeywordKind")) { Object.defineProperty(Identifier.prototype, "originalKeywordKind", { - get: deprecate(function(this: Identifier) { + get: deprecate(function (this: Identifier) { return idKeyword(this); }, { name: "originalKeywordKind", From 86ba694ca933061d694e2161e4e9e70e1c9ec93d Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 12 Jan 2023 11:30:21 -0500 Subject: [PATCH 12/13] PR Feedback --- src/compiler/binder.ts | 4 ++-- src/compiler/checker.ts | 4 ++-- src/compiler/transformers/es5.ts | 4 ++-- src/compiler/types.ts | 6 +---- src/compiler/utilities.ts | 17 ++----------- src/compiler/utilitiesPublic.ts | 7 ++++-- src/compiler/visitorPublic.ts | 4 ++-- .../5.0/identifierProperties.ts | 24 +++++++++++++------ src/services/codefixes/convertToEsModule.ts | 6 ++--- src/services/completions.ts | 11 +++++---- src/services/refactors/extractSymbol.ts | 5 ++-- 11 files changed, 43 insertions(+), 49 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 8b11dad3d197f..126c2532386fe 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -114,6 +114,7 @@ import { HasLocals, hasSyntacticModifier, Identifier, + identifierToKeywordKind, idText, IfStatement, ImportClause, @@ -283,7 +284,6 @@ import { SpreadElement, Statement, StringLiteral, - stringToToken, SuperExpression, SwitchStatement, Symbol, @@ -2422,7 +2422,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { !isIdentifierName(node)) { // strict mode identifiers - const originalKeywordKind = stringToToken(node.escapedText as string); + const originalKeywordKind = identifierToKeywordKind(node); if (inStrictMode && originalKeywordKind! >= SyntaxKind.FirstFutureReservedWord && originalKeywordKind! <= SyntaxKind.LastFutureReservedWord) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf3b1c2935bb8..11675a5b90edc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -377,6 +377,7 @@ import { hasSyntacticModifiers, HeritageClause, Identifier, + identifierToKeywordKind, IdentifierTypePredicate, idText, IfStatement, @@ -927,7 +928,6 @@ import { StringLiteralLike, StringLiteralType, StringMappingType, - stringToToken, stripQuotes, StructuredType, SubstitutionType, @@ -23213,7 +23213,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.Parameter: const param = declaration as ParameterDeclaration; if (isIdentifier(param.name)) { - const originalKeywordKind = stringToToken(param.name.escapedText as string); + const originalKeywordKind = identifierToKeywordKind(param.name); if ((isCallSignatureDeclaration(param.parent) || isMethodSignature(param.parent) || isFunctionTypeNode(param.parent)) && param.parent.parameters.indexOf(param) > -1 && (resolveName(param, param.name.escapedText, SymbolFlags.Type, undefined, param.name.escapedText, /*isUse*/ true) || diff --git a/src/compiler/transformers/es5.ts b/src/compiler/transformers/es5.ts index 25bc8fabb905d..24485e86c95e7 100644 --- a/src/compiler/transformers/es5.ts +++ b/src/compiler/transformers/es5.ts @@ -5,6 +5,7 @@ import { Expression, getOriginalNodeId, Identifier, + identifierToKeywordKind, isIdentifier, isPrivateIdentifier, isPropertyAccessExpression, @@ -18,7 +19,6 @@ import { PropertyAssignment, setTextRange, SourceFile, - stringToToken, SyntaxKind, TransformationContext, } from "../_namespaces/ts"; @@ -137,7 +137,7 @@ export function transformES5(context: TransformationContext): (x: SourceFile | B * @param name An Identifier */ function trySubstituteReservedName(name: Identifier) { - const token = stringToToken(name.escapedText as string); + const token = identifierToKeywordKind(name); if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) { return setTextRange(factory.createStringLiteralFromNode(name), name); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ac9f2352909da..556ec5593d619 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -834,7 +834,7 @@ export const enum NodeFlags { // The following flags repurpose other NodeFlags as different meanings for Identifier nodes /** @internal */ IdentifierHasExtendedUnicodeEscape = ContainsThis, // Indicates whether the identifier contains an extended unicode escape sequence - IdentifierIsInJSDocNamespace = HasAsyncFunctions, // Indicates whether the identifier is part of a JSDoc namespace + /** @internal */ IdentifierIsInJSDocNamespace = HasAsyncFunctions, // Indicates whether the identifier is part of a JSDoc namespace } export const enum ModifierFlags { @@ -1685,10 +1685,6 @@ export interface Identifier extends PrimaryExpression, Declaration, JSDocContain * Text of identifier, but if the identifier begins with two underscores, this will begin with three. */ readonly escapedText: __String; - /** @deprecated Use `idKeyword(identifier)` instead. */ - readonly originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later - /** @deprecated Use `identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ - readonly isInJSDocNamespace?: boolean; // if the node is a member in a JSDoc namespace. } // Transient identifier node (marked by id === -1) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4c9319f4c100a..3fb63f9dd0212 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -203,6 +203,7 @@ import { HasTypeArguments, HeritageClause, Identifier, + identifierToKeywordKind, IdentifierTypePredicate, identity, idText, @@ -4347,7 +4348,7 @@ export function isStringAKeyword(name: string) { /** @internal */ export function isIdentifierANonContextualKeyword(node: Identifier): boolean { - const originalKeywordKind = stringToToken(node.escapedText as string); + const originalKeywordKind = identifierToKeywordKind(node); return !!originalKeywordKind && !isContextualKeyword(originalKeywordKind); } @@ -7335,20 +7336,6 @@ function Identifier(this: Mutable, kind: SyntaxKind, pos: number, end: num this.emitNode = undefined; } -Object.defineProperties(Identifier.prototype, { - originalKeywordKind: { - get(this: Identifier) { - return stringToToken(this.escapedText as string); - } - }, - isInJSDocNamespace: { - get(this: Identifier) { - // NOTE: Returns `true` or `undefined` to match previous possible values. - return this.flags & NodeFlags.IdentifierIsInJSDocNamespace ? true : undefined; - } - } -}); - function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) { this.fileName = fileName; this.text = text; diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index a12b5e5429028..4d734e216b5d5 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -138,6 +138,7 @@ import { isJSDocTypeAlias, isJSDocTypeLiteral, isJSDocTypeTag, + isKeyword, isModuleBlock, isNonNullExpression, isNotEmittedStatement, @@ -259,6 +260,7 @@ import { TextChangeRange, TextRange, TextSpan, + tryCast, TypeElement, TypeNode, TypeOnlyAliasDeclaration, @@ -767,8 +769,9 @@ export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the * SyntaxKind for the matching keyword. */ -export function idKeyword(node: Identifier) { - return stringToToken(node.escapedText as string); +export function identifierToKeywordKind(node: Identifier) { + const token = stringToToken(node.escapedText as string); + return token ? tryCast(token, isKeyword) : undefined; } export function symbolName(symbol: Symbol): string { diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 193fd4693f831..7bd2806644378 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -7,6 +7,7 @@ import { FunctionBody, getEmitFlags, getEmitScriptTarget, + HasChildren, Identifier, isArray, isArrayBindingElement, @@ -98,7 +99,6 @@ import { Statement, SyntaxKind, TransformationContext, - VisitEachChildNodes, Visitor, } from "./_namespaces/ts"; @@ -518,7 +518,7 @@ type VisitEachChildFunction = (node: T, visitor: Visitor, contex // } // // This is then used as the expected type for `visitEachChildTable`. -type VisitEachChildTable = { [TNode in VisitEachChildNodes as TNode["kind"]]: VisitEachChildFunction }; +type VisitEachChildTable = { [TNode in HasChildren as TNode["kind"]]: VisitEachChildFunction }; // NOTE: Before you can add a new method to `visitEachChildTable`, you must first ensure the `Node` subtype you // wish to add is defined in the `HasChildren` union in types.ts. diff --git a/src/deprecatedCompat/5.0/identifierProperties.ts b/src/deprecatedCompat/5.0/identifierProperties.ts index 78ba8009c004e..fbbfc5ee55d15 100644 --- a/src/deprecatedCompat/5.0/identifierProperties.ts +++ b/src/deprecatedCompat/5.0/identifierProperties.ts @@ -1,30 +1,40 @@ import { addObjectAllocatorPatcher, + hasProperty, Identifier, - idKeyword, + identifierToKeywordKind, NodeFlags, } from "../_namespaces/ts"; import { deprecate } from "../deprecate"; +declare module "../../compiler/types" { + export interface Identifier { + /** @deprecated Use `idKeyword(identifier)` instead. */ + readonly originalKeywordKind?: SyntaxKind; + + /** @deprecated Use `.parent` or the surrounding context to determine this instead. */ + readonly isInJSDocNamespace?: boolean; + } +} + addObjectAllocatorPatcher(objectAllocator => { const Identifier = objectAllocator.getIdentifierConstructor(); - const propertyNames = Object.getOwnPropertyNames(Identifier.prototype); - if (!propertyNames.includes("originalKeywordKind")) { + if (!hasProperty(Identifier.prototype, "originalKeywordKind")) { Object.defineProperty(Identifier.prototype, "originalKeywordKind", { get: deprecate(function (this: Identifier) { - return idKeyword(this); + return identifierToKeywordKind(this); }, { name: "originalKeywordKind", since: "5.0", warnAfter: "5.1", errorAfter: "5.2", - message: "Use 'idKeyword(identifier)' instead." + message: "Use 'identifierToKeywordKind(identifier)' instead." }) }); } - if (!propertyNames.includes("isInJSDocNamespace")) { + if (!hasProperty(Identifier.prototype, "isInJSDocNamespace")) { Object.defineProperty(Identifier.prototype, "isInJSDocNamespace", { get: deprecate(function (this: Identifier) { // NOTE: Returns `true` or `undefined` to match previous possible values. @@ -34,7 +44,7 @@ addObjectAllocatorPatcher(objectAllocator => { since: "5.0", warnAfter: "5.1", errorAfter: "5.2", - message: "Use 'identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace' instead." + message: "Use '.parent' or the surrounding context to determine this instead." }) }); } diff --git a/src/services/codefixes/convertToEsModule.ts b/src/services/codefixes/convertToEsModule.ts index cf9e673121342..ea296b0a21790 100644 --- a/src/services/codefixes/convertToEsModule.ts +++ b/src/services/codefixes/convertToEsModule.ts @@ -50,7 +50,7 @@ import { isExportsOrModuleExportsOrAlias, isFunctionExpression, isIdentifier, - isNonContextualKeyword, + isIdentifierANonContextualKeyword, isObjectLiteralExpression, isPropertyAccessExpression, isRequireCall, @@ -75,7 +75,6 @@ import { SourceFile, Statement, StringLiteralLike, - stringToToken, SymbolFlags, SyntaxKind, textChanges, @@ -163,8 +162,7 @@ function collectExportRenames(sourceFile: SourceFile, checker: TypeChecker, iden const res = new Map(); forEachExportReference(sourceFile, node => { const { text } = node.name; - const originalKeywordKind = stringToToken(text); - if (!res.has(text) && (originalKeywordKind !== undefined && isNonContextualKeyword(originalKeywordKind) + if (!res.has(text) && (isIdentifierANonContextualKeyword(node.name) || checker.resolveName(text, node, SymbolFlags.Value, /*excludeGlobals*/ true))) { // Unconditionally add an underscore in case `text` is a keyword. res.set(text, makeUniqueName(`_${text}`, identifiers)); diff --git a/src/services/completions.ts b/src/services/completions.ts index 6a64d414748c3..0bf7c09e19618 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -107,6 +107,7 @@ import { hasInitializer, hasType, Identifier, + identifierToKeywordKind, ImportDeclaration, ImportEqualsDeclaration, ImportKind, @@ -1691,7 +1692,7 @@ function isModifierLike(node: Node): ModifierSyntaxKind | undefined { return node.kind; } if (isIdentifier(node)) { - const originalKeywordKind = stringToToken(node.escapedText as string); + const originalKeywordKind = identifierToKeywordKind(node); if (originalKeywordKind && isModifierKind(originalKeywordKind)) { return originalKeywordKind; } @@ -4723,7 +4724,7 @@ function isFunctionLikeBodyKeyword(kind: SyntaxKind) { } function keywordForNode(node: Node): SyntaxKind { - return isIdentifier(node) ? stringToToken(node.escapedText as string) || SyntaxKind.Unknown : node.kind; + return isIdentifier(node) ? identifierToKeywordKind(node) ?? SyntaxKind.Unknown : node.kind; } function getContextualKeywords( @@ -4827,8 +4828,8 @@ function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, } break; case SyntaxKind.Identifier: { - const originalKeywordKind = stringToToken((location as Identifier).text); - if (originalKeywordKind && isKeyword(originalKeywordKind)) { + const originalKeywordKind = identifierToKeywordKind(location as Identifier); + if (originalKeywordKind) { return undefined; } // class c { public prop = c| } @@ -4873,7 +4874,7 @@ function tryGetObjectTypeDeclarationCompletionContainer(sourceFile: SourceFile, return undefined; } const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword; - return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217 + return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(identifierToKeywordKind(contextToken) ?? SyntaxKind.Unknown)) ? contextToken.parent.parent as ObjectTypeDeclaration : undefined; } } diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 0d53736a5f1c3..3a0339a357bdf 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -61,6 +61,7 @@ import { hasEffectiveModifier, hasSyntacticModifier, Identifier, + identifierToKeywordKind, isArray, isArrowFunction, isAssignmentExpression, @@ -87,7 +88,6 @@ import { isJsxElement, isJsxFragment, isJsxSelfClosingElement, - isKeyword, isModuleBlock, isParenthesizedTypeNode, isPartOfTypeNode, @@ -136,7 +136,6 @@ import { SourceFile, Statement, StringLiteral, - stringToToken, suppressLeadingAndTrailingTrivia, Symbol, SymbolFlags, @@ -1352,7 +1351,7 @@ function extractConstantInScope( // Make a unique name for the extracted variable const file = scope.getSourceFile(); - const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) && !isPrivateIdentifier(node.name) && !isKeyword(stringToToken(node.name.escapedText as string) || SyntaxKind.Unknown) + const localNameText = isPropertyAccessExpression(node) && !isClassLike(scope) && !checker.resolveName(node.name.text, node, SymbolFlags.Value, /*excludeGlobals*/ false) && !isPrivateIdentifier(node.name) && !identifierToKeywordKind(node.name) ? node.name.text : getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file); const isJS = isInJSFile(scope); From 85e545338b44b5c323ad3b84300eafe8bf1fc549 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 12 Jan 2023 13:01:46 -0500 Subject: [PATCH 13/13] More PR feedback --- src/compiler/types.ts | 5 ----- src/compiler/utilitiesPublic.ts | 3 ++- src/harness/harnessUtils.ts | 3 +-- .../baselines/reference/api/tsserverlibrary.d.ts | 15 ++++++++------- tests/baselines/reference/api/typescript.d.ts | 15 ++++++++------- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 556ec5593d619..3877c51f16c34 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1013,11 +1013,6 @@ export type ForEachChildNodes = | JSDocOverloadTag ; -/** @internal */ -export type VisitEachChildNodes = - | HasChildren - ; - /** @internal */ export type HasChildren = | QualifiedName diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 4d734e216b5d5..2e78151cda548 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -190,6 +190,7 @@ import { JsxExpression, JsxOpeningLikeElement, JsxTagNameExpression, + KeywordSyntaxKind, LabeledStatement, lastOrUndefined, LeftHandSideExpression, @@ -769,7 +770,7 @@ export function idText(identifierOrPrivateName: Identifier | PrivateIdentifier): * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the * SyntaxKind for the matching keyword. */ -export function identifierToKeywordKind(node: Identifier) { +export function identifierToKeywordKind(node: Identifier): KeywordSyntaxKind | undefined { const token = stringToToken(node.escapedText as string); return token ? tryCast(token, isKeyword) : undefined; } diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index 6f985e2ed552d..f4d006e05aa4a 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -1,6 +1,5 @@ import * as ts from "./_namespaces/ts"; import * as Harness from "./_namespaces/Harness"; -import { isIdentifier } from "./_namespaces/ts"; export function encodeString(s: string): string { return ts.sys.bufferFrom!(s).toString("utf8"); @@ -221,7 +220,7 @@ export function sourceFileToJSON(file: ts.Node): string { // data we don't care about in the dump. We only care what the parser set directly // on the AST. let flags = n.flags & ~(ts.NodeFlags.JavaScriptFile | ts.NodeFlags.HasAggregatedChildData); - if (isIdentifier(n)) { + if (ts.isIdentifier(n)) { if (flags & ts.NodeFlags.IdentifierHasExtendedUnicodeEscape) { o.hasExtendedUnicodeEscape = true; flags &= ~ts.NodeFlags.IdentifierHasExtendedUnicodeEscape; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index a29297ef1590e..ca08413acb2b8 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -4414,8 +4414,7 @@ declare namespace ts { ReachabilityCheckFlags = 768, ReachabilityAndEmitFlags = 2816, ContextFlags = 50720768, - TypeExcludesFlags = 40960, - IdentifierIsInJSDocNamespace = 2048 + TypeExcludesFlags = 40960 } enum ModifierFlags { None = 0, @@ -4585,14 +4584,16 @@ declare namespace ts { * Text of identifier, but if the identifier begins with two underscores, this will begin with three. */ readonly escapedText: __String; - /** @deprecated Use `idKeyword(identifier)` instead. */ - readonly originalKeywordKind?: SyntaxKind; - /** @deprecated Use `identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ - readonly isInJSDocNamespace?: boolean; } interface Identifier { readonly text: string; } + interface Identifier { + /** @deprecated Use `idKeyword(identifier)` instead. */ + readonly originalKeywordKind?: SyntaxKind; + /** @deprecated Use `.parent` or the surrounding context to determine this instead. */ + readonly isInJSDocNamespace?: boolean; + } interface TransientIdentifier extends Identifier { resolvedSymbol: Symbol; } @@ -8605,7 +8606,7 @@ declare namespace ts { * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the * SyntaxKind for the matching keyword. */ - function idKeyword(node: Identifier): SyntaxKind | undefined; + function identifierToKeywordKind(node: Identifier): KeywordSyntaxKind | undefined; function symbolName(symbol: Symbol): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined; function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index e014912161bff..25a28c914bec3 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -479,8 +479,7 @@ declare namespace ts { ReachabilityCheckFlags = 768, ReachabilityAndEmitFlags = 2816, ContextFlags = 50720768, - TypeExcludesFlags = 40960, - IdentifierIsInJSDocNamespace = 2048 + TypeExcludesFlags = 40960 } enum ModifierFlags { None = 0, @@ -650,14 +649,16 @@ declare namespace ts { * Text of identifier, but if the identifier begins with two underscores, this will begin with three. */ readonly escapedText: __String; - /** @deprecated Use `idKeyword(identifier)` instead. */ - readonly originalKeywordKind?: SyntaxKind; - /** @deprecated Use `identifier.flags & NodeFlags.IdentifierIsInJSDocNamespace` instead. */ - readonly isInJSDocNamespace?: boolean; } interface Identifier { readonly text: string; } + interface Identifier { + /** @deprecated Use `idKeyword(identifier)` instead. */ + readonly originalKeywordKind?: SyntaxKind; + /** @deprecated Use `.parent` or the surrounding context to determine this instead. */ + readonly isInJSDocNamespace?: boolean; + } interface TransientIdentifier extends Identifier { resolvedSymbol: Symbol; } @@ -4670,7 +4671,7 @@ declare namespace ts { * If the text of an Identifier matches a keyword (including contextual and TypeScript-specific keywords), returns the * SyntaxKind for the matching keyword. */ - function idKeyword(node: Identifier): SyntaxKind | undefined; + function identifierToKeywordKind(node: Identifier): KeywordSyntaxKind | undefined; function symbolName(symbol: Symbol): string; function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | PrivateIdentifier | undefined; function getNameOfDeclaration(declaration: Declaration | Expression | undefined): DeclarationName | undefined;