Invalidate staticizing candidates whose references are not fixable.

Bug: 135172146, 119626580
Change-Id: I4d39dfaaebbf91d5c14df80dfc02c74f3a4ec717
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index d2a3838..cafc3bb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -98,6 +98,8 @@
   }
 
   private void finalEligibilityCheck() {
+    Set<Phi> visited = Sets.newIdentityHashSet();
+    Set<Phi> trivialPhis = Sets.newIdentityHashSet();
     Iterator<Entry<DexType, CandidateInfo>> it =
         classStaticizer.candidates.entrySet().iterator();
     while (it.hasNext()) {
@@ -147,6 +149,63 @@
         it.remove();
         continue;
       }
+
+      // CHECK: references to 'this' in instance methods are fixable.
+      boolean fixableThisPointer = true;
+      for (DexEncodedMethod method : candidateClass.methods()) {
+        if (method.isStatic() || factory().isConstructor(method.method)) {
+          continue;
+        }
+        IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.method.holder));
+        assert code != null;
+        Value thisValue = code.getThis();
+        assert thisValue != null;
+        visited.clear();
+        trivialPhis.clear();
+        boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfThis(
+            visited, thisValue.uniquePhiUsers(), thisValue, trivialPhis);
+        if (thisValue.numberOfPhiUsers() != 0 && !onlyHasTrivialPhis) {
+          fixableThisPointer = false;
+          break;
+        }
+      }
+      if (!fixableThisPointer) {
+        it.remove();
+        continue;
+      }
+
+      // CHECK: references to field read usages are fixable.
+      boolean fixableFieldReads = true;
+      for (DexEncodedMethod method : info.referencedFrom) {
+        IRCode code = method.buildIR(appView, appView.appInfo().originFor(method.method.holder));
+        assert code != null;
+        List<StaticGet> singletonFieldReads =
+            Streams.stream(code.instructionIterator())
+                .filter(Instruction::isStaticGet)
+                .map(Instruction::asStaticGet)
+                .filter(get -> get.getField() == info.singletonField.field)
+                .collect(Collectors.toList());
+        boolean fixableFieldReadsPerUsage = true;
+        for (StaticGet read : singletonFieldReads) {
+          Value dest = read.dest();
+          visited.clear();
+          trivialPhis.clear();
+          boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfSameFieldRead(
+              visited, dest.uniquePhiUsers(), read.getField(), trivialPhis);
+          if (dest.numberOfPhiUsers() != 0 && !onlyHasTrivialPhis) {
+            fixableFieldReadsPerUsage = false;
+            break;
+          }
+        }
+        if (!fixableFieldReadsPerUsage) {
+          fixableFieldReads = false;
+          break;
+        }
+      }
+      if (!fixableFieldReads) {
+        it.remove();
+        continue;
+      }
     }
   }
 
@@ -308,7 +367,7 @@
     boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfThis(
         Sets.newIdentityHashSet(), thisValue.uniquePhiUsers(), thisValue, trivialPhis);
     assert thisValue.numberOfPhiUsers() == 0 || onlyHasTrivialPhis;
-    assert !onlyHasTrivialPhis || trivialPhis.isEmpty();
+    assert trivialPhis.isEmpty() || onlyHasTrivialPhis;
 
     Set<Instruction> users = SetUtils.newIdentityHashSet(thisValue.uniqueUsers());
     // If that is the case, method calls we want to fix up include users of those phis.
@@ -398,7 +457,7 @@
     boolean onlyHasTrivialPhis = testAndCollectPhisComposedOfSameFieldRead(
         Sets.newIdentityHashSet(), dest.uniquePhiUsers(), field, trivialPhis);
     assert dest.numberOfPhiUsers() == 0 || onlyHasTrivialPhis;
-    assert !onlyHasTrivialPhis || trivialPhis.isEmpty();
+    assert trivialPhis.isEmpty() || onlyHasTrivialPhis;
 
     Set<Instruction> users = SetUtils.newIdentityHashSet(dest.uniqueUsers());
     // If that is the case, method calls we want to fix up include users of those phis.
diff --git a/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java
index 204901f..d6c8173 100644
--- a/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/MetadataStripTest.java
@@ -55,6 +55,8 @@
             .addKeepMainRule(mainClassName)
             .addKeepRules(KEEP_ANNOTATIONS)
             .addKeepRules("-keep class kotlin.Metadata")
+            // TODO(119626580): Remove when resolved.
+            .addOptionsModification(options -> options.enableClassStaticizer = true)
             .setMinApi(parameters.getRuntime())
             .run(parameters.getRuntime(), mainClassName);
     CodeInspector inspector = result.inspector();