diff options
Diffstat (limited to 'javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java')
-rw-r--r-- | javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java b/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java new file mode 100644 index 000000000..f370e960d --- /dev/null +++ b/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2007-2010 JĂșlio Vilmar Gesser. + * Copyright (C) 2011, 2013-2016 The JavaParser Team. + * + * This file is part of JavaParser. + * + * JavaParser can be used either under the terms of + * a) the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * b) the terms of the Apache License + * + * You should have received a copy of both licenses in LICENCE.LGPL and + * LICENCE.APACHE. Please refer to those files for details. + * + * JavaParser is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +package com.github.javaparser.ast; + +import com.github.javaparser.HasParentNode; +import com.github.javaparser.ast.observer.AstObserver; +import com.github.javaparser.ast.observer.Observable; +import com.github.javaparser.ast.visitor.GenericVisitor; +import com.github.javaparser.ast.visitor.Visitable; +import com.github.javaparser.ast.visitor.VoidVisitor; +import com.github.javaparser.metamodel.InternalProperty; + +import java.util.*; +import java.util.function.*; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * A list of nodes. + * It usually has a parent node. + * Unlike normal Nodes, this does not mean that it is a child of that parent. + * Instead, this list will make every node it contains a child of its parent. + * This way, a NodeList does not create an extra level inside the AST. + * + * @param <N> the type of nodes contained. + */ +public class NodeList<N extends Node> implements List<N>, Iterable<N>, HasParentNode<NodeList<N>>, Visitable, Observable { + @InternalProperty + private List<N> innerList = new ArrayList<>(0); + + private Node parentNode; + + private List<AstObserver> observers = new ArrayList<>(); + + public NodeList() { + parentNode = null; + } + + public NodeList(Collection<N> n) { + this.addAll(n); + } + + public NodeList(N... n) { + this.addAll(Arrays.asList(n)); + } + + @Override + public boolean add(N node) { + notifyElementAdded(innerList.size(), node); + own(node); + return innerList.add(node); + } + + private void own(N node) { + if (node == null) { + return; + } + setAsParentNodeOf(node); + } + + public boolean remove(Node node) { + int index = innerList.indexOf(node); + if (index != -1) { + notifyElementRemoved(index, node); + node.setParentNode(null); + } + return innerList.remove(node); + } + + public N removeFirst() { + return remove(0); + } + + public N removeLast() { + return remove(innerList.size() - 1); + } + + @SafeVarargs + public static <X extends Node> NodeList<X> nodeList(X... nodes) { + final NodeList<X> nodeList = new NodeList<>(); + Collections.addAll(nodeList, nodes); + return nodeList; + } + + public static <X extends Node> NodeList<X> nodeList(Collection<X> nodes) { + final NodeList<X> nodeList = new NodeList<>(); + nodeList.addAll(nodes); + return nodeList; + } + + public static <X extends Node> NodeList<X> nodeList(NodeList<X> nodes) { + final NodeList<X> nodeList = new NodeList<>(); + nodeList.addAll(nodes); + return nodeList; + } + + public boolean contains(N node) { + return innerList.contains(node); + } + + @Override + public int size() { + return innerList.size(); + } + + @Override + public N get(int i) { + return innerList.get(i); + } + + @Override + public Iterator<N> iterator() { + // TODO take care of "Iterator.remove" + return innerList.iterator(); + } + + @Override + public N set(int index, N element) { + if (index < 0 || index >= innerList.size()) { + throw new IllegalArgumentException("Illegal index. The index should be between 0 and " + innerList.size() + + " excluded. It is instead " + index); + } + if (element == innerList.get(index)) { + return element; + } + notifyElementReplaced(index, element); + innerList.get(index).setParentNode(null); + setAsParentNodeOf(element); + return innerList.set(index, element); + } + + @Override + public N remove(int index) { + notifyElementRemoved(index, innerList.get(index)); + N remove = innerList.remove(index); + if (remove != null) + remove.setParentNode(null); + return remove; + } + + @Override + public boolean isEmpty() { + return innerList.isEmpty(); + } + + @Override + public void sort(Comparator<? super N> comparator) { + innerList.sort(comparator); + } + + public void addAll(NodeList<N> otherList) { + for (N node : otherList) { + add(node); + } + } + + @Override + public void add(int index, N node) { + notifyElementAdded(index, node); + own(node); + innerList.add(index, node); + } + + /** + * Inserts the node before all other nodes. + */ + public NodeList<N> addFirst(N node) { + add(0, node); + return this; + } + + /** + * Inserts the node after all other nodes. (This is simply an alias for add.) + */ + public NodeList<N> addLast(N node) { + add(node); + return this; + } + + /** + * Inserts the node after afterThisNode. + * + * @throws IllegalArgumentException when afterThisNode is not in this list. + */ + public NodeList<N> addAfter(N node, N afterThisNode) { + int i = indexOf(afterThisNode); + if (i == -1) { + throw new IllegalArgumentException("Can't find node to insert after."); + } + add(i + 1, node); + return this; + } + + /** + * Inserts the node before beforeThisNode. + * + * @throws IllegalArgumentException when beforeThisNode is not in this list. + */ + public NodeList<N> addBefore(N node, N beforeThisNode) { + int i = indexOf(beforeThisNode); + if (i == -1) { + throw new IllegalArgumentException("Can't find node to insert before."); + } + add(i, node); + return this; + } + + + @Override + public Optional<Node> getParentNode() { + return Optional.ofNullable(parentNode); + } + + /** + * Sets the parentNode + * + * @param parentNode the parentNode + * @return this, the NodeList + */ + @Override + public NodeList<N> setParentNode(Node parentNode) { + this.parentNode = parentNode; + setAsParentNodeOf(innerList); + return this; + } + + @Override + public Node getParentNodeForChildren() { + return parentNode; + } + + @Override + public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) { + return v.visit(this, arg); + } + + @Override + public <A> void accept(final VoidVisitor<A> v, final A arg) { + v.visit(this, arg); + } + + /** + * @see java.lang.Iterable#forEach(java.util.function.Consumer) + */ + @Override + public void forEach(Consumer<? super N> action) { + innerList.forEach(action); + } + + /** + * @see java.util.List#contains(java.lang.Object) + */ + @Override + public boolean contains(Object o) { + return innerList.contains(o); + } + + /** + * @see java.util.List#toArray() + */ + @Override + public Object[] toArray() { + return innerList.toArray(); + } + + /** + * @see java.util.List#toArray(java.lang.Object[]) + */ + @Override + public <T> T[] toArray(T[] a) { + return innerList.toArray(a); + } + + /** + * @see java.util.List#remove(java.lang.Object) + */ + @Override + public boolean remove(Object o) { + if (o instanceof Node) { + return remove((Node) o); + } else { + return false; + } + } + + /** + * @see java.util.List#containsAll(java.util.Collection) + */ + @Override + public boolean containsAll(Collection<?> c) { + return innerList.containsAll(c); + } + + /** + * @see java.util.List#addAll(java.util.Collection) + */ + @Override + public boolean addAll(Collection<? extends N> c) { + c.forEach(this::add); + return !c.isEmpty(); + } + + /** + * @see java.util.List#addAll(int, java.util.Collection) + */ + @Override + public boolean addAll(int index, Collection<? extends N> c) { + for (N e : c) { + add(index++, e); + } + return !c.isEmpty(); + } + + /** + * @see java.util.List#removeAll(java.util.Collection) + */ + @Override + public boolean removeAll(Collection<?> c) { + boolean changed = false; + for (Object e : c) { + changed = remove(e) || changed; + } + return changed; + } + + /** + * @see java.util.List#retainAll(java.util.Collection) + */ + @Override + public boolean retainAll(Collection<?> c) { + boolean changed = false; + for (Object e : this.stream().filter(it -> !c.contains(it)).toArray()) { + if (!c.contains(e)) { + changed = remove(e) || changed; + } + } + return changed; + } + + /** + * @see java.util.List#replaceAll(java.util.function.UnaryOperator) + */ + @Override + public void replaceAll(UnaryOperator<N> operator) { + for (int i = 0; i < this.size(); i++) { + set(i, operator.apply(this.get(i))); + } + } + + /** + * @see java.util.Collection#removeIf(java.util.function.Predicate) + */ + @Override + public boolean removeIf(Predicate<? super N> filter) { + boolean changed = false; + for (Object e : this.stream().filter(filter).toArray()) { + changed = remove(e) || changed; + } + return changed; + } + + /** + * @see java.util.List#clear() + */ + @Override + public void clear() { + while (!isEmpty()) { + remove(0); + } + } + + /** + * @see java.util.List#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + return innerList.equals(o); + } + + /** + * @see java.util.List#hashCode() + */ + @Override + public int hashCode() { + return innerList.hashCode(); + } + + /** + * @see java.util.List#indexOf(java.lang.Object) + */ + @Override + public int indexOf(Object o) { + return innerList.indexOf(o); + } + + /** + * @see java.util.List#lastIndexOf(java.lang.Object) + */ + @Override + public int lastIndexOf(Object o) { + return innerList.lastIndexOf(o); + } + + /** + * @see java.util.List#listIterator() + */ + @Override + public ListIterator<N> listIterator() { + return innerList.listIterator(); + } + + /** + * @see java.util.List#listIterator(int) + */ + @Override + public ListIterator<N> listIterator(int index) { + return innerList.listIterator(index); + } + + /** + * @see java.util.Collection#parallelStream() + */ + @Override + public Stream<N> parallelStream() { + return innerList.parallelStream(); + } + + /** + * @see java.util.List#subList(int, int) + */ + @Override + public List<N> subList(int fromIndex, int toIndex) { + return innerList.subList(fromIndex, toIndex); + } + + /** + * @see java.util.List#spliterator() + */ + @Override + public Spliterator<N> spliterator() { + return innerList.spliterator(); + } + + private void notifyElementAdded(int index, Node nodeAddedOrRemoved) { + this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.ADDITION, index, nodeAddedOrRemoved)); + } + + private void notifyElementRemoved(int index, Node nodeAddedOrRemoved) { + this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.REMOVAL, index, nodeAddedOrRemoved)); + } + + private void notifyElementReplaced(int index, Node nodeAddedOrRemoved) { + this.observers.forEach(o -> o.listReplacement(this, index, this.get(index), nodeAddedOrRemoved)); + } + + @Override + public void unregister(AstObserver observer) { + this.observers.remove(observer); + } + + @Override + public void register(AstObserver observer) { + this.observers.add(observer); + } + + @Override + public boolean isRegistered(AstObserver observer) { + return this.observers.contains(observer); + } + + /** + * Replaces the first node that is equal to "old" with "replacement". + * + * @return true if a replacement has happened. + */ + public boolean replace(N old, N replacement) { + int i = indexOf(old); + if (i == -1) { + return false; + } + set(i, replacement); + return true; + } + + /** + * @return the opposite of isEmpty() + */ + public boolean isNonEmpty() { + return !isEmpty(); + } + + public void ifNonEmpty(Consumer<? super NodeList<N>> consumer) { + if (isNonEmpty()) + consumer.accept(this); + } + + public static <T extends Node> Collector<T, NodeList<T>, NodeList<T>> toNodeList() { + return Collector.of(NodeList::new, NodeList::add, (left, right) -> { + left.addAll(right); + return left; + }); + } + + private void setAsParentNodeOf(List<? extends Node> childNodes) { + if (childNodes != null) { + for (HasParentNode current : childNodes) { + current.setParentNode(getParentNodeForChildren()); + } + } + } + + private void setAsParentNodeOf(Node childNode) { + if (childNode != null) { + childNode.setParentNode(getParentNodeForChildren()); + } + } + + @Override + public String toString() { + return innerList.stream().map(Node::toString).collect(Collectors.joining(", ", "[", "]")); + } +} |