Make format args explicit in DocString.

Previously it was not clear that passing a single argument to
DocString.text, DocString.append, or DocString.uri would be treated as
a format string. With this change, the 'text', 'append', and 'uri'
methods take literal strings, and the new 'format', 'appendFormat',
and 'formattedUri' methods take format strings.

Bug: 23782192
Change-Id: I9a094575f0831de6659033052305f918c71ac8b7
diff --git a/tools/ahat/src/DocString.java b/tools/ahat/src/DocString.java
index 1d997dc..19666de 100644
--- a/tools/ahat/src/DocString.java
+++ b/tools/ahat/src/DocString.java
@@ -33,11 +33,18 @@
 
   /**
    * Construct a new DocString, initialized with the given text.
-   * Format arguments are supported.
    */
-  public static DocString text(String format, Object... args) {
+  public static DocString text(String str) {
     DocString doc = new DocString();
-    return doc.append(format, args);
+    return doc.append(str);
+  }
+
+  /**
+   * Construct a new DocString, initialized with the given formatted text.
+   */
+  public static DocString format(String format, Object... args) {
+    DocString doc = new DocString();
+    return doc.appendFormat(format, args);
   }
 
   /**
@@ -58,15 +65,22 @@
 
   /**
    * Append literal text to the given doc string.
-   * Format arguments are supported.
    * Returns this object.
    */
-  public DocString append(String format, Object... args) {
-    String text = String.format(format, args);
+  public DocString append(String text) {
     mStringBuilder.append(HtmlEscapers.htmlEscaper().escape(text));
     return this;
   }
 
+  /**
+   * Append formatted text to the given doc string.
+   * Returns this object.
+   */
+  public DocString appendFormat(String format, Object... args) {
+    append(String.format(format, args));
+    return this;
+  }
+
   public DocString append(DocString str) {
     mStringBuilder.append(str.html());
     return this;
@@ -101,10 +115,9 @@
 
   /**
    * Convenience function for constructing a URI from a string with a uri
-   * known to be valid. Format arguments are supported.
+   * known to be valid.
    */
-  public static URI uri(String format, Object... args) {
-    String uriString = String.format(format, args);
+  public static URI uri(String uriString) {
     try {
       return new URI(uriString);
     } catch (URISyntaxException e) {
@@ -113,6 +126,14 @@
   }
 
   /**
+   * Convenience function for constructing a URI from a formatted string with
+   * a uri known to be valid.
+   */
+  public static URI formattedUri(String format, Object... args) {
+    return uri(String.format(format, args));
+  }
+
+  /**
    * Render the DocString as html.
    */
   public String html() {
diff --git a/tools/ahat/src/DominatedList.java b/tools/ahat/src/DominatedList.java
index 53d1073..123d8be 100644
--- a/tools/ahat/src/DominatedList.java
+++ b/tools/ahat/src/DominatedList.java
@@ -140,7 +140,7 @@
   //  (showing X of Y objects - show none - show less - show more - show all)
   private static void printMenu(Doc doc, Query query, int shown, int all) {
     DocString menu = new DocString();
-    menu.append("(%d of %d objects shown - ", shown, all);
+    menu.appendFormat("(%d of %d objects shown - ", shown, all);
     if (shown > 0) {
       int less = Math.max(0, shown - kIncrAmount);
       menu.appendLink(query.with("dominated", 0), DocString.text("show none"));
diff --git a/tools/ahat/src/HeapTable.java b/tools/ahat/src/HeapTable.java
index 60bb387..37d5816 100644
--- a/tools/ahat/src/HeapTable.java
+++ b/tools/ahat/src/HeapTable.java
@@ -76,10 +76,10 @@
       for (Heap heap : heaps) {
         long size = config.getSize(elem, heap);
         total += size;
-        vals.add(DocString.text("%,14d", size));
+        vals.add(DocString.format("%,14d", size));
       }
       if (showTotal) {
-        vals.add(DocString.text("%,14d", total));
+        vals.add(DocString.format("%,14d", total));
       }
 
       for (ValueConfig<T> value : values) {
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java
index eecd7d1..5e321e2 100644
--- a/tools/ahat/src/ObjectHandler.java
+++ b/tools/ahat/src/ObjectHandler.java
@@ -39,7 +39,7 @@
     long id = query.getLong("id", 0);
     Instance inst = mSnapshot.findInstance(id);
     if (inst == null) {
-      doc.println(DocString.text("No object with id %08xl", id));
+      doc.println(DocString.format("No object with id %08xl", id));
       return;
     }
 
@@ -53,10 +53,10 @@
     ClassObj cls = inst.getClassObj();
     doc.descriptions();
     doc.description(DocString.text("Class"), Value.render(cls));
-    doc.description(DocString.text("Size"), DocString.text("%d", inst.getSize()));
+    doc.description(DocString.text("Size"), DocString.format("%d", inst.getSize()));
     doc.description(
         DocString.text("Retained Size"),
-        DocString.text("%d", inst.getTotalRetainedSize()));
+        DocString.format("%d", inst.getTotalRetainedSize()));
     doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName()));
     doc.end();
 
@@ -89,7 +89,7 @@
     doc.table(new Column("Index", Column.Align.RIGHT), new Column("Value"));
     Object[] elements = array.getValues();
     for (int i = 0; i < elements.length; i++) {
-      doc.row(DocString.text("%d", i), Value.render(elements[i]));
+      doc.row(DocString.format("%d", i), Value.render(elements[i]));
     }
     doc.end();
   }
@@ -146,7 +146,7 @@
     if (bitmap != null) {
       doc.section("Bitmap Image");
       doc.println(DocString.image(
-            DocString.uri("bitmap?id=%d", bitmap.getId()), "bitmap image"));
+            DocString.formattedUri("bitmap?id=%d", bitmap.getId()), "bitmap image"));
     }
   }
 
diff --git a/tools/ahat/src/ObjectsHandler.java b/tools/ahat/src/ObjectsHandler.java
index 066c9d5..4e9c42e 100644
--- a/tools/ahat/src/ObjectsHandler.java
+++ b/tools/ahat/src/ObjectsHandler.java
@@ -53,7 +53,7 @@
         new Column("Object"));
     for (Instance inst : insts) {
       doc.row(
-          DocString.text("%,d", inst.getSize()),
+          DocString.format("%,d", inst.getSize()),
           DocString.text(inst.getHeap().getName()),
           Value.render(inst));
     }
diff --git a/tools/ahat/src/OverviewHandler.java b/tools/ahat/src/OverviewHandler.java
index 6e6c323..f49c009 100644
--- a/tools/ahat/src/OverviewHandler.java
+++ b/tools/ahat/src/OverviewHandler.java
@@ -38,7 +38,7 @@
     doc.descriptions();
     doc.description(
         DocString.text("ahat version"),
-        DocString.text("ahat-%s", OverviewHandler.class.getPackage().getImplementationVersion()));
+        DocString.format("ahat-%s", OverviewHandler.class.getPackage().getImplementationVersion()));
     doc.description(DocString.text("hprof file"), DocString.text(mHprof.toString()));
     doc.end();
 
