KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > dom > OldASTRewrite


1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.corext.dom;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20
21 import org.eclipse.text.edits.TextEdit;
22 import org.eclipse.text.edits.TextEditGroup;
23
24 import org.eclipse.jface.text.IDocument;
25
26 import org.eclipse.jdt.core.dom.ASTNode;
27 import org.eclipse.jdt.core.dom.Block;
28 import org.eclipse.jdt.core.dom.FieldDeclaration;
29 import org.eclipse.jdt.core.dom.Statement;
30 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
31 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
32
33 import org.eclipse.jdt.internal.core.dom.rewrite.ListRewriteEvent;
34 import org.eclipse.jdt.internal.core.dom.rewrite.NodeRewriteEvent;
35 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEvent;
36 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore;
37 import org.eclipse.jdt.internal.corext.Assert;
38 import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
39
40 import org.eclipse.jdt.internal.ui.JavaPlugin;
41
42 /**
43  * Original version of the ASTRewrite: Mix of modifying an decribing API.
44  * Will be removed soon, please adapt to ASTRewrite.
45  */

46 public final class OldASTRewrite extends ASTRewrite { // illegal subclassing
47

48     private HashMap JavaDoc fChangedProperties;
49
50     private boolean fHasASTModifications;
51     private ASTNode fRootNode;
52     
53     /**
54      * Creates the <code>OldASTRewrite</code> object.
55      * @param node A node which is parent to all modified, changed or tracked nodes.
56      */

57     public OldASTRewrite(ASTNode node) {
58         super(node.getAST());
59         fRootNode= node;
60         fChangedProperties= new HashMap JavaDoc();
61
62         fHasASTModifications= false;
63         
64         // override the parent to child mapper to correct back modified modes from inserts
65
getRewriteEventStore().setNodePropertyMapper(new RewriteEventStore.INodePropertyMapper() {
66             public Object JavaDoc getOriginalValue(ASTNode parent, StructuralPropertyDescriptor childProperty) {
67                 Object JavaDoc originalValue= parent.getStructuralProperty(childProperty);
68                 if (parent.getStartPosition() == -1) {
69                     return originalValue; // ignore unnecessary inserts
70
}
71                 if (originalValue instanceof List JavaDoc) {
72                     List JavaDoc originalList= (List JavaDoc) originalValue;
73                     ArrayList JavaDoc fixedList= new ArrayList JavaDoc(originalList.size());
74                     for (int i= 0; i < originalList.size(); i++) {
75                         ASTNode curr= (ASTNode) originalList.get(i);
76                         if (!isInserted(curr)) {
77                             fixedList.add(curr);
78                         }
79                     }
80                     return fixedList;
81                 } else if (originalValue instanceof ASTNode) {
82                     if (isInserted((ASTNode) originalValue)) {
83                         return null;
84                     }
85                 }
86                 return originalValue;
87             }
88         });
89     }
90         
91     /**
92      * Perform rewriting: Analyses AST modifications and creates text edits that describe changes to the
93      * underlying code. Edits do only change code when the corresponding node has changed. New code
94      * is formatted using the standard code formatter.
95      * @param textBuffer Text buffer which is describing the code of the AST passed in in the
96      * constructor. This buffer is accessed read-only.
97      * @param rootEdit
98      */

99     public final void rewriteNode(TextBuffer textBuffer, TextEdit rootEdit) {
100         try {
101             TextEdit res= rewriteAST(textBuffer.getDocument(), null);
102             rootEdit.addChildren(res.removeChildren());
103         } catch (IllegalArgumentException JavaDoc e) {
104             JavaPlugin.log(e);
105         }
106     }
107     
108     /**
109      * New API.
110      */

111     public TextEdit rewriteAST(IDocument document, Map JavaDoc options) {
112         convertOldToNewEvents();
113         return super.rewriteAST(document, options);
114     }
115     
116     /**
117      * Returns the root node of the rewrite. All modifications or move/copy sources lie
118      * inside the root.
119      * @return Returns the root node or <code>null</code> if no node has been
120      * changed.
121      */

122     public ASTNode getRootNode() {
123         return fRootNode;
124     }
125     
126     /**
127      * Convert the old to the new events. Can only be done when rewrite is started
128      * (inserted node must not yet be added to the AST when marked)
129      */

130     private void convertOldToNewEvents() {
131         Set JavaDoc processedListEvents= new HashSet JavaDoc();
132         
133         for (Iterator JavaDoc iter= fChangedProperties.keySet().iterator(); iter.hasNext(); ) {
134             ASTNode node= (ASTNode) iter.next();
135             ASTInsert object= getChangeProperty(node);
136             if (object != null) {
137                 if (node.getParent().getStartPosition() != -1) { // ignore unnecessary inserts
138
processChange(node, null, node, object.description, processedListEvents);
139                     if (object.isBoundToPrevious) {
140                         getRewriteEventStore().setInsertBoundToPrevious(node);
141                     }
142                 }
143             }
144         }
145     }
146     
147     private void processChange(ASTNode nodeInAST, ASTNode originalNode, ASTNode newNode, TextEditGroup desc, Set JavaDoc processedListEvents) {
148         ASTNode parent= nodeInAST.getParent();
149         StructuralPropertyDescriptor childProperty= nodeInAST.getLocationInParent();
150         if (childProperty.isChildListProperty()) {
151             ListRewriteEvent event= getRewriteEventStore().getListEvent(parent, childProperty, true); // create
152
if (processedListEvents.add(event)) {
153                 convertListChange(event, (List JavaDoc) parent.getStructuralProperty(childProperty));
154             }
155         } else {
156             NodeRewriteEvent event= getRewriteEventStore().getNodeEvent(parent, childProperty, true);
157             event.setNewValue(newNode);
158             getRewriteEventStore().setEventEditGroup(event, desc);
159         }
160     }
161     
162     
163     private void convertListChange(ListRewriteEvent listEvent, List JavaDoc modifiedList) {
164         for (int i= 0; i < modifiedList.size(); i++) {
165             ASTNode curr= (ASTNode) modifiedList.get(i);
166             ASTInsert object= getChangeProperty(curr);
167             if (object != null) {
168                 RewriteEvent event= listEvent.insert(curr, i);
169                 getRewriteEventStore().setEventEditGroup(event, object.description);
170                 if (object.isBoundToPrevious) {
171                     getRewriteEventStore().setInsertBoundToPrevious(curr);
172                 }
173             }
174         }
175     }
176     
177     private boolean isInsertBoundToPreviousByDefault(ASTNode node) {
178         return (node instanceof Statement || node instanceof FieldDeclaration);
179     }
180     
181     /**
182      * Removes all modifications applied to the given AST.
183      */

184     public final void removeModifications() {
185         if (fHasASTModifications) {
186             getRootNode().accept(new ASTRewriteClear(this));
187             fHasASTModifications= false;
188         }
189         fChangedProperties.clear();
190
191         clearRewrite();
192     }
193     
194     public boolean hasASTModifications() {
195         return fHasASTModifications;
196     }
197     
198     /**
199      * Clears all events and other internal structures.
200      */

201     protected final void clearRewrite() {
202         getRewriteEventStore().clear();
203         getNodeStore().clear();
204     }
205     
206     public final boolean isCollapsed(ASTNode node) {
207         return getNodeStore().isCollapsed(node);
208     }
209     
210             
211     /**
212      * Marks a node as inserted. The node must not exist. To insert an existing node (move or copy),
213      * create a copy target first and insert this target node. ({@link #createCopyTarget(ASTNode)})
214      * @param node The node to be marked as inserted.
215      * @param description Description of the change.
216      */

217     public final void markAsInserted(ASTNode node, TextEditGroup description) {
218         Assert.isTrue(!isCollapsed(node), "Tries to insert a collapsed node"); //$NON-NLS-1$
219
ASTInsert insert= new ASTInsert();
220         insert.isBoundToPrevious= isInsertBoundToPreviousByDefault(node);
221         insert.description= description;
222         setChangeProperty(node, insert);
223         fHasASTModifications= true;
224         node.setSourceRange(-1, 0); // avoid troubles later when annotating extra node ranges.
225
}
226
227     /**
228      * Marks a node as inserted. The node must not exist. To insert an existing node (move or copy),
229      * create a copy target first and insert this target node. ({@link #createCopyTarget(ASTNode)})
230      * @param node The node to be marked as inserted.
231      */

232     public final void markAsInserted(ASTNode node) {
233         markAsInserted(node, (TextEditGroup) null);
234     }
235     
236     
237     /**
238      * Create a placeholder for a sequence of new statements to be inserted or placed at a single place.
239      * @param children The target nodes to collapse
240      * @return A placeholder node that stands for all of the statements
241      */

242     public final Block getCollapseTargetPlaceholder(Statement[] children) {
243         Block res= getNodeStore().createCollapsePlaceholder();
244         List JavaDoc statements= res.statements();
245         for (int i= 0; i < children.length; i++) {
246             statements.add(children[i]);
247         }
248         return res;
249     }
250     
251     /**
252      * Track a node, old API
253      * @param node
254      * @param editGroup
255      */

256     public final void markAsTracked(ASTNode node, TextEditGroup editGroup) {
257         if (getRewriteEventStore().getTrackedNodeData(node) != null) {
258             throw new IllegalArgumentException JavaDoc("Node is already marked as tracked"); //$NON-NLS-1$
259
}
260         
261         getRewriteEventStore().setTrackedNodeData(node, editGroup);
262     }
263         
264     /**
265      * Succeeding nodes in a list are collapsed and represented by a new 'compound' node. The new compound node is inserted in the list
266      * and replaces the collapsed node. The compound node can be used for rewriting, e.g. a copy can be created to move
267      * a whole range of statements. This operation modifies the AST.
268      * @param list
269      * @param index
270      * @param length
271      * @return
272      */

273     public final ASTNode collapseNodes(List JavaDoc list, int index, int length) {
274         Assert.isTrue(index >= 0 && length > 0 && list.size() >= (index + length), "Index or length out of bound"); //$NON-NLS-1$
275

276         ASTNode firstNode= (ASTNode) list.get(index);
277         ASTNode lastNode= (ASTNode) list.get(index + length - 1);
278         validateIsInsideAST(firstNode);
279         validateIsInsideAST(lastNode);
280         
281         Assert.isTrue(lastNode instanceof Statement, "Can only collapse statements"); //$NON-NLS-1$
282

283         int startPos= firstNode.getStartPosition();
284         int endPos= lastNode.getStartPosition() + lastNode.getLength();
285                 
286         Block compoundNode= getNodeStore().createCollapsePlaceholder();
287         List JavaDoc children= compoundNode.statements();
288         compoundNode.setSourceRange(startPos, endPos - startPos);
289         
290         StructuralPropertyDescriptor childProperty= firstNode.getLocationInParent();
291         
292         ListRewriteEvent existingEvent= getRewriteEventStore().getListEvent(firstNode.getParent(), childProperty, false);
293         if (existingEvent != null) {
294             RewriteEvent[] origChildren= existingEvent.getChildren();
295             Assert.isTrue(origChildren.length == list.size());
296             RewriteEvent[] newChildren= new RewriteEvent[origChildren.length - length + 1];
297             System.arraycopy(origChildren, 0, newChildren, 0, index);
298             newChildren[index]= new NodeRewriteEvent(compoundNode, compoundNode);
299             System.arraycopy(origChildren, index + length, newChildren, index + 1, origChildren.length - index - length);
300             getRewriteEventStore().addEvent(firstNode.getParent(), childProperty, new ListRewriteEvent(newChildren)); // replace
301

302             RewriteEvent[] newCollapsedChildren= new RewriteEvent[length];
303             System.arraycopy(origChildren, index, newCollapsedChildren, 0, length);
304             getRewriteEventStore().addEvent(compoundNode, Block.STATEMENTS_PROPERTY, new ListRewriteEvent(newCollapsedChildren));
305         }
306         
307         for (int i= 0; i < length; i++) {
308             Object JavaDoc curr= list.remove(index);
309             children.add(curr);
310         }
311         list.add(index, compoundNode);
312         
313         fHasASTModifications= true;
314         
315         return compoundNode;
316     }
317     
318     private final void validateIsInsideAST(ASTNode node) {
319         if (node.getStartPosition() == -1) {
320             throw new IllegalArgumentException JavaDoc("Node is not an existing node"); //$NON-NLS-1$
321
}
322     
323         if (node.getAST() != getAST()) {
324             throw new IllegalArgumentException JavaDoc("Node is not inside the AST"); //$NON-NLS-1$
325
}
326     }
327         
328     public final boolean isInserted(ASTNode node) {
329         return getChangeProperty(node) != null;
330     }
331     
332     
333     public boolean isRemoved(ASTNode node) {
334         return getRewriteEventStore().getChangeKind(node) == RewriteEvent.REMOVED;
335     }
336     
337     public boolean isReplaced(ASTNode node) {
338         return getRewriteEventStore().getChangeKind(node) == RewriteEvent.REPLACED;
339     }
340         
341     
342     public final ASTNode getReplacingNode(ASTNode node) {
343         RewriteEvent event= getRewriteEventStore().findEvent(node, RewriteEventStore.ORIGINAL);
344         if (event != null && event.getChangeKind() == RewriteEvent.REPLACED) {
345             return (ASTNode) event.getNewValue();
346         }
347         return null;
348     }
349                         
350     private final void setChangeProperty(ASTNode node, ASTInsert change) {
351         fChangedProperties.put(node, change);
352     }
353     
354     private final ASTInsert getChangeProperty(ASTNode node) {
355         return (ASTInsert) fChangedProperties.get(node);
356     }
357         
358     private static class ASTInsert {
359         public TextEditGroup description;
360         public boolean isBoundToPrevious;
361     }
362
363 }
364
Popular Tags