Support modern location expansions for run_binary (#490)

A common point of confusion I see around `run_binary` is that it's hard coded to only expand `$(location` values which in codebases I work in are otherwise completely eliminated due to it being described as "legacy"

> location: A synonym for either execpath or rootpath, depending on the attribute being expanded. This is legacy pre-Starlark behavior and not recommended unless you really know what it does for a particular rule. See [#2475](https://github.com/bazelbuild/bazel/issues/2475#issuecomment-339318016) for details.

If `execpath` is used instead as the appropriate alternative, the rule does no do any expansion and fails the action. This change adds support for expanding all available patterns whenever they're provided.
diff --git a/docs/run_binary_doc.md b/docs/run_binary_doc.md
index cec27c1..468c7f5 100755
--- a/docs/run_binary_doc.md
+++ b/docs/run_binary_doc.md
@@ -22,10 +22,10 @@
 | Name  | Description | Type | Mandatory | Default |
 | :------------- | :------------- | :------------- | :------------- | :------------- |
 | <a id="run_binary-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
-| <a id="run_binary-srcs"></a>srcs |  Additional inputs of the action.<br><br>These labels are available for `$(location)` expansion in `args` and `env`.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
-| <a id="run_binary-outs"></a>outs |  Output files generated by the action.<br><br>These labels are available for `$(location)` expansion in `args` and `env`.   | List of labels | required |  |
-| <a id="run_binary-args"></a>args |  Command line arguments of the binary.<br><br>Subject to [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables) expansion.   | List of strings | optional |  `[]`  |
-| <a id="run_binary-env"></a>env |  Environment variables of the action.<br><br>Subject to  [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables) expansion.   | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional |  `{}`  |
-| <a id="run_binary-tool"></a>tool |  The tool to run in the action.<br><br>Must be the label of a *_binary rule, of a rule that generates an executable file, or of a file that can be executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary with executable permission on Linux). This label is available for `$(location)` expansion in `args` and `env`.   | <a href="https://bazel.build/concepts/labels">Label</a> | required |  |
+| <a id="run_binary-srcs"></a>srcs |  Additional inputs of the action.<br><br>These labels are available for `$(execpath)` and `$(location)` expansion in `args` and `env`.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="run_binary-outs"></a>outs |  Output files generated by the action.<br><br>These labels are available for `$(execpath)` and `$(location)` expansion in `args` and `env`.   | List of labels | required |  |
+| <a id="run_binary-args"></a>args |  Command line arguments of the binary.<br><br>Subject to [`$(execpath)` and `$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables) expansion.   | List of strings | optional |  `[]`  |
+| <a id="run_binary-env"></a>env |  Environment variables of the action.<br><br>Subject to  [`$(execpath)` and `$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables) expansion.   | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional |  `{}`  |
+| <a id="run_binary-tool"></a>tool |  The tool to run in the action.<br><br>Must be the label of a *_binary rule, of a rule that generates an executable file, or of a file that can be executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary with executable permission on Linux). This label is available for `$(execpath)` and `$(location)` expansion in `args` and `env`.   | <a href="https://bazel.build/concepts/labels">Label</a> | required |  |
 
 
diff --git a/rules/run_binary.bzl b/rules/run_binary.bzl
index 7701fa0..82d6330 100644
--- a/rules/run_binary.bzl
+++ b/rules/run_binary.bzl
@@ -20,10 +20,10 @@
 
 load("//lib:dicts.bzl", "dicts")
 
-def _impl(ctx):
+def _run_binary_impl(ctx):
     tool_as_list = [ctx.attr.tool]
     args = [
-        # Expand $(location) / $(locations) in args.
+        # Expand $(execpath ...) / $(execpaths ...) / $(location ...) / $(locations ...) in args.
         #
         # To keep the rule simple, do not expand Make Variables (like *_binary.args usually would).
         # (We can add this feature later if users ask for it.)
@@ -33,12 +33,12 @@
         # tokenization they would have to write args=["'a b'"] or args=["a\\ b"]. There's no
         # documented tokenization function anyway (as of 2019-05-21 ctx.tokenize exists but is
         # undocumented, see https://github.com/bazelbuild/bazel/issues/8389).
-        ctx.expand_location(a, tool_as_list) if "$(location" in a else a
+        ctx.expand_location(a, tool_as_list)
         for a in ctx.attr.args
     ]
     envs = {
-        # Expand $(location) / $(locations) in the values.
-        k: ctx.expand_location(v, tool_as_list) if "$(location" in v else v
+        # Expand $(execpath ...) / $(execpaths ...) / $(location ...) / $(locations ...) in the values.
+        k: ctx.expand_location(v, tool_as_list)
         for k, v in ctx.attr.env.items()
     }
     ctx.actions.run(
@@ -57,7 +57,7 @@
     )
 
 run_binary = rule(
-    implementation = _impl,
+    implementation = _run_binary_impl,
     doc = "Runs a binary as a build action.\n\nThis rule does not require Bash (unlike" +
           " `native.genrule`).",
     attrs = {
@@ -66,7 +66,7 @@
                   " of a rule that generates an executable file, or of a file that can be" +
                   " executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary" +
                   " with executable permission on Linux). This label is available for" +
-                  " `$(location)` expansion in `args` and `env`.",
+                  " `$(execpath)` and `$(location)` expansion in `args` and `env`.",
             executable = True,
             allow_files = True,
             mandatory = True,
@@ -74,22 +74,22 @@
         ),
         "env": attr.string_dict(
             doc = "Environment variables of the action.\n\nSubject to " +
-                  " [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables)" +
+                  " [`$(execpath)` and `$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables)" +
                   " expansion.",
         ),
         "srcs": attr.label_list(
             allow_files = True,
             doc = "Additional inputs of the action.\n\nThese labels are available for" +
-                  " `$(location)` expansion in `args` and `env`.",
+                  " `$(execpath)` and `$(location)` expansion in `args` and `env`.",
         ),
         "outs": attr.output_list(
             mandatory = True,
             doc = "Output files generated by the action.\n\nThese labels are available for" +
-                  " `$(location)` expansion in `args` and `env`.",
+                  " `$(execpath)` and `$(location)` expansion in `args` and `env`.",
         ),
         "args": attr.string_list(
             doc = "Command line arguments of the binary.\n\nSubject to" +
-                  " [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables)" +
+                  " [`$(execpath)` and `$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables)" +
                   " expansion.",
         ),
     },
