Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ export function TypeArgumentedNode<T extends Constructor<TypeArgumentedNodeExten
index = verifyAndGetIndex(index, typeArguments.length);

if (typeArguments.length === 0) {
const identifier = this.getFirstChildByKindOrThrow(SyntaxKind.Identifier);
// For property access expressions like `this.foo()`, the identifier is nested
// inside the PropertyAccessExpression, not a direct child of the CallExpression
const expression = Node.hasExpression(this) ? this.getExpression() : undefined;
const identifier = Node.isPropertyAccessExpression(expression)
? expression.getLastChildByKindOrThrow(SyntaxKind.Identifier)
: this.getFirstChildByKindOrThrow(SyntaxKind.Identifier);
insertIntoParentTextRange({
insertPos: identifier.getEnd(),
parent: this,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { nameof } from "@ts-morph/common";
import { nameof, SyntaxKind } from "@ts-morph/common";
import { expect } from "chai";
import { ClassDeclaration, TypeArgumentedNode } from "../../../../compiler";
import { CallExpression, ClassDeclaration, TypeArgumentedNode } from "../../../../compiler";
import { getInfoFromText } from "../../testHelpers";

describe("TypeArgumentedNode", () => {
Expand Down Expand Up @@ -86,6 +86,29 @@ describe("TypeArgumentedNode", () => {
it("should add a type arg", () => {
doTest("@dec<1, 2>()\nclass T {}", "3", "@dec<1, 2, 3>()\nclass T {}");
});

// Issue #1228: addTypeArgument crashes on property access expressions
describe("property access expressions", () => {
function doTestPropertyAccess(code: string, text: string, expectedCode: string) {
const { sourceFile } = getInfoFromText(code);
const callExpr = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression)[0];
const result = callExpr.addTypeArgument(text);
expect(result.getText()).to.equal(text);
expect(sourceFile.getFullText()).to.equal(expectedCode);
}

it("should add type argument to property access on this", () => {
doTestPropertyAccess("this.foo();", "string", "this.foo<string>();");
});

it("should add type argument to property access on constructor", () => {
doTestPropertyAccess("new Test().foo();", "string", "new Test().foo<string>();");
});

it("should add type argument to property access on object", () => {
doTestPropertyAccess("obj.method();", "string", "obj.method<string>();");
});
});
});

describe(nameof<TypeArgumentedNode>("removeTypeArgument"), () => {
Expand Down