ParserUtil.java
////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code for adherence to a set of rules.
// Copyright (C) 2001-2021 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
////////////////////////////////////////////////////////////////////////////////
package com.puppycrawl.tools.checkstyle.utils;
import java.util.AbstractMap;
import java.util.Map;
import antlr.Token;
import com.puppycrawl.tools.checkstyle.DetailAstImpl;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
/**
* Contains utility methods for parser to use while creating ast.
*/
public final class ParserUtil {
/** Symbols with which javadoc starts. */
private static final String JAVADOC_START = "/**";
/** Symbols with which multiple comment starts. */
private static final String BLOCK_MULTIPLE_COMMENT_BEGIN = "/*";
/** Symbols with which multiple comment ends. */
private static final String BLOCK_MULTIPLE_COMMENT_END = "*/";
/** Stop instances being created. **/
private ParserUtil() {
}
/**
* Create block comment from string content.
*
* @param content comment content.
* @return DetailAST block comment
*/
public static DetailAST createBlockCommentNode(String content) {
final DetailAstImpl blockCommentBegin = new DetailAstImpl();
blockCommentBegin.setType(TokenTypes.BLOCK_COMMENT_BEGIN);
blockCommentBegin.setText(BLOCK_MULTIPLE_COMMENT_BEGIN);
blockCommentBegin.setLineNo(0);
blockCommentBegin.setColumnNo(-JAVADOC_START.length());
final DetailAstImpl commentContent = new DetailAstImpl();
commentContent.setType(TokenTypes.COMMENT_CONTENT);
commentContent.setText("*" + content);
commentContent.setLineNo(0);
// javadoc should starts at 0 column, so COMMENT_CONTENT node
// that contains javadoc identifier has -1 column
commentContent.setColumnNo(-1);
final DetailAstImpl blockCommentEnd = new DetailAstImpl();
blockCommentEnd.setType(TokenTypes.BLOCK_COMMENT_END);
blockCommentEnd.setText(BLOCK_MULTIPLE_COMMENT_END);
blockCommentBegin.setFirstChild(commentContent);
commentContent.setNextSibling(blockCommentEnd);
return blockCommentBegin;
}
/**
* Create block comment from token.
*
* @param token Token object.
* @return DetailAST with BLOCK_COMMENT type.
*/
public static DetailAST createBlockCommentNode(Token token) {
final DetailAstImpl blockComment = new DetailAstImpl();
blockComment.initialize(TokenTypes.BLOCK_COMMENT_BEGIN, BLOCK_MULTIPLE_COMMENT_BEGIN);
// column counting begins from 0
blockComment.setColumnNo(token.getColumn() - 1);
blockComment.setLineNo(token.getLine());
final DetailAstImpl blockCommentContent = new DetailAstImpl();
blockCommentContent.setType(TokenTypes.COMMENT_CONTENT);
// column counting begins from 0
// plus length of '/*'
blockCommentContent.setColumnNo(token.getColumn() - 1 + 2);
blockCommentContent.setLineNo(token.getLine());
blockCommentContent.setText(token.getText());
final DetailAstImpl blockCommentClose = new DetailAstImpl();
blockCommentClose.initialize(TokenTypes.BLOCK_COMMENT_END, BLOCK_MULTIPLE_COMMENT_END);
final Map.Entry<Integer, Integer> linesColumns = countLinesColumns(
token.getText(), token.getLine(), token.getColumn());
blockCommentClose.setLineNo(linesColumns.getKey());
blockCommentClose.setColumnNo(linesColumns.getValue());
blockComment.addChild(blockCommentContent);
blockComment.addChild(blockCommentClose);
return blockComment;
}
/**
* Count lines and columns (in last line) in text.
*
* @param text String.
* @param initialLinesCnt initial value of lines counter.
* @param initialColumnsCnt initial value of columns counter.
* @return entry(pair), key is line counter, value is column counter.
*/
private static Map.Entry<Integer, Integer> countLinesColumns(
String text, int initialLinesCnt, int initialColumnsCnt) {
int lines = initialLinesCnt;
int columns = initialColumnsCnt;
boolean foundCr = false;
for (char c : text.toCharArray()) {
if (c == '\n') {
foundCr = false;
lines++;
columns = 0;
}
else {
if (foundCr) {
foundCr = false;
lines++;
columns = 0;
}
if (c == '\r') {
foundCr = true;
}
columns++;
}
}
if (foundCr) {
lines++;
columns = 0;
}
return new AbstractMap.SimpleEntry<>(lines, columns);
}
}