diff --git a/tests/run_binary/BUILD b/tests/run_binary/BUILD
index 0b02087..18682f6 100644
--- a/tests/run_binary/BUILD
+++ b/tests/run_binary/BUILD
@@ -24,6 +24,8 @@
         "arg2=(bar)",
         "ENV_LOCATION=(a tests/run_binary/BUILD)",
         "ENV_LOCATIONS=(b\\ tests/run_binary/BUILD tests/run_binary/printargs.cc)",
+        "ENV_EXECPATH=(a tests/run_binary/BUILD)",
+        "ENV_EXECPATHS=(b\\ tests/run_binary/BUILD tests/run_binary/printargs.cc)",
         "ENV_COMPLEX=(xx/yy \\\"zz)",
         "ENV_PATH_BASH=($PATH)",
         "ENV_PATH_CMD=(%PATH%)",
@@ -51,12 +53,14 @@
     # Bash-tokenized, and should appear the same for Windows .bat files and Bash
     # .sh scripts.
     env = {
+        "ENV_COMPLEX": "xx/yy \\\"zz",
+        "ENV_EXECPATH": "a $(execpath BUILD)",
+        "ENV_EXECPATHS": "b\\ $(execpaths :dummy_srcs)",
         # Testing $(location) expansion only on source files so the result is
         # predictable. The path of generated files depends on the target
         # platform.
         "ENV_LOCATION": "a $(location BUILD)",
         "ENV_LOCATIONS": "b\\ $(locations :dummy_srcs)",
-        "ENV_COMPLEX": "xx/yy \\\"zz",
         "ENV_PATH_BASH": "$PATH",
         "ENV_PATH_CMD": "%PATH%",
         "OUT": "$(location run_script.out)",
@@ -76,6 +80,8 @@
             "@echo>>%OUT% arg2=(%2)",
             "@echo>>%OUT% ENV_LOCATION=(%ENV_LOCATION%)",
             "@echo>>%OUT% ENV_LOCATIONS=(%ENV_LOCATIONS%)",
+            "@echo>>%OUT% ENV_EXECPATH=(%ENV_EXECPATH%)",
+            "@echo>>%OUT% ENV_EXECPATHS=(%ENV_EXECPATHS%)",
             "@echo>>%OUT% ENV_COMPLEX=(%ENV_COMPLEX%)",
             "@echo>>%OUT% ENV_PATH_BASH=(%ENV_PATH_BASH%)",
             "@echo>>%OUT% ENV_PATH_CMD=(%ENV_PATH_CMD%)",
@@ -86,6 +92,8 @@
             "echo >> \"$OUT\" \"arg2=($2)\"",
             "echo >> \"$OUT\" \"ENV_LOCATION=($ENV_LOCATION)\"",
             "echo >> \"$OUT\" \"ENV_LOCATIONS=($ENV_LOCATIONS)\"",
+            "echo >> \"$OUT\" \"ENV_EXECPATH=($ENV_EXECPATH)\"",
+            "echo >> \"$OUT\" \"ENV_EXECPATHS=($ENV_EXECPATHS)\"",
             "echo >> \"$OUT\" \"ENV_COMPLEX=($ENV_COMPLEX)\"",
             "echo >> \"$OUT\" \"ENV_PATH_BASH=($ENV_PATH_BASH)\"",
             "echo >> \"$OUT\" \"ENV_PATH_CMD=($ENV_PATH_CMD)\"",
@@ -114,9 +122,13 @@
         "arg5=(tests/run_binary/BUILD)",
         "arg6=(tests/run_binary/BUILD tests/run_binary/printargs.cc)",
         "arg7=('tests/run_binary/BUILD $tests/run_binary/BUILD')",
-        "arg8=($PATH)",
-        "arg9=($$PATH)",
-        "arg10=(${PATH})",
+        "arg8=(tests/run_binary/BUILD)",
+        "arg9=(tests/run_binary/BUILD tests/run_binary/printargs.cc)",
+        "arg10=('tests/run_binary/BUILD $tests/run_binary/BUILD')",
+        "arg11=($PATH)",
+        "arg12=($$PATH)",
+        "arg13=(${PATH})",
+        "arg14=($(echo hello))",
         # Add trailing newline, as printed by printargs.
         "",
     ],
@@ -136,15 +148,20 @@
         "\"c d\"",
         "e\\ f",
         "xx/yy\\ \\\"zz",
-        # Testing $(location) expansion only on source files so the result is
+        # Testing $(execpath) expansion only on source files so the result is
         # predictable. The path of generated files depends on the target
         # platform.
+        "$(execpath BUILD)",
+        "$(execpaths :dummy_srcs)",
+        "'$(execpath BUILD) $$(execpath BUILD)'",
+        # Test the legacy 'location' expansions
         "$(location BUILD)",
         "$(locations :dummy_srcs)",
         "'$(location BUILD) $$(location BUILD)'",
         "$PATH",
         "$$PATH",
         "${PATH}",
+        "$(echo hello)",
     ],
     # Not testing any complex envvars here, because we already did in
     # "run_script".