/******************************************************************************* * Copyright (c) 2007, 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: * Institute for Software - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring; import java.util.ArrayList; import java.util.List; import org.eclipse.osgi.util.NLS; import org.eclipse.text.edits.TextEditGroup; import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTVisibilityLabel; import org.eclipse.cdt.internal.ui.refactoring.utils.VisibilityEnum; /** * Adds a declaration to an existing class via the ModificationCollector. It automatically searches * the correct insertion point for the desired visibility. * * @author Mirko Stocker */ public class AddDeclarationNodeToClassChange { private final ICPPASTCompositeTypeSpecifier nodeClass; private final VisibilityEnum visibility; private List<IASTNode> fieldNodes = new ArrayList<IASTNode>(); private final ModificationCollector collector; public static void createChange(ICPPASTCompositeTypeSpecifier nodeClass, VisibilityEnum visibility, IASTNode fieldNodes, boolean isField, ModificationCollector collector) { new AddDeclarationNodeToClassChange(nodeClass, visibility, fieldNodes, collector, isField); } public static void createChange(ICPPASTCompositeTypeSpecifier nodeClass, VisibilityEnum visibility, List<IASTNode> fieldNodes, boolean isField, ModificationCollector collector) { new AddDeclarationNodeToClassChange(nodeClass, visibility, fieldNodes, collector, isField); } private AddDeclarationNodeToClassChange(ICPPASTCompositeTypeSpecifier nodeClass, VisibilityEnum visibility, List<IASTNode> fieldNodes, ModificationCollector collector, boolean isField) { this.fieldNodes = fieldNodes; this.nodeClass = nodeClass; this.visibility = visibility; this.collector = collector; createRewrites(isField); } private AddDeclarationNodeToClassChange(ICPPASTCompositeTypeSpecifier nodeClass, VisibilityEnum visibility, IASTNode fieldNodes, ModificationCollector collector, boolean isField) { this.nodeClass = nodeClass; this.visibility = visibility; this.fieldNodes.add(fieldNodes); this.collector = collector; createRewrites(isField); } private void createRewrites(boolean isField) { int lastFunctionDeclaration = -1; int lastFieldDeclaration = -1; IASTDeclaration[] members = nodeClass.getMembers(); VisibilityEnum currentVisibility = VisibilityEnum.v_private; if (IASTCompositeTypeSpecifier.k_struct == nodeClass.getKey()) { currentVisibility = VisibilityEnum.v_public; } // Find the insert location by iterating over the elements of the class // and remembering the last element with the matching visibility for (int i = 0; i < members.length; i++) { IASTDeclaration declaration = members[i]; if (declaration instanceof ICPPASTVisibilityLabel) { currentVisibility = VisibilityEnum.from((ICPPASTVisibilityLabel) declaration); } if (declaration instanceof IASTSimpleDeclaration) { IASTSimpleDeclaration simple = (IASTSimpleDeclaration) declaration; IASTDeclarator[] declarators = simple.getDeclarators(); if (declarators.length > 0 && declarators[0] != null && declarators[0] instanceof IASTFunctionDeclarator) { if (currentVisibility.equals(visibility)) { lastFunctionDeclaration = i; } } else if (declarators.length > 0 && declarators[0] != null) { if (currentVisibility.equals(visibility)) { lastFieldDeclaration = i; } } } } IASTDeclaration nextFunctionDeclaration = null; if (lastFunctionDeclaration < members.length - 1 && lastFunctionDeclaration >= 0) nextFunctionDeclaration = members[lastFunctionDeclaration + 1]; IASTDeclaration nextFieldDeclaration = null; if (lastFieldDeclaration < members.length - 1 && lastFieldDeclaration >= 0) nextFieldDeclaration = members[lastFieldDeclaration + 1]; createInsert(isField, nextFunctionDeclaration, nextFieldDeclaration, currentVisibility); } private void createInsert(boolean isField, IASTDeclaration nextFunctionDeclaration, IASTDeclaration nextFieldDeclaration, VisibilityEnum currentVisibility) { if (isField) { if (nextFieldDeclaration != null) { insertBefore(nextFieldDeclaration); } else if (nextFunctionDeclaration != null) { insertBefore(nextFunctionDeclaration); } else { insertAtTheEnd(currentVisibility); } } else { if (nextFunctionDeclaration != null) { insertBefore(nextFunctionDeclaration); } else if (nextFieldDeclaration != null) { insertBefore(nextFieldDeclaration); } else { insertAtTheEnd(currentVisibility); } } } private void insertBefore(IASTNode nearestNode) { ASTRewrite rewrite = collector.rewriterForTranslationUnit(nearestNode.getTranslationUnit()); for (IASTNode node : fieldNodes) { rewrite.insertBefore(nearestNode.getParent(), nearestNode, node, createEditDescription()); } } private void insertAtTheEnd(VisibilityEnum currentVisibility) { ASTRewrite rewrite = collector.rewriterForTranslationUnit(nodeClass.getTranslationUnit()); if (!currentVisibility.equals(visibility)) { ICPPASTVisibilityLabel label = new CPPASTVisibilityLabel(visibility.getICPPASTVisiblityLabelVisibility()); rewrite.insertBefore(nodeClass, null, label, createEditDescription()); } for (IASTNode node : fieldNodes) { rewrite.insertBefore(nodeClass, null, node, createEditDescription()); } } private TextEditGroup createEditDescription() { return new TextEditGroup(NLS.bind(Messages.AddDeclarationNodeToClassChange_AddDeclaration, nodeClass.getName())); } }