/******************************************************************************* * Copyright (c) 2011 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: * Martin Schwab & Thomas Kallenberg - initial API and implementation ******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.togglefunction; import java.util.List; import org.eclipse.text.edits.TextEditGroup; import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite.CommentPosition; import org.eclipse.cdt.internal.core.dom.rewrite.ASTLiteralNode; import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector; import org.eclipse.cdt.internal.ui.refactoring.utils.CPPASTAllVisitor; public class ToggleFromImplementationToHeaderOrClassStrategy implements IToggleRefactoringStrategy { private ToggleRefactoringContext context; private TextEditGroup infoText; private IASTTranslationUnit other_tu; private ASTLiteralNode includenode; public ToggleFromImplementationToHeaderOrClassStrategy( ToggleRefactoringContext context) { this.context = context; this.infoText = new TextEditGroup(Messages.EditGroupName); } private boolean isFreeFunction(IASTFunctionDefinition definition) { return definition.getDeclarator().getName() instanceof ICPPASTQualifiedName; } public void run(ModificationCollector modifications) { newFileCheck(); ASTRewrite implast = modifications.rewriterForTranslationUnit(context.getDefinitionUnit()); List<IASTComment>leadingComments = implast.getComments(context.getDefinition(), CommentPosition.leading); removeDefinitionFromImplementation(implast); if (includenode != null) { implast.insertBefore(context.getDefinitionUnit(), context.getDefinitionUnit().getChildren()[0], includenode, infoText); } if (context.getDeclarationUnit() != null) { addDefinitionToClass(modifications, leadingComments); } else { addDefinitionToHeader(modifications, leadingComments); } } private void newFileCheck() { if (context.getDeclarationUnit() == null) { if (isFreeFunction(context.getDefinition())) { throw new NotSupportedException(Messages.ToggleFromImplementationToHeaderOrClassStrategy_CanNotToggle); } other_tu = context.getTUForSiblingFile(); if (other_tu == null) { ToggleFileCreator filecreator = new ToggleFileCreator(context, ".h"); //$NON-NLS-1$ if (filecreator.askUserForFileCreation(context)) { filecreator.createNewFile(); other_tu = filecreator.loadTranslationUnit(); includenode = new ASTLiteralNode(filecreator.getIncludeStatement() + "\n\n"); //$NON-NLS-1$ } else { throw new NotSupportedException(Messages.ToggleFromImplementationToHeaderOrClassStrategy_CanNotCreateNewFile); } } } } private void addDefinitionToHeader(ModificationCollector modifications, List<IASTComment> leadingComments) { ASTRewrite headerRewrite = modifications.rewriterForTranslationUnit(other_tu); IASTFunctionDefinition newDefinition = ToggleNodeHelper.createFunctionSignatureWithEmptyBody( context .getDefinition().getDeclSpecifier().copy(CopyStyle.withLocations), context.getDefinition() .getDeclarator().copy(CopyStyle.withLocations), context.getDefinition().copy(CopyStyle.withLocations)); newDefinition.setParent(other_tu); headerRewrite.insertBefore(other_tu.getTranslationUnit(), null, newDefinition, infoText); restoreBody(headerRewrite, newDefinition, modifications); for (IASTComment comment : leadingComments) { headerRewrite.addComment(newDefinition, comment, CommentPosition.leading); } } private void addDefinitionToClass(ModificationCollector modifications, List<IASTComment> leadingComments) { ASTRewrite headerRewrite = modifications.rewriterForTranslationUnit( context.getDeclarationUnit()); IASTFunctionDefinition newDefinition = ToggleNodeHelper.createInClassDefinition( context.getDeclaration(), context.getDefinition(), context.getDeclarationUnit()); newDefinition.setParent(getParent()); restoreBody(headerRewrite, newDefinition, modifications); headerRewrite.replace(context.getDeclaration().getParent(), newDefinition, infoText); for (IASTComment comment : leadingComments) { headerRewrite.addComment(newDefinition, comment, CommentPosition.leading); } } private IASTNode getParent() { IASTNode parent = ToggleNodeHelper.getAncestorOfType(context.getDefinition(), ICPPASTCompositeTypeSpecifier.class); IASTNode parentnode = null; if (parent != null) { parentnode = parent; } else { parentnode =context.getDeclarationUnit(); } return parentnode; } private void restoreBody(ASTRewrite headerRewrite, IASTFunctionDefinition newDefinition, ModificationCollector modifications) { IASTFunctionDefinition oldDefinition = context.getDefinition(); newDefinition.setBody(oldDefinition.getBody().copy(CopyStyle.withLocations)); if (newDefinition instanceof ICPPASTFunctionWithTryBlock && oldDefinition instanceof ICPPASTFunctionWithTryBlock) { ICPPASTFunctionWithTryBlock newTryDef = (ICPPASTFunctionWithTryBlock) newDefinition; ICPPASTFunctionWithTryBlock oldTryDef = (ICPPASTFunctionWithTryBlock) oldDefinition; for (ICPPASTCatchHandler handler : oldTryDef.getCatchHandlers()) { newTryDef.addCatchHandler(handler.copy(CopyStyle.withLocations)); } } copyAllCommentsToNewLocation(oldDefinition, modifications.rewriterForTranslationUnit(oldDefinition.getTranslationUnit()), headerRewrite); } private void copyAllCommentsToNewLocation(IASTNode node, final ASTRewrite oldRw, final ASTRewrite newRw) { node.accept(new CPPASTAllVisitor() { @Override public int visitAll(IASTNode node){ copyComments(oldRw, newRw, node, CommentPosition.leading); copyComments(oldRw, newRw, node, CommentPosition.trailing); copyComments(oldRw, newRw, node, CommentPosition.freestanding); return PROCESS_CONTINUE; } private void copyComments(final ASTRewrite oldRw, final ASTRewrite newRw, IASTNode node, CommentPosition pos) { List<IASTComment> comments = oldRw.getComments(node, pos); for (IASTComment comment : comments) { newRw.addComment(node, comment, pos); } } }); } private void removeDefinitionFromImplementation(ASTRewrite implast) { ICPPASTNamespaceDefinition ns = ToggleNodeHelper.getAncestorOfType( context.getDefinition(), ICPPASTNamespaceDefinition.class); if (ns != null && isSingleElementInNamespace(ns, context.getDefinition())) { implast.remove(ns, infoText); } else { implast.remove(context.getDefinition(), infoText); } } private boolean isSingleElementInNamespace(ICPPASTNamespaceDefinition ns, IASTFunctionDefinition definition) { return ns.getChildren().length == 2 && (ns.contains(definition)); } }