Merge "Remove use of Hashtable"
diff --git a/build.gradle b/build.gradle
index 35da63e..ef09f76 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,6 +10,7 @@
apply plugin: 'com.google.protobuf'
apply plugin: 'com.cookpad.android.licensetools'
apply plugin: 'net.ltgt.errorprone-base'
+apply plugin: "net.ltgt.apt"
def errorProneConfiguration = [
'-XepDisableAllChecks',
@@ -51,6 +52,7 @@
// classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
classpath files("third_party/shadow/shadow-2.0.1.jar")
classpath "net.ltgt.gradle:gradle-errorprone-plugin:0.0.13"
+ classpath "net.ltgt.gradle:gradle-apt-plugin:0.12"
}
}
@@ -169,12 +171,16 @@
jctfTestsCompile sourceSets.jctfCommon.output
examplesAndroidOCompile group: 'org.ow2.asm', name: 'asm', version: '6.0'
examplesAndroidPCompile group: 'org.ow2.asm', name: 'asm', version: '6.0'
+ // Import Guava for @Nullable annotation
+ examplesCompile 'com.google.guava:guava:23.0'
examplesCompile 'com.google.protobuf:protobuf-lite:3.0.0'
+ examplesCompileOnly "com.google.auto.value:auto-value:1.5"
examplesRuntime 'com.google.protobuf:protobuf-lite:3.0.0'
supportLibs 'com.android.support:support-v4:25.4.0'
supportLibs 'junit:junit:4.12'
supportLibs 'com.android.support.test.espresso:espresso-core:3.0.0'
debugTestResourcesKotlinCompileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.1.4-3'
+ apt 'com.google.auto.value:auto-value:1.5'
}
licenseTools {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index ae6326e..5255fc5 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -30,8 +30,7 @@
import com.android.tools.r8.shaking.DiscardedChecker;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.MainDexListBuilder;
-import com.android.tools.r8.shaking.ProguardClassNameList;
-import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
+import com.android.tools.r8.shaking.ProguardClassFilter;
import com.android.tools.r8.shaking.ReasonPrinter;
import com.android.tools.r8.shaking.RootSetBuilder;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
@@ -147,15 +146,9 @@
}
private Set<DexType> filterMissingClasses(Set<DexType> missingClasses,
- ProguardClassNameList dontWarnPatterns) {
+ ProguardClassFilter dontWarnPatterns) {
Set<DexType> result = new HashSet<>(missingClasses);
- dontWarnPatterns.forEachTypeMatcher(matcher -> {
- if (matcher instanceof MatchSpecificType) {
- result.remove(((MatchSpecificType) matcher).type);
- } else {
- result.removeIf(matcher::matches);
- }
- });
+ dontWarnPatterns.filterOutMatches(result);
return result;
}
diff --git a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
index d2fd60c..4c49a6a 100644
--- a/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
+++ b/src/main/java/com/android/tools/r8/compatproguard/CompatProguard.java
@@ -50,6 +50,8 @@
int minApi = 1;
boolean forceProguardCompatibility = false;
boolean multiDex = false;
+ boolean coreLibrary = false;
+
ImmutableList.Builder<String> builder = ImmutableList.builder();
if (args.length > 0) {
StringBuilder currentLine = new StringBuilder(args[0]);
@@ -64,6 +66,8 @@
output = args[++i];
} else if (arg.equals("--multi-dex")) {
multiDex = true;
+ } else if (arg.equals("--core-library")) {
+ coreLibrary = true;
} else if (arg.equals("-outjars")) {
throw new CompilationException(
"Proguard argument -outjar is not supported. Use R8 compatible --output flag");
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 41f9748..dccf887 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -58,7 +58,6 @@
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import java.security.MessageDigest;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -69,7 +68,6 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
-import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.zip.Adler32;
@@ -101,29 +99,13 @@
}
dest.putUleb128(mapping.getOffsetFor(annotation.type));
dest.putUleb128(annotation.elements.length);
- assert isSorted(annotation.elements, (element) -> element.name);
+ assert PresortedComparable.isSorted(annotation.elements, (element) -> element.name);
for (DexAnnotationElement element : annotation.elements) {
dest.putUleb128(mapping.getOffsetFor(element.name));
element.value.writeTo(dest, mapping);
}
}
- private static <T extends PresortedComparable<T>> boolean isSorted(KeyedDexItem<T>[] items) {
- return isSorted(items, KeyedDexItem::getKey);
- }
-
- private static <S, T extends Comparable<T>> boolean isSorted(S[] items, Function<S, T> getter) {
- T current = null;
- for (S item : items) {
- T next = getter.apply(item);
- if (current != null && current.compareTo(next) >= 0) {
- return false;
- }
- current = next;
- }
- return true;
- }
-
public FileWriter collect() {
// Use the class array from the mapping, as it has a deterministic iteration order.
new ProgramClassDependencyCollector(application, mapping.getClasses())
@@ -518,7 +500,7 @@
private void writeAnnotationSet(DexAnnotationSet set) {
assert !set.isEmpty();
- assert isSorted(set.annotations, (item) -> item.annotation.type);
+ assert PresortedComparable.isSorted(set.annotations, (item) -> item.annotation.type);
mixedSectionOffsets.setOffsetFor(set, dest.align(4));
if (Log.ENABLED) {
Log.verbose(getClass(), "Writing AnnotationSet @ 0x%08x.", dest.position());
@@ -564,7 +546,7 @@
}
private void writeEncodedFields(DexEncodedField[] fields) {
- assert isSorted(fields);
+ assert PresortedComparable.isSorted(fields);
int currentOffset = 0;
for (DexEncodedField field : fields) {
int nextOffset = mapping.getOffsetFor(field.field);
@@ -576,7 +558,7 @@
}
private void writeEncodedMethods(DexEncodedMethod[] methods, boolean clearBodies) {
- assert isSorted(methods);
+ assert PresortedComparable.isSorted(methods);
int currentOffset = 0;
for (DexEncodedMethod method : methods) {
int nextOffset = mapping.getOffsetFor(method.method);
@@ -614,21 +596,12 @@
}
private void addStaticFieldValues(DexProgramClass clazz) {
- DexEncodedField[] fields = clazz.staticFields();
- int length = 0;
- List<DexValue> values = new ArrayList<>(fields.length);
- for (int i = 0; i < fields.length; i++) {
- DexEncodedField field = fields[i];
- assert field.staticValue != null;
- values.add(field.staticValue);
- if (!field.staticValue.isDefault(field.field.type, application.dexItemFactory)) {
- length = i + 1;
- }
- }
- if (length > 0) {
- DexEncodedArray staticValues = new DexEncodedArray(
- values.subList(0, length).toArray(new DexValue[length]));
- clazz.setStaticValues(staticValues);
+ clazz.computeStaticValues(application.dexItemFactory);
+ // We have collected the individual components of this array due to the data stored in
+ // DexEncodedField#staticValues. However, we have to collect the DexEncodedArray itself
+ // here.
+ DexEncodedArray staticValues = clazz.getStaticValues();
+ if (staticValues != null) {
mixedSectionOffsets.add(staticValues);
}
}
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 8f3a923..5050711 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -23,9 +23,22 @@
public DexType superType;
public DexTypeList interfaces;
public DexString sourceFile;
+
+ /**
+ * Access has to be synchronized during concurrent collection/writing phase.
+ */
protected DexEncodedField[] staticFields;
+ /**
+ * Access has to be synchronized during concurrent collection/writing phase.
+ */
protected DexEncodedField[] instanceFields;
+ /**
+ * Access has to be synchronized during concurrent collection/writing phase.
+ */
protected DexEncodedMethod[] directMethods;
+ /**
+ * Access has to be synchronized during concurrent collection/writing phase.
+ */
protected DexEncodedMethod[] virtualMethods;
public DexAnnotationSet annotations;
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 3c9c796..b64053a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -8,17 +8,22 @@
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.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
public class DexProgramClass extends DexClass implements Supplier<DexProgramClass> {
+
+ private static DexEncodedArray SENTINEL_NOT_YET_COMPUTED = new DexEncodedArray(new DexValue[0]);
+
private final ProgramResource.Kind originKind;
- private DexEncodedArray staticValues;
+ private DexEncodedArray staticValues = SENTINEL_NOT_YET_COMPUTED;
private final Collection<DexProgramClass> synthesizedFrom;
public DexProgramClass(
@@ -97,10 +102,17 @@
if (interfaces != null) {
interfaces.collectIndexedItems(indexedItems);
}
- collectAll(indexedItems, staticFields);
- collectAll(indexedItems, instanceFields);
- collectAll(indexedItems, directMethods);
- collectAll(indexedItems, virtualMethods);
+ synchronizedCollectAll(indexedItems, staticFields);
+ synchronizedCollectAll(indexedItems, instanceFields);
+ synchronizedCollectAll(indexedItems, directMethods);
+ synchronizedCollectAll(indexedItems, virtualMethods);
+ }
+ }
+
+ private static <T extends DexItem> void synchronizedCollectAll(IndexedItemCollection collection,
+ T[] items) {
+ synchronized (items) {
+ collectAll(collection, items);
}
}
@@ -120,10 +132,10 @@
// We only have a class data item if there are methods or fields.
if (hasMethodsOrFields()) {
collector.add(this);
- collectAll(collector, directMethods);
- collectAll(collector, virtualMethods);
- collectAll(collector, staticFields);
- collectAll(collector, instanceFields);
+ synchronizedCollectAll(collector, directMethods);
+ synchronizedCollectAll(collector, virtualMethods);
+ synchronizedCollectAll(collector, staticFields);
+ synchronizedCollectAll(collector, instanceFields);
}
if (annotations != null) {
annotations.collectMixedSectionItems(collector);
@@ -134,6 +146,13 @@
annotations.collectMixedSectionItems(collector);
}
+ private static <T extends DexItem> void synchronizedCollectAll(MixedSectionCollection collection,
+ T[] items) {
+ synchronized (items) {
+ collectAll(collection, items);
+ }
+ }
+
@Override
public String toString() {
return type.toString();
@@ -176,11 +195,15 @@
}
private boolean hasAnnotations(DexEncodedField[] fields) {
- return fields != null && Arrays.stream(fields).anyMatch(DexEncodedField::hasAnnotation);
+ synchronized (fields) {
+ return Arrays.stream(fields).anyMatch(DexEncodedField::hasAnnotation);
+ }
}
private boolean hasAnnotations(DexEncodedMethod[] methods) {
- return methods != null && Arrays.stream(methods).anyMatch(DexEncodedMethod::hasAnnotation);
+ synchronized (methods) {
+ return Arrays.stream(methods).anyMatch(DexEncodedMethod::hasAnnotation);
+ }
}
private static Collection<DexProgramClass> accumulateSynthesizedFrom(
@@ -196,11 +219,38 @@
return accumulated;
}
- public void setStaticValues(DexEncodedArray staticValues) {
- this.staticValues = staticValues;
+ public void computeStaticValues(DexItemFactory factory) {
+ // It does not actually hurt to compute this multiple times. So racing on staticValues is OK.
+ if (staticValues == SENTINEL_NOT_YET_COMPUTED) {
+ synchronized (staticFields) {
+ assert PresortedComparable.isSorted(staticFields);
+ DexEncodedField[] fields = staticFields;
+ int length = 0;
+ List<DexValue> values = new ArrayList<>(fields.length);
+ for (int i = 0; i < fields.length; i++) {
+ DexEncodedField field = fields[i];
+ assert field.staticValue != null;
+ values.add(field.staticValue);
+ if (!field.staticValue.isDefault(field.field.type, factory)) {
+ length = i + 1;
+ }
+ }
+ if (length > 0) {
+ staticValues = new DexEncodedArray(
+ values.subList(0, length).toArray(new DexValue[length]));
+ } else {
+ staticValues = null;
+ }
+ }
+ }
}
public DexEncodedArray getStaticValues() {
+ // The sentinel value is left over for classes that actually have no fields.
+ if (staticValues == SENTINEL_NOT_YET_COMPUTED) {
+ assert !hasMethodsOrFields();
+ return null;
+ }
return staticValues;
}
@@ -208,30 +258,22 @@
assert !virtualMethod.accessFlags.isStatic();
assert !virtualMethod.accessFlags.isPrivate();
assert !virtualMethod.accessFlags.isConstructor();
- virtualMethods = Arrays.copyOf(virtualMethods, virtualMethods.length + 1);
- virtualMethods[virtualMethods.length - 1] = virtualMethod;
+ synchronized (virtualMethods) {
+ virtualMethods = Arrays.copyOf(virtualMethods, virtualMethods.length + 1);
+ virtualMethods[virtualMethods.length - 1] = virtualMethod;
+ }
}
public void addStaticMethod(DexEncodedMethod staticMethod) {
assert staticMethod.accessFlags.isStatic();
assert !staticMethod.accessFlags.isPrivate();
- directMethods = Arrays.copyOf(directMethods, directMethods.length + 1);
- directMethods[directMethods.length - 1] = staticMethod;
- }
-
- public void removeStaticMethod(DexEncodedMethod staticMethod) {
- assert staticMethod.accessFlags.isStatic();
- DexEncodedMethod[] newDirectMethods = new DexEncodedMethod[directMethods.length - 1];
- int toIndex = 0;
- for (int fromIndex = 0; fromIndex < directMethods.length; fromIndex++) {
- if (directMethods[fromIndex] != staticMethod) {
- newDirectMethods[toIndex++] = directMethods[fromIndex];
- }
+ synchronized (directMethods) {
+ directMethods = Arrays.copyOf(directMethods, directMethods.length + 1);
+ directMethods[directMethods.length - 1] = staticMethod;
}
- directMethods = newDirectMethods;
}
- public synchronized void sortMembers() {
+ public void sortMembers() {
sortEncodedFields(staticFields);
sortEncodedFields(instanceFields);
sortEncodedMethods(directMethods);
@@ -239,11 +281,15 @@
}
private void sortEncodedFields(DexEncodedField[] fields) {
- Arrays.sort(fields, Comparator.comparing(a -> a.field));
+ synchronized (fields) {
+ Arrays.sort(fields, Comparator.comparing(a -> a.field));
+ }
}
private void sortEncodedMethods(DexEncodedMethod[] methods) {
- Arrays.sort(methods, Comparator.comparing(a -> a.method));
+ synchronized (methods) {
+ Arrays.sort(methods, Comparator.comparing(a -> a.method));
+ }
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
index eb130d6..a4ee2ee 100644
--- a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
+++ b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
@@ -4,8 +4,26 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.naming.NamingLens;
+import java.util.function.Function;
public interface PresortedComparable<T> extends Presorted, Comparable<T> {
+
+ static <T extends PresortedComparable<T>> boolean isSorted(KeyedDexItem<T>[] items) {
+ return isSorted(items, KeyedDexItem::getKey);
+ }
+
+ static <S, T extends Comparable<T>> boolean isSorted(S[] items, Function<S, T> getter) {
+ T current = null;
+ for (S item : items) {
+ T next = getter.apply(item);
+ if (current != null && current.compareTo(next) >= 0) {
+ return false;
+ }
+ current = next;
+ }
+ return true;
+ }
+
// Slow comparison methods that make no use of indices for comparisons. These are used
// for sorting operations when reading dex files.
int slowCompareTo(T other);
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
index fe0ff72..552516d 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
@@ -12,19 +12,19 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueString;
-import com.android.tools.r8.shaking.ProguardClassNameList;
+import com.android.tools.r8.shaking.ProguardClassFilter;
import com.android.tools.r8.utils.DescriptorUtils;
import java.util.Map;
class IdentifierMinifier {
private final AppInfo appInfo;
- private final ProguardClassNameList adaptClassStrings;
+ private final ProguardClassFilter adaptClassStrings;
private final NamingLens lens;
IdentifierMinifier(
AppInfo appInfo,
- ProguardClassNameList adaptClassStrings,
+ ProguardClassFilter adaptClassStrings,
NamingLens lens) {
this.appInfo = appInfo;
this.adaptClassStrings = adaptClassStrings;
@@ -32,7 +32,7 @@
}
void run() {
- if (adaptClassStrings.size() != 0) {
+ if (!adaptClassStrings.isEmpty()) {
handleAdaptClassStrings();
}
// TODO(b/36799092): Handle influx of string literals from call sites to annotated members.
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassFilter.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassFilter.java
new file mode 100644
index 0000000..939dca3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassFilter.java
@@ -0,0 +1,64 @@
+// 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.shaking;
+
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.shaking.ProguardTypeMatcher.MatchSpecificType;
+import com.google.common.collect.ImmutableList;
+import java.util.Set;
+
+public class ProguardClassFilter {
+ private final ImmutableList<ProguardClassNameList> patterns;
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private final ImmutableList.Builder<ProguardClassNameList> patterns = ImmutableList.builder();
+
+ private Builder() {
+ }
+
+ public Builder addPattern(ProguardClassNameList pattern) {
+ patterns.add(pattern);
+ return this;
+ }
+
+ ProguardClassFilter build() {
+ return new ProguardClassFilter(patterns.build());
+ }
+ }
+
+ private ProguardClassFilter(ImmutableList<ProguardClassNameList> patterns) {
+ this.patterns = patterns;
+ }
+
+ public boolean isEmpty() {
+ return patterns.size() == 0;
+ }
+
+ public boolean matches(DexType type) {
+ for (ProguardClassNameList pattern : patterns) {
+ if (pattern.matches(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void filterOutMatches(Set<DexType> types) {
+ for (ProguardClassNameList pattern : patterns) {
+ pattern.forEachTypeMatcher(matcher -> {
+ if (matcher instanceof MatchSpecificType) {
+ assert matcher.getSpecificType() != null;
+ types.remove(matcher.getSpecificType());
+ } else {
+ types.removeIf(matcher::matches);
+ }
+ });
+ }
+ }
+}
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 dc800a3..3251c04 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -34,7 +34,7 @@
private boolean verbose;
private String renameSourceFileAttribute;
private final List<String> keepAttributePatterns = new ArrayList<>();
- private ProguardClassNameList dontWarnPatterns;
+ private ProguardClassFilter.Builder dontWarnPatterns = ProguardClassFilter.builder();
protected final List<ProguardConfigurationRule> rules = new ArrayList<>();
private final DexItemFactory dexItemFactory;
private boolean printSeeds;
@@ -44,8 +44,7 @@
private Path packageObfuscationDictionary;
private boolean useUniqueClassMemberNames;
private boolean keepParameterNames;
- private ProguardClassNameList adaptClassStrings = ProguardClassNameList.emptyList();
-
+ private ProguardClassFilter.Builder adaptClassStrings = ProguardClassFilter.builder();
private Builder(DexItemFactory dexItemFactory) {
this.dexItemFactory = dexItemFactory;
resetProguardDefaults();
@@ -69,7 +68,7 @@
verbose = false;
renameSourceFileAttribute = null;
keepAttributePatterns.clear();
- dontWarnPatterns = ProguardClassNameList.emptyList();
+ dontWarnPatterns = ProguardClassFilter.builder();
rules.clear();
printSeeds = false;
seedFile = null;
@@ -78,6 +77,7 @@
packageObfuscationDictionary = null;
useUniqueClassMemberNames = false;
keepParameterNames = false;
+ adaptClassStrings = ProguardClassFilter.builder();
}
public void addInjars(List<FilteredClassPath> injars) {
@@ -162,8 +162,8 @@
this.rules.add(rule);
}
- public void setDontWarnPatterns(ProguardClassNameList patterns) {
- dontWarnPatterns = patterns;
+ public void addDontWarnPattern(ProguardClassNameList pattern) {
+ dontWarnPatterns.addPattern(pattern);
}
public void setSeedFile(Path seedFile) {
@@ -202,8 +202,8 @@
return keepParameterNames;
}
- public void setAdaptClassStrings(ProguardClassNameList adaptClassStrings) {
- this.adaptClassStrings = adaptClassStrings;
+ public void addAdaptClassStringsPattern(ProguardClassNameList pattern) {
+ adaptClassStrings.addPattern(pattern);
}
public ProguardConfiguration build() throws CompilationException {
@@ -226,7 +226,7 @@
verbose,
renameSourceFileAttribute,
keepAttributePatterns,
- dontWarnPatterns,
+ dontWarnPatterns.build(),
rules,
printSeeds,
seedFile,
@@ -235,7 +235,7 @@
DictionaryReader.readAllNames(packageObfuscationDictionary),
useUniqueClassMemberNames,
keepParameterNames,
- adaptClassStrings);
+ adaptClassStrings.build());
}
}
@@ -257,7 +257,7 @@
private final boolean verbose;
private final String renameSourceFileAttribute;
private final ImmutableList<String> keepAttributesPatterns;
- private final ProguardClassNameList dontWarnPatterns;
+ private final ProguardClassFilter dontWarnPatterns;
protected final ImmutableList<ProguardConfigurationRule> rules;
private final boolean printSeeds;
private final Path seedFile;
@@ -266,7 +266,7 @@
private final ImmutableList<String> packageObfuscationDictionary;
private boolean useUniqueClassMemberNames;
private boolean keepParameterNames;
- private final ProguardClassNameList adaptClassStrings;
+ private final ProguardClassFilter adaptClassStrings;
private ProguardConfiguration(
DexItemFactory factory,
@@ -287,7 +287,7 @@
boolean verbose,
String renameSourceFileAttribute,
List<String> keepAttributesPatterns,
- ProguardClassNameList dontWarnPatterns,
+ ProguardClassFilter dontWarnPatterns,
List<ProguardConfigurationRule> rules,
boolean printSeeds,
Path seedFile,
@@ -296,7 +296,7 @@
ImmutableList<String> packageObfuscationDictionary,
boolean useUniqueClassMemberNames,
boolean keepParameterNames,
- ProguardClassNameList adaptClassStrings) {
+ ProguardClassFilter adaptClassStrings) {
this.dexItemFactory = factory;
this.injars = ImmutableList.copyOf(injars);
this.libraryjars = ImmutableList.copyOf(libraryjars);
@@ -419,7 +419,7 @@
return keepAttributesPatterns;
}
- public ProguardClassNameList getDontWarnPatterns() {
+ public ProguardClassFilter getDontWarnPatterns() {
return dontWarnPatterns;
}
@@ -447,7 +447,7 @@
return keepParameterNames;
}
- public ProguardClassNameList getAdaptClassStrings() {
+ public ProguardClassFilter getAdaptClassStrings() {
return adaptClassStrings;
}
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 ef63e40..40b7598 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -76,6 +76,7 @@
DexItemFactory dexItemFactory, DiagnosticsHandler diagnosticsHandler) {
this.dexItemFactory = dexItemFactory;
configurationBuilder = ProguardConfiguration.builder(dexItemFactory);
+
this.diagnosticsHandler = diagnosticsHandler;
}
@@ -212,9 +213,9 @@
configurationBuilder.setIgnoreWarnings(true);
} else if (acceptString("dontwarn")) {
if (isOptionalArgumentGiven()) {
- configurationBuilder.setDontWarnPatterns(parseClassNames());
+ configurationBuilder.addDontWarnPattern(parseClassNames());
} else {
- configurationBuilder.setDontWarnPatterns(
+ configurationBuilder.addDontWarnPattern(
ProguardClassNameList.singletonList(ProguardTypeMatcher.defaultAllMatcher()));
}
} else if (acceptString("repackageclasses")) {
@@ -292,9 +293,9 @@
} else if (acceptString("adaptclassstrings")) {
skipWhitespace();
if (isOptionalArgumentGiven()) {
- configurationBuilder.setAdaptClassStrings(parseClassNames());
+ configurationBuilder.addAdaptClassStringsPattern(parseClassNames());
} else {
- configurationBuilder.setAdaptClassStrings(
+ configurationBuilder.addAdaptClassStringsPattern(
ProguardClassNameList.singletonList(ProguardTypeMatcher.defaultAllMatcher()));
}
} else if (acceptString("identifiernamestring")) {
diff --git a/src/test/examples/autovalue/SimpleAutoValue.java b/src/test/examples/autovalue/SimpleAutoValue.java
new file mode 100644
index 0000000..2c0b2c6
--- /dev/null
+++ b/src/test/examples/autovalue/SimpleAutoValue.java
@@ -0,0 +1,54 @@
+// 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 autovalue;
+
+import com.google.auto.value.AutoValue;
+import javax.annotation.Nullable;
+
+public class SimpleAutoValue {
+
+ @AutoValue
+ static abstract class Pair {
+
+ Pair() {
+ // Intentionally left empty.
+ }
+
+ abstract int getOne();
+
+ @Nullable
+ abstract String getOther();
+
+ abstract String getRequiredOther();
+
+ static Builder builder() {
+ return new AutoValue_SimpleAutoValue_Pair.Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+
+ abstract Builder setOne(int value);
+
+ abstract Builder setOther(String value);
+
+ abstract Builder setRequiredOther(String value);
+
+ abstract Pair build();
+ }
+ }
+
+ public static void main(String... args) {
+ Pair.Builder builder = Pair.builder();
+ builder.setOne(42);
+ builder.setRequiredOther("123");
+ System.out.println(builder.build());
+ builder = Pair.builder();
+ try {
+ builder.build();
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/MinificationTest.java b/src/test/java/com/android/tools/r8/debug/MinificationTest.java
index a29562a..6a297cd 100644
--- a/src/test/java/com/android/tools/r8/debug/MinificationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/MinificationTest.java
@@ -3,9 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -63,19 +68,28 @@
final String innerClassName = minifiedNames ? "a" : "Minified$Inner";
final String innerMethodName = minifiedNames ? "a" : "innerTest";
final String innerSignature = "()I";
- runDebugTestR8(
- className,
- breakpoint(className, methodName, signature),
- run(),
- checkMethod(className, methodName, signature),
- checkLine(SOURCE_FILE, 14),
- stepOver(),
- checkMethod(className, methodName, signature),
- checkLine(SOURCE_FILE, 15),
- stepInto(),
- checkMethod(innerClassName, innerMethodName, innerSignature),
- checkLine(SOURCE_FILE, 8),
- run());
+ List<Command> commands =
+ new ArrayList<>(
+ Arrays.asList(
+ breakpoint(className, methodName, signature),
+ run(),
+ checkMethod(className, methodName, signature),
+ checkLine(SOURCE_FILE, 14),
+ stepOver(),
+ checkMethod(className, methodName, signature),
+ checkLine(SOURCE_FILE, 15),
+ stepInto()));
+ // Dalvik first enters ClassLoader, step over it.
+ // See also b/67225390.
+ if (ToolHelper.getDexVm() == DexVm.ART_4_4_4_HOST) {
+ commands.add(stepOver());
+ }
+ commands.addAll(
+ Arrays.asList(
+ checkMethod(innerClassName, innerMethodName, innerSignature),
+ checkLine(SOURCE_FILE, 8),
+ run()));
+ runDebugTestR8(className, commands);
}
@Test
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 00777fa..7912a9d 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -167,6 +167,25 @@
}
@Test
+ public void testDontWarnMultiple() throws Exception {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler);
+ List<String> configuration1 = ImmutableList.of("-dontwarn foo.**, bar.**");
+ List<String> configuration2 = ImmutableList.of("-dontwarn foo.**", "-dontwarn bar.**");
+ for (List<String> configuration : ImmutableList.of(configuration1, configuration2)) {
+ parser.parse(createConfigurationForTesting(configuration));
+ ProguardConfiguration config = parser.getConfig();
+ assertTrue(
+ config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoo/Bar;")));
+ assertTrue(
+ config.getDontWarnPatterns().matches(dexItemFactory.createType("Lfoo/bar7Bar;")));
+ assertTrue(
+ config.getDontWarnPatterns().matches(dexItemFactory.createType("Lbar/Foo;")));
+ }
+ }
+
+ @Test
public void testDontWarnAllExplicitly() throws Exception {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
@@ -360,6 +379,26 @@
}
@Test
+ public void testAdaptClassStringsMultiple() throws Exception {
+ DexItemFactory dexItemFactory = new DexItemFactory();
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(dexItemFactory, diagnosticsHandler);
+ List<String> configuration1 = ImmutableList.of("-adaptclassstrings foo.**, bar.**");
+ List<String> configuration2 =
+ ImmutableList.of("-adaptclassstrings foo.**", "-adaptclassstrings bar.**");
+ for (List<String> configuration : ImmutableList.of(configuration1, configuration2)) {
+ parser.parse(createConfigurationForTesting(configuration));
+ ProguardConfiguration config = parser.getConfig();
+ assertTrue(
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoo/Bar;")));
+ assertTrue(
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lfoo/bar7Bar;")));
+ assertTrue(
+ config.getAdaptClassStrings().matches(dexItemFactory.createType("Lbar/Foo;")));
+ }
+ }
+
+ @Test
public void testAdaptClassStringsAllExplicitly() throws Exception {
DexItemFactory dexItemFactory = new DexItemFactory();
ProguardConfigurationParser parser =
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
index 2737971..d8c43c9 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardNameMatchingTest.java
@@ -9,6 +9,9 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.shaking.ProguardTypeMatcher.ClassOrType;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.List;
import org.junit.Test;
public class ProguardNameMatchingTest {
@@ -24,12 +27,20 @@
}
private static boolean matchClassName(String className, String... patterns) {
- ProguardClassNameList.Builder builder = ProguardClassNameList.builder();
- for (String pattern : patterns) {
- boolean isNegated = pattern.startsWith("!");
- String actualPattern = isNegated ? pattern.substring(1) : pattern;
- builder.addClassName(isNegated,
- ProguardTypeMatcher.create(actualPattern, ClassOrType.CLASS, dexItemFactory));
+ return matchClassName(className, ImmutableList.of(Arrays.asList(patterns)));
+ }
+
+ private static boolean matchClassName(String className, List<List<String>> patternsList) {
+ ProguardClassFilter.Builder builder = ProguardClassFilter.builder();
+ for (List<String> patterns : patternsList) {
+ ProguardClassNameList.Builder listBuilder = ProguardClassNameList.builder();
+ for (String pattern : patterns) {
+ boolean isNegated = pattern.startsWith("!");
+ String actualPattern = isNegated ? pattern.substring(1) : pattern;
+ listBuilder.addClassName(isNegated,
+ ProguardTypeMatcher.create(actualPattern, ClassOrType.CLASS, dexItemFactory));
+ }
+ builder.addPattern(listBuilder.build());
}
return builder.build()
.matches(dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(className)));
@@ -65,6 +76,18 @@
assertTrue(matchClassName("boobar", "!foobar", "*bar"));
assertFalse(matchClassName("foobar", "!foobar", "*bar"));
+
+ assertFalse(matchClassName("foo", "!boo"));
+ assertFalse(matchClassName("foo", "baz,!boo"));
+
+ assertFalse(matchClassName("boo", "!boo", "**"));
+ assertTrue(matchClassName("boo", "**", "!boo"));
+ assertTrue(matchClassName("boo",
+ ImmutableList.of(ImmutableList.of("!boo"), ImmutableList.of("**"))));
+
+ assertFalse(matchClassName("boofoo", "!boo*,*foo,boofoo"));
+ assertTrue(matchClassName("boofoo",
+ ImmutableList.of(ImmutableList.of("!boo*,*foo"), ImmutableList.of("boofoo"))));
}
private void assertMatchesBasicTypes(String pattern) {
diff --git a/tools/archive.py b/tools/archive.py
index bb6c984..b88eb8d 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -78,7 +78,7 @@
version_file = os.path.join(temp, 'r8-version.properties')
with open(version_file,'w') as version_writer:
version_writer.write('version.sha=' + GetGitHash() + '\n')
- version_writer.write('releaser=' + os.environ.get('BUILDBOT_BUILDERNAME') + '\n')
+ version_writer.write('releaser=go/r8bot (' + os.environ.get('BUILDBOT_SLAVENAME') + ')\n')
version_writer.write('version-file.version.code=1\n')
for jar in [utils.D8_JAR, utils.R8_JAR, utils.COMPATDX_JAR, utils.COMPATPROGUARD_JAR]: