Skip to content

Commit 3c6c279

Browse files
authored
Ensure that we copy empty NodeArrays during transform (#48490)
1 parent 41aca7c commit 3c6c279

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

src/compiler/checker.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -5262,7 +5262,18 @@ namespace ts {
52625262
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
52635263
return node;
52645264
}
5265-
return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext)), node);
5265+
return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node);
5266+
}
5267+
5268+
function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T>, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T>;
5269+
function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T> | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> | undefined;
5270+
function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T> | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> | undefined {
5271+
if (nodes && nodes.length === 0) {
5272+
// Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements,
5273+
// which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding.
5274+
return setTextRange(factory.createNodeArray<T>(/*nodes*/ undefined, nodes.hasTrailingComma), nodes);
5275+
}
5276+
return visitNodes(nodes, visitor, test, start, count);
52665277
}
52675278
}
52685279

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @newline: LF
4+
// @Filename: a.ts
5+
////declare class Component<T> {
6+
//// setState(stateHandler: ((oldState: T, newState: T) => void)): void;
7+
////}
8+
////
9+
////class SubComponent extends Component<{}> {
10+
//// /*$*/
11+
////}
12+
13+
verify.completions({
14+
marker: "$",
15+
isNewIdentifierLocation: true,
16+
preferences: {
17+
includeCompletionsWithInsertText: true,
18+
includeCompletionsWithSnippetText: false,
19+
includeCompletionsWithClassMemberSnippets: true,
20+
},
21+
includes: [
22+
{
23+
name: "setState",
24+
sortText: completion.SortText.ClassMemberSnippets,
25+
insertText: "setState(stateHandler: (oldState: {}, newState: {}) => void): void {\n}",
26+
}
27+
]
28+
});

0 commit comments

Comments
 (0)