Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.sonar.java.model.JavaTreeMaker Maven / Gradle / Ivy
/*
* SonarQube Java
* Copyright (C) 2012 SonarSource
* [email protected]
*
* 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 02
*/
package org.sonar.java.model;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.sonar.sslr.api.AstNode;
import com.sonar.sslr.api.AstNodeType;
import com.sonar.sslr.impl.ast.AstXmlPrinter;
import org.sonar.java.ast.api.JavaKeyword;
import org.sonar.java.ast.api.JavaPunctuator;
import org.sonar.java.ast.api.JavaTokenType;
import org.sonar.java.ast.parser.JavaGrammar;
import org.sonar.plugins.java.api.tree.BlockTree;
import org.sonar.plugins.java.api.tree.CaseGroupTree;
import org.sonar.plugins.java.api.tree.CaseLabelTree;
import org.sonar.plugins.java.api.tree.CatchTree;
import org.sonar.plugins.java.api.tree.ClassTree;
import org.sonar.plugins.java.api.tree.CompilationUnitTree;
import org.sonar.plugins.java.api.tree.ExpressionTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.ImportTree;
import org.sonar.plugins.java.api.tree.LiteralTree;
import org.sonar.plugins.java.api.tree.MethodTree;
import org.sonar.plugins.java.api.tree.Modifier;
import org.sonar.plugins.java.api.tree.ModifiersTree;
import org.sonar.plugins.java.api.tree.PrimitiveTypeTree;
import org.sonar.plugins.java.api.tree.StatementTree;
import org.sonar.plugins.java.api.tree.SwitchStatementTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.TryStatementTree;
import org.sonar.plugins.java.api.tree.VariableTree;
import javax.annotation.Nullable;
import java.util.List;
public class JavaTreeMaker {
private final KindMaps kindMaps = new KindMaps();
private static void checkType(AstNode astNode, AstNodeType... expected) {
Preconditions.checkArgument(astNode.is(expected), "Unexpected AstNodeType: %s", astNode.getType().toString());
}
private IdentifierTree identifier(AstNode astNode) {
checkType(astNode, JavaTokenType.IDENTIFIER, JavaKeyword.THIS, JavaKeyword.CLASS, JavaKeyword.SUPER);
return new JavaTree.IdentifierTreeImpl(astNode, astNode.getTokenValue());
}
private ExpressionTree qualifiedIdentifier(AstNode astNode) {
checkType(astNode, JavaGrammar.QUALIFIED_IDENTIFIER);
List identifierNodes = astNode.getChildren(JavaTokenType.IDENTIFIER);
ExpressionTree result = identifier(identifierNodes.get(0));
for (int i = 1; i < identifierNodes.size(); i++) {
result = new JavaTree.MemberSelectExpressionTreeImpl(
identifierNodes.get(i),
result,
identifier(identifierNodes.get(i))
);
}
return result;
}
private List qualifiedIdentifierList(AstNode astNode) {
checkType(astNode, JavaGrammar.QUALIFIED_IDENTIFIER_LIST);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode qualifiedIdentifierNode : astNode.getChildren(JavaGrammar.QUALIFIED_IDENTIFIER)) {
result.add(qualifiedIdentifier(qualifiedIdentifierNode));
}
return result.build();
}
@VisibleForTesting
LiteralTree literal(AstNode astNode) {
checkType(astNode, JavaGrammar.LITERAL);
AstNode childNode = astNode.getFirstChild();
return new JavaTree.LiteralTreeImpl(childNode, kindMaps.getLiteral(childNode.getType()));
}
/*
* 4. Types, Values and Variables
*/
@VisibleForTesting
PrimitiveTypeTree basicType(AstNode astNode) {
checkType(astNode, JavaGrammar.BASIC_TYPE, JavaKeyword.VOID);
return new JavaTree.PrimitiveTypeTreeImpl(astNode);
}
private ExpressionTree classType(AstNode astNode) {
checkType(astNode, JavaGrammar.CLASS_TYPE, JavaGrammar.CREATED_NAME);
AstNode child = astNode.getFirstChild();
ExpressionTree result = identifier(child);
for (int i = 1; i < astNode.getNumberOfChildren(); i++) {
child = astNode.getChild(i);
if (child.is(JavaTokenType.IDENTIFIER)) {
result = new JavaTree.MemberSelectExpressionTreeImpl(child, result, identifier(child));
} else if (child.is(JavaGrammar.TYPE_ARGUMENTS)) {
result = new JavaTree.ParameterizedTypeTreeImpl(child, result, typeArguments(child));
} else if (child.is(JavaGrammar.NON_WILDCARD_TYPE_ARGUMENTS)) {
result = new JavaTree.ParameterizedTypeTreeImpl(child, result, nonWildcardTypeArguments(child));
} else if (!child.is(JavaPunctuator.DOT)) {
throw new IllegalStateException("Unexpected AstNodeType: " + astNode.getType().toString());
}
}
return result;
}
@VisibleForTesting
List typeArguments(AstNode astNode) {
checkType(astNode, JavaGrammar.TYPE_ARGUMENTS);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode child : astNode.getChildren(JavaGrammar.TYPE_ARGUMENT)) {
AstNode referenceTypeNode = child.getFirstChild(JavaGrammar.REFERENCE_TYPE);
Tree typeArgument = referenceTypeNode != null ? referenceType(referenceTypeNode) : null;
if (child.getFirstChild().is(JavaPunctuator.QUERY)) {
final Tree.Kind kind;
if (child.hasDirectChildren(JavaKeyword.EXTENDS)) {
kind = Tree.Kind.EXTENDS_WILDCARD;
} else if (child.hasDirectChildren(JavaKeyword.SUPER)) {
kind = Tree.Kind.SUPER_WILDCARD;
} else {
kind = Tree.Kind.UNBOUNDED_WILDCARD;
}
typeArgument = new JavaTree.WildcardTreeImpl(child, kind, typeArgument);
}
result.add(typeArgument);
}
return result.build();
}
private List nonWildcardTypeArguments(AstNode astNode) {
checkType(astNode, JavaGrammar.NON_WILDCARD_TYPE_ARGUMENTS);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode child : astNode.getChildren(JavaGrammar.REFERENCE_TYPE)) {
result.add(referenceType(child));
}
return result.build();
}
@VisibleForTesting
ExpressionTree referenceType(AstNode astNode) {
checkType(astNode, JavaGrammar.REFERENCE_TYPE, JavaGrammar.TYPE);
ExpressionTree result = astNode.getFirstChild().is(JavaGrammar.BASIC_TYPE) ? basicType(astNode.getFirstChild()) : classType(astNode.getFirstChild());
return applyDim(result, astNode.getChildren(JavaGrammar.DIM).size());
}
private ModifiersTree modifiers(List modifierNodes) {
if (modifierNodes.isEmpty()) {
return JavaTree.ModifiersTreeImpl.EMPTY;
}
ImmutableList.Builder modifiers = ImmutableList.builder();
for (AstNode astNode : modifierNodes) {
Preconditions.checkArgument(astNode.is(JavaGrammar.MODIFIER), "Unexpected AstNodeType: %s", astNode.getType().toString());
astNode = astNode.getFirstChild();
if (astNode.is(JavaGrammar.ANNOTATION)) {
// TODO
} else {
JavaKeyword keyword = (JavaKeyword) astNode.getType();
modifiers.add(kindMaps.getModifier(keyword));
}
}
return new JavaTree.ModifiersTreeImpl(modifierNodes.get(0), modifiers.build());
}
private VariableTree variableDeclarator(ModifiersTree modifiers, ExpressionTree type, AstNode astNode) {
checkType(astNode, JavaGrammar.VARIABLE_DECLARATOR);
return new JavaTree.VariableTreeImpl(
astNode,
modifiers,
applyDim(type, astNode.getChildren(JavaGrammar.DIM).size()),
astNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue(),
astNode.hasDirectChildren(JavaGrammar.VARIABLE_INITIALIZER) ? variableInitializer(astNode.getFirstChild(JavaGrammar.VARIABLE_INITIALIZER)) : null
);
}
private List variableDeclarators(ModifiersTree modifiers, ExpressionTree type, AstNode astNode) {
checkType(astNode, JavaGrammar.VARIABLE_DECLARATORS);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode variableDeclaratorNode : astNode.getChildren(JavaGrammar.VARIABLE_DECLARATOR)) {
result.add(variableDeclarator(modifiers, type, variableDeclaratorNode));
}
return result.build();
}
/*
* 7.3. Compilation Units
*/
public CompilationUnitTree compilationUnit(AstNode astNode) {
checkType(astNode, JavaGrammar.COMPILATION_UNIT);
ImmutableList.Builder imports = ImmutableList.builder();
for (AstNode importNode : astNode.getChildren(JavaGrammar.IMPORT_DECLARATION)) {
// TODO star import?
imports.add(new JavaTree.ImportTreeImpl(
importNode,
importNode.hasDirectChildren(JavaKeyword.STATIC),
qualifiedIdentifier(importNode.getFirstChild(JavaGrammar.QUALIFIED_IDENTIFIER))
));
}
ImmutableList.Builder types = ImmutableList.builder();
for (AstNode typeNode : astNode.getChildren(JavaGrammar.TYPE_DECLARATION)) {
AstNode declarationNode = typeNode.getFirstChild(
JavaGrammar.CLASS_DECLARATION,
JavaGrammar.ENUM_DECLARATION,
JavaGrammar.INTERFACE_DECLARATION,
JavaGrammar.ANNOTATION_TYPE_DECLARATION
);
if (declarationNode != null) {
types.add(typeDeclaration(modifiers(typeNode.getChildren(JavaGrammar.MODIFIER)), declarationNode));
}
}
// TODO package annotations
ExpressionTree packageDeclaration = null;
if (astNode.hasDirectChildren(JavaGrammar.PACKAGE_DECLARATION)) {
packageDeclaration = qualifiedIdentifier(astNode.getFirstChild(JavaGrammar.PACKAGE_DECLARATION).getFirstChild(JavaGrammar.QUALIFIED_IDENTIFIER));
}
return new JavaTree.CompilationUnitTreeImpl(
astNode,
packageDeclaration,
imports.build(),
types.build()
);
}
private ClassTree typeDeclaration(ModifiersTree modifiers, AstNode astNode) {
if (astNode.is(JavaGrammar.CLASS_DECLARATION)) {
return classDeclaration(modifiers, astNode);
} else if (astNode.is(JavaGrammar.ENUM_DECLARATION)) {
return enumDeclaration(modifiers, astNode);
} else if (astNode.is(JavaGrammar.INTERFACE_DECLARATION)) {
return interfaceDeclaration(modifiers, astNode);
} else if (astNode.is(JavaGrammar.ANNOTATION_TYPE_DECLARATION)) {
return annotationTypeDeclaration(modifiers, astNode);
} else {
throw new IllegalArgumentException("Unexpected AstNodeType: " + astNode.getType().toString());
}
}
/*
* 8. Classes
*/
/**
* 8.1. Class Declarations
*/
private ClassTree classDeclaration(ModifiersTree modifiers, AstNode astNode) {
checkType(astNode, JavaGrammar.CLASS_DECLARATION);
String simpleName = astNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue();
AstNode extendsNode = astNode.getFirstChild(JavaKeyword.EXTENDS);
Tree superClass = extendsNode != null ? classType(extendsNode.getNextSibling()) : null;
AstNode implementsNode = astNode.getFirstChild(JavaKeyword.IMPLEMENTS);
List superInterfaces = implementsNode != null ? classTypeList(implementsNode.getNextSibling()) : ImmutableList.of();
return new JavaTree.ClassTreeImpl(astNode, Tree.Kind.CLASS,
modifiers,
simpleName,
superClass,
superInterfaces,
classBody(astNode.getFirstChild(JavaGrammar.CLASS_BODY))
);
}
private List classTypeList(AstNode astNode) {
checkType(astNode, JavaGrammar.CLASS_TYPE_LIST);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode classTypeNode : astNode.getChildren(JavaGrammar.CLASS_TYPE)) {
result.add(classType(classTypeNode));
}
return result.build();
}
/**
* 8.1.6. Class Body and Member Declarations
*/
private List classBody(AstNode astNode) {
checkType(astNode, JavaGrammar.CLASS_BODY, JavaGrammar.ENUM_BODY_DECLARATIONS);
ImmutableList.Builder members = ImmutableList.builder();
for (AstNode classBodyDeclaration : astNode.getChildren(JavaGrammar.CLASS_BODY_DECLARATION)) {
ModifiersTree modifiers = modifiers(classBodyDeclaration.getChildren(JavaGrammar.MODIFIER));
if (classBodyDeclaration.hasDirectChildren(JavaGrammar.MEMBER_DECL)) {
AstNode memberDeclNode = classBodyDeclaration.getFirstChild(JavaGrammar.MEMBER_DECL);
if (memberDeclNode.hasDirectChildren(JavaGrammar.FIELD_DECLARATION)) {
members.addAll(fieldDeclaration(
modifiers,
memberDeclNode.getFirstChild(JavaGrammar.FIELD_DECLARATION)
));
} else {
members.add(memberDeclaration(modifiers, memberDeclNode));
}
} else if (classBodyDeclaration.getFirstChild().is(JavaGrammar.CLASS_INIT_DECLARATION)) {
AstNode classInitDeclarationNode = classBodyDeclaration.getFirstChild();
members.add(new JavaTree.BlockTreeImpl(
classInitDeclarationNode,
classInitDeclarationNode.hasDirectChildren(JavaKeyword.STATIC) ? Tree.Kind.STATIC_INITIALIZER : Tree.Kind.INITIALIZER,
blockStatements(classInitDeclarationNode.getFirstChild(JavaGrammar.BLOCK).getFirstChild(JavaGrammar.BLOCK_STATEMENTS))
));
}
}
return members.build();
}
/**
* 8.2. Class Members
*/
private Tree memberDeclaration(ModifiersTree modifiers, AstNode astNode) {
checkType(astNode, JavaGrammar.MEMBER_DECL);
AstNode declaration = astNode.getFirstChild(
JavaGrammar.INTERFACE_DECLARATION,
JavaGrammar.CLASS_DECLARATION,
JavaGrammar.ENUM_DECLARATION,
JavaGrammar.ANNOTATION_TYPE_DECLARATION
);
if (declaration != null) {
return typeDeclaration(modifiers, declaration);
}
declaration = astNode.getFirstChild(JavaGrammar.GENERIC_METHOD_OR_CONSTRUCTOR_REST);
if (declaration != null) {
// TODO TYPE_PARAMETERS
return methodDeclarator(
modifiers,
/* type */ declaration.getFirstChild(JavaGrammar.TYPE, JavaKeyword.VOID),
/* name */ declaration.getFirstChild(JavaTokenType.IDENTIFIER),
declaration.getFirstChild(JavaGrammar.METHOD_DECLARATOR_REST, JavaGrammar.CONSTRUCTOR_DECLARATOR_REST)
);
}
declaration = astNode.getFirstChild(
JavaGrammar.METHOD_DECLARATOR_REST,
JavaGrammar.VOID_METHOD_DECLARATOR_REST,
JavaGrammar.CONSTRUCTOR_DECLARATOR_REST
);
if (declaration != null) {
return methodDeclarator(
modifiers,
/* type */ astNode.getFirstChild(JavaGrammar.TYPE, JavaKeyword.VOID),
/* name */ astNode.getFirstChild(JavaTokenType.IDENTIFIER),
declaration
);
}
throw new IllegalStateException();
}
/**
* 8.3. Field Declarations
*/
private List fieldDeclaration(ModifiersTree modifiers, AstNode astNode) {
checkType(astNode, JavaGrammar.FIELD_DECLARATION);
return variableDeclarators(modifiers, referenceType(astNode.getFirstChild(JavaGrammar.TYPE)), astNode.getFirstChild(JavaGrammar.VARIABLE_DECLARATORS));
}
/**
* 8.4. Method Declarations
*/
private MethodTree methodDeclarator(ModifiersTree modifiers, @Nullable AstNode returnTypeNode, AstNode name, AstNode astNode) {
checkType(name, JavaTokenType.IDENTIFIER);
checkType(astNode, JavaGrammar.METHOD_DECLARATOR_REST,
JavaGrammar.VOID_METHOD_DECLARATOR_REST,
JavaGrammar.CONSTRUCTOR_DECLARATOR_REST,
JavaGrammar.VOID_INTERFACE_METHOD_DECLARATORS_REST,
JavaGrammar.INTERFACE_METHOD_DECLARATOR_REST);
// TODO type parameters
Tree returnType = null;
if (returnTypeNode != null) {
if (returnTypeNode.is(JavaKeyword.VOID)) {
returnType = basicType(returnTypeNode);
} else {
returnType = referenceType(returnTypeNode);
}
}
BlockTree body = null;
if (astNode.hasDirectChildren(JavaGrammar.METHOD_BODY)) {
body = block(astNode.getFirstChild(JavaGrammar.METHOD_BODY).getFirstChild(JavaGrammar.BLOCK));
}
AstNode throwsClauseNode = astNode.getFirstChild(JavaGrammar.QUALIFIED_IDENTIFIER_LIST);
return new JavaTree.MethodTreeImpl(
astNode,
modifiers,
returnType,
name.getTokenValue(),
formalParameters(astNode.getFirstChild(JavaGrammar.FORMAL_PARAMETERS)),
body,
throwsClauseNode != null ? qualifiedIdentifierList(throwsClauseNode) : ImmutableList.of(),
null
);
}
private List formalParameters(AstNode astNode) {
checkType(astNode, JavaGrammar.FORMAL_PARAMETERS);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode variableDeclaratorIdNode : astNode.getDescendants(JavaGrammar.VARIABLE_DECLARATOR_ID)) {
AstNode typeNode = variableDeclaratorIdNode.getPreviousAstNode();
Tree type = typeNode.is(JavaPunctuator.ELLIPSIS) ? new JavaTree.ArrayTypeTreeImpl(typeNode, referenceType(typeNode.getPreviousAstNode())) : referenceType(typeNode);
result.add(new JavaTree.VariableTreeImpl(
variableDeclaratorIdNode,
JavaTree.ModifiersTreeImpl.EMPTY,
type,
variableDeclaratorIdNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue(),
null
));
}
return result.build();
}
/**
* 8.9. Enums
*/
private ClassTree enumDeclaration(ModifiersTree modifiers, AstNode astNode) {
checkType(astNode, JavaGrammar.ENUM_DECLARATION);
IdentifierTree enumType = identifier(astNode.getFirstChild(JavaTokenType.IDENTIFIER));
ImmutableList.Builder members = ImmutableList.builder();
AstNode enumBodyNode = astNode.getFirstChild(JavaGrammar.ENUM_BODY);
AstNode enumConstantsNode = enumBodyNode.getFirstChild(JavaGrammar.ENUM_CONSTANTS);
if (enumConstantsNode != null) {
for (AstNode enumConstantNode : enumConstantsNode.getChildren(JavaGrammar.ENUM_CONSTANT)) {
AstNode argumentsNode = enumConstantNode.getFirstChild(JavaGrammar.ARGUMENTS);
AstNode classBodyNode = enumConstantNode.getFirstChild(JavaGrammar.CLASS_BODY);
IdentifierTree enumIdentifier = identifier(enumConstantNode.getFirstChild(JavaTokenType.IDENTIFIER));
members.add(new JavaTree.EnumConstantTreeImpl(
enumConstantNode,
JavaTree.ModifiersTreeImpl.EMPTY,
enumType,
enumIdentifier.name(),
new JavaTree.NewClassTreeImpl(
enumConstantNode,
/* enclosing expression: */ null,
enumIdentifier,
argumentsNode != null ? arguments(argumentsNode) : ImmutableList.of(),
classBodyNode == null ? null : new JavaTree.ClassTreeImpl(
classBodyNode,
Tree.Kind.CLASS,
JavaTree.ModifiersTreeImpl.EMPTY,
classBody(classBodyNode)
)
)
));
}
}
AstNode enumBodyDeclarationsNode = enumBodyNode.getFirstChild(JavaGrammar.ENUM_BODY_DECLARATIONS);
if (enumBodyDeclarationsNode != null) {
members.addAll(classBody(enumBodyDeclarationsNode));
}
AstNode implementsNode = astNode.getFirstChild(JavaKeyword.IMPLEMENTS);
List superInterfaces = implementsNode != null ? classTypeList(implementsNode.getNextSibling()) : ImmutableList.of();
return new JavaTree.ClassTreeImpl(astNode, Tree.Kind.ENUM, modifiers, enumType.name(), /* super class: */ null, superInterfaces, members.build());
}
/*
* 9. Interfaces
*/
/**
* 9.1. Interface Declarations
*/
private ClassTree interfaceDeclaration(ModifiersTree modifiers, AstNode astNode) {
checkType(astNode, JavaGrammar.INTERFACE_DECLARATION);
String simpleName = astNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue();
ImmutableList.Builder members = ImmutableList.builder();
for (AstNode interfaceBodyDeclarationNode : astNode.getFirstChild(JavaGrammar.INTERFACE_BODY).getChildren(JavaGrammar.INTERFACE_BODY_DECLARATION)) {
ModifiersTree memberModifiers = modifiers(interfaceBodyDeclarationNode.getChildren(JavaGrammar.MODIFIER));
AstNode interfaceMemberDeclNode = interfaceBodyDeclarationNode.getFirstChild(JavaGrammar.INTERFACE_MEMBER_DECL);
if (interfaceMemberDeclNode != null) {
appendInterfaceMember(memberModifiers, members, interfaceMemberDeclNode);
}
}
AstNode extendsNode = astNode.getFirstChild(JavaKeyword.EXTENDS);
List superInterfaces = extendsNode != null ? classTypeList(extendsNode.getNextSibling()) : ImmutableList.of();
return new JavaTree.ClassTreeImpl(astNode, Tree.Kind.INTERFACE, modifiers, simpleName, null, superInterfaces, members.build());
}
/**
* 9.1.4. Interface Body and Member Declarations
*/
private void appendInterfaceMember(ModifiersTree modifiers, ImmutableList.Builder members, AstNode astNode) {
checkType(astNode, JavaGrammar.INTERFACE_MEMBER_DECL);
AstNode declarationNode = astNode.getFirstChild(
JavaGrammar.INTERFACE_DECLARATION,
JavaGrammar.CLASS_DECLARATION,
JavaGrammar.ENUM_DECLARATION,
JavaGrammar.ANNOTATION_TYPE_DECLARATION
);
if (declarationNode != null) {
members.add(typeDeclaration(modifiers, declarationNode));
return;
}
declarationNode = astNode.getFirstChild(JavaGrammar.INTERFACE_METHOD_OR_FIELD_DECL);
if (declarationNode != null) {
AstNode interfaceMethodOrFieldRestNode = declarationNode.getFirstChild(JavaGrammar.INTERFACE_METHOD_OR_FIELD_REST);
AstNode interfaceMethodDeclaratorRestNode = interfaceMethodOrFieldRestNode.getFirstChild(JavaGrammar.INTERFACE_METHOD_DECLARATOR_REST);
if (interfaceMethodDeclaratorRestNode != null) {
members.add(methodDeclarator(
modifiers,
declarationNode.getFirstChild(JavaGrammar.TYPE, JavaKeyword.VOID),
declarationNode.getFirstChild(JavaTokenType.IDENTIFIER),
interfaceMethodDeclaratorRestNode
));
return;
} else {
appendConstantDeclarations(modifiers, members, declarationNode);
return;
}
}
declarationNode = astNode.getFirstChild(JavaGrammar.INTERFACE_GENERIC_METHOD_DECL);
if (declarationNode != null) {
// TODO TYPE_PARAMETERS
members.add(methodDeclarator(
modifiers,
/* type */ declarationNode.getFirstChild(JavaGrammar.TYPE, JavaKeyword.VOID),
/* name */ declarationNode.getFirstChild(JavaTokenType.IDENTIFIER),
declarationNode.getFirstChild(JavaGrammar.INTERFACE_METHOD_DECLARATOR_REST)
));
return;
}
declarationNode = astNode.getFirstChild(JavaGrammar.VOID_INTERFACE_METHOD_DECLARATORS_REST);
if (declarationNode != null) {
members.add(methodDeclarator(
modifiers,
/* type */ astNode.getFirstChild(JavaKeyword.VOID),
/* name */ astNode.getFirstChild(JavaTokenType.IDENTIFIER),
declarationNode
));
return;
}
throw new IllegalStateException();
}
private void appendConstantDeclarations(ModifiersTree modifiers, ImmutableList.Builder members, AstNode astNode) {
checkType(astNode, JavaGrammar.INTERFACE_METHOD_OR_FIELD_DECL, JavaGrammar.ANNOTATION_TYPE_ELEMENT_REST);
ExpressionTree type = referenceType(astNode.getFirstChild(JavaGrammar.TYPE, JavaKeyword.VOID));
for (AstNode constantDeclaratorRestNode : astNode.getDescendants(JavaGrammar.CONSTANT_DECLARATOR_REST)) {
AstNode identifierNode = constantDeclaratorRestNode.getPreviousAstNode();
Preconditions.checkState(identifierNode.is(JavaTokenType.IDENTIFIER));
members.add(new JavaTree.VariableTreeImpl(
constantDeclaratorRestNode,
modifiers,
applyDim(type, constantDeclaratorRestNode.getChildren(JavaGrammar.DIM).size()),
identifierNode.getTokenValue(),
variableInitializer(constantDeclaratorRestNode.getFirstChild(JavaGrammar.VARIABLE_INITIALIZER))
));
}
}
/**
* 9.6. Annotation Types
*/
private ClassTree annotationTypeDeclaration(ModifiersTree modifiers, AstNode astNode) {
checkType(astNode, JavaGrammar.ANNOTATION_TYPE_DECLARATION);
String simpleName = astNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue();
ImmutableList.Builder members = ImmutableList.builder();
for (AstNode annotationTypeElementDeclarationNode : astNode.getFirstChild(JavaGrammar.ANNOTATION_TYPE_BODY).getChildren(JavaGrammar.ANNOTATION_TYPE_ELEMENT_DECLARATION)) {
AstNode annotationTypeElementRestNode = annotationTypeElementDeclarationNode.getFirstChild(JavaGrammar.ANNOTATION_TYPE_ELEMENT_REST);
if (annotationTypeElementRestNode != null) {
appendAnnotationTypeElementDeclaration(members, annotationTypeElementRestNode);
}
}
return new JavaTree.ClassTreeImpl(astNode, Tree.Kind.ANNOTATION_TYPE,
modifiers,
simpleName,
/* super class: */ null,
ImmutableList.of(),
members.build()
);
}
/**
* 9.6.1. Annotation Type Elements
*/
private void appendAnnotationTypeElementDeclaration(ImmutableList.Builder members, AstNode astNode) {
checkType(astNode, JavaGrammar.ANNOTATION_TYPE_ELEMENT_REST);
AstNode declarationNode = astNode.getFirstChild(
JavaGrammar.INTERFACE_DECLARATION,
JavaGrammar.CLASS_DECLARATION,
JavaGrammar.ENUM_DECLARATION,
JavaGrammar.ANNOTATION_TYPE_DECLARATION
);
if (declarationNode != null) {
members.add(typeDeclaration(JavaTree.ModifiersTreeImpl.EMPTY, declarationNode));
return;
}
AstNode typeNode = astNode.getFirstChild(JavaGrammar.TYPE);
AstNode identifierNode = astNode.getFirstChild(JavaTokenType.IDENTIFIER);
AstNode annotationMethodRestNode = astNode.getFirstChild(JavaGrammar.ANNOTATION_METHOD_OR_CONSTANT_REST).getFirstChild(JavaGrammar.ANNOTATION_METHOD_REST);
if (annotationMethodRestNode != null) {
members.add(new JavaTree.MethodTreeImpl(
annotationMethodRestNode,
/* modifiers */ JavaTree.ModifiersTreeImpl.EMPTY,
/* return type */ referenceType(typeNode),
/* name */ identifierNode.getTokenValue(),
/* parameters */ ImmutableList.of(),
/* block */ null,
/* throws */ ImmutableList.of(),
// TODO DEFAULT_VALUE
/* default value */ null
));
} else {
appendConstantDeclarations(JavaTree.ModifiersTreeImpl.EMPTY, members, astNode);
}
}
/*
* 14. Blocks and Statements
*/
@VisibleForTesting
BlockTree block(AstNode astNode) {
checkType(astNode, JavaGrammar.BLOCK);
return new JavaTree.BlockTreeImpl(astNode, Tree.Kind.BLOCK, blockStatements(astNode.getFirstChild(JavaGrammar.BLOCK_STATEMENTS)));
}
private List blockStatements(AstNode astNode) {
checkType(astNode, JavaGrammar.BLOCK_STATEMENTS);
ImmutableList.Builder statements = ImmutableList.builder();
for (AstNode statementNode : astNode.getChildren(JavaGrammar.BLOCK_STATEMENT)) {
statementNode = statementNode.getFirstChild(
JavaGrammar.STATEMENT,
JavaGrammar.LOCAL_VARIABLE_DECLARATION_STATEMENT,
JavaGrammar.CLASS_DECLARATION,
JavaGrammar.ENUM_DECLARATION
);
if (statementNode.is(JavaGrammar.STATEMENT)) {
statements.add(statement(statementNode));
} else if (statementNode.is(JavaGrammar.LOCAL_VARIABLE_DECLARATION_STATEMENT)) {
// TODO modifiers
statements.addAll(variableDeclarators(
JavaTree.ModifiersTreeImpl.EMPTY,
referenceType(statementNode.getFirstChild(JavaGrammar.TYPE)),
statementNode.getFirstChild(JavaGrammar.VARIABLE_DECLARATORS)
));
} else if (statementNode.is(JavaGrammar.CLASS_DECLARATION)) {
statements.add(classDeclaration(JavaTree.ModifiersTreeImpl.EMPTY, statementNode));
} else if (statementNode.is(JavaGrammar.ENUM_DECLARATION)) {
statements.add(enumDeclaration(JavaTree.ModifiersTreeImpl.EMPTY, statementNode));
} else {
throw new IllegalStateException("Unexpected AstNodeType: " + statementNode.getType().toString());
}
}
return statements.build();
}
@VisibleForTesting
StatementTree statement(AstNode astNode) {
checkType(astNode, JavaGrammar.STATEMENT);
final AstNode statementNode = astNode.getFirstChild();
final StatementTree result;
switch ((JavaGrammar) statementNode.getType()) {
case BLOCK:
result = block(statementNode);
break;
case EMPTY_STATEMENT:
// 14.6. The Empty Statement
result = new JavaTree.EmptyStatementTreeImpl(statementNode);
break;
case LABELED_STATEMENT:
// 14.7. Labeled Statement
result = new JavaTree.LabeledStatementTreeImpl(
statementNode,
statementNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue(),
statement(statementNode.getFirstChild(JavaGrammar.STATEMENT))
);
break;
case EXPRESSION_STATEMENT:
// 14.8. Expression Statement
result = new JavaTree.ExpressionStatementTreeImpl(
statementNode,
expression(statementNode.getFirstChild(JavaGrammar.STATEMENT_EXPRESSION))
);
break;
case IF_STATEMENT:
// 14.9. The if Statement
List statements = statementNode.getChildren(JavaGrammar.STATEMENT);
result = new JavaTree.IfStatementTreeImpl(
statementNode,
expression(statementNode.getFirstChild(JavaGrammar.PAR_EXPRESSION)),
statement(statements.get(0)),
statements.size() > 1 ? statement(statements.get(1)) : null
);
break;
case ASSERT_STATEMENT:
// 14.10. The assert Statement
List expressions = statementNode.getChildren(JavaGrammar.EXPRESSION);
result = new JavaTree.AssertStatementTreeImpl(
statementNode,
expression(expressions.get(0)),
expressions.size() > 1 ? expression(expressions.get(1)) : null
);
break;
case SWITCH_STATEMENT:
result = switchStatement(statementNode);
break;
case WHILE_STATEMENT:
// 14.12. The while Statement
result = new JavaTree.WhileStatementTreeImpl(
statementNode,
expression(statementNode.getFirstChild(JavaGrammar.PAR_EXPRESSION)),
statement(statementNode.getFirstChild(JavaGrammar.STATEMENT))
);
break;
case DO_STATEMENT:
// 14.13. The do Statement
result = new JavaTree.DoWhileStatementTreeImpl(
statementNode,
statement(statementNode.getFirstChild(JavaGrammar.STATEMENT)),
expression(statementNode.getFirstChild(JavaGrammar.PAR_EXPRESSION))
);
break;
case FOR_STATEMENT:
result = forStatement(statementNode);
break;
case BREAK_STATEMENT:
// 14.15. The break Statement
result = new JavaTree.BreakStatementTreeImpl(
statementNode,
statementNode.hasDirectChildren(JavaTokenType.IDENTIFIER) ? statementNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue() : null
);
break;
case CONTINUE_STATEMENT:
// 14.16. The continue Statement
result = new JavaTree.ContinueStatementTreeImpl(
statementNode,
statementNode.hasDirectChildren(JavaTokenType.IDENTIFIER) ? statementNode.getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue() : null
);
break;
case RETURN_STATEMENT:
// 14.17. The return Statement
result = new JavaTree.ReturnStatementTreeImpl(
statementNode,
statementNode.hasDirectChildren(JavaGrammar.EXPRESSION) ? expression(statementNode.getFirstChild(JavaGrammar.EXPRESSION)) : null
);
break;
case THROW_STATEMENT:
// 14.18. The throw Statement
result = new JavaTree.ThrowStatementTreeImpl(
statementNode,
expression(statementNode.getFirstChild(JavaGrammar.EXPRESSION))
);
break;
case SYNCHRONIZED_STATEMENT:
// 14.19. The synchronized Statement
result = new JavaTree.SynchronizedStatementTreeImpl(
statementNode,
expression(statementNode.getFirstChild(JavaGrammar.PAR_EXPRESSION)),
block(statementNode.getFirstChild(JavaGrammar.BLOCK))
);
break;
case TRY_STATEMENT:
result = tryStatement(statementNode);
break;
default:
throw new IllegalStateException("Unexpected AstNodeType: " + astNode.getType().toString());
}
return result;
}
/**
* 14.11. The switch Statement
*/
private SwitchStatementTree switchStatement(AstNode astNode) {
ImmutableList.Builder cases = ImmutableList.builder();
List labels = Lists.newArrayList();
for (AstNode caseNode : astNode.getFirstChild(JavaGrammar.SWITCH_BLOCK_STATEMENT_GROUPS).getChildren(JavaGrammar.SWITCH_BLOCK_STATEMENT_GROUP)) {
AstNode expressionNode = caseNode.getFirstChild(JavaGrammar.SWITCH_LABEL).getFirstChild(JavaGrammar.CONSTANT_EXPRESSION);
AstNode blockStatementsNode = caseNode.getFirstChild(JavaGrammar.BLOCK_STATEMENTS);
labels.add(new JavaTree.CaseLabelTreeImpl(caseNode, expressionNode != null ? expression(expressionNode) : null));
if (blockStatementsNode.hasChildren()) {
cases.add(new JavaTree.CaseGroupTreeImpl(
labels.get(0).getAstNode(),
ImmutableList.copyOf(labels),
blockStatements(caseNode.getFirstChild(JavaGrammar.BLOCK_STATEMENTS))
));
labels.clear();
}
}
if (!labels.isEmpty()) {
cases.add(new JavaTree.CaseGroupTreeImpl(
labels.get(0).getAstNode(),
ImmutableList.copyOf(labels),
ImmutableList.of()
));
}
return new JavaTree.SwitchStatementTreeImpl(
astNode,
expression(astNode.getFirstChild(JavaGrammar.PAR_EXPRESSION)),
cases.build()
);
}
/**
* 14.14. The for Statement
*/
private StatementTree forStatement(AstNode astNode) {
AstNode formalParameterNode = astNode.getFirstChild(JavaGrammar.FORMAL_PARAMETER);
if (formalParameterNode == null) {
AstNode forInitNode = astNode.getFirstChild(JavaGrammar.FOR_INIT);
final List forInit;
if (forInitNode == null) {
forInit = ImmutableList.of();
} else if (forInitNode.hasDirectChildren(JavaGrammar.VARIABLE_DECLARATORS)) {
// TODO modifiers
forInit = variableDeclarators(
JavaTree.ModifiersTreeImpl.EMPTY,
referenceType(forInitNode.getFirstChild(JavaGrammar.TYPE)),
forInitNode.getFirstChild(JavaGrammar.VARIABLE_DECLARATORS)
);
} else {
forInit = statementExpressions(astNode.getFirstChild(JavaGrammar.FOR_INIT));
}
return new JavaTree.ForStatementTreeImpl(
astNode,
forInit,
astNode.hasDirectChildren(JavaGrammar.EXPRESSION) ? expression(astNode.getFirstChild(JavaGrammar.EXPRESSION)) : null,
astNode.hasDirectChildren(JavaGrammar.FOR_UPDATE) ? statementExpressions(astNode.getFirstChild(JavaGrammar.FOR_UPDATE)) : ImmutableList.of(),
statement(astNode.getFirstChild(JavaGrammar.STATEMENT))
);
} else {
return new JavaTree.ForEachStatementImpl(
astNode,
new JavaTree.VariableTreeImpl(
formalParameterNode,
JavaTree.ModifiersTreeImpl.EMPTY,
// TODO dim
referenceType(formalParameterNode.getFirstChild(JavaGrammar.TYPE)),
formalParameterNode.getFirstChild(JavaGrammar.VARIABLE_DECLARATOR_ID).getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue(),
/* initializer: */ null
),
expression(astNode.getFirstChild(JavaGrammar.EXPRESSION)),
statement(astNode.getFirstChild(JavaGrammar.STATEMENT))
);
}
}
private List statementExpressions(AstNode astNode) {
checkType(astNode, JavaGrammar.FOR_INIT, JavaGrammar.FOR_UPDATE);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode statementExpressionNode : astNode.getChildren(JavaGrammar.STATEMENT_EXPRESSION)) {
result.add(new JavaTree.ExpressionStatementTreeImpl(statementExpressionNode, expression(statementExpressionNode)));
}
return result.build();
}
/**
* 14.20. The try statement
*/
private TryStatementTree tryStatement(AstNode astNode) {
if (astNode.hasDirectChildren(JavaGrammar.TRY_WITH_RESOURCES_STATEMENT)) {
astNode = astNode.getFirstChild(JavaGrammar.TRY_WITH_RESOURCES_STATEMENT);
}
ImmutableList.Builder catches = ImmutableList.builder();
for (AstNode catchNode : astNode.getChildren(JavaGrammar.CATCH_CLAUSE)) {
AstNode catchFormalParameterNode = catchNode.getFirstChild(JavaGrammar.CATCH_FORMAL_PARAMETER);
catches.add(new JavaTree.CatchTreeImpl(
catchNode,
new JavaTree.VariableTreeImpl(
catchFormalParameterNode,
// TODO modifiers:
JavaTree.ModifiersTreeImpl.EMPTY,
catchType(catchFormalParameterNode.getFirstChild(JavaGrammar.CATCH_TYPE)),
// TODO WTF why VARIABLE_DECLARATOR_ID in grammar?
catchFormalParameterNode.getFirstChild(JavaGrammar.VARIABLE_DECLARATOR_ID).getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue(),
/* initializer: */ null
),
block(catchNode.getFirstChild(JavaGrammar.BLOCK))
));
}
BlockTree finallyBlock = null;
if (astNode.hasDirectChildren(JavaGrammar.FINALLY_)) {
finallyBlock = block(astNode.getFirstChild(JavaGrammar.FINALLY_).getFirstChild(JavaGrammar.BLOCK));
}
AstNode resourceSpecificationNode = astNode.getFirstChild(JavaGrammar.RESOURCE_SPECIFICATION);
return new JavaTree.TryStatementTreeImpl(
astNode,
resourceSpecificationNode == null ? ImmutableList.of() : resourceSpecification(resourceSpecificationNode),
block(astNode.getFirstChild(JavaGrammar.BLOCK)),
catches.build(),
finallyBlock
);
}
private Tree catchType(AstNode astNode) {
checkType(astNode, JavaGrammar.CATCH_TYPE);
List children = astNode.getChildren(JavaGrammar.QUALIFIED_IDENTIFIER);
if (children.size() == 1) {
return qualifiedIdentifier(children.get(0));
} else {
ImmutableList.Builder typeAlternatives = ImmutableList.builder();
for (AstNode child : children) {
typeAlternatives.add(qualifiedIdentifier(child));
}
return new JavaTree.UnionTypeTreeImpl(astNode, typeAlternatives.build());
}
}
private List resourceSpecification(AstNode astNode) {
checkType(astNode, JavaGrammar.RESOURCE_SPECIFICATION);
ImmutableList.Builder result = ImmutableList.builder();
for (AstNode resourceNode : astNode.getChildren(JavaGrammar.RESOURCE)) {
result.add(new JavaTree.VariableTreeImpl(
resourceNode,
// TODO modifiers:
JavaTree.ModifiersTreeImpl.EMPTY,
classType(resourceNode.getFirstChild(JavaGrammar.CLASS_TYPE)),
resourceNode.getFirstChild(JavaGrammar.VARIABLE_DECLARATOR_ID).getFirstChild(JavaTokenType.IDENTIFIER).getTokenValue(),
expression(resourceNode.getFirstChild(JavaGrammar.EXPRESSION))
));
}
return result.build();
}
@VisibleForTesting
ExpressionTree expression(AstNode astNode) {
if (astNode.is(JavaGrammar.CONSTANT_EXPRESSION, JavaGrammar.STATEMENT_EXPRESSION)) {
astNode = astNode.getFirstChild(JavaGrammar.EXPRESSION).getFirstChild();
} else if (astNode.is(JavaGrammar.EXPRESSION)) {
astNode = astNode.getFirstChild();
}
if (astNode.is(JavaGrammar.PAR_EXPRESSION)) {
return new JavaTree.ParenthesizedTreeImpl(astNode, expression(astNode.getFirstChild(JavaGrammar.EXPRESSION)));
} else if (astNode.is(JavaGrammar.PRIMARY)) {
return primary(astNode);
} else if (astNode.is(JavaGrammar.CONDITIONAL_OR_EXPRESSION,
JavaGrammar.CONDITIONAL_AND_EXPRESSION,
JavaGrammar.INCLUSIVE_OR_EXPRESSION,
JavaGrammar.EXCLUSIVE_OR_EXPRESSION,
JavaGrammar.AND_EXPRESSION,
JavaGrammar.EQUALITY_EXPRESSION,
JavaGrammar.RELATIONAL_EXPRESSION,
JavaGrammar.SHIFT_EXPRESSION,
JavaGrammar.ADDITIVE_EXPRESSION,
JavaGrammar.MULTIPLICATIVE_EXPRESSION)) {
return binaryExpression(astNode);
} else if (astNode.is(JavaGrammar.CONDITIONAL_EXPRESSION)) {
return conditionalExpression(astNode);
} else if (astNode.is(JavaGrammar.ASSIGNMENT_EXPRESSION)) {
return assignmentExpression(astNode);
} else if (astNode.is(JavaGrammar.UNARY_EXPRESSION)) {
return unaryExpression(astNode);
} else {
throw new IllegalArgumentException("Unexpected AstNodeType: " + astNode.getType().toString());
}
}
/**
* 15.11. Field Access Expressions
* 15.12. Method Invocation Expressions
* 15.13. Array Access Expressions
*/
@VisibleForTesting
ExpressionTree primary(AstNode astNode) {
AstNode firstChildNode = astNode.getFirstChild();
if (firstChildNode.is(JavaGrammar.PAR_EXPRESSION)) {
// (expression)
return expression(firstChildNode);
} else if (firstChildNode.is(JavaGrammar.NON_WILDCARD_TYPE_ARGUMENTS)) {
if (astNode.hasDirectChildren(JavaKeyword.THIS)) {
// this(arguments)
return new JavaTree.MethodInvocationTreeImpl(
astNode,
identifier(astNode.getFirstChild(JavaKeyword.THIS)),
arguments(astNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
} else {
AstNode explicitGenericInvocationSuffixNode = astNode.getFirstChild(JavaGrammar.EXPLICIT_GENERIC_INVOCATION_SUFFIX);
if (explicitGenericInvocationSuffixNode.hasDirectChildren(JavaKeyword.SUPER)) {
// super...
return applySuperSuffix(
identifier(explicitGenericInvocationSuffixNode.getFirstChild(JavaKeyword.SUPER)),
explicitGenericInvocationSuffixNode.getFirstChild(JavaGrammar.SUPER_SUFFIX)
);
} else {
// id(arguments)
return new JavaTree.MethodInvocationTreeImpl(
astNode,
identifier(explicitGenericInvocationSuffixNode.getFirstChild(JavaTokenType.IDENTIFIER)),
arguments(explicitGenericInvocationSuffixNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
}
}
} else if (firstChildNode.is(JavaKeyword.THIS)) {
IdentifierTree identifier = identifier(firstChildNode);
if (astNode.hasDirectChildren(JavaGrammar.ARGUMENTS)) {
// this(arguments)
return new JavaTree.MethodInvocationTreeImpl(
astNode,
identifier,
arguments(astNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
} else {
// this
return identifier;
}
} else if (firstChildNode.is(JavaKeyword.SUPER)) {
// super...
return applySuperSuffix(
identifier(firstChildNode),
astNode.getFirstChild(JavaGrammar.SUPER_SUFFIX)
);
} else if (firstChildNode.is(JavaGrammar.LITERAL)) {
// "literal"
return literal(firstChildNode);
} else if (firstChildNode.is(JavaKeyword.NEW)) {
// new...
return creator(astNode.getFirstChild(JavaGrammar.CREATOR));
} else if (firstChildNode.is(JavaGrammar.QUALIFIED_IDENTIFIER)) {
ExpressionTree identifier = qualifiedIdentifier(firstChildNode);
AstNode identifierSuffixNode = astNode.getFirstChild(JavaGrammar.IDENTIFIER_SUFFIX);
if (identifierSuffixNode == null) {
// id
return identifier;
} else {
if (identifierSuffixNode.getFirstChild().is(JavaPunctuator.LBRK)) {
if (identifierSuffixNode.hasDirectChildren(JavaKeyword.CLASS)) {
// 15.8.2. Class Literals
// id[].class
return new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
applyDim(identifier, identifierSuffixNode.getChildren(JavaGrammar.DIM).size() + 1),
identifier(identifierSuffixNode.getFirstChild(JavaKeyword.CLASS))
);
} else {
// id[expression]
return new JavaTree.ArrayAccessExpressionTreeImpl(
astNode,
identifier,
expression(identifierSuffixNode.getFirstChild(JavaGrammar.EXPRESSION))
);
}
} else if (identifierSuffixNode.getFirstChild().is(JavaGrammar.ARGUMENTS)) {
// id(arguments)
return new JavaTree.MethodInvocationTreeImpl(
astNode,
identifier,
arguments(identifierSuffixNode.getFirstChild())
);
} else if (identifierSuffixNode.getFirstChild().is(JavaPunctuator.DOT)) {
if (identifierSuffixNode.hasDirectChildren(JavaKeyword.CLASS)) {
// 15.8.2. Class Literals
// id.class
return new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
identifier,
identifier(identifierSuffixNode.getFirstChild(JavaKeyword.CLASS))
);
} else if (identifierSuffixNode.hasDirectChildren(JavaGrammar.EXPLICIT_GENERIC_INVOCATION)) {
// id.<...>...
return applyExplicitGenericInvocation(identifier, identifierSuffixNode.getFirstChild(JavaGrammar.EXPLICIT_GENERIC_INVOCATION));
} else if (identifierSuffixNode.hasDirectChildren(JavaKeyword.THIS)) {
// id.this
return new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
identifier,
identifier(identifierSuffixNode.getFirstChild(JavaKeyword.THIS))
);
} else if (identifierSuffixNode.hasDirectChildren(JavaKeyword.SUPER)) {
// id.super(arguments)
return new JavaTree.MethodInvocationTreeImpl(
astNode,
new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
identifier,
identifier(identifierSuffixNode.getFirstChild(JavaKeyword.SUPER))
),
arguments(identifierSuffixNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
} else if (identifierSuffixNode.hasDirectChildren(JavaKeyword.NEW)) {
// id.new...
AstNode innerCreatorNode = identifierSuffixNode.getFirstChild(JavaGrammar.INNER_CREATOR);
return applyClassCreatorRest(
identifier,
identifier(innerCreatorNode.getFirstChild(JavaTokenType.IDENTIFIER)),
innerCreatorNode.getFirstChild(JavaGrammar.CLASS_CREATOR_REST)
);
} else {
throw new IllegalArgumentException("Unexpected AstNodeType: " + identifierSuffixNode.getChild(1));
}
} else {
throw new IllegalArgumentException("Unexpected AstNodeType: " + identifierSuffixNode.getFirstChild());
}
}
} else if (firstChildNode.is(JavaGrammar.BASIC_TYPE, JavaKeyword.VOID)) {
// 15.8.2. Class Literals
// int.class
// int[].class
// void.class
return new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
applyDim(basicType(firstChildNode), astNode.getChildren(JavaGrammar.DIM).size()),
identifier(astNode.getFirstChild(JavaKeyword.CLASS))
);
} else {
throw new IllegalArgumentException("Unexpected AstNodeType: " + firstChildNode.getType());
}
}
private ExpressionTree creator(AstNode astNode) {
// TODO NON_WILDCARD_TYPE_ARGUMENTS
if (astNode.hasDirectChildren(JavaGrammar.CLASS_CREATOR_REST)) {
return applyClassCreatorRest(
/* enclosing expression: */ null,
classType(astNode.getFirstChild(JavaGrammar.CREATED_NAME)),
astNode.getFirstChild(JavaGrammar.CLASS_CREATOR_REST)
);
} else if (astNode.hasDirectChildren(JavaGrammar.ARRAY_CREATOR_REST)) {
AstNode arrayCreatorRestNode = astNode.getFirstChild(JavaGrammar.ARRAY_CREATOR_REST);
AstNode typeNode = arrayCreatorRestNode.getPreviousSibling();
Tree type = typeNode.is(JavaGrammar.BASIC_TYPE) ? basicType(typeNode) : classType(typeNode);
if (arrayCreatorRestNode.hasDirectChildren(JavaGrammar.ARRAY_INITIALIZER)) {
return arrayInitializer(type, arrayCreatorRestNode.getFirstChild(JavaGrammar.ARRAY_INITIALIZER));
} else {
ImmutableList.Builder dimensions = ImmutableList.builder();
dimensions.add(expression(arrayCreatorRestNode.getFirstChild(JavaGrammar.EXPRESSION)));
for (AstNode dimExpr : arrayCreatorRestNode.getChildren(JavaGrammar.DIM_EXPR)) {
dimensions.add(expression(dimExpr.getFirstChild(JavaGrammar.EXPRESSION)));
}
return new JavaTree.NewArrayTreeImpl(astNode, type, dimensions.build(), ImmutableList.of());
}
} else {
throw new IllegalArgumentException("Unexpected AstNodeType: " + astNode);
}
}
private ExpressionTree arrayInitializer(@Nullable Tree t, AstNode astNode) {
ImmutableList.Builder elems = ImmutableList.builder();
for (AstNode elem : astNode.getChildren(JavaGrammar.VARIABLE_INITIALIZER)) {
elems.add(variableInitializer(elem));
}
return new JavaTree.NewArrayTreeImpl(astNode, t, ImmutableList.of(), elems.build());
}
private ExpressionTree variableInitializer(AstNode astNode) {
if (astNode.getFirstChild().is(JavaGrammar.EXPRESSION)) {
return expression(astNode.getFirstChild());
} else {
return arrayInitializer(null, astNode.getFirstChild());
}
}
/**
* 15.14. Postfix Expressions
* 15.15. Unary Operators
* 15.16. Cast Expressions
*/
private ExpressionTree unaryExpression(AstNode astNode) {
if (astNode.hasDirectChildren(JavaGrammar.TYPE)) {
// 15.16. Cast Expressions
return new JavaTree.TypeCastExpressionTreeImpl(
astNode,
referenceType(astNode.getFirstChild(JavaGrammar.TYPE)),
expression(astNode.getChild(3))
);
} else if (astNode.hasDirectChildren(JavaGrammar.PREFIX_OP)) {
// 15.15. Unary Operators
JavaPunctuator punctuator = (JavaPunctuator) astNode.getFirstChild(JavaGrammar.PREFIX_OP).getFirstChild().getType();
Tree.Kind kind = kindMaps.getPrefixOperator(punctuator);
return new JavaTree.UnaryExpressionTreeImpl(
astNode,
kind,
expression(astNode.getChild(1))
);
} else {
// 15.14. Postfix Expressions
ExpressionTree result = expression(astNode.getFirstChild());
for (AstNode selectorNode : astNode.getChildren(JavaGrammar.SELECTOR)) {
result = applySelector(result, selectorNode);
}
for (AstNode postfixOpNode : astNode.getChildren(JavaGrammar.POST_FIX_OP)) {
JavaPunctuator punctuator = (JavaPunctuator) postfixOpNode.getFirstChild().getType();
Tree.Kind kind = kindMaps.getPostfixOperator(punctuator);
result = new JavaTree.UnaryExpressionTreeImpl(astNode, kind, result);
}
return result;
}
}
/**
* 15.17. Multiplicative Operators
* 15.18. Additive Operators
* 15.19. Shift Operators
* 15.20. Relational Operators
* 15.21. Equality Operators
* 15.22. Bitwise and Logical Operators
* 15.23. Conditional-And Operator &&
* 15.24. Conditional-Or Operator ||
*/
private ExpressionTree binaryExpression(AstNode astNode) {
if (astNode.hasDirectChildren(JavaKeyword.INSTANCEOF)) {
// 15.20.2. Type Comparison Operator instanceof
// TODO fix grammar - instanceof can't be chained
return new JavaTree.InstanceOfTreeImpl(
astNode,
expression(astNode.getFirstChild()),
referenceType(astNode.getFirstChild(JavaGrammar.REFERENCE_TYPE))
);
}
ExpressionTree expression = expression(astNode.getLastChild());
for (int i = astNode.getNumberOfChildren() - 3; i >= 0; i -= 2) {
JavaPunctuator punctuator = (JavaPunctuator) astNode.getChild(i + 1).getType();
Tree.Kind kind = kindMaps.getBinaryOperator(punctuator);
expression = new JavaTree.BinaryExpressionTreeImpl(
astNode,
expression(astNode.getChild(i)),
kind,
expression
);
}
return expression;
}
/**
* 15.25. Conditional Operator ? :
*/
private ExpressionTree conditionalExpression(AstNode astNode) {
ExpressionTree expression = expression(astNode.getLastChild());
for (int i = astNode.getNumberOfChildren() - 5; i >= 0; i -= 4) {
expression = new JavaTree.ConditionalExpressionTreeImpl(
astNode,
expression(astNode.getChild(i)),
expression(astNode.getChild(i + 2)),
expression
);
}
return expression;
}
/**
* 15.26. Assignment Operators
*/
private ExpressionTree assignmentExpression(AstNode astNode) {
ExpressionTree expression = expression(astNode.getLastChild());
for (int i = astNode.getNumberOfChildren() - 3; i >= 0; i -= 2) {
JavaPunctuator punctuator = (JavaPunctuator) astNode.getChild(i + 1).getFirstChild().getType();
Tree.Kind kind = kindMaps.getAssignmentOperator(punctuator);
expression = new JavaTree.AssignmentExpressionTreeImpl(
astNode,
expression(astNode.getChild(i)),
kind,
expression
);
}
return expression;
}
private ExpressionTree applySelector(ExpressionTree expression, AstNode selectorNode) {
checkType(selectorNode, JavaGrammar.SELECTOR);
if (selectorNode.hasDirectChildren(JavaGrammar.ARGUMENTS)) {
return new JavaTree.MethodInvocationTreeImpl(
selectorNode,
new JavaTree.MemberSelectExpressionTreeImpl(
selectorNode,
expression,
identifier(selectorNode.getFirstChild(JavaTokenType.IDENTIFIER))
),
arguments(selectorNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
} else if (selectorNode.hasDirectChildren(JavaTokenType.IDENTIFIER)) {
return new JavaTree.MemberSelectExpressionTreeImpl(
selectorNode,
expression,
identifier(selectorNode.getFirstChild(JavaTokenType.IDENTIFIER))
);
} else if (selectorNode.hasDirectChildren(JavaGrammar.EXPLICIT_GENERIC_INVOCATION)) {
return applyExplicitGenericInvocation(expression, selectorNode.getFirstChild(JavaGrammar.EXPLICIT_GENERIC_INVOCATION));
} else if (selectorNode.hasDirectChildren(JavaKeyword.THIS)) {
return new JavaTree.MemberSelectExpressionTreeImpl(
selectorNode,
expression,
identifier(selectorNode.getFirstChild(JavaKeyword.THIS))
);
} else if (selectorNode.hasDirectChildren(JavaGrammar.SUPER_SUFFIX)) {
return applySuperSuffix(
new JavaTree.MemberSelectExpressionTreeImpl(
selectorNode,
expression,
identifier(selectorNode.getFirstChild(JavaKeyword.SUPER))
),
selectorNode.getFirstChild(JavaGrammar.SUPER_SUFFIX)
);
} else if (selectorNode.hasDirectChildren(JavaKeyword.NEW)) {
AstNode innerCreatorNode = selectorNode.getFirstChild(JavaGrammar.INNER_CREATOR);
return applyClassCreatorRest(
expression,
identifier(innerCreatorNode.getFirstChild(JavaTokenType.IDENTIFIER)),
innerCreatorNode.getFirstChild(JavaGrammar.CLASS_CREATOR_REST)
);
} else if (selectorNode.hasDirectChildren(JavaGrammar.DIM_EXPR)) {
return new JavaTree.ArrayAccessExpressionTreeImpl(
selectorNode,
expression,
expression(selectorNode.getFirstChild(JavaGrammar.DIM_EXPR).getFirstChild(JavaGrammar.EXPRESSION))
);
} else {
throw new IllegalStateException(AstXmlPrinter.print(selectorNode));
}
}
private ExpressionTree applySuperSuffix(ExpressionTree expression, AstNode superSuffixNode) {
checkType(superSuffixNode, JavaGrammar.SUPER_SUFFIX);
if (superSuffixNode.hasDirectChildren(JavaGrammar.ARGUMENTS)) {
// super(arguments)
// super.method(arguments)
// super.method(arguments)
// TODO typeArguments
ExpressionTree methodSelect = expression;
if (superSuffixNode.hasDirectChildren(JavaTokenType.IDENTIFIER)) {
methodSelect = new JavaTree.MemberSelectExpressionTreeImpl(
superSuffixNode,
expression,
identifier(superSuffixNode.getFirstChild(JavaTokenType.IDENTIFIER))
);
}
return new JavaTree.MethodInvocationTreeImpl(
superSuffixNode,
methodSelect,
arguments(superSuffixNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
} else {
// super.field
return new JavaTree.MemberSelectExpressionTreeImpl(
superSuffixNode,
expression,
identifier(superSuffixNode.getFirstChild(JavaTokenType.IDENTIFIER))
);
}
}
private ExpressionTree applyClassCreatorRest(ExpressionTree enclosingExpression, ExpressionTree identifier, AstNode classCreatorRestNode) {
checkType(classCreatorRestNode, JavaGrammar.CLASS_CREATOR_REST);
ClassTree classBody = null;
if (classCreatorRestNode.hasDirectChildren(JavaGrammar.CLASS_BODY)) {
classBody = new JavaTree.ClassTreeImpl(
classCreatorRestNode,
Tree.Kind.CLASS,
JavaTree.ModifiersTreeImpl.EMPTY,
classBody(classCreatorRestNode.getFirstChild(JavaGrammar.CLASS_BODY))
);
}
return new JavaTree.NewClassTreeImpl(
classCreatorRestNode,
enclosingExpression,
identifier,
arguments(classCreatorRestNode.getFirstChild(JavaGrammar.ARGUMENTS)),
classBody
);
}
private ExpressionTree applyExplicitGenericInvocation(ExpressionTree expression, AstNode astNode) {
checkType(astNode, JavaGrammar.EXPLICIT_GENERIC_INVOCATION);
// TODO NON_WILDCARD_TYPE_ARGUMENTS
AstNode explicitGenericInvocationSuffixNode = astNode.getFirstChild(JavaGrammar.EXPLICIT_GENERIC_INVOCATION_SUFFIX);
if (explicitGenericInvocationSuffixNode.hasDirectChildren(JavaGrammar.SUPER_SUFFIX)) {
expression = new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
expression,
identifier(explicitGenericInvocationSuffixNode.getFirstChild(JavaKeyword.SUPER))
);
return applySuperSuffix(expression, explicitGenericInvocationSuffixNode.getFirstChild(JavaGrammar.SUPER_SUFFIX));
} else {
return new JavaTree.MethodInvocationTreeImpl(
astNode,
new JavaTree.MemberSelectExpressionTreeImpl(
astNode,
expression,
identifier(explicitGenericInvocationSuffixNode.getFirstChild(JavaTokenType.IDENTIFIER))
),
arguments(explicitGenericInvocationSuffixNode.getFirstChild(JavaGrammar.ARGUMENTS))
);
}
}
private List arguments(AstNode astNode) {
checkType(astNode, JavaGrammar.ARGUMENTS);
ImmutableList.Builder arguments = ImmutableList.builder();
for (AstNode argument : astNode.getChildren(JavaGrammar.EXPRESSION)) {
arguments.add(expression(argument));
}
return arguments.build();
}
private ExpressionTree applyDim(ExpressionTree expression, int count) {
ExpressionTree result = expression;
for (int i = 0; i < count; i++) {
result = new JavaTree.ArrayTypeTreeImpl(/* FIXME should not be null */null, expression);
}
return result;
}
}