Refactor class signature creation to use its builder.

This also updates the builder to canonicalize the "no signature"
information.

Bug: b/280356274
Change-Id: I62f122fcaf26a84db4b98781cf54ea2b26be22ff
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index c79cb1b..82d48be 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -31,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
@@ -817,8 +818,8 @@
   }
 
   public boolean validInterfaceSignatures() {
-    return getClassSignature().superInterfaceSignatures().isEmpty()
-        || interfaces.values.length == getClassSignature().superInterfaceSignatures.size();
+    return getClassSignature().getSuperInterfaceSignatures().isEmpty()
+        || interfaces.values.length == getClassSignature().getSuperInterfaceSignatures().size();
   }
 
   public void forEachImmediateInterfaceWithSignature(
@@ -826,7 +827,7 @@
     assert validInterfaceSignatures();
 
     // If there is no generic signature information don't pass any type arguments.
-    if (getClassSignature().superInterfaceSignatures().isEmpty()) {
+    if (getClassSignature().getSuperInterfaceSignatures().isEmpty()) {
       forEachImmediateInterface(
           superInterface ->
               consumer.accept(superInterface, new ClassTypeSignature(superInterface)));
@@ -835,7 +836,7 @@
 
     Iterator<DexType> interfaceIterator = Arrays.asList(interfaces.values).iterator();
     Iterator<ClassTypeSignature> interfaceSignatureIterator =
-        getClassSignature().superInterfaceSignatures().iterator();
+        getClassSignature().getSuperInterfaceSignatures().iterator();
 
     while (interfaceIterator.hasNext()) {
       assert interfaceSignatureIterator.hasNext();
@@ -846,9 +847,9 @@
   }
 
   public void forEachImmediateSupertypeWithSignature(
-      BiConsumer<DexType, ClassTypeSignature> consumer) {
+      DexItemFactory factory, BiConsumer<DexType, ClassTypeSignature> consumer) {
     if (superType != null) {
-      consumer.accept(superType, classSignature.superClassSignature);
+      consumer.accept(superType, classSignature.getSuperClassSignatureOrObject(factory));
     }
     forEachImmediateInterfaceWithSignature(consumer);
   }
@@ -859,7 +860,7 @@
     assert validInterfaceSignatures();
 
     // If there is no generic signature information don't pass any type arguments.
-    if (getClassSignature().superInterfaceSignatures().size() == 0) {
+    if (getClassSignature().getSuperInterfaceSignatures().isEmpty()) {
       forEachImmediateInterface(
           superInterface -> consumer.accept(superInterface, ImmutableList.of()));
       return;
@@ -867,7 +868,7 @@
 
     Iterator<DexType> interfaceIterator = Arrays.asList(interfaces.values).iterator();
     Iterator<ClassTypeSignature> interfaceSignatureIterator =
-        getClassSignature().superInterfaceSignatures().iterator();
+        getClassSignature().getSuperInterfaceSignatures().iterator();
 
     while (interfaceIterator.hasNext()) {
       assert interfaceSignatureIterator.hasNext();
@@ -890,17 +891,18 @@
       BiConsumer<DexType, List<FieldTypeSignature>> consumer) {
     if (superType != null) {
       consumer.accept(
-          superType, applyTypeArguments(getClassSignature().superClassSignature, typeArguments));
+          superType,
+          applyTypeArguments(getClassSignature().getSuperClassSignatureOrNull(), typeArguments));
     }
     forEachImmediateInterfaceWithAppliedTypeArguments(typeArguments, consumer);
   }
 
   private List<FieldTypeSignature> applyTypeArguments(
       ClassTypeSignature superInterfaceSignatures, List<FieldTypeSignature> appliedTypeArguments) {
-    ImmutableList.Builder<FieldTypeSignature> superTypeArgumentsBuilder = ImmutableList.builder();
-    if (superInterfaceSignatures.type.toSourceString().equals("java.util.Map")) {
-      System.currentTimeMillis();
+    if (superInterfaceSignatures == null) {
+      return Collections.emptyList();
     }
+    ImmutableList.Builder<FieldTypeSignature> superTypeArgumentsBuilder = ImmutableList.builder();
     superInterfaceSignatures
         .typeArguments()
         .forEach(
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index fc4c4a6..058aded 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -27,7 +27,6 @@
 import com.android.tools.r8.utils.structural.StructuralItem;
 import com.android.tools.r8.utils.structural.StructuralMapping;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -732,12 +731,12 @@
     methodCollection.replaceVirtualMethod(virtualMethod, replacement);
   }
 
-  public void addExtraInterfaces(List<ClassTypeSignature> extraInterfaces) {
+  public void addExtraInterfaces(List<ClassTypeSignature> extraInterfaces, DexItemFactory factory) {
     if (extraInterfaces.isEmpty()) {
       return;
     }
     addExtraInterfacesToInterfacesArray(extraInterfaces);
-    addExtraInterfacesToSignatureIfPresent(extraInterfaces);
+    addExtraInterfacesToSignatureIfPresent(extraInterfaces, factory);
   }
 
   private void addExtraInterfacesToInterfacesArray(List<ClassTypeSignature> extraInterfaces) {
@@ -749,21 +748,20 @@
     interfaces = new DexTypeList(newInterfaces);
   }
 
-  private void addExtraInterfacesToSignatureIfPresent(List<ClassTypeSignature> extraInterfaces) {
+  private void addExtraInterfacesToSignatureIfPresent(
+      List<ClassTypeSignature> extraInterfaces, DexItemFactory factory) {
+    assert !extraInterfaces.isEmpty();
     // We introduce the extra interfaces to the generic signature.
-    if (classSignature.hasNoSignature() || extraInterfaces.isEmpty()) {
+    if (classSignature.hasNoSignature()) {
       return;
     }
-    ImmutableList.Builder<ClassTypeSignature> interfacesBuilder =
-        ImmutableList.<ClassTypeSignature>builder().addAll(classSignature.superInterfaceSignatures);
-    for (ClassTypeSignature extraInterface : extraInterfaces) {
-      interfacesBuilder.add(extraInterface);
-    }
     classSignature =
-        new ClassSignature(
-            classSignature.formalTypeParameters,
-            classSignature.superClassSignature,
-            interfacesBuilder.build());
+        ClassSignature.builder()
+            .addSuperInterfaceSignatures(classSignature.getSuperInterfaceSignatures())
+            .addSuperInterfaceSignatures(extraInterfaces)
+            .setSuperClassSignature(classSignature.getSuperClassSignatureOrNull())
+            .addFormalTypeParameters(classSignature.getFormalTypeParameters())
+            .build(factory);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignature.java b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
index f1122b8..d669d502 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignature.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignature.java
@@ -9,6 +9,7 @@
 
 import com.android.tools.r8.DiagnosticsHandler;
 import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature.ClassSignatureBuilder;
 import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.DescriptorUtils;
@@ -17,6 +18,7 @@
 import java.nio.CharBuffer;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -207,35 +209,44 @@
   public static class ClassSignature implements DexDefinitionSignature<DexClass> {
 
     private static final ClassSignature NO_CLASS_SIGNATURE =
-        new ClassSignature(EMPTY_TYPE_PARAMS, NO_FIELD_TYPE_SIGNATURE, EMPTY_SUPER_INTERFACES);
+        new ClassSignature(EMPTY_TYPE_PARAMS, null, EMPTY_SUPER_INTERFACES);
 
-    final List<FormalTypeParameter> formalTypeParameters;
-    final ClassTypeSignature superClassSignature;
-    final List<ClassTypeSignature> superInterfaceSignatures;
+    public static ClassSignature noSignature() {
+      return NO_CLASS_SIGNATURE;
+    }
+
+    private final List<FormalTypeParameter> formalTypeParameters;
+    private final ClassTypeSignature superClassSignatureOrNullForObject;
+    private final List<ClassTypeSignature> superInterfaceSignatures;
 
     ClassSignature(
         List<FormalTypeParameter> formalTypeParameters,
         ClassTypeSignature superClassSignature,
         List<ClassTypeSignature> superInterfaceSignatures) {
       assert formalTypeParameters != null;
-      assert superClassSignature != null;
       assert superInterfaceSignatures != null;
       this.formalTypeParameters = formalTypeParameters;
-      this.superClassSignature = superClassSignature;
+      this.superClassSignatureOrNullForObject = superClassSignature;
       this.superInterfaceSignatures = superInterfaceSignatures;
     }
 
-    public ClassTypeSignature superClassSignature() {
-      return superClassSignature;
+    public ClassTypeSignature getSuperClassSignatureOrNull() {
+      return superClassSignatureOrNullForObject;
     }
 
-    public List<ClassTypeSignature> superInterfaceSignatures() {
+    public ClassTypeSignature getSuperClassSignatureOrObject(DexItemFactory factory) {
+      return superClassSignatureOrNullForObject != null
+          ? superClassSignatureOrNullForObject
+          : new ClassTypeSignature(factory.objectType);
+    }
+
+    public List<ClassTypeSignature> getSuperInterfaceSignatures() {
       return superInterfaceSignatures;
     }
 
     @Override
     public boolean hasSignature() {
-      return this != NO_CLASS_SIGNATURE;
+      return this != noSignature();
     }
 
     @Override
@@ -258,21 +269,32 @@
       return formalTypeParameters;
     }
 
-    public ClassSignature visit(GenericSignatureVisitor visitor) {
+    public ClassSignature visit(GenericSignatureVisitor visitor, DexItemFactory factory) {
       if (hasNoSignature()) {
         return this;
       }
       List<FormalTypeParameter> rewrittenParameters =
           visitor.visitFormalTypeParameters(formalTypeParameters);
-      ClassTypeSignature rewrittenSuperClass = visitor.visitSuperClass(superClassSignature);
+      ClassTypeSignature rewrittenSuperClass =
+          visitor.visitSuperClass(superClassSignatureOrNullForObject);
       List<ClassTypeSignature> rewrittenInterfaces =
           visitor.visitSuperInterfaces(superInterfaceSignatures);
       if (formalTypeParameters == rewrittenParameters
-          && superClassSignature == rewrittenSuperClass
+          && superClassSignatureOrNullForObject == rewrittenSuperClass
           && superInterfaceSignatures == rewrittenInterfaces) {
         return this;
       }
-      return new ClassSignature(rewrittenParameters, rewrittenSuperClass, rewrittenInterfaces);
+      return ClassSignature.builder()
+          .addFormalTypeParameters(rewrittenParameters)
+          .setSuperClassSignature(rewrittenSuperClass)
+          .addSuperInterfaceSignatures(rewrittenInterfaces)
+          .build(factory);
+    }
+
+    public void visitWithoutRewrite(GenericSignatureVisitor visitor) {
+      visitor.visitFormalTypeParameters(formalTypeParameters);
+      visitor.visitSuperClass(superClassSignatureOrNullForObject);
+      visitor.visitSuperInterfaces(superInterfaceSignatures);
     }
 
     public String toRenamedString(NamingLens namingLens, Predicate<DexType> isTypeMissing) {
@@ -290,14 +312,12 @@
       return toRenamedString(NamingLens.getIdentityLens(), alwaysTrue());
     }
 
-    public static ClassSignature noSignature() {
-      return NO_CLASS_SIGNATURE;
-    }
-
-    public List<FieldTypeSignature> getGenericArgumentsToSuperType(DexType type) {
+    public List<FieldTypeSignature> getGenericArgumentsToSuperType(
+        DexType type, DexItemFactory factory) {
       assert hasSignature();
-      if (superClassSignature.type == type) {
-        return superClassSignature.typeArguments;
+      ClassTypeSignature superClassSig = getSuperClassSignatureOrObject(factory);
+      if (superClassSig.type == type) {
+        return superClassSig.typeArguments;
       }
       for (ClassTypeSignature superInterfaceSignature : superInterfaceSignatures) {
         if (superInterfaceSignature.type == type) {
@@ -319,6 +339,11 @@
 
       private ClassSignatureBuilder() {}
 
+      public ClassSignatureBuilder addFormalTypeParameter(FormalTypeParameter formal) {
+        formalTypeParameters.add(formal);
+        return this;
+      }
+
       public ClassSignatureBuilder addFormalTypeParameters(List<FormalTypeParameter> formals) {
         formalTypeParameters.addAll(formals);
         return this;
@@ -329,12 +354,32 @@
         return this;
       }
 
-      public ClassSignatureBuilder addInterface(ClassTypeSignature iface) {
+      public ClassSignatureBuilder addSuperInterfaceSignature(ClassTypeSignature iface) {
         superInterfaceSignatures.add(iface);
         return this;
       }
 
-      public ClassSignature build() {
+      public ClassSignatureBuilder addSuperInterfaceSignatures(List<ClassTypeSignature> ifaces) {
+        superInterfaceSignatures.addAll(ifaces);
+        return this;
+      }
+
+      public ClassSignature build(DexItemFactory factory) {
+        // Any trivial super class signature is always represented by the null value.
+        if (superClassSignature != null) {
+          if (superClassSignature.type() == factory.objectType) {
+            assert !superClassSignature.hasTypeVariableArguments();
+            superClassSignature = null;
+          } else if (superClassSignature.hasNoSignature()) {
+            superClassSignature = null;
+          }
+        }
+        // Any trivial class signature is represented by the "no signature" singleton.
+        if (superClassSignature == null
+            && formalTypeParameters.isEmpty()
+            && superInterfaceSignatures.isEmpty()) {
+          return ClassSignature.noSignature();
+        }
         return new ClassSignature(
             formalTypeParameters, superClassSignature, superInterfaceSignatures);
       }
@@ -346,7 +391,7 @@
     private final String genericSignatureString;
 
     InvalidClassSignature(String genericSignatureString) {
-      super(EMPTY_TYPE_PARAMS, NO_FIELD_TYPE_SIGNATURE, EMPTY_SUPER_INTERFACES);
+      super(EMPTY_TYPE_PARAMS, null, EMPTY_SUPER_INTERFACES);
       this.genericSignatureString = genericSignatureString;
     }
 
@@ -367,12 +412,17 @@
     }
 
     @Override
-    public ClassSignature visit(GenericSignatureVisitor visitor) {
+    public ClassSignature visit(GenericSignatureVisitor visitor, DexItemFactory factory) {
       assert false : "Should not visit an invalid signature";
       return this;
     }
 
     @Override
+    public void visitWithoutRewrite(GenericSignatureVisitor visitor) {
+      assert false : "Should not visit an invalid signature";
+    }
+
+    @Override
     public boolean isInvalid() {
       return true;
     }
@@ -943,7 +993,7 @@
       DexItemFactory factory,
       DiagnosticsHandler diagnosticsHandler) {
     if (signature == null || signature.isEmpty()) {
-      return ClassSignature.NO_CLASS_SIGNATURE;
+      return ClassSignature.noSignature();
     }
     Parser parser = new Parser(factory);
     try {
@@ -951,7 +1001,7 @@
     } catch (GenericSignatureFormatError e) {
       diagnosticsHandler.warning(
           GenericSignatureFormatDiagnostic.invalidClassSignature(signature, className, origin, e));
-      return ClassSignature.NO_CLASS_SIGNATURE;
+      return ClassSignature.noSignature();
     }
   }
 
@@ -1100,34 +1150,28 @@
 
     private ClassSignature parseClassSignature() {
       // ClassSignature ::= FormalTypeParameters? SuperclassSignature SuperinterfaceSignature*.
-
-      List<FormalTypeParameter> formalTypeParameters = parseOptFormalTypeParameters();
-
+      ClassSignatureBuilder signatureBuilder = ClassSignature.builder();
+      parseOptFormalTypeParameters(signatureBuilder::addFormalTypeParameter);
       // SuperclassSignature ::= ClassTypeSignature.
-      ClassTypeSignature superClassSignature = parseClassTypeSignature();
-
-      ImmutableList.Builder<ClassTypeSignature> builder = ImmutableList.builder();
+      signatureBuilder.setSuperClassSignature(parseClassTypeSignature());
       while (symbol > 0) {
         // SuperinterfaceSignature ::= ClassTypeSignature.
-        builder.add(parseClassTypeSignature());
+        signatureBuilder.addSuperInterfaceSignature(parseClassTypeSignature());
       }
-
-      return new ClassSignature(formalTypeParameters, superClassSignature, builder.build());
+      return signatureBuilder.build(factory);
     }
 
-    private List<FormalTypeParameter> parseOptFormalTypeParameters() {
+    private void parseOptFormalTypeParameters(Consumer<FormalTypeParameter> consumer) {
       // FormalTypeParameters ::= "<" FormalTypeParameter+ ">".
       if (symbol != '<') {
-        return EMPTY_TYPE_PARAMS;
+        return;
       }
       scanSymbol();
 
-      ImmutableList.Builder<FormalTypeParameter> builder = ImmutableList.builder();
       while ((symbol != '>') && (symbol > 0)) {
-        builder.add(updateFormalTypeParameter());
+        consumer.accept(updateFormalTypeParameter());
       }
       expect('>');
-      return builder.build();
     }
 
     private FormalTypeParameter updateFormalTypeParameter() {
@@ -1288,7 +1332,8 @@
     private MethodTypeSignature parseMethodTypeSignature() {
       // MethodTypeSignature ::=
       //     FormalTypeParameters? "(" TypeSignature* ")" ReturnType ThrowsSignature*.
-      List<FormalTypeParameter> formalTypeParameters = parseOptFormalTypeParameters();
+      ImmutableList.Builder<FormalTypeParameter> formalsBuilder = ImmutableList.builder();
+      parseOptFormalTypeParameters(formalsBuilder::add);
 
       expect('(');
 
@@ -1315,7 +1360,7 @@
       }
 
       return new MethodTypeSignature(
-          formalTypeParameters,
+          formalsBuilder.build(),
           parameterSignatureBuilder.build(),
           returnType,
           throwsSignatureBuilder.build());
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
index 7864ee8..8bac211 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureCorrectnessHelper.java
@@ -250,26 +250,24 @@
         return VALID;
       }
       SignatureEvaluationResult signatureEvaluationResult =
-          evaluateFormalTypeParameters(classSignature.formalTypeParameters, typeParameterContext);
+          evaluateFormalTypeParameters(
+              classSignature.getFormalTypeParameters(), typeParameterContext);
       if (signatureEvaluationResult.isInvalid()) {
         return signatureEvaluationResult;
       }
-      if (context.superType == appView.dexItemFactory().objectType
-          && classSignature.superClassSignature().hasNoSignature()) {
-        // We represent no signature as object.
-      } else if (context.superType != classSignature.superClassSignature().type()) {
+      ClassTypeSignature superClassSignature =
+          classSignature.getSuperClassSignatureOrObject(appView.dexItemFactory());
+      if (context.superType != superClassSignature.type()) {
         assert mode.doNotVerify() : "Super type inconsistency in generic signature";
         return INVALID_SUPER_TYPE;
       }
       signatureEvaluationResult =
           evaluateTypeArgumentsAppliedToType(
-              classSignature.superClassSignature().typeArguments(),
-              context.superType,
-              typeParameterContext);
+              superClassSignature.typeArguments(), context.superType, typeParameterContext);
       if (signatureEvaluationResult.isInvalid()) {
         return signatureEvaluationResult;
       }
-      List<ClassTypeSignature> superInterfaces = classSignature.superInterfaceSignatures();
+      List<ClassTypeSignature> superInterfaces = classSignature.getSuperInterfaceSignatures();
       if (context.interfaces.size() != superInterfaces.size()) {
         assert mode.doNotVerify();
         return INVALID_INTERFACE_COUNT;
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java b/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java
index 12ca041..503000f 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignaturePartialTypeArgumentApplier.java
@@ -70,7 +70,7 @@
     if (classSignature.hasNoSignature() || classSignature.isInvalid()) {
       return classSignature;
     }
-    return classSignature.visit(this);
+    return classSignature.visit(this, appView.dexItemFactory());
   }
 
   @Override
@@ -206,8 +206,11 @@
   }
 
   @Override
-  public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) {
-    return classTypeSignature.visit(this);
+  public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignatureOrNullForObject) {
+    if (classTypeSignatureOrNullForObject == null) {
+      return classTypeSignatureOrNullForObject;
+    }
+    return classTypeSignatureOrNullForObject.visit(this);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java b/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java
index 9d54705..cff0d21 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignaturePrinter.java
@@ -31,7 +31,8 @@
 
   @Override
   public ClassSignature visitClassSignature(ClassSignature classSignature) {
-    return classSignature.visit(this);
+    classSignature.visitWithoutRewrite(this);
+    return classSignature;
   }
 
   @Override
@@ -108,9 +109,13 @@
   }
 
   @Override
-  public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) {
-    printFieldTypeSignature(classTypeSignature, false);
-    return classTypeSignature;
+  public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignatureOrNullForObject) {
+    if (classTypeSignatureOrNullForObject == null) {
+      sb.append("Ljava/lang/Object;");
+    } else {
+      printFieldTypeSignature(classTypeSignatureOrNullForObject, false);
+    }
+    return classTypeSignatureOrNullForObject;
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
index 7f224bb..cdbc19b 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeRewriter.java
@@ -61,7 +61,7 @@
     if (classSignature.hasNoSignature() || classSignature.isInvalid()) {
       return classSignature;
     }
-    return new GenericSignatureRewriter().visitClassSignature(classSignature);
+    return new GenericSignatureRewriter(factory).visitClassSignature(classSignature);
   }
 
   public FieldTypeSignature rewrite(FieldTypeSignature fieldTypeSignature) {
@@ -69,7 +69,7 @@
       return fieldTypeSignature;
     }
     FieldTypeSignature rewrittenSignature =
-        new GenericSignatureRewriter().visitFieldTypeSignature(fieldTypeSignature);
+        new GenericSignatureRewriter(factory).visitFieldTypeSignature(fieldTypeSignature);
     return rewrittenSignature == null ? FieldTypeSignature.noSignature() : rewrittenSignature;
   }
 
@@ -77,20 +77,20 @@
     if (methodTypeSignature.hasNoSignature() || methodTypeSignature.isInvalid()) {
       return methodTypeSignature;
     }
-    return new GenericSignatureRewriter().visitMethodSignature(methodTypeSignature);
+    return new GenericSignatureRewriter(factory).visitMethodSignature(methodTypeSignature);
   }
 
   private class GenericSignatureRewriter implements GenericSignatureVisitor {
 
+    private final DexItemFactory factory;
+
+    GenericSignatureRewriter(DexItemFactory factory) {
+      this.factory = factory;
+    }
+
     @Override
     public ClassSignature visitClassSignature(ClassSignature classSignature) {
-      ClassSignature rewritten = classSignature.visit(this);
-      if (rewritten.getFormalTypeParameters().isEmpty()
-          && rewritten.superInterfaceSignatures.isEmpty()
-          && rewritten.superClassSignature.type == factory.objectType) {
-        return ClassSignature.noSignature();
-      }
-      return rewritten;
+      return classSignature.visit(this, factory);
     }
 
     @Override
@@ -142,14 +142,12 @@
     }
 
     @Override
-    public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) {
-      if (context.superType == factory.objectType) {
-        return classTypeSignature.type == factory.objectType
-            ? classTypeSignature
-            : objectTypeSignature;
+    public ClassTypeSignature visitSuperClass(
+        ClassTypeSignature classTypeSignatureOrNullForObject) {
+      if (classTypeSignatureOrNullForObject == null) {
+        return classTypeSignatureOrNullForObject;
       }
-      ClassTypeSignature rewritten = classTypeSignature.visit(this);
-      return rewritten == null ? objectTypeSignature : rewritten;
+      return classTypeSignatureOrNullForObject.visit(this);
     }
 
     @Override
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java
index a619129..66e9682 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureTypeVisitor.java
@@ -30,7 +30,8 @@
     if (classSignature.hasNoSignature()) {
       return classSignature;
     }
-    return classSignature.visit(this);
+    classSignature.visitWithoutRewrite(this);
+    return classSignature;
   }
 
   @Override
@@ -87,16 +88,16 @@
   }
 
   @Override
-  public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) {
-    return classTypeSignature.visit(this);
+  public ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignatureOrNullForObject) {
+    if (classTypeSignatureOrNullForObject == null) {
+      return classTypeSignatureOrNullForObject;
+    }
+    return classTypeSignatureOrNullForObject.visit(this);
   }
 
   @Override
   public List<ClassTypeSignature> visitSuperInterfaces(
       List<ClassTypeSignature> interfaceSignatures) {
-    if (interfaceSignatures == null) {
-      return null;
-    }
     interfaceSignatures.forEach(this::visitSuperInterface);
     return interfaceSignatures;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java b/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java
index 37b3cbe..4072b82 100644
--- a/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java
+++ b/src/main/java/com/android/tools/r8/graph/GenericSignatureVisitor.java
@@ -49,7 +49,7 @@
     throw new Unreachable("Implement if visited");
   }
 
-  default ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignature) {
+  default ClassTypeSignature visitSuperClass(ClassTypeSignature classTypeSignatureOrNullForObject) {
     throw new Unreachable("Implement if visited");
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index 98b707f..be8dd14 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -128,7 +128,8 @@
         continue;
       }
       clazz.addExtraInterfaces(
-          Collections.singletonList(new ClassTypeSignature(newInterface.type)));
+          Collections.singletonList(new ClassTypeSignature(newInterface.type)),
+          appView.dexItemFactory());
       eventConsumer.acceptInterfaceInjection(clazz, newInterface);
       DexMethod itfMethod =
           syntheticHelper.emulatedInterfaceDispatchMethod(newInterface, descriptor);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 922fd4d..f69890a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -529,7 +529,7 @@
               eventConsumer.acceptEmulatedInterfaceMarkerInterface(
                   clazz, helper.ensureEmulatedInterfaceMarkerInterface(signature.type()));
             }
-            clazz.addExtraInterfaces(extraInterfaceSignatures);
+            clazz.addExtraInterfaces(extraInterfaceSignatures, appView.dexItemFactory());
           }
         });
   }
@@ -698,6 +698,7 @@
     // TODO(b/182329331): Only handle type arguments for Cf to Cf desugar.
     if (appView.options().isCfDesugaring() && clazz.validInterfaceSignatures()) {
       clazz.forEachImmediateSupertypeWithSignature(
+          appView.dexItemFactory(),
           (type, signature) -> {
             if (emulatesInterfaces.contains(type)) {
               extraInterfaceSignatures.put(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
index 47a6d30..d33fcec 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceApplicationRewriter.java
@@ -90,7 +90,7 @@
             false,
             emulatedInterface.getChecksumSupplier());
     newEmulatedInterface.addExtraInterfaces(
-        getRewrittenInterfacesOfEmulatedInterface(emulatedInterface));
+        getRewrittenInterfacesOfEmulatedInterface(emulatedInterface), appView.dexItemFactory());
     return newEmulatedInterface;
   }
 
@@ -106,7 +106,7 @@
           typeArguments = Collections.emptyList();
         } else {
           GenericSignature.ClassTypeSignature classTypeSignature =
-              classSignature.superInterfaceSignatures().get(i);
+              classSignature.getSuperInterfaceSignatures().get(i);
           assert itf == classTypeSignature.type();
           typeArguments = classTypeSignature.typeArguments();
         }
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 150e7c8..b1673ba 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1208,12 +1208,12 @@
       builder.addFormalTypeParameters(targetSignature.getFormalTypeParameters());
       if (!source.isInterface()) {
         if (rewrittenSource.hasSignature()) {
-          builder.setSuperClassSignature(rewrittenSource.superClassSignature());
+          builder.setSuperClassSignature(rewrittenSource.getSuperClassSignatureOrNull());
         } else {
           builder.setSuperClassSignature(new ClassTypeSignature(source.superType));
         }
       } else {
-        builder.setSuperClassSignature(targetSignature.superClassSignature());
+        builder.setSuperClassSignature(targetSignature.getSuperClassSignatureOrNull());
       }
       // Compute the seen set for interfaces to add. This is similar to the merging of interfaces
       // but allow us to maintain the type arguments.
@@ -1221,26 +1221,26 @@
       if (source.isInterface()) {
         seenInterfaces.add(source.type);
       }
-      for (ClassTypeSignature iFace : targetSignature.superInterfaceSignatures()) {
+      for (ClassTypeSignature iFace : targetSignature.getSuperInterfaceSignatures()) {
         if (seenInterfaces.add(iFace.type())) {
-          builder.addInterface(iFace);
+          builder.addSuperInterfaceSignature(iFace);
         }
       }
       if (rewrittenSource.hasSignature()) {
-        for (ClassTypeSignature iFace : rewrittenSource.superInterfaceSignatures()) {
+        for (ClassTypeSignature iFace : rewrittenSource.getSuperInterfaceSignatures()) {
           if (!seenInterfaces.contains(iFace.type())) {
-            builder.addInterface(iFace);
+            builder.addSuperInterfaceSignature(iFace);
           }
         }
       } else {
         // Synthesize raw uses of interfaces to align with the actual class
         for (DexType iFace : source.interfaces) {
           if (!seenInterfaces.contains(iFace)) {
-            builder.addInterface(new ClassTypeSignature(iFace));
+            builder.addSuperInterfaceSignature(new ClassTypeSignature(iFace));
           }
         }
       }
-      target.setClassSignature(builder.build());
+      target.setClassSignature(builder.build(appView.dexItemFactory()));
 
       // Go through all type-variable references for members and update them.
       CollectionUtils.forEach(
@@ -1273,7 +1273,9 @@
       // We can assert proper structure below because the generic signature validator has run
       // before and pruned invalid signatures.
       List<FieldTypeSignature> genericArgumentsToSuperType =
-          target.getClassSignature().getGenericArgumentsToSuperType(source.type);
+          target
+              .getClassSignature()
+              .getGenericArgumentsToSuperType(source.type, appView.dexItemFactory());
       if (genericArgumentsToSuperType == null) {
         assert false : "Type should be present in generic signature";
         return null;
diff --git a/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java b/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
index 4c92f65..e0f7e1d 100644
--- a/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/graph/GenericSignatureTest.java
@@ -118,8 +118,8 @@
     classSignature = clazz.classSignature;
     assertNotNull(classSignature);
 
-    assertEquals(1, classSignature.formalTypeParameters.size());
-    FormalTypeParameter formalTypeParameter = classSignature.formalTypeParameters.get(0);
+    assertEquals(1, classSignature.getFormalTypeParameters().size());
+    FormalTypeParameter formalTypeParameter = classSignature.getFormalTypeParameters().get(0);
     assertEquals("T", formalTypeParameter.name);
     assertTrue(formalTypeParameter.interfaceBounds.isEmpty());
     assertTrue(formalTypeParameter.classBound.isClassTypeSignature());
@@ -135,8 +135,8 @@
             .asTypeVariableSignature()
             .typeVariable);
 
-    assertTrue(classSignature.superInterfaceSignatures.isEmpty());
-    classTypeSignature = classSignature.superClassSignature;
+    assertTrue(classSignature.getSuperInterfaceSignatures().isEmpty());
+    classTypeSignature = classSignature.getSuperClassSignatureOrNull();
     assertEquals(cy.getDexProgramClass().type, classTypeSignature.type);
     typeArguments = classTypeSignature.typeArguments;
     assertEquals(1, typeArguments.size());