Merge "Repackage sparse conditional constant propagation."
diff --git a/build.gradle b/build.gradle
index a9c4e7a..db938f0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,6 +4,7 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import net.ltgt.gradle.errorprone.ErrorProneToolChain
import org.gradle.internal.os.OperatingSystem
+import tasks.GetJarsFromConfiguration
import utils.Utils
apply plugin: 'java'
@@ -470,7 +471,6 @@
baseName 'sources'
}
-
task R8(type: ShadowJar) {
from consolidatedLicense.outputs.files
from repackageSources.outputs.files
@@ -780,7 +780,7 @@
}
task extractExamplesRuntime(type: Sync) {
dependsOn configurations.examplesRuntime
- from configurations.examplesRuntime.collect { zipTree(it) }
+ from { configurations.examplesRuntime.collect { zipTree(it) } }
include "**/*.class"
includeEmptyDirs false
into "$buildDir/runtime/examples/"
@@ -1185,53 +1185,8 @@
args inFile
}
-task supportLibDir() {
- doLast {
- File dir = file("build/supportlibraries")
- dir.mkdir()
- }
-}
-
-configurations.supportLibs.files.each { file ->
- if (file.getName().endsWith(".aar")) {
- def name = "extract_"+file.getName()
- task "${name}"(type: Copy) {
- dependsOn supportLibDir
- from zipTree(file)
- into "build/supportlibraries"
- eachFile { FileCopyDetails fcp ->
- if (fcp.relativePath.pathString.equals("classes.jar")) {
- // remap the file to the root with correct name
- fcp.relativePath = new RelativePath(true, file.getName().replace(".aar", ".jar"))
- } else {
- fcp.exclude()
- }
- }
- }
- }
-}
-
-task supportLibList() {
- configurations.supportLibs.files.each {
- if (it.getName().endsWith(".aar")) {
- dependsOn "extract_"+it.getName()
- }
- }
- doLast {
- file("build/generated").mkdir()
- def file = file("build/generated/supportlibraries.txt")
- file.createNewFile()
- file.text = ""
- configurations.supportLibs.files.each {
- if (it.getName().endsWith(".aar")) {
- def outName = it.getName().replace(".aar", ".jar")
- file.text += ("build/supportlibraries/"
- + outName + "\n")
- } else {
- file.text += (it.getPath() + "\n")
- }
- }
- }
+task getJarsFromSupportLibs(type: GetJarsFromConfiguration) {
+ setConfiguration(configurations.supportLibs)
}
task AospJarTest(type: Exec) {
@@ -1243,7 +1198,7 @@
}
test {
- dependsOn supportLibList
+ dependsOn getJarsFromSupportLibs
testLogging.exceptionFormat = 'full'
if (project.hasProperty('print_test_stdout')) {
testLogging.showStandardStreams = true
diff --git a/buildSrc/src/main/java/tasks/GetJarsFromConfiguration.java b/buildSrc/src/main/java/tasks/GetJarsFromConfiguration.java
new file mode 100644
index 0000000..d638e0d
--- /dev/null
+++ b/buildSrc/src/main/java/tasks/GetJarsFromConfiguration.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2016, 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 tasks;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.file.FileTree;
+import org.gradle.api.tasks.InputFiles;
+import org.gradle.api.tasks.OutputDirectory;
+import org.gradle.api.tasks.OutputFile;
+import org.gradle.api.tasks.TaskAction;
+
+/**
+ * Extract all jars from the configuration. If an aar is in the configuration, classes.jar is
+ * extracted. Locations of the jars are written to a generated file.
+ */
+public class GetJarsFromConfiguration extends DefaultTask {
+
+ private Configuration configuration;
+
+ @InputFiles
+ public Configuration getInputFiles() {
+ return configuration;
+ }
+
+ public void setConfiguration(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ @OutputDirectory
+ public File getOutputDir() {
+ return new File(getProject().getBuildDir(), "supportlibraries");
+ }
+
+ @OutputFile
+ public File getGeneratedFile() {
+ return new File(getProject().getBuildDir(), "generated/supportlibraries.txt");
+ }
+
+ @TaskAction
+ public void extract() throws IOException {
+ Files.createDirectories(getOutputDir().toPath());
+
+ Set<File> configurationFiles = configuration.getFiles();
+ List<String> jarPaths = new ArrayList<>(configurationFiles.size());
+ for (File file : configurationFiles) {
+ jarPaths.add(getSingleJar(file));
+ }
+
+ Path generatedPath = getGeneratedFile().toPath();
+ Files.deleteIfExists(generatedPath);
+ Files.createDirectories(generatedPath.getParent());
+ Files.write(generatedPath, jarPaths);
+ }
+
+ private String getSingleJar(File jarOrAar) throws IOException {
+ if (jarOrAar.getName().endsWith(".aar")) {
+ FileTree aarEntries = getProject().zipTree(jarOrAar);
+
+ for (File aarEntry : aarEntries) {
+ if (aarEntry.getName().equals("classes.jar")) {
+ try (InputStream is = new FileInputStream(aarEntry)) {
+ String jarName = jarOrAar.getName().replaceAll("\\.aar$", ".jar");
+ Path extractedPath = getOutputDir().toPath().resolve(jarName);
+ Files.deleteIfExists(extractedPath);
+ Files.copy(is, extractedPath);
+
+ return extractedPath.toString();
+ }
+ }
+ }
+ throw new RuntimeException("Aar does not contain classes.jar: " + jarOrAar.toString());
+ } else {
+ return jarOrAar.toString();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index 8a0e247..4059ab8 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -110,17 +110,6 @@
return app;
}
- /**
- * This is not part of the public API of a command, but allows subclasses to add vdex
- * files as allowed input.
- *
- * Default is that vdex is not allowed.
- */
- B setVdexAllowed() {
- guard(() -> getAppBuilder().setVdexAllowed());
- return self();
- }
-
/** Add program file resources. */
public B addProgramFiles(Path... files) {
addProgramFiles(Arrays.asList(files));
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index be50c0e..59a3c86 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -44,8 +44,7 @@
" --help # Print this message."));
public static Command.Builder builder() {
- // Allow vdex files for the dex segments tool.
- return new Command.Builder().setVdexAllowed();
+ return new Command.Builder();
}
public static Command.Builder parse(String[] args) {
diff --git a/src/main/java/com/android/tools/r8/Diagnostic.java b/src/main/java/com/android/tools/r8/Diagnostic.java
index b0868cc..7896251 100644
--- a/src/main/java/com/android/tools/r8/Diagnostic.java
+++ b/src/main/java/com/android/tools/r8/Diagnostic.java
@@ -4,12 +4,27 @@
package com.android.tools.r8;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
/**
* Interface for all diagnostic message produced by D8 and R8.
*/
public interface Diagnostic {
+
+ /**
+ * Origin of the resource causing the problem.
+ * @return Origin.unknown() when origin is not available.
+ */
Origin getOrigin();
+ /**
+ * Position of the problem in the origin.
+ * @return {@link Position#UNKNOWN} when position is not available.
+ */
+ Position getPosition();
+
+ /**
+ * User friendly description of the problem.
+ */
String getDiagnosticMessage();
}
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index 6534361..b3c9a6d 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -5,11 +5,16 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Marker;
+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.graph.DexApplication;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.shaking.FilteredClassPath;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
import com.google.common.io.ByteStreams;
@@ -19,18 +24,30 @@
import java.util.concurrent.ExecutionException;
public class ExtractMarker {
+ public static class VdexOrigin extends Origin {
+
+ private final int index;
+
+ public VdexOrigin(Origin vdexOrigin, int index) {
+ super(vdexOrigin);
+ this.index = index;
+ }
+
+ @Override
+ public String part() {
+ return Integer.toString(index);
+ }
+ }
public static Marker extractMarkerFromDexFile(Path file) throws IOException, ExecutionException {
AndroidApp.Builder appBuilder = AndroidApp.builder();
- appBuilder.setVdexAllowed();
- appBuilder.addProgramFiles(FilteredClassPath.unfiltered(file));
+ addDexResources(appBuilder, file);
return extractMarker(appBuilder.build());
}
public static int extractDexSize(Path file) throws IOException, ExecutionException {
AndroidApp.Builder appBuilder = AndroidApp.builder();
- appBuilder.setVdexAllowed();
- appBuilder.addProgramFiles(FilteredClassPath.unfiltered(file));
+ addDexResources(appBuilder, file);
int size = 0;
for (Resource resource : appBuilder.build().getDexProgramResources()) {
try (InputStream input = resource.getStream()) {
@@ -46,6 +63,20 @@
return extractMarker(app);
}
+ private static void addDexResources(AndroidApp.Builder appBuilder, Path file) throws IOException {
+ if (FileUtils.isVDexFile(file)) {
+ PathOrigin vdexOrigin = new PathOrigin(file);
+ VDexFileReader reader = new VDexFileReader(new VDexFile(Resource.fromFile(file)));
+ int index = 0;
+ for (byte[] bytes : reader.getDexFiles()) {
+ appBuilder.addDexProgramData(bytes, new VdexOrigin(vdexOrigin, index));
+ index++;
+ }
+ } else {
+ appBuilder.addProgramFiles(FilteredClassPath.unfiltered(file));
+ }
+ }
+
private static Marker extractMarker(AndroidApp app) throws IOException, ExecutionException {
InternalOptions options = new InternalOptions();
options.skipReadingDexCode = true;
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 50e1e6e..57eed20 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -10,7 +10,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "v0.2.1-dev";
+ public static final String LABEL = "v0.2.2-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/errors/CompilationError.java b/src/main/java/com/android/tools/r8/errors/CompilationError.java
index 5c3220d..1104b29 100644
--- a/src/main/java/com/android/tools/r8/errors/CompilationError.java
+++ b/src/main/java/com/android/tools/r8/errors/CompilationError.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
/**
* Exception to signal an compilation error.
@@ -15,6 +16,7 @@
public class CompilationError extends RuntimeException implements Diagnostic {
private final Origin origin;
+ private final Position position;
public CompilationError(String message) {
this(message, Origin.unknown());
}
@@ -27,9 +29,14 @@
this(message, null, origin);
}
- public CompilationError(String message, Throwable cause, Origin location) {
+ public CompilationError(String message, Throwable cause, Origin origin) {
+ this(message, cause, origin, Position.UNKNOWN);
+ }
+
+ public CompilationError(String message, Throwable cause, Origin origin, Position position) {
super(message, cause);
- this.origin = location;
+ this.origin = origin;
+ this.position = position;
}
@Override
@@ -38,6 +45,11 @@
}
@Override
+ public Position getPosition() {
+ return position;
+ }
+
+ @Override
public String getDiagnosticMessage() {
return getMessage();
}
diff --git a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
index a72c1bc..f587642 100644
--- a/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/ClassAccessFlags.java
@@ -74,7 +74,13 @@
@Override
public int getAsDexAccessFlags() {
- return flags & ~Constants.ACC_SUPER;
+ // We unset the super flag here, as it is meaningless in DEX. Furthermore, we add missing
+ // abstract to interfaces to work around a javac bug when generating package-info classes.
+ if (isInterface()) {
+ return (flags & ~Constants.ACC_SUPER) | Constants.ACC_ABSTRACT;
+ } else {
+ return flags & ~Constants.ACC_SUPER;
+ }
}
@Override
diff --git a/src/main/java/com/android/tools/r8/origin/TextRangeOrigin.java b/src/main/java/com/android/tools/r8/origin/TextRangeOrigin.java
deleted file mode 100644
index 4df5540..0000000
--- a/src/main/java/com/android/tools/r8/origin/TextRangeOrigin.java
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.origin;
-
-/**
- * An {@link Origin} with a position in a text file.
- */
-public class TextRangeOrigin extends Origin {
-
- /**
- * A position in a text file determined by line and column.
- * Line and column numbers start at 1.
- */
- public static class TextPosition {
- private final int line;
- private final int column;
-
- public TextPosition(int line, int column) {
- this.line = line;
- this.column = column;
- }
-
- /**
- * Return the line of this position.
- */
- public int getLine() {
- return line;
- }
-
- /**
- * Return the column of this position.
- * @return May return {@link #UNKNOWN_COLUMN} if column information is not available.
- */
- public int getColumn() {
- return column;
- }
-
- @Override
- public String toString() {
- return "Line: " + line + ", column: " + column;
- }
-
- @Override
- public final int hashCode() {
- return line ^ (column << 16);
- }
-
- @Override
- public final boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof TextPosition) {
- TextPosition other = (TextPosition) o;
- return line == other.line && column == other.column;
- }
- return false;
- }
- }
-
- /**
- * Line or column is unknown.
- */
- public static final int UNKNOWN_COLUMN = -1;
-
- private final TextPosition start;
- private final TextPosition end;
-
- public static Origin get(Origin fileOrigin, int startLine, int startColumn) {
- return get(fileOrigin, startLine, startColumn, startLine, startColumn);
- }
-
- public static Origin get(Origin fileOrigin, int startLine, int startColumn, int endLine,
- int endColumn) {
- if (fileOrigin == Origin.unknown()) {
- return Origin.unknown();
- } else {
- assert startLine > 0
- && endLine >= startLine
- && ((startColumn == UNKNOWN_COLUMN && endColumn == UNKNOWN_COLUMN)
- || (startColumn > 0 && endColumn > 0));
- TextPosition start = new TextPosition(startLine, startColumn);
- TextPosition end;
- if (startLine == endLine && startColumn == endColumn) {
- end = start;
- } else {
- end = new TextPosition(endLine, endColumn);
- }
- return new TextRangeOrigin(fileOrigin, start, end);
- }
- }
-
- private TextRangeOrigin(Origin fileOrigin, TextPosition start, TextPosition end) {
- super(fileOrigin);
- this.start = start;
- this.end = end;
- }
-
- /**
- * Return the start position of this text range.
- */
- public TextPosition getStart() {
- return start;
- }
-
- /**
- * Return the end position of this text range.
- */
- public TextPosition getEnd() {
- return end;
- }
-
- @Override
- public String part() {
- return " line " + getStart().getLine();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/position/BinaryPosition.java b/src/main/java/com/android/tools/r8/position/BinaryPosition.java
new file mode 100644
index 0000000..5eb2da2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/position/BinaryPosition.java
@@ -0,0 +1,49 @@
+// 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.position;
+
+public class BinaryPosition implements Position {
+
+ /**
+ * Byte offset from start of the resource.
+ */
+ private final long offset;
+
+ public BinaryPosition(long offset) {
+ assert offset >= 0;
+ this.offset = offset;
+ }
+
+ public long getOffset() {
+ return offset;
+ }
+
+ @Override
+ public String toString() {
+ return "Index : " + offset;
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(offset);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o != null && o.getClass().equals(BinaryPosition.class)) {
+ BinaryPosition other = (BinaryPosition) o;
+ return offset == other.offset;
+ }
+ return false;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Offset " + offset;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/position/Position.java b/src/main/java/com/android/tools/r8/position/Position.java
new file mode 100644
index 0000000..902fad5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/position/Position.java
@@ -0,0 +1,28 @@
+// 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.position;
+
+/**
+ * Represent a position in a resource, it can for example be line in a text file of the byte offset
+ * in a binary stream.
+ */
+public interface Position {
+
+ /**
+ * Position is unknown.
+ */
+ Position UNKNOWN = new Position() {
+ @Override
+ public String getDescription() {
+ return "Unknown";
+ }
+ };
+
+ /**
+ * A user friendly text representation of this position.
+ */
+ String getDescription();
+
+}
diff --git a/src/main/java/com/android/tools/r8/position/TextPosition.java b/src/main/java/com/android/tools/r8/position/TextPosition.java
new file mode 100644
index 0000000..17de30d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/position/TextPosition.java
@@ -0,0 +1,79 @@
+// 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.position;
+
+/**
+ * A position in a text file determined by line and column.
+ * Line and column numbers start at 1.
+ */
+public class TextPosition implements Position {
+
+ /**
+ * Column is unknown.
+ */
+ public static final int UNKNOWN_COLUMN = -1;
+
+ /**
+ * Char offset from the start of the text resource.
+ */
+ private final long offset;
+ private final int line;
+ private final int column;
+
+ public TextPosition(long offset, int line, int column) {
+ assert (offset >= 1)
+ && (line >= 1)
+ && (column >= 1 || column == UNKNOWN_COLUMN);
+ this.offset = offset;
+ this.line = line;
+ this.column = column;
+ }
+
+ /**
+ * Return the line of this position.
+ */
+ public int getLine() {
+ return line;
+ }
+
+ /**
+ * Return the column of this position.
+ * @return May return {@link #UNKNOWN_COLUMN} if column information is not available.
+ */
+ public int getColumn() {
+ return column;
+ }
+
+ public long getOffset() {
+ return offset;
+ }
+
+ @Override
+ public String toString() {
+ return "Offset: " + offset + ", Line: " + line + ", column: " + column;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Line: " + line + (column != UNKNOWN_COLUMN ? ", column: " + column: "");
+ }
+
+ @Override
+ public int hashCode() {
+ return Long.hashCode(offset) ^ line ^ (column << 16);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o != null && o.getClass().equals(TextPosition.class)) {
+ TextPosition other = (TextPosition) o;
+ return offset == other.offset && line == other.line && column == other.column;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/position/TextRange.java b/src/main/java/com/android/tools/r8/position/TextRange.java
new file mode 100644
index 0000000..d7c0f43
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/position/TextRange.java
@@ -0,0 +1,51 @@
+// 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.position;
+
+public class TextRange implements Position {
+ private final TextPosition start;
+ private final TextPosition end;
+
+ public TextRange(TextPosition start, TextPosition end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ /**
+ * Return the start position of this range.
+ */
+ public TextPosition getStart() {
+ return start;
+ }
+
+ /**
+ * Return the end position of this range.
+ */
+ public TextPosition getEnd() {
+ return end;
+ }
+
+ @Override
+ public int hashCode() {
+ return start.hashCode() ^ end.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o != null && o.getClass().equals(getClass())) {
+ TextRange other = (TextRange) o;
+ return start.equals(other.getStart()) && end.equals(other.getEnd());
+ }
+ return false;
+ }
+
+ @Override
+ public String getDescription() {
+ return start.getDescription();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 631fbc0..8fe9355 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.naming.DictionaryReader;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.Reporter;
import com.google.common.collect.ImmutableList;
@@ -46,6 +47,7 @@
private boolean useUniqueClassMemberNames;
private boolean keepParameterNames;
private Origin keepParameterNamesOptionOrigin;
+ private Position keepParameterNamesOptionPosition;
private ProguardClassFilter.Builder adaptClassStrings = ProguardClassFilter.builder();
private boolean forceProguardCompatibility = false;
private boolean overloadAggressively;
@@ -169,10 +171,12 @@
return useUniqueClassMemberNames;
}
- public void setKeepParameterNames(boolean keepParameterNames, Origin optionOrigin) {
+ public void setKeepParameterNames(boolean keepParameterNames, Origin optionOrigin,
+ Position optionPosition) {
assert optionOrigin != null || !keepParameterNames;
this.keepParameterNames = keepParameterNames;
this.keepParameterNamesOptionOrigin = optionOrigin;
+ this.keepParameterNamesOptionPosition = optionPosition;
}
boolean isKeepParameterNames() {
@@ -183,6 +187,10 @@
return keepParameterNamesOptionOrigin;
}
+ Position getKeepParameterNamesOptionPosition() {
+ return keepParameterNamesOptionPosition;
+ }
+
public void addAdaptClassStringsPattern(ProguardClassNameList pattern) {
adaptClassStrings.addPattern(pattern);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 9c5fc27..4f5447d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import com.android.tools.r8.origin.TextRangeOrigin;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -11,6 +10,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.shaking.ProguardConfiguration.Builder;
import com.android.tools.r8.shaking.ProguardTypeMatcher.ClassOrType;
import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
@@ -90,7 +92,8 @@
// are not.
reporter.fatalError(new StringDiagnostic(
"-keepparameternames is not supported",
- configurationBuilder.getKeepParameterNamesOptionOrigin()));
+ configurationBuilder.getKeepParameterNamesOptionOrigin(),
+ configurationBuilder.getKeepParameterNamesOptionPosition()));
}
}
@@ -164,8 +167,7 @@
if (acceptArobaseInclude()) {
return true;
}
- int optionLine = line;
- int optionColumn = getColumn();
+ TextPosition optionStart = getPosition();
expectChar('-');
String option;
if (Iterables.any(IGNORED_SINGLE_ARG_OPTIONS, this::skipOptionWithSingleArg)
@@ -179,12 +181,13 @@
(option = Iterables.find(WARNED_SINGLE_ARG_OPTIONS,
this::skipOptionWithSingleArg, null)) != null
|| (option = Iterables.find(WARNED_FLAG_OPTIONS, this::skipFlag, null)) != null) {
- warnIgnoringOptions(option, optionLine, optionColumn);
+ warnIgnoringOptions(option, optionStart);
} else if (
(option = Iterables.find(UNSUPPORTED_FLAG_OPTIONS, this::skipFlag, null)) != null) {
reporter.error(new StringDiagnostic(
"Unsupported option: -" + option,
- getOrigin(optionLine, optionColumn)));
+ origin,
+ getPostion(optionStart)));
} else if (acceptString("renamesourcefileattribute")) {
skipWhitespace();
if (isOptionalArgumentGiven()) {
@@ -199,7 +202,7 @@
configurationBuilder.addRule(rule);
} else if (acceptString("keepparameternames")) {
configurationBuilder.setKeepParameterNames(true,
- getOrigin(optionLine, optionColumn));
+ origin, getPostion(optionStart));
} else if (acceptString("checkdiscard")) {
ProguardCheckDiscardRule rule = parseCheckDiscardRule();
configurationBuilder.addRule(rule);
@@ -217,9 +220,10 @@
if (expectedOptimizationPasses == null) {
throw reporter.fatalError(new StringDiagnostic(
"Missing n of \"-optimizationpasses n\"",
- getOrigin(optionLine, optionColumn)));
+ origin,
+ getPostion(optionStart)));
}
- warnIgnoringOptions("optimizationpasses", optionLine, optionColumn);
+ warnIgnoringOptions("optimizationpasses", optionStart);
} else if (acceptString("dontobfuscate")) {
configurationBuilder.setObfuscating(false);
} else if (acceptString("dontshrink")) {
@@ -245,7 +249,7 @@
} else if (acceptString("repackageclasses")) {
if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.FLATTEN) {
warnOverridingOptions("repackageclasses", "flattenpackagehierarchy",
- optionLine, optionColumn);
+ optionStart);
}
skipWhitespace();
if (acceptChar('\'')) {
@@ -257,7 +261,7 @@
} else if (acceptString("flattenpackagehierarchy")) {
if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.REPACKAGE) {
warnOverridingOptions("repackageclasses", "flattenpackagehierarchy",
- optionLine, optionColumn);
+ optionStart);
skipWhitespace();
if (isOptionalArgumentGiven()) {
skipSingleArgument();
@@ -329,25 +333,24 @@
} else {
String unknownOption = acceptString();
reporter.error(new StringDiagnostic("Unknown option \"-" + unknownOption + "\"",
- getOrigin(optionLine, optionColumn)));
+ origin, getPostion(optionStart)));
}
return true;
}
private void parseInclude() throws ProguardRuleParserException {
- int startLine = line;
- int startColumn = getColumn();
+ TextPosition start = getPosition();
Path included = parseFileName();
try {
new ProguardConfigurationSourceParser(new ProguardConfigurationSourceFile(included))
.parse();
} catch (FileNotFoundException | NoSuchFileException e) {
throw parseError("Included file '" + included.toString() + "' not found",
- startLine, startColumn, e);
+ start, e);
} catch (IOException e) {
throw parseError("Failed to read included file '" + included.toString() + "'",
- startLine, startColumn, e);
+ start, e);
}
}
@@ -534,13 +537,13 @@
} else {
// The only path to here is through "-keep" followed by "class".
unacceptString("-keepclass");
- int startLine = line;
- int startColumn = getColumn();
+ TextPosition start = getPosition();
acceptString("-");
String unknownOption = acceptString();
throw reporter.fatalError(new StringDiagnostic(
"Unknown option \"-" + unknownOption + "\"",
- getOrigin(startLine, startColumn)));
+ origin,
+ start));
}
} else {
builder.setType(ProguardKeepRuleType.KEEP);
@@ -618,8 +621,7 @@
private ProguardClassType parseClassType() throws ProguardRuleParserException {
skipWhitespace();
- int startLine = line;
- int startColumn = getColumn();
+ TextPosition start = getPosition();
if (acceptString("interface")) {
return ProguardClassType.INTERFACE;
} else if (acceptString("@interface")) {
@@ -630,7 +632,7 @@
return ProguardClassType.ENUM;
} else {
throw reporter.fatalError(new StringDiagnostic("Expected interface|class|enum",
- getOrigin(startLine, startColumn)));
+ origin, getPostion(start)));
}
}
@@ -780,8 +782,7 @@
} else if (acceptString("false")) {
ruleBuilder.setReturnValue(new ProguardMemberRuleReturnValue(false));
} else {
- int fieldStartLine = line;
- int fieldStartColumn = getColumn();
+ TextPosition fieldStart = getPosition();
String qualifiedFieldName = acceptFieldName();
if (qualifiedFieldName != null) {
if (ruleBuilder.getTypeMatcher() instanceof MatchSpecificType) {
@@ -798,12 +799,10 @@
.createField(fieldClass, fieldType, fieldName);
ruleBuilder.setReturnValue(new ProguardMemberRuleReturnValue(field));
} else {
- throw parseError("Expected specific type", fieldStartLine,
- fieldStartColumn);
+ throw parseError("Expected specific type", fieldStart);
}
} else {
- int valueStartLine = line;
- int valueStartColumn = getColumn();
+ TextPosition valueStart = getPosition();
Integer min = acceptInteger();
Integer max = min;
if (min == null) {
@@ -817,8 +816,7 @@
}
}
if (!allowValueSpecification) {
- throw parseError("Unexpected value specification", valueStartLine,
- valueStartColumn);
+ throw parseError("Unexpected value specification", valueStart);
}
ruleBuilder.setReturnValue(
new ProguardMemberRuleReturnValue(new LongInterval(min, max)));
@@ -864,15 +862,14 @@
}
private Path parseFileName() throws ProguardRuleParserException {
- int startLine = this.line;
- int startColumn = getColumn();
+ TextPosition start = getPosition();
skipWhitespace();
String fileName = acceptString(character ->
character != File.pathSeparatorChar
&& !Character.isWhitespace(character)
&& character != '(');
if (fileName == null) {
- throw parseError("File name expected", startLine, startColumn);
+ throw parseError("File name expected", start);
}
return baseDirectory.resolve(fileName);
}
@@ -912,14 +909,13 @@
}
private String parseFileFilter() throws ProguardRuleParserException {
- int startLine = line;
- int startColumn = getColumn();
+ TextPosition start = getPosition();
skipWhitespace();
String fileFilter = acceptString(character ->
character != ',' && character != ';' && character != ')'
&& !Character.isWhitespace(character));
if (fileFilter == null) {
- throw parseError("file filter expected", startLine, startColumn);
+ throw parseError("file filter expected", start);
}
return fileFilter;
}
@@ -1067,12 +1063,11 @@
while (pattern != null) {
patterns.add(pattern);
skipWhitespace();
- int startLine = line;
- int startColumn = getColumn();
+ TextPosition start = getPosition();
if (acceptChar(',')) {
pattern = acceptPattern();
if (pattern == null) {
- throw parseError("Expected list element", startLine, startColumn);
+ throw parseError("Expected list element", start);
}
} else {
pattern = null;
@@ -1157,53 +1152,58 @@
}
return name;
}
- private String snippetForPosition(int lineNumber, int columnNumber) {
+ private String snippetForPosition(TextPosition start) {
// TODO(ager): really should deal with \r as well to get column right.
String[] lines = contents.split("\n", -1); // -1 to get trailing empty lines represented.
- String line = lines[lineNumber-1];
- String arrow = CharBuffer.allocate(columnNumber - 1).toString().replace('\0', ' ') + '^';
- return name + ":" + (lineNumber + 1) + ":" + columnNumber + "\n" + line
+ String line = lines[start.getLine() - 1];
+ String arrow = CharBuffer.allocate(start.getColumn() - 1).toString().replace('\0', ' ') + '^';
+ return name + ":" + (start.getLine() + 1) + ":" + start.getColumn() + "\n" + line
+ '\n' + arrow;
}
private ProguardRuleParserException parseError(String message) {
- return new ProguardRuleParserException(message, snippetForPosition(), getOrigin());
+ return new ProguardRuleParserException(message, snippetForPosition(), origin, getPosition());
}
private ProguardRuleParserException parseError(String message, Throwable cause) {
- return new ProguardRuleParserException(message, snippetForPosition(), getOrigin(), cause);
+ return new ProguardRuleParserException(message, snippetForPosition(), origin, getPosition(),
+ cause);
}
- private ProguardRuleParserException parseError(String message, int startLine, int startColumn,
+ private ProguardRuleParserException parseError(String message, TextPosition start,
Throwable cause) {
- return new ProguardRuleParserException(message, snippetForPosition(startLine, startColumn),
- getOrigin(startLine, startColumn), cause);
+ return new ProguardRuleParserException(message, snippetForPosition(start),
+ origin, getPostion(start), cause);
}
- private ProguardRuleParserException parseError(String message, int startLine, int startColumn) {
- return new ProguardRuleParserException(message, snippetForPosition(startLine, startColumn),
- getOrigin(startLine, startColumn));
+ private ProguardRuleParserException parseError(String message, TextPosition start) {
+ return new ProguardRuleParserException(message, snippetForPosition(start),
+ origin, getPostion(start));
}
- private void warnIgnoringOptions(String optionName, int startLine, int startColumn) {
+ private void warnIgnoringOptions(String optionName, TextPosition start) {
reporter.warning(new StringDiagnostic(
"Ignoring option: -" + optionName,
- getOrigin(startLine, startColumn)));
+ origin,
+ getPostion(start)));
}
- private void warnOverridingOptions(String optionName, String victim, int optionLine,
- int optionColumn) {
+ private void warnOverridingOptions(String optionName, String victim, TextPosition start) {
reporter.warning(
new StringDiagnostic("Option -" + optionName + " overrides -" + victim,
- getOrigin(optionLine, optionColumn)));
+ origin, getPostion(start)));
}
- private Origin getOrigin(int startLine, int startColumn) {
- return TextRangeOrigin.get(origin, startLine, startColumn, line, getColumn());
+ private Position getPostion(TextPosition start) {
+ if (start.getOffset() == position) {
+ return start;
+ } else {
+ return new TextRange(start, getPosition());
+ }
}
- private Origin getOrigin() {
- return TextRangeOrigin.get(origin, line, getColumn());
+ private TextPosition getPosition() {
+ return new TextPosition(position, line, getColumn());
}
private int getColumn() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardRuleParserException.java b/src/main/java/com/android/tools/r8/shaking/ProguardRuleParserException.java
index 4b9308c..603c56a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardRuleParserException.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardRuleParserException.java
@@ -5,22 +5,26 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
public class ProguardRuleParserException extends Exception implements Diagnostic {
private final String message;
private final String snippet;
private final Origin origin;
+ private final Position position;
- public ProguardRuleParserException(String message, String snippet, Origin origin) {
+ public ProguardRuleParserException(String message, String snippet, Origin origin,
+ Position position) {
this.message = message;
this.snippet = snippet;
this.origin = origin;
+ this.position = position;
}
public ProguardRuleParserException(String message, String snippet, Origin origin,
- Throwable cause) {
- this(message, snippet,origin);
+ Position position, Throwable cause) {
+ this(message, snippet,origin, position);
initCause(cause);
}
@@ -30,6 +34,11 @@
}
@Override
+ public Position getPosition() {
+ return position;
+ }
+
+ @Override
public String getDiagnosticMessage() {
return message + " at " + snippet;
}
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 4b7b6d4..d6dcdb8 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -6,13 +6,10 @@
import static com.android.tools.r8.utils.FileUtils.isArchive;
import static com.android.tools.r8.utils.FileUtils.isClassFile;
import static com.android.tools.r8.utils.FileUtils.isDexFile;
-import static com.android.tools.r8.utils.FileUtils.isVDexFile;
import com.android.tools.r8.ArchiveClassFileProvider;
import com.android.tools.r8.ClassFileResourceProvider;
import com.android.tools.r8.Resource;
-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.origin.Origin;
@@ -162,12 +159,6 @@
/** Get input streams for all dex program resources. */
public List<Resource> getDexProgramResources() throws IOException {
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(resource.origin, bytes))
- .collect(Collectors.toList()));
- }
for (ProgramFileArchiveReader reader : programFileArchiveReaders) {
dexResources.addAll(reader.getDexProgramResources());
}
@@ -712,15 +703,6 @@
return this;
}
- public Builder setVdexAllowed() {
- vdexAllowed = true;
- return this;
- }
-
- public boolean isVdexAllowed() {
- return vdexAllowed;
- }
-
/**
* Build final AndroidApp.
*/
@@ -746,8 +728,6 @@
}
if (isDexFile(file)) {
addProgramResources(Kind.DEX, Resource.fromFile(file));
- } else if (isVDexFile(file) && isVdexAllowed()) {
- addProgramResources(Kind.VDEX, Resource.fromFile(file));
} else if (isClassFile(file)) {
addProgramResources(Kind.CLASS, Resource.fromFile(file));
} else if (isArchive(file)) {
diff --git a/src/main/java/com/android/tools/r8/utils/IOExceptionDiagnostic.java b/src/main/java/com/android/tools/r8/utils/IOExceptionDiagnostic.java
index 8856f26..3ebb621 100644
--- a/src/main/java/com/android/tools/r8/utils/IOExceptionDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/utils/IOExceptionDiagnostic.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.position.Position;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
@@ -60,6 +61,11 @@
}
@Override
+ public Position getPosition() {
+ return Position.UNKNOWN;
+ }
+
+ @Override
public String getDiagnosticMessage() {
return message;
}
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramResource.java b/src/main/java/com/android/tools/r8/utils/ProgramResource.java
index 0cbf11e..034fb6a 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramResource.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramResource.java
@@ -12,7 +12,6 @@
public enum Kind {
DEX,
CLASS,
- VDEX
}
public final Kind kind;
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 cd5bbcd..b7cd855 100644
--- a/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/utils/StringDiagnostic.java
@@ -5,10 +5,12 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
public class StringDiagnostic implements Diagnostic {
private final Origin origin;
+ private final Position position;
private final String message;
public StringDiagnostic(String message) {
@@ -16,7 +18,12 @@
}
public StringDiagnostic(String message, Origin origin) {
+ this(message, origin, Position.UNKNOWN);
+ }
+
+ public StringDiagnostic(String message, Origin origin, Position position) {
this.origin = origin;
+ this.position = position;
this.message = message;
}
@@ -26,6 +33,11 @@
}
@Override
+ public Position getPosition() {
+ return position;
+ }
+
+ @Override
public String getDiagnosticMessage() {
return message;
}
diff --git a/src/test/apiUsageSample/com/android/tools/apiusagesample/D8DiagnosticsHandler.java b/src/test/apiUsageSample/com/android/tools/apiusagesample/D8DiagnosticsHandler.java
index 3dca445..d9f11b0 100644
--- a/src/test/apiUsageSample/com/android/tools/apiusagesample/D8DiagnosticsHandler.java
+++ b/src/test/apiUsageSample/com/android/tools/apiusagesample/D8DiagnosticsHandler.java
@@ -9,7 +9,9 @@
import com.android.tools.r8.origin.ArchiveEntryOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
-import com.android.tools.r8.origin.TextRangeOrigin;
+import com.android.tools.r8.position.Position;
+import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.position.TextRange;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -45,14 +47,21 @@
String textMessage = diagnostic.getDiagnosticMessage();
Origin origin = diagnostic.getOrigin();
+ Position positionInOrigin = diagnostic.getPosition();
String position;
- if (origin instanceof TextRangeOrigin && origin.parent() instanceof PathOrigin) {
- TextRangeOrigin textRange = (TextRangeOrigin) origin;
- position = ((PathOrigin) origin.parent()).getPath().toFile() + ": "
- + textRange.getStart().getLine() + "," + textRange.getStart().getColumn()
- + " - " + textRange.getEnd().getLine() + "," + textRange.getEnd().getColumn();
- } else if (origin.parent() instanceof PathOrigin) {
- position = ((PathOrigin) origin.parent()).getPath().toFile().toString();
+ if (origin instanceof PathOrigin) {
+ if (positionInOrigin instanceof TextRange) {
+ TextRange textRange = (TextRange) positionInOrigin;
+ position = ((PathOrigin) origin.parent()).getPath().toFile() + ": "
+ + textRange.getStart().getLine() + "," + textRange.getStart().getColumn()
+ + " - " + textRange.getEnd().getLine() + "," + textRange.getEnd().getColumn();
+ } else if (positionInOrigin instanceof TextPosition) {
+ TextPosition textPosition = (TextPosition) positionInOrigin;
+ position = ((PathOrigin) origin.parent()).getPath().toFile() + ": "
+ + textPosition.getLine() + "," + textPosition.getColumn();
+ } else {
+ position = ((PathOrigin) origin.parent()).getPath().toFile().toString();
+ }
} else {
position = "UNKNOWN";
if (origin != Origin.unknown()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index 7f39d8e..65d1009 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -14,13 +14,14 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.origin.TextRangeOrigin;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.position.TextPosition;
+import com.android.tools.r8.position.TextRange;
import com.android.tools.r8.utils.AbortException;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
@@ -980,9 +981,15 @@
int columnStart, String... messageParts) {
assertEquals(1, diagnostics.size());
Diagnostic diagnostic = diagnostics.get(0);
- assertEquals(path, ((PathOrigin) diagnostic.getOrigin().parent()).getPath());
- assertEquals(new TextRangeOrigin.TextPosition(lineStart, columnStart),
- ((TextRangeOrigin) diagnostic.getOrigin()).getStart());
+ assertEquals(path, ((PathOrigin) diagnostic.getOrigin()).getPath());
+ TextPosition position;
+ if (diagnostic.getPosition() instanceof TextRange) {
+ position = ((TextRange) diagnostic.getPosition()).getStart();
+ } else {
+ position = ((TextPosition) diagnostic.getPosition());
+ }
+ assertEquals(lineStart, position.getLine());
+ assertEquals(columnStart, position.getColumn());
for (String part:messageParts) {
assertTrue(diagnostic.getDiagnosticMessage()+ "doesn't contain \"" + part + "\"",
diagnostic.getDiagnosticMessage().contains(part));
diff --git a/tests/api_usage_sample.jar b/tests/api_usage_sample.jar
index 69af652..59eb757 100644
--- a/tests/api_usage_sample.jar
+++ b/tests/api_usage_sample.jar
Binary files differ