AutoValue and Immutable Collection Conversion: NestDigest and its Dependent Classes.
#java11 #desugar #refactor
- NestDigest and its Dependent Classes have been settled down to have clear boundary
between reading and writing.
- Followup of https://github.com/bazelbuild/bazel/commit/5dbaff6b836281bd22c8c1c92f9b95a52173c05f
PiperOrigin-RevId: 295281029
diff --git a/src/test/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecordTest.java b/src/test/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecordTest.java
index 85b4553..c0dd084 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecordTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecordTest.java
@@ -18,6 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
+import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord.ClassMemberRecordBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -25,9 +26,9 @@
/** Tests for {@link ClassMemberRecord}. */
@RunWith(JUnit4.class)
-public class ClassMemberRecordTest {
+public final class ClassMemberRecordTest {
- private final ClassMemberRecord classMemberRecord = ClassMemberRecord.create();
+ private final ClassMemberRecordBuilder classMemberRecord = ClassMemberRecord.builder();
@Test
public void trackFieldUse() {
@@ -38,7 +39,7 @@
classMemberRecord.logMemberUse(classMemberKey, Opcodes.H_GETFIELD);
classMemberRecord.logMemberUse(classMemberKey, Opcodes.H_PUTFIELD);
- assertThat(classMemberRecord.findAllMemberUseKind(classMemberKey))
+ assertThat(classMemberRecord.build().findAllMemberUseKind(classMemberKey))
.containsExactly(
MemberUseKind.GETFIELD,
MemberUseKind.PUTFIELD,
@@ -53,7 +54,7 @@
classMemberRecord.logMemberUse(classMemberKey, Opcodes.INVOKESPECIAL);
classMemberRecord.logMemberUse(classMemberKey, Opcodes.H_NEWINVOKESPECIAL);
- assertThat(classMemberRecord.findAllMemberUseKind(classMemberKey))
+ assertThat(classMemberRecord.build().findAllMemberUseKind(classMemberKey))
.containsExactly(MemberUseKind.INVOKESPECIAL, MemberUseKind.H_NEWINVOKESPECIAL);
}
@@ -72,7 +73,7 @@
classMemberRecord.logMemberUse(classMemberKey, Opcodes.H_NEWINVOKESPECIAL);
classMemberRecord.logMemberUse(classMemberKey, Opcodes.H_INVOKEINTERFACE);
- assertThat(classMemberRecord.findAllMemberUseKind(classMemberKey))
+ assertThat(classMemberRecord.build().findAllMemberUseKind(classMemberKey))
.containsExactly(
MemberUseKind.INVOKEVIRTUAL,
MemberUseKind.INVOKESPECIAL,
@@ -93,9 +94,10 @@
classMemberRecord.logMemberDecl(
classMemberKey, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, Opcodes.ACC_PRIVATE);
- assertThat(classMemberRecord.findOwnerAccessCode(classMemberKey))
+ ClassMemberRecord readOnlyClassMemberRecord = classMemberRecord.build();
+ assertThat(readOnlyClassMemberRecord.findOwnerAccessCode(classMemberKey))
.isEqualTo(Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER);
- assertThat(classMemberRecord.findMemberAccessCode(classMemberKey))
+ assertThat(readOnlyClassMemberRecord.findMemberAccessCode(classMemberKey))
.isEqualTo(Opcodes.ACC_PRIVATE);
}
@@ -107,15 +109,16 @@
classMemberKey,
Opcodes.ACC_DEPRECATED | Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER,
Opcodes.ACC_DEPRECATED | Opcodes.ACC_PRIVATE);
- assertThat(classMemberRecord.findOwnerAccessCode(classMemberKey))
+ ClassMemberRecord rawClassMemberRecord = classMemberRecord.build();
+ assertThat(rawClassMemberRecord.findOwnerAccessCode(classMemberKey))
.isEqualTo(Opcodes.ACC_DEPRECATED | Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER);
- assertThat(classMemberRecord.findMemberAccessCode(classMemberKey))
+ assertThat(rawClassMemberRecord.findMemberAccessCode(classMemberKey))
.isEqualTo(Opcodes.ACC_DEPRECATED | Opcodes.ACC_PRIVATE);
}
@Test
public void mergeRecord_trackingReasons() {
- ClassMemberRecord otherClassMemberRecord = ClassMemberRecord.create();
+ ClassMemberRecordBuilder otherClassMemberRecord = ClassMemberRecord.builder();
MethodKey method1 =
MethodKey.create(ClassName.create("package/path/OwnerClass"), "method1", "(II)I");
@@ -131,23 +134,24 @@
otherClassMemberRecord.logMemberUse(method2, Opcodes.INVOKESPECIAL);
otherClassMemberRecord.logMemberUse(method3, Opcodes.INVOKEVIRTUAL);
- classMemberRecord.mergeFrom(otherClassMemberRecord);
+ ClassMemberRecord mergedRecord =
+ classMemberRecord.mergeFrom(otherClassMemberRecord.build()).build();
- assertThat(classMemberRecord.hasDeclReason(method1)).isTrue();
- assertThat(classMemberRecord.findOwnerAccessCode(method1)).isEqualTo(Opcodes.ACC_SUPER);
- assertThat(classMemberRecord.findMemberAccessCode(method1)).isEqualTo(Opcodes.ACC_PRIVATE);
- assertThat(classMemberRecord.findAllMemberUseKind(method1)).isEmpty();
+ assertThat(mergedRecord.hasDeclReason(method1)).isTrue();
+ assertThat(mergedRecord.findOwnerAccessCode(method1)).isEqualTo(Opcodes.ACC_SUPER);
+ assertThat(mergedRecord.findMemberAccessCode(method1)).isEqualTo(Opcodes.ACC_PRIVATE);
+ assertThat(mergedRecord.findAllMemberUseKind(method1)).isEmpty();
- assertThat(classMemberRecord.hasDeclReason(method2)).isTrue();
- assertThat(classMemberRecord.findOwnerAccessCode(method2)).isEqualTo(Opcodes.ACC_SUPER);
- assertThat(classMemberRecord.findMemberAccessCode(method2)).isEqualTo(Opcodes.ACC_PRIVATE);
- assertThat(classMemberRecord.findAllMemberUseKind(method2))
+ assertThat(mergedRecord.hasDeclReason(method2)).isTrue();
+ assertThat(mergedRecord.findOwnerAccessCode(method2)).isEqualTo(Opcodes.ACC_SUPER);
+ assertThat(mergedRecord.findMemberAccessCode(method2)).isEqualTo(Opcodes.ACC_PRIVATE);
+ assertThat(mergedRecord.findAllMemberUseKind(method2))
.containsExactly(MemberUseKind.INVOKEVIRTUAL, MemberUseKind.INVOKESPECIAL);
- assertThat(classMemberRecord.hasDeclReason(method3)).isFalse();
- assertThat(classMemberRecord.findOwnerAccessCode(method3)).isEqualTo(0);
- assertThat(classMemberRecord.findMemberAccessCode(method3)).isEqualTo(0);
- assertThat(classMemberRecord.findAllMemberUseKind(method3))
+ assertThat(mergedRecord.hasDeclReason(method3)).isFalse();
+ assertThat(mergedRecord.findOwnerAccessCode(method3)).isEqualTo(0);
+ assertThat(mergedRecord.findMemberAccessCode(method3)).isEqualTo(0);
+ assertThat(mergedRecord.findAllMemberUseKind(method3))
.containsExactly(MemberUseKind.INVOKEVIRTUAL);
}
@@ -157,10 +161,12 @@
MethodKey.create(ClassName.create("package/path/OwnerClass"), "method", "(II)I");
classMemberRecord.logMemberUse(classMemberKey, Opcodes.INVOKEVIRTUAL);
- assertThat(classMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
+ ClassMemberRecord rawClassMemberRecord = classMemberRecord.build();
+ assertThat(rawClassMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
- classMemberRecord.filterUsedMemberWithTrackedDeclaration();
- assertThat(classMemberRecord.hasTrackingReason(classMemberKey)).isFalse();
+ ClassMemberRecord filteredRecord =
+ rawClassMemberRecord.filterUsedMemberWithTrackedDeclaration();
+ assertThat(filteredRecord.hasTrackingReason(classMemberKey)).isFalse();
}
@Test
@@ -170,10 +176,12 @@
classMemberRecord.logMemberDecl(
classMemberKey, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, Opcodes.ACC_PRIVATE);
- assertThat(classMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
+ ClassMemberRecord rawClassMemberRecord = classMemberRecord.build();
+ assertThat(rawClassMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
- classMemberRecord.filterUsedMemberWithTrackedDeclaration();
- assertThat(classMemberRecord.hasTrackingReason(classMemberKey)).isFalse();
+ ClassMemberRecord filteredRecord =
+ rawClassMemberRecord.filterUsedMemberWithTrackedDeclaration();
+ assertThat(filteredRecord.hasTrackingReason(classMemberKey)).isFalse();
}
@Test
@@ -183,9 +191,11 @@
classMemberRecord.logMemberDecl(
classMemberKey, Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE, Opcodes.ACC_PRIVATE);
- assertThat(classMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
+ ClassMemberRecord rawClassMemberRecord = classMemberRecord.build();
+ assertThat(rawClassMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
- classMemberRecord.filterUsedMemberWithTrackedDeclaration();
- assertThat(classMemberRecord.hasTrackingReason(classMemberKey)).isTrue();
+ ClassMemberRecord filteredRecord =
+ rawClassMemberRecord.filterUsedMemberWithTrackedDeclaration();
+ assertThat(filteredRecord.hasTrackingReason(classMemberKey)).isTrue();
}
}
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/NestAnalyzerTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/NestAnalyzerTest.java
index 24c3343..21c4f33 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/NestAnalyzerTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/NestAnalyzerTest.java
@@ -19,8 +19,6 @@
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.android.desugar.io.FileContentProvider;
-import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord;
-import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord;
import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
import com.google.devtools.build.android.desugar.testing.junit.DesugarRunner;
import com.google.devtools.build.android.desugar.testing.junit.JarEntryRecord;
@@ -51,15 +49,10 @@
.enableIterativeTransformation(0)
.build();
- private final ClassMemberRecord classMemberRecord = ClassMemberRecord.create();
- private final ClassAttributeRecord classAttributeRecord = ClassAttributeRecord.create();
- private final NestDigest nestDigest = NestDigest.create(classMemberRecord, classAttributeRecord);
-
@Test
public void emptyInputFiles() throws IOException {
- NestAnalyzer nestAnalyzer =
- new NestAnalyzer(ImmutableList.of(), nestDigest, classMemberRecord, classAttributeRecord);
- nestAnalyzer.analyze();
+ NestDigest nestDigest = NestAnalyzer.analyzeNests(ImmutableList.of());
+
assertThat(nestDigest.getAllCompanionClassNames()).isEmpty();
}
@@ -72,19 +65,15 @@
throws IOException {
JarFile jarFile = analyzedTarget.jarFile();
- NestAnalyzer nestAnalyzer =
- new NestAnalyzer(
+
+ NestDigest nestDigest =
+ NestAnalyzer.analyzeNests(
jarFile.stream()
.map(
entry ->
new FileContentProvider<>(
entry.getName(), () -> getJarEntryInputStream(jarFile, entry)))
- .collect(toImmutableList()),
- nestDigest,
- classMemberRecord,
- classAttributeRecord);
-
- nestAnalyzer.analyze();
+ .collect(toImmutableList()));
assertThat(nestDigest.getAllCompanionClassNames())
.containsExactly(
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/NestDigestTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/NestDigestTest.java
index d789b3b..0f95132 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/NestDigestTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/NestDigestTest.java
@@ -17,8 +17,10 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord;
+import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord.ClassAttributeRecordBuilder;
import com.google.devtools.build.android.desugar.langmodel.ClassAttributes;
import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord;
+import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord.ClassMemberRecordBuilder;
import com.google.devtools.build.android.desugar.langmodel.ClassName;
import com.google.devtools.build.android.desugar.langmodel.MethodKey;
import org.junit.Test;
@@ -28,11 +30,10 @@
/** The tests for {@link NestDigest}. */
@RunWith(JUnit4.class)
-public class NestDigestTest {
+public final class NestDigestTest {
- private final ClassMemberRecord classMemberRecord = ClassMemberRecord.create();
- private final ClassAttributeRecord classAttributeRecord = ClassAttributeRecord.create();
- private final NestDigest nestDigest = NestDigest.create(classMemberRecord, classAttributeRecord);
+ private final ClassMemberRecordBuilder classMemberRecord = ClassMemberRecord.builder();
+ private final ClassAttributeRecordBuilder classAttributeRecord = ClassAttributeRecord.builder();
@Test
public void prepareCompanionClassWriters_noCompanionClassesGenerated() {
@@ -41,7 +42,11 @@
/* ownerAccess= */ Opcodes.ACC_PUBLIC | Opcodes.ACC_INTERFACE,
/* memberDeclAccess= */ Opcodes.ACC_PRIVATE);
- nestDigest.prepareCompanionClasses();
+ NestDigest nestDigest =
+ NestDigest.builder()
+ .setClassMemberRecord(classMemberRecord.build())
+ .setClassAttributeRecord(classAttributeRecord.build())
+ .build();
assertThat(nestDigest.getAllCompanionClassNames()).isEmpty();
}
@@ -53,18 +58,22 @@
classMemberRecord.logMemberDecl(
constructor, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, Opcodes.ACC_PRIVATE);
classMemberRecord.logMemberUse(constructor, Opcodes.INVOKESPECIAL);
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create("package/path/OwnerClass$NestedClass"))
.setNestHost(ClassName.create("package/path/OwnerClass"))
.build());
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create("package/path/OwnerClass"))
.addNestMember(ClassName.create("package/path/OwnerClass$NestedClass"))
.build());
- nestDigest.prepareCompanionClasses();
+ NestDigest nestDigest =
+ NestDigest.builder()
+ .setClassMemberRecord(classMemberRecord.build())
+ .setClassAttributeRecord(classAttributeRecord.build())
+ .build();
assertThat(nestDigest.getAllCompanionClassNames())
.containsExactly("package/path/OwnerClass$NestCC");
@@ -95,29 +104,33 @@
MethodKey.create(ClassName.create("package/path/OwnerClassB"), "<init>", "()V"),
Opcodes.INVOKESPECIAL);
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create("package/path/OwnerClassA$NestedClass"))
.setNestHost(ClassName.create("package/path/OwnerClassA"))
.build());
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create("package/path/OwnerClassB$NestedClass"))
.setNestHost(ClassName.create("package/path/OwnerClassB"))
.build());
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create("package/path/OwnerClassA"))
.addNestMember(ClassName.create("package/path/OwnerClassA$NestedClass"))
.build());
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create("package/path/OwnerClassB"))
.addNestMember(ClassName.create("package/path/OwnerClassB$NestedClass"))
.build());
- nestDigest.prepareCompanionClasses();
+ NestDigest nestDigest =
+ NestDigest.builder()
+ .setClassMemberRecord(classMemberRecord.build())
+ .setClassAttributeRecord(classAttributeRecord.build())
+ .build();
assertThat(nestDigest.getAllCompanionClassNames())
.containsExactly("package/path/OwnerClassA$NestCC", "package/path/OwnerClassB$NestCC");
@@ -132,18 +145,22 @@
constructor, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, Opcodes.ACC_PRIVATE);
classMemberRecord.logMemberUse(constructor, Opcodes.INVOKESPECIAL);
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create(constructor.ownerName() + "$NestClass"))
.setNestHost(ClassName.create(constructor.ownerName()))
.build());
- classAttributeRecord.setClassAttributes(
+ classAttributeRecord.addClassAttributes(
ClassAttributes.builder()
.setClassBinaryName(ClassName.create(constructor.ownerName()))
.addNestMember(ClassName.create(constructor.ownerName() + "$NestClass"))
.build());
- nestDigest.prepareCompanionClasses();
+ NestDigest nestDigest =
+ NestDigest.builder()
+ .setClassMemberRecord(classMemberRecord.build())
+ .setClassAttributeRecord(classAttributeRecord.build())
+ .build();
assertThat(nestDigest.getAllCompanionClassNames())
.containsExactly("package/path/$Owner$Class$$NestCC");
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
index 625eb1c..9eff3bc 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
@@ -40,8 +40,6 @@
import com.google.devtools.build.android.desugar.io.InputFileProvider;
import com.google.devtools.build.android.desugar.io.OutputFileProvider;
import com.google.devtools.build.android.desugar.io.ThrowingClassLoader;
-import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord;
-import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord;
import com.google.devtools.build.android.desugar.langmodel.ClassMemberUseCounter;
import com.google.devtools.build.android.desugar.nest.NestAnalyzer;
import com.google.devtools.build.android.desugar.nest.NestDesugaring;
@@ -655,12 +653,10 @@
ClassVsInterface interfaceCache,
ImmutableSet.Builder<String> interfaceLambdaMethodCollector)
throws IOException {
- ClassMemberRecord classMemberRecord = ClassMemberRecord.create();
- ClassAttributeRecord classAttributeRecord = ClassAttributeRecord.create();
+
ImmutableList<FileContentProvider<? extends InputStream>> inputFileContents =
inputFiles.toInputFileStreams();
- NestDigest nestDigest =
- NestAnalyzer.analyzeNests(inputFileContents, classMemberRecord, classAttributeRecord);
+ NestDigest nestDigest = NestAnalyzer.analyzeNests(inputFileContents);
// Apply core library type name remapping to the digest instance produced by the nest analyzer,
// since the analysis-oriented nest analyzer visits core library classes without name remapping
// as those transformation-oriented visitors.
@@ -1142,6 +1138,7 @@
return 0;
}
+ @SuppressWarnings("CatchAndPrintStackTrace")
static void verifyLambdaDumpDirectoryRegistered(Path dumpDirectory) throws IOException {
try {
Class<?> klass = Class.forName("java.lang.invoke.InnerClassLambdaMetafactory");
@@ -1161,7 +1158,7 @@
} catch (ReflectiveOperationException e) {
// We do not want to crash Desugar, if we cannot load or access these classes or fields.
// We aim to provide better diagnostics. If we cannot, just let it go.
- e.printStackTrace(System.err); // To silence error-prone's complaint.
+ e.printStackTrace(System.err);
}
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassAttributeRecord.java b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassAttributeRecord.java
index 95b21e0..b54b2fe 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassAttributeRecord.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassAttributeRecord.java
@@ -18,58 +18,59 @@
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
/** Tracks {@link ClassAttributes} for all classes under investigation. */
-public final class ClassAttributeRecord implements TypeMappable<ClassAttributeRecord> {
+@AutoValue
+public abstract class ClassAttributeRecord implements TypeMappable<ClassAttributeRecord> {
- private final Map<ClassName, ClassAttributes> record;
+ public abstract ImmutableMap<ClassName, ClassAttributes> record();
- public static ClassAttributeRecord create() {
- return new ClassAttributeRecord(new HashMap<>());
+ public static ClassAttributeRecordBuilder builder() {
+ return new AutoValue_ClassAttributeRecord.Builder();
}
- private ClassAttributeRecord(Map<ClassName, ClassAttributes> record) {
- this.record = record;
- }
-
- public ClassAttributes setClassAttributes(ClassAttributes classAttributes) {
- ClassName classBinaryName = classAttributes.classBinaryName();
- if (record.containsKey(classBinaryName)) {
- throw new IllegalStateException(
- String.format(
- "Expected the ClassAttributes of a class to be put into this record only once during"
- + " {@link ClassVisitor#visitEnd}: Pre-existing: (%s), Now (%s)",
- record.get(classBinaryName), classAttributes));
- }
- return record.put(classBinaryName, classAttributes);
- }
-
- public Optional<ClassName> getNestHost(ClassName className) {
- ClassAttributes classAttributes = record.get(className);
+ public final Optional<ClassName> getNestHost(ClassName className) {
+ ClassAttributes classAttributes = record().get(className);
checkNotNull(
classAttributes,
"Expected recorded ClassAttributes for (%s). Available record: %s",
className,
- record.keySet());
+ record().keySet());
return classAttributes.nestHost();
}
- public ImmutableSet<ClassName> getNestMembers(ClassName className) {
- ClassAttributes classAttributes = record.get(className);
+ public final ImmutableSet<ClassName> getNestMembers(ClassName className) {
+ ClassAttributes classAttributes = record().get(className);
checkNotNull(
classAttributes,
"Expected recorded ClassAttributes for (%s). Available record: %s",
className,
- record.keySet());
+ record().keySet());
return classAttributes.nestMembers();
}
@Override
- public ClassAttributeRecord acceptTypeMapper(TypeMapper typeMapper) {
- return new ClassAttributeRecord(typeMapper.mapMutable(record));
+ public final ClassAttributeRecord acceptTypeMapper(TypeMapper typeMapper) {
+ return ClassAttributeRecord.builder().setRecord(typeMapper.map(record())).build();
+ }
+
+ /** The builder for {@link ClassAttributeRecord}. */
+ @AutoValue.Builder
+ public abstract static class ClassAttributeRecordBuilder {
+
+ abstract ImmutableMap.Builder<ClassName, ClassAttributes> recordBuilder();
+
+ abstract ClassAttributeRecordBuilder setRecord(ImmutableMap<ClassName, ClassAttributes> record);
+
+ public final ClassAttributeRecordBuilder addClassAttributes(ClassAttributes classAttributes) {
+ recordBuilder().put(classAttributes.classBinaryName(), classAttributes);
+ return this;
+ }
+
+ public abstract ClassAttributeRecord build();
}
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecord.java b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecord.java
index 28786ae..0608a91 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecord.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberRecord.java
@@ -17,8 +17,13 @@
package com.google.devtools.build.android.desugar.langmodel;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableMap.toImmutableMap;
+import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.devtools.build.android.desugar.langmodel.ClassMemberTrackReason.ClassMemberTrackReasonBuilder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Predicate;
@@ -27,105 +32,123 @@
* A record that tracks the declarations and usages of a class member, including fields,
* constructors and methods.
*/
-public final class ClassMemberRecord implements TypeMappable<ClassMemberRecord> {
+@AutoValue
+public abstract class ClassMemberRecord implements TypeMappable<ClassMemberRecord> {
/** Tracks a class member with a reason. */
- private final Map<ClassMemberKey<?>, ClassMemberTrackReason> reasons;
+ abstract ImmutableMap<ClassMemberKey<?>, ClassMemberTrackReason> reasons();
- /** The factory method of this class. */
- public static ClassMemberRecord create() {
- return new ClassMemberRecord(new LinkedHashMap<>());
+ /** Creates a builder instance for this class. */
+ public static ClassMemberRecordBuilder builder() {
+ return new AutoValue_ClassMemberRecord.Builder();
}
/** Gets class members with both tracked declarations and tracked usage. */
- public boolean filterUsedMemberWithTrackedDeclaration() {
- return reasons
- .values()
- .removeIf(
- reason -> {
- // keep interface members and class members with use references.
- return !(reason.hasInterfaceDeclReason()
- || (reason.hasDeclReason() && reason.hasMemberUseReason()));
- });
- }
-
- private ClassMemberRecord(Map<ClassMemberKey<?>, ClassMemberTrackReason> reasons) {
- this.reasons = reasons;
+ public final ClassMemberRecord filterUsedMemberWithTrackedDeclaration() {
+ return builder()
+ .setReasons(
+ reasons().entrySet().stream()
+ .filter(
+ entry -> {
+ ClassMemberTrackReason reason = entry.getValue();
+ // keep interface members and class members with use references.
+ return reason.hasInterfaceDeclReason()
+ || (reason.hasDeclReason() && reason.hasMemberUseReason());
+ })
+ .collect(toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)))
+ .autoInternalBuild();
}
/** Find all member keys that represent a constructor. */
- public ImmutableList<ClassMemberKey<?>> findAllConstructorMemberKeys() {
+ public final ImmutableList<ClassMemberKey<?>> findAllConstructorMemberKeys() {
return findAllMatchedMemberKeys(ClassMemberKey::isConstructor);
}
/** Find all member keys based on the given member key predicate. */
- ImmutableList<ClassMemberKey<?>> findAllMatchedMemberKeys(
+ private ImmutableList<ClassMemberKey<?>> findAllMatchedMemberKeys(
Predicate<ClassMemberKey<?>> predicate) {
- return reasons.keySet().stream().filter(predicate).collect(toImmutableList());
+ return reasons().keySet().stream().filter(predicate).collect(toImmutableList());
}
- /** Whether this record has any reason to desugar a nest. */
- public boolean hasAnyReason() {
- return !reasons.isEmpty();
+ public final boolean hasTrackingReason(ClassMemberKey<?> classMemberKey) {
+ return reasons().containsKey(classMemberKey);
}
- public boolean hasTrackingReason(ClassMemberKey<?> classMemberKey) {
- return reasons.containsKey(classMemberKey);
- }
-
- boolean hasDeclReason(ClassMemberKey<?> classMemberKey) {
- return hasTrackingReason(classMemberKey) && reasons.get(classMemberKey).hasDeclReason();
+ final boolean hasDeclReason(ClassMemberKey<?> classMemberKey) {
+ return hasTrackingReason(classMemberKey) && reasons().get(classMemberKey).hasDeclReason();
}
/** Find the original access code for the owner of the class member. */
- int findOwnerAccessCode(ClassMemberKey<?> memberKey) {
- if (reasons.containsKey(memberKey)) {
- return reasons.get(memberKey).getOwnerAccess();
+ final int findOwnerAccessCode(ClassMemberKey<?> memberKey) {
+ if (reasons().containsKey(memberKey)) {
+ return reasons().get(memberKey).ownerAccess();
}
throw new IllegalStateException(String.format("ClassMemberKey Not Found: %s", memberKey));
}
/** Find the original access code for the class member declaration. */
- int findMemberAccessCode(ClassMemberKey<?> memberKey) {
- if (reasons.containsKey(memberKey)) {
- return reasons.get(memberKey).getMemberAccess();
+ final int findMemberAccessCode(ClassMemberKey<?> memberKey) {
+ if (reasons().containsKey(memberKey)) {
+ return reasons().get(memberKey).memberAccess();
}
throw new IllegalStateException(String.format("ClassMemberKey Not Found: %s", memberKey));
}
/** Find all invocation codes of a class member. */
- public ImmutableList<MemberUseKind> findAllMemberUseKind(ClassMemberKey<?> memberKey) {
- if (reasons.containsKey(memberKey)) {
- return ImmutableList.copyOf(reasons.get(memberKey).getUseAccesses());
- }
- return ImmutableList.of();
- }
-
- /** Logs the declaration of a class member. */
- public ClassMemberTrackReason logMemberDecl(
- ClassMemberKey<?> memberKey, int ownerAccess, int memberDeclAccess) {
- return reasons
- .computeIfAbsent(memberKey, classMemberKey -> new ClassMemberTrackReason())
- .setDeclAccess(ownerAccess, memberDeclAccess);
- }
-
- /** Logs the use of a class member, including field access and method invocations. */
- public ClassMemberTrackReason logMemberUse(ClassMemberKey<?> memberKey, int invokeOpcode) {
- return reasons
- .computeIfAbsent(memberKey, classMemberKey -> new ClassMemberTrackReason())
- .addUseAccess(invokeOpcode);
- }
-
- /** Merge an another member record into this record. */
- public void mergeFrom(ClassMemberRecord otherClassMemberRecord) {
- otherClassMemberRecord.reasons.forEach(
- (classMemberKey, classMemberTrackReason) ->
- reasons.merge(
- classMemberKey, classMemberTrackReason, ClassMemberTrackReason::mergeFrom));
+ public final ImmutableList<MemberUseKind> findAllMemberUseKind(ClassMemberKey<?> memberKey) {
+ return reasons().containsKey(memberKey)
+ ? reasons().get(memberKey).useAccesses().asList()
+ : ImmutableList.of();
}
@Override
public ClassMemberRecord acceptTypeMapper(TypeMapper typeMapper) {
- return new ClassMemberRecord(typeMapper.mapKey(reasons));
+ return builder().setReasons(typeMapper.mapKey(reasons())).autoInternalBuild();
+ }
+
+ /** The builder for {@link ClassMemberRecord}. */
+ @AutoValue.Builder
+ public abstract static class ClassMemberRecordBuilder {
+
+ private final Map<ClassMemberKey<?>, ClassMemberTrackReasonBuilder> reasonsCollector =
+ new LinkedHashMap<>();
+
+ abstract ClassMemberRecordBuilder setReasons(
+ Map<ClassMemberKey<?>, ClassMemberTrackReason> value);
+
+ /** Logs the declaration of a class member. */
+ public final ClassMemberTrackReasonBuilder logMemberDecl(
+ ClassMemberKey<?> memberKey, int ownerAccess, int memberDeclAccess) {
+ return getTrackReason(memberKey).setDeclAccess(ownerAccess, memberDeclAccess);
+ }
+
+ /** Logs the use of a class member, including field access and method invocations. */
+ public final ClassMemberTrackReasonBuilder logMemberUse(
+ ClassMemberKey<?> memberKey, int invokeOpcode) {
+ return getTrackReason(memberKey).addUseAccess(invokeOpcode);
+ }
+
+ /** Merges an another member record into this record builder. */
+ public final ClassMemberRecordBuilder mergeFrom(ClassMemberRecord otherClassMemberRecord) {
+ otherClassMemberRecord
+ .reasons()
+ .forEach(
+ (otherMemberKey, otherMemberTrackReason) ->
+ getTrackReason(otherMemberKey).mergeFrom(otherMemberTrackReason));
+ return this;
+ }
+
+ private ClassMemberTrackReasonBuilder getTrackReason(ClassMemberKey<?> memberKey) {
+ return reasonsCollector.computeIfAbsent(
+ memberKey, classMemberKey -> ClassMemberTrackReason.builder());
+ }
+
+ public final ClassMemberRecord build() {
+ return setReasons(
+ Maps.transformValues(reasonsCollector, ClassMemberTrackReasonBuilder::build))
+ .autoInternalBuild();
+ }
+
+ abstract ClassMemberRecord autoInternalBuild();
}
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberTrackReason.java b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberTrackReason.java
index 223682f..8c06f32 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberTrackReason.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/ClassMemberTrackReason.java
@@ -16,98 +16,79 @@
package com.google.devtools.build.android.desugar.langmodel;
-import com.google.common.hash.Hashing;
-import java.util.EnumSet;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
import org.objectweb.asm.Opcodes;
/**
* Used to track the declaration and invocation information of a class member, including fields,
* constructors and methods.
*/
-public final class ClassMemberTrackReason {
+@AutoValue
+abstract class ClassMemberTrackReason {
- private boolean hasDeclReason;
- private int ownerAccess;
- private int memberAccess;
- private final EnumSet<MemberUseKind> useAccesses = EnumSet.noneOf(MemberUseKind.class);
+ abstract boolean hasDeclReason();
- ClassMemberTrackReason setDeclAccess(int ownerAccess, int memberAccess) {
- this.ownerAccess = ownerAccess;
- this.memberAccess = memberAccess;
- this.hasDeclReason = true;
- return this;
+ abstract int ownerAccess();
+
+ abstract int memberAccess();
+
+ abstract ImmutableSet<MemberUseKind> useAccesses();
+
+ public static ClassMemberTrackReasonBuilder builder() {
+ return new AutoValue_ClassMemberTrackReason.Builder()
+ .setHasDeclReason(false)
+ .setOwnerAccess(0)
+ .setMemberAccess(0);
}
- ClassMemberTrackReason addUseAccess(int invokeOpcode) {
- this.useAccesses.add(MemberUseKind.fromValue(invokeOpcode));
- return this;
+ abstract ClassMemberTrackReasonBuilder toBuilder();
+
+ final boolean hasInterfaceDeclReason() {
+ return hasDeclReason() && (ownerAccess() & Opcodes.ACC_INTERFACE) != 0;
}
- boolean hasDeclReason() {
- return hasDeclReason;
+ final boolean hasMemberUseReason() {
+ return !useAccesses().isEmpty();
}
- boolean hasInterfaceDeclReason() {
- return hasDeclReason && (ownerAccess & Opcodes.ACC_INTERFACE) != 0;
- }
+ /** The builder for {@link ClassMemberTrackReason}. */
+ @AutoValue.Builder
+ abstract static class ClassMemberTrackReasonBuilder {
- boolean hasMemberUseReason() {
- return !useAccesses.isEmpty();
- }
+ abstract ClassMemberTrackReasonBuilder setHasDeclReason(boolean value);
- int getOwnerAccess() {
- return ownerAccess;
- }
+ abstract ClassMemberTrackReasonBuilder setOwnerAccess(int value);
- int getMemberAccess() {
- return memberAccess;
- }
+ abstract ClassMemberTrackReasonBuilder setMemberAccess(int value);
- EnumSet<MemberUseKind> getUseAccesses() {
- return useAccesses;
- }
+ abstract ClassMemberTrackReasonBuilder setUseAccesses(Collection<MemberUseKind> value);
- ClassMemberTrackReason mergeFrom(ClassMemberTrackReason otherClassMemberTrackReason) {
- if (!hasDeclReason() && otherClassMemberTrackReason.hasDeclReason()) {
- ownerAccess = otherClassMemberTrackReason.getOwnerAccess();
- memberAccess = otherClassMemberTrackReason.getMemberAccess();
- hasDeclReason = true;
+ abstract ImmutableSet.Builder<MemberUseKind> useAccessesBuilder();
+
+ final ClassMemberTrackReasonBuilder setDeclAccess(int ownerAccess, int memberAccess) {
+ return setHasDeclReason(true).setOwnerAccess(ownerAccess).setMemberAccess(memberAccess);
}
- useAccesses.addAll(otherClassMemberTrackReason.getUseAccesses());
- return this;
- }
- @Override
- public int hashCode() {
- return Hashing.sha256()
- .newHasher()
- .putBoolean(hasDeclReason)
- .putInt(ownerAccess)
- .putInt(memberAccess)
- .putInt(useAccesses.hashCode())
- .hash()
- .asInt();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
+ final ClassMemberTrackReasonBuilder addUseAccess(int invokeOpcode) {
+ useAccessesBuilder().add(MemberUseKind.fromValue(invokeOpcode));
+ return this;
}
- if (obj instanceof ClassMemberTrackReason) {
- ClassMemberTrackReason other = (ClassMemberTrackReason) obj;
- return this.hasDeclReason == other.hasDeclReason
- && this.ownerAccess == other.ownerAccess
- && this.memberAccess == other.memberAccess
- && this.useAccesses.equals(other.useAccesses);
- }
- return false;
- }
- @Override
- public String toString() {
- return String.format(
- "%s{hasDeclReason=%s, ownerAccess=%d, memberAccess=%d, useAccesses=%s}",
- getClass().getSimpleName(), hasDeclReason, ownerAccess, memberAccess, useAccesses);
+ final ClassMemberTrackReasonBuilder addAllUseAccesses(Collection<MemberUseKind> values) {
+ useAccessesBuilder().addAll(values);
+ return this;
+ }
+
+ final ClassMemberTrackReasonBuilder mergeFrom(ClassMemberTrackReason otherReason) {
+ if (otherReason.hasDeclReason()) {
+ setDeclAccess(otherReason.ownerAccess(), otherReason.memberAccess());
+ }
+ addAllUseAccesses(otherReason.useAccesses());
+ return this;
+ }
+
+ abstract ClassMemberTrackReason build();
}
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/TypeMapper.java b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/TypeMapper.java
index 25ecee2..4ed92bd 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/TypeMapper.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/langmodel/TypeMapper.java
@@ -20,14 +20,11 @@
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.stream.Collectors.toCollection;
-import static java.util.stream.Collectors.toMap;
import com.google.common.collect.ConcurrentHashMultiset;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import java.util.HashMap;
-import java.util.Map;
import java.util.function.Function;
import org.objectweb.asm.commons.Remapper;
@@ -73,32 +70,10 @@
e -> e.getKey().acceptTypeMapper(this), e -> e.getValue().acceptTypeMapper(this)));
}
- // TODO(b/149403079): Remove this method once the map collection used by referencing classes have
- // been migrated to immutable.
- public <K extends TypeMappable<? extends K>, V extends TypeMappable<V>> Map<K, V> mapMutable(
- Map<K, V> mappableTypes) {
- return mappableTypes.entrySet().stream()
- .collect(
- toMap(
- e -> e.getKey().acceptTypeMapper(this),
- e -> e.getValue().acceptTypeMapper(this),
- (prev, next) -> next,
- HashMap::new));
- }
-
public <K extends TypeMappable<? extends K>, V> ImmutableMap<K, V> mapKey(
ImmutableMap<K, V> mappableTypes) {
return mappableTypes.entrySet().stream()
.collect(toImmutableMap(e -> e.getKey().acceptTypeMapper(this), e -> e.getValue()));
}
- public <K extends TypeMappable<? extends K>, V> Map<K, V> mapKey(Map<K, V> mappableTypes) {
- return mappableTypes.entrySet().stream()
- .collect(
- toMap(
- e -> e.getKey().acceptTypeMapper(this),
- e -> e.getValue(),
- (prev, next) -> next,
- HashMap::new));
- }
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/nest/CrossMateMainCollector.java b/src/tools/android/java/com/google/devtools/build/android/desugar/nest/CrossMateMainCollector.java
index 24d7b65..937abb6 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/nest/CrossMateMainCollector.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/nest/CrossMateMainCollector.java
@@ -14,10 +14,11 @@
package com.google.devtools.build.android.desugar.nest;
-import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord;
+import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord.ClassAttributeRecordBuilder;
import com.google.devtools.build.android.desugar.langmodel.ClassAttributes;
import com.google.devtools.build.android.desugar.langmodel.ClassAttributes.ClassAttributesBuilder;
import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord;
+import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord.ClassMemberRecordBuilder;
import com.google.devtools.build.android.desugar.langmodel.ClassName;
import com.google.devtools.build.android.desugar.langmodel.FieldKey;
import com.google.devtools.build.android.desugar.langmodel.LangModelHelper;
@@ -34,15 +35,15 @@
final class CrossMateMainCollector extends ClassVisitor {
/** The project-wise class member records. */
- private final ClassMemberRecord memberRecord;
+ private final ClassMemberRecordBuilder memberRecord;
- private final ClassAttributeRecord classAttributeRecord;
+ private final ClassAttributeRecordBuilder classAttributeRecord;
/**
* An class member record to stage member record candidates, merging into the project-wise member
* record during the {@link #visitEnd()} where eligible conditions are specified.
*/
- private final ClassMemberRecord stagingMemberRecord = ClassMemberRecord.create();
+ private final ClassMemberRecordBuilder stagingMemberRecord = ClassMemberRecord.builder();
private final ClassAttributesBuilder classAttributesBuilder = ClassAttributes.builder();
@@ -51,7 +52,7 @@
private boolean isInNest;
public CrossMateMainCollector(
- ClassMemberRecord memberRecord, ClassAttributeRecord classAttributeRecord) {
+ ClassMemberRecordBuilder memberRecord, ClassAttributeRecordBuilder classAttributeRecord) {
super(Opcodes.ASM7);
this.memberRecord = memberRecord;
this.classAttributeRecord = classAttributeRecord;
@@ -129,9 +130,9 @@
@Override
public void visitEnd() {
if (isInNest || (classAccessCode & Opcodes.ACC_INTERFACE) != 0) {
- memberRecord.mergeFrom(stagingMemberRecord);
+ memberRecord.mergeFrom(stagingMemberRecord.build());
}
- classAttributeRecord.setClassAttributes(classAttributesBuilder.build());
+ classAttributeRecord.addClassAttributes(classAttributesBuilder.build());
super.visitEnd();
}
@@ -150,10 +151,12 @@
*
* <p>@see CrossMateMainCollector#stagingMemberRecord for more details.
*/
- private final ClassMemberRecord memberRecord;
+ private final ClassMemberRecordBuilder memberRecord;
CrossMateRefCollector(
- MethodVisitor methodVisitor, MethodKey enclosingMethodKey, ClassMemberRecord memberRecord) {
+ MethodVisitor methodVisitor,
+ MethodKey enclosingMethodKey,
+ ClassMemberRecordBuilder memberRecord) {
super(Opcodes.ASM7, methodVisitor);
this.enclosingMethodKey = enclosingMethodKey;
this.memberRecord = memberRecord;
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestAnalyzer.java b/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestAnalyzer.java
index 14a0e77..204dfea 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestAnalyzer.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestAnalyzer.java
@@ -16,11 +16,12 @@
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.android.desugar.io.FileContentProvider;
import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord;
+import com.google.devtools.build.android.desugar.langmodel.ClassAttributeRecord.ClassAttributeRecordBuilder;
import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord;
+import com.google.devtools.build.android.desugar.langmodel.ClassMemberRecord.ClassMemberRecordBuilder;
import java.io.IOException;
import java.io.InputStream;
import org.objectweb.asm.ClassReader;
@@ -32,9 +33,8 @@
public class NestAnalyzer {
private final ImmutableList<FileContentProvider<? extends InputStream>> inputFileContents;
- private final NestDigest nestDigest;
- private final ClassMemberRecord classMemberRecord;
- private final ClassAttributeRecord classAttributeRecord;
+ private final ClassMemberRecordBuilder classMemberRecord;
+ private final ClassAttributeRecordBuilder classAttributeRecord;
/**
* Perform a nest-based analysis of input classes, including tracking private member access
@@ -43,32 +43,25 @@
* @return A manager class for nest companions.
*/
public static NestDigest analyzeNests(
- ImmutableList<FileContentProvider<? extends InputStream>> inputFileContents,
- ClassMemberRecord classMemberRecord,
- ClassAttributeRecord classAttributeRecord)
+ ImmutableList<FileContentProvider<? extends InputStream>> inputFileContents)
throws IOException {
- NestDigest nestDigest = NestDigest.create(classMemberRecord, classAttributeRecord);
NestAnalyzer nestAnalyzer =
- new NestAnalyzer(inputFileContents, nestDigest, classMemberRecord, classAttributeRecord);
- nestAnalyzer.analyze();
- return nestDigest;
+ new NestAnalyzer(
+ inputFileContents, ClassAttributeRecord.builder(), ClassMemberRecord.builder());
+ return nestAnalyzer.analyze();
}
- @VisibleForTesting
- NestAnalyzer(
+ private NestAnalyzer(
ImmutableList<FileContentProvider<? extends InputStream>> inputFileContents,
- NestDigest nestDigest,
- ClassMemberRecord classMemberRecord,
- ClassAttributeRecord classAttributeRecord) {
+ ClassAttributeRecordBuilder classAttributeRecord,
+ ClassMemberRecordBuilder classMemberRecord) {
this.inputFileContents = checkNotNull(inputFileContents);
- this.nestDigest = checkNotNull(nestDigest);
- this.classMemberRecord = checkNotNull(classMemberRecord);
+ this.classMemberRecord = classMemberRecord;
this.classAttributeRecord = classAttributeRecord;
}
/** Performs class member declaration and usage analysis of files. */
- @VisibleForTesting
- void analyze() throws IOException {
+ private NestDigest analyze() throws IOException {
for (FileContentProvider<? extends InputStream> inputClassFile : inputFileContents) {
if (inputClassFile.isClassFile()) {
try (InputStream inputStream = inputClassFile.get()) {
@@ -79,7 +72,10 @@
}
}
}
- classMemberRecord.filterUsedMemberWithTrackedDeclaration();
- nestDigest.prepareCompanionClasses();
+
+ return NestDigest.builder()
+ .setClassMemberRecord(classMemberRecord.build().filterUsedMemberWithTrackedDeclaration())
+ .setClassAttributeRecord(classAttributeRecord.build())
+ .build();
}
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestDigest.java b/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestDigest.java
index 9d983f2..d39c49e 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestDigest.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/nest/NestDigest.java
@@ -16,8 +16,11 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.devtools.build.android.desugar.langmodel.LangModelConstants.NEST_COMPANION_CLASS_SIMPLE_NAME;
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;
@@ -30,7 +33,6 @@
import com.google.devtools.build.android.desugar.langmodel.TypeMappable;
import com.google.devtools.build.android.desugar.langmodel.TypeMapper;
import java.io.ByteArrayInputStream;
-import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -38,60 +40,50 @@
import org.objectweb.asm.ClassWriter;
/** Manages the creation and IO stream for nest-companion classes. */
-public class NestDigest implements TypeMappable<NestDigest> {
+@AutoValue
+public abstract class NestDigest implements TypeMappable<NestDigest> {
- private final ClassMemberRecord classMemberRecord;
- private final ClassAttributeRecord classAttributeRecord;
- private final Map<ClassName, ClassName> nestCompanionToHostMap;
+ public abstract ClassMemberRecord classMemberRecord();
+
+ public abstract ClassAttributeRecord classAttributeRecord();
+
+ @Memoized
+ ImmutableList<ClassName> nestHostsWithCompanion() {
+ return classMemberRecord().findAllConstructorMemberKeys().stream()
+ .map(
+ constructor -> nestHost(constructor.owner(), classAttributeRecord(), ImmutableMap.of()))
+ .flatMap(Streams::stream)
+ .distinct()
+ .collect(toImmutableList());
+ }
+
+ @Memoized
+ ImmutableMap<ClassName, ClassName> nestCompanionToHostMap() {
+ return nestHostsWithCompanion().stream()
+ .collect(
+ toImmutableMap(
+ nestHost -> nestHost.innerClass(NEST_COMPANION_CLASS_SIMPLE_NAME),
+ nestHost -> nestHost));
+ }
/**
* A map from the class binary names of nest hosts to the associated class writer of the nest's
* companion.
*/
- private ImmutableMap<ClassName, ClassWriter> companionWriters;
-
- public static NestDigest create(
- ClassMemberRecord classMemberRecord, ClassAttributeRecord classAttributeRecord) {
- return new NestDigest(
- classMemberRecord, classAttributeRecord, new HashMap<>(), /* companionWriters= */ null);
+ @Memoized
+ ImmutableMap<ClassName, ClassWriter> companionWriters() {
+ return nestHostsWithCompanion().stream()
+ .collect(
+ toImmutableMap(
+ nestHost -> nestHost, nestHost -> new ClassWriter(ClassWriter.COMPUTE_MAXS)));
}
- private NestDigest(
- ClassMemberRecord classMemberRecord,
- ClassAttributeRecord classAttributeRecord,
- Map<ClassName, ClassName> nestCompanionToHostMap,
- ImmutableMap<ClassName, ClassWriter> companionWriters) {
- this.classMemberRecord = classMemberRecord;
- this.classAttributeRecord = classAttributeRecord;
- this.nestCompanionToHostMap = nestCompanionToHostMap;
- this.companionWriters = companionWriters;
- }
-
- /**
- * Generates the nest companion class writers. The nest companion classes will be generated as the
- * last placeholder class type for the synthetic constructor, whose originating constructor has
- * any invocation in other classes in nest.
- */
- void prepareCompanionClasses() {
- ImmutableList<ClassName> nestHostsWithCompanion =
- classMemberRecord.findAllConstructorMemberKeys().stream()
- .map(
- constructor ->
- nestHost(constructor.owner(), classAttributeRecord, nestCompanionToHostMap))
- .flatMap(Streams::stream)
- .distinct()
- .collect(toImmutableList());
- ImmutableMap.Builder<ClassName, ClassWriter> companionWriterBuilders = ImmutableMap.builder();
- for (ClassName nestHost : nestHostsWithCompanion) {
- ClassName nestCompanion = nestHost.innerClass(NEST_COMPANION_CLASS_SIMPLE_NAME);
- nestCompanionToHostMap.put(nestCompanion, nestHost);
- companionWriterBuilders.put(nestHost, new ClassWriter(ClassWriter.COMPUTE_MAXS));
- }
- companionWriters = companionWriterBuilders.build();
+ public static NestDigestBuilder builder() {
+ return new AutoValue_NestDigest.Builder();
}
public boolean hasAnyTrackingReason(ClassMemberKey<?> classMemberKey) {
- return classMemberRecord.hasTrackingReason(classMemberKey);
+ return classMemberRecord().hasTrackingReason(classMemberKey);
}
public boolean hasAnyUse(ClassMemberKey<?> classMemberKey, MemberUseKind useKind) {
@@ -99,7 +91,7 @@
}
public ImmutableList<MemberUseKind> findAllMemberUseKinds(ClassMemberKey<?> classMemberKey) {
- return classMemberRecord.findAllMemberUseKind(classMemberKey);
+ return classMemberRecord().findAllMemberUseKind(classMemberKey);
}
/**
@@ -110,8 +102,8 @@
*/
public Optional<ClassName> nestHost(ClassName className) {
// Ensures prepareCompanionClasses has been executed.
- checkNotNull(companionWriters);
- return nestHost(className, classAttributeRecord, nestCompanionToHostMap);
+ checkNotNull(companionWriters());
+ return nestHost(className, classAttributeRecord(), nestCompanionToHostMap());
}
/**
@@ -163,7 +155,7 @@
*/
@Nullable
public ClassWriter getCompanionClassWriter(ClassName className) {
- return nestHost(className).map(nestHost -> companionWriters.get(nestHost)).orElse(null);
+ return nestHost(className).map(nestHost -> companionWriters().get(nestHost)).orElse(null);
}
/** Gets all nest companion classes required to be generated. */
@@ -172,7 +164,7 @@
}
public ImmutableList<ClassName> getAllCompanionClasses() {
- return companionWriters.keySet().stream().map(this::nestCompanion).collect(toImmutableList());
+ return companionWriters().keySet().stream().map(this::nestCompanion).collect(toImmutableList());
}
/** Gets all nest companion files required to be generated. */
@@ -194,16 +186,26 @@
checkNotNull(
companionClassWriter,
"Expected companion class (%s) to be present in (%s)",
- companionWriters);
+ companionWriters());
return new ByteArrayInputStream(companionClassWriter.toByteArray());
}
@Override
public NestDigest acceptTypeMapper(TypeMapper typeMapper) {
- return new NestDigest(
- classMemberRecord.acceptTypeMapper(typeMapper),
- classAttributeRecord.acceptTypeMapper(typeMapper),
- typeMapper.mapMutable(nestCompanionToHostMap),
- typeMapper.mapKey(companionWriters));
+ return NestDigest.builder()
+ .setClassMemberRecord(classMemberRecord().acceptTypeMapper(typeMapper))
+ .setClassAttributeRecord(classAttributeRecord().acceptTypeMapper(typeMapper))
+ .build();
+ }
+
+ /** The builder class for {@link NestDigest}. */
+ @AutoValue.Builder
+ public abstract static class NestDigestBuilder {
+
+ public abstract NestDigestBuilder setClassMemberRecord(ClassMemberRecord value);
+
+ public abstract NestDigestBuilder setClassAttributeRecord(ClassAttributeRecord value);
+
+ public abstract NestDigest build();
}
}