Don't cache child lists for tokens (#58233)

This commit is contained in:
Daniel Rosenwasser 2024-04-19 14:49:31 -07:00 committed by GitHub
parent aedd1b1bb5
commit e8f22253ba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 21 additions and 19 deletions

View File

@ -1,14 +1,20 @@
import { Node } from "../_namespaces/ts";
import {
emptyArray,
isNodeKind,
Node,
} from "../_namespaces/ts";
const nodeChildren = new WeakMap<Node, Node[] | undefined>();
const nodeChildren = new WeakMap<Node, readonly Node[] | undefined>();
/** @internal */
export function getNodeChildren(node: Node): Node[] | undefined {
export function getNodeChildren(node: Node): readonly Node[] | undefined {
if (!isNodeKind(node.kind)) return emptyArray;
return nodeChildren.get(node);
}
/** @internal */
export function setNodeChildren(node: Node, children: Node[]): Node[] {
export function setNodeChildren(node: Node, children: readonly Node[]): readonly Node[] {
nodeChildren.set(node, children);
return children;
}

View File

@ -6209,7 +6209,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
}
// @api
function createSyntaxList(children: Node[]) {
function createSyntaxList(children: readonly Node[]) {
const node = createBaseNode<SyntaxList>(SyntaxKind.SyntaxList);
setNodeChildren(node, children);
return node;

View File

@ -9006,7 +9006,7 @@ export interface NodeFactory {
// Synthetic Nodes
//
/** @internal */ createSyntheticExpression(type: Type, isSpread?: boolean, tupleNameSource?: ParameterDeclaration | NamedTupleMember): SyntheticExpression;
/** @internal */ createSyntaxList(children: Node[]): SyntaxList;
/** @internal */ createSyntaxList(children: readonly Node[]): SyntaxList;
//
// Transformation nodes

View File

@ -438,7 +438,7 @@ class NodeObject<TKind extends SyntaxKind> implements Node {
return this.getChildren(sourceFile)[index];
}
public getChildren(sourceFile?: SourceFileLike): Node[] {
public getChildren(sourceFile?: SourceFileLike): readonly Node[] {
this.assertHasRealPosition("Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine");
return getNodeChildren(this) ?? setNodeChildren(this, createChildren(this, sourceFile));
}
@ -473,11 +473,7 @@ class NodeObject<TKind extends SyntaxKind> implements Node {
}
}
function createChildren(node: Node, sourceFile: SourceFileLike | undefined): Node[] {
if (!isNodeKind(node.kind)) {
return emptyArray;
}
function createChildren(node: Node, sourceFile: SourceFileLike | undefined): readonly Node[] {
const children: Node[] = [];
if (isJSDocCommentContainingNode(node)) {

View File

@ -279,7 +279,7 @@ function getSelectionChildren(node: Node): readonly Node[] {
* Groups sibling nodes together into their own SyntaxList if they
* a) are adjacent, AND b) match a predicate function.
*/
function groupChildren(children: Node[], groupOn: (child: Node) => boolean): Node[] {
function groupChildren(children: readonly Node[], groupOn: (child: Node) => boolean): Node[] {
const result: Node[] = [];
let group: Node[] | undefined;
for (const child of children) {
@ -315,7 +315,7 @@ function groupChildren(children: Node[], groupOn: (child: Node) => boolean): Nod
* @param separateTrailingSemicolon If the last token is a semicolon, it will be returned as a separate
* child rather than be included in the right-hand group.
*/
function splitChildren(children: Node[], pivotOn: (child: Node) => boolean, separateTrailingSemicolon = true): Node[] {
function splitChildren(children: readonly Node[], pivotOn: (child: Node) => boolean, separateTrailingSemicolon = true): readonly Node[] {
if (children.length < 2) {
return children;
}
@ -336,7 +336,7 @@ function splitChildren(children: Node[], pivotOn: (child: Node) => boolean, sepa
return separateLastToken ? result.concat(lastToken) : result;
}
function createSyntaxList(children: Node[]): SyntaxList {
function createSyntaxList(children: readonly Node[]): SyntaxList {
Debug.assertGreaterThanOrEqual(children.length, 1);
return setTextRangePosEnd(parseNodeFactory.createSyntaxList(children), children[0].pos, last(children).end);
}

View File

@ -49,9 +49,9 @@ declare module "../compiler/types" {
getSourceFile(): SourceFile;
getChildCount(sourceFile?: SourceFile): number;
getChildAt(index: number, sourceFile?: SourceFile): Node;
getChildren(sourceFile?: SourceFile): Node[];
getChildren(sourceFile?: SourceFile): readonly Node[];
/** @internal */
getChildren(sourceFile?: SourceFileLike): Node[]; // eslint-disable-line @typescript-eslint/unified-signatures
getChildren(sourceFile?: SourceFileLike): readonly Node[]; // eslint-disable-line @typescript-eslint/unified-signatures
getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number;
/** @internal */
getStart(sourceFile?: SourceFileLike, includeJsDocComment?: boolean): number; // eslint-disable-line @typescript-eslint/unified-signatures

View File

@ -1830,7 +1830,7 @@ function findRightmostToken(n: Node, sourceFile: SourceFileLike): Node | undefin
/**
* Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens.
*/
function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number, sourceFile: SourceFileLike, parentKind: SyntaxKind): Node | undefined {
function findRightmostChildNodeWithTokens(children: readonly Node[], exclusiveStartPosition: number, sourceFile: SourceFileLike, parentKind: SyntaxKind): Node | undefined {
for (let i = exclusiveStartPosition - 1; i >= 0; i--) {
const child = children[i];

View File

@ -4215,7 +4215,7 @@ declare namespace ts {
getSourceFile(): SourceFile;
getChildCount(sourceFile?: SourceFile): number;
getChildAt(index: number, sourceFile?: SourceFile): Node;
getChildren(sourceFile?: SourceFile): Node[];
getChildren(sourceFile?: SourceFile): readonly Node[];
getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number;
getFullStart(): number;
getEnd(): number;