• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3  * Copyright (C) 2011, 2013-2016 The JavaParser Team.
4  *
5  * This file is part of JavaParser.
6  *
7  * JavaParser can be used either under the terms of
8  * a) the GNU Lesser General Public License as published by
9  *     the Free Software Foundation, either version 3 of the License, or
10  *     (at your option) any later version.
11  * b) the terms of the Apache License
12  *
13  * You should have received a copy of both licenses in LICENCE.LGPL and
14  * LICENCE.APACHE. Please refer to those files for details.
15  *
16  * JavaParser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  */
21 
22 package com.github.javaparser.ast;
23 
24 import com.github.javaparser.HasParentNode;
25 import com.github.javaparser.ast.observer.AstObserver;
26 import com.github.javaparser.ast.observer.Observable;
27 import com.github.javaparser.ast.visitor.GenericVisitor;
28 import com.github.javaparser.ast.visitor.Visitable;
29 import com.github.javaparser.ast.visitor.VoidVisitor;
30 import com.github.javaparser.metamodel.InternalProperty;
31 
32 import java.util.*;
33 import java.util.function.*;
34 import java.util.stream.Collector;
35 import java.util.stream.Collectors;
36 import java.util.stream.Stream;
37 
38 /**
39  * A list of nodes.
40  * It usually has a parent node.
41  * Unlike normal Nodes, this does not mean that it is a child of that parent.
42  * Instead, this list will make every node it contains a child of its parent.
43  * This way, a NodeList does not create an extra level inside the AST.
44  *
45  * @param <N> the type of nodes contained.
46  */
47 public class NodeList<N extends Node> implements List<N>, Iterable<N>, HasParentNode<NodeList<N>>, Visitable, Observable {
48     @InternalProperty
49     private List<N> innerList = new ArrayList<>(0);
50 
51     private Node parentNode;
52 
53     private List<AstObserver> observers = new ArrayList<>();
54 
NodeList()55     public NodeList() {
56         parentNode = null;
57     }
58 
NodeList(Collection<N> n)59     public NodeList(Collection<N> n) {
60         this.addAll(n);
61     }
62 
63     @SafeVarargs
NodeList(N... n)64     public NodeList(N... n) {
65         this.addAll(Arrays.asList(n));
66     }
67 
68     @Override
add(N node)69     public boolean add(N node) {
70         notifyElementAdded(innerList.size(), node);
71         own(node);
72         return innerList.add(node);
73     }
74 
own(N node)75     private void own(N node) {
76         if (node == null) {
77             return;
78         }
79         setAsParentNodeOf(node);
80     }
81 
remove(Node node)82     public boolean remove(Node node) {
83         int index = innerList.indexOf(node);
84         if (index != -1) {
85             notifyElementRemoved(index, node);
86             node.setParentNode(null);
87         }
88         return innerList.remove(node);
89     }
90 
removeFirst()91     public N removeFirst() {
92         return remove(0);
93     }
94 
removeLast()95     public N removeLast() {
96         return remove(innerList.size() - 1);
97     }
98 
99     @SafeVarargs
nodeList(X... nodes)100     public static <X extends Node> NodeList<X> nodeList(X... nodes) {
101         final NodeList<X> nodeList = new NodeList<>();
102         Collections.addAll(nodeList, nodes);
103         return nodeList;
104     }
105 
nodeList(Collection<X> nodes)106     public static <X extends Node> NodeList<X> nodeList(Collection<X> nodes) {
107         final NodeList<X> nodeList = new NodeList<>();
108         nodeList.addAll(nodes);
109         return nodeList;
110     }
111 
nodeList(NodeList<X> nodes)112     public static <X extends Node> NodeList<X> nodeList(NodeList<X> nodes) {
113         final NodeList<X> nodeList = new NodeList<>();
114         nodeList.addAll(nodes);
115         return nodeList;
116     }
117 
contains(N node)118     public boolean contains(N node) {
119         return innerList.contains(node);
120     }
121 
122     @Override
size()123     public int size() {
124         return innerList.size();
125     }
126 
127     @Override
get(int i)128     public N get(int i) {
129         return innerList.get(i);
130     }
131 
132     @Override
iterator()133     public Iterator<N> iterator() {
134         // TODO take care of "Iterator.remove"
135         return innerList.iterator();
136     }
137 
138     @Override
set(int index, N element)139     public N set(int index, N element) {
140         if (index < 0 || index >= innerList.size()) {
141             throw new IllegalArgumentException("Illegal index. The index should be between 0 and " + innerList.size()
142                     + " excluded. It is instead " + index);
143         }
144         if (element == innerList.get(index)) {
145             return element;
146         }
147         notifyElementReplaced(index, element);
148         innerList.get(index).setParentNode(null);
149         setAsParentNodeOf(element);
150         return innerList.set(index, element);
151     }
152 
153     @Override
remove(int index)154     public N remove(int index) {
155         notifyElementRemoved(index, innerList.get(index));
156         N remove = innerList.remove(index);
157         if (remove != null)
158             remove.setParentNode(null);
159         return remove;
160     }
161 
162     @Override
isEmpty()163     public boolean isEmpty() {
164         return innerList.isEmpty();
165     }
166 
167     @Override
sort(Comparator<? super N> comparator)168     public void sort(Comparator<? super N> comparator) {
169         innerList.sort(comparator);
170     }
171 
addAll(NodeList<N> otherList)172     public void addAll(NodeList<N> otherList) {
173         for (N node : otherList) {
174             add(node);
175         }
176     }
177 
178     @Override
add(int index, N node)179     public void add(int index, N node) {
180         notifyElementAdded(index, node);
181         own(node);
182         innerList.add(index, node);
183     }
184 
185     /**
186      * Inserts the node before all other nodes.
187      */
addFirst(N node)188     public void addFirst(N node) {
189         add(0, node);
190     }
191 
192     /**
193      * Inserts the node after all other nodes. (This is simply an alias for add.)
194      */
addLast(N node)195     public void addLast(N node) {
196         add(node);
197     }
198 
199     /**
200      * Inserts the node after afterThisNode.
201      *
202      * @throws IllegalArgumentException when afterThisNode is not in this list.
203      */
addAfter(N node, N afterThisNode)204     public NodeList<N> addAfter(N node, N afterThisNode) {
205         int i = indexOf(afterThisNode);
206         if (i == -1) {
207             throw new IllegalArgumentException("Can't find node to insert after.");
208         }
209         add(i + 1, node);
210         return this;
211     }
212 
213     /**
214      * Inserts the node before beforeThisNode.
215      *
216      * @throws IllegalArgumentException when beforeThisNode is not in this list.
217      */
addBefore(N node, N beforeThisNode)218     public NodeList<N> addBefore(N node, N beforeThisNode) {
219         int i = indexOf(beforeThisNode);
220         if (i == -1) {
221             throw new IllegalArgumentException("Can't find node to insert before.");
222         }
223         add(i, node);
224         return this;
225     }
226 
227 
228     @Override
getParentNode()229     public Optional<Node> getParentNode() {
230         return Optional.ofNullable(parentNode);
231     }
232 
233     /**
234      * Sets the parentNode
235      *
236      * @param parentNode the parentNode
237      * @return this, the NodeList
238      */
239     @Override
setParentNode(Node parentNode)240     public NodeList<N> setParentNode(Node parentNode) {
241         this.parentNode = parentNode;
242         setAsParentNodeOf(innerList);
243         return this;
244     }
245 
246     @Override
getParentNodeForChildren()247     public Node getParentNodeForChildren() {
248         return parentNode;
249     }
250 
251     @Override
accept(final GenericVisitor<R, A> v, final A arg)252     public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
253         return v.visit(this, arg);
254     }
255 
256     @Override
accept(final VoidVisitor<A> v, final A arg)257     public <A> void accept(final VoidVisitor<A> v, final A arg) {
258         v.visit(this, arg);
259     }
260 
261     /**
262      * @see java.lang.Iterable#forEach(java.util.function.Consumer)
263      */
264     @Override
forEach(Consumer<? super N> action)265     public void forEach(Consumer<? super N> action) {
266         innerList.forEach(action);
267     }
268 
269     /**
270      * @see java.util.List#contains(java.lang.Object)
271      */
272     @Override
contains(Object o)273     public boolean contains(Object o) {
274         return innerList.contains(o);
275     }
276 
277     /**
278      * @see java.util.List#toArray()
279      */
280     @Override
toArray()281     public Object[] toArray() {
282         return innerList.toArray();
283     }
284 
285     /**
286      * @see java.util.List#toArray(java.lang.Object[])
287      */
288     @Override
toArray(T[] a)289     public <T> T[] toArray(T[] a) {
290         return innerList.toArray(a);
291     }
292 
293     /**
294      * @see java.util.List#remove(java.lang.Object)
295      */
296     @Override
remove(Object o)297     public boolean remove(Object o) {
298         if (o instanceof Node) {
299             return remove((Node) o);
300         } else {
301             return false;
302         }
303     }
304 
305     /**
306      * @see java.util.List#containsAll(java.util.Collection)
307      */
308     @Override
containsAll(Collection<?> c)309     public boolean containsAll(Collection<?> c) {
310         return innerList.containsAll(c);
311     }
312 
313     /**
314      * @see java.util.List#addAll(java.util.Collection)
315      */
316     @Override
addAll(Collection<? extends N> c)317     public boolean addAll(Collection<? extends N> c) {
318         c.forEach(this::add);
319         return !c.isEmpty();
320     }
321 
322     /**
323      * @see java.util.List#addAll(int, java.util.Collection)
324      */
325     @Override
addAll(int index, Collection<? extends N> c)326     public boolean addAll(int index, Collection<? extends N> c) {
327         for (N e : c) {
328             add(index++, e);
329         }
330         return !c.isEmpty();
331     }
332 
333     /**
334      * @see java.util.List#removeAll(java.util.Collection)
335      */
336     @Override
removeAll(Collection<?> c)337     public boolean removeAll(Collection<?> c) {
338         boolean changed = false;
339         for (Object e : c) {
340             changed = remove(e) || changed;
341         }
342         return changed;
343     }
344 
345     /**
346      * @see java.util.List#retainAll(java.util.Collection)
347      */
348     @Override
retainAll(Collection<?> c)349     public boolean retainAll(Collection<?> c) {
350         boolean changed = false;
351         for (Object e : this.stream().filter(it -> !c.contains(it)).toArray()) {
352             if (!c.contains(e)) {
353                 changed = remove(e) || changed;
354             }
355         }
356         return changed;
357     }
358 
359     /**
360      * @see java.util.List#replaceAll(java.util.function.UnaryOperator)
361      */
362     @Override
replaceAll(UnaryOperator<N> operator)363     public void replaceAll(UnaryOperator<N> operator) {
364         for (int i = 0; i < this.size(); i++) {
365             set(i, operator.apply(this.get(i)));
366         }
367     }
368 
369     /**
370      * @see java.util.Collection#removeIf(java.util.function.Predicate)
371      */
372     @Override
removeIf(Predicate<? super N> filter)373     public boolean removeIf(Predicate<? super N> filter) {
374         boolean changed = false;
375         for (Object e : this.stream().filter(filter).toArray()) {
376             changed = remove(e) || changed;
377         }
378         return changed;
379     }
380 
381     /**
382      * @see java.util.List#clear()
383      */
384     @Override
clear()385     public void clear() {
386         while (!isEmpty()) {
387             remove(0);
388         }
389     }
390 
391     /**
392      * @see java.util.List#equals(java.lang.Object)
393      */
394     @Override
equals(Object o)395     public boolean equals(Object o) {
396         return innerList.equals(o);
397     }
398 
399     /**
400      * @see java.util.List#hashCode()
401      */
402     @Override
hashCode()403     public int hashCode() {
404         return innerList.hashCode();
405     }
406 
407     /**
408      * @see java.util.List#indexOf(java.lang.Object)
409      */
410     @Override
indexOf(Object o)411     public int indexOf(Object o) {
412         return innerList.indexOf(o);
413     }
414 
415     /**
416      * @see java.util.List#lastIndexOf(java.lang.Object)
417      */
418     @Override
lastIndexOf(Object o)419     public int lastIndexOf(Object o) {
420         return innerList.lastIndexOf(o);
421     }
422 
423     /**
424      * @see java.util.List#listIterator()
425      */
426     @Override
listIterator()427     public ListIterator<N> listIterator() {
428         return innerList.listIterator();
429     }
430 
431     /**
432      * @see java.util.List#listIterator(int)
433      */
434     @Override
listIterator(int index)435     public ListIterator<N> listIterator(int index) {
436         return innerList.listIterator(index);
437     }
438 
439     /**
440      * @see java.util.Collection#parallelStream()
441      */
442     @Override
parallelStream()443     public Stream<N> parallelStream() {
444         return innerList.parallelStream();
445     }
446 
447     /**
448      * @see java.util.List#subList(int, int)
449      */
450     @Override
subList(int fromIndex, int toIndex)451     public List<N> subList(int fromIndex, int toIndex) {
452         return innerList.subList(fromIndex, toIndex);
453     }
454 
455     /**
456      * @see java.util.List#spliterator()
457      */
458     @Override
spliterator()459     public Spliterator<N> spliterator() {
460         return innerList.spliterator();
461     }
462 
notifyElementAdded(int index, Node nodeAddedOrRemoved)463     private void notifyElementAdded(int index, Node nodeAddedOrRemoved) {
464         this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.ADDITION, index, nodeAddedOrRemoved));
465     }
466 
notifyElementRemoved(int index, Node nodeAddedOrRemoved)467     private void notifyElementRemoved(int index, Node nodeAddedOrRemoved) {
468         this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.REMOVAL, index, nodeAddedOrRemoved));
469     }
470 
notifyElementReplaced(int index, Node nodeAddedOrRemoved)471     private void notifyElementReplaced(int index, Node nodeAddedOrRemoved) {
472         this.observers.forEach(o -> o.listReplacement(this, index, this.get(index), nodeAddedOrRemoved));
473     }
474 
475     @Override
unregister(AstObserver observer)476     public void unregister(AstObserver observer) {
477         this.observers.remove(observer);
478     }
479 
480     @Override
register(AstObserver observer)481     public void register(AstObserver observer) {
482         if(!this.observers.contains(observer)) {
483             this.observers.add(observer);
484         }
485     }
486 
487     @Override
isRegistered(AstObserver observer)488     public boolean isRegistered(AstObserver observer) {
489         return this.observers.contains(observer);
490     }
491 
492     /**
493      * Replaces the first node that is equal to "old" with "replacement".
494      *
495      * @return true if a replacement has happened.
496      */
replace(N old, N replacement)497     public boolean replace(N old, N replacement) {
498         int i = indexOf(old);
499         if (i == -1) {
500             return false;
501         }
502         set(i, replacement);
503         return true;
504     }
505 
506     /**
507      * @return the opposite of isEmpty()
508      */
isNonEmpty()509     public boolean isNonEmpty() {
510         return !isEmpty();
511     }
512 
ifNonEmpty(Consumer<? super NodeList<N>> consumer)513     public void ifNonEmpty(Consumer<? super NodeList<N>> consumer) {
514         if (isNonEmpty())
515             consumer.accept(this);
516     }
517 
toNodeList()518     public static <T extends Node> Collector<T, NodeList<T>, NodeList<T>> toNodeList() {
519         return Collector.of(NodeList::new, NodeList::add, (left, right) -> {
520             left.addAll(right);
521             return left;
522         });
523     }
524 
setAsParentNodeOf(List<? extends Node> childNodes)525     private void setAsParentNodeOf(List<? extends Node> childNodes) {
526         if (childNodes != null) {
527             for (HasParentNode current : childNodes) {
528                 current.setParentNode(getParentNodeForChildren());
529             }
530         }
531     }
532 
setAsParentNodeOf(Node childNode)533     private void setAsParentNodeOf(Node childNode) {
534         if (childNode != null) {
535             childNode.setParentNode(getParentNodeForChildren());
536         }
537     }
538 
539     @Override
toString()540     public String toString() {
541         return innerList.stream().map(Node::toString).collect(Collectors.joining(", ", "[", "]"));
542     }
543 }
544