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