KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > dom > rewrite > RewriteEventStore


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

11 package org.eclipse.jdt.internal.core.dom.rewrite;
12
13 import java.util.*;
14
15 import org.eclipse.jdt.core.Signature;
16 import org.eclipse.jdt.core.dom.*;
17 import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
18 import org.eclipse.text.edits.TextEditGroup;
19
20
21 /**
22  * Stores all rewrite events, descriptions of events and knows which nodes
23  * are copy or move sources or tracked.
24  */

25 public final class RewriteEventStore {
26     
27
28     public static final class PropertyLocation {
29         private final ASTNode parent;
30         private final StructuralPropertyDescriptor property;
31         
32         public PropertyLocation(ASTNode parent, StructuralPropertyDescriptor property) {
33             this.parent= parent;
34             this.property= property;
35         }
36
37         public ASTNode getParent() {
38             return this.parent;
39         }
40
41         public StructuralPropertyDescriptor getProperty() {
42             return this.property;
43         }
44         
45         public boolean equals(Object JavaDoc obj) {
46             if (obj != null && obj.getClass().equals(this.getClass())) {
47                 PropertyLocation other= (PropertyLocation) obj;
48                 return other.getParent().equals(getParent()) && other.getProperty().equals(getProperty());
49             }
50             return false;
51         }
52         
53         public int hashCode() {
54             return getParent().hashCode() + getProperty().hashCode();
55         }
56         
57     }
58     
59     /**
60      * Interface that allows to override the way how children are accessed from
61      * a parent. Use this interface when the rewriter is set up on an already
62      * modified AST's (as it is the case in the old ASTRewrite infrastructure)
63      */

64     public static interface INodePropertyMapper {
65         /**
66          * Returns the node attribute for a given property name.
67          * @param parent The parent node
68          * @param childProperty The child property to access
69          * @return The child node at the given property location.
70          */

71         Object JavaDoc getOriginalValue(ASTNode parent, StructuralPropertyDescriptor childProperty);
72     }
73     
74     /*
75      * Store element to associate event and node position/
76      */

77     private static class EventHolder {
78         public final ASTNode parent;
79         public final StructuralPropertyDescriptor childProperty;
80         public final RewriteEvent event;
81         
82         public EventHolder(ASTNode parent, StructuralPropertyDescriptor childProperty, RewriteEvent change) {
83             this.parent= parent;
84             this.childProperty= childProperty;
85             this.event= change;
86         }
87         
88         public String JavaDoc toString() {
89             StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
90             buf.append(this.parent).append(" - "); //$NON-NLS-1$
91
buf.append(this.childProperty.getId()).append(": "); //$NON-NLS-1$
92
buf.append(this.event).append('\n');
93             return buf.toString();
94         }
95     }
96     
97     public static class CopySourceInfo implements Comparable JavaDoc {
98         public final PropertyLocation location; // can be null, only used to mark as removed on move
99
private final ASTNode node;
100         public final boolean isMove;
101         
102         public CopySourceInfo(PropertyLocation location, ASTNode node, boolean isMove) {
103             this.location= location;
104             this.node= node;
105             this.isMove= isMove;
106         }
107         
108         public ASTNode getNode() {
109             return this.node;
110         }
111         
112         public int compareTo(Object JavaDoc o2) {
113             CopySourceInfo r2= (CopySourceInfo) o2;
114         
115             int startDiff= this.getNode().getStartPosition() - r2.getNode().getStartPosition();
116             if (startDiff != 0) {
117                 return startDiff; // insert before if start node is first
118
}
119
120             if (r2.isMove != this.isMove) {
121                 return this.isMove ? -1 : 1; // first move then copy
122
}
123             return 0;
124         }
125         
126         public String JavaDoc toString() {
127             StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
128             if (this.isMove) {
129                 buf.append("move source: "); //$NON-NLS-1$
130
} else {
131                 buf.append("copy source: "); //$NON-NLS-1$
132
}
133             buf.append(this.node);
134             return buf.toString();
135         }
136     }
137     
138     private static class NodeRangeInfo implements Comparable JavaDoc {
139         private final ASTNode first;
140         private final ASTNode last;
141         public final CopySourceInfo copyInfo; // containing the internal placeholder and the 'isMove' flag
142
public final ASTNode replacingNode;
143         public final TextEditGroup editGroup;
144         
145         public NodeRangeInfo(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, CopySourceInfo copyInfo, ASTNode replacingNode, TextEditGroup editGroup) {
146             this.first= first;
147             this.last= last;
148             this.copyInfo= copyInfo;
149             this.replacingNode= replacingNode;
150             this.editGroup= editGroup;
151         }
152         
153         public ASTNode getStartNode() {
154             return this.first;
155         }
156         
157         public ASTNode getEndNode() {
158             return this.last;
159         }
160         
161         public boolean isMove() {
162             return this.copyInfo.isMove;
163         }
164         
165         public Block getInternalPlaceholder() {
166             return (Block) this.copyInfo.getNode();
167         }
168                 
169         public int compareTo(Object JavaDoc o2) {
170             NodeRangeInfo r2= (NodeRangeInfo) o2;
171         
172             int startDiff= this.getStartNode().getStartPosition() - r2.getStartNode().getStartPosition();
173             if (startDiff != 0) {
174                 return startDiff; // insert before if start node is first
175
}
176             int endDiff= this.getEndNode().getStartPosition() - r2.getEndNode().getStartPosition();
177             if (endDiff != 0) {
178                 return -endDiff; // insert before if length is longer
179
}
180             if (r2.isMove() != this.isMove()) {
181                 return this.isMove() ? -1 : 1; // first move then copy
182
}
183             return 0;
184         }
185         
186         public void updatePlaceholderSourceRanges(TargetSourceRangeComputer sourceRangeComputer) {
187             TargetSourceRangeComputer.SourceRange startRange= sourceRangeComputer.computeSourceRange(getStartNode());
188             TargetSourceRangeComputer.SourceRange endRange= sourceRangeComputer.computeSourceRange(getEndNode());
189             int startPos= startRange.getStartPosition();
190             int endPos= endRange.getStartPosition() + endRange.getLength();
191             
192             Block internalPlaceholder= getInternalPlaceholder();
193             internalPlaceholder.setSourceRange(startPos, endPos - startPos);
194         }
195         
196         public String JavaDoc toString() {
197             StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
198             if (this.first != this.last) {
199                 buf.append("range "); //$NON-NLS-1$
200
}
201             if (isMove()) {
202                 buf.append("move source: "); //$NON-NLS-1$
203
} else {
204                 buf.append("copy source: "); //$NON-NLS-1$
205
}
206             buf.append(this.first);
207             buf.append(" - "); //$NON-NLS-1$
208
buf.append(this.last);
209             return buf.toString();
210         }
211
212
213     }
214     
215     /**
216      * Iterates over all event parent nodes, tracked nodes and all copy/move sources
217      */

218     private class ParentIterator implements Iterator {
219         
220         private Iterator eventIter;
221         private Iterator sourceNodeIter;
222         private Iterator rangeNodeIter;
223         private Iterator trackedNodeIter;
224         
225         public ParentIterator() {
226             this.eventIter= RewriteEventStore.this.events.iterator();
227             if (RewriteEventStore.this.nodeCopySources != null) {
228                 this.sourceNodeIter= RewriteEventStore.this.nodeCopySources.iterator();
229             } else {
230                 this.sourceNodeIter= Collections.EMPTY_LIST.iterator();
231             }
232             if (RewriteEventStore.this.nodeRangeInfos != null) {
233                 this.rangeNodeIter= RewriteEventStore.this.nodeRangeInfos.keySet().iterator();
234             } else {
235                 this.rangeNodeIter= Collections.EMPTY_LIST.iterator();
236             }
237             if (RewriteEventStore.this.trackedNodes != null) {
238                 this.trackedNodeIter= RewriteEventStore.this.trackedNodes.keySet().iterator();
239             } else {
240                 this.trackedNodeIter= Collections.EMPTY_LIST.iterator();
241             }
242         }
243
244         /* (non-Javadoc)
245          * @see java.util.Iterator#hasNext()
246          */

247         public boolean hasNext() {
248             return this.eventIter.hasNext() || this.sourceNodeIter.hasNext() || this.rangeNodeIter.hasNext() || this.trackedNodeIter.hasNext();
249         }
250
251         /* (non-Javadoc)
252          * @see java.util.Iterator#next()
253          */

254         public Object JavaDoc next() {
255             if (this.eventIter.hasNext()) {
256                 return ((EventHolder) this.eventIter.next()).parent;
257             }
258             if (this.sourceNodeIter.hasNext()) {
259                 return ((CopySourceInfo) this.sourceNodeIter.next()).getNode();
260             }
261             if (this.rangeNodeIter.hasNext()) {
262                 return ((PropertyLocation) this.rangeNodeIter.next()).getParent();
263             }
264             return this.trackedNodeIter.next();
265         }
266
267         /* (non-Javadoc)
268          * @see java.util.Iterator#remove()
269          */

270         public void remove() {
271             throw new UnsupportedOperationException JavaDoc();
272         }
273     }
274     
275     public final static int NEW= 1;
276     public final static int ORIGINAL= 2;
277     public final static int BOTH= NEW | ORIGINAL;
278         
279     
280     /** all events */
281     final List events;
282     
283     /** cache for last accessed event */
284     private EventHolder lastEvent;
285     
286     /** Maps events to group descriptions */
287     private Map editGroups;
288         
289     /** Stores which nodes are source of a copy or move (list of CopySourceInfo)*/
290     List nodeCopySources;
291     
292     /** Stores node ranges that are used to copy or move (map of <PropertyLocation, CopyRangeInfo>)*/
293     Map nodeRangeInfos;
294     
295     /** Stores which nodes are tracked and the corresponding edit group*/
296     Map trackedNodes;
297     
298     /** Stores which inserted nodes bound to the previous node. If not, a node is
299      * always bound to the next node */

300     private Set insertBoundToPrevious;
301     
302     /** optional mapper to allow fix already modified AST trees */
303     private INodePropertyMapper nodePropertyMapper;
304     
305     private static final String JavaDoc INTERNAL_PLACEHOLDER_PROPERTY= "rewrite_internal_placeholder"; //$NON-NLS-1$
306

307     public RewriteEventStore() {
308         this.events= new ArrayList();
309         this.lastEvent= null;
310         
311         this.editGroups= null; // lazy initialization
312

313         this.trackedNodes= null;
314         this.insertBoundToPrevious= null;
315         
316         this.nodePropertyMapper= null;
317         this.nodeCopySources= null;
318         this.nodeRangeInfos= null;
319     }
320     
321     /**
322      * Override the default way how to access children from a parent node.
323      * @param nodePropertyMapper The new <code>INodePropertyMapper</code> or
324      * <code>null</code>. to use the default.
325      */

326     public void setNodePropertyMapper(INodePropertyMapper nodePropertyMapper) {
327         this.nodePropertyMapper= nodePropertyMapper;
328     }
329     
330     public void clear() {
331         this.events.clear();
332         this.lastEvent= null;
333         this.trackedNodes= null;
334         
335         this.editGroups= null; // lazy initialization
336
this.insertBoundToPrevious= null;
337         this.nodeCopySources= null;
338     }
339     
340     public void addEvent(ASTNode parent, StructuralPropertyDescriptor childProperty, RewriteEvent event) {
341         validateHasChildProperty(parent, childProperty);
342         
343         if (event.isListRewrite()) {
344             validateIsListProperty(childProperty);
345         }
346         
347         EventHolder holder= new EventHolder(parent, childProperty, event);
348         
349         // check if already in list
350
for (int i= 0; i < this.events.size(); i++) {
351             EventHolder curr= (EventHolder) this.events.get(i);
352             if (curr.parent == parent && curr.childProperty == childProperty) {
353                 this.events.set(i, holder);
354                 this.lastEvent= null;
355                 return;
356             }
357         }
358         this.events.add(holder);
359     }
360     
361     public RewriteEvent getEvent(ASTNode parent, StructuralPropertyDescriptor property) {
362         validateHasChildProperty(parent, property);
363         
364         if (this.lastEvent != null && this.lastEvent.parent == parent && this.lastEvent.childProperty == property) {
365             return this.lastEvent.event;
366         }
367         
368         for (int i= 0; i < this.events.size(); i++) {
369             EventHolder holder= (EventHolder) this.events.get(i);
370             if (holder.parent == parent && holder.childProperty == property) {
371                 this.lastEvent= holder;
372                 return holder.event;
373             }
374         }
375         return null;
376     }
377     
378     public NodeRewriteEvent getNodeEvent(ASTNode parent, StructuralPropertyDescriptor childProperty, boolean forceCreation) {
379         validateIsNodeProperty(childProperty);
380         NodeRewriteEvent event= (NodeRewriteEvent) getEvent(parent, childProperty);
381         if (event == null && forceCreation) {
382             Object JavaDoc originalValue= accessOriginalValue(parent, childProperty);
383             event= new NodeRewriteEvent(originalValue, originalValue);
384             addEvent(parent, childProperty, event);
385         }
386         return event;
387     }
388     
389     public ListRewriteEvent getListEvent(ASTNode parent, StructuralPropertyDescriptor childProperty, boolean forceCreation) {
390         validateIsListProperty(childProperty);
391         ListRewriteEvent event= (ListRewriteEvent) getEvent(parent, childProperty);
392         if (event == null && forceCreation) {
393             List originalValue= (List) accessOriginalValue(parent, childProperty);
394             event= new ListRewriteEvent(originalValue);
395             addEvent(parent, childProperty, event);
396         }
397         return event;
398     }
399     
400     public Iterator getChangeRootIterator() {
401         return new ParentIterator();
402     }
403     
404     
405     public boolean hasChangedProperties(ASTNode parent) {
406         for (int i= 0; i < this.events.size(); i++) {
407             EventHolder holder= (EventHolder) this.events.get(i);
408             if (holder.parent == parent) {
409                 if (holder.event.getChangeKind() != RewriteEvent.UNCHANGED) {
410                     return true;
411                 }
412             }
413         }
414         return false;
415     }
416     
417     public PropertyLocation getPropertyLocation(Object JavaDoc value, int kind) {
418         for (int i= 0; i < this.events.size(); i++) {
419             EventHolder holder= (EventHolder) this.events.get(i);
420             RewriteEvent event= holder.event;
421             if (isNodeInEvent(event, value, kind)) {
422                 return new PropertyLocation(holder.parent, holder.childProperty);
423             }
424             if (event.isListRewrite()) {
425                 RewriteEvent[] children= event.getChildren();
426                 for (int k= 0; k < children.length; k++) {
427                     if (isNodeInEvent(children[k], value, kind)) {
428                         return new PropertyLocation(holder.parent, holder.childProperty);
429                     }
430                 }
431             }
432         }
433         if (value instanceof ASTNode) {
434             ASTNode node= (ASTNode) value;
435             return new PropertyLocation(node.getParent(), node.getLocationInParent());
436         }
437         return null;
438     }
439     
440     
441     /**
442      * Kind is either ORIGINAL, NEW, or BOTH
443      * @param value
444      * @param kind
445      * @return Returns the event with the given value of <code>null</code>.
446      */

447     public RewriteEvent findEvent(Object JavaDoc value, int kind) {
448         for (int i= 0; i < this.events.size(); i++) {
449             RewriteEvent event= ((EventHolder) this.events.get(i)).event;
450             if (isNodeInEvent(event, value, kind)) {
451                 return event;
452             }
453             if (event.isListRewrite()) {
454                 RewriteEvent[] children= event.getChildren();
455                 for (int k= 0; k < children.length; k++) {
456                     if (isNodeInEvent(children[k], value, kind)) {
457                         return children[k];
458                     }
459                 }
460             }
461         }
462         return null;
463     }
464     
465     private boolean isNodeInEvent(RewriteEvent event, Object JavaDoc value, int kind) {
466         if (((kind & NEW) != 0) && event.getNewValue() == value) {
467             return true;
468         }
469         if (((kind & ORIGINAL) != 0) && event.getOriginalValue() == value) {
470             return true;
471         }
472         return false;
473     }
474     
475     
476     public Object JavaDoc getOriginalValue(ASTNode parent, StructuralPropertyDescriptor property) {
477         RewriteEvent event= getEvent(parent, property);
478         if (event != null) {
479             return event.getOriginalValue();
480         }
481         return accessOriginalValue(parent, property);
482     }
483     
484     public Object JavaDoc getNewValue(ASTNode parent, StructuralPropertyDescriptor property) {
485         RewriteEvent event= getEvent(parent, property);
486         if (event != null) {
487             return event.getNewValue();
488         }
489         return accessOriginalValue(parent, property);
490     }
491     
492     public int getChangeKind(ASTNode node) {
493         RewriteEvent event= findEvent(node, ORIGINAL);
494         if (event != null) {
495             return event.getChangeKind();
496         }
497         return RewriteEvent.UNCHANGED;
498     }
499     
500     /*
501      * Gets an original child from the AST.
502      * Temporarily overridden to port the old rewriter to the new infrastructure.
503      */

504     private Object JavaDoc accessOriginalValue(ASTNode parent, StructuralPropertyDescriptor childProperty) {
505         if (this.nodePropertyMapper != null) {
506             return this.nodePropertyMapper.getOriginalValue(parent, childProperty);
507         }
508         
509         return parent.getStructuralProperty(childProperty);
510     }
511     
512     public TextEditGroup getEventEditGroup(RewriteEvent event) {
513         if (this.editGroups == null) {
514             return null;
515         }
516         return (TextEditGroup) this.editGroups.get(event);
517     }
518     
519     public void setEventEditGroup(RewriteEvent event, TextEditGroup editGroup) {
520         if (this.editGroups == null) {
521             this.editGroups= new IdentityHashMap(5);
522         }
523         this.editGroups.put(event, editGroup);
524     }
525     
526     
527     public final TextEditGroup getTrackedNodeData(ASTNode node) {
528         if (this.trackedNodes != null) {
529             return (TextEditGroup) this.trackedNodes.get(node);
530         }
531         return null;
532     }
533     
534     public void setTrackedNodeData(ASTNode node, TextEditGroup editGroup) {
535         if (this.trackedNodes == null) {
536             this.trackedNodes= new IdentityHashMap();
537         }
538         this.trackedNodes.put(node, editGroup);
539     }
540     
541     /**
542      * Marks a node as tracked. The edits added to the group editGroup can be used to get the
543      * position of the node after the rewrite operation.
544      * @param node The node to track
545      * @param editGroup Collects the range markers describing the node position.
546      */

547     public final void markAsTracked(ASTNode node, TextEditGroup editGroup) {
548         if (getTrackedNodeData(node) != null) {
549             throw new IllegalArgumentException JavaDoc("Node is already marked as tracked"); //$NON-NLS-1$
550
}
551         setTrackedNodeData(node, editGroup);
552     }
553     
554     private final CopySourceInfo createCopySourceInfo(PropertyLocation location, ASTNode node, boolean isMove) {
555         CopySourceInfo copySource= new CopySourceInfo(location, node, isMove);
556         
557         if (this.nodeCopySources == null) {
558             this.nodeCopySources= new ArrayList();
559         }
560         this.nodeCopySources.add(copySource);
561         return copySource;
562     }
563     
564     public final CopySourceInfo markAsCopySource(ASTNode parent, StructuralPropertyDescriptor property, ASTNode node, boolean isMove) {
565         return createCopySourceInfo(new PropertyLocation(parent, property), node, isMove);
566     }
567     
568     public final boolean isRangeCopyPlaceholder(ASTNode node) {
569         return node.getProperty(INTERNAL_PLACEHOLDER_PROPERTY) != null;
570     }
571     
572     public final CopySourceInfo createRangeCopy(ASTNode parent, StructuralPropertyDescriptor childProperty, ASTNode first, ASTNode last, boolean isMove, ASTNode internalPlaceholder, ASTNode replacingNode, TextEditGroup editGroup) {
573         CopySourceInfo copyInfo= createCopySourceInfo(null, internalPlaceholder, isMove);
574         internalPlaceholder.setProperty(INTERNAL_PLACEHOLDER_PROPERTY, internalPlaceholder);
575         
576         NodeRangeInfo copyRangeInfo= new NodeRangeInfo(parent, childProperty, first, last, copyInfo, replacingNode, editGroup);
577         
578         ListRewriteEvent listEvent= getListEvent(parent, childProperty, true);
579         
580         int indexFirst= listEvent.getIndex(first, ListRewriteEvent.OLD);
581         if (indexFirst == -1) {
582             throw new IllegalArgumentException JavaDoc("Start node is not a original child of the given list"); //$NON-NLS-1$
583
}
584         int indexLast= listEvent.getIndex(last, ListRewriteEvent.OLD);
585         if (indexLast == -1) {
586             throw new IllegalArgumentException JavaDoc("End node is not a original child of the given list"); //$NON-NLS-1$
587
}
588
589         if (indexFirst > indexLast) {
590             throw new IllegalArgumentException JavaDoc("Start node must be before end node"); //$NON-NLS-1$
591
}
592         
593         if (this.nodeRangeInfos == null) {
594             this.nodeRangeInfos= new HashMap();
595         }
596         PropertyLocation loc= new PropertyLocation(parent, childProperty);
597         List innerList= (List) this.nodeRangeInfos.get(loc);
598         if (innerList == null) {
599             innerList= new ArrayList(2);
600             this.nodeRangeInfos.put(loc, innerList);
601         } else {
602             assertNoOverlap(listEvent, indexFirst, indexLast, innerList);
603         }
604         innerList.add(copyRangeInfo);
605         
606         
607         return copyInfo;
608     }
609     
610     public CopySourceInfo[] getNodeCopySources(ASTNode node) {
611         if (this.nodeCopySources == null) {
612             return null;
613         }
614         return internalGetCopySources(this.nodeCopySources, node);
615     }
616     
617     
618     public CopySourceInfo[] internalGetCopySources(List copySources, ASTNode node) {
619         ArrayList res= new ArrayList(3);
620         for (int i= 0; i < copySources.size(); i++) {
621             CopySourceInfo curr= (CopySourceInfo) copySources.get(i);
622             if (curr.getNode() == node) {
623                 res.add(curr);
624             }
625         }
626         if (res.isEmpty()) {
627             return null;
628         }
629         
630         CopySourceInfo[] arr= (CopySourceInfo[]) res.toArray(new CopySourceInfo[res.size()]);
631         Arrays.sort(arr);
632         return arr;
633     }
634     
635     
636     private void assertNoOverlap(ListRewriteEvent listEvent, int indexFirst, int indexLast, List innerList) {
637         for (Iterator iter= innerList.iterator(); iter.hasNext();) {
638             NodeRangeInfo curr= (NodeRangeInfo) iter.next();
639             int currStart= listEvent.getIndex(curr.getStartNode(), ListRewriteEvent.BOTH);
640             int currEnd= listEvent.getIndex(curr.getEndNode(), ListRewriteEvent.BOTH);
641             if (currStart < indexFirst && currEnd < indexLast && currEnd >= indexFirst
642                     || currStart > indexFirst && currStart <= currEnd && currEnd > indexLast) {
643                 throw new IllegalArgumentException JavaDoc("Range overlapps with an existing copy or move range"); //$NON-NLS-1$
644
}
645         }
646     }
647     
648     public void prepareMovedNodes(TargetSourceRangeComputer sourceRangeComputer) {
649         if (this.nodeCopySources != null) {
650             prepareSingleNodeCopies();
651         }
652         
653         if (this.nodeRangeInfos != null) {
654             prepareNodeRangeCopies(sourceRangeComputer);
655         }
656     }
657     
658     public void revertMovedNodes() {
659         if (this.nodeRangeInfos != null) {
660             removeMoveRangePlaceholders();
661         }
662     }
663     
664     private void removeMoveRangePlaceholders() {
665         for (Iterator iter= this.nodeRangeInfos.entrySet().iterator(); iter.hasNext();) {
666             Map.Entry entry= (Map.Entry) iter.next();
667             Set placeholders= new HashSet(); // collect all placeholders
668
List rangeInfos= (List) entry.getValue(); // list of CopySourceRange
669
for (int i= 0; i < rangeInfos.size(); i++) {
670                 placeholders.add(((NodeRangeInfo) rangeInfos.get(i)).getInternalPlaceholder());
671             }
672             
673             PropertyLocation loc= (PropertyLocation) entry.getKey();
674             
675             RewriteEvent[] children= getListEvent(loc.getParent(), loc.getProperty(), true).getChildren();
676             List revertedChildren= new ArrayList();
677             revertListWithRanges(children, placeholders, revertedChildren);
678             RewriteEvent[] revertedChildrenArr= (RewriteEvent[]) revertedChildren.toArray(new RewriteEvent[revertedChildren.size()]);
679             addEvent(loc.getParent(), loc.getProperty(), new ListRewriteEvent(revertedChildrenArr)); // replace the current edits
680
}
681     }
682     
683     private void revertListWithRanges(RewriteEvent[] childEvents, Set placeholders, List revertedChildren) {
684         for (int i= 0; i < childEvents.length; i++) {
685             RewriteEvent event= childEvents[i];
686             ASTNode node= (ASTNode) event.getOriginalValue();
687             if (placeholders.contains(node)) {
688                 RewriteEvent[] placeholderChildren= getListEvent(node, Block.STATEMENTS_PROPERTY, false).getChildren();
689                 revertListWithRanges(placeholderChildren, placeholders, revertedChildren);
690             } else {
691                 revertedChildren.add(event);
692             }
693         }
694     }
695
696     private void prepareNodeRangeCopies(TargetSourceRangeComputer sourceRangeComputer) {
697         for (Iterator iter= this.nodeRangeInfos.entrySet().iterator(); iter.hasNext();) {
698             Map.Entry entry= (Map.Entry) iter.next();
699             List rangeInfos= (List) entry.getValue(); // list of CopySourceRange
700
Collections.sort(rangeInfos); // sort by start index, length, move or copy
701

702             PropertyLocation loc= (PropertyLocation) entry.getKey();
703             RewriteEvent[] children= getListEvent(loc.getParent(), loc.getProperty(), true).getChildren();
704             
705             RewriteEvent[] newChildren= processListWithRanges(rangeInfos, children, sourceRangeComputer);
706             addEvent(loc.getParent(), loc.getProperty(), new ListRewriteEvent(newChildren)); // replace the current edits
707
}
708     }
709
710     private RewriteEvent[] processListWithRanges(List rangeInfos, RewriteEvent[] childEvents, TargetSourceRangeComputer sourceRangeComputer) {
711         List newChildEvents= new ArrayList(childEvents.length);
712         NodeRangeInfo topInfo= null;
713         Stack newChildrenStack= new Stack();
714         Stack topInfoStack= new Stack();
715
716         Iterator rangeInfoIterator= rangeInfos.iterator();
717         NodeRangeInfo nextInfo= (NodeRangeInfo) rangeInfoIterator.next();
718         
719         for (int k= 0; k < childEvents.length; k++) {
720             RewriteEvent event= childEvents[k];
721             ASTNode node= (ASTNode) event.getOriginalValue();
722             // check for ranges and add a placeholder for them
723
while (nextInfo != null && node == nextInfo.getStartNode()) { // is this child the beginning of a range?
724
nextInfo.updatePlaceholderSourceRanges(sourceRangeComputer);
725                 
726                 Block internalPlaceholder= nextInfo.getInternalPlaceholder();
727                 RewriteEvent newEvent;
728                 if (nextInfo.isMove()) {
729                     newEvent= new NodeRewriteEvent(internalPlaceholder, nextInfo.replacingNode); // remove or replace
730
} else {
731                     newEvent= new NodeRewriteEvent(internalPlaceholder, internalPlaceholder); // unchanged
732
}
733                 newChildEvents.add(newEvent);
734                 if (nextInfo.editGroup != null) {
735                     setEventEditGroup(newEvent, nextInfo.editGroup);
736                 }
737                 
738                 newChildrenStack.push(newChildEvents);
739                 topInfoStack.push(topInfo);
740                 
741                 newChildEvents= new ArrayList(childEvents.length);
742                 topInfo= nextInfo;
743                 
744                 nextInfo= rangeInfoIterator.hasNext() ? (NodeRangeInfo) rangeInfoIterator.next() : null;
745             }
746             
747             newChildEvents.add(event);
748
749             while (topInfo != null && node == topInfo.getEndNode()) {
750                 RewriteEvent[] placeholderChildEvents= (RewriteEvent[]) newChildEvents.toArray(new RewriteEvent[newChildEvents.size()]);
751                 Block internalPlaceholder= topInfo.getInternalPlaceholder();
752                 addEvent(internalPlaceholder, Block.STATEMENTS_PROPERTY, new ListRewriteEvent(placeholderChildEvents));
753                 
754                 newChildEvents= (List) newChildrenStack.pop();
755                 topInfo= (NodeRangeInfo) topInfoStack.pop();
756             }
757         }
758         return (RewriteEvent[]) newChildEvents.toArray(new RewriteEvent[newChildEvents.size()]);
759     }
760
761     /**
762      * Make sure all moved nodes are marked as removed or replaced.
763      */

764     private void prepareSingleNodeCopies() {
765         for (int i= 0; i < this.nodeCopySources.size(); i++) {
766             CopySourceInfo curr= (CopySourceInfo) this.nodeCopySources.get(i);
767             if (curr.isMove && curr.location != null) {
768                 doMarkMovedAsRemoved(curr, curr.location.getParent(), curr.location.getProperty());
769             }
770         }
771         
772     }
773     
774     private void doMarkMovedAsRemoved(CopySourceInfo curr, ASTNode parent, StructuralPropertyDescriptor childProperty) {
775         if (childProperty.isChildListProperty()) {
776             ListRewriteEvent event= getListEvent(parent, childProperty, true);
777             int index= event.getIndex(curr.getNode(), ListRewriteEvent.OLD);
778             if (index != -1 && event.getChangeKind(index) == RewriteEvent.UNCHANGED) {
779                 event.setNewValue(null, index);
780             }
781         } else {
782             NodeRewriteEvent event= getNodeEvent(parent, childProperty, true);
783             if (event.getChangeKind() == RewriteEvent.UNCHANGED) {
784                 event.setNewValue(null);
785             }
786         }
787     }
788
789     public boolean isInsertBoundToPrevious(ASTNode node) {
790         if (this.insertBoundToPrevious != null) {
791             return this.insertBoundToPrevious.contains(node);
792         }
793         return false;
794     }
795
796     public void setInsertBoundToPrevious(ASTNode node) {
797         if (this.insertBoundToPrevious == null) {
798             this.insertBoundToPrevious= new HashSet();
799         }
800         this.insertBoundToPrevious.add(node);
801     }
802     
803     private void validateIsListProperty(StructuralPropertyDescriptor property) {
804         if (!property.isChildListProperty()) {
805             String JavaDoc message= property.getId() + " is not a list property"; //$NON-NLS-1$
806
throw new IllegalArgumentException JavaDoc(message);
807         }
808     }
809     
810     private void validateHasChildProperty(ASTNode parent, StructuralPropertyDescriptor property) {
811         if (!parent.structuralPropertiesForType().contains(property)) {
812             String JavaDoc message= Signature.getSimpleName(parent.getClass().getName()) + " has no property " + property.getId(); //$NON-NLS-1$
813
throw new IllegalArgumentException JavaDoc(message);
814         }
815     }
816     
817     private void validateIsNodeProperty(StructuralPropertyDescriptor property) {
818         if (property.isChildListProperty()) {
819             String JavaDoc message= property.getId() + " is not a node property"; //$NON-NLS-1$
820
throw new IllegalArgumentException JavaDoc(message);
821         }
822     }
823     
824     public String JavaDoc toString() {
825         StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
826         for (int i= 0; i < this.events.size(); i++) {
827             buf.append(this.events.get(i).toString()).append('\n');
828         }
829         return buf.toString();
830     }
831     
832     public static boolean isNewNode(ASTNode node) {
833         return (node.getFlags() & ASTNode.ORIGINAL) == 0;
834     }
835
836
837 }
838
Popular Tags