aboutsummaryrefslogtreecommitdiffstats
path: root/javaparser-core/src/main/java/com/github/javaparser/ast/NodeList.java
diff options
context:
space:
mode:
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.java542
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(", ", "[", "]"));
+ }
+}