diff --git a/tools/ahat/src/SiteHandler.java b/tools/ahat/src/SiteHandler.java
index 8fbc176..0a9381e 100644
--- a/tools/ahat/src/SiteHandler.java
+++ b/tools/ahat/src/SiteHandler.java
@@ -61,7 +61,7 @@
 
             public DocString render(Site element) {
               return DocString.link(
-                  DocString.uri("site?stack=%d&depth=%d",
+                  DocString.formattedUri("site?stack=%d&depth=%d",
                     element.getStackId(), element.getStackDepth()),
                   DocString.text(element.getName()));
             }
@@ -87,11 +87,11 @@
     for (Site.ObjectsInfo info : infos) {
       String className = AhatSnapshot.getClassName(info.classObj);
       doc.row(
-          DocString.text("%,14d", info.numBytes),
+          DocString.format("%,14d", info.numBytes),
           DocString.link(
-            DocString.uri("objects?stack=%d&depth=%d&heap=%s&class=%s",
+            DocString.formattedUri("objects?stack=%d&depth=%d&heap=%s&class=%s",
                 site.getStackId(), site.getStackDepth(), info.heap.getName(), className),
-            DocString.text("%,14d", info.numInstances)),
+            DocString.format("%,14d", info.numInstances)),
           DocString.text(info.heap.getName()),
           Value.render(info.classObj));
     }
diff --git a/tools/ahat/src/SitePrinter.java b/tools/ahat/src/SitePrinter.java
index 9c0c2e0..be87032 100644
--- a/tools/ahat/src/SitePrinter.java
+++ b/tools/ahat/src/SitePrinter.java
@@ -51,7 +51,7 @@
               str.append("→ ");
             }
             str.appendLink(
-                DocString.uri("site?stack=%d&depth=%d",
+                DocString.formattedUri("site?stack=%d&depth=%d",
                     element.getStackId(), element.getStackDepth()),
                 DocString.text(element.getName()));
             return str;
diff --git a/tools/ahat/src/Value.java b/tools/ahat/src/Value.java
index 22c3b8f..9b483fa 100644
--- a/tools/ahat/src/Value.java
+++ b/tools/ahat/src/Value.java
@@ -45,7 +45,7 @@
     // Annotate Strings with their values.
     String stringValue = InstanceUtils.asString(inst);
     if (stringValue != null) {
-      link.append("\"%s\"", stringValue);
+      link.appendFormat("\"%s\"", stringValue);
     }
 
     // Annotate DexCache with its location.
@@ -54,14 +54,14 @@
       link.append(" for " + dexCacheLocation);
     }
 
-    URI objTarget = DocString.uri("object?id=%d", inst.getId());
+    URI objTarget = DocString.formattedUri("object?id=%d", inst.getId());
     DocString formatted = DocString.link(objTarget, link);
 
     // Annotate bitmaps with a thumbnail.
     Instance bitmap = InstanceUtils.getAssociatedBitmapInstance(inst);
     String thumbnail = "";
     if (bitmap != null) {
-      URI uri = DocString.uri("bitmap?id=%d", bitmap.getId());
+      URI uri = DocString.formattedUri("bitmap?id=%d", bitmap.getId());
       formatted.appendThumbnail(uri, "bitmap image");
     }
     return formatted;
@@ -74,7 +74,7 @@
     if (val instanceof Instance) {
       return renderInstance((Instance)val);
     } else {
-      return DocString.text("%s", val);
+      return DocString.format("%s", val);
     }
   }
 }