com.github.javaparser.ast.NodeList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stubparser Show documentation
Show all versions of stubparser Show documentation
This project contains a parser for the Checker Framework's stub files: https://checkerframework.org/manual/#stub . It is a fork of the JavaParser project.
The newest version!
/*
* Copyright (C) 2007-2010 Júlio Vilmar Gesser.
* Copyright (C) 2011, 2013-2024 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.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
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 the type of nodes contained.
*/
public class NodeList
implements List, Iterable, HasParentNode>, Visitable, Observable {
@InternalProperty
private final List innerList = new ArrayList<>(0);
private Node parentNode;
private final List observers = new ArrayList<>();
public NodeList() {
parentNode = null;
}
public NodeList(Collection n) {
this.addAll(n);
}
@SafeVarargs
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 NodeList nodeList(X... nodes) {
final NodeList nodeList = new NodeList<>();
Collections.addAll(nodeList, nodes);
return nodeList;
}
public static NodeList nodeList(Collection nodes) {
final NodeList nodeList = new NodeList<>();
nodeList.addAll(nodes);
return nodeList;
}
public static NodeList nodeList(NodeList nodes) {
final NodeList 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 iterator() {
// Custom iterator required, to ensure that the relevant `notifyElement...` methods are called.
return new NodeListIterator(innerList);
}
@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 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 addFirst(N node) {
add(0, node);
return this;
}
/**
* Inserts the node after all other nodes. (This is simply an alias for add.)
*/
public NodeList addLast(N node) {
add(node);
return this;
}
/**
* Inserts the node after afterThisNode.
*
* @throws IllegalArgumentException when afterThisNode is not in this list.
*/
public NodeList 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 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;
}
/**
* @return the first node, or empty if the list is empty.
*/
public Optional getFirst() {
if (isEmpty()) {
return Optional.empty();
}
return Optional.of(get(0));
}
/**
* @return the last node, or empty if the list is empty.
*/
public Optional getLast() {
if (isEmpty()) {
return Optional.empty();
}
return Optional.of(get(size() - 1));
}
@Override
public Optional getParentNode() {
return Optional.ofNullable(parentNode);
}
/**
* Sets the parentNode
*
* @param parentNode the parentNode
* @return this, the NodeList
*/
@Override
public NodeList setParentNode(Node parentNode) {
this.parentNode = parentNode;
setAsParentNodeOf(innerList);
return this;
}
@Override
public Node getParentNodeForChildren() {
return parentNode;
}
@Override
public R accept(final GenericVisitor v, final A arg) {
return v.visit(this, arg);
}
@Override
public void accept(final VoidVisitor 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[] 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);
}
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 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 listIterator() {
// Custom iterator required, to ensure that the relevant `notifyElement...` methods are called.
return new NodeListIterator(innerList);
}
/**
* @see java.util.List#listIterator(int)
*/
@Override
public ListIterator listIterator(int index) {
// Custom iterator required, to ensure that the relevant `notifyElement...` methods are called.
return new NodeListIterator(innerList, index);
}
/**
* @see java.util.Collection#parallelStream()
*/
@Override
public Stream parallelStream() {
return innerList.parallelStream();
}
/**
* @see java.util.List#subList(int, int)
*/
@Override
public List subList(int fromIndex, int toIndex) {
return innerList.subList(fromIndex, toIndex);
}
/**
* @see java.util.List#spliterator()
*/
@Override
public Spliterator 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) {
if (!this.observers.contains(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> consumer) {
if (isNonEmpty()) consumer.accept(this);
}
public static Collector, NodeList> 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(", ", "[", "]"));
}
protected class NodeListIterator implements ListIterator {
ListIterator iterator;
N current = null;
// initialize pointer to head of the list for iteration
public NodeListIterator(List list) {
iterator = list.listIterator();
}
public NodeListIterator(List list, int index) {
iterator = list.listIterator(index);
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public N next() {
current = iterator.next();
return current;
}
@Override
public boolean hasPrevious() {
return iterator.hasPrevious();
}
@Override
public N previous() {
current = iterator.previous();
return current;
}
@Override
public int nextIndex() {
return iterator.nextIndex();
}
@Override
public int previousIndex() {
return iterator.previousIndex();
}
@Override
public void remove() {
int index = innerList.indexOf(current);
if (index != -1) {
notifyElementRemoved(index, current);
current.setParentNode(null);
}
iterator.remove();
}
@Override
public void set(N n) {
int index = innerList.indexOf(current);
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 (n != innerList.get(index)) {
notifyElementReplaced(index, n);
innerList.get(index).setParentNode(null);
setAsParentNodeOf(n);
iterator.set(n);
}
}
@Override
public void add(N n) {
notifyElementAdded(innerList.size(), n);
own(n);
iterator.add(n);
}
@Override
public void forEachRemaining(Consumer super N> action) {
iterator.forEachRemaining(action);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy