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