xref: /aosp_15_r20/external/bazelbuild-rules_rust/rust/private/clippy.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
1*d4726bddSHONG Yifan# Copyright 2020 The Bazel Authors. All rights reserved.
2*d4726bddSHONG Yifan#
3*d4726bddSHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License");
4*d4726bddSHONG Yifan# you may not use this file except in compliance with the License.
5*d4726bddSHONG Yifan# You may obtain a copy of the License at
6*d4726bddSHONG Yifan#
7*d4726bddSHONG Yifan#    http://www.apache.org/licenses/LICENSE-2.0
8*d4726bddSHONG Yifan#
9*d4726bddSHONG Yifan# Unless required by applicable law or agreed to in writing, software
10*d4726bddSHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS,
11*d4726bddSHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*d4726bddSHONG Yifan# See the License for the specific language governing permissions and
13*d4726bddSHONG Yifan# limitations under the License.
14*d4726bddSHONG Yifan
15*d4726bddSHONG Yifan"""A module defining clippy rules"""
16*d4726bddSHONG Yifan
17*d4726bddSHONG Yifanload("//rust/private:common.bzl", "rust_common")
18*d4726bddSHONG Yifanload("//rust/private:providers.bzl", "CaptureClippyOutputInfo", "ClippyInfo")
19*d4726bddSHONG Yifanload(
20*d4726bddSHONG Yifan    "//rust/private:rustc.bzl",
21*d4726bddSHONG Yifan    "collect_deps",
22*d4726bddSHONG Yifan    "collect_inputs",
23*d4726bddSHONG Yifan    "construct_arguments",
24*d4726bddSHONG Yifan)
25*d4726bddSHONG Yifanload(
26*d4726bddSHONG Yifan    "//rust/private:utils.bzl",
27*d4726bddSHONG Yifan    "determine_output_hash",
28*d4726bddSHONG Yifan    "find_cc_toolchain",
29*d4726bddSHONG Yifan    "find_toolchain",
30*d4726bddSHONG Yifan)
31*d4726bddSHONG Yifan
32*d4726bddSHONG YifanClippyFlagsInfo = provider(
33*d4726bddSHONG Yifan    doc = "Pass each value as an additional flag to clippy invocations",
34*d4726bddSHONG Yifan    fields = {"clippy_flags": "List[string] Flags to pass to clippy"},
35*d4726bddSHONG Yifan)
36*d4726bddSHONG Yifan
37*d4726bddSHONG Yifandef _clippy_flag_impl(ctx):
38*d4726bddSHONG Yifan    return ClippyFlagsInfo(clippy_flags = [f for f in ctx.build_setting_value if f != ""])
39*d4726bddSHONG Yifan
40*d4726bddSHONG Yifanclippy_flag = rule(
41*d4726bddSHONG Yifan    doc = (
42*d4726bddSHONG Yifan        "Add a custom clippy flag from the command line with `--@rules_rust//:clippy_flag`." +
43*d4726bddSHONG Yifan        "Multiple uses are accumulated and appended after the extra_rustc_flags."
44*d4726bddSHONG Yifan    ),
45*d4726bddSHONG Yifan    implementation = _clippy_flag_impl,
46*d4726bddSHONG Yifan    build_setting = config.string(flag = True, allow_multiple = True),
47*d4726bddSHONG Yifan)
48*d4726bddSHONG Yifan
49*d4726bddSHONG Yifandef _clippy_flags_impl(ctx):
50*d4726bddSHONG Yifan    return ClippyFlagsInfo(clippy_flags = ctx.build_setting_value)
51*d4726bddSHONG Yifan
52*d4726bddSHONG Yifanclippy_flags = rule(
53*d4726bddSHONG Yifan    doc = (
54*d4726bddSHONG Yifan        "Add custom clippy flags from the command line with `--@rules_rust//:clippy_flags`."
55*d4726bddSHONG Yifan    ),
56*d4726bddSHONG Yifan    implementation = _clippy_flags_impl,
57*d4726bddSHONG Yifan    build_setting = config.string_list(flag = True),
58*d4726bddSHONG Yifan)
59*d4726bddSHONG Yifan
60*d4726bddSHONG Yifandef _get_clippy_ready_crate_info(target, aspect_ctx = None):
61*d4726bddSHONG Yifan    """Check that a target is suitable for clippy and extract the `CrateInfo` provider from it.
62*d4726bddSHONG Yifan
63*d4726bddSHONG Yifan    Args:
64*d4726bddSHONG Yifan        target (Target): The target the aspect is running on.
65*d4726bddSHONG Yifan        aspect_ctx (ctx, optional): The aspect's context object.
66*d4726bddSHONG Yifan
67*d4726bddSHONG Yifan    Returns:
68*d4726bddSHONG Yifan        CrateInfo, optional: A `CrateInfo` provider if clippy should be run or `None`.
69*d4726bddSHONG Yifan    """
70*d4726bddSHONG Yifan
71*d4726bddSHONG Yifan    # Ignore external targets
72*d4726bddSHONG Yifan    if target.label.workspace_root.startswith("external"):
73*d4726bddSHONG Yifan        return None
74*d4726bddSHONG Yifan
75*d4726bddSHONG Yifan    # Targets with specific tags will not be formatted
76*d4726bddSHONG Yifan    if aspect_ctx:
77*d4726bddSHONG Yifan        ignore_tags = [
78*d4726bddSHONG Yifan            "noclippy",
79*d4726bddSHONG Yifan            "no-clippy",
80*d4726bddSHONG Yifan        ]
81*d4726bddSHONG Yifan
82*d4726bddSHONG Yifan        for tag in ignore_tags:
83*d4726bddSHONG Yifan            if tag in aspect_ctx.rule.attr.tags:
84*d4726bddSHONG Yifan                return None
85*d4726bddSHONG Yifan
86*d4726bddSHONG Yifan    # Obviously ignore any targets that don't contain `CrateInfo`
87*d4726bddSHONG Yifan    if rust_common.crate_info in target:
88*d4726bddSHONG Yifan        return target[rust_common.crate_info]
89*d4726bddSHONG Yifan    elif rust_common.test_crate_info in target:
90*d4726bddSHONG Yifan        return target[rust_common.test_crate_info].crate
91*d4726bddSHONG Yifan    else:
92*d4726bddSHONG Yifan        return None
93*d4726bddSHONG Yifan
94*d4726bddSHONG Yifandef _clippy_aspect_impl(target, ctx):
95*d4726bddSHONG Yifan    crate_info = _get_clippy_ready_crate_info(target, ctx)
96*d4726bddSHONG Yifan    if not crate_info:
97*d4726bddSHONG Yifan        return [ClippyInfo(output = depset([]))]
98*d4726bddSHONG Yifan
99*d4726bddSHONG Yifan    toolchain = find_toolchain(ctx)
100*d4726bddSHONG Yifan    cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
101*d4726bddSHONG Yifan
102*d4726bddSHONG Yifan    dep_info, build_info, _ = collect_deps(
103*d4726bddSHONG Yifan        deps = crate_info.deps,
104*d4726bddSHONG Yifan        proc_macro_deps = crate_info.proc_macro_deps,
105*d4726bddSHONG Yifan        aliases = crate_info.aliases,
106*d4726bddSHONG Yifan    )
107*d4726bddSHONG Yifan
108*d4726bddSHONG Yifan    compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs, ambiguous_libs = collect_inputs(
109*d4726bddSHONG Yifan        ctx,
110*d4726bddSHONG Yifan        ctx.rule.file,
111*d4726bddSHONG Yifan        ctx.rule.files,
112*d4726bddSHONG Yifan        # Clippy doesn't need to invoke transitive linking, therefore doesn't need linkstamps.
113*d4726bddSHONG Yifan        depset([]),
114*d4726bddSHONG Yifan        toolchain,
115*d4726bddSHONG Yifan        cc_toolchain,
116*d4726bddSHONG Yifan        feature_configuration,
117*d4726bddSHONG Yifan        crate_info,
118*d4726bddSHONG Yifan        dep_info,
119*d4726bddSHONG Yifan        build_info,
120*d4726bddSHONG Yifan    )
121*d4726bddSHONG Yifan
122*d4726bddSHONG Yifan    args, env = construct_arguments(
123*d4726bddSHONG Yifan        ctx = ctx,
124*d4726bddSHONG Yifan        attr = ctx.rule.attr,
125*d4726bddSHONG Yifan        file = ctx.file,
126*d4726bddSHONG Yifan        toolchain = toolchain,
127*d4726bddSHONG Yifan        tool_path = toolchain.clippy_driver.path,
128*d4726bddSHONG Yifan        cc_toolchain = cc_toolchain,
129*d4726bddSHONG Yifan        feature_configuration = feature_configuration,
130*d4726bddSHONG Yifan        crate_info = crate_info,
131*d4726bddSHONG Yifan        dep_info = dep_info,
132*d4726bddSHONG Yifan        linkstamp_outs = linkstamp_outs,
133*d4726bddSHONG Yifan        ambiguous_libs = ambiguous_libs,
134*d4726bddSHONG Yifan        output_hash = determine_output_hash(crate_info.root, ctx.label),
135*d4726bddSHONG Yifan        rust_flags = [],
136*d4726bddSHONG Yifan        out_dir = out_dir,
137*d4726bddSHONG Yifan        build_env_files = build_env_files,
138*d4726bddSHONG Yifan        build_flags_files = build_flags_files,
139*d4726bddSHONG Yifan        emit = ["dep-info", "metadata"],
140*d4726bddSHONG Yifan        skip_expanding_rustc_env = True,
141*d4726bddSHONG Yifan    )
142*d4726bddSHONG Yifan
143*d4726bddSHONG Yifan    if crate_info.is_test:
144*d4726bddSHONG Yifan        args.rustc_flags.add("--test")
145*d4726bddSHONG Yifan
146*d4726bddSHONG Yifan    clippy_flags = ctx.attr._clippy_flags[ClippyFlagsInfo].clippy_flags
147*d4726bddSHONG Yifan
148*d4726bddSHONG Yifan    if hasattr(ctx.attr, "_clippy_flag"):
149*d4726bddSHONG Yifan        clippy_flags = clippy_flags + ctx.attr._clippy_flag[ClippyFlagsInfo].clippy_flags
150*d4726bddSHONG Yifan
151*d4726bddSHONG Yifan    # For remote execution purposes, the clippy_out file must be a sibling of crate_info.output
152*d4726bddSHONG Yifan    # or rustc may fail to create intermediate output files because the directory does not exist.
153*d4726bddSHONG Yifan    if ctx.attr._capture_output[CaptureClippyOutputInfo].capture_output:
154*d4726bddSHONG Yifan        clippy_out = ctx.actions.declare_file(ctx.label.name + ".clippy.out", sibling = crate_info.output)
155*d4726bddSHONG Yifan        args.process_wrapper_flags.add("--stderr-file", clippy_out)
156*d4726bddSHONG Yifan
157*d4726bddSHONG Yifan        if clippy_flags:
158*d4726bddSHONG Yifan            args.rustc_flags.add_all(clippy_flags)
159*d4726bddSHONG Yifan
160*d4726bddSHONG Yifan        # If we are capturing the output, we want the build system to be able to keep going
161*d4726bddSHONG Yifan        # and consume the output. Some clippy lints are denials, so we cap everything at warn.
162*d4726bddSHONG Yifan        args.rustc_flags.add("--cap-lints=warn")
163*d4726bddSHONG Yifan    else:
164*d4726bddSHONG Yifan        # A marker file indicating clippy has executed successfully.
165*d4726bddSHONG Yifan        # This file is necessary because "ctx.actions.run" mandates an output.
166*d4726bddSHONG Yifan        clippy_out = ctx.actions.declare_file(ctx.label.name + ".clippy.ok", sibling = crate_info.output)
167*d4726bddSHONG Yifan        args.process_wrapper_flags.add("--touch-file", clippy_out)
168*d4726bddSHONG Yifan
169*d4726bddSHONG Yifan        if clippy_flags:
170*d4726bddSHONG Yifan            args.rustc_flags.add_all(clippy_flags)
171*d4726bddSHONG Yifan        else:
172*d4726bddSHONG Yifan            # The user didn't provide any clippy flags explicitly so we apply conservative defaults.
173*d4726bddSHONG Yifan
174*d4726bddSHONG Yifan            # Turn any warnings from clippy or rustc into an error, as otherwise
175*d4726bddSHONG Yifan            # Bazel will consider the execution result of the aspect to be "success",
176*d4726bddSHONG Yifan            # and Clippy won't be re-triggered unless the source file is modified.
177*d4726bddSHONG Yifan            args.rustc_flags.add("-Dwarnings")
178*d4726bddSHONG Yifan
179*d4726bddSHONG Yifan    # Upstream clippy requires one of these two filenames or it silently uses
180*d4726bddSHONG Yifan    # the default config. Enforce the naming so users are not confused.
181*d4726bddSHONG Yifan    valid_config_file_names = [".clippy.toml", "clippy.toml"]
182*d4726bddSHONG Yifan    if ctx.file._config.basename not in valid_config_file_names:
183*d4726bddSHONG Yifan        fail("The clippy config file must be named one of: {}".format(valid_config_file_names))
184*d4726bddSHONG Yifan    env["CLIPPY_CONF_DIR"] = "${{pwd}}/{}".format(ctx.file._config.dirname)
185*d4726bddSHONG Yifan    compile_inputs = depset([ctx.file._config], transitive = [compile_inputs])
186*d4726bddSHONG Yifan
187*d4726bddSHONG Yifan    ctx.actions.run(
188*d4726bddSHONG Yifan        executable = ctx.executable._process_wrapper,
189*d4726bddSHONG Yifan        inputs = compile_inputs,
190*d4726bddSHONG Yifan        outputs = [clippy_out],
191*d4726bddSHONG Yifan        env = env,
192*d4726bddSHONG Yifan        tools = [toolchain.clippy_driver],
193*d4726bddSHONG Yifan        arguments = args.all,
194*d4726bddSHONG Yifan        mnemonic = "Clippy",
195*d4726bddSHONG Yifan        toolchain = "@rules_rust//rust:toolchain_type",
196*d4726bddSHONG Yifan    )
197*d4726bddSHONG Yifan
198*d4726bddSHONG Yifan    return [
199*d4726bddSHONG Yifan        OutputGroupInfo(clippy_checks = depset([clippy_out])),
200*d4726bddSHONG Yifan        ClippyInfo(output = depset([clippy_out])),
201*d4726bddSHONG Yifan    ]
202*d4726bddSHONG Yifan
203*d4726bddSHONG Yifan# Example: Run the clippy checker on all targets in the codebase.
204*d4726bddSHONG Yifan#   bazel build --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect \
205*d4726bddSHONG Yifan#               --output_groups=clippy_checks \
206*d4726bddSHONG Yifan#               //...
207*d4726bddSHONG Yifanrust_clippy_aspect = aspect(
208*d4726bddSHONG Yifan    fragments = ["cpp"],
209*d4726bddSHONG Yifan    attrs = {
210*d4726bddSHONG Yifan        "_capture_output": attr.label(
211*d4726bddSHONG Yifan            doc = "Value of the `capture_clippy_output` build setting",
212*d4726bddSHONG Yifan            default = Label("//:capture_clippy_output"),
213*d4726bddSHONG Yifan        ),
214*d4726bddSHONG Yifan        "_cc_toolchain": attr.label(
215*d4726bddSHONG Yifan            doc = (
216*d4726bddSHONG Yifan                "Required attribute to access the cc_toolchain. See [Accessing the C++ toolchain]" +
217*d4726bddSHONG Yifan                "(https://docs.bazel.build/versions/master/integrating-with-rules-cc.html#accessing-the-c-toolchain)"
218*d4726bddSHONG Yifan            ),
219*d4726bddSHONG Yifan            default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
220*d4726bddSHONG Yifan        ),
221*d4726bddSHONG Yifan        "_clippy_flag": attr.label(
222*d4726bddSHONG Yifan            doc = "Arguments to pass to clippy." +
223*d4726bddSHONG Yifan                  "Multiple uses are accumulated and appended after the extra_rustc_flags.",
224*d4726bddSHONG Yifan            default = Label("//:clippy_flag"),
225*d4726bddSHONG Yifan        ),
226*d4726bddSHONG Yifan        "_clippy_flags": attr.label(
227*d4726bddSHONG Yifan            doc = "Arguments to pass to clippy",
228*d4726bddSHONG Yifan            default = Label("//:clippy_flags"),
229*d4726bddSHONG Yifan        ),
230*d4726bddSHONG Yifan        "_config": attr.label(
231*d4726bddSHONG Yifan            doc = "The `clippy.toml` file used for configuration",
232*d4726bddSHONG Yifan            allow_single_file = True,
233*d4726bddSHONG Yifan            default = Label("//:clippy.toml"),
234*d4726bddSHONG Yifan        ),
235*d4726bddSHONG Yifan        "_error_format": attr.label(
236*d4726bddSHONG Yifan            doc = "The desired `--error-format` flags for clippy",
237*d4726bddSHONG Yifan            default = "//:error_format",
238*d4726bddSHONG Yifan        ),
239*d4726bddSHONG Yifan        "_extra_rustc_flag": attr.label(
240*d4726bddSHONG Yifan            default = Label("//:extra_rustc_flag"),
241*d4726bddSHONG Yifan        ),
242*d4726bddSHONG Yifan        "_per_crate_rustc_flag": attr.label(
243*d4726bddSHONG Yifan            default = Label("//:experimental_per_crate_rustc_flag"),
244*d4726bddSHONG Yifan        ),
245*d4726bddSHONG Yifan        "_process_wrapper": attr.label(
246*d4726bddSHONG Yifan            doc = "A process wrapper for running clippy on all platforms",
247*d4726bddSHONG Yifan            default = Label("//util/process_wrapper"),
248*d4726bddSHONG Yifan            executable = True,
249*d4726bddSHONG Yifan            cfg = "exec",
250*d4726bddSHONG Yifan        ),
251*d4726bddSHONG Yifan    },
252*d4726bddSHONG Yifan    provides = [ClippyInfo],
253*d4726bddSHONG Yifan    required_providers = [
254*d4726bddSHONG Yifan        [rust_common.crate_info],
255*d4726bddSHONG Yifan        [rust_common.test_crate_info],
256*d4726bddSHONG Yifan    ],
257*d4726bddSHONG Yifan    toolchains = [
258*d4726bddSHONG Yifan        str(Label("//rust:toolchain_type")),
259*d4726bddSHONG Yifan        "@bazel_tools//tools/cpp:toolchain_type",
260*d4726bddSHONG Yifan    ],
261*d4726bddSHONG Yifan    implementation = _clippy_aspect_impl,
262*d4726bddSHONG Yifan    doc = """\
263*d4726bddSHONG YifanExecutes the clippy checker on specified targets.
264*d4726bddSHONG Yifan
265*d4726bddSHONG YifanThis aspect applies to existing rust_library, rust_test, and rust_binary rules.
266*d4726bddSHONG Yifan
267*d4726bddSHONG YifanAs an example, if the following is defined in `examples/hello_lib/BUILD.bazel`:
268*d4726bddSHONG Yifan
269*d4726bddSHONG Yifan```python
270*d4726bddSHONG Yifanload("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
271*d4726bddSHONG Yifan
272*d4726bddSHONG Yifanrust_library(
273*d4726bddSHONG Yifan    name = "hello_lib",
274*d4726bddSHONG Yifan    srcs = ["src/lib.rs"],
275*d4726bddSHONG Yifan)
276*d4726bddSHONG Yifan
277*d4726bddSHONG Yifanrust_test(
278*d4726bddSHONG Yifan    name = "greeting_test",
279*d4726bddSHONG Yifan    srcs = ["tests/greeting.rs"],
280*d4726bddSHONG Yifan    deps = [":hello_lib"],
281*d4726bddSHONG Yifan)
282*d4726bddSHONG Yifan```
283*d4726bddSHONG Yifan
284*d4726bddSHONG YifanThen the targets can be analyzed with clippy using the following command:
285*d4726bddSHONG Yifan
286*d4726bddSHONG Yifan```output
287*d4726bddSHONG Yifan$ bazel build --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect \
288*d4726bddSHONG Yifan              --output_groups=clippy_checks //hello_lib:all
289*d4726bddSHONG Yifan```
290*d4726bddSHONG Yifan""",
291*d4726bddSHONG Yifan)
292*d4726bddSHONG Yifan
293*d4726bddSHONG Yifandef _rust_clippy_rule_impl(ctx):
294*d4726bddSHONG Yifan    clippy_ready_targets = [dep for dep in ctx.attr.deps if "clippy_checks" in dir(dep[OutputGroupInfo])]
295*d4726bddSHONG Yifan    files = depset([], transitive = [dep[OutputGroupInfo].clippy_checks for dep in clippy_ready_targets])
296*d4726bddSHONG Yifan    return [DefaultInfo(files = files)]
297*d4726bddSHONG Yifan
298*d4726bddSHONG Yifanrust_clippy = rule(
299*d4726bddSHONG Yifan    implementation = _rust_clippy_rule_impl,
300*d4726bddSHONG Yifan    attrs = {
301*d4726bddSHONG Yifan        "deps": attr.label_list(
302*d4726bddSHONG Yifan            doc = "Rust targets to run clippy on.",
303*d4726bddSHONG Yifan            providers = [
304*d4726bddSHONG Yifan                [rust_common.crate_info],
305*d4726bddSHONG Yifan                [rust_common.test_crate_info],
306*d4726bddSHONG Yifan            ],
307*d4726bddSHONG Yifan            aspects = [rust_clippy_aspect],
308*d4726bddSHONG Yifan        ),
309*d4726bddSHONG Yifan    },
310*d4726bddSHONG Yifan    doc = """\
311*d4726bddSHONG YifanExecutes the clippy checker on a specific target.
312*d4726bddSHONG Yifan
313*d4726bddSHONG YifanSimilar to `rust_clippy_aspect`, but allows specifying a list of dependencies \
314*d4726bddSHONG Yifanwithin the build system.
315*d4726bddSHONG Yifan
316*d4726bddSHONG YifanFor example, given the following example targets:
317*d4726bddSHONG Yifan
318*d4726bddSHONG Yifan```python
319*d4726bddSHONG Yifanload("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
320*d4726bddSHONG Yifan
321*d4726bddSHONG Yifanrust_library(
322*d4726bddSHONG Yifan    name = "hello_lib",
323*d4726bddSHONG Yifan    srcs = ["src/lib.rs"],
324*d4726bddSHONG Yifan)
325*d4726bddSHONG Yifan
326*d4726bddSHONG Yifanrust_test(
327*d4726bddSHONG Yifan    name = "greeting_test",
328*d4726bddSHONG Yifan    srcs = ["tests/greeting.rs"],
329*d4726bddSHONG Yifan    deps = [":hello_lib"],
330*d4726bddSHONG Yifan)
331*d4726bddSHONG Yifan```
332*d4726bddSHONG Yifan
333*d4726bddSHONG YifanRust clippy can be set as a build target with the following:
334*d4726bddSHONG Yifan
335*d4726bddSHONG Yifan```python
336*d4726bddSHONG Yifanload("@rules_rust//rust:defs.bzl", "rust_clippy")
337*d4726bddSHONG Yifan
338*d4726bddSHONG Yifanrust_clippy(
339*d4726bddSHONG Yifan    name = "hello_library_clippy",
340*d4726bddSHONG Yifan    testonly = True,
341*d4726bddSHONG Yifan    deps = [
342*d4726bddSHONG Yifan        ":hello_lib",
343*d4726bddSHONG Yifan        ":greeting_test",
344*d4726bddSHONG Yifan    ],
345*d4726bddSHONG Yifan)
346*d4726bddSHONG Yifan```
347*d4726bddSHONG Yifan""",
348*d4726bddSHONG Yifan)
349*d4726bddSHONG Yifan
350*d4726bddSHONG Yifandef _capture_clippy_output_impl(ctx):
351*d4726bddSHONG Yifan    """Implementation of the `capture_clippy_output` rule
352*d4726bddSHONG Yifan
353*d4726bddSHONG Yifan    Args:
354*d4726bddSHONG Yifan        ctx (ctx): The rule's context object
355*d4726bddSHONG Yifan
356*d4726bddSHONG Yifan    Returns:
357*d4726bddSHONG Yifan        list: A list containing the CaptureClippyOutputInfo provider
358*d4726bddSHONG Yifan    """
359*d4726bddSHONG Yifan    return [CaptureClippyOutputInfo(capture_output = ctx.build_setting_value)]
360*d4726bddSHONG Yifan
361*d4726bddSHONG Yifancapture_clippy_output = rule(
362*d4726bddSHONG Yifan    doc = "Control whether to print clippy output or store it to a file, using the configured error_format.",
363*d4726bddSHONG Yifan    implementation = _capture_clippy_output_impl,
364*d4726bddSHONG Yifan    build_setting = config.bool(flag = True),
365*d4726bddSHONG Yifan)
366