Skip to content

createNodeArray mutates its input if not already a NodeArray #20471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2811,7 +2811,7 @@ namespace ts {
entityName = nameIdentifier;
}

let typeArgumentNodes: ReadonlyArray<TypeNode> | undefined;
let typeArgumentNodes: TypeNode[] | undefined;
if (typeArguments.length > 0) {
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
typeArgumentNodes = mapToTypeNodes(typeArguments.slice(i, typeParameterCount), context);
Expand Down Expand Up @@ -3039,7 +3039,7 @@ namespace ts {
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
Debug.assert(chain && 0 <= index && index < chain.length);
const symbol = chain[index];
let typeParameterNodes: ReadonlyArray<TypeNode> | undefined;
let typeParameterNodes: TypeNode[] | undefined;
if (context.flags & NodeBuilderFlags.WriteTypeParametersInQualifiedName && index > 0) {
const parentSymbol = chain[index - 1];
let typeParameters: TypeParameter[];
Expand Down
386 changes: 192 additions & 194 deletions src/compiler/factory.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/compiler/transformers/es2017.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ namespace ts {
const declarations = endLexicalEnvironment();
if (some(declarations)) {
const block = convertToFunctionBody(expression);
return updateBlock(block, setTextRange(createNodeArray(concatenate(block.statements, declarations)), block.statements));
return updateBlock(block, concatToNodeArray(block.statements, declarations));
}

return expression;
Expand All @@ -274,7 +274,7 @@ namespace ts {
startLexicalEnvironment();
const visited = convertToFunctionBody(visitNode(body, visitor, isConciseBody));
const declarations = endLexicalEnvironment();
return updateBlock(visited, setTextRange(createNodeArray(concatenate(visited.statements, declarations)), visited.statements));
return updateBlock(visited, concatToNodeArray(visited.statements, declarations));
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

/* @internal */
namespace ts {
export const emptyArray: never[] = [] as never[];
// TODO: GH#16312 Should be a ReadonlyArray<never>
export const emptyArray: never[] = Object.freeze([]) as never[];
export const emptyMap: ReadonlyMap<never> = createMap<never>();

export const externalHelpersModuleNameText = "tslib";
Expand Down Expand Up @@ -2841,7 +2842,7 @@ namespace ts {
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters, checkJSDoc?: boolean): ReadonlyArray<TypeParameterDeclaration> {
export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters, checkJSDoc?: boolean): NodeArray<TypeParameterDeclaration> {
if (node.typeParameters) {
return node.typeParameters;
}
Expand Down
10 changes: 7 additions & 3 deletions src/compiler/visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,12 @@ namespace ts {
if (ensureUseStrict && !startsWithUseStrict(statements)) {
statements = setTextRange(createNodeArray([createStatement(createLiteral("use strict")), ...statements]), statements);
}
const declarations = context.endLexicalEnvironment();
return setTextRange(createNodeArray(concatenate(statements, declarations)), statements);
return concatToNodeArray(statements, context.endLexicalEnvironment());
}

/* @internal */
export function concatToNodeArray<T extends Node>(a: NodeArray<T>, b: ReadonlyArray<T> | undefined): NodeArray<T> {
return b === undefined ? a : setTextRange(createNodeArray(a.concat(b)), a);
}

/**
Expand Down Expand Up @@ -1448,7 +1452,7 @@ namespace ts {
}

return isNodeArray(statements)
? setTextRange(createNodeArray(concatenate(statements, declarations)), statements)
? setTextRange(createNodeArray(statements.concat(declarations)), statements)
: addRange(statements, declarations);
}

Expand Down
4 changes: 2 additions & 2 deletions src/harness/unittests/printer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace ts {
/*decorators*/ undefined,
/*modifiers*/ [createToken(SyntaxKind.DeclareKeyword)],
createIdentifier("global"),
createModuleBlock(emptyArray),
createModuleBlock([]),
NodeFlags.GlobalAugmentation),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
Expand All @@ -154,7 +154,7 @@ namespace ts {
/*decorators*/ undefined,
/*modifiers*/ undefined,
createIdentifier("global"),
createModuleBlock(emptyArray),
createModuleBlock([]),
NodeFlags.GlobalAugmentation),
createSourceFile("source.ts", "", ScriptTarget.ES2015)
));
Expand Down
8 changes: 4 additions & 4 deletions src/harness/unittests/textChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ namespace M
/*asteriskToken*/ undefined,
/*name*/ "bar",
/*typeParameters*/ undefined,
/*parameters*/ emptyArray,
/*parameters*/ [],
/*type*/ createKeywordTypeNode(SyntaxKind.AnyKeyword),
/*body */ createBlock(statements)
);
Expand All @@ -110,7 +110,7 @@ namespace M
createCall(
/*expression*/ newFunction.name,
/*typeArguments*/ undefined,
/*argumentsArray*/ emptyArray
/*argumentsArray*/ [],
));
changeTracker.replaceNodeRange(sourceFile, statements[0], lastOrUndefined(statements), newStatement, { suffix: newLineCharacter });
});
Expand Down Expand Up @@ -346,8 +346,8 @@ namespace M {
function createTestSuperCall() {
const superCall = createCall(
createSuper(),
/*typeArguments*/ undefined,
/*argumentsArray*/ emptyArray
/*typeArguments*/ undefined,
/*argumentsArray*/ [],
);
return createStatement(superCall);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace ts.codefix {
}

const changeTracker = textChanges.ChangeTracker.fromContext(context);
const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ emptyArray));
const superCall = createStatement(createCall(createSuper(), /*typeArguments*/ undefined, /*argumentsArray*/ []));
changeTracker.insertNodeAtConstructorStart(sourceFile, <ConstructorDeclaration>token.parent, superCall, context.newLineCharacter);

