1 /* 2 * Copyright 2018, Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google LLC nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 package com.android.tools.smali.dexlib2.builder; 32 33 import java.util.AbstractSet; 34 import java.util.ArrayList; 35 import java.util.Collections; 36 import java.util.Iterator; 37 import java.util.List; 38 import java.util.Set; 39 import javax.annotation.Nonnull; 40 import javax.annotation.Nullable; 41 42 public abstract class LocatedItems<T extends ItemWithLocation> { 43 // We end up creating and keeping around a *lot* of MethodLocation objects 44 // when building a new dex file, so it's worth the trouble of lazily creating 45 // the labels and debugItems lists only when they are needed 46 @Nullable 47 private List<T> items = null; 48 49 @Nonnull getItems()50 private List<T> getItems() { 51 if (items == null) { 52 return Collections.emptyList(); 53 } 54 return items; 55 } 56 getModifiableItems(MethodLocation newItemsLocation)57 public Set<T> getModifiableItems(MethodLocation newItemsLocation) { 58 return new AbstractSet<T>() { 59 @Nonnull 60 @Override 61 public Iterator<T> iterator() { 62 final Iterator<T> it = getItems().iterator(); 63 64 return new Iterator<T>() { 65 private @Nullable 66 T currentItem = null; 67 68 @Override 69 public boolean hasNext() { 70 return it.hasNext(); 71 } 72 73 @Override 74 public T next() { 75 currentItem = it.next(); 76 return currentItem; 77 } 78 79 @Override 80 public void remove() { 81 if (currentItem != null) { 82 currentItem.setLocation(null); 83 } 84 it.remove(); 85 } 86 }; 87 } 88 89 @Override 90 public int size() { 91 return getItems().size(); 92 } 93 94 @Override 95 public boolean add(@Nonnull T item) { 96 if (item.isPlaced()) { 97 throw new IllegalArgumentException(getAddLocatedItemError()); 98 } 99 item.setLocation(newItemsLocation); 100 addItem(item); 101 return true; 102 } 103 }; 104 } 105 106 private void addItem(@Nonnull T item) { 107 if (items == null) { 108 items = new ArrayList<>(1); 109 } 110 items.add(item); 111 } 112 113 protected abstract String getAddLocatedItemError(); 114 115 public void mergeItemsIntoNext(@Nonnull MethodLocation nextLocation, LocatedItems<T> otherLocatedItems) { 116 if (otherLocatedItems == this) { 117 return; 118 } 119 if (items != null) { 120 for (T item : items) { 121 item.setLocation(nextLocation); 122 } 123 List<T> mergedItems = items; 124 mergedItems.addAll(otherLocatedItems.getItems()); 125 otherLocatedItems.items = mergedItems; 126 items = null; 127 } 128 } 129 } 130