Skip to content

Commit

Permalink
fix: Fix crashes when dealing with statemented nodes that don't have …
Browse files Browse the repository at this point in the history
…a body.
  • Loading branch information
dsherret committed Sep 15, 2018
1 parent 808198c commit 7a08ab1
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
18 changes: 15 additions & 3 deletions src/compiler/statement/StatementedNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,8 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
insertStatements(index: number, writerFunction: WriterFunction): Statement[];
insertStatements(index: number, textOrWriterFunction: string | WriterFunction): Statement[];
insertStatements(index: number, textOrWriterFunction: string | WriterFunction) {
addBodyIfNotExists(this);

return getChildSyntaxList.call(this).insertChildText(index, textOrWriterFunction);

function getChildSyntaxList(this: Node) {
Expand Down Expand Up @@ -625,7 +627,6 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
}

getFunctions(): FunctionDeclaration[] {
// todo: remove type assertion
return (this.getChildSyntaxListOrThrow().getChildrenOfKind(SyntaxKind.FunctionDeclaration))
.filter(f => f.isAmbient() || f.isImplementation());
}
Expand Down Expand Up @@ -877,8 +878,12 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
// need to get the inner-most body for namespaces
return (this.getInnerBody().compilerNode as ts.Block).statements;
}
else if (TypeGuards.isBodyableNode(this))
return (this.getBodyOrThrow().compilerNode as any).statements as ts.NodeArray<ts.Statement>;
else if (TypeGuards.isBodyableNode(this)) {
const body = this.getBody();
if (body == null)
return [] as any as ts.NodeArray<ts.Statement>;
return (body.compilerNode as any).statements as ts.NodeArray<ts.Statement>;
}
else if (TypeGuards.isBodiedNode(this))
return (this.getBody().compilerNode as any).statements as ts.NodeArray<ts.Statement>;
else if (TypeGuards.isBlock(this))
Expand All @@ -888,6 +893,8 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
}

_insertChildren<TNode extends Node, TStructure>(opts: InsertChildrenOptions<TStructure>) {
addBodyIfNotExists(this);

return insertIntoBracesOrSourceFileWithGetChildren<TNode, TStructure>({
expectedKind: opts.expectedKind,
getIndexedChildren: () => this.getStatements(),
Expand Down Expand Up @@ -918,3 +925,8 @@ export function StatementedNode<T extends Constructor<StatementedNodeExtensionTy
}
};
}

function addBodyIfNotExists(node: Node) {
if (TypeGuards.isBodyableNode(node) && !node.hasBody())
node.addBody();
}
16 changes: 15 additions & 1 deletion src/tests/compiler/statement/statementedNode/classTests.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from "chai";
import { ClassDeclaration, StatementedNode } from "../../../../compiler";
import { FunctionDeclaration, ClassDeclaration, StatementedNode } from "../../../../compiler";
import { ClassDeclarationStructure } from "../../../../structures";
import { getInfoFromText } from "../../testHelpers";

Expand Down Expand Up @@ -87,6 +87,20 @@ describe(nameof(StatementedNode), () => {

expect(sourceFile.getFullText()).to.equal("declare module Namespace {\n class Identifier {\n myMethod();\n }\n}\n");
});

function doFunctionTest(startText: string, endText: string) {
const { firstChild, sourceFile } = getInfoFromText<FunctionDeclaration>(startText);
firstChild.insertClasses(0, [{ name: "C" }]);
expect(sourceFile.getFullText()).to.equal(endText);
}

it("should insert into a function with no body", () => {
doFunctionTest("function test();", "function test() {\n class C {\n }\n}");
});

it("should insert into a function with a body", () => {
doFunctionTest("function test() {\n}", "function test() {\n class C {\n }\n}");
});
});

describe(nameof<StatementedNode>(n => n.insertClass), () => {
Expand Down
9 changes: 9 additions & 0 deletions src/tests/compiler/statement/statementedNodeTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ describe(nameof(StatementedNode), () => {
doFirstChildTest<FunctionDeclaration>("function i() { var t; var m; }", ["var t;", "var m;"]);
});

it("should get the statements of a function with no body", () => {
doFirstChildTest<FunctionDeclaration>("function i();", []);
});

it("should get the statements of a namespace", () => {
doFirstChildTest<NamespaceDeclaration>("namespace n { var t; var m; }", ["var t;", "var m;"]);
});
Expand Down Expand Up @@ -158,6 +162,11 @@ describe(nameof(StatementedNode), () => {
expect(sourceFile.getFullText()).to.equal(expectedCode);
}

it("should insert statements into a function with no body", () => {
doFirstChildTest<FunctionDeclaration>("function i();\n", 0, "statement;", 1,
"function i() {\n statement;\n}\n");
});

it("should insert statements into an empty function", () => {
doFirstChildTest<FunctionDeclaration>("function i() {\n}\n", 0, "statement;", 1,
"function i() {\n statement;\n}\n");
Expand Down

0 comments on commit 7a08ab1

Please sign in to comment.