aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar laurentlb <laurentlb@google.com>2018-03-22 08:32:01 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-03-22 08:33:15 -0700
commit8c434685584388a6e5e1b70685e9d9acbb948831 (patch)
tree762545b6f1a82f7895a2134dc14132813c5c2454
parent3dc6c7253ef273530702fa84e1bf67f416a49da6 (diff)
RELNOTES: In int() function, do not auto-detect base if input starts with '0'.
PiperOrigin-RevId: 190069001
-rw-r--r--src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java43
-rw-r--r--src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java8
2 files changed, 39 insertions, 12 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
index 83d954daf4..3ddf3f8399 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/MethodLibrary.java
@@ -1687,25 +1687,38 @@ public class MethodLibrary {
name = "int",
returnType = Integer.class,
doc =
- "Converts a value to int. "
- + "If the argument is a string, it is converted using the given base and raises an "
- + "error if the conversion fails. "
- + "The base can be between 2 and 36 (inclusive) and defaults to 10. "
- + "The value can be prefixed with 0b/0o/ox to represent values in base 2/8/16. "
- + "If such a prefix is present, a base of 0 can be used to automatically determine the "
- + "correct base: "
+ "Returns x as an int value."
+ + "<ul>"
+ + "<li>If <code>x</code> is already an int, it is returned as-is."
+ + "<li>If <code>x</code> is a boolean, a true value returns 1 and a false value "
+ + " returns 0."
+ + "<li>If <code>x</code> is a string, it is interpreted using the <code>base</code> "
+ + " argument (default 10). If <code>base</code> is non-zero, the string must be a "
+ + " sequence of digits optionally preceded by a sign. The characters a-z (or "
+ + " equivalently, A-Z) are used as digits for 10-35. The radix prefixes 0b/0o/0x "
+ + " (or 0B/0O/0X) may optionally be supplied when <code>base</code> is 2/8/16 "
+ + " respectively. If <code>base</code> is 0, the string is interpreted as an "
+ + " integer literal, where the base to use is determined by which if any of these "
+ + " prefixes is present. In the case where <code>base</code> is 0 and there is no "
+ + " prefix, the digits must not begin with a 0, to avoid confusion with octal "
+ + " numbers."
+ + "</ul>"
+ + "This method fails if the value is any other type, or if the value is a string not "
+ + "satisfying the above requirements."
+ "<pre class=\"language-python\">int(\"0xFF\", 0) == int(\"0xFF\", 16) == 255</pre>"
- + "If the argument is a bool, it returns 0 (False) or 1 (True). "
- + "If the argument is an int, it is simply returned."
+ "<pre class=\"language-python\">int(\"123\") == 123</pre>",
+ // TODO(bazel-team): Update documentation to remove mention about int("0123", 0) being
+ // disallowed once octal literals of form 0123 (without the 'o') are disallowed.
parameters = {
@Param(name = "x", type = Object.class, doc = "The string to convert."),
@Param(
name = "base",
type = Object.class,
defaultValue = "unbound",
- doc = "The base to use to interpret a string value; defaults to 10. This parameter must "
- + "not be supplied if the value is not a string."
+ doc =
+ "The base used to interpret a string value; defaults to 10. Must be between 2 and 36 "
+ + "(inclusive), or 0 to detect the base as if <code>x</code> were an integer "
+ + "literal. This parameter must not be supplied if the value is not a string."
)
},
useLocation = true
@@ -1746,6 +1759,14 @@ public class MethodLibrary {
// Nothing to strip. Infer base 10 if it was unknown (0).
digits = string;
if (base == 0) {
+ if (string.length() > 1 && string.startsWith("0")) {
+ // We don't infer the base when input starts with '0' (due
+ // to confusion between octal and decimal).
+ throw new EvalException(
+ loc,
+ Printer.format(
+ "cannot infer base for int() when value begins with a 0: %r", string));
+ }
base = 10;
}
} else {
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
index 6553a3d88e..fd7365136c 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/MethodLibraryTest.java
@@ -967,6 +967,7 @@ public class MethodLibraryTest extends EvaluationTestCase {
.testIfErrorContains("invalid literal for int() with base 10: \"1.5\"", "int('1.5')")
.testIfErrorContains("invalid literal for int() with base 10: \"ab\"", "int('ab')")
.testStatement("int(42)", 42)
+ .testStatement("int('016')", 16)
.testStatement("int(-1)", -1)
.testStatement("int(True)", 1)
.testStatement("int(False)", 0)
@@ -982,12 +983,17 @@ public class MethodLibraryTest extends EvaluationTestCase {
.testStatement("int('11', 36)", 37)
.testStatement("int('az', 36)", 395)
.testStatement("int('11', 10)", 11)
- .testStatement("int('11', 0)", 11);
+ .testStatement("int('11', 0)", 11)
+ .testStatement("int('016', 8)", 14)
+ .testStatement("int('016', 16)", 22);
}
@Test
public void testIntWithBase_InvalidBase() throws Exception {
new BothModesTest()
+ .testIfErrorContains(
+ "cannot infer base for int() when value begins with a 0: \"016\"",
+ "int('016', 0)")
.testIfExactError("invalid literal for int() with base 3: \"123\"", "int('123', 3)")
.testIfExactError("invalid literal for int() with base 15: \"FF\"", "int('FF', 15)")
.testIfExactError("int() base must be >= 2 and <= 36", "int('123', -1)")