/*******************************************************************************
* 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.EnumSet;
import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
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.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
import org.eclipse.cdt.core.parser.Keywords;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
/**
* Generates source code of declaration nodes. The actual string operations are delegated
* to the <code>Scribe</code> class.
*
* @see Scribe
* @see IASTDeclaration
* @author Emanuel Graf IFS
*/
public class DeclarationWriter extends NodeWriter {
private static final String ASM_END = ")"; //$NON-NLS-1$
private static final String ASM_START = "asm("; //$NON-NLS-1$
private static final String TEMPLATE_DECLARATION = "template<"; //$NON-NLS-1$
private static final String TEMPLATE_SPECIALIZATION = "template <> "; //$NON-NLS-1$
private boolean printSemicolon;
public DeclarationWriter(Scribe scribe, ASTWriterVisitor visitor, NodeCommentMap commentMap) {
super(scribe, visitor, commentMap);
}
protected void writeDeclaration(IASTDeclaration declaration) throws ProblemRuntimeException{
writeDeclaration(declaration, true);
}
protected void writeDeclaration(IASTDeclaration declaration, boolean writeSemicolon) {
boolean addNewLine = true;
printSemicolon = writeSemicolon;
if (declaration instanceof IASTASMDeclaration) {
writeASMDeclatation((IASTASMDeclaration) declaration);
} else if (declaration instanceof IASTFunctionDefinition) {
writeFunctionDefinition((IASTFunctionDefinition) declaration);
addNewLine = false;
} else if (declaration instanceof IASTProblemDeclaration) {
throw new ProblemRuntimeException((IASTProblemDeclaration) declaration);
} else if (declaration instanceof IASTSimpleDeclaration) {
writeSimpleDeclaration((IASTSimpleDeclaration) declaration);
} else if (declaration instanceof ICPPASTExplicitTemplateInstantiation) {
writeExplicitTemplateInstantiation((ICPPASTExplicitTemplateInstantiation) declaration);
addNewLine = false;
} else if (declaration instanceof ICPPASTLinkageSpecification) {
writeLinkageSpecification((ICPPASTLinkageSpecification) declaration);
} else if (declaration instanceof ICPPASTNamespaceAlias) {
writeNamespaceAlias((ICPPASTNamespaceAlias) declaration);
} else if (declaration instanceof ICPPASTTemplateDeclaration) {
writeTemplateDeclaration((ICPPASTTemplateDeclaration) declaration);
addNewLine = false;
} else if (declaration instanceof ICPPASTTemplateSpecialization) {
writeTemplateSpecialization((ICPPASTTemplateSpecialization) declaration);
addNewLine = false;
} else if (declaration instanceof ICPPASTUsingDeclaration) {
writeUsingDeclaration((ICPPASTUsingDeclaration) declaration);
} else if (declaration instanceof ICPPASTUsingDirective) {
writeUsingDirective((ICPPASTUsingDirective) declaration);
} else if (declaration instanceof ICPPASTVisibilityLabel) {
writeVisibilityLabel((ICPPASTVisibilityLabel) declaration);
} else if (declaration instanceof ICPPASTAliasDeclaration) {
writeAliasDeclaration((ICPPASTAliasDeclaration) declaration);
}
writeTrailingComments(declaration, addNewLine);
if (hasFreestandingComments(declaration)) {
if (declaration instanceof IASTFunctionDefinition) {
scribe.newLine();
}
writeFreestandingComments(declaration);
}
}
private void writeAliasDeclaration(ICPPASTAliasDeclaration aliasDeclaration) {
scribe.printStringSpace(Keywords.USING);
IASTName alias = aliasDeclaration.getAlias();
if (alias != null) {
alias.accept(visitor);
}
writeAttributes(aliasDeclaration, EnumSet.of(SpaceLocation.BEFORE));
scribe.print(EQUALS);
ICPPASTTypeId aliasedType = aliasDeclaration.getMappingTypeId();
if (aliasedType != null) {
aliasedType.accept(visitor);
}
scribe.printSemicolon();
}
private void writeVisibilityLabel(ICPPASTVisibilityLabel visiblityLabel) {
scribe.decrementIndentationLevel();
switch (visiblityLabel.getVisibility()) {
case ICPPASTVisibilityLabel.v_private:
scribe.print(Keywords.PRIVATE);
scribe.print(':');
break;
case ICPPASTVisibilityLabel.v_protected:
scribe.print(Keywords.PROTECTED);
scribe.print(':');
break;
case ICPPASTVisibilityLabel.v_public:
scribe.print(Keywords.PUBLIC);
scribe.print(':');
break;
default:
return;
}
scribe.incrementIndentationLevel();
}
private void writeUsingDirective(ICPPASTUsingDirective usingDirective) {
writeCPPAttributes(usingDirective, EnumSet.of(SpaceLocation.AFTER));
scribe.printStringSpace(Keywords.USING);
scribe.printStringSpace(Keywords.NAMESPACE);
usingDirective.getQualifiedName().accept(visitor);
writeGCCAttributes(usingDirective, EnumSet.of(SpaceLocation.BEFORE));
scribe.printSemicolon();
}
private void writeUsingDeclaration(ICPPASTUsingDeclaration usingDeclaration) {
scribe.printStringSpace(Keywords.USING);
if (usingDeclaration.isTypename()) {
scribe.printStringSpace(Keywords.TYPENAME);
}
usingDeclaration.getName().accept(visitor);
scribe.printSemicolon();
}
private void writeTemplateSpecialization(ICPPASTTemplateSpecialization templateSpecialization) {
scribe.print(TEMPLATE_SPECIALIZATION);
templateSpecialization.getDeclaration().accept(visitor);
}
protected void writeTemplateDeclaration(ICPPASTTemplateDeclaration templateDeclaration) {
if (templateDeclaration.isExported()) {
scribe.printStringSpace(Keywords.EXPORT);
}
scribe.print(TEMPLATE_DECLARATION);
ICPPASTTemplateParameter[] paraDecls = templateDeclaration.getTemplateParameters();
for (int i = 0; i < paraDecls.length; ++i) {
paraDecls[i].accept(visitor);
if (i + 1 < paraDecls.length) {
scribe.print(',');
scribe.printSpaces(1);
}
}
scribe.print('>');
scribe.printSpace();
templateDeclaration.getDeclaration().accept(visitor);
}
protected void writeDeclaration(ICPPASTNamespaceDefinition declaration) {
printSemicolon = true;
writeNamespaceDefinition(declaration);
}
private void writeNamespaceDefinition(ICPPASTNamespaceDefinition namespaceDefinition) {
scribe.printStringSpace(Keywords.NAMESPACE);
namespaceDefinition.getName().accept(visitor);
writeGCCAttributes(namespaceDefinition, EnumSet.of(SpaceLocation.BEFORE));
if (!hasTrailingComments(namespaceDefinition.getName())) {
scribe.newLine();
}
scribe.print('{');
scribe.newLine(2);
writeDeclarationsInNamespace(namespaceDefinition, namespaceDefinition.getDeclarations());
if (hasFreestandingComments(namespaceDefinition)) {
writeFreestandingComments(namespaceDefinition);
}
scribe.newLine();
scribe.print('}');
if (hasTrailingComments(namespaceDefinition)) {
writeTrailingComments(namespaceDefinition);
} else {
scribe.newLine();
}
}
protected void writeDeclarationsInNamespace(ICPPASTNamespaceDefinition namespaceDefinition, IASTDeclaration[] declarations) {
for (IASTDeclaration declaration : declarations) {
declaration.accept(visitor);
}
}
private void writeNamespaceAlias(ICPPASTNamespaceAlias namespaceAliasDefinition) {
scribe.printStringSpace(Keywords.NAMESPACE);
namespaceAliasDefinition.getAlias().accept(visitor);
scribe.print(EQUALS);
namespaceAliasDefinition.getMappingName().accept(visitor);
printSemicolon();
}
private void writeLinkageSpecification(ICPPASTLinkageSpecification linkageSpecification) {
scribe.printStringSpace(Keywords.EXTERN);
scribe.printStringSpace(linkageSpecification.getLiteral());
IASTDeclaration[] declarations = linkageSpecification.getDeclarations();
if (declarations.length > 1) {
scribe.printLBrace();
scribe.decrementIndentationLevel();
scribe.newLine();
for (IASTDeclaration declaration : declarations) {
declaration.accept(visitor);
}
scribe.printRBrace();
scribe.incrementIndentationLevel();
} else if (declarations.length > 0) {
visitNodeIfNotNull(declarations[0]);
}
}
private void writeExplicitTemplateInstantiation(ICPPASTExplicitTemplateInstantiation explicitTemplateInstantiation) {
switch(explicitTemplateInstantiation.getModifier()) {
case ICPPASTExplicitTemplateInstantiation.EXTERN:
scribe.printStringSpace(Keywords.EXTERN);
break;
case ICPPASTExplicitTemplateInstantiation.INLINE:
scribe.printStringSpace(Keywords.INLINE);
break;
case ICPPASTExplicitTemplateInstantiation.STATIC:
scribe.printStringSpace(Keywords.STATIC);
break;
}
scribe.printStringSpace(Keywords.TEMPLATE);
explicitTemplateInstantiation.getDeclaration().accept(visitor);
}
private void writeASMDeclatation(IASTASMDeclaration asmDeclaration) {
scribe.print(ASM_START);
scribe.print(asmDeclaration.getAssembly());
scribe.print(ASM_END);
printSemicolon();
}
private void printSemicolon() {
if (printSemicolon) {
scribe.printSemicolon();
}
}
private void writeFunctionDefinition(IASTFunctionDefinition funcDef) {
if (funcDef instanceof IASTAttributeOwner) {
writeAttributes((IASTAttributeOwner) funcDef, EnumSet.of(SpaceLocation.AFTER));
}
IASTDeclSpecifier declSpecifier = funcDef.getDeclSpecifier();
if (declSpecifier != null)
declSpecifier.accept(visitor);
if (declSpecifier instanceof IASTSimpleDeclSpecifier) {
IASTSimpleDeclSpecifier simDeclSpec = (IASTSimpleDeclSpecifier) declSpecifier;
if (simDeclSpec.getType() != IASTSimpleDeclSpecifier.t_unspecified) {
visitor.setSpaceNeededBeforeName(true);
}
} else {
visitor.setSpaceNeededBeforeName(true);
}
IASTDeclarator declarator = ASTQueries.findOutermostDeclarator(funcDef.getDeclarator());
declarator.accept(visitor);
if (funcDef instanceof ICPPASTFunctionWithTryBlock) {
scribe.newLine();
scribe.print(Keywords.TRY);
}
if (funcDef instanceof ICPPASTFunctionDefinition) {
ICPPASTFunctionDefinition cppFuncDef= (ICPPASTFunctionDefinition) funcDef;
writeCtorChainInitializer(cppFuncDef, cppFuncDef.getMemberInitializers());
if (cppFuncDef.isDefaulted()) {
scribe.print(EQUALS);
scribe.print(Keywords.DEFAULT);
scribe.printSemicolon();
} else if (cppFuncDef.isDeleted()) {
scribe.print(EQUALS);
scribe.print(Keywords.DELETE);
scribe.printSemicolon();
}
}
scribe.newLine();
IASTStatement body = funcDef.getBody();
if (body != null) {
body.accept(visitor);
}
if (funcDef instanceof ICPPASTFunctionWithTryBlock) {
ICPPASTFunctionWithTryBlock tryblock = (ICPPASTFunctionWithTryBlock) funcDef;
ICPPASTCatchHandler[] catches = tryblock.getCatchHandlers();
for (ICPPASTCatchHandler handler : catches) {
handler.accept(visitor);
}
}
}
protected void writeCtorChainInitializer(ICPPASTFunctionDefinition funcDec,
ICPPASTConstructorChainInitializer[] ctorInitChain) {
if (ctorInitChain.length != 0) {
scribe.newLine();
scribe.print(':');
}
for (int i = 0; i < ctorInitChain.length; ++i) {
ICPPASTConstructorChainInitializer initializer = ctorInitChain[i];
initializer.accept(visitor);
if (i + 1 < ctorInitChain.length) {
scribe.print(COMMA_SPACE);
}
}
}
private void writeSimpleDeclaration(IASTSimpleDeclaration simpDec) {
IASTDeclSpecifier declSpecifier = simpDec.getDeclSpecifier();
IASTDeclarator[] decls = simpDec.getDeclarators();
writeAttributes(simpDec, EnumSet.of(SpaceLocation.AFTER));
declSpecifier.accept(visitor);
boolean noSpace = false;
if (declSpecifier instanceof IASTSimpleDeclSpecifier) {
IASTSimpleDeclSpecifier simpleDeclSpecifier = (IASTSimpleDeclSpecifier) declSpecifier;
if (simpleDeclSpecifier.getType() == IASTSimpleDeclSpecifier.t_unspecified) {
noSpace = true;
}
}
if (decls.length > 0) {
if (decls.length == 1) {
if (!noSpace)
visitor.setSpaceNeededBeforeName(true);
decls[0].accept(visitor);
} else {
if (!noSpace) {
scribe.printSpace();
}
writeNodeList(decls);
}
}
printSemicolon();
}
}