Support merging of classes with static fields

Bug: 163311975

Change-Id: I58d4641525289b315d2d98dd73f1a7716db35f55
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java
new file mode 100644
index 0000000..ce4b93e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2020, 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.horizontalclassmerging;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerGraphLens.Builder;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class ClassStaticFieldsMerger {
+  private final Builder lensBuilder;
+  private final DexProgramClass target;
+  private final Map<DexField, DexEncodedField> targetFields = new LinkedHashMap<>();
+  private final DexItemFactory dexItemFactory;
+  private final AppView<?> appView;
+
+  public ClassStaticFieldsMerger(
+      AppView<?> appView,
+      HorizontalClassMergerGraphLens.Builder lensBuilder,
+      DexProgramClass target) {
+    this.appView = appView;
+    this.lensBuilder = lensBuilder;
+
+    this.target = target;
+    // Add mappings for all target fields.
+    target.staticFields().forEach(field -> targetFields.put(field.getReference(), field));
+
+    this.dexItemFactory = appView.dexItemFactory();
+  }
+
+  private final boolean isFresh(DexField fieldReference) {
+    return !targetFields.containsKey(fieldReference);
+  }
+
+  private void addField(DexEncodedField field) {
+    DexField oldFieldReference = field.getReference();
+    DexField templateReference = field.getReference().withHolder(target.type, dexItemFactory);
+    DexField newFieldReference =
+        dexItemFactory.createFreshFieldName(templateReference, field.holder(), this::isFresh);
+
+    field = field.toTypeSubstitutedField(newFieldReference);
+    targetFields.put(newFieldReference, field);
+
+    lensBuilder.mapField(oldFieldReference, newFieldReference);
+  }
+
+  public void addFields(DexProgramClass toMerge) {
+    toMerge.staticFields().forEach(this::addField);
+  }
+
+  public void merge(DexProgramClass clazz) {
+    clazz.setStaticFields(targetFields.values().toArray(DexEncodedField.EMPTY_ARRAY));
+  }
+}