Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

review: refactor: PrinterHelper to CommentHelper, LiteralHelper and OperatorHelper #1525

Merged
merged 7 commits into from Sep 11, 2017
Merged
134 changes: 134 additions & 0 deletions src/main/java/spoon/reflect/visitor/CommentHelper.java
@@ -0,0 +1,134 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program 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 CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.visitor;

import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtJavaDoc;
import spoon.reflect.code.CtJavaDocTag;
import spoon.reflect.visitor.printer.PrinterHelper;

import static spoon.reflect.visitor.DefaultJavaPrettyPrinter.JAVADOC_START;
import static spoon.reflect.visitor.DefaultJavaPrettyPrinter.INLINE_COMMENT_START;
import static spoon.reflect.visitor.DefaultJavaPrettyPrinter.BLOCK_COMMENT_START;
import static spoon.reflect.visitor.DefaultJavaPrettyPrinter.BLOCK_COMMENT_END;

import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

import static spoon.reflect.visitor.DefaultJavaPrettyPrinter.COMMENT_STAR;

/**
* Computes source code representation of the Comment literal
*/
class CommentHelper {

/**
* RegExp which matches all possible line separators
*/
private static final Pattern LINE_SEPARATORS_RE = Pattern.compile("\\n\\r|\\n|\\r");

private CommentHelper() {
}

public static void printComment(PrinterHelper printer, CtComment comment) {
List<CtJavaDocTag> tags = null;
if (comment instanceof CtJavaDoc) {
tags = ((CtJavaDoc) comment).getTags();
}
printComment(printer, comment.getCommentType(), comment.getContent(), tags);
}

public static void printComment(PrinterHelper printer, CtComment.CommentType commentType, String content, Collection<CtJavaDocTag> javaDocTags) {
switch (commentType) {
case FILE:
printer.write(JAVADOC_START).writeln();
break;
case JAVADOC:
printer.write(JAVADOC_START).writeln().writeTabs();
break;
case INLINE:
printer.write(INLINE_COMMENT_START);
break;
case BLOCK:
printer.write(BLOCK_COMMENT_START);
break;
}
switch (commentType) {
case INLINE:
printer.write(content);
break;
default:
String[] lines = LINE_SEPARATORS_RE.split(content);
for (int i = 0; i < lines.length; i++) {
String com = lines[i];
if (commentType == CtComment.CommentType.BLOCK) {
printer.write(com);
if (lines.length > 1) {
printer.writeln().writeTabs();
}
} else {
if (com.length() > 0) {
printer.write(COMMENT_STAR + com).writeln().writeTabs();
} else {
printer.write(" *" /* no trailing space */ + com).writeln().writeTabs();
}
}
}
if (javaDocTags != null && javaDocTags.isEmpty() == false) {
printer.write(" *").writeln().writeTabs();
for (CtJavaDocTag docTag : javaDocTags) {
printJavaDocTag(printer, docTag);
}
}
break;
}
switch (commentType) {
case BLOCK:
printer.write(BLOCK_COMMENT_END);
break;
case FILE:
printer.write(BLOCK_COMMENT_END);
break;
case JAVADOC:
printer.write(BLOCK_COMMENT_END);
break;
}
}

public static void printJavaDocTag(PrinterHelper printer, CtJavaDocTag docTag) {
printer.write(COMMENT_STAR);
printer.write(CtJavaDocTag.JAVADOC_TAG_PREFIX);
printer.write(docTag.getType().name().toLowerCase());
printer.write(" ");
if (docTag.getType().hasParam()) {
printer.write(docTag.getParam()).writeln().writeTabs();
}

String[] tagLines = LINE_SEPARATORS_RE.split(docTag.getContent());
for (int i = 0; i < tagLines.length; i++) {
String com = tagLines[i];
if (i > 0 || docTag.getType().hasParam()) {
printer.write(COMMENT_STAR);
}
if (docTag.getType().hasParam()) {
printer.write("\t\t");
}
printer.write(com.trim()).writeln().writeTabs();
}
}
}
85 changes: 7 additions & 78 deletions src/main/java/spoon/reflect/visitor/DefaultJavaPrettyPrinter.java
Expand Up @@ -911,91 +911,20 @@ public void visitCtJavaDoc(CtJavaDoc comment) {

@Override
public void visitCtJavaDocTag(CtJavaDocTag docTag) {
printer.write(COMMENT_STAR);
printer.write(CtJavaDocTag.JAVADOC_TAG_PREFIX);
printer.write(docTag.getType().name().toLowerCase());
printer.write(" ");
if (docTag.getType().hasParam()) {
printer.write(docTag.getParam()).writeln().writeTabs();
}

String[] tagLines = docTag.getContent().split(CtComment.LINE_SEPARATOR);
for (int i = 0; i < tagLines.length; i++) {
String com = tagLines[i];
if (i > 0 || docTag.getType().hasParam()) {
printer.write(COMMENT_STAR);
}
if (docTag.getType().hasParam()) {
printer.write("\t\t");
}
printer.write(com.trim()).writeln().writeTabs();
}
/*
* is not called during normal printing of java sources.
* It can be called only when CtJavaDocTag has to be printed directly.
* E.g. from CtJavaDocTag#toString
*/
CommentHelper.printJavaDocTag(printer, docTag);
}

@Override
public void visitCtComment(CtComment comment) {
if (!env.isCommentsEnabled() && context.elementStack.size() > 1) {
return;
}
switch (comment.getCommentType()) {
case FILE:
printer.write(JAVADOC_START).writeln();
break;
case JAVADOC:
printer.write(JAVADOC_START).writeln().writeTabs();
break;
case INLINE:
printer.write(INLINE_COMMENT_START);
break;
case BLOCK:
printer.write(BLOCK_COMMENT_START);
break;
}
String content = comment.getContent();
switch (comment.getCommentType()) {
case INLINE:
printer.write(content);
break;
default:
String[] lines = content.split(CtComment.LINE_SEPARATOR);
for (int i = 0; i < lines.length; i++) {
String com = lines[i];
if (comment.getCommentType() == CtComment.CommentType.BLOCK) {
printer.write(com);
if (lines.length > 1) {
printer.writeln().writeTabs();
}
} else {
if (com.length() > 0) {
printer.write(COMMENT_STAR + com).writeln().writeTabs();
} else {
printer.write(" *" /* no trailing space */ + com).writeln().writeTabs();
}
}

}
if (comment instanceof CtJavaDoc) {
if (!((CtJavaDoc) comment).getTags().isEmpty()) {
printer.write(" *").writeln().writeTabs();
}
for (CtJavaDocTag docTag : ((CtJavaDoc) comment).getTags()) {
scan(docTag);
}
}
break;
}

switch (comment.getCommentType()) {
case BLOCK:
printer.write(BLOCK_COMMENT_END);
break;
case FILE:
printer.write(BLOCK_COMMENT_END);
break;
case JAVADOC:
printer.write(BLOCK_COMMENT_END);
break;
}
CommentHelper.printComment(printer, comment);
}

@Override
Expand Down
132 changes: 132 additions & 0 deletions src/main/java/spoon/reflect/visitor/printer/LiteralHelper.java
@@ -0,0 +1,132 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program 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 CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.visitor.printer;

import spoon.reflect.code.CtLiteral;
import spoon.reflect.cu.SourcePosition;

/**
* Computes source code representation of the literal
*/
abstract class LiteralHelper {

private LiteralHelper() {
}

/**
* @param literal to be converted literal
* @return source code representation of the literal
*/
public static <T> String getLiteralToken(CtLiteral<T> literal) {
if (literal.getValue() == null) {
return "null";
} else if (literal.getValue() instanceof Long) {
return literal.getValue() + "L";
} else if (literal.getValue() instanceof Float) {
return literal.getValue() + "F";
} else if (literal.getValue() instanceof Character) {

boolean mayContainsSpecialCharacter = true;

SourcePosition position = literal.getPosition();
if (position != null) {
// the size of the string in the source code, the -1 is the size of the ' or " in the source code
int stringLength = position.getSourceEnd() - position.getSourceStart() - 1;
// if the string in the source is not the same as the string in the literal, the string may contains special characters
mayContainsSpecialCharacter = stringLength != 1;
}
StringBuilder sb = new StringBuilder(10);
sb.append('\'');
appendCharLiteral(sb, (Character) literal.getValue(), mayContainsSpecialCharacter);
sb.append('\'');
return sb.toString();
} else if (literal.getValue() instanceof String) {
boolean mayContainsSpecialCharacters = true;

SourcePosition position = literal.getPosition();
if (position != null) {
// the size of the string in the source code, the -1 is the size of the ' or " in the source code
int stringLength = position.getSourceEnd() - position.getSourceStart() - 1;
// if the string in the source is not the same as the string in the literal, the string may contains special characters
mayContainsSpecialCharacters = ((String) literal.getValue()).length() != stringLength;
}
return "\"" + getStringLiteral((String) literal.getValue(), mayContainsSpecialCharacters) + "\"";
} else if (literal.getValue() instanceof Class) {
return ((Class<?>) literal.getValue()).getName();
} else {
return literal.getValue().toString();
}
}

static void appendCharLiteral(StringBuilder sb, Character c, boolean mayContainsSpecialCharacter) {
if (!mayContainsSpecialCharacter) {
sb.append(c);
} else if (Character.UnicodeBlock.of(c) != Character.UnicodeBlock.BASIC_LATIN) {
if (c < 0x10) {
sb.append("\\u000" + Integer.toHexString(c));
} else if (c < 0x100) {
sb.append("\\u00" + Integer.toHexString(c));
} else if (c < 0x1000) {
sb.append("\\u0" + Integer.toHexString(c));
} else {
sb.append("\\u" + Integer.toHexString(c));
}
} else {
switch (c) {
case '\b':
sb.append("\\b"); //$NON-NLS-1$
break;
case '\t':
sb.append("\\t"); //$NON-NLS-1$
break;
case '\n':
sb.append("\\n"); //$NON-NLS-1$
break;
case '\f':
sb.append("\\f"); //$NON-NLS-1$
break;
case '\r':
sb.append("\\r"); //$NON-NLS-1$
break;
case '\"':
sb.append("\\\""); //$NON-NLS-1$
break;
case '\'':
sb.append("\\'"); //$NON-NLS-1$
break;
case '\\': // take care not to display the escape as a potential
// real char
sb.append("\\\\"); //$NON-NLS-1$
break;
default:
sb.append(Character.isISOControl(c) ? String.format("\\u%04x", (int) c) : Character.toString(c));
}
}
}

static String getStringLiteral(String value, boolean mayContainsSpecialCharacter) {
if (!mayContainsSpecialCharacter) {
return value;
} else {
StringBuilder sb = new StringBuilder(value.length() * 2);
for (int i = 0; i < value.length(); i++) {
appendCharLiteral(sb, value.charAt(i), mayContainsSpecialCharacter);
}
return sb.toString();
}
}
}