/*
* SonarQube Java
* Copyright (C) 2012-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program 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 3 of the License, or (at your option) any later version.
*
* 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 GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.java.model;
import org.sonar.plugins.java.api.tree.Arguments;
import org.sonar.plugins.java.api.tree.ArrayAccessExpressionTree;
import org.sonar.plugins.java.api.tree.AssignmentExpressionTree;
import org.sonar.plugins.java.api.tree.BinaryExpressionTree;
import org.sonar.plugins.java.api.tree.BlockTree;
import org.sonar.plugins.java.api.tree.ConditionalExpressionTree;
import org.sonar.plugins.java.api.tree.ExpressionStatementTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.ForEachStatement;
import org.sonar.plugins.java.api.tree.ForStatementTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.IfStatementTree;
import org.sonar.plugins.java.api.tree.InstanceOfTree;
import org.sonar.plugins.java.api.tree.ListTree;
import org.sonar.plugins.java.api.tree.LiteralTree;
import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.ModifierTree;
import org.sonar.plugins.java.api.tree.NewClassTree;
import org.sonar.plugins.java.api.tree.ParenthesizedTree;
import org.sonar.plugins.java.api.tree.ReturnStatementTree;
import org.sonar.plugins.java.api.tree.StatementTree;
import org.sonar.plugins.java.api.tree.SwitchStatementTree;
import org.sonar.plugins.java.api.tree.SynchronizedStatementTree;
import org.sonar.plugins.java.api.tree.SyntaxToken;
import org.sonar.plugins.java.api.tree.ThrowStatementTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.TypeCastTree;
import org.sonar.plugins.java.api.tree.UnaryExpressionTree;
import org.sonar.plugins.java.api.tree.VariableTree;
import org.sonar.plugins.java.api.tree.WhileStatementTree;
public class SyntaxTreeDebug {
private SyntaxTreeDebug() {
}
public static String toString(Tree syntaxNode) {
switch (syntaxNode.kind()) {
case ARGUMENTS:
return argumentsString((Arguments) syntaxNode);
case VARIABLE:
return variableString((VariableTree) syntaxNode);
case IDENTIFIER:
return identifierString((IdentifierTree) syntaxNode);
case METHOD_INVOCATION:
return methodInvocationString((MethodInvocationTree) syntaxNode);
case MEMBER_SELECT:
return memberSelectString((MemberSelectExpressionTree) syntaxNode);
case EQUAL_TO:
case NOT_EQUAL_TO:
case CONDITIONAL_AND:
case CONDITIONAL_OR:
case LESS_THAN:
case LESS_THAN_OR_EQUAL_TO:
case GREATER_THAN:
case GREATER_THAN_OR_EQUAL_TO:
case AND:
case OR:
case XOR:
case PLUS:
case MINUS:
case MULTIPLY:
case DIVIDE:
case REMAINDER:
case LEFT_SHIFT:
case RIGHT_SHIFT:
case UNSIGNED_RIGHT_SHIFT:
return binaryExpressionString((BinaryExpressionTree) syntaxNode);
case ASSIGNMENT:
case PLUS_ASSIGNMENT:
case MINUS_ASSIGNMENT:
case MULTIPLY_ASSIGNMENT:
case DIVIDE_ASSIGNMENT:
case REMAINDER_ASSIGNMENT:
case AND_ASSIGNMENT:
case LEFT_SHIFT_ASSIGNMENT:
case RIGHT_SHIFT_ASSIGNMENT:
case UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
return assignmentString((AssignmentExpressionTree) syntaxNode);
case NULL_LITERAL:
return "null";
case STRING_LITERAL:
case CHAR_LITERAL:
case BOOLEAN_LITERAL:
case INT_LITERAL:
case LONG_LITERAL:
case FLOAT_LITERAL:
case DOUBLE_LITERAL:
return literalString((LiteralTree) syntaxNode);
case IF_STATEMENT:
return ifStatementString((IfStatementTree) syntaxNode);
case FOR_EACH_STATEMENT:
return forEachStatementString((ForEachStatement) syntaxNode);
case FOR_STATEMENT:
return forStatementString((ForStatementTree) syntaxNode);
case NEW_CLASS:
return newInstanceString((NewClassTree) syntaxNode);
case LIST:
return listString((ListTree<?>) syntaxNode);
case INSTANCE_OF:
return instanceOfString((InstanceOfTree) syntaxNode);
case RETURN_STATEMENT:
return returnString((ReturnStatementTree) syntaxNode);
case CONDITIONAL_EXPRESSION:
return conditionalExpressionString((ConditionalExpressionTree) syntaxNode);
case EMPTY_STATEMENT:
case TRY_STATEMENT:
case DO_STATEMENT:
return "";
case SYNCHRONIZED_STATEMENT:
return synchronizedStatementString((SynchronizedStatementTree) syntaxNode);
case PREFIX_DECREMENT:
case PREFIX_INCREMENT:
case LOGICAL_COMPLEMENT:
case BITWISE_COMPLEMENT:
case UNARY_MINUS:
case UNARY_PLUS:
return prefixExpressionString((UnaryExpressionTree) syntaxNode);
case POSTFIX_DECREMENT:
case POSTFIX_INCREMENT:
return postfixExpressionString((UnaryExpressionTree) syntaxNode);
case TYPE_CAST:
return typeCastString((TypeCastTree) syntaxNode);
case PARENTHESIZED_EXPRESSION:
return parenthesizedTreeString((ParenthesizedTree) syntaxNode);
case WHILE_STATEMENT:
return whileStatementString((WhileStatementTree) syntaxNode);
case SWITCH_STATEMENT:
return switchStatementString((SwitchStatementTree) syntaxNode);
case BREAK_STATEMENT:
return "break";
case CONTINUE_STATEMENT:
return "continue";
case ARRAY_ACCESS_EXPRESSION:
return arrayAccessString((ArrayAccessExpressionTree) syntaxNode);
case THROW_STATEMENT:
return throwStatementString((ThrowStatementTree) syntaxNode);
case EXPRESSION_STATEMENT:
return expressionStatementString((ExpressionStatementTree) syntaxNode);
case METHOD:
return methodString((MethodTree) syntaxNode);
case BLOCK:
return blockString((BlockTree) syntaxNode);
default:
return syntaxNode.toString();
}
}
private static String blockString(BlockTree syntaxNode) {
StringBuilder buffer = new StringBuilder();
boolean first = true;
for (StatementTree tree : syntaxNode.body()) {
if (first) {
first = false;
} else {
buffer.append(", ");
}
buffer.append(tree);
}
return buffer.toString();
}
private static String methodString(MethodTree syntaxNode) {
StringBuilder buffer = new StringBuilder();
for (ModifierTree modifier : syntaxNode.modifiers()) {
if (modifier.is(Tree.Kind.TOKEN)) {
buffer.append(((SyntaxToken) modifier).text());
buffer.append(' ');
}
}
buffer.append(syntaxNode.returnType().symbolType().toString());
buffer.append(' ');
buffer.append(syntaxNode.simpleName().name());
buffer.append('(');
boolean first = true;
for (VariableTree parameter : syntaxNode.parameters()) {
if (first) {
first = false;
} else {
buffer.append(", ");
}
buffer.append(parameter.type().symbolType().toString());
buffer.append(' ');
buffer.append(parameter.simpleName().toString());
}
buffer.append(')');
return buffer.toString();
}
private static String synchronizedStatementString(SynchronizedStatementTree syntaxNode) {
return "synchronized(" + toString(syntaxNode.expression()) + ')';
}
private static String argumentsString(Arguments syntaxNode) {
StringBuilder buffer = new StringBuilder();
boolean first = true;
for (ExpressionTree expressionTree : syntaxNode) {
if (first) {
first = false;
} else {
buffer.append(',');
}
buffer.append(toString(expressionTree));
}
return buffer.toString();
}
private static String expressionStatementString(ExpressionStatementTree syntaxNode) {
return toString(syntaxNode.expression());
}
private static String methodInvocationString(MethodInvocationTree method) {
StringBuilder buffer = new StringBuilder();
ExpressionTree methodSelect = method.methodSelect();
if (methodSelect.is(Tree.Kind.IDENTIFIER)) {
buffer.append(identifierString((IdentifierTree) methodSelect));
} else if (methodSelect.is(Tree.Kind.MEMBER_SELECT)) {
buffer.append(memberSelectString((MemberSelectExpressionTree) methodSelect));
}
buffer.append('(');
buffer.append(toString(method.arguments()));
buffer.append(')');
return buffer.toString();
}
private static String variableString(VariableTree variable) {
return variable.simpleName().name();
}
private static String identifierString(IdentifierTree identifier) {
return identifier.name();
}
private static String literalString(LiteralTree literal) {
return literal.token().text();
}
private static String memberSelectString(MemberSelectExpressionTree expression) {
StringBuilder buffer = new StringBuilder();
ExpressionTree target = expression.expression();
switch (target.kind()) {
case IDENTIFIER:
buffer.append(identifierString((IdentifierTree) target));
break;
case METHOD_INVOCATION:
buffer.append(methodInvocationString((MethodInvocationTree) target));
break;
case VARIABLE:
buffer.append(variableString((VariableTree) target));
break;
case INT_LITERAL:
buffer.append(literalString((LiteralTree) target));
break;
default:
break;
}
buffer.append('.');
buffer.append(identifierString(expression.identifier()));
return buffer.toString();
}
private static String prefixExpressionString(UnaryExpressionTree syntaxNode) {
return syntaxNode.operatorToken().text() + toString(syntaxNode.expression());
}
private static String postfixExpressionString(UnaryExpressionTree syntaxNode) {
return toString(syntaxNode.expression()) + syntaxNode.operatorToken().text();
}
private static String typeCastString(TypeCastTree syntaxNode) {
return "(" + syntaxNode.type().toString() + ") ";
}
private static String assignmentString(AssignmentExpressionTree syntaxNode) {
return toString(syntaxNode.variable()) + syntaxNode.operatorToken().text() + toString(syntaxNode.expression());
}
private static String ifStatementString(IfStatementTree syntaxNode) {
return "if (" + toString(syntaxNode.condition()) + ')';
}
private static String forStatementString(ForStatementTree syntaxNode) {
StringBuilder buffer = new StringBuilder("for {");
if (syntaxNode.initializer() != null) {
buffer.append(toString(syntaxNode.initializer()));
}
buffer.append(';');
if (syntaxNode.condition() != null) {
buffer.append(toString(syntaxNode.condition()));
}
buffer.append(';');
if (syntaxNode.update() != null) {
buffer.append(toString(syntaxNode.update()));
}
buffer.append('}');
return buffer.toString();
}
private static String listString(ListTree<?> syntaxNode) {
StringBuilder buffer = new StringBuilder();
boolean first = true;
for (Object object : syntaxNode) {
if (first) {
first = false;
} else {
buffer.append(',');
}
buffer.append(toString((Tree) object));
}
return buffer.toString();
}
private static String binaryExpressionString(BinaryExpressionTree syntaxNode) {
return toString(syntaxNode.leftOperand()) + ' ' + syntaxNode.operatorToken().text() + ' ' + toString(syntaxNode.rightOperand());
}
private static String conditionalExpressionString(ConditionalExpressionTree syntaxNode) {
return toString(syntaxNode.condition()) + " ? " + toString(syntaxNode.trueExpression()) + " : " + toString(syntaxNode.falseExpression());
}
private static String instanceOfString(InstanceOfTree syntaxNode) {
return toString(syntaxNode.expression()) + ' ' + syntaxNode.instanceofKeyword().text() + ' ' + syntaxNode.type().toString();
}
private static String returnString(ReturnStatementTree syntaxNode) {
StringBuilder buffer = new StringBuilder("return");
if (syntaxNode.expression() != null) {
buffer.append(' ');
buffer.append(toString(syntaxNode.expression()));
}
return buffer.toString();
}
private static String parenthesizedTreeString(ParenthesizedTree syntaxNode) {
return "(" + toString(syntaxNode.expression()) + ')';
}
private static String whileStatementString(WhileStatementTree syntaxNode) {
return "while (" + toString(syntaxNode.condition()) + ')';
}
private static String switchStatementString(SwitchStatementTree syntaxNode) {
return "switch (" + toString(syntaxNode.expression()) + ')';
}
private static String forEachStatementString(ForEachStatement syntaxNode) {
return "for {" + variableString(syntaxNode.variable()) + " : " + toString(syntaxNode.expression()) + '}';
}
private static String arrayAccessString(ArrayAccessExpressionTree syntaxNode) {
return toString(syntaxNode.expression()) + '[' + toString(syntaxNode.dimension().expression()) + ']';
}
private static String throwStatementString(ThrowStatementTree syntaxNode) {
return "throw " + toString(syntaxNode.expression());
}
private static String newInstanceString(NewClassTree syntaxNode) {
StringBuilder buffer = new StringBuilder("new ");
buffer.append(syntaxNode.identifier().toString());
buffer.append('(');
boolean first = true;
for (ExpressionTree argument : syntaxNode.arguments()) {
if (first) {
first = false;
} else {
buffer.append(',');
}
buffer.append(toString(argument));
}
buffer.append(')');
return buffer.toString();
}
}