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 NodeList<N> addFirst(N node) { 189 add(0, node); 190 return this; 191 } 192 193 /** 194 * Inserts the node after all other nodes. (This is simply an alias for add.) 195 */ addLast(N node)196 public NodeList<N> addLast(N node) { 197 add(node); 198 return this; 199 } 200 201 /** 202 * Inserts the node after afterThisNode. 203 * 204 * @throws IllegalArgumentException when afterThisNode is not in this list. 205 */ addAfter(N node, N afterThisNode)206 public NodeList<N> addAfter(N node, N afterThisNode) { 207 int i = indexOf(afterThisNode); 208 if (i == -1) { 209 throw new IllegalArgumentException("Can't find node to insert after."); 210 } 211 add(i + 1, node); 212 return this; 213 } 214 215 /** 216 * Inserts the node before beforeThisNode. 217 * 218 * @throws IllegalArgumentException when beforeThisNode is not in this list. 219 */ addBefore(N node, N beforeThisNode)220 public NodeList<N> addBefore(N node, N beforeThisNode) { 221 int i = indexOf(beforeThisNode); 222 if (i == -1) { 223 throw new IllegalArgumentException("Can't find node to insert before."); 224 } 225 add(i, node); 226 return this; 227 } 228 229 230 @Override getParentNode()231 public Optional<Node> getParentNode() { 232 return Optional.ofNullable(parentNode); 233 } 234 235 /** 236 * Sets the parentNode 237 * 238 * @param parentNode the parentNode 239 * @return this, the NodeList 240 */ 241 @Override setParentNode(Node parentNode)242 public NodeList<N> setParentNode(Node parentNode) { 243 this.parentNode = parentNode; 244 setAsParentNodeOf(innerList); 245 return this; 246 } 247 248 @Override getParentNodeForChildren()249 public Node getParentNodeForChildren() { 250 return parentNode; 251 } 252 253 @Override accept(final GenericVisitor<R, A> v, final A arg)254 public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) { 255 return v.visit(this, arg); 256 } 257 258 @Override accept(final VoidVisitor<A> v, final A arg)259 public <A> void accept(final VoidVisitor<A> v, final A arg) { 260 v.visit(this, arg); 261 } 262 263 /** 264 * @see java.lang.Iterable#forEach(java.util.function.Consumer) 265 */ 266 @Override forEach(Consumer<? super N> action)267 public void forEach(Consumer<? super N> action) { 268 innerList.forEach(action); 269 } 270 271 /** 272 * @see java.util.List#contains(java.lang.Object) 273 */ 274 @Override contains(Object o)275 public boolean contains(Object o) { 276 return innerList.contains(o); 277 } 278 279 /** 280 * @see java.util.List#toArray() 281 */ 282 @Override toArray()283 public Object[] toArray() { 284 return innerList.toArray(); 285 } 286 287 /** 288 * @see java.util.List#toArray(java.lang.Object[]) 289 */ 290 @Override toArray(T[] a)291 public <T> T[] toArray(T[] a) { 292 return innerList.toArray(a); 293 } 294 295 /** 296 * @see java.util.List#remove(java.lang.Object) 297 */ 298 @Override remove(Object o)299 public boolean remove(Object o) { 300 if (o instanceof Node) { 301 return remove((Node) o); 302 } else { 303 return false; 304 } 305 } 306 307 /** 308 * @see java.util.List#containsAll(java.util.Collection) 309 */ 310 @Override containsAll(Collection<?> c)311 public boolean containsAll(Collection<?> c) { 312 return innerList.containsAll(c); 313 } 314 315 /** 316 * @see java.util.List#addAll(java.util.Collection) 317 */ 318 @Override addAll(Collection<? extends N> c)319 public boolean addAll(Collection<? extends N> c) { 320 c.forEach(this::add); 321 return !c.isEmpty(); 322 } 323 324 /** 325 * @see java.util.List#addAll(int, java.util.Collection) 326 */ 327 @Override addAll(int index, Collection<? extends N> c)328 public boolean addAll(int index, Collection<? extends N> c) { 329 for (N e : c) { 330 add(index++, e); 331 } 332 return !c.isEmpty(); 333 } 334 335 /** 336 * @see java.util.List#removeAll(java.util.Collection) 337 */ 338 @Override removeAll(Collection<?> c)339 public boolean removeAll(Collection<?> c) { 340 boolean changed = false; 341 for (Object e : c) { 342 changed = remove(e) || changed; 343 } 344 return changed; 345 } 346 347 /** 348 * @see java.util.List#retainAll(java.util.Collection) 349 */ 350 @Override retainAll(Collection<?> c)351 public boolean retainAll(Collection<?> c) { 352 boolean changed = false; 353 for (Object e : this.stream().filter(it -> !c.contains(it)).toArray()) { 354 if (!c.contains(e)) { 355 changed = remove(e) || changed; 356 } 357 } 358 return changed; 359 } 360 361 /** 362 * @see java.util.List#replaceAll(java.util.function.UnaryOperator) 363 */ 364 @Override replaceAll(UnaryOperator<N> operator)365 public void replaceAll(UnaryOperator<N> operator) { 366 for (int i = 0; i < this.size(); i++) { 367 set(i, operator.apply(this.get(i))); 368 } 369 } 370 371 /** 372 * @see java.util.Collection#removeIf(java.util.function.Predicate) 373 */ 374 @Override removeIf(Predicate<? super N> filter)375 public boolean removeIf(Predicate<? super N> filter) { 376 boolean changed = false; 377 for (Object e : this.stream().filter(filter).toArray()) { 378 changed = remove(e) || changed; 379 } 380 return changed; 381 } 382 383 /** 384 * @see java.util.List#clear() 385 */ 386 @Override clear()387 public void clear() { 388 while (!isEmpty()) { 389 remove(0); 390 } 391 } 392 393 /** 394 * @see java.util.List#equals(java.lang.Object) 395 */ 396 @Override equals(Object o)397 public boolean equals(Object o) { 398 return innerList.equals(o); 399 } 400 401 /** 402 * @see java.util.List#hashCode() 403 */ 404 @Override hashCode()405 public int hashCode() { 406 return innerList.hashCode(); 407 } 408 409 /** 410 * @see java.util.List#indexOf(java.lang.Object) 411 */ 412 @Override indexOf(Object o)413 public int indexOf(Object o) { 414 return innerList.indexOf(o); 415 } 416 417 /** 418 * @see java.util.List#lastIndexOf(java.lang.Object) 419 */ 420 @Override lastIndexOf(Object o)421 public int lastIndexOf(Object o) { 422 return innerList.lastIndexOf(o); 423 } 424 425 /** 426 * @see java.util.List#listIterator() 427 */ 428 @Override listIterator()429 public ListIterator<N> listIterator() { 430 return innerList.listIterator(); 431 } 432 433 /** 434 * @see java.util.List#listIterator(int) 435 */ 436 @Override listIterator(int index)437 public ListIterator<N> listIterator(int index) { 438 return innerList.listIterator(index); 439 } 440 441 /** 442 * @see java.util.Collection#parallelStream() 443 */ 444 @Override parallelStream()445 public Stream<N> parallelStream() { 446 return innerList.parallelStream(); 447 } 448 449 /** 450 * @see java.util.List#subList(int, int) 451 */ 452 @Override subList(int fromIndex, int toIndex)453 public List<N> subList(int fromIndex, int toIndex) { 454 return innerList.subList(fromIndex, toIndex); 455 } 456 457 /** 458 * @see java.util.List#spliterator() 459 */ 460 @Override spliterator()461 public Spliterator<N> spliterator() { 462 return innerList.spliterator(); 463 } 464 notifyElementAdded(int index, Node nodeAddedOrRemoved)465 private void notifyElementAdded(int index, Node nodeAddedOrRemoved) { 466 this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.ADDITION, index, nodeAddedOrRemoved)); 467 } 468 notifyElementRemoved(int index, Node nodeAddedOrRemoved)469 private void notifyElementRemoved(int index, Node nodeAddedOrRemoved) { 470 this.observers.forEach(o -> o.listChange(this, AstObserver.ListChangeType.REMOVAL, index, nodeAddedOrRemoved)); 471 } 472 notifyElementReplaced(int index, Node nodeAddedOrRemoved)473 private void notifyElementReplaced(int index, Node nodeAddedOrRemoved) { 474 this.observers.forEach(o -> o.listReplacement(this, index, this.get(index), nodeAddedOrRemoved)); 475 } 476 477 @Override unregister(AstObserver observer)478 public void unregister(AstObserver observer) { 479 this.observers.remove(observer); 480 } 481 482 @Override register(AstObserver observer)483 public void register(AstObserver observer) { 484 if(!this.observers.contains(observer)) { 485 this.observers.add(observer); 486 } 487 } 488 489 @Override isRegistered(AstObserver observer)490 public boolean isRegistered(AstObserver observer) { 491 return this.observers.contains(observer); 492 } 493 494 /** 495 * Replaces the first node that is equal to "old" with "replacement". 496 * 497 * @return true if a replacement has happened. 498 */ replace(N old, N replacement)499 public boolean replace(N old, N replacement) { 500 int i = indexOf(old); 501 if (i == -1) { 502 return false; 503 } 504 set(i, replacement); 505 return true; 506 } 507 508 /** 509 * @return the opposite of isEmpty() 510 */ isNonEmpty()511 public boolean isNonEmpty() { 512 return !isEmpty(); 513 } 514 ifNonEmpty(Consumer<? super NodeList<N>> consumer)515 public void ifNonEmpty(Consumer<? super NodeList<N>> consumer) { 516 if (isNonEmpty()) 517 consumer.accept(this); 518 } 519 toNodeList()520 public static <T extends Node> Collector<T, NodeList<T>, NodeList<T>> toNodeList() { 521 return Collector.of(NodeList::new, NodeList::add, (left, right) -> { 522 left.addAll(right); 523 return left; 524 }); 525 } 526 setAsParentNodeOf(List<? extends Node> childNodes)527 private void setAsParentNodeOf(List<? extends Node> childNodes) { 528 if (childNodes != null) { 529 for (HasParentNode current : childNodes) { 530 current.setParentNode(getParentNodeForChildren()); 531 } 532 } 533 } 534 setAsParentNodeOf(Node childNode)535 private void setAsParentNodeOf(Node childNode) { 536 if (childNode != null) { 537 childNode.setParentNode(getParentNodeForChildren()); 538 } 539 } 540 541 @Override toString()542 public String toString() { 543 return innerList.stream().map(Node::toString).collect(Collectors.joining(", ", "[", "]")); 544 } 545 } 546