Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit caf66d02 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Expand formatSimple() to support widths.

One of the highest-traffic users of String.format() is in the
notification code, which uses argument widths.  To support these
use-cases, this change adds argument width support, with tests.

Bug: 170978902
Test: atest error_prone_android_framework_test
Exempt-From-Owner-Approval: trivial additions
Change-Id: I8e36d4725a6d0cc896dedc5c457eb5f38486d7b6
parent 5c46da2a
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -2095,6 +2095,9 @@ public class TextUtils {
     * <li>{@code %s} for {@code String}
     * <li>{@code %x} for hex representation of {@code int} or {@code long}
     * <li>{@code %%} for literal {@code %}
     * <li>{@code %04d} style grammar to specify the argument width, such as
     * {@code %04d} to prefix an {@code int} with zeros or {@code %10b} to
     * prefix a {@code boolean} with spaces
     * </ul>
     *
     * @throws IllegalArgumentException if the format string or arguments don't
@@ -2106,8 +2109,23 @@ public class TextUtils {
        int j = 0;
        for (int i = 0; i < sb.length(); ) {
            if (sb.charAt(i) == '%') {
                char code = sb.charAt(i + 1);

                // Decode any argument width request
                char prefixChar = '\0';
                int prefixLen = 0;
                int consume = 2;
                while ('0' <= code && code <= '9') {
                    if (prefixChar == '\0') {
                        prefixChar = (code == '0') ? '0' : ' ';
                    }
                    prefixLen *= 10;
                    prefixLen += Character.digit(code, 10);
                    consume += 1;
                    code = sb.charAt(i + consume - 1);
                }

                final String repl;
                final char code = sb.charAt(i + 1);
                switch (code) {
                    case 'b': {
                        if (j == args.length) {
@@ -2155,8 +2173,15 @@ public class TextUtils {
                        throw new IllegalArgumentException("Unsupported format code " + code);
                    }
                }
                sb.replace(i, i + 2, repl);
                i += repl.length();

                sb.replace(i, i + consume, repl);

                // Apply any argument width request
                final int prefixInsert = (prefixChar == '0' && repl.charAt(0) == '-') ? 1 : 0;
                for (int k = repl.length(); k < prefixLen; k++) {
                    sb.insert(i + prefixInsert, prefixChar);
                }
                i += Math.max(repl.length(), prefixLen);
            } else {
                i++;
            }
+26 −0
Original line number Diff line number Diff line
@@ -821,6 +821,25 @@ public class TextUtilsTest {
        assertEquals("%", formatSimple("%%"));
    }

    @Test
    public void testFormatSimple_Width() {
        assertEquals("42", formatSimple("%1d", 42));
        assertEquals("42", formatSimple("%2d", 42));
        assertEquals(" 42", formatSimple("%3d", 42));
        assertEquals("  42", formatSimple("%4d", 42));
        assertEquals("  42  42", formatSimple("%4d%4d", 42, 42));
        assertEquals(" -42", formatSimple("%4d", -42));
        assertEquals("        42", formatSimple("%10d", 42));

        assertEquals("42", formatSimple("%01d", 42));
        assertEquals("42", formatSimple("%02d", 42));
        assertEquals("042", formatSimple("%03d", 42));
        assertEquals("0042", formatSimple("%04d", 42));
        assertEquals("00420042", formatSimple("%04d%04d", 42, 42));
        assertEquals("-042", formatSimple("%04d", -42));
        assertEquals("0000000042", formatSimple("%010d", 42));
    }

    @Test
    public void testFormatSimple_Empty() {
        assertEquals("", formatSimple(""));
@@ -832,6 +851,13 @@ public class TextUtilsTest {
                formatSimple("String %s%s and %%%% number %d%d together", "foo", "bar", -4, 2));
    }

    @Test
    public void testFormatSimple_Advanced() {
        assertEquals("crtcl=0x002a:intrsv=Y:grnk=0x0018:gsmry=A:example:rnk=0x0000",
                formatSimple("crtcl=0x%04x:intrsv=%c:grnk=0x%04x:gsmry=%c:%s:rnk=0x%04x",
                        42, 'Y', 24, 'A', "example", 0));
    }

    @Test
    public void testFormatSimple_Mismatch() {
        try {
+4 −2
Original line number Diff line number Diff line
@@ -180,8 +180,10 @@ public final class EfficientStringsChecker extends BugChecker
        for (int i = 0; i < format.length(); i++) {
            char c = format.charAt(i);
            if (c == '%') {
                i++;
                c = format.charAt(i);
                c = format.charAt(++i);
                while ('0' <= c && c <= '9') {
                    c = format.charAt(++i);
                }
                switch (c) {
                    case 'b':
                    case 'c':
+8 −2
Original line number Diff line number Diff line
@@ -41,9 +41,13 @@ public class EfficientStringsCheckerTest {
        assertTrue(EfficientStringsChecker.isSimple(""));
        assertTrue(EfficientStringsChecker.isSimple("%s"));
        assertTrue(EfficientStringsChecker.isSimple("String %s%s and %%%% number %d%d together"));
        assertTrue(EfficientStringsChecker.isSimple("%04d"));
        assertTrue(EfficientStringsChecker.isSimple("%02x:%02x:%02x"));
        assertTrue(EfficientStringsChecker.isSimple("%10d"));

        assertFalse(EfficientStringsChecker.isSimple("%04d"));
        assertFalse(EfficientStringsChecker.isSimple("%02x:%02x:%02x"));
        assertFalse(EfficientStringsChecker.isSimple("%0.4f"));
        assertFalse(EfficientStringsChecker.isSimple("%t"));
        assertFalse(EfficientStringsChecker.isSimple("%1$s"));
    }

    @Test
@@ -58,6 +62,7 @@ public class EfficientStringsCheckerTest {
                        "    String.format(\"foo %s bar\", str);",
                        "    // BUG: Diagnostic contains:",
                        "    String.format(\"foo %d bar\", 42);",
                        "    // BUG: Diagnostic contains:",
                        "    String.format(\"foo %04d bar\", 42);",
                        "  }",
                        "  public void exampleLocale(String str) {",
@@ -66,6 +71,7 @@ public class EfficientStringsCheckerTest {
                        "    String.format(Locale.US, \"foo %s bar\", str);",
                        "    // BUG: Diagnostic contains:",
                        "    String.format(Locale.US, \"foo %d bar\", 42);",
                        "    // BUG: Diagnostic contains:",
                        "    String.format(Locale.US, \"foo %04d bar\", 42);",
                        "  }",
                        "}")