Update side effect modelling for StringBuilder and StringBuffer

Bug: 133745205
Change-Id: I6bbfb6d38680510c7c8ab0b260ada0e54285c339
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 85cf68a..79e15c5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -25,6 +25,7 @@
 import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.kotlin.Kotlin;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.ArrayUtils;
@@ -461,8 +462,12 @@
       Streams.<Pair<DexMethod, Predicate<InvokeMethod>>>concat(
               Stream.of(new Pair<>(objectMethods.constructor, alwaysTrue())),
               mapToPredicate(classMethods.getNames, alwaysTrue()),
-              mapToPredicate(stringBufferMethods.constructorMethods, alwaysTrue()),
-              mapToPredicate(stringBuilderMethods.constructorMethods, alwaysTrue()),
+              mapToPredicate(
+                  stringBufferMethods.constructorMethods,
+                  stringBufferMethods::constructorInvokeIsSideEffectFree),
+              mapToPredicate(
+                  stringBuilderMethods.constructorMethods,
+                  stringBuilderMethods::constructorInvokeIsSideEffectFree),
               mapToPredicate(boxedValueOfMethods(), alwaysTrue()))
           .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond));
 
@@ -892,6 +897,37 @@
     public boolean isAppendMethod(DexMethod method) {
       return appendMethods.contains(method);
     }
+
+    public boolean constructorInvokeIsSideEffectFree(InvokeMethod invoke) {
+      DexMethod invokedMethod = invoke.getInvokedMethod();
+      if (invokedMethod == charSequenceConstructor) {
+        // NullPointerException - if seq is null.
+        Value seqValue = invoke.inValues().get(1);
+        return !seqValue.getTypeLattice().isNullable();
+      }
+
+      if (invokedMethod == defaultConstructor) {
+        return true;
+      }
+
+      if (invokedMethod == intConstructor) {
+        // NegativeArraySizeException - if the capacity argument is less than 0.
+        Value capacityValue = invoke.inValues().get(1);
+        if (capacityValue.hasValueRange()) {
+          return capacityValue.getValueRange().getMin() >= 0;
+        }
+        return false;
+      }
+
+      if (invokedMethod == stringConstructor) {
+        // NullPointerException - if str is null.
+        Value strValue = invoke.inValues().get(1);
+        return !strValue.getTypeLattice().isNullable();
+      }
+
+      assert false : "Unexpected invoke targeting `" + invokedMethod.toSourceString() +  "`";
+      return false;
+    }
   }
 
   public class PolymorphicMethods {