Ensure that we copy empty NodeArrays during transform (#48490)

This commit is contained in:
Jake Bailey 2022-03-30 15:33:51 -07:00 committed by GitHub
parent 41aca7c337
commit 3c6c2799b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 1 deletions

View File

@ -5262,7 +5262,18 @@ namespace ts {
if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) {
return node;
}
return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext)), node);
return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node);
}
function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T>, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T>;
function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T> | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> | undefined;
function deepCloneOrReuseNodes<T extends Node>(nodes: NodeArray<T> | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray<T> | undefined {
if (nodes && nodes.length === 0) {
// Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements,
// which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding.
return setTextRange(factory.createNodeArray<T>(/*nodes*/ undefined, nodes.hasTrailingComma), nodes);
}
return visitNodes(nodes, visitor, test, start, count);
}
}

View File

@ -0,0 +1,28 @@
/// <reference path="fourslash.ts" />
// @newline: LF
// @Filename: a.ts
////declare class Component<T> {
//// setState(stateHandler: ((oldState: T, newState: T) => void)): void;
////}
////
////class SubComponent extends Component<{}> {
//// /*$*/
////}
verify.completions({
marker: "$",
isNewIdentifierLocation: true,
preferences: {
includeCompletionsWithInsertText: true,
includeCompletionsWithSnippetText: false,
includeCompletionsWithClassMemberSnippets: true,
},
includes: [
{
name: "setState",
sortText: completion.SortText.ClassMemberSnippets,
insertText: "setState(stateHandler: (oldState: {}, newState: {}) => void): void {\n}",
}
]
});