diff --git a/key.util/src/main/java/org/key_project/util/collection/ImmutableList.java b/key.util/src/main/java/org/key_project/util/collection/ImmutableList.java index 7cdc34a9231..4936563ae05 100644 --- a/key.util/src/main/java/org/key_project/util/collection/ImmutableList.java +++ b/key.util/src/main/java/org/key_project/util/collection/ImmutableList.java @@ -111,7 +111,7 @@ public interface ImmutableList /// @param list the list to wrap /// @return an ImmutableList containing the elements of the input list static ImmutableList fromList(List list) { - return new ImmutableListList<>(list); + return new ImmutableListList<>(new ArrayList<>(list)); } /// Creates an [ImmutableList] from an array. @@ -123,6 +123,18 @@ public interface ImmutableList /// @param array the array to wrap /// @return an ImmutableList containing the elements of the input array static ImmutableList fromArray(T[] array) { + return new ImmutableListArray<>(array.clone()); + } + + /// Creates an [ImmutableList] from an array. + /// + /// This method wraps the given array in an immutable wrapper. + /// + /// @param the element type + /// @param array the array to wrap + /// @return an ImmutableList containing the elements of the input array + static ImmutableList fromItems(T... array) { + // weigl: copy needed, array dynamical created and not leaked. return new ImmutableListArray<>(array); } @@ -246,7 +258,8 @@ default ImmutableList prependReverse(Iterable collection) { /// @param array the array to prepend /// @return a new list with the array's elements at the beginning default ImmutableList prepend(T... array) { - return new ImmutableListConcat<>(ImmutableList.fromArray(array), this); + // weigl: here we can use the leaky version + return new ImmutableListConcat<>(new ImmutableListArray<>(array), this); } /// Appends a single element to this list. diff --git a/key.util/src/main/java/org/key_project/util/collection/ImmutableListArray.java b/key.util/src/main/java/org/key_project/util/collection/ImmutableListArray.java index 5c6e224138d..0dd4f6c7116 100644 --- a/key.util/src/main/java/org/key_project/util/collection/ImmutableListArray.java +++ b/key.util/src/main/java/org/key_project/util/collection/ImmutableListArray.java @@ -22,7 +22,14 @@ final class ImmutableListArray implements ImmutableList { private final T[] data; - public ImmutableListArray(T[] data) { + /** + * Caution: This constructor does *not* the argument array but refers to it directly. + * Do not call it but from contexts where you know that data remains unmodified. + * + * @see ImmutableList#fromArray(Object[]) + * @param data the array data + */ + ImmutableListArray(T[] data) { this.data = data; } diff --git a/key.util/src/test/java/org/key_project/util/collection/ImmutableListArrayTest.java b/key.util/src/test/java/org/key_project/util/collection/ImmutableListArrayTest.java index 15c6605efdd..dae423b10c5 100644 --- a/key.util/src/test/java/org/key_project/util/collection/ImmutableListArrayTest.java +++ b/key.util/src/test/java/org/key_project/util/collection/ImmutableListArrayTest.java @@ -29,6 +29,41 @@ public static Integer[] create(int i) { return IntStream.range(1, i + 1).boxed().toArray(Integer[]::new); } + @Test + void immutability1() { + Integer[] array = { 0, 1, 4 }; + // constructor does not copy the array, so changes to the array are reflected in the list + // While this seems dangerous, the constructur is package-private and thus considered safe. + ImmutableListArray list = new ImmutableListArray<>(array); + assertThat(list.get(2)).isEqualTo(4); + array[2] = 2; + assertThat(list.get(2)).isEqualTo(2); + } + + @Test + void immutability2() { + Integer[] array = { 0, 1, 4 }; + ImmutableList list = ImmutableList.fromArray(array); + array[2] = 2; + assertThat(list.get(2)).isEqualTo(4); + } + + @Test + void immutability3() { + Integer[] array = { 0, 1, 4 }; + ImmutableList list = ImmutableList.fromItems(array); + array[2] = 2; + assertThat(list.get(2)).isEqualTo(4); + } + + @Test + void immutability4() { + Integer[] array = { 0, 1, 4 }; + ImmutableList list = ImmutableList.fromItems(-1).prepend(array); + assertThat(list.get(2)).isEqualTo(4); + array[2] = 2; + assertThat(list.get(2)).isEqualTo(4); + } @Test void size() {