From db932f9491dabf954367cb11f305165dca4b5921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Thu, 3 Oct 2019 22:07:10 +0200 Subject: [PATCH 01/26] WIP: parser WIP parser: refactor prettier ignore support --- packages/java-parser/src/comments.js | 189 +++++++++------------------ packages/java-parser/src/index.js | 27 +--- packages/java-parser/src/parser.js | 14 +- 3 files changed, 72 insertions(+), 158 deletions(-) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index 19d1c2507..42e264f5a 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -1,89 +1,4 @@ "use strict"; -const _ = require("lodash"); - -function attachComments(tokens, comments) { - const attachComments = [...comments]; - - // edge case: when the file contains only one token (;/if no token then EOF) - if (tokens.length === 1) { - attachComments.forEach(comment => { - if (comment.endOffset < tokens[0].startOffset) { - if (!tokens[0].leadingComments) { - tokens[0].leadingComments = []; - } - tokens[0].leadingComments.push(comment); - } else { - if (!tokens[0].trailingComments) { - tokens[0].trailingComments = []; - } - tokens[0].trailingComments.push(comment); - } - }); - return tokens; - } - - // edge case: when the file start with comments, it attaches as leadingComments to the first token - const firstToken = tokens[0]; - const headComments = []; - while ( - attachComments.length > 0 && - attachComments[0].endOffset < firstToken.startOffset - ) { - headComments.push(attachComments[0]); - attachComments.splice(0, 1); - } - - if (headComments.length > 0) { - firstToken.leadingComments = headComments; - } - - // edge case: when the file end with comments, it attaches as trailingComments to the last token - const lastToken = tokens[tokens.length - 1]; - const tailComments = []; - while ( - attachComments.length > 0 && - attachComments[attachComments.length - 1].startOffset > lastToken.endOffset - ) { - tailComments.push(attachComments[attachComments.length - 1]); - attachComments.splice(attachComments.length - 1, 1); - } - - if (tailComments.length > 0) { - lastToken.trailingComments = tailComments.reverse(); - } - - let currentToken = 0; - attachComments.forEach(element => { - // find the correct position to place the comment - while ( - !( - element.startOffset > tokens[currentToken].endOffset && - element.endOffset < tokens[currentToken + 1].startOffset - ) - ) { - currentToken++; - } - - // attach comment to the next token by default, - // it attaches to the current one when the comment and token is on the same line - if ( - element.startLine === tokens[currentToken].endLine && - element.startLine !== tokens[currentToken + 1].startLine - ) { - if (!tokens[currentToken].trailingComments) { - tokens[currentToken].trailingComments = []; - } - tokens[currentToken].trailingComments.push(element); - } else { - if (!tokens[currentToken + 1].leadingComments) { - tokens[currentToken + 1].leadingComments = []; - } - tokens[currentToken + 1].leadingComments.push(element); - } - }); - - return tokens; -} /** * Search where is the position of the comment in the token array by @@ -113,63 +28,85 @@ function findUpperBoundToken(tokens, comment) { return i; } -/** - * Extends each comments offsets to the left and the right in order to match the - * previous and next token offset. This allow to directly match the prettier-ignore - * comment to the correct CSTNode. - * @param {*} tokens ordered array of tokens - * @param {*} comments array of prettier-ignore comments - * @return prettier-ignore comment array with extended location - */ -function extendCommentRange(tokens, comments) { - const ignoreComments = [...comments]; +function pretraitement(tokens, comments) { + const commentsEndOffset = {}; + const commentsStartOffset = {}; + let position; - ignoreComments.forEach(comment => { + comments.forEach(comment => { position = findUpperBoundToken(tokens, comment); - comment.extendedRange = {}; - comment.extendedRange.startOffset = + const startOffset = position - 1 < 0 ? comment.startOffset : tokens[position - 1].endOffset; - comment.extendedRange.endOffset = + const endOffset = position == tokens.length ? comment.endOffset : tokens[position].startOffset; + + if (commentsEndOffset[endOffset] === undefined) { + commentsEndOffset[endOffset] = [comment]; + } else { + commentsEndOffset[endOffset].push(comment); + } + + if (commentsStartOffset[startOffset] === undefined) { + commentsStartOffset[startOffset] = [comment]; + } else { + commentsStartOffset[startOffset].push(comment); + } }); - return ignoreComments; -} -function filterPrettierIgnore(comments) { - return [...comments].filter(comment => - comment.image.match( - /(\/\/(\s*)prettier-ignore(\s*))|(\/\*(\s*)prettier-ignore(\s*)\*\/)/gm - ) - ); + return { commentsEndOffset, commentsStartOffset }; } -function shouldIgnore(node, comments, ignoredNodes) { - const matchingComment = _.find( - comments, - comment => comment.extendedRange.endOffset === node.location.startOffset +function attachComments(tokens, comments, parser) { + const { commentsStartOffset, commentsEndOffset } = pretraitement( + tokens, + comments ); - if (matchingComment) { - ignoredNodes[matchingComment.startOffset] = node; - } -} + const commentsToAttach = new Set(comments); + + Object.keys(parser.leadingComments).forEach(startOffset => { + if (commentsEndOffset[startOffset] !== undefined) { + parser.leadingComments[startOffset].leadingComments = + commentsEndOffset[startOffset]; + + // prettier ignore support + let ignoreNode = false; + for (let i = 0; i < commentsEndOffset[startOffset].length; i++) { + if ( + commentsEndOffset[startOffset][i].image.match( + /(\/\/(\s*)prettier-ignore(\s*))|(\/\*(\s*)prettier-ignore(\s*)\*\/)/gm + ) + ) { + ignoreNode = true; + } + } + + if (ignoreNode) { + parser.leadingComments[startOffset].ignore = true; + } -function attachIgnoreNodes(ignoreComments, ignoredNodes) { - ignoreComments.forEach(comment => { - if (ignoredNodes[comment.startOffset]) { - ignoredNodes[comment.startOffset].ignore = true; + commentsEndOffset[startOffset].forEach(comment => { + commentsToAttach.delete(comment); + }); } }); -} -function ignoredComments(tokens, comments) { - return extendCommentRange(tokens, filterPrettierIgnore(comments)); + Object.keys(parser.trailingComments).forEach(endOffset => { + if (commentsStartOffset[endOffset] !== undefined) { + const nodeTrailingComments = commentsStartOffset[endOffset].filter( + comment => commentsToAttach.has(comment) + ); + + if (nodeTrailingComments.length > 0) { + parser.trailingComments[ + endOffset + ].trailingComments = nodeTrailingComments; + } + } + }); } module.exports = { - attachComments, - shouldIgnore, - ignoredComments, - attachIgnoreNodes + attachComments }; diff --git a/packages/java-parser/src/index.js b/packages/java-parser/src/index.js index 2f1689c55..818b85a99 100644 --- a/packages/java-parser/src/index.js +++ b/packages/java-parser/src/index.js @@ -1,11 +1,7 @@ "use strict"; const JavaLexer = require("./lexer"); const JavaParser = require("./parser"); -const { - attachComments, - ignoredComments, - attachIgnoreNodes -} = require("./comments"); +const { attachComments } = require("./comments"); const parser = new JavaParser(); const BaseJavaCstVisitor = parser.getBaseCstVisitorConstructor(); @@ -29,13 +25,6 @@ function parse(inputText, entryPoint = "compilationUnit") { parser.input = lexResult.tokens; - // prettier-ignore support - const ignoreComments = ignoredComments( - lexResult.tokens, - lexResult.groups.comments - ); - parser.setIgnoredComments(ignoreComments); - // Automatic CST created when parsing const cst = parser[entryPoint](); @@ -53,19 +42,9 @@ function parse(inputText, entryPoint = "compilationUnit") { ); } - // only comments code support - // https://github.com/jhipster/prettier-java/pull/217 - if (lexResult.tokens.length === 0) { - const EOF = Object.assign({}, cst.children.EOF[0]); - EOF.startOffset = Number.MAX_SAFE_INTEGER; - EOF.endOffset = Number.MAX_SAFE_INTEGER; - cst.children.EOF = [EOF]; - attachComments(cst.children.EOF, lexResult.groups.comments); - } else { - attachComments(lexResult.tokens, lexResult.groups.comments); - } + // TODO: only comments code support - attachIgnoreNodes(ignoreComments, parser.ignoredNodes); + attachComments(lexResult.tokens, lexResult.groups.comments, parser); return cst; } diff --git a/packages/java-parser/src/parser.js b/packages/java-parser/src/parser.js index 3c18d1ff1..9f2be80e3 100644 --- a/packages/java-parser/src/parser.js +++ b/packages/java-parser/src/parser.js @@ -10,7 +10,6 @@ const interfaces = require("./productions/interfaces"); const arrays = require("./productions/arrays"); const blocksStatements = require("./productions/blocks-and-statements"); const expressions = require("./productions/expressions"); -const { shouldIgnore } = require("./comments"); /** * This parser attempts to strongly align with the specs style at: @@ -45,8 +44,9 @@ class JavaParser extends Parser { }); const $ = this; - this.ignoreNodes = {}; - this.ignoreComments = []; + + this.leadingComments = {}; + this.trailingComments = {}; // --------------------- // Productions from §3 (Lexical Structure) @@ -79,6 +79,9 @@ class JavaParser extends Parser { super.cstPostNonTerminal(ruleCstResult, ruleName); if (this.isBackTracking() === false) { shouldIgnore(ruleCstResult, this.ignoredComments, this.ignoredNodes); + + this.leadingComments[ruleCstResult.location.startOffset] = ruleCstResult; + this.trailingComments[ruleCstResult.location.endOffset] = ruleCstResult; } } @@ -103,11 +106,6 @@ class JavaParser extends Parser { } }); } - - setIgnoredComments(comments) { - this.ignoredNodes = {}; - this.ignoredComments = [...comments]; - } } module.exports = JavaParser; From 2406982244cb10fa8ff59dfbd7e63ff226194484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 08:46:43 +0200 Subject: [PATCH 02/26] edge case: comments only --- packages/java-parser/src/comments.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index 42e264f5a..b8a48fae3 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -59,6 +59,12 @@ function pretraitement(tokens, comments) { } function attachComments(tokens, comments, parser) { + // Edge case: only comments + if (tokens.length === 0) { + parser.leadingComments[NaN].leadingComments = comments; + return; + } + const { commentsStartOffset, commentsEndOffset } = pretraitement( tokens, comments @@ -105,6 +111,8 @@ function attachComments(tokens, comments, parser) { } } }); + + // console.log(commentsToAttach); } module.exports = { From 03be6f994e4ca6d58c26524495de4e0ebeb3d638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 08:58:10 +0200 Subject: [PATCH 03/26] attach non attached comments to tokens --- packages/java-parser/src/comments.js | 34 +++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index b8a48fae3..d9d5fa388 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -112,7 +112,39 @@ function attachComments(tokens, comments, parser) { } }); - // console.log(commentsToAttach); + attachRestCommentsToToken(tokens, commentsToAttach); +} + +function attachRestCommentsToToken(tokens, commentsToAttach) { + let currentToken = 0; + commentsToAttach.forEach(comment => { + // find the correct position to place the comment + while ( + !( + comment.startOffset > tokens[currentToken].endOffset && + comment.endOffset < tokens[currentToken + 1].startOffset + ) + ) { + currentToken++; + } + + // attach comment to the next token by default, + // it attaches to the current one when the comment and token is on the same line + if ( + comment.startLine === tokens[currentToken].endLine && + comment.startLine !== tokens[currentToken + 1].startLine + ) { + if (!tokens[currentToken].trailingComments) { + tokens[currentToken].trailingComments = []; + } + tokens[currentToken].trailingComments.push(comment); + } else { + if (!tokens[currentToken + 1].leadingComments) { + tokens[currentToken + 1].leadingComments = []; + } + tokens[currentToken + 1].leadingComments.push(comment); + } + }); } module.exports = { From 3ce39a1532080ea0b37444b1e07cd2dc68d37979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 09:40:06 +0200 Subject: [PATCH 04/26] fix --- packages/java-parser/src/comments.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index d9d5fa388..b1981b9a1 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -109,6 +109,10 @@ function attachComments(tokens, comments, parser) { endOffset ].trailingComments = nodeTrailingComments; } + + nodeTrailingComments.forEach(comment => { + commentsToAttach.delete(comment); + }); } }); From 298244a6a8592f712f9b1907d0001b965aa81cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Thu, 3 Oct 2019 22:55:37 +0200 Subject: [PATCH 05/26] WIP printer --- packages/prettier-plugin-java/src/comments.js | 76 +++++++++++++++++++ .../prettier-plugin-java/src/cst-printer.js | 5 +- .../src/printers/prettier-builder.js | 9 +-- 3 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 packages/prettier-plugin-java/src/comments.js diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js new file mode 100644 index 000000000..5f145fb7b --- /dev/null +++ b/packages/prettier-plugin-java/src/comments.js @@ -0,0 +1,76 @@ +"use strict"; +const { concat } = require("./printers/prettier-builder"); +const { hardline } = require("prettier").doc.builders; + +function processComments(ctx, value) { + if (!Array.isArray(ctx)) { + return processComentsOnNode(ctx, value); + } + + return concat( + ctx.map(elt => { + return processComentsOnNode(elt, value); + }) + ); +} + +function processComentsOnNode(node, value) { + const arr = []; + if (Object.prototype.hasOwnProperty.call(node, "leadingComments")) { + node.leadingComments.forEach(element => { + if (element.startLine !== node.location.startLine) { + arr.push(concat(formatComment(element))); + arr.push(hardline); + } else { + arr.push(concat(formatComment(element))); + } + }); + } + + arr.push(value); + + if (Object.prototype.hasOwnProperty.call(node, "trailingComments")) { + if (node.trailingComments[0].startLine !== node.location.startLine) { + arr.push(hardline); + } + node.trailingComments.forEach(element => { + if (element.startLine !== node.location.startLine) { + arr.push(concat(formatComment(element))); + arr.push(hardline); + } else if (element.tokenType.tokenName === "LineComment") { + // Do not add extra space in case of empty statement + const separator = " "; + arr.push(concat([separator, concat(formatComment(element))])); + } else { + arr.push(concat(formatComment(element))); + } + }); + if ( + node.trailingComments[node.trailingComments.length - 1].startLine !== + node.location.startLine + ) { + arr.pop(); + } + } + return concat(arr); +} + +function formatComment(comment) { + const res = []; + comment.image.split("\n").forEach(l => { + if (l.match(/(\s+)(\*)(.*)/gm) && !l.match(/(\/)(\*)(.*)(\*)(\/)/gm)) { + res.push(" " + l.trim()); + } else { + res.push(l); + } + res.push(hardline); + }); + if (res[res.length - 1] === hardline) { + res.pop(); + } + return res; +} + +module.exports = { + processComments +}; diff --git a/packages/prettier-plugin-java/src/cst-printer.js b/packages/prettier-plugin-java/src/cst-printer.js index d061622b1..55f4abb90 100644 --- a/packages/prettier-plugin-java/src/cst-printer.js +++ b/packages/prettier-plugin-java/src/cst-printer.js @@ -23,6 +23,8 @@ const { getCSTNodeStartEndToken } = require("./printers/printer-utils"); +const { processComments } = require("./comments"); + class CstPrettierPrinter extends BaseJavaCstVisitor { constructor() { super(); @@ -91,7 +93,8 @@ class CstPrettierPrinter extends BaseJavaCstVisitor { } } - return orgVisit.call(this, ctx, inParam); + // return orgVisit.call(this, ctx, inParam); + return processComments(ctx, orgVisit.call(this, ctx, inParam)); }; } } diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index ed60349ef..43d9c9b6b 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -4,11 +4,7 @@ const prettier = require("prettier").doc.builders; const hardLineWithoutBreakParent = { type: "line", hard: true }; function getImageWithComments(token) { - return concat([ - getLeadingComments(token), - token.image, - getTrailingComments(token) - ]); + return token.image; } function getLeadingComments(token) { @@ -168,5 +164,6 @@ module.exports = { getImageWithComments, getLeadingComments, getTrailingComments, - hardLineWithoutBreakParent + hardLineWithoutBreakParent, + formatComment }; From 57404b5cdbfdbe090879c4466bc957274da8880e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 10:36:40 +0200 Subject: [PATCH 06/26] WIP printer --- packages/prettier-plugin-java/src/comments.js | 7 +++- .../src/printers/classes.js | 5 +-- .../src/printers/expressions.js | 1 + .../src/printers/interfaces.js | 5 +-- .../src/printers/prettier-builder.js | 34 +++++++++---------- .../src/printers/printer-utils.js | 8 +++-- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index 5f145fb7b..bf9fa69dd 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -7,6 +7,10 @@ function processComments(ctx, value) { return processComentsOnNode(ctx, value); } + if (ctx.length === 1) { + return processComentsOnNode(ctx[0], value); + } + return concat( ctx.map(elt => { return processComentsOnNode(elt, value); @@ -52,7 +56,8 @@ function processComentsOnNode(node, value) { arr.pop(); } } - return concat(arr); + + return arr.length === 1 ? value : concat(arr); } function formatComment(comment) { diff --git a/packages/prettier-plugin-java/src/printers/classes.js b/packages/prettier-plugin-java/src/printers/classes.js index 3f20260c2..ff07511ac 100644 --- a/packages/prettier-plugin-java/src/printers/classes.js +++ b/packages/prettier-plugin-java/src/printers/classes.js @@ -356,8 +356,9 @@ class ClassesPrettierVisitor { const headerBodySeparator = body !== undefined && body.type === "concat" && - body.parts && - body.parts.includes(";") + body.parts.length === 1 && + body.parts[0].type === "concat" && + body.parts[0].parts[0] === ";" ? "" : " "; diff --git a/packages/prettier-plugin-java/src/printers/expressions.js b/packages/prettier-plugin-java/src/printers/expressions.js index 5ab1e0b65..ad6564088 100644 --- a/packages/prettier-plugin-java/src/printers/expressions.js +++ b/packages/prettier-plugin-java/src/printers/expressions.js @@ -11,6 +11,7 @@ const { } = require("./prettier-builder"); const { matchCategory, + reject, rejectAndJoin, rejectAndConcat, sortAnnotationIdentifier, diff --git a/packages/prettier-plugin-java/src/printers/interfaces.js b/packages/prettier-plugin-java/src/printers/interfaces.js index 063633438..2723f8a8a 100644 --- a/packages/prettier-plugin-java/src/printers/interfaces.js +++ b/packages/prettier-plugin-java/src/printers/interfaces.js @@ -145,8 +145,9 @@ class InterfacesPrettierVisitor { const separator = methodBody !== undefined && methodBody.type === "concat" && - methodBody.parts && - methodBody.parts.includes(";") + methodBody.parts.length === 1 && + methodBody.parts[0].type === "concat" && + methodBody.parts[0].parts[0] === ";" ? "" : " "; diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index 43d9c9b6b..6f81d4e4c 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -1,10 +1,11 @@ "use strict"; const prettier = require("prettier").doc.builders; -const hardLineWithoutBreakParent = { type: "line", hard: true }; - function getImageWithComments(token) { - return token.image; + const leadingComments = getLeadingComments(token); + const trailingComments = getTrailingComments(token); + + return concat([leadingComments, token.image, trailingComments]); } function getLeadingComments(token) { @@ -14,7 +15,7 @@ function getLeadingComments(token) { if (element.startLine !== token.startLine) { arr.push(prettier.lineSuffixBoundary); arr.push(concat(formatComment(element))); - arr.push(hardLineWithoutBreakParent); + arr.push(prettier.hardline); } else { arr.push(concat(formatComment(element))); } @@ -28,12 +29,12 @@ function getTrailingComments(token) { const arr = []; if (Object.prototype.hasOwnProperty.call(token, "trailingComments")) { if (token.trailingComments[0].startLine !== token.startLine) { - arr.push(hardLineWithoutBreakParent); + arr.push(prettier.hardline); } token.trailingComments.forEach(element => { if (element.startLine !== token.startLine) { arr.push(concat(formatComment(element))); - arr.push(hardLineWithoutBreakParent); + arr.push(prettier.hardline); } else if (element.tokenType.name === "LineComment") { // Do not add extra space in case of empty statement const separator = token.image === "" ? "" : " "; @@ -86,17 +87,17 @@ function formatJavaDoc(lines) { function formatComment(comment) { const res = []; - const lines = comment.image.split("\n"); - - if (isJavaDoc(comment, lines)) { - return formatJavaDoc(lines); - } - - lines.forEach(line => { - res.push(line); - res.push(prettier.literalline); + comment.image.split("\n").forEach(l => { + if (l.match(/(\s+)(\*)(.*)/gm) && !l.match(/(\/)(\*)(.*)(\*)(\/)/gm)) { + res.push(" " + l.trim()); + } else { + res.push(l); + } + res.push(prettier.hardline); }); - res.pop(); + if (res[res.length - 1] === prettier.hardline) { + res.pop(); + } return res; } @@ -164,6 +165,5 @@ module.exports = { getImageWithComments, getLeadingComments, getTrailingComments, - hardLineWithoutBreakParent, formatComment }; diff --git a/packages/prettier-plugin-java/src/printers/printer-utils.js b/packages/prettier-plugin-java/src/printers/printer-utils.js index 79b5265ca..8d2cf6da7 100644 --- a/packages/prettier-plugin-java/src/printers/printer-utils.js +++ b/packages/prettier-plugin-java/src/printers/printer-utils.js @@ -31,6 +31,9 @@ function rejectAndJoinSeps(sepTokens, elems, sep) { function reject(elems) { return elems.filter(item => { + if (typeof item === "string") { + return item !== ""; + } // eslint-ignore next - We want the conversion to boolean! return item != false && item !== undefined; }); @@ -526,8 +529,9 @@ function getCSTNodeStartEndToken(ctx) { function isStatementEmptyStatement(statement) { return ( statement.type === "concat" && - statement.parts[0] === "" && - statement.parts[1] === ";" + statement.parts[0].type === "concat" && + statement.parts[0].parts[0].type === "concat" && + statement.parts[0].parts[0].parts[0] === ";" ); } From 216c94a31e9414a73ae39eb2eb3139458fa35eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 11:14:59 +0200 Subject: [PATCH 07/26] WIP printer --- .../prettier-plugin-java/src/printers/classes.js | 14 ++++---------- .../src/printers/interfaces.js | 12 +++--------- .../src/printers/prettier-builder.js | 4 +++- .../src/printers/printer-utils.js | 6 ++---- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/packages/prettier-plugin-java/src/printers/classes.js b/packages/prettier-plugin-java/src/printers/classes.js index ff07511ac..dd075c4e4 100644 --- a/packages/prettier-plugin-java/src/printers/classes.js +++ b/packages/prettier-plugin-java/src/printers/classes.js @@ -12,7 +12,8 @@ const { displaySemicolon, putIntoBraces, putIntoCurlyBraces, - getClassBodyDeclarationsSeparator + getClassBodyDeclarationsSeparator, + isStatementEmptyStatement } = require("./printer-utils"); const { concat, @@ -353,14 +354,8 @@ class ClassesPrettierVisitor { const header = this.visit(ctx.methodHeader); const body = this.visit(ctx.methodBody); - const headerBodySeparator = - body !== undefined && - body.type === "concat" && - body.parts.length === 1 && - body.parts[0].type === "concat" && - body.parts[0].parts[0] === ";" - ? "" - : " "; + + const headerBodySeparator = isStatementEmptyStatement(body) ? "" : " "; return rejectAndJoin(hardline, [ rejectAndJoin(hardline, firstAnnotations), @@ -605,7 +600,6 @@ class ClassesPrettierVisitor { const argumentList = this.visit(ctx.argumentList); return rejectAndConcat([ typeArguments, - " ", keyWord, group( rejectAndConcat([ diff --git a/packages/prettier-plugin-java/src/printers/interfaces.js b/packages/prettier-plugin-java/src/printers/interfaces.js index 2723f8a8a..d4c2038e9 100644 --- a/packages/prettier-plugin-java/src/printers/interfaces.js +++ b/packages/prettier-plugin-java/src/printers/interfaces.js @@ -16,7 +16,8 @@ const { getInterfaceBodyDeclarationsSeparator, putIntoBraces, putIntoCurlyBraces, - displaySemicolon + displaySemicolon, + isStatementEmptyStatement } = require("./printer-utils"); class InterfacesPrettierVisitor { @@ -142,14 +143,7 @@ class InterfacesPrettierVisitor { const methodHeader = this.visit(ctx.methodHeader); const methodBody = this.visit(ctx.methodBody); - const separator = - methodBody !== undefined && - methodBody.type === "concat" && - methodBody.parts.length === 1 && - methodBody.parts[0].type === "concat" && - methodBody.parts[0].parts[0] === ";" - ? "" - : " "; + const separator = isStatementEmptyStatement(methodBody) ? "" : " "; return rejectAndJoin(hardline, [ rejectAndJoin(hardline, firstAnnotations), diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index 6f81d4e4c..afece624d 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -5,7 +5,9 @@ function getImageWithComments(token) { const leadingComments = getLeadingComments(token); const trailingComments = getTrailingComments(token); - return concat([leadingComments, token.image, trailingComments]); + return leadingComments === "" && trailingComments === "" + ? token.image + : concat([leadingComments, token.image, trailingComments]); } function getLeadingComments(token) { diff --git a/packages/prettier-plugin-java/src/printers/printer-utils.js b/packages/prettier-plugin-java/src/printers/printer-utils.js index 8d2cf6da7..c05dccfe7 100644 --- a/packages/prettier-plugin-java/src/printers/printer-utils.js +++ b/packages/prettier-plugin-java/src/printers/printer-utils.js @@ -528,10 +528,8 @@ function getCSTNodeStartEndToken(ctx) { function isStatementEmptyStatement(statement) { return ( - statement.type === "concat" && - statement.parts[0].type === "concat" && - statement.parts[0].parts[0].type === "concat" && - statement.parts[0].parts[0].parts[0] === ";" + statement === ";" || + (statement.type === "concat" && statement.parts[0] === ";") ); } From d30c60a520fefa3ecd85728418c63f46901f5a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 11:49:44 +0200 Subject: [PATCH 08/26] fix parser --- packages/java-parser/src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/java-parser/src/index.js b/packages/java-parser/src/index.js index 818b85a99..78932e037 100644 --- a/packages/java-parser/src/index.js +++ b/packages/java-parser/src/index.js @@ -24,6 +24,8 @@ function parse(inputText, entryPoint = "compilationUnit") { } parser.input = lexResult.tokens; + parser.leadingComments = {}; + parser.trailingComments = {}; // Automatic CST created when parsing const cst = parser[entryPoint](); From 3fcb89323b0b23ca88c2c33ada94b9fb57aa608d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 11:52:01 +0200 Subject: [PATCH 09/26] clean comment --- packages/java-parser/src/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/java-parser/src/index.js b/packages/java-parser/src/index.js index 78932e037..6e7377078 100644 --- a/packages/java-parser/src/index.js +++ b/packages/java-parser/src/index.js @@ -44,8 +44,6 @@ function parse(inputText, entryPoint = "compilationUnit") { ); } - // TODO: only comments code support - attachComments(lexResult.tokens, lexResult.groups.comments, parser); return cst; From 6b4a450508ac9cbaafb37079611c1d5533a5c7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 12:02:52 +0200 Subject: [PATCH 10/26] fix prettier ignore print --- .../prettier-plugin-java/src/cst-printer.js | 21 ++++---- .../src/printers/printer-utils.js | 50 ------------------- 2 files changed, 10 insertions(+), 61 deletions(-) diff --git a/packages/prettier-plugin-java/src/cst-printer.js b/packages/prettier-plugin-java/src/cst-printer.js index 55f4abb90..c5ce879e0 100644 --- a/packages/prettier-plugin-java/src/cst-printer.js +++ b/packages/prettier-plugin-java/src/cst-printer.js @@ -18,11 +18,6 @@ const { const { PackagesAndModulesPrettierVisitor } = require("./printers/packages-and-modules"); -const { - buildOriginalText, - getCSTNodeStartEndToken -} = require("./printers/printer-utils"); - const { processComments } = require("./comments"); class CstPrettierPrinter extends BaseJavaCstVisitor { @@ -79,12 +74,16 @@ class CstPrettierPrinter extends BaseJavaCstVisitor { if (ctx.ignore) { try { - const startEndTokens = getCSTNodeStartEndToken(ctx); - return buildOriginalText( - startEndTokens[0], - startEndTokens[1], - this.originalText - ); + const startOffset = + ctx.leadingComments !== undefined + ? ctx.leadingComments[0].startOffset + : ctx.location.startOffset; + const endOffset = + ctx.trailingComments !== undefined + ? ctx.trailingComments[ctx.trailingComments.length - 1].endOffset + : ctx.location.endOffset; + + return this.originalText.substring(startOffset, endOffset + 1); } catch (e) { throw Error( e + diff --git a/packages/prettier-plugin-java/src/printers/printer-utils.js b/packages/prettier-plugin-java/src/printers/printer-utils.js index c05dccfe7..49dc21316 100644 --- a/packages/prettier-plugin-java/src/printers/printer-utils.js +++ b/packages/prettier-plugin-java/src/printers/printer-utils.js @@ -478,54 +478,6 @@ function retrieveNodesTokenRec(ctx) { return tokens; } -function buildOriginalText(firstToken, lastToken, originalText) { - let startOffset = firstToken.startOffset; - let endOffset = lastToken.endOffset; - if (firstToken.leadingComments) { - startOffset = firstToken.leadingComments[0].startOffset; - } - if (lastToken.trailingComments) { - endOffset = - lastToken.trailingComments[lastToken.trailingComments.length - 1] - .endOffset; - } - return originalText.substring(startOffset, endOffset + 1); -} - -function getCSTNodeStartEndToken(ctx) { - const tokens = []; - if ( - ctx && - Object.prototype.hasOwnProperty.call(ctx, "image") && - ctx.tokenType - ) { - return [ctx, ctx]; - } - Object.keys(ctx.children).forEach(child => { - ctx.children[child].forEach(subctx => { - const subStartEndToken = getCSTNodeStartEndToken(subctx); - if (subStartEndToken) { - tokens.push(subStartEndToken); - } - }); - }); - if (tokens.length === 0) { - return; - } - const startEndTokens = tokens.reduce((tokenArr1, tokenArr2) => { - const ftoken = - tokenArr1[0].startOffset - tokenArr2[0].startOffset < 0 - ? tokenArr1[0] - : tokenArr2[0]; - const ltoken = - tokenArr2[1].startOffset - tokenArr1[1].startOffset < 0 - ? tokenArr1[1] - : tokenArr2[1]; - return [ftoken, ltoken]; - }); - return startEndTokens; -} - function isStatementEmptyStatement(statement) { return ( statement === ";" || @@ -627,8 +579,6 @@ module.exports = { separateTokensIntoGroups, isShiftOperator, retrieveNodesToken, - buildOriginalText, - getCSTNodeStartEndToken, isStatementEmptyStatement, sortImports, isUniqueMethodInvocation From 464cd25f0c54157f5f8d211a4f4390bb35d550e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Fri, 4 Oct 2019 13:37:55 +0200 Subject: [PATCH 11/26] WIP printer --- packages/java-parser/src/comments.js | 92 +++++++++++++------ packages/prettier-plugin-java/src/comments.js | 44 +++++---- .../src/printers/packages-and-modules.js | 8 +- .../_output.java | 12 ++- .../comments/comments-only/_output.java | 1 - .../unit-test/comments/interface/_output.java | 2 +- .../unit-test/comments/package/_output.java | 10 +- .../unit-test/empty_statement/_output.java | 6 +- .../classDeclaration/_output.java | 2 +- 9 files changed, 109 insertions(+), 68 deletions(-) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index b1981b9a1..2fa4463fb 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -28,6 +28,12 @@ function findUpperBoundToken(tokens, comment) { return i; } +function isPrettierIgnoreComment(comment) { + return comment.image.match( + /(\/\/(\s*)prettier-ignore(\s*))|(\/\*(\s*)prettier-ignore(\s*)\*\/)/gm + ); +} + function pretraitement(tokens, comments) { const commentsEndOffset = {}; const commentsStartOffset = {}; @@ -41,6 +47,9 @@ function pretraitement(tokens, comments) { position == tokens.length ? comment.endOffset : tokens[position].startOffset; + comment.extendedOffset = { + endOffset + }; if (commentsEndOffset[endOffset] === undefined) { commentsEndOffset[endOffset] = [comment]; @@ -58,6 +67,30 @@ function pretraitement(tokens, comments) { return { commentsEndOffset, commentsStartOffset }; } +function shouldAttachTrailingComments(comment, node, parser) { + if (isPrettierIgnoreComment(comment)) { + return false; + } + + const nextNode = parser.leadingComments[comment.extendedOffset.endOffset]; + if (nextNode === undefined) { + return true; + } + + if (comment.startLine !== node.location.endLine) { + return false; + } + + if ( + nextNode !== undefined && + comment.endLine === nextNode.location.startLine + ) { + return false; + } + + return true; +} + function attachComments(tokens, comments, parser) { // Edge case: only comments if (tokens.length === 0) { @@ -71,46 +104,53 @@ function attachComments(tokens, comments, parser) { ); const commentsToAttach = new Set(comments); - Object.keys(parser.leadingComments).forEach(startOffset => { - if (commentsEndOffset[startOffset] !== undefined) { - parser.leadingComments[startOffset].leadingComments = - commentsEndOffset[startOffset]; - - // prettier ignore support - let ignoreNode = false; - for (let i = 0; i < commentsEndOffset[startOffset].length; i++) { - if ( - commentsEndOffset[startOffset][i].image.match( - /(\/\/(\s*)prettier-ignore(\s*))|(\/\*(\s*)prettier-ignore(\s*)\*\/)/gm - ) - ) { - ignoreNode = true; + Object.keys(parser.trailingComments).forEach(endOffset => { + if (commentsStartOffset[endOffset] !== undefined) { + const nodeTrailingComments = commentsStartOffset[endOffset].filter( + comment => { + return ( + shouldAttachTrailingComments( + comment, + parser.trailingComments[endOffset], + parser + ) && commentsToAttach.has(comment) + ); } - } + ); - if (ignoreNode) { - parser.leadingComments[startOffset].ignore = true; + if (nodeTrailingComments.length > 0) { + parser.trailingComments[ + endOffset + ].trailingComments = nodeTrailingComments; } - commentsEndOffset[startOffset].forEach(comment => { + nodeTrailingComments.forEach(comment => { commentsToAttach.delete(comment); }); } }); - Object.keys(parser.trailingComments).forEach(endOffset => { - if (commentsStartOffset[endOffset] !== undefined) { - const nodeTrailingComments = commentsStartOffset[endOffset].filter( + Object.keys(parser.leadingComments).forEach(startOffset => { + if (commentsEndOffset[startOffset] !== undefined) { + const nodeLeadingComments = commentsEndOffset[startOffset].filter( comment => commentsToAttach.has(comment) ); - if (nodeTrailingComments.length > 0) { - parser.trailingComments[ - endOffset - ].trailingComments = nodeTrailingComments; + parser.leadingComments[startOffset].leadingComments = nodeLeadingComments; + + // prettier ignore support + let ignoreNode = false; + for (let i = 0; i < nodeLeadingComments.length; i++) { + if (isPrettierIgnoreComment(nodeLeadingComments[i])) { + ignoreNode = true; + } } - nodeTrailingComments.forEach(comment => { + if (ignoreNode) { + parser.leadingComments[startOffset].ignore = true; + } + + nodeLeadingComments.forEach(comment => { commentsToAttach.delete(comment); }); } diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index bf9fa69dd..49c8dca1d 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -1,6 +1,6 @@ "use strict"; const { concat } = require("./printers/prettier-builder"); -const { hardline } = require("prettier").doc.builders; +const { hardline, lineSuffix } = require("prettier").doc.builders; function processComments(ctx, value) { if (!Array.isArray(ctx)) { @@ -21,42 +21,40 @@ function processComments(ctx, value) { function processComentsOnNode(node, value) { const arr = []; if (Object.prototype.hasOwnProperty.call(node, "leadingComments")) { - node.leadingComments.forEach(element => { - if (element.startLine !== node.location.startLine) { - arr.push(concat(formatComment(element))); + node.leadingComments.forEach(comment => { + if (comment.endLine !== node.location.startLine) { + arr.push(concat(formatComment(comment))); arr.push(hardline); } else { - arr.push(concat(formatComment(element))); + arr.push(concat(formatComment(comment))); } }); } arr.push(value); + let previousEndLine = node.location.endLine; if (Object.prototype.hasOwnProperty.call(node, "trailingComments")) { - if (node.trailingComments[0].startLine !== node.location.startLine) { - arr.push(hardline); - } - node.trailingComments.forEach(element => { - if (element.startLine !== node.location.startLine) { - arr.push(concat(formatComment(element))); + node.trailingComments.forEach((comment, idx) => { + let separator = ""; + + if (comment.startLine !== previousEndLine) { arr.push(hardline); - } else if (element.tokenType.tokenName === "LineComment") { - // Do not add extra space in case of empty statement - const separator = " "; - arr.push(concat([separator, concat(formatComment(element))])); + } else if (value !== "" && idx === 0) { + separator = " "; + } + + if (comment.tokenType.name == "LineComment") { + arr.push( + lineSuffix(concat([separator, concat(formatComment(comment))])) + ); } else { - arr.push(concat(formatComment(element))); + arr.push(concat(formatComment(comment))); } + + previousEndLine = comment.endLine; }); - if ( - node.trailingComments[node.trailingComments.length - 1].startLine !== - node.location.startLine - ) { - arr.pop(); - } } - return arr.length === 1 ? value : concat(arr); } diff --git a/packages/prettier-plugin-java/src/printers/packages-and-modules.js b/packages/prettier-plugin-java/src/printers/packages-and-modules.js index 52bb1b8bf..919b227ee 100644 --- a/packages/prettier-plugin-java/src/printers/packages-and-modules.js +++ b/packages/prettier-plugin-java/src/printers/packages-and-modules.js @@ -18,7 +18,12 @@ class PackagesAndModulesPrettierVisitor { compilationUnit(ctx) { const compilationUnit = ctx.ordinaryCompilationUnit || ctx.modularCompilationUnit; - return concat([this.visit(compilationUnit[0]), ctx.EOF[0]]); + + // Do not add additional line if only comments in file + const additionalLine = isNaN(compilationUnit[0].location.startOffset) + ? "" + : line; + return concat([this.visit(compilationUnit[0]), additionalLine]); } ordinaryCompilationUnit(ctx) { @@ -29,7 +34,6 @@ class PackagesAndModulesPrettierVisitor { const staticImports = this.mapVisit(sortedImportsDecl.staticImports); const typesDecl = this.mapVisit(ctx.typeDeclaration); - // TODO: utility to add item+line (or multiple lines) but only if an item exists return rejectAndConcat([ rejectAndJoin(concat([hardline, hardline]), [ diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java index 9e03bb108..ccb11e8d6 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java @@ -40,10 +40,11 @@ private void myFunction( 2 }; - loop: // Label statement + loop:// Label statement //foreach - for (int num /* num is every number in arr*/: arr) { - /*switch*/switch (num) { //switch + for (int num/* num is every number in arr*/ : arr) { + /*switch*/switch (num) { + //switch case 1: System.out.println("One "); System.out.println("One "); @@ -65,13 +66,14 @@ private void myFunction( } private synchronized void myFunction(int arg1, int arg2/*overloading*/) { - for (int i = 0; i < /*=*/arg1; i++) do /*dodododo*/{ //do whiles + for (int i = 0; i < /*=*/arg1; i++) do /*dodododo*/{ + //do whiles //asserting assert /*true*/true == true; continue; break/*dead code*/; return/*dead code*/; - } /*at least one iteration !*/while (false); + }/*at least one iteration !*/ while (false); synchronized /*declares synchronizd statement*/(this) { while /*infinite*/(true) /*stop the program*/throw new RuntimeException(); } diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-only/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-only/_output.java index 648a96e9b..89cd6c766 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-only/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-only/_output.java @@ -1,4 +1,3 @@ - /* * # Copyright 2013-2019 the original author or authors from the JHipster project. * # diff --git a/packages/prettier-plugin-java/test/unit-test/comments/interface/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/interface/_output.java index 0e4df7e51..abc184250 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/interface/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/interface/_output.java @@ -19,5 +19,5 @@ public void myMethodInterface( /*b*//*a*/Param2 /*b*//*a*/p2/*b*/, Param3 p3 ) - /*a*/throws /*b*/Exception/*a*/, /*b*/RuntimeException/*a*/;/*b*/ + /*a*/throws /*b*/Exception/*a*/, /*b*/RuntimeException /*a*/;/*b*/ } diff --git a/packages/prettier-plugin-java/test/unit-test/comments/package/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/package/_output.java index 096340d02..3f1bba26f 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/package/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/package/_output.java @@ -2,14 +2,12 @@ /*a*/requires /*a*/java.desktopa/*a*/;/*b*/ requires soat.vending.machine.model; requires /*a*/transitive /*b*/soat.core; - /*a*/exports /*b*/fr.soat.vending.machine.model - /*a*/to /*b*/another/*a*/, /*b*/again/*c*/, /*d*/ano/*a*/;/*b*/ + /*a*/exports /*b*/fr.soat.vending.machine.model/*a*/ + to /*b*/another/*a*/, /*b*/again/*c*/, /*d*/ano/*a*/;/*b*/ // opens - /*a*/opens /*b*/fr.soat.vending.machine.model /*a*/to - /*b*/another/*a*/, - /*b*/again/*c*/, - /*d*/ano/*a*/;/*b*/ + /*a*/opens /*b*/fr.soat.vending.machine.model/*a*/ + to /*b*/another/*a*/, /*b*/again/*c*/, /*d*/ano/*a*/;/*b*/ // uses /*a*/uses /*b*/fr.soat.vendinga/*a*/./*b*/machine.services.DrinksService/*a*/;/*b*/ diff --git a/packages/prettier-plugin-java/test/unit-test/empty_statement/_output.java b/packages/prettier-plugin-java/test/unit-test/empty_statement/_output.java index 2e48d4361..57501a9c3 100644 --- a/packages/prettier-plugin-java/test/unit-test/empty_statement/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/empty_statement/_output.java @@ -53,7 +53,7 @@ public void ifElseWithEmptyStatementsWithComments() { System.out.println("one"); } - if (test); /*test*/else { + if (test);/*test*/ else { System.out.println("one"); } @@ -65,7 +65,7 @@ public void ifElseWithEmptyStatementsWithComments() { System.out.println("two"); } else;/*test*/ - if (test); /*test*/else;/*test*/ + if (test);/*test*/ else;/*test*/ if (test) /*test*/; else /*test*/; } @@ -81,6 +81,6 @@ public void simpleWhileWithEmptyStatement(boolean one) { public void doWhileWithEmptyStatement(boolean one) { do; while (one); do /*test*/; while (one); - do; /*test*/while (one); + do;/*test*/ while (one); } } diff --git a/packages/prettier-plugin-java/test/unit-test/prettier-ignore/classDeclaration/_output.java b/packages/prettier-plugin-java/test/unit-test/prettier-ignore/classDeclaration/_output.java index 436a75470..70b38d465 100644 --- a/packages/prettier-plugin-java/test/unit-test/prettier-ignore/classDeclaration/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/prettier-ignore/classDeclaration/_output.java @@ -3,4 +3,4 @@ public class PrettierIgnoreClass { public void myMethod(int param1, int param2, int param3, int param4, int param5, int param6, int param7, int param8, int param9, int param10) { } -} \ No newline at end of file +} From 2c02d5580243f85e07c662ff78230595d7ae8e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Sat, 5 Oct 2019 01:39:48 +0200 Subject: [PATCH 12/26] add unit tests --- .../test/unit-test/comments/class/_input.java | 19 +++++++++++- .../unit-test/comments/class/_output.java | 29 ++++++++++++++++++ .../test/unit-test/switch/_input.java | 30 +++++++++++++++++++ .../test/unit-test/switch/_output.java | 30 +++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) diff --git a/packages/prettier-plugin-java/test/unit-test/comments/class/_input.java b/packages/prettier-plugin-java/test/unit-test/comments/class/_input.java index 52a66b883..b3a7b6f70 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/class/_input.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/class/_input.java @@ -795,4 +795,21 @@ public Optional getCurrentAuditor() { // See https://jira.spring.io/browse/DATACMNS-1231 return Optional.of(Constants.SYSTEM_ACCOUNT); } -} \ No newline at end of file + + // Bug Fix: #262 + @Test + @Transactional + public void getAllCountries() throws Exception { + // Initialize the database + countryRepository.saveAndFlush(country); + + // Get all the countryList + restCountryMockMvc.perform(get("/api/countries?sort=id,desc")).andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.[*].id").value(hasItem(country.getId().intValue()))) + .andExpect(jsonPath("$.[*].isoCode").value(hasItem(DEFAULT_ISO_CODE.toString()))) + .andExpect(jsonPath("$.[*].label").value(hasItem(DEFAULT_LABEL.toString()))) + .andExpect(jsonPath("$.[*].display").value(hasItem(DEFAULT_DISPLAY.booleanValue()))).andExpect( + jsonPath("$.[*].internationalDialingCode").value(hasItem(DEFAULT_INTERNATIONAL_DIALING_CODE.toString()))); + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java index 5124e0d0e..ea022c5c7 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java @@ -836,4 +836,33 @@ public Optional getCurrentAuditor() { // See https://jira.spring.io/browse/DATACMNS-1231 return Optional.of(Constants.SYSTEM_ACCOUNT); } + + // Bug Fix: #262 + @Test + @Transactional + public void getAllCountries() throws Exception { + // Initialize the database + countryRepository.saveAndFlush(country); + + // Get all the countryList + restCountryMockMvc.perform(get("/api/countries?sort=id,desc")) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect( + jsonPath("$.[*].id").value(hasItem(country.getId().intValue())) + ) + .andExpect( + jsonPath("$.[*].isoCode").value(hasItem(DEFAULT_ISO_CODE.toString())) + ) + .andExpect( + jsonPath("$.[*].label").value(hasItem(DEFAULT_LABEL.toString())) + ) + .andExpect( + jsonPath("$.[*].display").value(hasItem(DEFAULT_DISPLAY.booleanValue())) + ) + .andExpect( + jsonPath("$.[*].internationalDialingCode") + .value(hasItem(DEFAULT_INTERNATIONAL_DIALING_CODE.toString())) + ); + } } diff --git a/packages/prettier-plugin-java/test/unit-test/switch/_input.java b/packages/prettier-plugin-java/test/unit-test/switch/_input.java index 8aa488a1c..ebd1af46e 100644 --- a/packages/prettier-plugin-java/test/unit-test/switch/_input.java +++ b/packages/prettier-plugin-java/test/unit-test/switch/_input.java @@ -13,4 +13,34 @@ void simple(Answer answer) { } } + // Bug fix: #276 + public int method() { + switch ("abc") { + case "a": + return 1; + case "b": + return 2; + case "c": + return 3; + // default case + default: + return 3; + } + } + + // Bug fix: #276 + public int method2() { + switch ("abc") { + case "a": + return 1; + case "b": + return 2; + // case c + case "c": + return 3; + default: + return 3; + } + } + } diff --git a/packages/prettier-plugin-java/test/unit-test/switch/_output.java b/packages/prettier-plugin-java/test/unit-test/switch/_output.java index e655201c1..ecd40f701 100644 --- a/packages/prettier-plugin-java/test/unit-test/switch/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/switch/_output.java @@ -12,4 +12,34 @@ void simple(Answer answer) { break; } } + + // Bug fix: #276 + public int method() { + switch ("abc") { + case "a": + return 1; + case "b": + return 2; + case "c": + return 3; + // default case + default: + return 3; + } + } + + // Bug fix: #276 + public int method2() { + switch ("abc") { + case "a": + return 1; + case "b": + return 2; + // case c + case "c": + return 3; + default: + return 3; + } + } } From bb0db1d9fc68771e5ca56e69fd811a22dba6d779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Wed, 23 Oct 2019 10:49:58 +0200 Subject: [PATCH 13/26] fix rebase --- packages/java-parser/src/parser.js | 2 -- .../src/printers/packages-and-modules.js | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/java-parser/src/parser.js b/packages/java-parser/src/parser.js index 9f2be80e3..1eeeb3d4c 100644 --- a/packages/java-parser/src/parser.js +++ b/packages/java-parser/src/parser.js @@ -78,8 +78,6 @@ class JavaParser extends Parser { cstPostNonTerminal(ruleCstResult, ruleName) { super.cstPostNonTerminal(ruleCstResult, ruleName); if (this.isBackTracking() === false) { - shouldIgnore(ruleCstResult, this.ignoredComments, this.ignoredNodes); - this.leadingComments[ruleCstResult.location.startOffset] = ruleCstResult; this.trailingComments[ruleCstResult.location.endOffset] = ruleCstResult; } diff --git a/packages/prettier-plugin-java/src/printers/packages-and-modules.js b/packages/prettier-plugin-java/src/printers/packages-and-modules.js index 919b227ee..db2461ff1 100644 --- a/packages/prettier-plugin-java/src/printers/packages-and-modules.js +++ b/packages/prettier-plugin-java/src/printers/packages-and-modules.js @@ -23,6 +23,7 @@ class PackagesAndModulesPrettierVisitor { const additionalLine = isNaN(compilationUnit[0].location.startOffset) ? "" : line; + return concat([this.visit(compilationUnit[0]), additionalLine]); } @@ -41,8 +42,7 @@ class PackagesAndModulesPrettierVisitor { rejectAndJoin(hardline, staticImports), rejectAndJoin(hardline, nonStaticImports), rejectAndJoin(concat([hardline, hardline]), typesDecl) - ]), - line + ]) ]); } @@ -58,8 +58,7 @@ class PackagesAndModulesPrettierVisitor { rejectAndJoin(hardline, staticImports), rejectAndJoin(hardline, nonStaticImports), moduleDeclaration - ]), - line + ]) ]); } From 8fdcc741f6028cb7ac0e75ca2d8e1a1373218ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Wed, 23 Oct 2019 10:50:17 +0200 Subject: [PATCH 14/26] update after rebase --- packages/prettier-plugin-java/src/comments.js | 49 ++++++++++++++----- .../src/printers/prettier-builder.js | 20 ++++---- .../unit-test/comments/class/_output.java | 6 +-- 3 files changed, 51 insertions(+), 24 deletions(-) diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index 49c8dca1d..56c21bc14 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -1,6 +1,6 @@ "use strict"; const { concat } = require("./printers/prettier-builder"); -const { hardline, lineSuffix } = require("prettier").doc.builders; +const { hardline, lineSuffix, literalline } = require("prettier").doc.builders; function processComments(ctx, value) { if (!Array.isArray(ctx)) { @@ -58,19 +58,46 @@ function processComentsOnNode(node, value) { return arr.length === 1 ? value : concat(arr); } -function formatComment(comment) { - const res = []; - comment.image.split("\n").forEach(l => { - if (l.match(/(\s+)(\*)(.*)/gm) && !l.match(/(\/)(\*)(.*)(\*)(\/)/gm)) { - res.push(" " + l.trim()); - } else { - res.push(l); +function isJavaDoc(comment, lines) { + let isJavaDoc = true; + if (comment.tokenType.name === "TraditionalComment" && lines.length > 1) { + for (let i = 1; i < lines.length; i++) { + if (lines[i].trim().charAt(0) !== "*") { + isJavaDoc = false; + break; + } } + } else { + isJavaDoc = false; + } + + return isJavaDoc; +} + +function formatJavaDoc(lines) { + const res = [lines[0].trim()]; + + for (let i = 1; i < lines.length; i++) { res.push(hardline); - }); - if (res[res.length - 1] === hardline) { - res.pop(); + res.push(" " + lines[i].trim()); } + + return res; +} + +function formatComment(comment) { + const res = []; + const lines = comment.image.split("\n"); + + if (isJavaDoc(comment, lines)) { + return formatJavaDoc(lines); + } + + lines.forEach(line => { + res.push(line); + res.push(literalline); + }); + res.pop(); return res; } diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index afece624d..fb78755fe 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -89,17 +89,17 @@ function formatJavaDoc(lines) { function formatComment(comment) { const res = []; - comment.image.split("\n").forEach(l => { - if (l.match(/(\s+)(\*)(.*)/gm) && !l.match(/(\/)(\*)(.*)(\*)(\/)/gm)) { - res.push(" " + l.trim()); - } else { - res.push(l); - } - res.push(prettier.hardline); - }); - if (res[res.length - 1] === prettier.hardline) { - res.pop(); + const lines = comment.image.split("\n"); + + if (isJavaDoc(comment, lines)) { + return formatJavaDoc(lines); } + + lines.forEach(line => { + res.push(line); + res.push(prettier.literalline); + }); + res.pop(); return res; } diff --git a/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java index ea022c5c7..d8845acdd 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/class/_output.java @@ -158,8 +158,7 @@ private ArrayTable( * elements but rowKeySet() will be empty and containsRow() won't * acknolwedge them. */ - rowKeyToIndex = - Maps.indexMap(rowList); + rowKeyToIndex = Maps.indexMap(rowList); columnKeyToIndex = Maps.indexMap(columnList); @SuppressWarnings( @@ -845,7 +844,8 @@ public void getAllCountries() throws Exception { countryRepository.saveAndFlush(country); // Get all the countryList - restCountryMockMvc.perform(get("/api/countries?sort=id,desc")) + restCountryMockMvc + .perform(get("/api/countries?sort=id,desc")) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) .andExpect( From 108f5b3b0a4bcde3c37bcbdbe02a4c8455710a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Wed, 23 Oct 2019 11:15:57 +0200 Subject: [PATCH 15/26] clean duplicated code --- packages/prettier-plugin-java/src/comments.js | 47 +------------------ 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index 56c21bc14..a4edc8fad 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -1,6 +1,6 @@ "use strict"; -const { concat } = require("./printers/prettier-builder"); -const { hardline, lineSuffix, literalline } = require("prettier").doc.builders; +const { concat, formatComment } = require("./printers/prettier-builder"); +const { hardline, lineSuffix } = require("prettier").doc.builders; function processComments(ctx, value) { if (!Array.isArray(ctx)) { @@ -58,49 +58,6 @@ function processComentsOnNode(node, value) { return arr.length === 1 ? value : concat(arr); } -function isJavaDoc(comment, lines) { - let isJavaDoc = true; - if (comment.tokenType.name === "TraditionalComment" && lines.length > 1) { - for (let i = 1; i < lines.length; i++) { - if (lines[i].trim().charAt(0) !== "*") { - isJavaDoc = false; - break; - } - } - } else { - isJavaDoc = false; - } - - return isJavaDoc; -} - -function formatJavaDoc(lines) { - const res = [lines[0].trim()]; - - for (let i = 1; i < lines.length; i++) { - res.push(hardline); - res.push(" " + lines[i].trim()); - } - - return res; -} - -function formatComment(comment) { - const res = []; - const lines = comment.image.split("\n"); - - if (isJavaDoc(comment, lines)) { - return formatJavaDoc(lines); - } - - lines.forEach(line => { - res.push(line); - res.push(literalline); - }); - res.pop(); - return res; -} - module.exports = { processComments }; From 6b0f03b39afe84acc40b72d2d716257f100f2f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Wed, 23 Oct 2019 14:37:37 +0200 Subject: [PATCH 16/26] attach comments to the correct node/token --- packages/java-parser/src/comments.js | 70 ++++++++++------------------ 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index 2fa4463fb..33dae700f 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -34,7 +34,20 @@ function isPrettierIgnoreComment(comment) { ); } -function pretraitement(tokens, comments) { +// Optimisation by encapsulating token in a node ? +function preprocessingTokens(tokens, leadingComments, trailingComments) { + tokens.forEach(token => { + if (leadingComments[token.startOffset] === undefined) { + leadingComments[token.startOffset] = token; + } + + if (trailingComments[token.endOffset] === undefined) { + trailingComments[token.endOffset] = token; + } + }); +} + +function preprocessingComments(tokens, comments) { const commentsEndOffset = {}; const commentsStartOffset = {}; @@ -77,18 +90,17 @@ function shouldAttachTrailingComments(comment, node, parser) { return true; } - if (comment.startLine !== node.location.endLine) { + const nodeEndLine = + node.location !== undefined ? node.location.endLine : node.endLine; + if (comment.startLine !== nodeEndLine) { return false; } - if ( - nextNode !== undefined && - comment.endLine === nextNode.location.startLine - ) { - return false; - } - - return true; + const nextNodeStartLine = + nextNode.location !== undefined + ? nextNode.location.startLine + : nextNode.startLine; + return comment.endLine !== nextNodeStartLine; } function attachComments(tokens, comments, parser) { @@ -98,7 +110,9 @@ function attachComments(tokens, comments, parser) { return; } - const { commentsStartOffset, commentsEndOffset } = pretraitement( + preprocessingTokens(tokens, parser.leadingComments, parser.trailingComments); + + const { commentsStartOffset, commentsEndOffset } = preprocessingComments( tokens, comments ); @@ -155,40 +169,6 @@ function attachComments(tokens, comments, parser) { }); } }); - - attachRestCommentsToToken(tokens, commentsToAttach); -} - -function attachRestCommentsToToken(tokens, commentsToAttach) { - let currentToken = 0; - commentsToAttach.forEach(comment => { - // find the correct position to place the comment - while ( - !( - comment.startOffset > tokens[currentToken].endOffset && - comment.endOffset < tokens[currentToken + 1].startOffset - ) - ) { - currentToken++; - } - - // attach comment to the next token by default, - // it attaches to the current one when the comment and token is on the same line - if ( - comment.startLine === tokens[currentToken].endLine && - comment.startLine !== tokens[currentToken + 1].startLine - ) { - if (!tokens[currentToken].trailingComments) { - tokens[currentToken].trailingComments = []; - } - tokens[currentToken].trailingComments.push(comment); - } else { - if (!tokens[currentToken + 1].leadingComments) { - tokens[currentToken + 1].leadingComments = []; - } - tokens[currentToken + 1].leadingComments.push(comment); - } - }); } module.exports = { From 7832163c1526e7985e7294c3ec09f1b2f5646a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Wed, 23 Oct 2019 15:25:28 +0200 Subject: [PATCH 17/26] wip reafficahge --- .../scripts/single-printer-run/_input.java | 50 ++++++++++--------- .../scripts/single-printer-run/_output.java | 40 +++++++++------ packages/prettier-plugin-java/src/comments.js | 14 ++++-- .../src/printers/prettier-builder.js | 9 +++- 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/packages/prettier-plugin-java/scripts/single-printer-run/_input.java b/packages/prettier-plugin-java/scripts/single-printer-run/_input.java index edf095b87..f110c02c6 100644 --- a/packages/prettier-plugin-java/scripts/single-printer-run/_input.java +++ b/packages/prettier-plugin-java/scripts/single-printer-run/_input.java @@ -1,33 +1,35 @@ -public enum Enum { - - SOME_ENUM, ANOTHER_ENUM, LAST_ENUM; - -} - -public enum Enum { - - THIS_IS_GOOD("abc"), THIS_IS_FINE("abc"); - - public static final String thisWillBeDeleted = "DELETED"; - - private final String value; - - public Enum(String value) { - this.value = value; +class T { + + void t() { + if (e) { + // empty + } + // comment + else {} } - public String toString() { - return "STRING"; + void t() { + if (e) { + // empty + } // comment + else {} } - } -class CLassWithEnum { - - public static enum VALID_THINGS { - - FIRST, SECOND +class T { + void t() { + if (e) { + // empty + } // comment + else {} } + void t() { + if (e) { + // empty + } // comment + else {} + } } + diff --git a/packages/prettier-plugin-java/scripts/single-printer-run/_output.java b/packages/prettier-plugin-java/scripts/single-printer-run/_output.java index f86f9a1c7..455ca81d9 100644 --- a/packages/prettier-plugin-java/scripts/single-printer-run/_output.java +++ b/packages/prettier-plugin-java/scripts/single-printer-run/_output.java @@ -1,25 +1,33 @@ -public enum Enum { - SOME_ENUM, ANOTHER_ENUM, LAST_ENUM; -} - -public enum Enum { - THIS_IS_GOOD("abc"), THIS_IS_FINE("abc"); - public static final String thisWillBeDeleted = "DELETED"; - - private final String value; +class T { - public Enum(String value) { - this.value = value; + void t() { + if (e) { + // empty + } // comment + else {} } - public String toString() { - return "STRING"; + void t() { + if (e) { + // empty + } // comment + else {} } } -class CLassWithEnum { +class T { + + void t() { + if (e) { + // empty + } // comment + else {} + } - public static enum VALID_THINGS { - FIRST, SECOND; + void t() { + if (e) { + // empty + } // comment + else {} } } diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index a4edc8fad..b089eca16 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -1,6 +1,11 @@ "use strict"; const { concat, formatComment } = require("./printers/prettier-builder"); -const { hardline, lineSuffix } = require("prettier").doc.builders; +const { + breakParent, + hardline, + lineSuffix, + lineSuffixBoundary +} = require("prettier").doc.builders; function processComments(ctx, value) { if (!Array.isArray(ctx)) { @@ -44,9 +49,12 @@ function processComentsOnNode(node, value) { separator = " "; } - if (comment.tokenType.name == "LineComment") { + if (comment.tokenType.name === "LineComment") { arr.push( - lineSuffix(concat([separator, concat(formatComment(comment))])) + lineSuffix( + concat([separator, concat(formatComment(comment)), breakParent]) + ), + lineSuffixBoundary ); } else { arr.push(concat(formatComment(comment))); diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index fb78755fe..c2ca5813f 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -42,8 +42,13 @@ function getTrailingComments(token) { const separator = token.image === "" ? "" : " "; arr.push( prettier.lineSuffix( - concat([separator, concat(formatComment(element))]) - ) + concat([ + separator, + concat(formatComment(element)), + prettier.breakParent + ]) + ), + prettier.lineSuffixBoundary ); } else { arr.push(concat(formatComment(element))); From 8eff194d7d48813c68f5a3ad5149c66f43ebd942 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Sat, 16 Nov 2019 17:33:08 +0100 Subject: [PATCH 18/26] fix comments in else statements --- packages/prettier-plugin-java/src/comments.js | 10 +--- .../src/printers/blocks-and-statements.js | 13 ++++- .../src/printers/printer-utils.js | 2 + .../_input.java | 53 ++++++++++++------- .../_output.java | 26 ++++++--- .../unit-test/comments/package/_output.java | 8 +-- .../unit-test/empty_statement/_output.java | 6 +-- 7 files changed, 76 insertions(+), 42 deletions(-) diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index b089eca16..a19d6de69 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -1,11 +1,6 @@ "use strict"; const { concat, formatComment } = require("./printers/prettier-builder"); -const { - breakParent, - hardline, - lineSuffix, - lineSuffixBoundary -} = require("prettier").doc.builders; +const { breakParent, hardline, lineSuffix } = require("prettier").doc.builders; function processComments(ctx, value) { if (!Array.isArray(ctx)) { @@ -53,8 +48,7 @@ function processComentsOnNode(node, value) { arr.push( lineSuffix( concat([separator, concat(formatComment(comment)), breakParent]) - ), - lineSuffixBoundary + ) ); } else { arr.push(concat(formatComment(comment))); diff --git a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js index 13d8f0bc5..ee1c12169 100644 --- a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js +++ b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js @@ -19,7 +19,9 @@ const { putIntoBraces, putIntoCurlyBraces, isStatementEmptyStatement, - sortModifiers + sortModifiers, + hasTrailingComments, + hasLeadingComments } = require("./printer-utils"); class BlocksAndStatementPrettierVisitor { @@ -122,8 +124,15 @@ class BlocksAndStatementPrettierVisitor { }); const elseSeparator = isStatementEmptyStatement(elseStatement) ? "" : " "; + const elseOnSameLine = + hasTrailingComments(ctx.statement[0]) || + (hasLeadingComments(ctx.Else[0]) && + ctx.Else[0].leadingComments.tokenType === "LineComment") + ? hardline + : " "; + elsePart = rejectAndJoin(elseSeparator, [ - concat([" ", ctx.Else[0]]), + concat([elseOnSameLine, ctx.Else[0]]), elseStatement ]); } diff --git a/packages/prettier-plugin-java/src/printers/printer-utils.js b/packages/prettier-plugin-java/src/printers/printer-utils.js index 49dc21316..48735b636 100644 --- a/packages/prettier-plugin-java/src/printers/printer-utils.js +++ b/packages/prettier-plugin-java/src/printers/printer-utils.js @@ -568,6 +568,8 @@ module.exports = { sortModifiers, rejectAndJoinSeps, findDeepElementInPartsArray, + hasLeadingComments, + hasTrailingComments, isExplicitLambdaParameter, getBlankLinesSeparator, displaySemicolon, diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java index d5e9082e5..1fe8d2efe 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java @@ -1,12 +1,29 @@ public class PrettierTest { - + var x=0; - + + void commentsIf() { + if ( + t // test + ) { + + } // test + else { + int i // test + = 3; + } + + if (t) { + + } /* test */ else { + } + } + public void myFunction(int arg1){ - try { + try { ;// Empty Statement - + } /*catch*/catch ( EmptyStackException e){ throw new RuntimeException(e); } /*multi-catch*/catch ( /*1*/FirstException | /*2*/SecondException |/*3*/ ThirdException e2) @@ -16,11 +33,11 @@ public void myFunction(int arg1){ System.out.println("That's all folks !"); } } - + private void myFunction(/* axis x */ int arg1, /* axis y */ int arg2, /* axis z */int arg3){ if(arg1 == 0 && arg2 == 0 && arg == 3) throw new RuntimeException("X Y Z cannot be all 0"); - + int /*variable name is of value var */var = arg1+arg2+arg3; if/*true*/ (var == 0){ System.out.println("The value is 0"); @@ -28,14 +45,14 @@ private void myFunction(/* axis x */ int arg1, /* axis y */ int arg2, /* axis z int[] arr= { /*One*/1,/*Two */2, /*zero*/0, /*One again*/1,-1 /*Minus One*/ ,0,2}; - + loop: // Label statement - + //foreach for (int num /* num is every number in arr*/ : arr) { /*switch*/switch(num){//switch case 1: - + System.out.println("One "); System.out.println("One "); @@ -47,7 +64,7 @@ private void myFunction(/* axis x */ int arg1, /* axis y */ int arg2, /* axis z break; case 0: System.out.println("Zero "); - + continue/*labeled continued*/ loop; default/*def*/: /*labeled break*/break loop; @@ -55,9 +72,9 @@ private void myFunction(/* axis x */ int arg1, /* axis y */ int arg2, /* axis z } } } - - - + + + private synchronized void myFunction(int arg1, int arg2 /*overloading*/){ for(int i=0; i Date: Sun, 17 Nov 2019 00:40:26 +0100 Subject: [PATCH 19/26] improve tests for comments in if statements --- .../src/printers/blocks-and-statements.js | 28 ++++++---- .../src/printers/prettier-builder.js | 3 +- .../src/printers/printer-utils.js | 22 +++++++- .../{ => complex}/_input.java | 17 ------ .../{ => complex}/_output.java | 17 +----- .../if-statement/_input.java | 56 +++++++++++++++++++ .../if-statement/_output.java | 41 ++++++++++++++ .../test/unit-test/comments/comments-spec.js | 7 ++- 8 files changed, 143 insertions(+), 48 deletions(-) rename packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/{ => complex}/_input.java (93%) rename packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/{ => complex}/_output.java (91%) create mode 100644 packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_input.java create mode 100644 packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_output.java diff --git a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js index ee1c12169..8d447a2d9 100644 --- a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js +++ b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js @@ -20,8 +20,8 @@ const { putIntoCurlyBraces, isStatementEmptyStatement, sortModifiers, - hasTrailingComments, - hasLeadingComments + hasTrailingLineComments, + hasLeadingLineComments } = require("./printer-utils"); class BlocksAndStatementPrettierVisitor { @@ -125,9 +125,8 @@ class BlocksAndStatementPrettierVisitor { const elseSeparator = isStatementEmptyStatement(elseStatement) ? "" : " "; const elseOnSameLine = - hasTrailingComments(ctx.statement[0]) || - (hasLeadingComments(ctx.Else[0]) && - ctx.Else[0].leadingComments.tokenType === "LineComment") + hasTrailingLineComments(ctx.statement[0]) || + hasLeadingLineComments(ctx.Else[0]) ? hardline : " "; @@ -254,11 +253,20 @@ class BlocksAndStatementPrettierVisitor { const statementSeparator = isStatementEmptyStatement(statement) ? "" : " "; return rejectAndConcat([ - rejectAndJoin(" ", [ctx.For[0], ctx.LBrace[0]]), - forInit, - rejectAndJoin(" ", [ctx.Semicolon[0], expression]), - rejectAndJoin(" ", [ctx.Semicolon[1], forUpdate]), - concat([ctx.RBrace[0], statementSeparator]), + rejectAndJoin(" ", [ + ctx.For[0], + putIntoBraces( + rejectAndConcat([ + forInit, + rejectAndJoin(line, [ctx.Semicolon[0], expression]), + rejectAndJoin(line, [ctx.Semicolon[1], forUpdate]) + ]), + softline, + ctx.LBrace[0], + ctx.RBrace[0] + ) + ]), + statementSeparator, statement ]); } diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index c2ca5813f..633e6ce62 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -47,8 +47,7 @@ function getTrailingComments(token) { concat(formatComment(element)), prettier.breakParent ]) - ), - prettier.lineSuffixBoundary + ) ); } else { arr.push(concat(formatComment(element))); diff --git a/packages/prettier-plugin-java/src/printers/printer-utils.js b/packages/prettier-plugin-java/src/printers/printer-utils.js index 48735b636..9b592f9fc 100644 --- a/packages/prettier-plugin-java/src/printers/printer-utils.js +++ b/packages/prettier-plugin-java/src/printers/printer-utils.js @@ -196,6 +196,24 @@ function hasTrailingComments(token) { return token.trailingComments !== undefined; } +function hasLeadingLineComments(token) { + return ( + token.leadingComments !== undefined && + token.leadingComments.length !== 0 && + token.leadingComments[token.leadingComments.length - 1].tokenType.name === + "LineComment" + ); +} + +function hasTrailingLineComments(token) { + return ( + token.trailingComments !== undefined && + token.trailingComments.length !== 0 && + token.trailingComments[token.trailingComments.length - 1].tokenType.name === + "LineComment" + ); +} + function hasComments(token) { return hasLeadingComments(token) || hasTrailingComments(token); } @@ -568,8 +586,8 @@ module.exports = { sortModifiers, rejectAndJoinSeps, findDeepElementInPartsArray, - hasLeadingComments, - hasTrailingComments, + hasLeadingLineComments, + hasTrailingLineComments, isExplicitLambdaParameter, getBlankLinesSeparator, displaySemicolon, diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_input.java similarity index 93% rename from packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java rename to packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_input.java index 1fe8d2efe..818661947 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_input.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_input.java @@ -3,23 +3,6 @@ public class PrettierTest { var x=0; - void commentsIf() { - if ( - t // test - ) { - - } // test - else { - int i // test - = 3; - } - - if (t) { - - } /* test */ else { - } - } - public void myFunction(int arg1){ try { ;// Empty Statement diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java similarity index 91% rename from packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java rename to packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java index cb1bbcce0..b79143a9f 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java @@ -1,18 +1,6 @@ public class PrettierTest { var x = 0; - void commentsIf() { - if ( - t // test - ) {} // test - else { - int i = // test - 3; - } - - if (t) {} /* test */else {} - } - public void myFunction(int arg1) { try { // Empty Statement @@ -52,11 +40,9 @@ private void myFunction( 2 }; - loop: // Label statement - //foreach + loop://foreach // Label statement for (int num /* num is every number in arr*/: arr) { /*switch*/switch (num) { //switch - case 1: System.out.println("One "); System.out.println("One "); @@ -79,7 +65,6 @@ private void myFunction( private synchronized void myFunction(int arg1, int arg2/*overloading*/) { for (int i = 0; i < /*=*/arg1; i++) do /*dodododo*/{ //do whiles - //asserting assert /*true*/true == true; continue; diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_input.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_input.java new file mode 100644 index 000000000..d53f91789 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_input.java @@ -0,0 +1,56 @@ +class IfStatements { + + void commentsIfLineComment() { + if ( // test + t) { + } + + if (t // test + ) { + } + + if (t) { + } // test + + if ( // test + t) { + } + } + + void commentsIfBlockComment() { + if (/* test */ + t) { + } + + if (t/* test */ + ) { + } + + if (t)/* test */ { + } + + if/* test */ (t) { + } + } + + void commentsElseLineComment() { + if (t) { + } // test + else { + } + + if (t) { + } else { + } // test + } + + void commentsElseBlockComment() { + if (t) { + } /* test */ else { + } + + if (t) { + } else/* test */ { + } + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_output.java new file mode 100644 index 000000000..217808bd6 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/if-statement/_output.java @@ -0,0 +1,41 @@ +class IfStatements { + + void commentsIfLineComment() { + if ( // test + t + ) {} + + if ( + t // test + ) {} + + if (t) {} // test + + if ( // test + t + ) {} + } + + void commentsIfBlockComment() { + if (/* test */t) {} + + if (t/* test */) {} + + if (t) /* test */{} + + if /* test */(t) {} + } + + void commentsElseLineComment() { + if (t) {} // test + else {} + + if (t) {} else {} // test + } + + void commentsElseBlockComment() { + if (t) {} /* test */else {} + + if (t) {} else /* test */{} + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js b/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js index 91c1a8753..1788acde1 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js @@ -6,7 +6,12 @@ describe("prettier-java", () => { testSample(path.resolve(__dirname, "./edge")); testSample(path.resolve(__dirname, "./interface")); testSample(path.resolve(__dirname, "./package")); - testSample(path.resolve(__dirname, "./comments-blocks-and-statements")); + testSample( + path.resolve(__dirname, "./comments-blocks-and-statements/complex") + ); + testSample( + path.resolve(__dirname, "./comments-blocks-and-statements/if-statement") + ); testSample(path.resolve(__dirname, "./comments-only")); testSample(path.resolve(__dirname, "./bug-fixes")); }); From 8b78ad3b08920f203d004ae5b695813e51ea336f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Sun, 17 Nov 2019 13:20:46 +0100 Subject: [PATCH 20/26] fix comments in labeled statements --- .eslintrc.yml | 2 + packages/java-parser/src/comments.js | 6 +- packages/prettier-plugin-java/src/comments.js | 6 +- .../src/printers/blocks-and-statements.js | 25 +++ .../src/printers/prettier-builder.js | 6 +- .../complex/_output.java | 5 +- .../labeled-statement/_input.java | 144 ++++++++++++++++++ .../labeled-statement/_output.java | 106 +++++++++++++ .../test/unit-test/comments/comments-spec.js | 6 + 9 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_input.java create mode 100644 packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_output.java diff --git a/.eslintrc.yml b/.eslintrc.yml index f6f8f297a..99460c8ce 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -5,6 +5,8 @@ root: true env: es6: true node: true +parserOptions: + ecmaVersion: 2018 rules: no-fallthrough: off curly: error diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index 33dae700f..d4481875d 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -150,7 +150,11 @@ function attachComments(tokens, comments, parser) { comment => commentsToAttach.has(comment) ); - parser.leadingComments[startOffset].leadingComments = nodeLeadingComments; + if (nodeLeadingComments.length > 0) { + parser.leadingComments[ + startOffset + ].leadingComments = nodeLeadingComments; + } // prettier ignore support let ignoreNode = false; diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js index a19d6de69..56d401f11 100644 --- a/packages/prettier-plugin-java/src/comments.js +++ b/packages/prettier-plugin-java/src/comments.js @@ -22,7 +22,11 @@ function processComentsOnNode(node, value) { const arr = []; if (Object.prototype.hasOwnProperty.call(node, "leadingComments")) { node.leadingComments.forEach(comment => { - if (comment.endLine !== node.location.startLine) { + if ( + comment.tokenType.name === "LineComment" || + comment.endLine !== node.location.startLine || + comment.startOffset > node.location.startOffset + ) { arr.push(concat(formatComment(comment))); arr.push(hardline); } else { diff --git a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js index 8d447a2d9..f471db9c1 100644 --- a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js +++ b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js @@ -82,6 +82,31 @@ class BlocksAndStatementPrettierVisitor { } statement(ctx, params) { + // handling Labeled statements comments + if (ctx.labeledStatement !== undefined) { + const newLabelStatement = { ...ctx.labeledStatement[0] }; + const newColon = { ...ctx.labeledStatement[0].children.Colon[0] }; + const newStatement = { ...ctx.labeledStatement[0].children.statement[0] }; + + const labeledStatementLeadingComments = []; + + if (newColon.trailingComments !== undefined) { + labeledStatementLeadingComments.push(...newColon.trailingComments); + delete newColon.trailingComments; + } + + if (newStatement.leadingComments !== undefined) { + labeledStatementLeadingComments.push(...newStatement.leadingComments); + delete newStatement.leadingComments; + } + + newLabelStatement.leadingComments = labeledStatementLeadingComments; + newLabelStatement.children.Colon[0] = newColon; + newLabelStatement.children.statement[0] = newStatement; + + return this.visit([newLabelStatement]); + } + return this.visitSingle(ctx, params); } diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index 633e6ce62..ff0928948 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -14,7 +14,11 @@ function getLeadingComments(token) { const arr = []; if (Object.prototype.hasOwnProperty.call(token, "leadingComments")) { token.leadingComments.forEach(element => { - if (element.startLine !== token.startLine) { + if ( + element.tokenType.name === "LineComment" || + element.startLine !== token.startLine || + element.startOffset > token.startOffset + ) { arr.push(prettier.lineSuffixBoundary); arr.push(concat(formatComment(element))); arr.push(prettier.hardline); diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java index b79143a9f..72850c318 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/complex/_output.java @@ -40,8 +40,9 @@ private void myFunction( 2 }; - loop://foreach // Label statement - for (int num /* num is every number in arr*/: arr) { + // Label statement + //foreach + loop:for (int num /* num is every number in arr*/: arr) { /*switch*/switch (num) { //switch case 1: System.out.println("One "); diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_input.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_input.java new file mode 100644 index 000000000..48edfb674 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_input.java @@ -0,0 +1,144 @@ +class LabeledStatements { + + void commentsLabeledStatementLineComment() { + loop: // Label statement + + // comment1 + for (int num : arr) { + } + + loop: // Label statement + // comment1 + // comment2 + for (int num : arr) { + } + + // Label statement + loop: + // comment1 + // comment2 + for (int num : arr) { + } + + loop: + // comment1 + // comment2 + for (int num : arr) { + } + + loop: + // comment1 + for (int num : arr) { + } + + loop: // comment1 + for (int num : arr) { + } + + loop: + for (int num : arr) { + } + } + + void commentsLabeledStatementBlockComment() { + loop: /* Label statement */ + + /* comment1 */ + for (int num : arr) { + } + + loop: /* Label statement */ + /* comment1 */ + /* comment2 */ + for (int num : arr) { + } + + /* Label statement */ + loop: + /* comment1 */ + /* comment2 */ + for (int num : arr) { + } + + loop: + /* comment1 */ + /* comment2 */ + for (int num : arr) { + } + + loop: + /* comment1 */ + for (int num : arr) { + } + + loop: /* comment1 */ + for (int num : arr) { + } + + loop: for (int num : arr) { + } + } + + void commentsLabeledStatementMixedComment() { + loop: // Label statement + + /* comment1 */ + for (int num : arr) { + } + + loop: /* Label statement */ + + // comment1 + for (int num : arr) { + } + + loop: /* Label statement */ + // comment1 + // comment2 + for (int num : arr) { + } + + loop: // Label statement + /* comment1 */ + // comment2 + for (int num : arr) { + } + + loop: // Label statement + // comment1 + /* comment2 */ + for (int num : arr) { + } + + loop: /* Label statement */ + // comment1 + /* comment2 */ + for (int num : arr) { + } + + loop: // Label statement + /* comment1 */ + /* comment2 */ + for (int num : arr) { + } + + loop: /* Label statement */ + /* comment1 */ + // comment2 + for (int num : arr) { + } + + loop: + // comment1 + /* comment2 */ + for (int num : arr) { + } + + oop: + /* comment1 */ + // comment2 + for (int num : arr) { + } + } +} + diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_output.java b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_output.java new file mode 100644 index 000000000..a114fea2b --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-blocks-and-statements/labeled-statement/_output.java @@ -0,0 +1,106 @@ +class LabeledStatements { + + void commentsLabeledStatementLineComment() { + // Label statement + // comment1 + loop:for (int num : arr) {} + + // Label statement + // comment1 + // comment2 + loop:for (int num : arr) {} + + // Label statement + // comment1 + // comment2 + loop:for (int num : arr) {} + + // comment1 + // comment2 + loop:for (int num : arr) {} + + // comment1 + loop:for (int num : arr) {} + + // comment1 + loop:for (int num : arr) {} + + loop:for (int num : arr) {} + } + + void commentsLabeledStatementBlockComment() { + /* Label statement */ + /* comment1 */ + loop:for (int num : arr) {} + + /* Label statement */ + /* comment1 */ + /* comment2 */ + loop:for (int num : arr) {} + + /* Label statement */ + /* comment1 */ + /* comment2 */ + loop:for (int num : arr) {} + + /* comment1 */ + /* comment2 */ + loop:for (int num : arr) {} + + /* comment1 */ + loop:for (int num : arr) {} + + /* comment1 */ + loop:for (int num : arr) {} + + loop:for (int num : arr) {} + } + + void commentsLabeledStatementMixedComment() { + // Label statement + /* comment1 */ + loop:for (int num : arr) {} + + /* Label statement */ + // comment1 + loop:for (int num : arr) {} + + /* Label statement */ + // comment1 + // comment2 + loop:for (int num : arr) {} + + // Label statement + /* comment1 */ + // comment2 + loop:for (int num : arr) {} + + // Label statement + // comment1 + /* comment2 */ + loop:for (int num : arr) {} + + /* Label statement */ + // comment1 + /* comment2 */ + loop:for (int num : arr) {} + + // Label statement + /* comment1 */ + /* comment2 */ + loop:for (int num : arr) {} + + /* Label statement */ + /* comment1 */ + // comment2 + loop:for (int num : arr) {} + + // comment1 + /* comment2 */ + loop:for (int num : arr) {} + + /* comment1 */ + // comment2 + oop:for (int num : arr) {} + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js b/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js index 1788acde1..6cf28a1cf 100644 --- a/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js +++ b/packages/prettier-plugin-java/test/unit-test/comments/comments-spec.js @@ -12,6 +12,12 @@ describe("prettier-java", () => { testSample( path.resolve(__dirname, "./comments-blocks-and-statements/if-statement") ); + testSample( + path.resolve( + __dirname, + "./comments-blocks-and-statements/labeled-statement" + ) + ); testSample(path.resolve(__dirname, "./comments-only")); testSample(path.resolve(__dirname, "./bug-fixes")); }); From 81753d491da85b4ee9a958915508101e9f257d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Sun, 17 Nov 2019 13:57:45 +0100 Subject: [PATCH 21/26] revert changes on single-print-run --- .../scripts/single-printer-run/_input.java | 50 +++++++++---------- .../scripts/single-printer-run/_output.java | 40 ++++++--------- 2 files changed, 40 insertions(+), 50 deletions(-) diff --git a/packages/prettier-plugin-java/scripts/single-printer-run/_input.java b/packages/prettier-plugin-java/scripts/single-printer-run/_input.java index f110c02c6..edf095b87 100644 --- a/packages/prettier-plugin-java/scripts/single-printer-run/_input.java +++ b/packages/prettier-plugin-java/scripts/single-printer-run/_input.java @@ -1,35 +1,33 @@ -class T { - - void t() { - if (e) { - // empty - } - // comment - else {} - } +public enum Enum { + + SOME_ENUM, ANOTHER_ENUM, LAST_ENUM; - void t() { - if (e) { - // empty - } // comment - else {} - } } -class T { +public enum Enum { + + THIS_IS_GOOD("abc"), THIS_IS_FINE("abc"); - void t() { - if (e) { - // empty - } // comment - else {} + public static final String thisWillBeDeleted = "DELETED"; + + private final String value; + + public Enum(String value) { + this.value = value; } - void t() { - if (e) { - // empty - } // comment - else {} + public String toString() { + return "STRING"; } + } +class CLassWithEnum { + + public static enum VALID_THINGS { + + FIRST, SECOND + + } + +} diff --git a/packages/prettier-plugin-java/scripts/single-printer-run/_output.java b/packages/prettier-plugin-java/scripts/single-printer-run/_output.java index 455ca81d9..f86f9a1c7 100644 --- a/packages/prettier-plugin-java/scripts/single-printer-run/_output.java +++ b/packages/prettier-plugin-java/scripts/single-printer-run/_output.java @@ -1,33 +1,25 @@ -class T { +public enum Enum { + SOME_ENUM, ANOTHER_ENUM, LAST_ENUM; +} + +public enum Enum { + THIS_IS_GOOD("abc"), THIS_IS_FINE("abc"); + public static final String thisWillBeDeleted = "DELETED"; + + private final String value; - void t() { - if (e) { - // empty - } // comment - else {} + public Enum(String value) { + this.value = value; } - void t() { - if (e) { - // empty - } // comment - else {} + public String toString() { + return "STRING"; } } -class T { - - void t() { - if (e) { - // empty - } // comment - else {} - } +class CLassWithEnum { - void t() { - if (e) { - // empty - } // comment - else {} + public static enum VALID_THINGS { + FIRST, SECOND; } } From 40d7de0718c13c8724a09a65ae2b1ad203b5bb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Sun, 17 Nov 2019 14:04:56 +0100 Subject: [PATCH 22/26] clean --- packages/prettier-plugin-java/src/cst-printer.js | 1 - packages/prettier-plugin-java/src/printers/expressions.js | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/prettier-plugin-java/src/cst-printer.js b/packages/prettier-plugin-java/src/cst-printer.js index c5ce879e0..e8092a0f8 100644 --- a/packages/prettier-plugin-java/src/cst-printer.js +++ b/packages/prettier-plugin-java/src/cst-printer.js @@ -92,7 +92,6 @@ class CstPrettierPrinter extends BaseJavaCstVisitor { } } - // return orgVisit.call(this, ctx, inParam); return processComments(ctx, orgVisit.call(this, ctx, inParam)); }; } diff --git a/packages/prettier-plugin-java/src/printers/expressions.js b/packages/prettier-plugin-java/src/printers/expressions.js index ad6564088..5ab1e0b65 100644 --- a/packages/prettier-plugin-java/src/printers/expressions.js +++ b/packages/prettier-plugin-java/src/printers/expressions.js @@ -11,7 +11,6 @@ const { } = require("./prettier-builder"); const { matchCategory, - reject, rejectAndJoin, rejectAndConcat, sortAnnotationIdentifier, From 89590249c0161009a02ef6f1278e29849e261a7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Mon, 18 Nov 2019 05:33:50 +0100 Subject: [PATCH 23/26] refactor: clean comments handling to remove duplicated code --- packages/prettier-plugin-java/src/comments.js | 69 ------ .../prettier-plugin-java/src/cst-printer.js | 4 +- .../src/printers/blocks-and-statements.js | 13 +- .../src/printers/classes.js | 39 ++- .../src/printers/comments.js | 229 ++++++++++++++++++ .../src/printers/expressions.js | 14 +- .../src/printers/interfaces.js | 18 +- .../src/printers/lexical-structure.js | 10 +- .../src/printers/names.js | 6 +- .../src/printers/packages-and-modules.js | 5 +- .../src/printers/prettier-builder.js | 141 +---------- .../src/printers/printer-utils.js | 12 +- .../printers/types-values-and-variables.js | 7 +- 13 files changed, 291 insertions(+), 276 deletions(-) delete mode 100644 packages/prettier-plugin-java/src/comments.js create mode 100644 packages/prettier-plugin-java/src/printers/comments.js diff --git a/packages/prettier-plugin-java/src/comments.js b/packages/prettier-plugin-java/src/comments.js deleted file mode 100644 index 56d401f11..000000000 --- a/packages/prettier-plugin-java/src/comments.js +++ /dev/null @@ -1,69 +0,0 @@ -"use strict"; -const { concat, formatComment } = require("./printers/prettier-builder"); -const { breakParent, hardline, lineSuffix } = require("prettier").doc.builders; - -function processComments(ctx, value) { - if (!Array.isArray(ctx)) { - return processComentsOnNode(ctx, value); - } - - if (ctx.length === 1) { - return processComentsOnNode(ctx[0], value); - } - - return concat( - ctx.map(elt => { - return processComentsOnNode(elt, value); - }) - ); -} - -function processComentsOnNode(node, value) { - const arr = []; - if (Object.prototype.hasOwnProperty.call(node, "leadingComments")) { - node.leadingComments.forEach(comment => { - if ( - comment.tokenType.name === "LineComment" || - comment.endLine !== node.location.startLine || - comment.startOffset > node.location.startOffset - ) { - arr.push(concat(formatComment(comment))); - arr.push(hardline); - } else { - arr.push(concat(formatComment(comment))); - } - }); - } - - arr.push(value); - - let previousEndLine = node.location.endLine; - if (Object.prototype.hasOwnProperty.call(node, "trailingComments")) { - node.trailingComments.forEach((comment, idx) => { - let separator = ""; - - if (comment.startLine !== previousEndLine) { - arr.push(hardline); - } else if (value !== "" && idx === 0) { - separator = " "; - } - - if (comment.tokenType.name === "LineComment") { - arr.push( - lineSuffix( - concat([separator, concat(formatComment(comment)), breakParent]) - ) - ); - } else { - arr.push(concat(formatComment(comment))); - } - - previousEndLine = comment.endLine; - }); - } - return arr.length === 1 ? value : concat(arr); -} - -module.exports = { - processComments -}; diff --git a/packages/prettier-plugin-java/src/cst-printer.js b/packages/prettier-plugin-java/src/cst-printer.js index e8092a0f8..95f9fefad 100644 --- a/packages/prettier-plugin-java/src/cst-printer.js +++ b/packages/prettier-plugin-java/src/cst-printer.js @@ -18,7 +18,7 @@ const { const { PackagesAndModulesPrettierVisitor } = require("./printers/packages-and-modules"); -const { processComments } = require("./comments"); +const { processCommentsOnNode } = require("./printers/comments"); class CstPrettierPrinter extends BaseJavaCstVisitor { constructor() { @@ -92,7 +92,7 @@ class CstPrettierPrinter extends BaseJavaCstVisitor { } } - return processComments(ctx, orgVisit.call(this, ctx, inParam)); + return processCommentsOnNode(ctx, orgVisit.call(this, ctx, inParam)); }; } } diff --git a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js index f471db9c1..55649cdf4 100644 --- a/packages/prettier-plugin-java/src/printers/blocks-and-statements.js +++ b/packages/prettier-plugin-java/src/printers/blocks-and-statements.js @@ -2,13 +2,8 @@ /* eslint-disable no-unused-vars */ const { line, softline, hardline } = require("prettier").doc.builders; -const { - group, - indent, - concat, - join, - getImageWithComments -} = require("./prettier-builder"); +const { group, indent, concat, join } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); const { displaySemicolon, rejectAndConcat, @@ -78,7 +73,7 @@ class BlocksAndStatementPrettierVisitor { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } statement(ctx, params) { @@ -308,7 +303,7 @@ class BlocksAndStatementPrettierVisitor { const statementExpressions = this.mapVisit(ctx.statementExpression); const commas = ctx.Comma ? ctx.Comma.map(elt => { - return concat([getImageWithComments(elt), " "]); + return concat([printTokenWithComments(elt), " "]); }) : []; return rejectAndJoinSeps(commas, statementExpressions); diff --git a/packages/prettier-plugin-java/src/printers/classes.js b/packages/prettier-plugin-java/src/printers/classes.js index dd075c4e4..337065be5 100644 --- a/packages/prettier-plugin-java/src/printers/classes.js +++ b/packages/prettier-plugin-java/src/printers/classes.js @@ -15,15 +15,12 @@ const { getClassBodyDeclarationsSeparator, isStatementEmptyStatement } = require("./printer-utils"); +const { concat, join, group, indent } = require("./prettier-builder"); const { - concat, - join, - group, - indent, - getImageWithComments, - getLeadingComments, - getTrailingComments -} = require("./prettier-builder"); + printTokenWithComments, + getTokenLeadingComments, + getTokenTrailingComments +} = require("./comments"); class ClassesPrettierVisitor { classDeclaration(ctx) { @@ -79,7 +76,7 @@ class ClassesPrettierVisitor { return this.visit(ctx.annotation); } // public | protected | private | ... - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } typeParameters(ctx) { @@ -182,7 +179,7 @@ class ClassesPrettierVisitor { return this.visit(ctx.annotation); } // public | protected | private | ... - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } variableDeclaratorList(ctx) { @@ -290,7 +287,7 @@ class ClassesPrettierVisitor { if (ctx.numericType) { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } unannReferenceType(ctx) { @@ -344,7 +341,7 @@ class ClassesPrettierVisitor { } unannTypeVariable(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } methodDeclaration(ctx) { @@ -371,7 +368,7 @@ class ClassesPrettierVisitor { return this.visit(ctx.annotation); } // public | protected | private | Synchronized | ... - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } methodHeader(ctx) { @@ -404,11 +401,11 @@ class ClassesPrettierVisitor { return this.visit(ctx.unannType); } // void - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } methodDeclarator(ctx) { - const identifier = getImageWithComments(ctx.Identifier[0]); + const identifier = printTokenWithComments(ctx.Identifier[0]); const formalParameterList = this.visit(ctx.formalParameterList); const dims = this.visit(ctx.dims); @@ -480,7 +477,7 @@ class ClassesPrettierVisitor { if (ctx.annotation) { return this.visit(ctx.annotation); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } throws(ctx) { @@ -503,7 +500,7 @@ class ClassesPrettierVisitor { return this.visit(ctx.block); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } instanceInitializer(ctx) { @@ -550,7 +547,7 @@ class ClassesPrettierVisitor { return this.visit(ctx.annotation); } // public | protected | private | Synchronized | ... - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } constructorDeclarator(ctx) { @@ -572,7 +569,7 @@ class ClassesPrettierVisitor { } simpleTypeName(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } constructorBody(ctx) { @@ -712,9 +709,9 @@ class ClassesPrettierVisitor { } return concat([ - getLeadingComments(ctx.Semicolon[0]), + ...getTokenLeadingComments(ctx.Semicolon[0]), "", - getTrailingComments(ctx.Semicolon[0]) + ...getTokenTrailingComments(ctx.Semicolon[0]) ]); } diff --git a/packages/prettier-plugin-java/src/printers/comments.js b/packages/prettier-plugin-java/src/printers/comments.js new file mode 100644 index 000000000..fd763c6d1 --- /dev/null +++ b/packages/prettier-plugin-java/src/printers/comments.js @@ -0,0 +1,229 @@ +"use strict"; +const { + concat, + hardline, + lineSuffix, + breakParent, + literalline +} = require("prettier").doc.builders; + +/** + * Takes a token and return a doc with: + * - concatenated leading comments + * - the token image + * - concatenated trailing comments + * + * @param {Token} token + * @return a doc with the token and its comments + */ +function printTokenWithComments(token) { + return printWithComments( + token, + token.image, + getTokenLeadingComments, + getTokenTrailingComments + ); +} + +/** + * Takes a node and return a doc with: + * - concatenated leading comments + * - the node doc value + * - concatenated trailing comments + * + * @param {CSTNode} node + * @param {Doc} value - the converted node value + * @return a doc with the token and its comments + */ +function printNodeWithComments(node, value) { + return printWithComments( + node, + value, + getNodeLeadingComments, + getNodeTrailingComments + ); +} + +function printWithComments( + nodeOrToken, + value, + getLeadingComments, + getTrailingComments +) { + const leadingComments = getLeadingComments(nodeOrToken); + const trailingComments = getTrailingComments(nodeOrToken, value); + + return leadingComments.length === 0 && trailingComments.length === 0 + ? value + : concat([...leadingComments, value, ...trailingComments]); +} + +/** + * @param {Token} token + * @return an array containing processed leading comments and separators + */ +function getTokenLeadingComments(token) { + return getLeadingComments(token, token); +} + +/** + * @param {CSTNode} node + * @return an array containing processed leading comments and separators + */ +function getNodeLeadingComments(node) { + return getLeadingComments(node, node.location); +} + +function getLeadingComments(nodeOrToken, location) { + const arr = []; + if (Object.prototype.hasOwnProperty.call(nodeOrToken, "leadingComments")) { + nodeOrToken.leadingComments.forEach(comment => { + if ( + comment.tokenType.name === "LineComment" || + comment.endLine !== location.startLine || + comment.startOffset > location.startOffset + ) { + arr.push(concat(formatComment(comment))); + arr.push(hardline); + } else { + arr.push(concat(formatComment(comment))); + } + }); + } + + return arr; +} + +/** + * @param {Token} token + * @return an array containing processed trailing comments and separators + */ +function getTokenTrailingComments(token) { + return getTrailingComments(token, token.image, token); +} + +/** + * @param {CSTNode} node + * @return an array containing processed trailing comments and separators + */ +function getNodeTrailingComments(node, value) { + return getTrailingComments(node, value, node.location); +} + +function getTrailingComments(nodeOrToken, value, location) { + const arr = []; + let previousEndLine = location.endLine; + if (Object.prototype.hasOwnProperty.call(nodeOrToken, "trailingComments")) { + nodeOrToken.trailingComments.forEach((comment, idx) => { + let separator = ""; + + if (comment.startLine !== previousEndLine) { + arr.push(hardline); + } else if (value !== "" && idx === 0) { + separator = " "; + } + + if (comment.tokenType.name === "LineComment") { + arr.push( + lineSuffix( + concat([separator, concat(formatComment(comment)), breakParent]) + ) + ); + } else { + arr.push(concat(formatComment(comment))); + } + + previousEndLine = comment.endLine; + }); + } + + return arr; +} + +function isJavaDoc(comment, lines) { + let isJavaDoc = true; + if (comment.tokenType.name === "TraditionalComment" && lines.length > 1) { + for (let i = 1; i < lines.length; i++) { + if (lines[i].trim().charAt(0) !== "*") { + isJavaDoc = false; + break; + } + } + } else { + isJavaDoc = false; + } + + return isJavaDoc; +} + +function formatJavaDoc(lines) { + const res = [lines[0].trim()]; + + for (let i = 1; i < lines.length; i++) { + res.push(hardline); + res.push(" " + lines[i].trim()); + } + + return res; +} + +function formatComment(comment) { + const res = []; + const lines = comment.image.split("\n"); + + if (isJavaDoc(comment, lines)) { + return formatJavaDoc(lines); + } + + lines.forEach(line => { + res.push(line); + res.push(literalline); + }); + res.pop(); + return res; +} + +function isToken(doc) { + return ( + doc && Object.prototype.hasOwnProperty.call(doc, "image") && doc.tokenType + ); +} + +function processComments(docs) { + if (!Array.isArray(docs)) { + if (isToken(docs)) { + return printTokenWithComments(docs); + } + return docs; + } + return docs.map(elt => { + if (isToken(elt)) { + return printTokenWithComments(elt); + } + return elt; + }); +} + +function processCommentsOnNode(ctx, value) { + if (!Array.isArray(ctx)) { + return printNodeWithComments(ctx, value); + } + + if (ctx.length === 1) { + return printNodeWithComments(ctx[0], value); + } + + return concat( + ctx.map(elt => { + return printNodeWithComments(elt, value); + }) + ); +} + +module.exports = { + processComments, + printTokenWithComments, + getTokenLeadingComments, + getTokenTrailingComments, + processCommentsOnNode +}; diff --git a/packages/prettier-plugin-java/src/printers/expressions.js b/packages/prettier-plugin-java/src/printers/expressions.js index 5ab1e0b65..448018e5c 100644 --- a/packages/prettier-plugin-java/src/printers/expressions.js +++ b/packages/prettier-plugin-java/src/printers/expressions.js @@ -3,12 +3,8 @@ const _ = require("lodash"); const { ifBreak, line, softline, hardline } = require("prettier").doc.builders; -const { - concat, - group, - indent, - getImageWithComments -} = require("./prettier-builder"); +const { concat, group, indent } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); const { matchCategory, rejectAndJoin, @@ -44,7 +40,7 @@ class ExpressionsPrettierVisitor { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } lambdaParametersWithBraces(ctx) { @@ -122,7 +118,7 @@ class ExpressionsPrettierVisitor { if (ctx.unannType) { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } lambdaBody(ctx) { @@ -328,7 +324,7 @@ class ExpressionsPrettierVisitor { primaryPrefix(ctx, params) { if (ctx.This || ctx.Void || ctx.Boolean) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } return this.visitSingle(ctx, params); diff --git a/packages/prettier-plugin-java/src/printers/interfaces.js b/packages/prettier-plugin-java/src/printers/interfaces.js index d4c2038e9..5c45d1957 100644 --- a/packages/prettier-plugin-java/src/printers/interfaces.js +++ b/packages/prettier-plugin-java/src/printers/interfaces.js @@ -2,12 +2,8 @@ /* eslint-disable no-unused-vars */ const { line, softline, hardline } = require("prettier").doc.builders; -const { - concat, - group, - indent, - getImageWithComments -} = require("./prettier-builder"); +const { concat, group, indent } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); const { rejectAndConcat, rejectAndJoin, @@ -65,7 +61,7 @@ class InterfacesPrettierVisitor { if (ctx.annotation) { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } extendsInterfaces(ctx) { @@ -133,7 +129,7 @@ class InterfacesPrettierVisitor { if (ctx.annotation) { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } interfaceMethodDeclaration(ctx) { @@ -158,7 +154,7 @@ class InterfacesPrettierVisitor { if (ctx.annotation) { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } annotationTypeDeclaration(ctx) { @@ -190,7 +186,7 @@ class InterfacesPrettierVisitor { annotationTypeMemberDeclaration(ctx) { if (ctx.Semicolon) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } return this.visitSingle(ctx); } @@ -227,7 +223,7 @@ class InterfacesPrettierVisitor { if (ctx.annotation) { return this.visitSingle(ctx); } - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } defaultValue(ctx) { diff --git a/packages/prettier-plugin-java/src/printers/lexical-structure.js b/packages/prettier-plugin-java/src/printers/lexical-structure.js index a31805258..5e15a233e 100644 --- a/packages/prettier-plugin-java/src/printers/lexical-structure.js +++ b/packages/prettier-plugin-java/src/printers/lexical-structure.js @@ -1,24 +1,24 @@ "use strict"; /* eslint-disable no-unused-vars */ -const { getImageWithComments } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); class LexicalStructurePrettierVisitor { literal(ctx) { if (ctx.CharLiteral || ctx.StringLiteral || ctx.Null) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } return this.visitSingle(ctx); } integerLiteral(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } floatingPointLiteral(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } booleanLiteral(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } } diff --git a/packages/prettier-plugin-java/src/printers/names.js b/packages/prettier-plugin-java/src/printers/names.js index c61b2e2dd..b82c96e38 100644 --- a/packages/prettier-plugin-java/src/printers/names.js +++ b/packages/prettier-plugin-java/src/printers/names.js @@ -2,11 +2,11 @@ /* eslint-disable no-unused-vars */ const { buildFqn } = require("./printer-utils"); -const { getImageWithComments } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); class NamesPrettierVisitor { typeIdentifier(ctx) { - return getImageWithComments(ctx.Identifier[0]); + return printTokenWithComments(ctx.Identifier[0]); } moduleName(ctx) { @@ -26,7 +26,7 @@ class NamesPrettierVisitor { } methodName(ctx) { - return getImageWithComments(ctx.Identifier[0]); + return printTokenWithComments(ctx.Identifier[0]); } packageOrTypeName(ctx) { diff --git a/packages/prettier-plugin-java/src/printers/packages-and-modules.js b/packages/prettier-plugin-java/src/printers/packages-and-modules.js index db2461ff1..dbaa2b820 100644 --- a/packages/prettier-plugin-java/src/printers/packages-and-modules.js +++ b/packages/prettier-plugin-java/src/printers/packages-and-modules.js @@ -2,7 +2,8 @@ /* eslint-disable no-unused-vars */ const { line, hardline, indent, group } = require("prettier").doc.builders; -const { concat, join, getImageWithComments } = require("./prettier-builder"); +const { concat, join } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); const { buildFqn, rejectAndJoin, @@ -223,7 +224,7 @@ class PackagesAndModulesPrettierVisitor { } requiresModifier(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } isModuleCompilationUnit(ctx) { diff --git a/packages/prettier-plugin-java/src/printers/prettier-builder.js b/packages/prettier-plugin-java/src/printers/prettier-builder.js index ff0928948..62d4bd13e 100644 --- a/packages/prettier-plugin-java/src/printers/prettier-builder.js +++ b/packages/prettier-plugin-java/src/printers/prettier-builder.js @@ -1,136 +1,13 @@ "use strict"; const prettier = require("prettier").doc.builders; -function getImageWithComments(token) { - const leadingComments = getLeadingComments(token); - const trailingComments = getTrailingComments(token); +const { processComments } = require("./comments"); - return leadingComments === "" && trailingComments === "" - ? token.image - : concat([leadingComments, token.image, trailingComments]); -} - -function getLeadingComments(token) { - const arr = []; - if (Object.prototype.hasOwnProperty.call(token, "leadingComments")) { - token.leadingComments.forEach(element => { - if ( - element.tokenType.name === "LineComment" || - element.startLine !== token.startLine || - element.startOffset > token.startOffset - ) { - arr.push(prettier.lineSuffixBoundary); - arr.push(concat(formatComment(element))); - arr.push(prettier.hardline); - } else { - arr.push(concat(formatComment(element))); - } - }); - } - - return concat(arr); -} - -function getTrailingComments(token) { - const arr = []; - if (Object.prototype.hasOwnProperty.call(token, "trailingComments")) { - if (token.trailingComments[0].startLine !== token.startLine) { - arr.push(prettier.hardline); - } - token.trailingComments.forEach(element => { - if (element.startLine !== token.startLine) { - arr.push(concat(formatComment(element))); - arr.push(prettier.hardline); - } else if (element.tokenType.name === "LineComment") { - // Do not add extra space in case of empty statement - const separator = token.image === "" ? "" : " "; - arr.push( - prettier.lineSuffix( - concat([ - separator, - concat(formatComment(element)), - prettier.breakParent - ]) - ) - ); - } else { - arr.push(concat(formatComment(element))); - } - }); - if ( - token.trailingComments[token.trailingComments.length - 1].startLine !== - token.startLine - ) { - arr.pop(); - } - } - - return concat(arr); -} - -function isJavaDoc(comment, lines) { - let isJavaDoc = true; - if (comment.tokenType.name === "TraditionalComment" && lines.length > 1) { - for (let i = 1; i < lines.length; i++) { - if (lines[i].trim().charAt(0) !== "*") { - isJavaDoc = false; - break; - } - } - } else { - isJavaDoc = false; - } - - return isJavaDoc; -} - -function formatJavaDoc(lines) { - const res = [lines[0].trim()]; - - for (let i = 1; i < lines.length; i++) { - res.push(prettier.hardline); - res.push(" " + lines[i].trim()); - } - - return res; -} - -function formatComment(comment) { - const res = []; - const lines = comment.image.split("\n"); - - if (isJavaDoc(comment, lines)) { - return formatJavaDoc(lines); - } - - lines.forEach(line => { - res.push(line); - res.push(prettier.literalline); - }); - res.pop(); - return res; -} - -function isToken(doc) { - return ( - doc && Object.prototype.hasOwnProperty.call(doc, "image") && doc.tokenType - ); -} - -function processComments(docs) { - if (!Array.isArray(docs)) { - if (isToken(docs)) { - return getImageWithComments(docs); - } - return docs; - } - return docs.map(elt => { - if (isToken(elt)) { - return getImageWithComments(elt); - } - return elt; - }); -} +/* + * ------------------------------------------------------------------ + * Wraps the Prettier builder functions to print tokens with comments + * ------------------------------------------------------------------ + */ function concat(docs) { const concatenation = prettier.concat(processComments(docs)); @@ -171,9 +48,5 @@ module.exports = { group, fill, indent, - dedent, - getImageWithComments, - getLeadingComments, - getTrailingComments, - formatComment + dedent }; diff --git a/packages/prettier-plugin-java/src/printers/printer-utils.js b/packages/prettier-plugin-java/src/printers/printer-utils.js index 9b592f9fc..40292b6c8 100644 --- a/packages/prettier-plugin-java/src/printers/printer-utils.js +++ b/packages/prettier-plugin-java/src/printers/printer-utils.js @@ -1,11 +1,7 @@ "use strict"; const _ = require("lodash"); -const { - join, - concat, - group, - getImageWithComments -} = require("./prettier-builder"); +const { join, concat, group } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); const { indent, hardline } = require("prettier").doc.builders; function buildFqn(tokens, dots) { @@ -177,7 +173,7 @@ function findDeepElementInPartsArray(item, elt) { function displaySemicolon(token, params) { if (params !== undefined && params.allowEmptyStatement) { - return getImageWithComments(token); + return printTokenWithComments(token); } if (!hasComments(token)) { @@ -185,7 +181,7 @@ function displaySemicolon(token, params) { } token.image = ""; - return getImageWithComments(token); + return printTokenWithComments(token); } function hasLeadingComments(token) { diff --git a/packages/prettier-plugin-java/src/printers/types-values-and-variables.js b/packages/prettier-plugin-java/src/printers/types-values-and-variables.js index c1e8e1d0f..35ae8d2fc 100644 --- a/packages/prettier-plugin-java/src/printers/types-values-and-variables.js +++ b/packages/prettier-plugin-java/src/printers/types-values-and-variables.js @@ -3,7 +3,8 @@ const _ = require("lodash"); -const { concat, join, getImageWithComments } = require("./prettier-builder"); +const { concat, join } = require("./prettier-builder"); +const { printTokenWithComments } = require("./comments"); const { rejectAndJoin, rejectAndConcat, @@ -26,11 +27,11 @@ class TypesValuesAndVariablesPrettierVisitor { } integralType(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } floatingPointType(ctx) { - return getImageWithComments(this.getSingle(ctx)); + return printTokenWithComments(this.getSingle(ctx)); } referenceType(ctx) { From 596f5aa0cb6dd9f0841b536c76c9677a38123ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Mon, 18 Nov 2019 12:51:55 +0100 Subject: [PATCH 24/26] refactor: clean and document handling comments in parser --- packages/java-parser/src/comments.js | 174 ++++++++++++++++++--------- packages/java-parser/src/index.js | 11 +- packages/java-parser/src/parser.js | 12 +- 3 files changed, 132 insertions(+), 65 deletions(-) diff --git a/packages/java-parser/src/comments.js b/packages/java-parser/src/comments.js index d4481875d..c12134e73 100644 --- a/packages/java-parser/src/comments.js +++ b/packages/java-parser/src/comments.js @@ -34,64 +34,103 @@ function isPrettierIgnoreComment(comment) { ); } -// Optimisation by encapsulating token in a node ? -function preprocessingTokens(tokens, leadingComments, trailingComments) { +/** + * Pre-processing of tokens in order to + * complete the parser's mostEnclosiveCstNodeByStartOffset and mostEnclosiveCstNodeByEndOffset structures. + * + * @param {ITokens[]} tokens - array of tokens + * @param {{[startOffset: number]: CSTNode}} mostEnclosiveCstNodeByStartOffset + * @param {{[endOffset: number]: CSTNode}} mostEnclosiveCstNodeByEndOffset + */ +function completeMostEnclosiveCSTNodeByOffset( + tokens, + mostEnclosiveCstNodeByStartOffset, + mostEnclosiveCstNodeByEndOffset +) { tokens.forEach(token => { - if (leadingComments[token.startOffset] === undefined) { - leadingComments[token.startOffset] = token; + if (mostEnclosiveCstNodeByStartOffset[token.startOffset] === undefined) { + mostEnclosiveCstNodeByStartOffset[token.startOffset] = token; } - if (trailingComments[token.endOffset] === undefined) { - trailingComments[token.endOffset] = token; + if (mostEnclosiveCstNodeByEndOffset[token.endOffset] === undefined) { + mostEnclosiveCstNodeByEndOffset[token.endOffset] = token; } }); } -function preprocessingComments(tokens, comments) { - const commentsEndOffset = {}; - const commentsStartOffset = {}; +/** + * Create two data structures we use to know at which offset a comment can be attached. + * - commentsByExtendedStartOffset: map a comment by the endOffset of the previous token. + * - commentsByExtendedEndOffset: map a comment by the startOffset of the next token + * + * @param {ITokens[]} tokens - array of tokens + * @param {[]} comments - array of comments + * + * @return {{commentsByExtendedStartOffset: {[extendedStartOffset: number]: Comment[]}, commentsByExtendedEndOffset: {[extendedEndOffset: number]: Comment[]}}} + */ +function mapCommentsByExtendedRange(tokens, comments) { + const commentsByExtendedEndOffset = {}; + const commentsByExtendedStartOffset = {}; let position; comments.forEach(comment => { position = findUpperBoundToken(tokens, comment); - const startOffset = + + const extendedStartOffset = position - 1 < 0 ? comment.startOffset : tokens[position - 1].endOffset; - const endOffset = + const extendedEndOffset = position == tokens.length ? comment.endOffset : tokens[position].startOffset; comment.extendedOffset = { - endOffset + endOffset: extendedEndOffset }; - if (commentsEndOffset[endOffset] === undefined) { - commentsEndOffset[endOffset] = [comment]; + if (commentsByExtendedEndOffset[extendedEndOffset] === undefined) { + commentsByExtendedEndOffset[extendedEndOffset] = [comment]; } else { - commentsEndOffset[endOffset].push(comment); + commentsByExtendedEndOffset[extendedEndOffset].push(comment); } - if (commentsStartOffset[startOffset] === undefined) { - commentsStartOffset[startOffset] = [comment]; + if (commentsByExtendedStartOffset[extendedStartOffset] === undefined) { + commentsByExtendedStartOffset[extendedStartOffset] = [comment]; } else { - commentsStartOffset[startOffset].push(comment); + commentsByExtendedStartOffset[extendedStartOffset].push(comment); } }); - return { commentsEndOffset, commentsStartOffset }; + return { commentsByExtendedEndOffset, commentsByExtendedStartOffset }; } -function shouldAttachTrailingComments(comment, node, parser) { +/** + * Determine if a comment should be attached as a trailing comment to a specific node. + * A comment should be trailing if it is on the same line than the previous token and + * not on the same line than the next token + * + * @param {*} comment + * @param {CSTNode} node + * @param {{[startOffset: number]: CSTNode}} mostEnclosiveCstNodeByStartOffset + */ +function shouldAttachTrailingComments( + comment, + node, + mostEnclosiveCstNodeByStartOffset +) { if (isPrettierIgnoreComment(comment)) { return false; } - const nextNode = parser.leadingComments[comment.extendedOffset.endOffset]; + const nextNode = + mostEnclosiveCstNodeByStartOffset[comment.extendedOffset.endOffset]; + + // Last node of the file if (nextNode === undefined) { return true; } const nodeEndLine = node.location !== undefined ? node.location.endLine : node.endLine; + if (comment.startLine !== nodeEndLine) { return false; } @@ -103,37 +142,62 @@ function shouldAttachTrailingComments(comment, node, parser) { return comment.endLine !== nextNodeStartLine; } -function attachComments(tokens, comments, parser) { - // Edge case: only comments +/** + * Attach comments to the most enclosive CSTNode (node or token) + * + * @param {ITokens[]} tokens + * @param {*} comments + * @param {{[startOffset: number]: CSTNode}} mostEnclosiveCstNodeByStartOffset + * @param {{[endOffset: number]: CSTNode}} mostEnclosiveCstNodeByEndOffset + */ +function attachComments( + tokens, + comments, + mostEnclosiveCstNodeByStartOffset, + mostEnclosiveCstNodeByEndOffset +) { + // Edge case: only comments in the file if (tokens.length === 0) { - parser.leadingComments[NaN].leadingComments = comments; + mostEnclosiveCstNodeByStartOffset[NaN].leadingComments = comments; return; } - preprocessingTokens(tokens, parser.leadingComments, parser.trailingComments); - - const { commentsStartOffset, commentsEndOffset } = preprocessingComments( + // Pre-processing phase to complete the data structures we need to attach + // a comment to the right place + completeMostEnclosiveCSTNodeByOffset( tokens, - comments + mostEnclosiveCstNodeByStartOffset, + mostEnclosiveCstNodeByEndOffset ); + const { + commentsByExtendedStartOffset, + commentsByExtendedEndOffset + } = mapCommentsByExtendedRange(tokens, comments); + + /* + This set is here to ensure that we attach comments only once + If a comment is attached to a node or token, we remove it from this set + */ const commentsToAttach = new Set(comments); - Object.keys(parser.trailingComments).forEach(endOffset => { - if (commentsStartOffset[endOffset] !== undefined) { - const nodeTrailingComments = commentsStartOffset[endOffset].filter( - comment => { - return ( - shouldAttachTrailingComments( - comment, - parser.trailingComments[endOffset], - parser - ) && commentsToAttach.has(comment) - ); - } - ); + // Attach comments as trailing comments if desirable + Object.keys(mostEnclosiveCstNodeByEndOffset).forEach(endOffset => { + // We look if some comments is directly following this node/token + if (commentsByExtendedStartOffset[endOffset] !== undefined) { + const nodeTrailingComments = commentsByExtendedStartOffset[ + endOffset + ].filter(comment => { + return ( + shouldAttachTrailingComments( + comment, + mostEnclosiveCstNodeByEndOffset[endOffset], + mostEnclosiveCstNodeByStartOffset + ) && commentsToAttach.has(comment) + ); + }); if (nodeTrailingComments.length > 0) { - parser.trailingComments[ + mostEnclosiveCstNodeByEndOffset[ endOffset ].trailingComments = nodeTrailingComments; } @@ -144,33 +208,27 @@ function attachComments(tokens, comments, parser) { } }); - Object.keys(parser.leadingComments).forEach(startOffset => { - if (commentsEndOffset[startOffset] !== undefined) { - const nodeLeadingComments = commentsEndOffset[startOffset].filter( - comment => commentsToAttach.has(comment) - ); + // Attach rest of comments as leading comments + Object.keys(mostEnclosiveCstNodeByStartOffset).forEach(startOffset => { + // We look if some comments is directly preceding this node/token + if (commentsByExtendedEndOffset[startOffset] !== undefined) { + const nodeLeadingComments = commentsByExtendedEndOffset[ + startOffset + ].filter(comment => commentsToAttach.has(comment)); if (nodeLeadingComments.length > 0) { - parser.leadingComments[ + mostEnclosiveCstNodeByStartOffset[ startOffset ].leadingComments = nodeLeadingComments; } // prettier ignore support - let ignoreNode = false; for (let i = 0; i < nodeLeadingComments.length; i++) { if (isPrettierIgnoreComment(nodeLeadingComments[i])) { - ignoreNode = true; + mostEnclosiveCstNodeByStartOffset[startOffset].ignore = true; + break; } } - - if (ignoreNode) { - parser.leadingComments[startOffset].ignore = true; - } - - nodeLeadingComments.forEach(comment => { - commentsToAttach.delete(comment); - }); } }); } diff --git a/packages/java-parser/src/index.js b/packages/java-parser/src/index.js index 6e7377078..84548efc9 100644 --- a/packages/java-parser/src/index.js +++ b/packages/java-parser/src/index.js @@ -24,8 +24,8 @@ function parse(inputText, entryPoint = "compilationUnit") { } parser.input = lexResult.tokens; - parser.leadingComments = {}; - parser.trailingComments = {}; + parser.mostEnclosiveCstNodeByStartOffset = {}; + parser.mostEnclosiveCstNodeByEndOffset = {}; // Automatic CST created when parsing const cst = parser[entryPoint](); @@ -44,7 +44,12 @@ function parse(inputText, entryPoint = "compilationUnit") { ); } - attachComments(lexResult.tokens, lexResult.groups.comments, parser); + attachComments( + lexResult.tokens, + lexResult.groups.comments, + parser.mostEnclosiveCstNodeByStartOffset, + parser.mostEnclosiveCstNodeByEndOffset + ); return cst; } diff --git a/packages/java-parser/src/parser.js b/packages/java-parser/src/parser.js index 1eeeb3d4c..2e0d999d3 100644 --- a/packages/java-parser/src/parser.js +++ b/packages/java-parser/src/parser.js @@ -45,8 +45,8 @@ class JavaParser extends Parser { const $ = this; - this.leadingComments = {}; - this.trailingComments = {}; + this.mostEnclosiveCstNodeByStartOffset = {}; + this.mostEnclosiveCstNodeByEndOffset = {}; // --------------------- // Productions from §3 (Lexical Structure) @@ -78,8 +78,12 @@ class JavaParser extends Parser { cstPostNonTerminal(ruleCstResult, ruleName) { super.cstPostNonTerminal(ruleCstResult, ruleName); if (this.isBackTracking() === false) { - this.leadingComments[ruleCstResult.location.startOffset] = ruleCstResult; - this.trailingComments[ruleCstResult.location.endOffset] = ruleCstResult; + this.mostEnclosiveCstNodeByStartOffset[ + ruleCstResult.location.startOffset + ] = ruleCstResult; + this.mostEnclosiveCstNodeByEndOffset[ + ruleCstResult.location.endOffset + ] = ruleCstResult; } } From 4e8fe2b1b4a6dc0b85f7aea1c21ad375bcd65a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Mon, 18 Nov 2019 13:08:10 +0100 Subject: [PATCH 25/26] docs: add docs on comments handling in the Java parser --- packages/java-parser/docs/comments.md | 58 +++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 packages/java-parser/docs/comments.md diff --git a/packages/java-parser/docs/comments.md b/packages/java-parser/docs/comments.md new file mode 100644 index 000000000..775b5acce --- /dev/null +++ b/packages/java-parser/docs/comments.md @@ -0,0 +1,58 @@ +# Handling comments + +## Objective + +Attach each comment to a CST node or token as either leading or trainling comment. + +### Attach comment to the highest node possible + +A comment could often be attached at several nodes or token. For instance, in the following code snippet: + +```java +// comment +public void t() {} +``` + +`// comment` could be attached to: + +- the `methodDeclaration` node +- the `methodModifier` node +- the `public` token + +We have made the decision to attach the comment to the highest node possible (the most enclosive one). It makes the more sense to us, and it ease handling comments in the prettier-plugin. + +### Trailing comments + +A comment should be considered as a trailing comment in very specific cases: + +- If it is on the same line as the node/token it followed, and not on the same line as the node/token it preceded. For instance, `//comment` is considered as a trailing comment in the following code snippet: + + ```java + int i = 1; // comment + int j = 2; + ``` + +- If it is at the end of the file + +### Consecutives comments + +If there are consecutive comments, each comment will be considered separately. For instance: + +```java +int i = 1; +// comment1 +// comment2 +int j = 2; +``` + +`// comment1` and `// comment2` will be both attached as leading comments to the second `localVariableDeclarationStatement` node. + +When in: + +```java +int i = 1; // comment1 +// comment2 +int j = 2; +``` + +`// comment1` will be attached as a trailing comment to the first `localVariableDeclarationStatement` node and `// comment2` will be attached as a leading comment to the second one. From ae624c9d4be3b55a1cca3e1ccea2781bc9f47cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Dessoude?= Date: Mon, 25 Nov 2019 22:51:21 +0100 Subject: [PATCH 26/26] fix typo --- packages/java-parser/docs/comments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/java-parser/docs/comments.md b/packages/java-parser/docs/comments.md index 775b5acce..e468ada01 100644 --- a/packages/java-parser/docs/comments.md +++ b/packages/java-parser/docs/comments.md @@ -2,7 +2,7 @@ ## Objective -Attach each comment to a CST node or token as either leading or trainling comment. +Attach each comment to a CST node or token as either leading or trailing comment. ### Attach comment to the highest node possible