From 26f8ddd46a7c1dd528f1812bd647b5135118be53 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Mon, 11 Feb 2019 12:01:02 -0800 Subject: [PATCH] create functions for copying trailing comments and rename previous copyComment function --- .../codefixes/convertFunctionToEs6Class.ts | 10 ++--- .../addOrRemoveBracesToArrowFunction.ts | 4 +- src/services/utilities.ts | 43 ++++++++++++++++++- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/services/codefixes/convertFunctionToEs6Class.ts b/src/services/codefixes/convertFunctionToEs6Class.ts index 78e10ce2044..b87a78106ad 100644 --- a/src/services/codefixes/convertFunctionToEs6Class.ts +++ b/src/services/codefixes/convertFunctionToEs6Class.ts @@ -35,7 +35,7 @@ namespace ts.codefix { precedingNode = ctorDeclaration.parent.parent; newClassDeclaration = createClassFromVariableDeclaration(ctorDeclaration as VariableDeclaration); if ((ctorDeclaration.parent).declarations.length === 1) { - copyComments(precedingNode, newClassDeclaration!, sourceFile); // TODO: GH#18217 + copyLeadingComments(precedingNode, newClassDeclaration!, sourceFile); // TODO: GH#18217 changes.delete(sourceFile, precedingNode); } else { @@ -48,7 +48,7 @@ namespace ts.codefix { return undefined; } - copyComments(ctorDeclaration, newClassDeclaration, sourceFile); + copyLeadingComments(ctorDeclaration, newClassDeclaration, sourceFile); // Because the preceding node could be touched, we need to insert nodes before delete nodes. changes.insertNodeAfter(sourceFile, precedingNode!, newClassDeclaration); @@ -112,7 +112,7 @@ namespace ts.codefix { const fullModifiers = concatenate(modifiers, getModifierKindFromSource(functionExpression, SyntaxKind.AsyncKeyword)); const method = createMethod(/*decorators*/ undefined, fullModifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, /*typeParameters*/ undefined, functionExpression.parameters, /*type*/ undefined, functionExpression.body); - copyComments(assignmentBinaryExpression, method, sourceFile); + copyLeadingComments(assignmentBinaryExpression, method, sourceFile); return method; } @@ -132,7 +132,7 @@ namespace ts.codefix { const fullModifiers = concatenate(modifiers, getModifierKindFromSource(arrowFunction, SyntaxKind.AsyncKeyword)); const method = createMethod(/*decorators*/ undefined, fullModifiers, /*asteriskToken*/ undefined, memberDeclaration.name, /*questionToken*/ undefined, /*typeParameters*/ undefined, arrowFunction.parameters, /*type*/ undefined, bodyBlock); - copyComments(assignmentBinaryExpression, method, sourceFile); + copyLeadingComments(assignmentBinaryExpression, method, sourceFile); return method; } @@ -143,7 +143,7 @@ namespace ts.codefix { } const prop = createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined, /*type*/ undefined, assignmentBinaryExpression.right); - copyComments(assignmentBinaryExpression.parent, prop, sourceFile); + copyLeadingComments(assignmentBinaryExpression.parent, prop, sourceFile); return prop; } } diff --git a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts index c5fccde13db..97d6f4d6667 100644 --- a/src/services/refactors/addOrRemoveBracesToArrowFunction.ts +++ b/src/services/refactors/addOrRemoveBracesToArrowFunction.ts @@ -48,13 +48,13 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction { const returnStatement = createReturn(expression); body = createBlock([returnStatement], /* multiLine */ true); suppressLeadingAndTrailingTrivia(body); - copyComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true); + copyLeadingComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true); } else if (actionName === removeBracesActionName && returnStatement) { const actualExpression = expression || createVoidZero(); body = needsParentheses(actualExpression) ? createParen(actualExpression) : actualExpression; suppressLeadingAndTrailingTrivia(body); - copyComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); + copyLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false); } else { Debug.fail("invalid action"); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 2b6d0acde88..46ec160c022 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1831,7 +1831,7 @@ namespace ts { return lastPos; } - export function copyComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { + export function copyLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, (pos, end, kind, htnl) => { if (kind === SyntaxKind.MultiLineCommentTrivia) { // Remove leading /* @@ -1847,6 +1847,47 @@ namespace ts { }); } + export function copyTrailingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { + forEachTrailingCommentRange(sourceFile.text, sourceNode.end, (pos, end, kind, htnl) => { + if (kind === SyntaxKind.MultiLineCommentTrivia) { + // Remove leading /* + pos += 2; + // Remove trailing */ + end -= 2; + } + else { + // Remove leading // + pos += 2; + } + addSyntheticTrailingComment(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl); + }); + } + + /** + * This function copies the trailing comments for the token that comes before `sourceNode`, as leading comments of `targetNode`. + * This is useful because sometimes a comment that refers to `sourceNode` will be a leading comment for `sourceNode`, according to the + * notion of trivia ownership, and instead will be a trailing comment for the token before `sourceNode`, e.g.: + * `function foo(\* not leading comment for a *\ a: string) {}` + * The comment refers to `a` but belongs to the `(` token, but we might want to copy it. + */ + export function copyTrailingAsLeadingComments(sourceNode: Node, targetNode: Node, sourceFile: SourceFile, commentKind?: CommentKind, hasTrailingNewLine?: boolean) { + forEachTrailingCommentRange(sourceFile.text, sourceNode.pos, (pos, end, kind, htnl) => { + if (kind === SyntaxKind.MultiLineCommentTrivia) { + // Remove leading /* + pos += 2; + // Remove trailing */ + end -= 2; + } + else { + // Remove leading // + pos += 2; + } + addSyntheticLeadingComment(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl); + }); + } + + + function indexInTextChange(change: string, name: string): number { if (startsWith(change, name)) return 0; // Add a " " to avoid references inside words