From d89e21aecd929c5ef9cad8f1cfde148514c3ca1e Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Mon, 7 Mar 2016 16:48:40 -0800 Subject: [PATCH] General fixes and cleanup --- src/compiler/factory.ts | 60 ++++++++-------------- src/compiler/printer.ts | 6 ++- src/compiler/transformers/destructuring.ts | 6 +-- src/compiler/transformers/es6.ts | 14 +++-- src/compiler/transformers/module/module.ts | 2 +- src/compiler/transformers/module/system.ts | 2 +- src/compiler/transformers/ts.ts | 18 +++---- src/compiler/types.ts | 1 + src/compiler/utilities.ts | 7 +-- src/compiler/visitor.ts | 12 ++--- 10 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 61077ec8f6e..88fda6a5080 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -110,21 +110,15 @@ namespace ts { } /** - * Creates a shallow, memberwise clone of a node. The "kind", "pos", "end", "flags", and "parent" - * properties are excluded by default, and can be provided via the "location", "flags", and - * "parent" parameters. - * - * @param node The node to clone. - * @param location An optional TextRange to use to supply the new position. - * @param flags The NodeFlags to use for the cloned node. - * @param parent The parent for the new node. - * @param original An optional pointer to the original source tree node. + * Creates a shallow, memberwise clone of a node with no source map location. */ - export function cloneNode(node: T, location?: TextRange, flags?: NodeFlags, parent?: Node, original?: Node): T { + export function getSynthesizedClone(node: T): T { // We don't use "clone" from core.ts here, as we need to preserve the prototype chain of // the original node. We also need to exclude specific properties and only include own- // properties (to skip members already defined on the shared prototype). - const clone = createNode(node.kind, location); + const clone = createSynthesizedNode(node.kind); + clone.flags = node.flags; + clone.original = node; for (const key in node) { if (clone.hasOwnProperty(key) || !node.hasOwnProperty(key)) { @@ -134,18 +128,6 @@ namespace ts { (clone)[key] = (node)[key]; } - if (flags !== undefined) { - clone.flags = flags; - } - - if (parent !== undefined) { - clone.parent = parent; - } - - if (original !== undefined) { - clone.original = original; - } - return clone; } @@ -153,21 +135,21 @@ namespace ts { * Creates a shallow, memberwise clone of a node for mutation. */ export function getMutableClone(node: T): T { - return cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); - } - - /** - * Creates a shallow, memberwise clone of a node with no source map location. - */ - export function getSynthesizedClone(node: T): T { - return nodeIsSynthesized(node) ? node : cloneNode(node, /*location*/ undefined, node.flags, /*parent*/ undefined, /*original*/ node); + const clone = getSynthesizedClone(node); + clone.pos = node.pos; + clone.end = node.end; + clone.parent = node.parent; + return clone; } /** * Creates a shallow, memberwise clone of a node at the specified source map location. */ export function getRelocatedClone(node: T, location: TextRange): T { - return cloneNode(node, location, node.flags, /*parent*/ undefined, /*original*/ node); + const clone = getSynthesizedClone(node); + clone.pos = location.pos; + clone.end = location.end; + return clone; } export function createNodeArrayNode(elements: T[]): NodeArrayNode { @@ -718,8 +700,8 @@ namespace ts { export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression { return isIdentifier(memberName) - ? createPropertyAccess(target, cloneNode(memberName), location) - : createElementAccess(target, cloneNode(isComputedPropertyName(memberName) ? memberName.expression : memberName), location); + ? createPropertyAccess(target, getSynthesizedClone(memberName), location) + : createElementAccess(target, getSynthesizedClone(isComputedPropertyName(memberName) ? memberName.expression : memberName), location); } export function createRestParameter(name: string | Identifier) { @@ -1154,15 +1136,15 @@ namespace ts { return isQualifiedName(node) ? createPropertyAccess( createExpressionFromEntityName(node.left), - cloneNode(node.right) + getSynthesizedClone(node.right) ) - : cloneNode(node); + : getSynthesizedClone(node); } export function createExpressionForPropertyName(memberName: PropertyName, location?: TextRange): Expression { return isIdentifier(memberName) ? createLiteral(memberName.text, location) - : isComputedPropertyName(memberName) ? cloneNode(memberName.expression, location) - : cloneNode(memberName, location); + : isComputedPropertyName(memberName) ? getRelocatedClone(memberName.expression, location) + : getRelocatedClone(memberName, location); } // Utilities @@ -1370,7 +1352,7 @@ namespace ts { const callee = expression.expression; if (callee.kind === SyntaxKind.FunctionExpression || callee.kind === SyntaxKind.ArrowFunction) { - const clone = cloneNode(expression, expression, expression.flags, expression.parent, expression); + const clone = getMutableClone(expression); clone.expression = createParen(callee, /*location*/ callee); return clone; } diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts index eb1bb2a6581..6f81d0974a4 100644 --- a/src/compiler/printer.ts +++ b/src/compiler/printer.ts @@ -675,7 +675,7 @@ const _super = (function (geti, seti) { // function emitIdentifier(node: Identifier) { - if (getNodeEmitFlags(node) && NodeEmitFlags.UMDDefine) { + if (getNodeEmitFlags(node) & NodeEmitFlags.UMDDefine) { writeLines(umdHelper); } else { @@ -1411,6 +1411,10 @@ const _super = (function (geti, seti) { } function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) { + if (body.multiLine) { + return false; + } + const originalNode = getOriginalNode(parentNode); if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode)) { const body = originalNode.body; diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 442201a1f7d..0e1cbfe1b3a 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -236,7 +236,7 @@ namespace ts { emitArrayLiteralAssignment(target, value, location); } else { - const name = cloneNode(target, /*location*/ target, /*flags*/ undefined, /*parent*/ undefined, /*original*/ target); + const name = getRelocatedClone(target, /*location*/ target); emitAssignment(name, value, location, /*original*/ undefined); } } @@ -326,7 +326,7 @@ namespace ts { } } else { - const clonedName = cloneNode(name, /*location*/ undefined, /*flags*/ undefined, /*parent*/ undefined, /*original*/ name); + const clonedName = getSynthesizedClone(name); emitAssignment(clonedName, value, target, target); } } @@ -365,7 +365,7 @@ namespace ts { // otherwise occur when the identifier is emitted. return createElementAccess( expression, - cloneNode(propertyName) + getSynthesizedClone(propertyName) ); } } diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index ebc50ad7b16..f9c457b430a 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -16,6 +16,7 @@ namespace ts { startLexicalEnvironment, endLexicalEnvironment, hoistVariableDeclaration, + getNodeEmitFlags, setNodeEmitFlags, } = context; @@ -50,6 +51,7 @@ namespace ts { function transformSourceFile(node: SourceFile) { currentSourceFile = node; + enclosingBlockScopeContainer = node; return visitEachChild(node, visitor, context); } @@ -772,7 +774,9 @@ namespace ts { enableSubstitutionsForCapturedThis(); } - return transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined); + const func = transformFunctionLikeToExpression(node, /*location*/ node, /*name*/ undefined); + setNodeEmitFlags(func, NodeEmitFlags.CapturesThis); + return func; } /** @@ -1514,7 +1518,7 @@ namespace ts { * @param node A template literal. */ function visitTemplateLiteral(node: LiteralExpression): LeftHandSideExpression { - return createLiteral(node.text); + return createLiteral(node.text, /*location*/ node); } /** @@ -1579,7 +1583,7 @@ namespace ts { // and LineTerminatorSequences are normalized to for both TV and TRV. text = text.replace(/\r\n?/g, "\n"); text = escapeString(text); - return createLiteral(text); + return createLiteral(text, /*location*/ node); } /** @@ -1689,7 +1693,7 @@ namespace ts { addCaptureThisForNodeIfNeeded(statements, node); addRange(statements, visitNodes(createNodeArray(remaining), visitor, isStatement)); addRange(statements, endLexicalEnvironment()); - const clone = cloneNode(node, node, node.flags, /*parent*/ undefined, node); + const clone = getMutableClone(node); clone.statements = createNodeArray(statements, /*location*/ node.statements); return clone; } @@ -1705,7 +1709,7 @@ namespace ts { if (enabledSubstitutions & ES6SubstitutionFlags.CapturedThis && isFunctionLike(node)) { // If we are tracking a captured `this`, push a bit that indicates whether the // containing function is an arrow function. - useCapturedThis = node.kind === SyntaxKind.ArrowFunction; + useCapturedThis = (getNodeEmitFlags(node) & NodeEmitFlags.CapturesThis) !== 0; } previousOnEmitNode(node, emit); diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index a1c737fecfd..dd2934599ea 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -750,7 +750,7 @@ namespace ts { } function updateSourceFile(node: SourceFile, statements: Statement[]) { - const updated = cloneNode(node, node, node.flags, /*parent*/ undefined, node); + const updated = getMutableClone(node); updated.statements = createNodeArray(statements, node.statements); return updated; } diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index e5d3dad0a7d..70e5f2edb9c 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -1271,7 +1271,7 @@ namespace ts { } function updateSourceFile(node: SourceFile, statements: Statement[]) { - const updated = cloneNode(node, node, node.flags, /*parent*/ undefined, node); + const updated = getMutableClone(node); updated.statements = createNodeArray(statements, node.statements); return updated; } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 07a572ac415..ea9b517391b 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -198,8 +198,11 @@ namespace ts { // Fallback to the default visit behavior. return visitorWorker(node); + case SyntaxKind.SemicolonClassElement: + return node; + default: - Debug.fail("Unexpected node."); + Debug.fail(`Unexpected node kind: ${formatSyntaxKind(node.kind)}.`); break; } } @@ -867,7 +870,7 @@ namespace ts { function transformParameterWithPropertyAssignment(node: ParameterDeclaration) { Debug.assert(isIdentifier(node.name)); - const name = cloneNode(node.name); + const name = getSynthesizedClone(node.name); return startOnNewLine( createStatement( createAssignment( @@ -1730,10 +1733,7 @@ namespace ts { ); } else { - return setOriginalNode( - cloneNode(name), - name - ); + return getSynthesizedClone(name); } } @@ -2347,7 +2347,7 @@ namespace ts { function trackChildOfNotEmittedNode(parent: Node, child: T, original: T) { if (!child.parent && !child.original) { - child = cloneNode(child, child, child.flags, child.parent, original); + child = getMutableClone(child); } setNodeEmitFlags(parent, NodeEmitFlags.IsNotEmittedNode); @@ -2403,7 +2403,7 @@ namespace ts { ); if (isNamespaceExport(node)) { - moduleParam = createAssignment(cloneNode(node.name), moduleParam); + moduleParam = createAssignment(getSynthesizedClone(node.name), moduleParam); } currentNamespaceLocalName = getGeneratedNameForNode(node); @@ -2710,7 +2710,7 @@ namespace ts { if (declaration) { const classAlias = currentDecoratedClassAliases[getNodeId(declaration)]; if (classAlias) { - return cloneNode(classAlias); + return getRelocatedClone(classAlias, /*location*/ node); } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f5c4468ef67..e470bc6df0b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2810,6 +2810,7 @@ namespace ts { IsNotEmittedNode = 1 << 8, // Is a node that is not emitted but whose comments should be preserved if possible. EmitCommentsOfNotEmittedParent = 1 << 9, // Emits comments of missing parent nodes. NoSubstitution = 1 << 10, // Disables further substitution of an expression. + CapturesThis = 1 << 11, // The function captures a lexical `this` } /** Additional context provided to `visitEachChild` */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 8ee83810949..2ec96b16bc2 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1666,11 +1666,11 @@ namespace ts { * @param parent The parent for the cloned node. */ export function cloneEntityName(node: EntityName, parent?: Node): EntityName { - const clone = cloneNode(node, node, node.flags, parent); + const clone = getMutableClone(node); if (isQualifiedName(clone)) { const { left, right } = clone; clone.left = cloneEntityName(left, clone); - clone.right = cloneNode(right, right, right.flags, parent); + clone.right = getMutableClone(right); } return clone; @@ -3066,7 +3066,8 @@ namespace ts { || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.GetAccessor || kind === SyntaxKind.SetAccessor - || kind === SyntaxKind.IndexSignature; + || kind === SyntaxKind.IndexSignature + || kind === SyntaxKind.SemicolonClassElement; } export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement { diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 18b22b5e83f..d25d3ded807 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -516,7 +516,7 @@ namespace ts { return undefined; } - Debug.assert(test === undefined || test(visited), "Wrong node type after visit."); + Debug.assert(test === undefined || test(visited), "Wrong node type after visit.", () => `Node ${formatSyntaxKind(visited.kind)} did not pass test ${(test).name}.`); aggregateTransformFlags(visited); return visited; } @@ -717,7 +717,7 @@ namespace ts { from = parenthesize(from, parentNode); } - Debug.assert(test === undefined || test(from), "Wrong node type after visit."); + Debug.assert(test === undefined || test(from), "Wrong node type after visit.", () => `Node ${formatSyntaxKind(from.kind)} did not pass test ${(test).name}.`); if (startOnNewLine) { from.startsOnNewLine = true; @@ -774,7 +774,7 @@ namespace ts { */ export function mergeSourceFileLexicalEnvironment(node: SourceFile, declarations: Statement[]) { if (declarations !== undefined && declarations.length) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.statements = mergeStatements(mutableNode.statements, declarations); return mutableNode; } @@ -791,7 +791,7 @@ namespace ts { export function mergeModuleDeclarationLexicalEnvironment(node: ModuleDeclaration, declarations: Statement[]) { Debug.assert(node.body.kind === SyntaxKind.ModuleBlock); if (declarations !== undefined && declarations.length) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.body = mergeBlockLexicalEnvironment(node.body, declarations); return mutableNode; } @@ -808,7 +808,7 @@ namespace ts { function mergeFunctionLikeLexicalEnvironment(node: FunctionLikeDeclaration, declarations: Statement[]) { Debug.assert(node.body !== undefined); if (declarations !== undefined && declarations.length) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.body = mergeConciseBodyLexicalEnvironment(mutableNode.body, declarations); return mutableNode; } @@ -859,7 +859,7 @@ namespace ts { * @param declarations The lexical declarations to merge. */ function mergeBlockLexicalEnvironment(node: T, declarations: Statement[]) { - const mutableNode = cloneNode(node, /*location*/ node, node.flags, /*parent*/ undefined, /*original*/ node); + const mutableNode = getMutableClone(node); mutableNode.statements = mergeStatements(node.statements, declarations); return mutableNode; }