Update optimization info for fields/methods known to return null

Change-Id: I071afd86a5d2e00bb256f5d48f5901a0e72d258f
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 6e60771..34677e0 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -542,6 +542,7 @@
             timing.begin("UninstantiatedTypeOptimization");
             UninstantiatedTypeOptimizationGraphLense lens =
                 new UninstantiatedTypeOptimization(appViewWithLiveness)
+                    .strenghtenOptimizationInfo()
                     .run(
                         new MethodPoolCollection(appViewWithLiveness, subtypingInfo),
                         executorService,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 8ca93eb..96fd58c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -280,12 +280,7 @@
       return;
     }
 
-    AbstractValue abstractReturnValue;
-    if (singleTarget.returnType().isAlwaysNull(appView)) {
-      abstractReturnValue = appView.abstractValueFactory().createSingleNumberValue(0);
-    } else {
-      abstractReturnValue = singleTarget.getOptimizationInfo().getAbstractReturnValue();
-    }
+    AbstractValue abstractReturnValue = singleTarget.getOptimizationInfo().getAbstractReturnValue();
 
     if (abstractReturnValue.isSingleValue()) {
       SingleValue singleReturnValue = abstractReturnValue.asSingleValue();
@@ -356,9 +351,7 @@
     }
 
     AbstractValue abstractValue;
-    if (field.type.isAlwaysNull(appView)) {
-      abstractValue = appView.abstractValueFactory().createSingleNumberValue(0);
-    } else if (appView.appInfo().isFieldWrittenByFieldPutInstruction(target)) {
+    if (appView.appInfo().isFieldWrittenByFieldPutInstruction(target)) {
       abstractValue = target.getOptimizationInfo().getAbstractValue();
       if (abstractValue.isUnknown() && !target.isStatic()) {
         AbstractValue abstractReceiverValue =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 11245e7..cb1eec7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -15,6 +15,8 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessInfo;
+import com.android.tools.r8.graph.FieldAccessInfoCollection;
 import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.RewrittenPrototypeDescription;
@@ -22,6 +24,7 @@
 import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
 import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.FieldInstruction;
 import com.android.tools.r8.ir.code.IRCode;
@@ -31,6 +34,8 @@
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Timing;
@@ -104,6 +109,33 @@
     this.appView = appView;
   }
 
+  public UninstantiatedTypeOptimization strenghtenOptimizationInfo() {
+    OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
+    FieldAccessInfoCollection<?> fieldAccessInfoCollection =
+        appView.appInfo().getFieldAccessInfoCollection();
+    AbstractValue nullValue = appView.abstractValueFactory().createSingleNumberValue(0);
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      clazz.forEachField(
+          field -> {
+            if (field.type().isAlwaysNull(appView)) {
+              FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field);
+              if (fieldAccessInfo != null) {
+                // Clear all writes since each write must write `null` to the field.
+                fieldAccessInfo.asMutable().clearWrites();
+              }
+              feedback.recordFieldHasAbstractValue(field, appView, nullValue);
+            }
+          });
+      clazz.forEachMethod(
+          method -> {
+            if (method.returnType().isAlwaysNull(appView)) {
+              feedback.methodReturnsAbstractValue(method, appView, nullValue);
+            }
+          });
+    }
+    return this;
+  }
+
   public UninstantiatedTypeOptimizationGraphLense run(
       MethodPoolCollection methodPoolCollection, ExecutorService executorService, Timing timing) {
     try {