blob: f832ae4ec45de28b098331d277f45033666acef5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2014 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Institute for Software - initial API and implementation
* Markus Schorn (Wind River Systems)
* Sergey Prigogin (Google)
* Thomas Corbat (IFS)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.astwriter;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
import org.eclipse.cdt.core.dom.ast.gnu.IGNUASTCompoundStatementExpression;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.internal.core.dom.rewrite.ASTLiteralNode;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
/**
* Visits all nodes, prints leading comments and handles macro expansions. The
* source code generation is delegated to severals {@code NodeWriter}s.
*
* @see MacroExpansionHandler
*
* @author Emanuel Graf IFS
*/
public class ASTWriterVisitor extends ASTVisitor {
protected final Scribe scribe = new Scribe();
protected NodeCommentMap commentMap;
protected ExpressionWriter expWriter;
protected DeclSpecWriter declSpecWriter;
protected StatementWriter statementWriter;
protected DeclaratorWriter declaratorWriter;
protected DeclarationWriter declarationWriter;
protected InitializerWriter initializerWriter;
protected NameWriter nameWriter;
protected TemplateParameterWriter tempParameterWriter;
protected AttributeWriter attributeWriter;
protected MacroExpansionHandler macroHandler;
private boolean insertLeadingBlankLine;
private boolean suppressLeadingBlankLine;
private boolean spaceNeededBeforeName;
{
shouldVisitArrayModifiers = true;
shouldVisitBaseSpecifiers = true;
shouldVisitDeclarations = true;
shouldVisitDeclarators = true;
shouldVisitDeclSpecifiers = true;
shouldVisitDecltypeSpecifiers = true;
shouldVisitExpressions = true;
shouldVisitInitializers = true;
shouldVisitNames = true;
shouldVisitNamespaces = true;
shouldVisitParameterDeclarations = true;
shouldVisitPointerOperators = true;
shouldVisitStatements = true;
shouldVisitTemplateParameters = true;
shouldVisitTranslationUnit = true;
shouldVisitTypeIds = true;
shouldVisitAttributes= true;
}
/**
* Creates a writer with an empty comment map.
*/
public ASTWriterVisitor() {
this(new NodeCommentMap());
}
/**
* Creates a writer with an empty comment map that uses const placement
* properties of the project associated with the provided translation unit.
*/
public ASTWriterVisitor(ITranslationUnit tu) {
this();
configureForTU(tu);
}
public ASTWriterVisitor(NodeCommentMap commentMap) {
super();
init(commentMap);
this.commentMap = commentMap;
this.suppressLeadingBlankLine = true;
}
private void init(NodeCommentMap commentMap) {
macroHandler = new MacroExpansionHandler(scribe);
statementWriter = new StatementWriter(scribe, this, commentMap);
declaratorWriter = new DeclaratorWriter(scribe, this, commentMap);
declarationWriter = new DeclarationWriter(scribe, this, commentMap);
declSpecWriter = new DeclSpecWriter(scribe, this, commentMap);
expWriter = new ExpressionWriter(scribe, this, macroHandler, commentMap);
initializerWriter = new InitializerWriter (scribe, this, commentMap);
// ppStmtWriter = new PreprocessorStatementWriter(scribe, this, commentMap);
nameWriter = new NameWriter(scribe, this, commentMap);
tempParameterWriter = new TemplateParameterWriter(scribe, this, commentMap);
attributeWriter = new AttributeWriter(scribe, this, commentMap);
}
public void configureForTU(ITranslationUnit tu) {
boolean placeConstRight = ConstPlacement.placeConstRight(tu);
declSpecWriter.setPlaceConstRight(placeConstRight);
}
@Override
public String toString() {
return scribe.toString();
}
@Override
public int leave(IASTTranslationUnit tu) {
for (IASTComment comment : commentMap.getFreestandingCommentsForNode(tu)) {
scribe.print(comment.getComment());
scribe.newLine();
}
return super.leave(tu);
}
private void writeLeadingComments(IASTNode node) {
for (IASTComment comment : getLeadingComments(node)) {
scribe.print(comment.getComment());
scribe.newLine();
}
}
private List<IASTComment> getLeadingComments(IASTNode node) {
List<IASTComment> leadingComments = commentMap.getLeadingCommentsForNode(node);
IASTNode originalNode = node.getOriginalNode();
if (originalNode != node)
leadingComments.addAll(commentMap.getLeadingCommentsForNode(originalNode));
return leadingComments;
}
public void visit(ASTLiteralNode lit) {
insertBlankLineIfNeeded(lit);
scribe.print(lit.getRawSignature());
}
@Override
public int visit(ICPPASTBaseSpecifier baseSpecifier) {
declSpecWriter.writeBaseSpecifiers(baseSpecifier);
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTName name) {
if (spaceNeededBeforeName && name.getSimpleID().length != 0) {
scribe.printSpace();
spaceNeededBeforeName = false;
}
writeLeadingComments(name);
if (!macroHandler.checkisMacroExpansionNode(name)) {
nameWriter.writeName(name);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTDeclSpecifier declSpec) {
writeLeadingComments(declSpec);
declSpecWriter.writeDelcSpec(declSpec);
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(ICPPASTDecltypeSpecifier decltypeSpec) {
scribe.print(Keywords.DECLTYPE);
scribe.print('(');
decltypeSpec.getDecltypeExpression().accept(this);
scribe.print(')');
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTExpression expression) {
writeLeadingComments(expression);
if (!macroHandler.checkisMacroExpansionNode(expression)) {
if (expression instanceof IGNUASTCompoundStatementExpression) {
IGNUASTCompoundStatementExpression gnuCompStmtExp =
(IGNUASTCompoundStatementExpression) expression;
gnuCompStmtExp.getCompoundStatement().accept(this);
} else {
expWriter.writeExpression(expression);
}
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTStatement statement) {
insertBlankLineIfNeeded(statement);
writeLeadingComments(statement);
try {
if (macroHandler.isStatementWithMixedLocation(statement) &&
!(statement instanceof IASTCompoundStatement)) {
return statementWriter.writeMixedStatement(statement);
}
if (macroHandler.checkisMacroExpansionNode(statement)) {
return ASTVisitor.PROCESS_SKIP;
}
return statementWriter.writeStatement(statement, true);
} finally {
setLeadingBlankLineFlags(statement);
}
}
@Override
public int visit(IASTDeclaration declaration) {
insertBlankLineIfNeeded(declaration);
writeLeadingComments(declaration);
if (!macroHandler.checkisMacroExpansionNode(declaration)) {
declarationWriter.writeDeclaration(declaration);
setLeadingBlankLineFlags(declaration);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTDeclarator declarator) {
writeLeadingComments(declarator);
if (!macroHandler.checkisMacroExpansionNode(declarator)) {
declaratorWriter.writeDeclarator(declarator);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTArrayModifier amod) {
if (!macroHandler.checkisMacroExpansionNode(amod)) {
declaratorWriter.writeArrayModifier(amod);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTInitializer initializer) {
writeLeadingComments(initializer);
if (!macroHandler.checkisMacroExpansionNode(initializer)) {
initializerWriter.writeInitializer(initializer);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTParameterDeclaration parameterDeclaration) {
writeLeadingComments(parameterDeclaration);
if (!macroHandler.checkisMacroExpansionNode(parameterDeclaration)) {
parameterDeclaration.getDeclSpecifier().accept(this);
IASTDeclarator declarator = getParameterDeclarator(parameterDeclaration);
spaceNeededBeforeName = true;
declarator.accept(this);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTPointerOperator pointerOperator) {
writeLeadingComments(pointerOperator);
if (!macroHandler.checkisMacroExpansionNode(pointerOperator)) {
declaratorWriter.writePointerOperator(pointerOperator);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTTypeId typeId) {
IASTDeclSpecifier declSpecifier = typeId.getDeclSpecifier();
if (declSpecifier != null) declSpecifier.accept(this);
if (typeId instanceof ICPPASTTypeId) {
if (((ICPPASTTypeId) typeId).isPackExpansion()) {
scribe.print(Keywords.cpELLIPSIS);
}
}
IASTDeclarator declarator = typeId.getAbstractDeclarator();
if (declarator != null) {
declarator.accept(this);
}
return ASTVisitor.PROCESS_SKIP;
}
protected IASTName getParameterName(IASTDeclarator declarator) {
return declarator.getName();
}
protected IASTDeclarator getParameterDeclarator(IASTParameterDeclaration parameterDeclaration) {
return parameterDeclaration.getDeclarator();
}
@Override
public int visit(ICPPASTNamespaceDefinition namespace) {
insertBlankLineIfNeeded(namespace);
writeLeadingComments(namespace);
if (!macroHandler.checkisMacroExpansionNode(namespace)) {
declarationWriter.writeDeclaration(namespace);
setLeadingBlankLineFlags(namespace);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(ICPPASTTemplateParameter parameter) {
writeLeadingComments(parameter);
if (!macroHandler.checkisMacroExpansionNode(parameter)) {
tempParameterWriter.writeTemplateParameter(parameter);
}
return ASTVisitor.PROCESS_SKIP;
}
@Override
public int visit(IASTAttributeSpecifier specifier) {
attributeWriter.writeAttributeSpecifier(specifier);
return ASTVisitor.PROCESS_SKIP;
}
public void cleanCache() {
scribe.cleanCache();
macroHandler.reset();
}
private void insertBlankLineIfNeeded(IASTNode node) {
if (!suppressLeadingBlankLine &&
(insertLeadingBlankLine || ASTWriter.requiresLeadingBlankLine(node))) {
scribe.newLine();
}
insertLeadingBlankLine = false;
suppressLeadingBlankLine = false;
}
private void setLeadingBlankLineFlags(IASTNode node) {
insertLeadingBlankLine = ASTWriter.requiresTrailingBlankLine(node);
suppressLeadingBlankLine = ASTWriter.suppressesTrailingBlankLine(node);
}
public boolean isSuppressLeadingBlankLine() {
return suppressLeadingBlankLine;
}
public void setSuppressLeadingBlankLine(boolean value) {
this.suppressLeadingBlankLine = value;
}
public boolean isSpaceNeededBeforeName() {
return spaceNeededBeforeName;
}
public void setSpaceNeededBeforeName(boolean value) {
this.spaceNeededBeforeName = value;
}
public Scribe getScribe() {
return scribe;
}
public void newLine() {
scribe.newLine();
}
}