return [{
Expand Down
8 changes: 4 additions & 4 deletions src/services/codefixes/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ namespace ts.codefix {
return parameters;
}

function createMethodImplementingSignatures(signatures: ReadonlyArray<Signature>, name: PropertyName, optional: boolean, modifiers: ReadonlyArray<Modifier> | undefined): MethodDeclaration {
function createMethodImplementingSignatures(signatures: ReadonlyArray<Signature>, name: PropertyName, optional: boolean, modifiers: Nodes<Modifier> | undefined): MethodDeclaration {
/** This is *a* signature with the maximal number of arguments,
* such that if there is a "maximal" signature without rest arguments,
* this is one of them.
Expand Down Expand Up @@ -230,11 +230,11 @@ namespace ts.codefix {
}

export function createStubbedMethod(
modifiers: ReadonlyArray<Modifier>,
modifiers: Nodes<Modifier>,
name: PropertyName,
optional: boolean,
typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined,
parameters: ReadonlyArray<ParameterDeclaration>,
typeParameters: Nodes<TypeParameterDeclaration> | undefined,
parameters: Nodes<ParameterDeclaration>,
returnType: TypeNode | undefined) {
return createMethod(
/*decorators*/ undefined,
Expand Down
10 changes: 5 additions & 5 deletions src/services/refactors/annotateWithTypeFromJSDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
switch (node.kind) {
case SyntaxKind.JSDocAllType:
case SyntaxKind.JSDocUnknownType:
return createTypeReferenceNode("any", emptyArray);
return createTypeReferenceNode("any", []);
case SyntaxKind.JSDocOptionalType:
return transformJSDocOptionalType(node as JSDocOptionalType);
case SyntaxKind.JSDocNonNullableType:
Expand All @@ -180,11 +180,11 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
}

function transformJSDocOptionalType(node: JSDocOptionalType) {
return createUnionTypeNode([visitNode(node.type, transformJSDocType), createTypeReferenceNode("undefined", emptyArray)]);
return createUnionTypeNode([visitNode(node.type, transformJSDocType), createTypeReferenceNode("undefined", [])]);
}

function transformJSDocNullableType(node: JSDocNullableType) {
return createUnionTypeNode([visitNode(node.type, transformJSDocType), createTypeReferenceNode("null", emptyArray)]);
return createUnionTypeNode([visitNode(node.type, transformJSDocType), createTypeReferenceNode("null", [])]);
}

function transformJSDocVariadicType(node: JSDocVariadicType) {
Expand All @@ -193,7 +193,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {

function transformJSDocFunctionType(node: JSDocFunctionType) {
const parameters = node.parameters && node.parameters.map(transformJSDocType);
return createFunctionTypeNode(emptyArray, parameters as ParameterDeclaration[], node.type);
return createFunctionTypeNode([], parameters as ParameterDeclaration[], node.type);
}

function transformJSDocParameter(node: ParameterDeclaration) {
Expand Down Expand Up @@ -227,7 +227,7 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
}
name = createIdentifier(text);
if ((text === "Array" || text === "Promise") && !node.typeArguments) {
args = createNodeArray([createTypeReferenceNode("any", emptyArray)]);
args = createNodeArray([createTypeReferenceNode("any", [])]);
}
else {
args = visitNodes(node.typeArguments, transformJSDocType);
Expand Down
2 changes: 1 addition & 1 deletion src/services/refactors/convertFunctionToEs6Class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ namespace ts.refactor.convertFunctionToES6Class {
}

function getModifierKindFromSource(source: Node, kind: SyntaxKind) {
return filter(source.modifiers, modifier => modifier.kind === kind);
return source.modifiers && source.modifiers.filter(modifier => modifier.kind === kind);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/refactors/extractSymbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -751,13 +751,13 @@ namespace ts.refactor.extractSymbol {
const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values()).map(type => ({ type, declaration: getFirstDeclaration(type) }));
const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder);

const typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined = sortedTypeParametersAndDeclarations.length === 0
const typeParameters = sortedTypeParametersAndDeclarations.length === 0
? undefined
: sortedTypeParametersAndDeclarations.map(t => t.declaration as TypeParameterDeclaration);

// Strictly speaking, we should check whether each name actually binds to the appropriate type
// parameter. In cases of shadowing, they may not.
const callTypeArguments: ReadonlyArray<TypeNode> | undefined = typeParameters !== undefined
const callTypeArguments = typeParameters !== undefined
? typeParameters.map(decl => createTypeReferenceNode(decl.name, /*typeArguments*/ undefined))
: undefined;

Expand Down
Loading