1 /*******************************************************************************
2 * Copyright (c) 2008, 2011 Institute for Software, HSR Hochschule fuer Technik
3 * Rapperswil, University of applied sciences and others.
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Institute for Software - initial API and implementation
11 * Sergey Prigogin (Google)
12 * Marc-Andre Laperle - do not search for definition insert location twice.
13 *******************************************************************************/
14 package org.eclipse.cdt.internal.ui.refactoring.gettersandsetters;
16 import java.util.ArrayList;
17 import java.util.List;
19 import org.eclipse.core.resources.IFile;
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.OperationCanceledException;
23 import org.eclipse.core.runtime.SubMonitor;
24 import org.eclipse.jface.viewers.ISelection;
25 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
26 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
27 import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
29 import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
30 import org.eclipse.cdt.core.dom.ast.ASTVisitor;
31 import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
32 import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
33 import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
34 import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
35 import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
36 import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
37 import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
38 import org.eclipse.cdt.core.dom.ast.IASTName;
39 import org.eclipse.cdt.core.dom.ast.IASTNode;
40 import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
41 import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
42 import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
43 import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
44 import org.eclipse.cdt.core.model.ICElement;
45 import org.eclipse.cdt.core.model.ICProject;
47 import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ContainerNode;
49 import org.eclipse.cdt.internal.ui.refactoring.CRefactoring2;
50 import org.eclipse.cdt.internal.ui.refactoring.AddDeclarationNodeToClassChange;
51 import org.eclipse.cdt.internal.ui.refactoring.Container;
52 import org.eclipse.cdt.internal.ui.refactoring.ModificationCollector;
53 import org.eclipse.cdt.internal.ui.refactoring.RefactoringASTCache;
54 import org.eclipse.cdt.internal.ui.refactoring.implementmethod.InsertLocation;
55 import org.eclipse.cdt.internal.ui.refactoring.implementmethod.MethodDefinitionInsertLocationFinder;
56 import org.eclipse.cdt.internal.ui.refactoring.utils.Checks;
57 import org.eclipse.cdt.internal.ui.refactoring.utils.NodeHelper;
58 import org.eclipse.cdt.internal.ui.refactoring.utils.VisibilityEnum;
61 * @author Thomas Corbat
63 public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
65 private final class CompositeTypeSpecFinder extends ASTVisitor {
66 private final int start;
67 private final Container<IASTCompositeTypeSpecifier> container;
69 shouldVisitDeclSpecifiers = true;
72 private CompositeTypeSpecFinder(int start, Container<IASTCompositeTypeSpecifier> container) {
74 this.container = container;
78 public int visit(IASTDeclSpecifier declSpec) {
79 if (declSpec instanceof IASTCompositeTypeSpecifier) {
80 IASTFileLocation loc = declSpec.getFileLocation();
81 if (start > loc.getNodeOffset() && start < loc.getNodeOffset() + loc.getNodeLength()) {
82 container.setObject((IASTCompositeTypeSpecifier) declSpec);
83 return ASTVisitor.PROCESS_ABORT;
87 return super.visit(declSpec);
91 private static final String MEMBER_DECLARATION = "MEMBER_DECLARATION"; //$NON-NLS-1$
92 private final GetterSetterContext context;
93 private InsertLocation definitionInsertLocation;
95 public GenerateGettersAndSettersRefactoring(ICElement element, ISelection selection,
96 ICProject project, RefactoringASTCache astCache) {
97 super(element, selection, project, astCache);
98 context = new GetterSetterContext();
102 public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
103 throws CoreException, OperationCanceledException {
104 SubMonitor sm = SubMonitor.convert(pm, 10);
106 RefactoringStatus status = super.checkInitialConditions(sm.newChild(6));
107 if (status.hasError()) {
111 if (!initStatus.hasFatalError()) {
113 if (context.existingFields.isEmpty()) {
114 initStatus.addFatalError(Messages.GenerateGettersAndSettersRefactoring_NoFields);
121 public RefactoringStatus checkFinalConditions(IProgressMonitor pm,
122 CheckConditionsContext checkContext) throws CoreException, OperationCanceledException {
123 RefactoringStatus result = new RefactoringStatus();
124 if (!context.isImplementationInHeader()) {
125 findDefinitionInsertLocation(pm);
126 if (definitionInsertLocation == null || tu.equals(definitionInsertLocation.getTranslationUnit())) {
127 result.addInfo(Messages.GenerateGettersAndSettersRefactoring_NoImplFile);
130 Checks.addModifiedFilesToChecker(getAllFilesToModify(), checkContext);
134 private IFile[] getAllFilesToModify() {
135 List<IFile> files = new ArrayList<IFile>(2);
136 IFile file = (IFile) tu.getResource();
140 if (definitionInsertLocation != null) {
141 file = definitionInsertLocation.getFile();
146 return files.toArray(new IFile[files.size()]);
149 private void initRefactoring(IProgressMonitor pm) throws OperationCanceledException, CoreException {
150 IASTTranslationUnit ast = astCache.getAST(tu, null);
151 context.selectedName = getSelectedName(ast);
152 IASTCompositeTypeSpecifier compositeTypeSpecifier = null;
153 if (context.selectedName != null) {
154 compositeTypeSpecifier = getCompositeTypeSpecifier(context.selectedName);
156 compositeTypeSpecifier = findCurrentCompositeTypeSpecifier(ast);
158 if (compositeTypeSpecifier != null) {
159 findDeclarations(compositeTypeSpecifier);
161 initStatus.addFatalError(Messages.GenerateGettersAndSettersRefactoring_NoCassDefFound);
165 private IASTCompositeTypeSpecifier findCurrentCompositeTypeSpecifier(IASTTranslationUnit ast)
166 throws OperationCanceledException, CoreException {
167 final int start = selectedRegion.getOffset();
168 Container<IASTCompositeTypeSpecifier> container = new Container<IASTCompositeTypeSpecifier>();
169 ast.accept(new CompositeTypeSpecFinder(start, container));
170 return container.getObject();
173 private IASTCompositeTypeSpecifier getCompositeTypeSpecifier(IASTName selectedName) {
174 IASTNode node = selectedName;
175 while(node != null && !(node instanceof IASTCompositeTypeSpecifier)) {
176 node = node.getParent();
178 return (IASTCompositeTypeSpecifier) node;
181 private IASTName getSelectedName(IASTTranslationUnit ast) {
182 List<IASTName> names = findAllMarkedNames(ast);
183 if (names.size() < 1) {
186 return names.get(names.size() - 1);
189 protected void findDeclarations(IASTCompositeTypeSpecifier compositeTypeSpecifier) {
190 compositeTypeSpecifier.accept(new ASTVisitor() {
192 shouldVisitDeclarations = true;
196 public int visit(IASTDeclaration declaration) {
197 if (declaration instanceof IASTSimpleDeclaration) {
198 IASTSimpleDeclaration fieldDeclaration = (IASTSimpleDeclaration) declaration;
199 ASTNodeProperty props = fieldDeclaration.getPropertyInParent();
200 if (props.getName().contains(MEMBER_DECLARATION)) {
201 final IASTDeclarator[] declarators = fieldDeclaration.getDeclarators();
202 if (declarators.length > 0) {
203 IASTDeclarator innermostDeclarator = declarators[0];
204 while (innermostDeclarator.getNestedDeclarator() != null) {
205 innermostDeclarator = innermostDeclarator.getNestedDeclarator();
207 if ((innermostDeclarator instanceof IASTFunctionDeclarator)) {
208 context.existingFunctionDeclarations.add(fieldDeclaration);
209 } else if (fieldDeclaration.isPartOfTranslationUnitFile()) {
210 context.existingFields.add(fieldDeclaration);
215 if (declaration instanceof IASTFunctionDefinition) {
216 IASTFunctionDefinition functionDefinition = (IASTFunctionDefinition) declaration;
217 ASTNodeProperty props = functionDefinition.getPropertyInParent();
218 if (props.getName().contains(MEMBER_DECLARATION)) {
219 context.existingFunctionDefinitions.add(functionDefinition);
222 return super.visit(declaration);
228 protected void collectModifications(IProgressMonitor pm,ModificationCollector collector)
229 throws CoreException, OperationCanceledException {
230 List<IASTNode> getterAndSetters = new ArrayList<IASTNode>();
231 List<IASTFunctionDefinition> definitions = new ArrayList<IASTFunctionDefinition>();
232 for (GetterSetterInsertEditProvider currentProvider : context.selectedFunctions) {
233 if (context.isImplementationInHeader()) {
234 getterAndSetters.add(currentProvider.getFunctionDefinition(false));
236 getterAndSetters.add(currentProvider.getFunctionDeclaration());
237 definitions.add(currentProvider.getFunctionDefinition(true));
240 if (!context.isImplementationInHeader()) {
241 addDefinition(collector, definitions, pm);
243 ICPPASTCompositeTypeSpecifier classDefinition =
244 (ICPPASTCompositeTypeSpecifier) context.existingFields.get(context.existingFields.size() - 1).getParent();
246 AddDeclarationNodeToClassChange.createChange(classDefinition, VisibilityEnum.v_public,
247 getterAndSetters, false, collector);
250 private void addDefinition(ModificationCollector collector, List<IASTFunctionDefinition> definitions, IProgressMonitor pm)
251 throws CoreException {
252 findDefinitionInsertLocation(pm);
253 IASTNode parent = definitionInsertLocation.getParentOfNodeToInsertBefore();
254 IASTTranslationUnit ast = parent.getTranslationUnit();
255 ASTRewrite rewrite = collector.rewriterForTranslationUnit(ast);
256 IASTNode nodeToInsertBefore = definitionInsertLocation.getNodeToInsertBefore();
257 ContainerNode cont = new ContainerNode();
258 for (IASTFunctionDefinition functionDefinition : definitions) {
259 cont.addNode(functionDefinition);
261 rewrite = rewrite.insertBefore(parent, nodeToInsertBefore, cont, null);
264 public GetterSetterContext getContext() {
268 private void findDefinitionInsertLocation(IProgressMonitor pm) throws CoreException {
269 if (definitionInsertLocation != null) {
273 IASTSimpleDeclaration decl = context.existingFields.get(0);
274 MethodDefinitionInsertLocationFinder methodDefinitionInsertLocationFinder = new MethodDefinitionInsertLocationFinder();
275 InsertLocation location = methodDefinitionInsertLocationFinder.find(
276 tu, decl.getFileLocation(), decl.getParent(), astCache, pm);
278 if (location.getFile() == null || NodeHelper.isContainedInTemplateDeclaration(decl)) {
279 location.setNodeToInsertAfter(NodeHelper.findTopLevelParent(decl), tu);
282 definitionInsertLocation = location;
286 protected RefactoringDescriptor getRefactoringDescriptor() {
287 // TODO egraf add Descriptor