upload tizen1.0 source
[sdk/ide/product.git] / org.eclipse.cdt.ui / src / org / eclipse / cdt / internal / ui / refactoring / gettersandsetters / GenerateGettersAndSettersRefactoring.java
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  
8  *  
9  * Contributors: 
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;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
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;
28
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;
46
47 import org.eclipse.cdt.internal.core.dom.rewrite.astwriter.ContainerNode;
48
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;
59
60 /**
61  * @author Thomas Corbat
62  */
63 public class GenerateGettersAndSettersRefactoring extends CRefactoring2 {
64
65         private final class CompositeTypeSpecFinder extends ASTVisitor {
66                 private final int start;
67                 private final Container<IASTCompositeTypeSpecifier> container;
68                 {
69                         shouldVisitDeclSpecifiers = true;
70                 }
71
72                 private CompositeTypeSpecFinder(int start, Container<IASTCompositeTypeSpecifier> container) {
73                         this.start = start;
74                         this.container = container;
75                 }
76
77                 @Override
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;
84                                 }
85                         }
86                         
87                         return super.visit(declSpec);
88                 }
89         }
90
91         private static final String MEMBER_DECLARATION = "MEMBER_DECLARATION"; //$NON-NLS-1$
92         private final GetterSetterContext context;
93         private InsertLocation definitionInsertLocation;        
94         
95         public GenerateGettersAndSettersRefactoring(ICElement element, ISelection selection,
96                         ICProject project, RefactoringASTCache astCache) {
97                 super(element, selection, project, astCache);
98                 context = new GetterSetterContext();
99         }
100         
101         @Override
102         public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
103                         throws CoreException, OperationCanceledException {
104                 SubMonitor sm = SubMonitor.convert(pm, 10);
105
106                 RefactoringStatus status = super.checkInitialConditions(sm.newChild(6));
107                 if (status.hasError()) {
108                         return status;
109                 }
110
111                 if (!initStatus.hasFatalError()) {
112                         initRefactoring(pm);            
113                         if (context.existingFields.isEmpty()) {
114                                 initStatus.addFatalError(Messages.GenerateGettersAndSettersRefactoring_NoFields);
115                         }
116                 }               
117                 return initStatus;
118         }
119
120         @Override
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);
128                         }
129                 }
130                 Checks.addModifiedFilesToChecker(getAllFilesToModify(), checkContext);
131                 return result;
132         }
133
134         private IFile[] getAllFilesToModify() {
135                 List<IFile> files = new ArrayList<IFile>(2);
136                 IFile file = (IFile) tu.getResource();
137                 if (file != null) {
138                         files.add(file);
139                 }
140                 if (definitionInsertLocation != null) {
141                         file = definitionInsertLocation.getFile();
142                         if (file != null) {
143                                 files.add(file);
144                         }
145                 }
146                 return files.toArray(new IFile[files.size()]);
147         }
148
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);
155                 } else {
156                         compositeTypeSpecifier = findCurrentCompositeTypeSpecifier(ast);
157                 }
158                 if (compositeTypeSpecifier != null) {
159                         findDeclarations(compositeTypeSpecifier);
160                 } else {
161                         initStatus.addFatalError(Messages.GenerateGettersAndSettersRefactoring_NoCassDefFound);
162                 }
163         }
164         
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();
171         }
172
173         private IASTCompositeTypeSpecifier getCompositeTypeSpecifier(IASTName selectedName) {
174                 IASTNode node = selectedName;
175                 while(node != null && !(node instanceof IASTCompositeTypeSpecifier)) {
176                         node = node.getParent();
177                 }
178                 return (IASTCompositeTypeSpecifier) node;
179         }
180
181         private IASTName getSelectedName(IASTTranslationUnit ast) {
182                 List<IASTName> names = findAllMarkedNames(ast);
183                 if (names.size() < 1) {
184                         return null;
185                 }
186                 return names.get(names.size() - 1);
187         }
188
189         protected void findDeclarations(IASTCompositeTypeSpecifier compositeTypeSpecifier) {
190                 compositeTypeSpecifier.accept(new ASTVisitor() {
191                         {
192                                 shouldVisitDeclarations = true;
193                         }
194
195                         @Override
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();
206                                                         }
207                                                         if ((innermostDeclarator instanceof IASTFunctionDeclarator)) {
208                                                                 context.existingFunctionDeclarations.add(fieldDeclaration);
209                                                         } else if (fieldDeclaration.isPartOfTranslationUnitFile()) {
210                                                                 context.existingFields.add(fieldDeclaration);
211                                                         }
212                                                 }
213                                         }
214                                 }
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);
220                                         }
221                                 }
222                                 return super.visit(declaration);
223                         }
224                 });
225         }
226
227         @Override
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));
235                         } else {
236                                 getterAndSetters.add(currentProvider.getFunctionDeclaration());
237                                 definitions.add(currentProvider.getFunctionDefinition(true));
238                         }
239                 }
240                 if (!context.isImplementationInHeader()) {
241                         addDefinition(collector, definitions, pm);
242                 }
243                 ICPPASTCompositeTypeSpecifier classDefinition =
244                                 (ICPPASTCompositeTypeSpecifier) context.existingFields.get(context.existingFields.size() - 1).getParent();
245
246                 AddDeclarationNodeToClassChange.createChange(classDefinition, VisibilityEnum.v_public,
247                                 getterAndSetters, false, collector);
248         }
249
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);
260                 }
261                 rewrite = rewrite.insertBefore(parent, nodeToInsertBefore, cont, null);
262         }
263
264         public GetterSetterContext getContext() {
265                 return context;
266         }
267         
268         private void findDefinitionInsertLocation(IProgressMonitor pm) throws CoreException {
269                 if (definitionInsertLocation != null) {
270                         return;
271                 }
272                 
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);
277
278                 if (location.getFile() == null || NodeHelper.isContainedInTemplateDeclaration(decl)) {
279                         location.setNodeToInsertAfter(NodeHelper.findTopLevelParent(decl), tu);
280                 }
281                 
282                 definitionInsertLocation = location;
283         }
284
285         @Override
286         protected RefactoringDescriptor getRefactoringDescriptor() {
287                 // TODO egraf add Descriptor
288                 return null;
289         }       
290 }