Merge "Disallow the use of filled-new-array of objects before kitkat."
diff --git a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
index 0313cf8..ae022a5 100644
--- a/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/ArchiveClassFileProvider.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.utils.FileUtils.isArchive;
import static com.android.tools.r8.utils.FileUtils.isClassFile;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.shaking.FilteredClassPath;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -23,11 +24,24 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-/**
- * Lazy Java class file resource provider loading class files form a zip archive.
- */
+/** Lazy Java class file resource provider loading class files form a zip archive. */
public class ArchiveClassFileProvider implements ClassFileResourceProvider, Closeable {
+ private static class ArchiveEntryOrigin extends Origin {
+ final String descriptor;
+
+ public ArchiveEntryOrigin(String descriptor, Origin parent) {
+ super(parent);
+ this.descriptor = descriptor;
+ }
+
+ @Override
+ public String part() {
+ return descriptor;
+ }
+ }
+
+ private final Origin origin;
private final Set<String> descriptors = new HashSet<>();
private final ZipFile zipFile;
@@ -42,6 +56,7 @@
private ArchiveClassFileProvider(FilteredClassPath archive) throws IOException {
assert isArchive(archive.getPath());
+ origin = new Resource.PathOrigin(archive.getPath(), Origin.root());
zipFile = new ZipFile(archive.getPath().toFile());
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
@@ -67,7 +82,7 @@
try (InputStream inputStream = zipFile.getInputStream(getZipEntryFromDescriptor(descriptor))) {
return Resource.fromBytes(
- Resource.Kind.CLASSFILE,
+ new ArchiveEntryOrigin(descriptor, origin),
ByteStreams.toByteArray(inputStream),
Collections.singleton(descriptor));
} catch (IOException e) {
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index 9239a9a..58ea240 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -97,7 +97,8 @@
Map<String, Integer> result = new HashMap<>();
try (Closer closer = Closer.create()) {
for (Resource resource : app.getDexProgramResources()) {
- for (Segment segment: DexFileReader.parseMapFrom(closer.register(resource.getStream()))) {
+ for (Segment segment :
+ DexFileReader.parseMapFrom(closer.register(resource.getStream()), resource.origin)) {
int value = result.computeIfAbsent(segment.typeName(), (key) -> 0);
result.put(segment.typeName(), value + segment.size());
}
diff --git a/src/main/java/com/android/tools/r8/Diagnostic.java b/src/main/java/com/android/tools/r8/Diagnostic.java
index 3991c4f..1c1961d 100644
--- a/src/main/java/com/android/tools/r8/Diagnostic.java
+++ b/src/main/java/com/android/tools/r8/Diagnostic.java
@@ -3,9 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.Resource.Origin;
+
/**
* Interface for all diagnostic message produced by D8 and R8.
*/
public interface Diagnostic {
+ Origin getOrigin();
+
String getDiagnosticMessage();
}
diff --git a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
index 3548644..8e69699 100644
--- a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
+++ b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.Resource.Origin;
+
/**
* A DiagnosticsHandler can be provided to customize handling of diagnostics information.
*
@@ -16,6 +18,11 @@
* @param warning Diagnostic containing warning information.
*/
default void warning(Diagnostic warning) {
+ if (warning.getOrigin() != Origin.unknown()) {
+ System.err.print("Warning in " + warning.getOrigin() + ":\n ");
+ } else {
+ System.err.print("Warning: ");
+ }
System.err.println(warning.getDiagnosticMessage());
}
@@ -25,6 +32,9 @@
* @param info Diagnostic containing the information.
*/
default void info(Diagnostic info) {
+ if (info.getOrigin() != Origin.unknown()) {
+ System.out.print("In " + info.getOrigin() + ":\n ");
+ }
System.out.println(info.getDiagnosticMessage());
}
}
diff --git a/src/main/java/com/android/tools/r8/Resource.java b/src/main/java/com/android/tools/r8/Resource.java
index 56b511d..b2bc53d 100644
--- a/src/main/java/com/android/tools/r8/Resource.java
+++ b/src/main/java/com/android/tools/r8/Resource.java
@@ -9,35 +9,176 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
/** Represents application resources. */
public abstract class Resource {
- /** Kind of the resource describing the resource content. */
- public enum Kind {
- DEX, CLASSFILE, VDEX
+
+ /**
+ * Origin description of a resource.
+ *
+ * <p>An origin is a list of parts that describe where a resource originates from. The first part
+ * is the most recent part and is associated with the present resource, each successive part is
+ * then associated with the context of the previous part.
+ *
+ * <p>For example, for a class file, say {@code my/class/Foo.class}, that is contained within a
+ * jar archive, say {@code myjar.jar}, the Origin of of this resource will be {@code
+ * myjar.jar:my/class/Foo.class} where each part is separated by a colon.
+ *
+ * <p>There are two top-most origins which have no parent: {@code Origin.root()} and {@code
+ * Origin.unknown()}. The former is the parent of any file path, while the latter is an unknown
+ * origin (e.g., for generated resources of raw bytes).
+ */
+ public abstract static class Origin implements Comparable<Origin> {
+
+ private static final Origin ROOT =
+ new Origin() {
+ @Override
+ public String part() {
+ return "";
+ }
+
+ @Override
+ List<String> buildParts(int size) {
+ return new ArrayList<>(size);
+ }
+ };
+
+ private static final Origin UNKNOWN =
+ new Origin() {
+ @Override
+ public String part() {
+ return "<unknown>";
+ }
+
+ @Override
+ List<String> buildParts(int size) {
+ List<String> parts = new ArrayList<>(size + 1);
+ parts.add(part());
+ return parts;
+ }
+ };
+
+ public static Origin root() {
+ return ROOT;
+ }
+
+ public static Origin unknown() {
+ return UNKNOWN;
+ }
+
+ private final Origin parent;
+
+ private Origin() {
+ this.parent = null;
+ }
+
+ protected Origin(Origin parent) {
+ assert parent != null;
+ this.parent = parent;
+ }
+
+ public abstract String part();
+
+ public Origin parent() {
+ return parent;
+ }
+
+ public List<String> parts() {
+ return buildParts(0);
+ }
+
+ List<String> buildParts(int size) {
+ List<String> parts = parent().buildParts(size + 1);
+ parts.add(part());
+ return parts;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof Origin)) {
+ return false;
+ }
+ Origin self = this;
+ Origin other = (Origin) obj;
+ while (self != null && other != null && self.part().equals(other.part())) {
+ self = self.parent();
+ other = other.parent();
+ }
+ return self == other;
+ }
+
+ @Override
+ public int compareTo(Origin other) {
+ // Lexicographic ordering from root to leaf.
+ List<String> thisParts = parts();
+ List<String> otherParts = other.parts();
+ int len = Math.min(thisParts.size(), otherParts.size());
+ for (int i = 0; i < len; i++) {
+ int compare = thisParts.get(i).compareTo(otherParts.get(i));
+ if (compare != 0) {
+ return compare;
+ }
+ }
+ return Integer.compare(thisParts.size(), otherParts.size());
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ for (String part : parts()) {
+ hash = 31 * hash + part.hashCode();
+ }
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return String.join(":", parts());
+ }
}
- protected Resource(Kind kind) {
- this.kind = kind;
+ /** Path component in an origin description. */
+ public static class PathOrigin extends Origin {
+ private final Path path;
+
+ public PathOrigin(Path path, Origin parent) {
+ super(parent);
+ assert path != null;
+ this.path = path;
+ }
+
+ @Override
+ public String part() {
+ return path.toString();
+ }
}
- /** Kind of the resource. */
- public final Kind kind;
+ /** Origin of the resource. */
+ public final Origin origin;
+
+ protected Resource(Origin origin) {
+ this.origin = origin;
+ }
/** Create an application resource for a given file. */
- public static Resource fromFile(Kind kind, Path file) {
- return new FileResource(kind, file);
+ public static Resource fromFile(Path file) {
+ return new FileResource(file);
}
/** Create an application resource for a given content. */
- public static Resource fromBytes(Kind kind, byte[] bytes) {
- return fromBytes(kind, bytes, null);
+ public static Resource fromBytes(Origin origin, byte[] bytes) {
+ return fromBytes(origin, bytes, null);
}
/** Create an application resource for a given content and type descriptor. */
- public static Resource fromBytes(Kind kind, byte[] bytes, Set<String> typeDescriptors) {
- return new ByteResource(kind, bytes, typeDescriptors);
+ public static Resource fromBytes(Origin origin, byte[] bytes, Set<String> typeDescriptors) {
+ return new ByteResource(origin, bytes, typeDescriptors);
}
/**
@@ -49,12 +190,16 @@
/** Get the resource as a stream. */
public abstract InputStream getStream() throws IOException;
- /** File based application resource. */
+ /**
+ * File-based application resource.
+ *
+ * <p>The origin of a file resource is the path of the file.
+ */
private static class FileResource extends Resource {
final Path file;
- FileResource(Kind kind, Path file) {
- super(kind);
+ FileResource(Path file) {
+ super(new PathOrigin(file, Origin.root()));
assert file != null;
this.file = file;
}
@@ -70,13 +215,18 @@
}
}
- /** Byte content based application resource. */
+ /**
+ * Byte-content based application resource.
+ *
+ * <p>The origin of a byte resource must be supplied upon construction. If no reasonable origin
+ * exits, use {@code Origin.unknown()}.
+ */
private static class ByteResource extends Resource {
final Set<String> classDescriptors;
final byte[] bytes;
- ByteResource(Kind kind, byte[] bytes, Set<String> classDescriptors) {
- super(kind);
+ ByteResource(Origin origin, byte[] bytes, Set<String> classDescriptors) {
+ super(origin);
assert bytes != null;
this.classDescriptors = classDescriptors;
this.bytes = bytes;
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index d389a8c..3e4d28d 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.graph.ClassKind.CLASSPATH;
import static com.android.tools.r8.graph.ClassKind.LIBRARY;
import static com.android.tools.r8.graph.ClassKind.PROGRAM;
-import static com.android.tools.r8.utils.FileUtils.DEFAULT_DEX_FILENAME;
import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.Resource;
@@ -24,10 +23,10 @@
import com.android.tools.r8.naming.ProguardMapReader;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DexVersion;
import com.android.tools.r8.utils.ClassProvider;
import com.android.tools.r8.utils.ClasspathClassCollection;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.DexVersion;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.LibraryClassCollection;
import com.android.tools.r8.utils.MainDexList;
@@ -167,7 +166,7 @@
try (InputStream is = input.getStream()) {
DexFile file = new DexFile(is);
computedMinApiLevel = verifyOrComputeMinApiLevel(computedMinApiLevel, file);
- fileReaders.add(new DexFileReader(file, classKind, itemFactory));
+ fileReaders.add(new DexFileReader(input.origin, file, classKind, itemFactory));
}
}
options.minApiLevel = computedMinApiLevel;
@@ -195,7 +194,7 @@
for (Resource input : classSources) {
futures.add(executorService.submit(() -> {
try (InputStream is = input.getStream()) {
- reader.read(DEFAULT_DEX_FILENAME, classKind, is);
+ reader.read(input.origin, classKind, is);
}
// No other way to have a void callable, but we want the IOException from the previous
// line to be wrapped into an ExecutionException.
diff --git a/src/main/java/com/android/tools/r8/dex/DexFileReader.java b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
index f3542be..8175834 100644
--- a/src/main/java/com/android/tools/r8/dex/DexFileReader.java
+++ b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
@@ -8,7 +8,8 @@
import static com.android.tools.r8.utils.EncodedValueUtils.parseSigned;
import static com.android.tools.r8.utils.EncodedValueUtils.parseUnsigned;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
+import com.android.tools.r8.Resource.PathOrigin;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.InstructionFactory;
import com.android.tools.r8.graph.ClassKind;
@@ -51,6 +52,7 @@
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.logging.Log;
+import com.android.tools.r8.utils.ProgramResource.Kind;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.ByteArrayOutputStream;
@@ -68,21 +70,22 @@
public class DexFileReader {
final int NO_INDEX = -1;
+ private final Origin origin;
private DexFile file;
private final Segment[] segments;
private int[] stringIDs;
private final ClassKind classKind;
public static Segment[] parseMapFrom(Path file) throws IOException {
- return parseMapFrom(new DexFile(file.toString()));
+ return parseMapFrom(new DexFile(file.toString()), new PathOrigin(file, Origin.root()));
}
- public static Segment[] parseMapFrom(InputStream stream) throws IOException {
- return parseMapFrom(new DexFile(stream));
+ public static Segment[] parseMapFrom(InputStream stream, Origin origin) throws IOException {
+ return parseMapFrom(new DexFile(stream), origin);
}
- private static Segment[] parseMapFrom(DexFile dex) {
- DexFileReader reader = new DexFileReader(dex, ClassKind.PROGRAM, new DexItemFactory());
+ private static Segment[] parseMapFrom(DexFile dex, Origin origin) {
+ DexFileReader reader = new DexFileReader(origin, dex, ClassKind.PROGRAM, new DexItemFactory());
return reader.segments;
}
@@ -107,7 +110,9 @@
// Factory to canonicalize certain dexitems.
private final DexItemFactory dexItemFactory;
- public DexFileReader(DexFile file, ClassKind classKind, DexItemFactory dexItemFactory) {
+ public DexFileReader(
+ Origin origin, DexFile file, ClassKind classKind, DexItemFactory dexItemFactory) {
+ this.origin = origin;
this.file = file;
this.dexItemFactory = dexItemFactory;
file.setByteOrder();
@@ -662,7 +667,8 @@
}
clazz = classKind.create(
type,
- Resource.Kind.DEX,
+ Kind.DEX,
+ origin,
flags,
superclass,
typeListAt(interfacesOffsets[i]),
diff --git a/src/main/java/com/android/tools/r8/graph/ClassKind.java b/src/main/java/com/android/tools/r8/graph/ClassKind.java
index 9298ba5..90644e5 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassKind.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassKind.java
@@ -1,6 +1,7 @@
package com.android.tools.r8.graph;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
+import com.android.tools.r8.utils.ProgramResource;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -11,11 +12,19 @@
LIBRARY(DexLibraryClass::new, DexClass::isLibraryClass);
private interface Factory {
- DexClass create(DexType type, Resource.Kind origin, DexAccessFlags accessFlags,
+ DexClass create(
+ DexType type,
+ ProgramResource.Kind kind,
+ Origin origin,
+ DexAccessFlags accessFlags,
DexType superType,
- DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
- DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
- DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods);
+ DexTypeList interfaces,
+ DexString sourceFile,
+ DexAnnotationSet annotations,
+ DexEncodedField[] staticFields,
+ DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods,
+ DexEncodedMethod[] virtualMethods);
}
private final Factory factory;
@@ -27,12 +36,31 @@
}
public DexClass create(
- DexType type, Resource.Kind origin, DexAccessFlags accessFlags, DexType superType,
- DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
- DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
- DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods) {
- return factory.create(type, origin, accessFlags, superType, interfaces, sourceFile,
- annotations, staticFields, instanceFields, directMethods, virtualMethods);
+ DexType type,
+ ProgramResource.Kind kind,
+ Origin origin,
+ DexAccessFlags accessFlags,
+ DexType superType,
+ DexTypeList interfaces,
+ DexString sourceFile,
+ DexAnnotationSet annotations,
+ DexEncodedField[] staticFields,
+ DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods,
+ DexEncodedMethod[] virtualMethods) {
+ return factory.create(
+ type,
+ kind,
+ origin,
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ annotations,
+ staticFields,
+ instanceFields,
+ directMethods,
+ virtualMethods);
}
public boolean isOfKind(DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index e5d4a56..8f3a923 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
@@ -17,7 +17,7 @@
private static final DexEncodedMethod[] NO_METHODS = {};
private static final DexEncodedField[] NO_FIELDS = {};
- public final Resource.Kind origin;
+ public final Origin origin;
public final DexType type;
public final DexAccessFlags accessFlags;
public DexType superType;
@@ -30,10 +30,17 @@
public DexAnnotationSet annotations;
public DexClass(
- DexString sourceFile, DexTypeList interfaces, DexAccessFlags accessFlags, DexType superType,
- DexType type, DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
- DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods,
- DexAnnotationSet annotations, Resource.Kind origin) {
+ DexString sourceFile,
+ DexTypeList interfaces,
+ DexAccessFlags accessFlags,
+ DexType superType,
+ DexType type,
+ DexEncodedField[] staticFields,
+ DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods,
+ DexEncodedMethod[] virtualMethods,
+ DexAnnotationSet annotations,
+ Origin origin) {
this.origin = origin;
this.sourceFile = sourceFile;
this.interfaces = interfaces;
@@ -215,7 +222,7 @@
.orElse(null);
}
- public Resource.Kind getOrigin() {
+ public Origin getOrigin() {
return this.origin;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
index 27ab302..d39763e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClasspathClass.java
@@ -3,20 +3,32 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.ProgramResource;
+import com.android.tools.r8.utils.ProgramResource.Kind;
import java.util.function.Supplier;
public class DexClasspathClass extends DexClass implements Supplier<DexClasspathClass> {
- public DexClasspathClass(DexType type, Resource.Kind origin, DexAccessFlags accessFlags,
- DexType superType, DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
- DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
- DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods) {
+ public DexClasspathClass(
+ DexType type,
+ ProgramResource.Kind kind,
+ Origin origin,
+ DexAccessFlags accessFlags,
+ DexType superType,
+ DexTypeList interfaces,
+ DexString sourceFile,
+ DexAnnotationSet annotations,
+ DexEncodedField[] staticFields,
+ DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods,
+ DexEncodedMethod[] virtualMethods) {
super(sourceFile, interfaces, accessFlags, superType, type,
staticFields, instanceFields, directMethods, virtualMethods, annotations, origin);
+ assert kind == Kind.CLASS : "Invalid kind " + kind + " for class-path class " + type;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
index ffff701..3c9cbdd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexLibraryClass.java
@@ -3,18 +3,29 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.ProgramResource;
+import com.android.tools.r8.utils.ProgramResource.Kind;
import java.util.function.Supplier;
public class DexLibraryClass extends DexClass implements Supplier<DexLibraryClass> {
- public DexLibraryClass(DexType type, Resource.Kind origin, DexAccessFlags accessFlags,
- DexType superType, DexTypeList interfaces, DexString sourceFile, DexAnnotationSet annotations,
- DexEncodedField[] staticFields, DexEncodedField[] instanceFields,
- DexEncodedMethod[] directMethods, DexEncodedMethod[] virtualMethods) {
+ public DexLibraryClass(
+ DexType type,
+ ProgramResource.Kind kind,
+ Origin origin,
+ DexAccessFlags accessFlags,
+ DexType superType,
+ DexTypeList interfaces,
+ DexString sourceFile,
+ DexAnnotationSet annotations,
+ DexEncodedField[] staticFields,
+ DexEncodedField[] instanceFields,
+ DexEncodedMethod[] directMethods,
+ DexEncodedMethod[] virtualMethods) {
super(sourceFile, interfaces, accessFlags, superType, type,
staticFields, instanceFields, directMethods, virtualMethods, annotations, origin);
// Set all static field values to unknown. We don't want to use the value from the library
@@ -22,6 +33,7 @@
for (DexEncodedField staticField : staticFields) {
staticField.staticValue = DexValue.UNKNOWN;
}
+ assert kind == Kind.CLASS : "Invalid kind " + kind + " for library-path class " + type;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 4332df8..3c9c796 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.utils.ProgramResource;
+import com.android.tools.r8.utils.ProgramResource.Kind;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -15,12 +17,14 @@
import java.util.function.Supplier;
public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {
-
+ private final ProgramResource.Kind originKind;
private DexEncodedArray staticValues;
private final Collection<DexProgramClass> synthesizedFrom;
- public DexProgramClass(DexType type,
- Resource.Kind origin,
+ public DexProgramClass(
+ DexType type,
+ ProgramResource.Kind originKind,
+ Origin origin,
DexAccessFlags accessFlags,
DexType superType,
DexTypeList interfaces,
@@ -30,7 +34,9 @@
DexEncodedField[] instanceFields,
DexEncodedMethod[] directMethods,
DexEncodedMethod[] virtualMethods) {
- this(type,
+ this(
+ type,
+ originKind,
origin,
accessFlags,
superType,
@@ -44,8 +50,10 @@
Collections.emptyList());
}
- public DexProgramClass(DexType type,
- Resource.Kind origin,
+ public DexProgramClass(
+ DexType type,
+ ProgramResource.Kind originKind,
+ Origin origin,
DexAccessFlags accessFlags,
DexType superType,
DexTypeList interfaces,
@@ -59,9 +67,18 @@
super(sourceFile, interfaces, accessFlags, superType, type, staticFields,
instanceFields, directMethods, virtualMethods, classAnnotations, origin);
assert classAnnotations != null;
+ this.originKind = originKind;
this.synthesizedFrom = accumulateSynthesizedFrom(new HashSet<>(), synthesizedDirectlyFrom);
}
+ public boolean originatesFromDexResource() {
+ return originKind == Kind.DEX;
+ }
+
+ public boolean originatesFromClassResource() {
+ return originKind == Kind.CLASS;
+ }
+
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems) {
if (indexedItems.addClass(this)) {
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index a90373e..001480f 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -7,7 +7,7 @@
import static org.objectweb.asm.Opcodes.ACC_DEPRECATED;
import static org.objectweb.asm.Opcodes.ASM6;
-import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
@@ -26,6 +26,7 @@
import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.graph.JarCode.ReparseContext;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ProgramResource.Kind;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -60,10 +61,10 @@
this.classConsumer = classConsumer;
}
- public void read(String file, ClassKind classKind, InputStream input) throws IOException {
+ public void read(Origin origin, ClassKind classKind, InputStream input) throws IOException {
ClassReader reader = new ClassReader(input);
reader.accept(new CreateDexClassVisitor(
- file, classKind, reader.b, application, classConsumer), SKIP_FRAMES);
+ origin, classKind, reader.b, application, classConsumer), SKIP_FRAMES);
}
private static DexAccessFlags createAccessFlags(int access) {
@@ -93,7 +94,7 @@
}
private static class CreateDexClassVisitor extends ClassVisitor {
- private final String file;
+ private final Origin origin;
private final ClassKind classKind;
private final JarApplicationReader application;
private final Consumer<DexClass> classConsumer;
@@ -116,13 +117,13 @@
private final List<DexEncodedMethod> virtualMethods = new ArrayList<>();
public CreateDexClassVisitor(
- String file,
+ Origin origin,
ClassKind classKind,
byte[] classCache,
JarApplicationReader application,
Consumer<DexClass> classConsumer) {
super(ASM6);
- this.file = file;
+ this.origin = origin;
this.classKind = classKind;
this.classConsumer = classConsumer;
this.context.classCache = classCache;
@@ -248,7 +249,8 @@
}
DexClass clazz = classKind.create(
type,
- Resource.Kind.CLASSFILE,
+ Kind.CLASS,
+ origin,
accessFlags,
superType,
interfaces,
@@ -512,7 +514,7 @@
if (!flags.isAbstract()
&& !flags.isNative()
&& parent.classKind == ClassKind.PROGRAM) {
- code = new JarCode(method, parent.context, parent.application);
+ code = new JarCode(method, parent.origin, parent.context, parent.application);
}
DexAnnotationSetRefList parameterAnnotationSets;
if (parameterAnnotations == null) {
@@ -529,11 +531,8 @@
&& internalOptions.canUseParameterNameAnnotations()) {
assert parameterFlags != null;
if (parameterNames.size() != parameterCount) {
- internalOptions.warningInvalidParameterAnnotations =
- "Invalid parameter count in MethodParameters attributes of "
- + method.toSourceString() + " from '" + parent.file + "'. Found "
- + parameterNames.size() + " while expecting " + parameterCount + "."
- + " This is likely due to proguard having removed a parameter.";
+ internalOptions.warningInvalidParameterAnnotations(
+ method, parent.origin, parameterCount, parameterNames.size());
}
getAnnotations().add(DexAnnotation.createMethodParametersAnnotation(
parameterNames.toArray(new DexValue[parameterNames.size()]),
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 39c580e..5988ae5 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.ApiLevelException;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.ValueNumberGenerator;
@@ -37,13 +38,16 @@
}
private final DexType clazz;
+ private final Origin origin;
private MethodNode node;
private ReparseContext context;
private final JarApplicationReader application;
- public JarCode(DexMethod method, ReparseContext context, JarApplicationReader application) {
+ public JarCode(
+ DexMethod method, Origin origin, ReparseContext context, JarApplicationReader application) {
this.clazz = method.getHolder();
+ this.origin = origin;
this.context = context;
this.application = application;
context.lookupMap.put(method, this);
@@ -105,7 +109,7 @@
try {
return internalBuild(encodedMethod, generator, options);
} catch (InvalidDebugInfoException e) {
- options.warningInvalidDebugInfo(encodedMethod, e);
+ options.warningInvalidDebugInfo(encodedMethod, origin, e);
node.localVariables.clear();
return internalBuild(encodedMethod, generator, options);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index d3964d1..09371f7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -273,15 +273,7 @@
DefaultMethodsHelper helper = new DefaultMethodsHelper();
DexClass definedInterface = rewriter.findDefinitionFor(iface);
if (definedInterface == null) {
- String message = "Interface `" + iface.toSourceString()
- + "` not found. It's needed to make sure desugaring of `"
- + classToDesugar.toSourceString() + "` is correct. Desugaring will assume that this"
- + " interface has no default method";
- if (classToDesugar != implementing) {
- message += ". This missing interface is declared in the direct hierarchy of `"
- + implementing.toString() + "`";
- }
- rewriter.warnMissingClass(iface, message);
+ rewriter.warnMissingInterface(classToDesugar, implementing, iface);
return helper.wrapInCollection();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index a851831..2c43bd7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.ApiLevelException;
-import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
@@ -127,7 +126,7 @@
// NOTE: leave unchanged those calls to undefined targets. This may lead to runtime
// exception but we can not report it as error since it can also be the intended
// behavior.
- warnMissingClass(encodedMethod.method, method.holder);
+ warnMissingType(encodedMethod.method, method.holder);
} else if (clazz.isInterface() && !clazz.isLibraryClass()) {
// NOTE: we intentionally don't desugar static calls into static interface
// methods coming from android.jar since it is only possible in case v24+
@@ -149,7 +148,7 @@
// NOTE: leave unchanged those calls to undefined targets. This may lead to runtime
// exception but we can not report it as error since it can also be the intended
// behavior.
- warnMissingClass(encodedMethod.method, method.holder);
+ warnMissingType(encodedMethod.method, method.holder);
} else if (clazz != null && (clazz.isInterface() && !clazz.isLibraryClass())) {
// NOTE: we intentionally don't desugar super calls into interface methods
// coming from android.jar since it is only possible in case v24+ version
@@ -171,7 +170,7 @@
// NOTE: If the class definition is missing we can't check. Let it be handled as any other
// missing call target.
if (holderClass == null) {
- warnMissingClass(referencedFrom, handle.asMethod().holder);
+ warnMissingType(referencedFrom, handle.asMethod().holder);
} else if (holderClass.isInterface()) {
throw new Unimplemented(
"Desugaring of static interface method handle as in `"
@@ -249,7 +248,7 @@
private static boolean shouldProcess(
DexProgramClass clazz, Flavor flavour, boolean mustBeInterface) {
- return (clazz.getOrigin() != Resource.Kind.DEX || flavour == Flavor.IncludeAllResources)
+ return (!clazz.originatesFromDexResource() || flavour == Flavor.IncludeAllResources)
&& clazz.isInterface() == mustBeInterface;
}
@@ -294,17 +293,44 @@
return true;
}
- void warnMissingClass(DexType missing, String message) {
- // TODO replace by a proper warning mechanic (see b/65154707).
+ public void warnMissingInterface(
+ DexClass classToDesugar, DexClass implementing, DexType missing) {
// TODO think about using a common deduplicating mechanic with Enqueuer
- if (reportedMissing.add(missing)) {
- options.diagnosticsHandler.warning(new StringDiagnostic(message));
+ if (!reportedMissing.add(missing)) {
+ return;
}
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append("Interface `")
+ .append(missing.toSourceString())
+ .append("` not found. It's needed to make sure desugaring of `")
+ .append(classToDesugar.toSourceString())
+ .append("` is correct. Desugaring will assume that this interface has no default method.");
+ if (classToDesugar != implementing) {
+ builder
+ .append(" This missing interface is declared in the direct hierarchy of `")
+ .append(implementing)
+ .append("`");
+ }
+ options.diagnosticsHandler.warning(
+ new StringDiagnostic(classToDesugar.getOrigin(), builder.toString()));
}
- private void warnMissingClass(DexItem referencedFrom, DexType clazz) {
- warnMissingClass(clazz,
- "Type `" + clazz.toSourceString() + "` was not found, it is required for default or"
- + " static interface methods desugaring of `" + referencedFrom.toSourceString() + "`");
+ private void warnMissingType(DexMethod referencedFrom, DexType missing) {
+ // TODO think about using a common deduplicating mechanic with Enqueuer
+ if (!reportedMissing.add(missing)) {
+ return;
+ }
+ StringBuilder builder = new StringBuilder();
+ builder
+ .append("Type `")
+ .append(missing.toSourceString())
+ .append("` was not found, ")
+ .append("it is required for default or static interface methods desugaring of `")
+ .append(referencedFrom.toSourceString())
+ .append("`");
+ DexClass referencedFromClass = converter.appInfo.definitionFor(referencedFrom.getHolder());
+ options.diagnosticsHandler.warning(
+ new StringDiagnostic(referencedFromClass.getOrigin(), builder.toString()));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 02d6dc9..fb3507b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -128,6 +128,7 @@
DexProgramClass companionClass = new DexProgramClass(
companionClassType,
null,
+ null,
companionClassFlags,
rewriter.factory.objectType,
DexTypeList.empty(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 0fe0f99..569d088 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -120,6 +120,7 @@
return new DexProgramClass(
type,
null,
+ null,
new DexAccessFlags(Constants.ACC_FINAL | Constants.ACC_SYNTHETIC),
rewriter.factory.objectType,
buildInterfaces(),
@@ -129,8 +130,7 @@
synthesizeInstanceFields(),
synthesizeDirectMethods(),
synthesizeVirtualMethods(),
- synthesizedFrom
- );
+ synthesizedFrom);
}
final DexField getCaptureField(int index) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 49dcb45..35d2e14 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -1075,6 +1075,7 @@
DexProgramClass clazz = new DexProgramClass(
type,
null,
+ null,
accessFlags,
superType,
interfaces,
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 80a2393..3cfcc92 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -11,12 +11,13 @@
import com.android.tools.r8.ArchiveClassFileProvider;
import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.Resource;
-import com.android.tools.r8.Resource.Kind;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.VDexFile;
import com.android.tools.r8.dex.VDexFileReader;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.shaking.FilteredClassPath;
+import com.android.tools.r8.utils.ProgramResource.Kind;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.ByteStreams;
@@ -55,7 +56,7 @@
public static final String DEFAULT_PROGUARD_MAP_FILE = "proguard.map";
- private final ImmutableList<Resource> programResources;
+ private final ImmutableList<ProgramResource> programResources;
private final ImmutableMap<Resource, String> programResourcesMainDescriptor;
private final ImmutableList<ClassFileResourceProvider> classpathResourceProviders;
private final ImmutableList<ClassFileResourceProvider> libraryResourceProviders;
@@ -70,7 +71,7 @@
// See factory methods and AndroidApp.Builder below.
private AndroidApp(
- ImmutableList<Resource> programResources,
+ ImmutableList<ProgramResource> programResources,
ImmutableMap<Resource, String> programResourcesMainDescriptor,
ImmutableList<ProgramFileArchiveReader> programFileArchiveReaders,
ImmutableList<ClassFileResourceProvider> classpathResourceProviders,
@@ -159,11 +160,11 @@
/** Get input streams for all dex program resources. */
public List<Resource> getDexProgramResources() throws IOException {
- List<Resource> dexResources = filter(programResources, Resource.Kind.DEX);
+ List<Resource> dexResources = filter(programResources, Kind.DEX);
for (Resource resource : filter(programResources, Kind.VDEX)) {
VDexFileReader reader = new VDexFileReader(new VDexFile(resource));
dexResources.addAll(reader.getDexFiles().stream()
- .map(bytes -> Resource.fromBytes(Kind.DEX, bytes))
+ .map(bytes -> Resource.fromBytes(resource.origin, bytes))
.collect(Collectors.toList()));
}
for (ProgramFileArchiveReader reader : programFileArchiveReaders) {
@@ -174,12 +175,12 @@
public List<Resource> getDexProgramResourcesForOutput() {
assert programFileArchiveReaders.isEmpty();
- return filter(programResources, Resource.Kind.DEX);
+ return filter(programResources, Kind.DEX);
}
/** Get input streams for all Java-bytecode program resources. */
public List<Resource> getClassProgramResources() throws IOException {
- List<Resource> classResources = filter(programResources, Resource.Kind.CLASSFILE);
+ List<Resource> classResources = filter(programResources, Kind.CLASS);
for (ProgramFileArchiveReader reader : programFileArchiveReaders) {
classResources.addAll(reader.getClassProgramResources());
}
@@ -200,11 +201,11 @@
return programFileArchiveReaders;
}
- private List<Resource> filter(List<Resource> resources, Resource.Kind kind) {
+ private List<Resource> filter(List<ProgramResource> resources, Kind kind) {
List<Resource> out = new ArrayList<>(resources.size());
- for (Resource resource : resources) {
- if (kind == resource.kind) {
- out.add(resource);
+ for (ProgramResource code : resources) {
+ if (code.kind == kind) {
+ out.add(code.resource);
}
}
return out;
@@ -440,7 +441,7 @@
*/
public static class Builder {
- private final List<Resource> programResources = new ArrayList<>();
+ private final List<ProgramResource> programResources = new ArrayList<>();
private final Map<Resource, String> programResourcesMainDescriptor = new HashMap<>();
private final List<ProgramFileArchiveReader> programFileArchiveReaders = new ArrayList<>();
private final List<ClassFileResourceProvider> classpathResourceProviders = new ArrayList<>();
@@ -566,8 +567,7 @@
* Add dex program-data with class descriptor.
*/
public Builder addDexProgramData(byte[] data, Set<String> classDescriptors) {
- programResources.add(
- Resource.fromBytes(Resource.Kind.DEX, data, classDescriptors));
+ addProgramResources(Kind.DEX, Resource.fromBytes(Origin.unknown(), data, classDescriptors));
return this;
}
@@ -578,8 +578,8 @@
byte[] data,
Set<String> classDescriptors,
String primaryClassDescriptor) {
- Resource resource = Resource.fromBytes(Resource.Kind.DEX, data, classDescriptors);
- programResources.add(resource);
+ Resource resource = Resource.fromBytes(Origin.unknown(), data, classDescriptors);
+ addProgramResources(Kind.DEX, resource);
programResourcesMainDescriptor.put(resource, primaryClassDescriptor);
return this;
}
@@ -596,7 +596,7 @@
*/
public Builder addDexProgramData(Collection<byte[]> data) {
for (byte[] datum : data) {
- programResources.add(Resource.fromBytes(Resource.Kind.DEX, datum));
+ addProgramResources(Kind.DEX, Resource.fromBytes(Origin.unknown(), datum));
}
return this;
}
@@ -613,12 +613,19 @@
*/
public Builder addClassProgramData(Collection<byte[]> data) {
for (byte[] datum : data) {
- programResources.add(Resource.fromBytes(Resource.Kind.CLASSFILE, datum));
+ addProgramResources(Kind.CLASS, Resource.fromBytes(Origin.unknown(), datum));
}
return this;
}
/**
+ * Add Java-bytecode program data.
+ */
+ public Builder addClassProgramData(Origin origin, byte[] data) {
+ return addProgramResources(Kind.CLASS, Resource.fromBytes(origin, data));
+ }
+
+ /**
* Set dead-code data.
*/
public Builder setDeadCode(byte[] content) {
@@ -639,7 +646,7 @@
* Set proguard-map file.
*/
public Builder setProguardMapFile(Path file) {
- proguardMap = file == null ? null : Resource.fromFile(null, file);
+ proguardMap = file == null ? null : Resource.fromFile(file);
return this;
}
@@ -680,12 +687,11 @@
}
// TODO(sgjesse): Should we just read the file here? This will sacrifice the parallelism
// in ApplicationReader where all input resources are read in parallel.
- mainDexListResources.add(Resource.fromFile(null, file));
+ mainDexListResources.add(Resource.fromFile(file));
}
return this;
}
-
/**
* Add main-dex classes.
*/
@@ -758,11 +764,11 @@
throw new FileNotFoundException("Non-existent input file: " + file);
}
if (isDexFile(file)) {
- programResources.add(Resource.fromFile(Resource.Kind.DEX, file));
+ addProgramResources(Kind.DEX, Resource.fromFile(file));
} else if (isVDexFile(file) && isVdexAllowed()) {
- programResources.add(Resource.fromFile(Resource.Kind.VDEX, file));
+ addProgramResources(Kind.VDEX, Resource.fromFile(file));
} else if (isClassFile(file)) {
- programResources.add(Resource.fromFile(Resource.Kind.CLASSFILE, file));
+ addProgramResources(Kind.CLASS, Resource.fromFile(file));
} else if (isArchive(file)) {
programFileArchiveReaders
.add(new ProgramFileArchiveReader(filteredClassPath, ignoreDexInArchive));
@@ -771,6 +777,17 @@
}
}
+ private Builder addProgramResources(ProgramResource.Kind kind, Resource... resources) {
+ return addProgramResources(kind, Arrays.asList(resources));
+ }
+
+ private Builder addProgramResources(ProgramResource.Kind kind, Collection<Resource> resources) {
+ for (Resource resource : resources) {
+ programResources.add(new ProgramResource(kind, resource));
+ }
+ return this;
+ }
+
private void addClassProvider(FilteredClassPath classPath,
List<ClassFileResourceProvider> providerList)
throws IOException {
diff --git a/src/main/java/com/android/tools/r8/utils/ClassProvider.java b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
index 63a847a..5ad270b 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassProvider.java
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-import static com.android.tools.r8.utils.FileUtils.DEFAULT_DEX_FILENAME;
-
import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.CompilationError;
@@ -100,7 +98,7 @@
try (Closer closer = Closer.create()) {
JarClassFileReader classReader =
new JarClassFileReader(reader, classKind.bridgeConsumer(classConsumer));
- classReader.read(DEFAULT_DEX_FILENAME, classKind, closer.register(resource.getStream()));
+ classReader.read(resource.origin, classKind, closer.register(resource.getStream()));
} catch (IOException e) {
throw new CompilationError("Failed to load class: " + descriptor, e);
}
diff --git a/src/main/java/com/android/tools/r8/utils/DirectoryClassFileProvider.java b/src/main/java/com/android/tools/r8/utils/DirectoryClassFileProvider.java
index 7de53d2..eba7f8e 100644
--- a/src/main/java/com/android/tools/r8/utils/DirectoryClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/DirectoryClassFileProvider.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.Resource;
import com.google.common.collect.Sets;
import java.io.File;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
@@ -57,11 +58,9 @@
// Build expected file path based on type descriptor.
String classBinaryName = DescriptorUtils.getClassBinaryNameFromDescriptor(descriptor);
- Path filePath = root.resolve(classBinaryName + CLASS_EXTENSION);
- File file = filePath.toFile();
+ Path file = root.resolve(classBinaryName + CLASS_EXTENSION);
- return (file.exists() && !file.isDirectory())
- ? Resource.fromFile(Resource.Kind.CLASSFILE, filePath) : null;
+ return (Files.exists(file) && !Files.isDirectory(file)) ? Resource.fromFile(file) : null;
}
/** Create resource provider from directory path. */
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java
index 3eaa2be..d2a4239 100644
--- a/src/main/java/com/android/tools/r8/utils/FileUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -25,7 +25,6 @@
public static final String VDEX_EXTENSION = ".vdex";
public static final String JAR_EXTENSION = ".jar";
public static final String ZIP_EXTENSION = ".zip";
- public static final String DEFAULT_DEX_FILENAME = "classes.dex";
public static final String JAVA_EXTENSION = ".java";
public static boolean isDexFile(Path path) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 8145bb3..dd0a60c 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -4,17 +4,23 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.Resource.Origin;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
import java.util.function.Function;
public class InternalOptions {
@@ -118,11 +124,24 @@
public ImmutableList<ProguardConfigurationRule> mainDexKeepRules = ImmutableList.of();
public boolean minimalMainDex;
- public String warningInvalidParameterAnnotations = null;
+ public static class InvalidParameterAnnotationInfo {
+ final DexMethod method;
+ final int expectedParameterCount;
+ final int actualParameterCount;
+
+ public InvalidParameterAnnotationInfo(
+ DexMethod method, int expectedParameterCount, int actualParameterCount) {
+ this.method = method;
+ this.expectedParameterCount = expectedParameterCount;
+ this.actualParameterCount = actualParameterCount;
+ }
+ }
public boolean warningMissingEnclosingMember = false;
- public int warningInvalidDebugInfoCount = 0;
+ private Map<Origin, List<InvalidParameterAnnotationInfo>> warningInvalidParameterAnnotations;
+
+ private Map<Origin, List<DexEncodedMethod>> warningInvalidDebugInfo;
// Don't read code from dex files. Used to extract non-code information from vdex files where
// the code contains unsupported byte codes.
@@ -132,23 +151,66 @@
public DiagnosticsHandler diagnosticsHandler = new DefaultDiagnosticsHandler();
- public void warningInvalidDebugInfo(DexEncodedMethod method, InvalidDebugInfoException e) {
- warningInvalidDebugInfoCount++;
+ public void warningInvalidParameterAnnotations(
+ DexMethod method, Origin origin, int expected, int actual) {
+ if (warningInvalidParameterAnnotations == null) {
+ warningInvalidParameterAnnotations = new HashMap<>();
+ }
+ warningInvalidParameterAnnotations
+ .computeIfAbsent(origin, k -> new ArrayList<>())
+ .add(new InvalidParameterAnnotationInfo(method, expected, actual));
+ }
+
+ public void warningInvalidDebugInfo(
+ DexEncodedMethod method, Origin origin, InvalidDebugInfoException e) {
+ if (warningInvalidDebugInfo == null) {
+ warningInvalidDebugInfo = new HashMap<>();
+ }
+ warningInvalidDebugInfo.computeIfAbsent(origin, k -> new ArrayList<>()).add(method);
}
public boolean printWarnings() {
boolean printed = false;
boolean printOutdatedToolchain = false;
if (warningInvalidParameterAnnotations != null) {
+ // TODO(b/67626202): Add a regression test with a program that hits this issue.
diagnosticsHandler.warning(
- new StringDiagnostic(warningInvalidParameterAnnotations));
+ new StringDiagnostic(
+ "Invalid parameter counts in MethodParameter attributes. "
+ + "This is likely due to Proguard having removed a parameter."));
+ for (Origin origin : new TreeSet<>(warningInvalidParameterAnnotations.keySet())) {
+ StringBuilder builder =
+ new StringBuilder("Methods with invalid MethodParameter attributes:");
+ for (InvalidParameterAnnotationInfo info : warningInvalidParameterAnnotations.get(origin)) {
+ builder
+ .append("\n ")
+ .append(info.method)
+ .append(" expected count: ")
+ .append(info.expectedParameterCount)
+ .append(" actual count: ")
+ .append(info.actualParameterCount);
+ }
+ diagnosticsHandler.info(new StringDiagnostic(origin, builder.toString()));
+ }
printed = true;
}
- if (warningInvalidDebugInfoCount > 0) {
+ if (warningInvalidDebugInfo != null) {
+ int count = 0;
+ for (List<DexEncodedMethod> methods : warningInvalidDebugInfo.values()) {
+ count += methods.size();
+ }
diagnosticsHandler.warning(
- new StringDiagnostic("Stripped invalid locals information from "
- + warningInvalidDebugInfoCount
- + (warningInvalidDebugInfoCount == 1 ? " method." : " methods.")));
+ new StringDiagnostic(
+ "Stripped invalid locals information from "
+ + count
+ + (count == 1 ? " method." : " methods.")));
+ for (Origin origin : new TreeSet<>(warningInvalidDebugInfo.keySet())) {
+ StringBuilder builder = new StringBuilder("Methods with invalid locals information:");
+ for (DexEncodedMethod method : warningInvalidDebugInfo.get(origin)) {
+ builder.append("\n ").append(method.toSourceString());
+ }
+ diagnosticsHandler.info(new StringDiagnostic(origin, builder.toString()));
+ }
printed = true;
printOutdatedToolchain = true;
}
@@ -161,7 +223,7 @@
printOutdatedToolchain = true;
}
if (printOutdatedToolchain) {
- diagnosticsHandler.warning(
+ diagnosticsHandler.info(
new StringDiagnostic(
"Some warnings are typically a sign of using an outdated Java toolchain."
+ " To fix, recompile the source with an updated toolchain."));
diff --git a/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java b/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
index c94d7be..863cce0 100644
--- a/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/LibraryClassCollection.java
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-import com.android.tools.r8.Resource;
-import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexLibraryClass;
@@ -19,11 +17,6 @@
@Override
DexLibraryClass resolveClassConflict(DexLibraryClass a, DexLibraryClass b) {
- if (a.origin != Resource.Kind.CLASSFILE || b.origin != Resource.Kind.CLASSFILE) {
- // We only support conflicts for classes both coming from jar files.
- throw new CompilationError(
- "Library type already present: " + a.type.toSourceString());
- }
if (Log.ENABLED) {
Log.warn(DexApplication.class,
"Class `%s` was specified twice as a library type.", a.type.toSourceString());
diff --git a/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java b/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java
index 51aa312..cc9c1e3 100644
--- a/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java
+++ b/src/main/java/com/android/tools/r8/utils/OneShotByteResource.java
@@ -14,8 +14,8 @@
private byte[] bytes;
private final Set<String> classDescriptors;
- OneShotByteResource(Kind kind, byte[] bytes, Set<String> classDescriptors) {
- super(kind);
+ OneShotByteResource(Origin origin, byte[] bytes, Set<String> classDescriptors) {
+ super(origin);
assert bytes != null;
this.bytes = bytes;
this.classDescriptors = classDescriptors;
diff --git a/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java b/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
index 3f402d0..01ea7ba 100644
--- a/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
+++ b/src/main/java/com/android/tools/r8/utils/PreloadedClassFileProvider.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
import com.google.common.collect.Sets;
import java.util.Collections;
import java.util.HashMap;
@@ -16,6 +17,20 @@
*/
public final class PreloadedClassFileProvider implements ClassFileResourceProvider {
+ private static class ClassDescriptorOrigin extends Origin {
+ private final String descriptor;
+
+ public ClassDescriptorOrigin(String descriptor) {
+ super(Origin.unknown());
+ this.descriptor = descriptor;
+ }
+
+ @Override
+ public String part() {
+ return descriptor;
+ }
+ }
+
private final Map<String, byte[]> content;
private PreloadedClassFileProvider(Map<String, byte[]> content) {
@@ -33,7 +48,8 @@
if (bytes == null) {
return null;
}
- return Resource.fromBytes(Resource.Kind.CLASSFILE, bytes, Collections.singleton(descriptor));
+ return Resource.fromBytes(
+ new ClassDescriptorOrigin(descriptor), bytes, Collections.singleton(descriptor));
}
public static ClassFileResourceProvider fromClassData(String descriptor, byte[] data) {
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index 590ba83..17ca1a9 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils;
-import com.android.tools.r8.Resource;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexProgramClass;
@@ -50,8 +49,8 @@
private static DexProgramClass resolveClassConflictImpl(DexProgramClass a, DexProgramClass b) {
// Currently only allow collapsing synthetic lambda classes.
- if (a.getOrigin() == Resource.Kind.DEX
- && b.getOrigin() == Resource.Kind.DEX
+ if (a.originatesFromDexResource()
+ && b.originatesFromDexResource()
&& a.accessFlags.isSynthetic()
&& b.accessFlags.isSynthetic()
&& LambdaRewriter.hasLambdaClassPrefix(a.type)
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java b/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
index f33bf77..2cce6da 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramFileArchiveReader.java
@@ -8,6 +8,8 @@
import static com.android.tools.r8.utils.FileUtils.isDexFile;
import com.android.tools.r8.Resource;
+import com.android.tools.r8.Resource.Origin;
+import com.android.tools.r8.Resource.PathOrigin;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.shaking.FilteredClassPath;
import com.google.common.io.ByteStreams;
@@ -26,12 +28,14 @@
public class ProgramFileArchiveReader {
+ private final Origin origin;
private final FilteredClassPath archive;
private boolean ignoreDexInArchive;
private List<Resource> dexResources = null;
private List<Resource> classResources = null;
ProgramFileArchiveReader(FilteredClassPath archive, boolean ignoreDexInArchive) {
+ origin = new PathOrigin(archive.getPath(), Origin.root());
this.archive = archive;
this.ignoreDexInArchive = ignoreDexInArchive;
}
@@ -46,18 +50,23 @@
ZipEntry entry = entries.nextElement();
try (InputStream stream = zipFile.getInputStream(entry)) {
Path name = Paths.get(entry.getName());
+ Origin entryOrigin = new PathOrigin(name, origin);
if (archive.matchesFile(name)) {
if (isDexFile(name)) {
if (!ignoreDexInArchive) {
Resource resource =
- new OneShotByteResource(Resource.Kind.DEX, ByteStreams.toByteArray(stream),
+ new OneShotByteResource(
+ entryOrigin,
+ ByteStreams.toByteArray(stream),
null);
dexResources.add(resource);
}
} else if (isClassFile(name)) {
String descriptor = DescriptorUtils.guessTypeDescriptor(name);
- Resource resource = new OneShotByteResource(Resource.Kind.CLASSFILE,
- ByteStreams.toByteArray(stream), Collections.singleton(descriptor));
+ Resource resource = new OneShotByteResource(
+ entryOrigin,
+ ByteStreams.toByteArray(stream),
+ Collections.singleton(descriptor));
classResources.add(resource);
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramResource.java b/src/main/java/com/android/tools/r8/utils/ProgramResource.java
new file mode 100644
index 0000000..0cbf11e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ProgramResource.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.utils;
+
+import com.android.tools.r8.Resource;
+
+// A program resource can come from either DEX or Java-bytecode source. Currently we only support
+// Java-bytecode sources for classpath and library inputs. The occurance of VDEX here is to allow
+// toolings to read in VDEX sources (eg, the Marker extraction tool).
+public class ProgramResource {
+ public enum Kind {
+ DEX,
+ CLASS,
+ VDEX
+ }
+
+ public final Kind kind;
+ public final Resource resource;
+
+ ProgramResource(Kind kind, Resource resource) {
+ this.kind = kind;
+ this.resource = resource;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
index 9c690ff..b2add4a 100644
--- a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
@@ -4,15 +4,27 @@
package com.android.tools.r8.utils;
import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.Resource.Origin;
public class StringDiagnostic implements Diagnostic {
+ private final Origin origin;
private final String message;
public StringDiagnostic(String message) {
+ this(Origin.unknown(), message);
+ }
+
+ public StringDiagnostic(Origin origin, String message) {
+ this.origin = origin;
this.message = message;
}
@Override
+ public Origin getOrigin() {
+ return origin;
+ }
+
+ @Override
public String getDiagnosticMessage() {
return message;
}
diff --git a/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java b/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java
index 239e4fd..f0c882f 100644
--- a/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java
@@ -16,7 +16,6 @@
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-
public class R8CodeCanonicalizationTest {
private static final String SOURCE_DEX = "invokeempty/classes.dex";
diff --git a/src/test/java/com/android/tools/r8/R8EntryPointTests.java b/src/test/java/com/android/tools/r8/R8EntryPointTests.java
index a03ae3d..e2cb5d6 100644
--- a/src/test/java/com/android/tools/r8/R8EntryPointTests.java
+++ b/src/test/java/com/android/tools/r8/R8EntryPointTests.java
@@ -40,7 +40,7 @@
public void testRun1Dir() throws Exception {
Path out = temp.newFolder("outdex").toPath();
R8.run(getCommand(out));
- Assert.assertTrue(Files.isRegularFile(out.resolve(FileUtils.DEFAULT_DEX_FILENAME)));
+ Assert.assertTrue(Files.isRegularFile(out.resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
}
@@ -63,7 +63,7 @@
} finally {
executor.shutdown();
}
- Assert.assertTrue(Files.isRegularFile(out.resolve(FileUtils.DEFAULT_DEX_FILENAME)));
+ Assert.assertTrue(Files.isRegularFile(out.resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
}
@@ -92,7 +92,7 @@
"--pg-conf", testFlags.toString(),
INPUT_JAR.toString());
Assert.assertEquals(0, r8.exitCode);
- Assert.assertTrue(Files.isRegularFile(out.resolve(FileUtils.DEFAULT_DEX_FILENAME)));
+ Assert.assertTrue(Files.isRegularFile(out.resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
}
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index 1fb3175..92de268 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -123,10 +123,10 @@
// Interface initializer is not triggered after desugaring.
.put("962-iface-static", AndroidApiLevel.N.getLevel())
// Interface initializer is not triggered after desugaring.
- .put("964-default-iface-init-gen",AndroidApiLevel.N.getLevel())
+ .put("964-default-iface-init-gen", AndroidApiLevel.N.getLevel())
// AbstractMethodError (for method not implemented in class) instead of
// IncompatibleClassChangeError (for conflict of default interface methods).
- .put("968-default-partial-compile-gen",AndroidApiLevel.N.getLevel())
+ .put("968-default-partial-compile-gen", AndroidApiLevel.N.getLevel())
// NoClassDefFoundError (for companion class) instead of NoSuchMethodError.
.put("970-iface-super-resolution-gen", AndroidApiLevel.N.getLevel())
// NoClassDefFoundError (for companion class) instead of AbstractMethodError.
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index 5c7d303..e21e1bb 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.shaking.ProguardRuleParserException;
-import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.JarBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -184,7 +183,7 @@
}
private Path getOriginalDexFile() {
- return Paths.get(EXAMPLE_DIR, pkg, FileUtils.DEFAULT_DEX_FILENAME);
+ return Paths.get(EXAMPLE_DIR, pkg, ToolHelper.DEFAULT_DEX_FILENAME);
}
private DexTool getTool() {
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 3258b87..0f1a7bd 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.shaking.ProguardRuleParserException;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 08f196c..fc4eefe 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -10,15 +10,14 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.FoundClassSubject;
import com.android.tools.r8.utils.DexInspector.FoundMethodSubject;
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
import com.android.tools.r8.utils.DexInspector.InvokeInstructionSubject;
-import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
import com.google.common.collect.ImmutableList;
@@ -405,7 +404,7 @@
throws ZipException, IOException, ExecutionException {
try (ZipFile zipFile = new ZipFile(zip.toFile())) {
try (InputStream in =
- zipFile.getInputStream(zipFile.getEntry(FileUtils.DEFAULT_DEX_FILENAME))) {
+ zipFile.getInputStream(zipFile.getEntry(ToolHelper.DEFAULT_DEX_FILENAME))) {
return new DexInspector(AndroidApp.fromDexProgramData(ByteStreams.toByteArray(in)));
}
}
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
index 06916a8..4ff65ba 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidPTest.java
@@ -16,8 +16,6 @@
import com.android.tools.r8.utils.DexInspector.FoundClassSubject;
import com.android.tools.r8.utils.DexInspector.FoundMethodSubject;
import com.android.tools.r8.utils.DexInspector.InstructionSubject;
-import com.android.tools.r8.utils.DexInspector.InvokeInstructionSubject;
-import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OffOrAuto;
import com.google.common.collect.ImmutableList;
@@ -39,7 +37,6 @@
import java.util.stream.Collectors;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
-import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -264,7 +261,7 @@
throws ZipException, IOException, ExecutionException {
try (ZipFile zipFile = new ZipFile(zip.toFile())) {
try (InputStream in =
- zipFile.getInputStream(zipFile.getEntry(FileUtils.DEFAULT_DEX_FILENAME))) {
+ zipFile.getInputStream(zipFile.getEntry(ToolHelper.DEFAULT_DEX_FILENAME))) {
return new DexInspector(AndroidApp.fromDexProgramData(ByteStreams.toByteArray(in)));
}
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index fdd2fa6..80c1e76 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -68,6 +68,7 @@
public static final String LINE_SEPARATOR = StringUtils.LINE_SEPARATOR;
public final static String PATH_SEPARATOR = File.pathSeparator;
+ public static final String DEFAULT_DEX_FILENAME = "classes.dex";
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
private static final int DEFAULT_MIN_SDK = AndroidApiLevel.I.getLevel();
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index 508ed3f..158388a 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.dex;
import com.android.tools.r8.Resource;
-import com.android.tools.r8.Resource.Kind;
import com.android.tools.r8.code.ConstString;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
@@ -83,10 +82,19 @@
Collection<DexProgramClass> synthesizedFrom) {
String desc = DescriptorUtils.javaTypeToDescriptor(name);
DexType type = dexItemFactory.createType(desc);
- return new DexProgramClass(type, Kind.DEX, new DexAccessFlags(Constants.ACC_PUBLIC),
- dexItemFactory.objectType, DexTypeList.empty(), null, DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY, DexEncodedField.EMPTY_ARRAY, DexEncodedMethod.EMPTY_ARRAY,
- new DexEncodedMethod[]{makeMethod(type, stringCount, startOffset)},
+ return new DexProgramClass(
+ type,
+ null,
+ null,
+ new DexAccessFlags(Constants.ACC_PUBLIC),
+ dexItemFactory.objectType,
+ DexTypeList.empty(),
+ null,
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ new DexEncodedMethod[] {makeMethod(type, stringCount, startOffset)},
synthesizedFrom);
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
index 0db6991..663901f 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jasmin;
+import com.android.tools.r8.Resource.Origin;
+import com.android.tools.r8.Resource.PathOrigin;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.naming.MemberNaming.FieldSignature;
@@ -17,6 +19,7 @@
import jasmin.ClassFile;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@@ -38,6 +41,10 @@
this.superName = superName;
}
+ public String getSourceFile() {
+ return name + ".j";
+ }
+
public MethodSignature addVirtualMethod(
String name,
List<String> argumentTypes,
@@ -109,7 +116,7 @@
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append(".source ").append(name).append(".j\n");
+ builder.append(".source ").append(getSourceFile()).append("\n");
builder.append(".class public ").append(name).append("\n");
builder.append(".super ").append(superName).append("\n");
if (makeInit) {
@@ -169,8 +176,17 @@
}
public AndroidApp build() throws Exception {
+ Origin root = new PathOrigin(Paths.get("JasminBuilder"), Origin.root());
AndroidApp.Builder builder = AndroidApp.builder();
- builder.addClassProgramData(buildClasses());
+ for (ClassBuilder clazz : classes) {
+ Origin origin = new Origin(root) {
+ @Override
+ public String part() {
+ return clazz.getSourceFile();
+ }
+ };
+ builder.addClassProgramData(origin, compile(clazz));
+ }
return builder.build();
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index c289c8e..b68f901 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -317,7 +317,7 @@
byte[] ref = null;
byte[] ref2 = null;
for (Path testDir : testDirs.keySet()) {
- Path primaryDexFile = testDir.resolve(FileUtils.DEFAULT_DEX_FILENAME);
+ Path primaryDexFile = testDir.resolve(ToolHelper.DEFAULT_DEX_FILENAME);
Path secondaryDexFile = testDir.resolve("classes2.dex");
assertTrue(Files.exists(primaryDexFile));
boolean hasSecondaryDexFile = !allClasses && mode == CompilationMode.DEBUG;
@@ -600,6 +600,7 @@
new DexProgramClass(
type,
null,
+ null,
new DexAccessFlags(),
factory.objectType,
DexTypeList.empty(),
diff --git a/tools/archive.py b/tools/archive.py
index 4e36724..2ab1f1f 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -3,6 +3,7 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+import gradle
import d8
import os
import r8
@@ -68,7 +69,10 @@
print 'On master, using git hash for archiving'
version = GetGitHash()
- for jar in [utils.D8_JAR, utils.R8_JAR, utils.COMPATDX_JAR]:
+ # Ensure all archived artifacts has been built before archiving.
+ gradle.RunGradle([utils.D8, utils.R8, utils.COMPATDX, utils.COMPATPROGUARD])
+
+ for jar in [utils.D8_JAR, utils.R8_JAR, utils.COMPATDX_JAR, utils.COMPATPROGUARD_JAR]:
file_name = os.path.basename(jar)
destination = GetUploadDestination(version, file_name, is_master)
print('Uploading %s to %s' % (jar, destination))
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index ee8981b..d8fac83 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -150,8 +150,6 @@
args.extend(['--min-api', values['min-api']])
if options.compiler == 'r8':
- if 'pgmap' in values:
- args.extend(['--pg-map', values['pgmap']])
if 'pgconf' in values and not options.k:
for pgconf in values['pgconf']:
args.extend(['--pg-conf', pgconf])
diff --git a/tools/utils.py b/tools/utils.py
index 18f9779..7d198fa 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -18,11 +18,17 @@
DEX_SEGMENTS_JAR = os.path.join(REPO_ROOT, 'build', 'libs',
'dexsegments.jar')
DEX_SEGMENTS_RESULT_PATTERN = re.compile('- ([^:]+): ([0-9]+)')
-COMPATDX_JAR = os.path.join(REPO_ROOT, 'build', 'libs', 'compatdx.jar')
LIBS = os.path.join(REPO_ROOT, 'build', 'libs')
+
+D8 = 'd8'
+R8 = 'r8'
+COMPATDX = 'compatdx'
+COMPATPROGUARD = 'compatproguard'
+
D8_JAR = os.path.join(LIBS, 'd8.jar')
R8_JAR = os.path.join(LIBS, 'r8.jar')
COMPATDX_JAR = os.path.join(LIBS, 'compatdx.jar')
+COMPATPROGUARD_JAR = os.path.join(LIBS, 'compatproguard.jar')
def PrintCmd(s):
if type(s) is list: