diff options
Diffstat (limited to 'src/test/java/com/google/devtools/build/android/desugar/testdata')
39 files changed, 1893 insertions, 0 deletions
diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java new file mode 100644 index 0000000000..6c4b6f5169 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/CaptureLambda.java @@ -0,0 +1,33 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.stream.Collectors; + +public class CaptureLambda { + + private final List<String> names; + + public CaptureLambda(List<String> names) { + this.names = names; + } + + public List<String> prefixed(String prefix) { + return names + .stream() + .filter(n -> n.startsWith(prefix)) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java new file mode 100644 index 0000000000..1026437b9e --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingLongCompare.java @@ -0,0 +1,51 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +/** This class calls Long.compare(long, long) */ +public class ClassCallingLongCompare { + + public static int compareLongByCallingLong_compare(long a, long b) { + return Long.compare(a, b); + } + + public static String compareLongByCallingLong_compare2(long a, long b) { + if (Long.compare(a, b) == 0) { + return "e"; + } + if (Long.compare(a, b) > 0) { + return "g"; + } + if (Long.compare(a, b) < 0) { + return "l"; + } + throw new AssertionError("unreachable"); + } + + public static int compareLongWithLambda(long a, long b) { + return internalCompare(a, b, (long l1, long l2) -> Long.compare(l1, l2)); + } + + public static int compareLongWithMethodReference(long a, long b) { + return internalCompare(a, b, Long::compare); + } + + private static interface LongCmpFunc { + int compare(long a, long b); + } + + private static int internalCompare(long a, long b, LongCmpFunc func) { + return func.compare(a, b); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java new file mode 100644 index 0000000000..3823f1d774 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassCallingRequireNonNull.java @@ -0,0 +1,53 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.Objects; +import java.util.function.IntSupplier; + +/** This class is for the testing of desugaring calls to Objects.requireNonNull(Object o...) */ +public class ClassCallingRequireNonNull { + + public static int getStringLengthWithMethodReference(String s) { + return toInt(s::length); + } + + public static int toInt(IntSupplier function) { + return function.getAsInt(); + } + + public static int getStringLengthWithLambdaAndExplicitCallToRequireNonNull(final String s) { + return toInt(() -> Objects.requireNonNull(s).length()); + } + + public static char getFirstCharVersionOne(String string) { + Objects.requireNonNull(string); + return string.charAt(0); + } + + public static char getFirstCharVersionTwo(String string) { + string = Objects.requireNonNull(string); + return string.charAt(0); + } + + public static char callRequireNonNullWithArgumentString(String string) { + string = Objects.requireNonNull(string, "the string should not be null"); + return string.charAt(0); + } + + public static char callRequireNonNullWithArgumentSupplier(String string) { + string = Objects.requireNonNull(string, () -> "the string should not be null"); + return string.charAt(0); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java new file mode 100644 index 0000000000..c340c8489d --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ClassUsingTryWithResources.java @@ -0,0 +1,88 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.ByteArrayOutputStream; +import java.io.Closeable; +import java.io.IOException; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +/** + * This is a test subject for {@link + * com.google.devtools.build.android.desugar.TryWithResourcesRewriter} + */ +public class ClassUsingTryWithResources { + + /** + * A simple resource, which always throws an exception when being closed. + * + * <p>Note that we need to implement java.io.Closeable instead of java.lang.AutoCloseable, because + * AutoCloseable is not available below API 19 + * + * <p>java9 will emit $closeResource(Throwable, AutoCloseable) for the following class. + */ + public static class SimpleResource implements Closeable { + + public void call(boolean throwException) { + if (throwException) { + throw new RuntimeException("exception in call()"); + } + } + + @Override + public void close() throws IOException { + throw new IOException("exception in close()."); + } + } + + /** This method will always throw {@link java.lang.Exception}. */ + public static void simpleTryWithResources() throws Exception { + // Throwable.addSuppressed(Throwable) should be called in the following block. + try (SimpleResource resource = new SimpleResource()) { + resource.call(true); + } + } + + public static Throwable[] checkSuppressedExceptions(boolean throwException) { + // Throwable.addSuppressed(Throwable) should be called in the following block. + try (SimpleResource resource = new SimpleResource()) { + resource.call(throwException); + } catch (Exception e) { + return e.getSuppressed(); // getSuppressed() is called. + } + return new Throwable[0]; + } + + public static String printStackTraceOfCaughtException() { + try { + simpleTryWithResources(); + } catch (Exception e) { + PrintStream err = System.err; + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + System.setErr(new PrintStream(stream, true, "utf-8")); + e.printStackTrace(); + } catch (UnsupportedEncodingException e1) { + throw new AssertionError(e1); + } finally { + System.setErr(err); + } + return new String(stream.toByteArray(), UTF_8); + } + return ""; + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java new file mode 100644 index 0000000000..69bacdc6a8 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConcreteFunction.java @@ -0,0 +1,54 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import com.google.devtools.build.android.desugar.testdata.separate.SeparateInterface; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ConcreteFunction implements SpecializedFunction<String, Long> { + @Override + public Long apply(String input) { + return Long.valueOf(input); + } + + // SpecializedParser makes it so we have to search multiple extended interfaces for bridge methods + // when desugaring the lambda returned by this method. + public static SpecializedParser<Integer> toInt() { + return (s -> Integer.valueOf(s)); + } + + public static SeparateInterface<Long> isInt() { + return (l -> Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE); + } + + public static <T extends Number> List<T> parseAll(List<String> in, + SpecializedFunction<String, T> parser) { + return in.stream().map(parser).collect(Collectors.toList()); + } + + public static <T extends Number> List<T> doFilter(List<T> in, SeparateInterface<T> filter) { + return in.stream().filter(filter).collect(Collectors.toList()); + } + + interface Parser<T> extends Function<String, T> { + @Override public T apply(String in); + } + + public interface SpecializedParser<T extends Number> + extends SpecializedFunction<String, T>, Parser<T> { + @Override public T apply(String in); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java new file mode 100644 index 0000000000..03af2a3ea8 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/ConstructorReference.java @@ -0,0 +1,56 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class ConstructorReference { + + private final List<String> names; + + private ConstructorReference(String name) { + names = new ArrayList<>(1); + names.add(name); + } + + public ConstructorReference(List<String> names) { + this.names = names; + } + + public List<Integer> toInt() { + return names.stream().map(Integer::new).collect(Collectors.toList()); + } + + public static Function<String, ConstructorReference> singleton() { + return ConstructorReference::new; + } + + public static Supplier<ConstructorReference> emptyThroughJavacGeneratedBridge() { + // Because Empty is private in another (inner) class, Javac seems to generate a lambda body + // method in this case that calls the Empty(SentinalType) bridge constructor Javac generates. + return Empty::new; + } + + private static class Empty extends ConstructorReference { + + private Empty() { + super(new ArrayList<String>(0)); + throw new RuntimeException("got it!"); + } + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java new file mode 100644 index 0000000000..4974d2561b --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/GuavaLambda.java @@ -0,0 +1,31 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import static com.google.common.collect.Iterables.filter; + +import java.util.List; + +public class GuavaLambda { + + private final List<String> names; + + public GuavaLambda(List<String> names) { + this.names = names; + } + + public Iterable<String> as() { + return filter(names, n -> n.startsWith("A")); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java new file mode 100644 index 0000000000..0fe12b9a5c --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/InnerClassLambda.java @@ -0,0 +1,51 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class InnerClassLambda { + + protected final List<String> reference; + + public InnerClassLambda(List<String> names) { + this.reference = names; + } + + /** + * Uses a lambda that refers to a method parameter across 2 nested anonymous inner classes as well + * as a field in the outer scope, the former being relatively unusual as it causes javac to emit + * 2 getfields to pass the captured parameter directly to the generated lambda class, covering + * an unusual branch in how we rewrite invokedynamics. + */ + public Function<List<String>, Callable<List<String>>> prefixFilter(String prefix) { + return new Function<List<String>, Callable<List<String>>>() { + @Override + public Callable<List<String>> apply(List<String> input) { + return new Callable<List<String>>() { + @Override + public List<String> call() throws Exception { + return input + .stream() + .filter(n -> n.startsWith(prefix) && reference.contains(n)) + .collect(Collectors.toList()); + } + }; + } + }; + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java new file mode 100644 index 0000000000..47d8ab6ecd --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/InterfaceWithLambda.java @@ -0,0 +1,25 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import com.google.common.collect.ImmutableList; + +public interface InterfaceWithLambda { + String ZERO = String.valueOf(0); + ImmutableList<String> DIGITS = + ImmutableList.of(0, 1) + .stream() + .map(i -> i == 0 ? ZERO : String.valueOf(i)) + .collect(ImmutableList.toImmutableList()); +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java new file mode 100644 index 0000000000..48c81c8c87 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/Lambda.java @@ -0,0 +1,60 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class Lambda { + + private final List<String> names; + + public Lambda(List<String> names) { + this.names = names; + } + + public List<String> as() { + return names + .stream() + .filter(n -> n.startsWith("A")) + .collect(Collectors.toList()); + } + + public static Callable<String> hello() { + return (Callable<String> & java.util.RandomAccess) () -> "hello"; + } + + public static Function<Integer, Callable<Long>> mult(int x) { + return new Function<Integer, Callable<Long>>() { + @Override + public Callable<Long> apply(Integer y) { + return () -> (long) x * (long) y; + } + }; + } + + /** + * Test method for b/62456849. This method will first be converted to a synthetic method by {@link + * com.google.devtools.build.android.desugar.Bug62456849TestDataGenerator}, and then Desugar + * should keep it in this class without desugaring it (such as renaming). + * + * <p>Please ignore the lint error on the method name. The method name is intentionally chosen to + * trigger a bug in Desugar. + */ + public static int lambda$mult$0() { + return 0; + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java new file mode 100644 index 0000000000..1f683f8788 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/LambdaInOverride.java @@ -0,0 +1,35 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Test class carefully constructed so javac emits a lambda body method called lambda$filter$0, + * which is exactly the name used for the lambda body method generated by javac for the superclass. + */ +public class LambdaInOverride extends OuterReferenceLambda { + public LambdaInOverride(List<String> names) { + super(names); + } + + public List<String> filter(List<String> names) { + return super + .filter(names) + .stream() + .filter(n -> !reference.contains(n)) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java new file mode 100644 index 0000000000..a293ceab03 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReference.java @@ -0,0 +1,88 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import com.google.devtools.build.android.desugar.testdata.separate.SeparateBaseClass; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class MethodReference extends SeparateBaseClass<String> { + + private final List<String> names; + + public MethodReference(List<String> names) { + super(names); + this.names = names; + } + + // Class method reference + public void appendAll(StringBuilder dest) { + names.stream().forEach(dest::append); + } + + // Interface method reference (regression test for b/33304582) + public List<String> transform(Transformer<String> transformer) { + return names.stream().map(transformer::transform).collect(Collectors.toList()); + } + + // Private method reference (regression test for b/33378312) + public List<String> some() { + return names.stream().filter(MethodReference::startsWithS).collect(Collectors.toList()); + } + + // Protected method reference in a base class of another package (regression test for b/33378312) + public List<String> intersect(List<String> other) { + return other.stream().filter(this::contains).collect(Collectors.toList()); + } + + // Contains the same method reference as intersect + public List<String> onlyIn(List<String> other) { + Predicate<String> p = this::contains; + return other.stream().filter(p.negate()).collect(Collectors.toList()); + } + + // Private method reference to an instance method that throws (regression test for b/33378312) + public Callable<String> stringer() { + return this::throwing; + } + + /** Returns a method reference derived from an expression (object.toString()). */ + public static Function<Integer, Character> stringChars(Object object) { + return (object == null ? "" : object.toString())::charAt; + } + + /** Returns a method reference derived from a field */ + public Predicate<String> toPredicate() { + return names::contains; + } + + private static boolean startsWithS(String input) { + return input.startsWith("S"); + } + + private String throwing() throws Exception { + StringBuilder msg = new StringBuilder(); + appendAll(msg); + throw new IOException(msg.toString()); + } + + /** Interface to create a method reference for in {@link #transform}. */ + public interface Transformer<T> { + T transform(T input); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java new file mode 100644 index 0000000000..fb1c49ece8 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceInSubclass.java @@ -0,0 +1,37 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.stream.Collectors; + +public class MethodReferenceInSubclass extends MethodReferenceSuperclass { + + public MethodReferenceInSubclass(List<String> names) { + super(names); + } + + // Private method reference in subclass that causes a bridge method with the same signature as in + // a superclass in the same package (regression test for b/36201257). Both superclass and this + // class need a method reference to a private *instance* method with the same signature, and they + // should each only one method reference and no lambdas so any class-local counter matches, for + // this class to serve as a repro for b/36201257. + public List<String> containsE() { + return names.stream().filter(this::containsE).collect(Collectors.toList()); + } + + private boolean containsE(String input) { + return input.contains("e"); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java new file mode 100644 index 0000000000..c24cf55b81 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/MethodReferenceSuperclass.java @@ -0,0 +1,39 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.stream.Collectors; + +public class MethodReferenceSuperclass { + + protected final List<String> names; + + public MethodReferenceSuperclass(List<String> names) { + this.names = names; + } + + // Method reference that causes a simple bridge method because the referenced method is private. + // We want to make sure that bridge methods generated in subclasses don't clobber this one. + public List<String> startsWithL() { + return names + .stream() + .filter(this::startsWithL) + .collect(Collectors.toList()); + } + + private boolean startsWithL(String input) { + return input.startsWith("L"); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java new file mode 100644 index 0000000000..d3cf829900 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/OuterReferenceLambda.java @@ -0,0 +1,33 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.List; +import java.util.stream.Collectors; + +public class OuterReferenceLambda { + + protected final List<String> reference; + + public OuterReferenceLambda(List<String> names) { + this.reference = names; + } + + public List<String> filter(List<String> names) { + return names + .stream() + .filter(n -> reference.contains(n)) + .collect(Collectors.toList()); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java new file mode 100644 index 0000000000..b7616a0ae3 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/SpecializedFunction.java @@ -0,0 +1,22 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata; + +import java.util.function.Function; + +public interface SpecializedFunction<S, T extends Number> extends Function<S, T> { + Integer DO_NOT_COPY_INTO_LAMBDA_CLASSES = Integer.valueOf(42); + @Override + public T apply(S in); +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java new file mode 100644 index 0000000000..bdf298cce1 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/java/lang/AutoboxedTypes.java @@ -0,0 +1,36 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This test class is in the java.lang namespace to trigger the hardcoded JVM restrictions that +// desugar --core_library works around +package java.lang; + +/** + * This class will be desugared with --core_library and then functionally tested by {@code + * DesugarCoreLibraryFunctionalTest} + */ +public class AutoboxedTypes { + /** + * Dummy functional interface for autoboxedTypeLambda to return without introducing a dependency + * on any other java.* classes. + */ + @FunctionalInterface + public interface Lambda { + String charAt(String s); + } + + public static Lambda autoboxedTypeLambda(Integer i) { + return n -> n.substring(i, i + 1); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java new file mode 100644 index 0000000000..c39d7bc3bf --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/core_library/test/util/TestClassForStackMapFrame.java @@ -0,0 +1,56 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package test.util; + +/** Test input for b/36654936 */ +public class TestClassForStackMapFrame { + + /** + * This method caused cl/152199391 to fail due to stack map frame corruption. So it is to make + * sure the desugared version of this class still has correct stack map frames. + */ + public String joinIntegers(int integers) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < integers; i++) { + if (i > 0) { + builder.append(","); + } + builder.append(i); + builder.append('='); + Object value = i % 2 == 0 ? "Even" : "Odd"; + if (i % 2 == 0) { + builder.append(value); + } else { + builder.append(value); + } + } + return builder.toString(); + } + + /** + * This method triggers ASM bug 317785 . + * + * @return 20 + */ + public static int testInputForAsmBug317785() { + Integer x = 0; + for (int i = 0; i < 10; ++i) { + x++; + } + for (int i = 0; i < 10; ++i) { + x++; + } + return x; + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java new file mode 100644 index 0000000000..eb794885c6 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/AnnotationsOfDefaultMethodsShouldBeKept.java @@ -0,0 +1,43 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** Test for b/38302860. The annotations of default methods should be kept after desugaring. */ +public class AnnotationsOfDefaultMethodsShouldBeKept { + + /** + * An interface, that has annotation, annotated abstract methods, and annotated default methods. + * After desugaring, all these annotations should remain in the interface. + */ + @SomeAnnotation(1) + public interface AnnotatedInterface { + + @SomeAnnotation(2) + void annotatedAbstractMethod(); + + @SomeAnnotation(3) + default void annotatedDefaultMethod() {} + } + + /** + * A simple annotation, used for testing. + */ + @Retention(value = RetentionPolicy.RUNTIME) + public @interface SomeAnnotation { + int value(); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java new file mode 100644 index 0000000000..0d9f70a76b --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteDefaultInterfaceWithLambda.java @@ -0,0 +1,28 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import com.google.common.collect.ImmutableList; + +public class ConcreteDefaultInterfaceWithLambda implements DefaultInterfaceWithLambda { + static final String ONE = String.valueOf(1); + + @Override + public ImmutableList<String> digits() { + return ImmutableList.of(0, 2) + .stream() + .map(i -> i == 0 ? ONE : String.valueOf(i)) + .collect(ImmutableList.toImmutableList()); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java new file mode 100644 index 0000000000..cdcc5e9ce3 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/ConcreteOverridesDefaultWithLambda.java @@ -0,0 +1,37 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import com.google.common.collect.ImmutableList; + +public class ConcreteOverridesDefaultWithLambda implements DefaultInterfaceWithLambda { + static final String TWO = String.valueOf(2); + static final String THREE = String.valueOf(3); + + @Override + public ImmutableList<String> defaultWithLambda() { + return ImmutableList.of(0, 3) + .stream() + .map(i -> i == 0 ? TWO : String.valueOf(i)) + .collect(ImmutableList.toImmutableList()); + } + + @Override + public ImmutableList<String> digits() { + return ImmutableList.of(0, 4) + .stream() + .map(i -> i == 0 ? THREE : String.valueOf(i)) + .collect(ImmutableList.toImmutableList()); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java new file mode 100644 index 0000000000..dbbf55569d --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceMethodWithStaticInitializer.java @@ -0,0 +1,172 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.List; + +/** + * Interfaces with default methods are intialized differently from those without default methods. + * When we load such an interface, its static intializer will be executed. + * + * <p>However, interfaces without default methods are only initialized when their non-primitive + * fields are accessed. + * + * <p>Test data for b/38255926 + */ +public class DefaultInterfaceMethodWithStaticInitializer { + + final List<String> initializationOrder = new ArrayList<>(); + + DefaultInterfaceMethodWithStaticInitializer register(Class<?> enclosingInterfaceClass) { + initializationOrder.add(enclosingInterfaceClass.getSimpleName()); + return this; + } + + private static long getTime() { + return 0; + } + + /** The simplest case: direct implementation. */ + public static class TestInterfaceSetOne { + + /** + * A writable field so that other interfaces can set it in their static initializers. + * (b/64290760) + */ + static long writableStaticField; + + static final DefaultInterfaceMethodWithStaticInitializer RECORDER = + new DefaultInterfaceMethodWithStaticInitializer(); + + /** With a default method, this interface should run clinit. */ + interface I1 { + long NOW = TestInterfaceSetOne.writableStaticField = getTime(); + DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class); + + default int defaultM1() { + return 1; + } + } + + /** With a default method, this interface should run clinit. */ + interface I2 { + long NOW = TestInterfaceSetOne.writableStaticField = getTime(); + DefaultInterfaceMethodWithStaticInitializer D = RECORDER.register(I2.class); + + default int defaultM2() { + return 10; + } + } + + /** Class to trigger the clinit. */ + public static class C implements I1, I2 { + public int sum() { + return defaultM1() + defaultM2(); + } + } + + public static ImmutableList<String> getExpectedInitializationOrder() { + return ImmutableList.of(I1.class.getSimpleName(), I2.class.getSimpleName()); + } + + public static ImmutableList<String> getRealInitializationOrder() { + return ImmutableList.copyOf(RECORDER.initializationOrder); + } + } + + /** Test for initializer execution order. */ + public static class TestInterfaceSetTwo { + + static final DefaultInterfaceMethodWithStaticInitializer RECORDER = + new DefaultInterfaceMethodWithStaticInitializer(); + + interface I1 { + DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class); + + default int defaultM1() { + return 1; + } + } + + interface I2 extends I1 { + DefaultInterfaceMethodWithStaticInitializer D = RECORDER.register(I2.class); + + default int defaultM2() { + return 2; + } + } + + /** + * Loading this class will trigger the execution of the static initializers of I2 and I1. + * However, I1 will be loaded first, as I2 extends I1. + */ + public static class C implements I2, I1 { + protected static final Integer INT_VALUE = Integer.valueOf(1); // To create a <clinit> + + public int sum() { + return defaultM1() + defaultM2(); + } + } + + public static ImmutableList<String> getExpectedInitializationOrder() { + return ImmutableList.of(I1.class.getSimpleName(), I2.class.getSimpleName()); + } + + public static ImmutableList<String> getRealInitializationOrder() { + return ImmutableList.copyOf(RECORDER.initializationOrder); + } + } + + /** Test: I2's <clinit> should not be executed. */ + public static class TestInterfaceSetThree { + static final DefaultInterfaceMethodWithStaticInitializer RECORDER = + new DefaultInterfaceMethodWithStaticInitializer(); + + interface I1 { + DefaultInterfaceMethodWithStaticInitializer C = RECORDER.register(I1.class); + + default int defaultM1() { + return 6; + } + } + + interface I2 extends I1 { + default int defaultM2() { + return 5; + } + } + + /** + * Loading this class will trigger the execution of the static initializers of I1. I2's will not + * execute. + */ + public static class C implements I2, I1 { + protected static final Integer INT_VALUE = Integer.valueOf(1); // To create a <clinit> + + public int sum() { + return defaultM1() + defaultM2(); + } + } + + public static ImmutableList<String> getExpectedInitializationOrder() { + return ImmutableList.of(I1.class.getSimpleName()); + } + + public static ImmutableList<String> getRealInitializationOrder() { + return ImmutableList.copyOf(RECORDER.initializationOrder); + } + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java new file mode 100644 index 0000000000..c5fb2d35e5 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithBridges.java @@ -0,0 +1,66 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** + * The base interface, which is generic, and has two default methods. These two default methods will + * introduce bridge methods in the child-interfaces + */ +interface GenericInterfaceWithDefaultMethod<T extends Number> { + default T copy(T t) { + return t; + } + + default Number getNumber() { + return 1; + } +} + +/** This interface generate two additional bridge methods */ +interface InterfaceWithDefaultAndBridgeMethods extends GenericInterfaceWithDefaultMethod<Integer> { + @Override + default Integer copy(Integer t) { + return GenericInterfaceWithDefaultMethod.super.copy(t); + } + + @Override + default Double getNumber() { + return 2.3d; + } +} + +/** A class implementing the interface. */ +class ClassWithDefaultAndBridgeMethods implements InterfaceWithDefaultAndBridgeMethods {} + +/** The client class that uses the interfaces and the class that implements the interfaces. */ +public class DefaultInterfaceWithBridges { + private final ClassWithDefaultAndBridgeMethods c = new ClassWithDefaultAndBridgeMethods(); + + public Integer copy(Integer i) { + return c.copy(i); + } + + public Number getNumber() { + return ((GenericInterfaceWithDefaultMethod) c).getNumber(); + } + + public Double getDouble() { + return c.getNumber(); + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public Number copy(Number n) { + return ((GenericInterfaceWithDefaultMethod) c).copy(n); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java new file mode 100644 index 0000000000..e97cae9561 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/DefaultInterfaceWithLambda.java @@ -0,0 +1,33 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import com.google.common.collect.ImmutableList; + +public interface DefaultInterfaceWithLambda { + String ZERO = String.valueOf(0); + + public default ImmutableList<String> defaultWithLambda() { + return ImmutableList.of(0, 1) + .stream() + .map(i -> i == 0 ? ZERO : String.valueOf(i)) + .collect(ImmutableList.toImmutableList()); + } + + public default ImmutableList<String> defaultCallsInterfaceMethod() { + return digits(); + } + + public ImmutableList<String> digits(); +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java new file mode 100644 index 0000000000..176eacece0 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionWithDefaultMethod.java @@ -0,0 +1,78 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** Desugaring test input interface that includes a default method and a static method. */ +public interface FunctionWithDefaultMethod<T extends Number> extends Function<T, T> { + + @Override + T apply(T input); + + static <T extends Number> Function<T, Long> toLong() { + return input -> input.longValue(); + } + + default T twice(T input) { + return apply(apply(input)); + } + + /** Don't call this method from tests, it won't work since Desugar moves it! */ + static FunctionWithDefaultMethod<Integer> inc(int add) { + return input -> input + add; + } + + /** + * Implementation of {@link FunctionWithDefaultMethod} that overrides the default method. + * Also declares static methods the test uses to exercise the code in this file. + */ + public static class DoubleInts implements FunctionWithDefaultMethod<Integer> { + @Override + public Integer apply(Integer input) { + return 2 * input; + } + + @Override + public Integer twice(Integer input) { + return 5 * input; // deliberately wrong :) + } + + public static List<Long> add(List<Integer> ints, int add) { + return ints.stream().map(inc(add)).map(toLong()).collect(Collectors.toList()); + } + + public static FunctionWithDefaultMethod<Integer> doubleLambda() { + return input -> 2 * input; + } + + public static FunctionWithDefaultMethod<Integer> incTwice(int add) { + return inc(add)::twice; + } + + public static FunctionWithDefaultMethod<Integer> times5() { + return new DoubleInts2()::twice; + } + + public static Function<Integer, FunctionWithDefaultMethod<Integer>> incFactory() { + return FunctionWithDefaultMethod::inc; + } + } + + /** Empty subclass that explicitly implements the interface the superclass already implements. */ + public static class DoubleInts2 extends DoubleInts implements FunctionWithDefaultMethod<Integer> { + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java new file mode 100644 index 0000000000..cde6c7b679 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/FunctionalInterfaceWithInitializerAndDefaultMethods.java @@ -0,0 +1,60 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** + * An interface that has a default method, and a non-empty static initializer. The initializer is + * NOT expected to run during desugaring. + */ +public interface FunctionalInterfaceWithInitializerAndDefaultMethods { + + ClassWithInitializer CONSTANT = new ClassWithInitializer(); + boolean BOOLEAN = getFalse(); + char CHAR = "hello".charAt(0); + byte BYTE = Byte.parseByte("0"); + short SHORT = Short.parseShort("0"); + int INT = Integer.parseInt("0"); + float FLOAT = Float.parseFloat("0"); + long LONG = Long.parseLong("0"); + double DOUBLE = Double.parseDouble("0"); + + int convert(); + + /** + * The default method ensures that the static initializer of this interface will be executed when + * the interface is loaded. + */ + default void defaultMethod() {} + + static boolean getFalse() { + return false; + } + + /** + * A class with a static initializer that has side effects (In this class, the printing to stdout) + */ + class ClassWithInitializer { + static { + System.out.println("THIS STRING IS NOT EXPECTED TO APPEAR IN THE OUTPUT OF DESUGAR!!!"); + } + + /** + * A lambda to trigger Desugar to load the interface {@link + * FunctionalInterfaceWithInitializerAndDefaultMethods} + */ + public FunctionalInterfaceWithInitializerAndDefaultMethods length(String s) { + return s::length; + } + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java new file mode 100644 index 0000000000..58396794bf --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/GenericDefaultInterfaceWithLambda.java @@ -0,0 +1,97 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** An interface with default methods, lambdas, and generics */ +public interface GenericDefaultInterfaceWithLambda<T> { + + T getBaseValue(); + + T increment(T value); + + String toString(T value); + + public default ArrayList<T> toList(int bound) { + ArrayList<T> result = new ArrayList<>(); + if (bound == 0) { + return result; + } + result.add(getBaseValue()); + for (int i = 1; i < bound; ++i) { + result.add(increment(result.get(i - 1))); + } + return result; + } + + public default List<String> convertToStringList(List<T> list) { + return list.stream().map(this::toString).collect(Collectors.toList()); + } + + public default Function<Integer, ArrayList<T>> toListSupplier() { + return this::toList; + } + + /** The type parameter is concretized to {@link Number} */ + interface LevelOne<T extends Number> extends GenericDefaultInterfaceWithLambda<T> {} + + /** The type parameter is instantiated to {@link Integer} */ + interface LevelTwo extends LevelOne<Integer> { + + @Override + default Integer getBaseValue() { + return 0; + } + } + + /** An abstract class with no implementing methods. */ + abstract static class ClassOne implements LevelTwo {} + + /** A class for {@link Integer} */ + class ClassTwo extends ClassOne { + + @Override + public Integer increment(Integer value) { + return value + 1; + } + + @Override + public String toString(Integer value) { + return value.toString(); + } + } + + /** A class fo {@link Long} */ + class ClassThree implements LevelOne<Long> { + + @Override + public Long getBaseValue() { + return Long.valueOf(0); + } + + @Override + public Long increment(Long value) { + return value + 1; + } + + @Override + public String toString(Long value) { + return value.toString(); + } + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java new file mode 100644 index 0000000000..622e6e51e7 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceMethod.java @@ -0,0 +1,49 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Desugar test input interface that declares lambdas and method references in default and static + * interface methods. + */ +public interface InterfaceMethod { + public default List<String> defaultMethodReference(List<String> names) { + return names.stream().filter(this::startsWithS).collect(Collectors.toList()); + } + + public default List<String> staticMethodReference(List<String> names) { + return names.stream().filter(InterfaceMethod::startsWithA).collect(Collectors.toList()); + } + + public default List<String> lambdaCallsDefaultMethod(List<String> names) { + return names.stream().filter(s -> startsWithS(s)).collect(Collectors.toList()); + } + + public static boolean startsWithA(String input) { + return input.startsWith("A"); + } + + public default boolean startsWithS(String input) { + return input.startsWith("S"); + } + + /** + * Empty class implementing {@link InterfaceMethod} so the test can instantiate and call default + * methods. + */ + public static class Concrete implements InterfaceMethod {} +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java new file mode 100644 index 0000000000..b2d1beb7cb --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDefaultMethod.java @@ -0,0 +1,41 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** Interface for testing default methods overridden by extending interfaces. */ +public interface InterfaceWithDefaultMethod { + default int version() { + return 1; + } + + /** Interface that overrides {@link #version}. */ + public interface Redefine extends InterfaceWithDefaultMethod { + @Override + default int version() { + return 2; + } + } + + /** Class that implements both interfaces, supertype before subtype. */ + public static class Version2 implements InterfaceWithDefaultMethod, Redefine {} + + /** Base class that just implements {@link Redefine}. */ + static class Version2Base implements Redefine {} + + /** + * Subclass that implements an interface explicitly that the superclass also implements, + * but the superclass implements a more specific interface that overrides a defautl method. + */ + public static class AlsoVersion2 extends Version2Base implements InterfaceWithDefaultMethod {} +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java new file mode 100644 index 0000000000..56217b8c08 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/InterfaceWithDuplicateMethods.java @@ -0,0 +1,45 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** + * Test for b/38308515. This interface has one instance method {@code m()} and one static method + * {@code m(InterfaceWithDuplicateMethods)}, which may cause Desugar to dump a companion class with + * duplicate method signatures. + */ +public interface InterfaceWithDuplicateMethods { + + /** + * In the companion class, this default method will be transformed to {@code int + * getZero(InterfaceWithDuplicateMethods)}, which has the same signature as the static interface + * method below. + */ + @SuppressWarnings("AmbiguousMethodReference") + default int getZero() { + return 0; + } + + /** Should not be called. Should only be called by the class {@link ClassWithDuplicateMethods} */ + @SuppressWarnings("AmbiguousMethodReference") + static int getZero(InterfaceWithDuplicateMethods i) { + return 1; + } + + /** This class implements the interface, and calls the static interface method. */ + class ClassWithDuplicateMethods implements InterfaceWithDuplicateMethods { + public int getZeroFromStaticInterfaceMethod() { + return InterfaceWithDuplicateMethods.getZero(this); + } + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java new file mode 100644 index 0000000000..ae9ef4f765 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Java7InterfaceWithBridges.java @@ -0,0 +1,56 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** + * The test classes for desugaring default methods. Desugar is not expected to generate companion + * classes for interfaces without default methods. The bridge methods are automatically generated by + * javac and put in the implementing classes. + * + * <p>NOTE: There should be NO companion class generated for this class. + */ +public interface Java7InterfaceWithBridges<T> { + T add(T value); + + /** Concretize T to {@link Number)} */ + interface LevelOne<T extends Number> extends Java7InterfaceWithBridges<T> { + @Override + T add(T value); + } + + /** Concretize to {@link Integer} */ + interface LevelTwo extends LevelOne<Integer> { + @Override + Integer add(Integer value); + } + + /** Empty abstract class. This class should have no bridge methods */ + abstract static class AbstractClassOne implements LevelTwo {} + + /** Implementing class. */ + static class ClassAddOne extends AbstractClassOne { + @Override + public Integer add(Integer value) { + return value + 1; + } + } + + /** Implementing class. */ + static class ClassAddTwo extends AbstractClassOne implements LevelTwo { + @Override + public Integer add(Integer value) { + return value + 2; + } + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java new file mode 100644 index 0000000000..4c44ffd611 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/Named.java @@ -0,0 +1,72 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** Desugar test interface to test precedence of inherited methods over default methods. */ +public interface Named { + default String name() { + return getClass().getSimpleName(); + } + + /** Base class defining {@link #name} without implementing {@link Named}. */ + static class ExplicitNameBase { + private final String name; + + public ExplicitNameBase(String name) { + this.name = name; + } + + public String name() { + return name; + } + } + + /** Class whose base class implementes {@link #name}. */ + public static class ExplicitName extends ExplicitNameBase implements Named { + public ExplicitName(String name) { + super(name); + } + } + + /** Class that explicitly defers to the default method in {@link Named}. */ + public static class DefaultName extends ExplicitNameBase implements Named { + public DefaultName() { + super(null); + } + + @Override + public String name() { + return Named.super.name() + "-once"; + } + } + + /** Subclass of {@link DefaultName} that uses {@code super} as well. */ + public static class DefaultNameSubclass extends DefaultName { + @Override + public String name() { + return super.name() + "-twice"; + } + } + + /** Base class that declares {@link #name} abstract. */ + abstract static class AbstractNameBase { + public abstract String name(); + } + + /** + * Class that inherits {@link #name} abstract so subclasses must implement it despite default + * method in implemented interface. + */ + public abstract static class AbstractName extends AbstractNameBase implements Named {} +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java new file mode 100644 index 0000000000..e9456ead99 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/TwoInheritedDefaultMethods.java @@ -0,0 +1,36 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +/** Desugar test class that explicitly calls default methods from two implemented interfaces. */ +public class TwoInheritedDefaultMethods implements Name1, Name2 { + @Override + public String name() { + return Name1.super.name() + ":" + Name2.super.name(); + } +} + +/** Test interface for {@link TwoInheritedDefaultMethods}. */ +interface Name1 { + default String name() { + return "One"; + } +} + +/** Test interface for {@link TwoInheritedDefaultMethods}. */ +interface Name2 { + default String name() { + return "Two"; + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java new file mode 100644 index 0000000000..b6bd37997e --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/VisibilityTestClass.java @@ -0,0 +1,23 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8; + +import com.google.devtools.build.android.desugar.testdata.java8.subpackage.PublicInterface; + +/** + * Class that transitively implements a package-private interface in another package. Default + * method desugaring will need to make the default method defined in that interface publicly + * accessible. + */ +public class VisibilityTestClass implements PublicInterface {} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java new file mode 100644 index 0000000000..9153c12264 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PackagePrivateInterface.java @@ -0,0 +1,33 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8.subpackage; + +/** Package-private interface with default method. */ +interface PackagePrivateInterface { + + /** + * This field makes this interface need to be initialized. With the default methods, when this + * interface is loaded, its initializer should also be run. + * + * <p>However, this test interface is different, as it is package-private. We need to to make sure + * the desugared code does not trigger IllegalAccessError. + * + * <p>See b/38255926. + */ + Integer VERSION = Integer.valueOf(0); + + default int m() { + return 42; + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java new file mode 100644 index 0000000000..c3d51db446 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/java8/subpackage/PublicInterface.java @@ -0,0 +1,22 @@ +// Copyright 2017 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.java8.subpackage; + +/** + * Public interface extending a package-private interface so classes in other packages can + * transitively implement a package-private interface. + * + * @see com.google.devtools.build.android.desugar.testdata.java8.VisibilityTestClass + */ +public interface PublicInterface extends PackagePrivateInterface {} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java new file mode 100644 index 0000000000..a182c53329 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateBaseClass.java @@ -0,0 +1,32 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.separate; + +import java.util.List; + +/** + * Test base class for testing method references to protected methods in another compilation. + */ +public class SeparateBaseClass<T> { + + private final List<T> list; + + protected SeparateBaseClass(List<T> list) { + this.list = list; + } + + protected boolean contains(T elem) { + return list.contains(elem); + } +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java new file mode 100644 index 0000000000..ce4b0584b9 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/separate/SeparateInterface.java @@ -0,0 +1,21 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.android.desugar.testdata.separate; + +import java.util.function.Predicate; + +public interface SeparateInterface<T extends Number> extends Predicate<T> { + @Override + boolean test(T input); +} diff --git a/src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt b/src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt new file mode 100644 index 0000000000..30d74d2584 --- /dev/null +++ b/src/test/java/com/google/devtools/build/android/desugar/testdata/testresource.txt @@ -0,0 +1 @@ +test
\ No newline at end of file |