diff --git a/docs/clang-tidy.md b/docs/clang-tidy.md index 7dec2f58..e922154b 100644 --- a/docs/clang-tidy.md +++ b/docs/clang-tidy.md @@ -45,7 +45,7 @@ clang_tidy = lint_clang_tidy_aspect(
load("@aspect_rules_lint//lint:clang_tidy.bzl", "clang_tidy_action")
-clang_tidy_action(ctx, compilation_context, executable, srcs, stdout, exit_code)
+clang_tidy_action(ctx, compilation_context, executable, src, stdout, exit_code)
Create a Bazel Action that spawns a clang-tidy process.
@@ -62,7 +62,7 @@ https://clang.llvm.org/extra/clang-tidy/
| ctx | an action context OR aspect context | none |
| compilation_context | from target | none |
| executable | struct with a clang-tidy field | none |
-| srcs | file objects to lint | none |
+| src | file object to lint | none |
| stdout | output file containing the stdout or --output-file of clang-tidy | none |
| exit_code | output file containing the exit code of clang-tidy. If None, then fail the build when clang-tidy exits non-zero. | none |
@@ -74,7 +74,7 @@ https://clang.llvm.org/extra/clang-tidy/
load("@aspect_rules_lint//lint:clang_tidy.bzl", "clang_tidy_fix")
-clang_tidy_fix(ctx, compilation_context, executable, srcs, patch, stdout, exit_code)
+clang_tidy_fix(ctx, compilation_context, executable, src, patch, stdout, exit_code)
Create a Bazel Action that spawns clang-tidy with --fix.
@@ -87,7 +87,7 @@ Create a Bazel Action that spawns clang-tidy with --fix.
| ctx | an action context OR aspect context | none |
| compilation_context | from target | none |
| executable | struct with a clang_tidy field | none |
-| srcs | list of file objects to lint | none |
+| src | file object to lint | none |
| patch | output file containing the applied fixes that can be applied with the patch(1) command. | none |
| stdout | output file containing the stdout or --output-file of clang-tidy | none |
| exit_code | output file containing the exit code of clang-tidy | none |
diff --git a/lint/clang_tidy.bzl b/lint/clang_tidy.bzl
index 5538f1d7..8976f0e6 100644
--- a/lint/clang_tidy.bzl
+++ b/lint/clang_tidy.bzl
@@ -46,8 +46,8 @@ _DISABLED_FEATURES = [
"layering_check",
]
-def _gather_inputs(ctx, compilation_context, srcs):
- inputs = srcs + ctx.files._configs
+def _gather_inputs(ctx, compilation_context, src):
+ inputs = [src] + ctx.files._configs
if (any(ctx.files._global_config)):
inputs.append(ctx.files._global_config[0])
return depset(inputs, transitive = [compilation_context.headers])
@@ -229,8 +229,8 @@ def _aggregate_regex(ctx, compilation_context):
def _quoted_arg(arg):
return "\"" + arg + "\""
-def _get_env(ctx, srcs):
- sources_are_cxx = _is_cxx(srcs[0])
+def _get_env(ctx, src):
+ sources_are_cxx = _is_cxx(src)
if (sources_are_cxx):
user_flags = ctx.fragments.cpp.cxxopts + ctx.fragments.cpp.copts
env = _toolchain_env(ctx, user_flags, ACTION_NAMES.cpp_compile)
@@ -245,7 +245,7 @@ def _get_env(ctx, srcs):
env["MSYS_ARG_CONV_EXCL"] = "*"
return env
-def _get_args(ctx, compilation_context, srcs):
+def _get_args(ctx, compilation_context, src):
args = []
if (any(ctx.files._global_config)):
args.append("--config-file=" + ctx.files._global_config[0].short_path)
@@ -256,15 +256,15 @@ def _get_args(ctx, compilation_context, srcs):
elif (ctx.attr._header_filter):
regex = ctx.attr._header_filter
args.append(_quoted_arg("-header-filter=" + regex))
- args.extend([src.short_path for src in srcs])
+ args.append(src.short_path)
return args
-def _get_compiler_args(ctx, compilation_context, srcs):
+def _get_compiler_args(ctx, compilation_context, src):
# add args specified by the toolchain, on the command line and rule copts
args = []
rule_flags = ctx.rule.attr.copts if hasattr(ctx.rule.attr, "copts") else []
- sources_are_cxx = _is_cxx(srcs[0])
- if (sources_are_cxx):
+ source_is_cxx = _is_cxx(src)
+ if (source_is_cxx):
user_flags = ctx.fragments.cpp.cxxopts + ctx.fragments.cpp.copts
args.extend(_safe_flags(ctx, _toolchain_flags(ctx, user_flags, ACTION_NAMES.cpp_compile) + rule_flags) + ["-xc++"])
else:
@@ -291,7 +291,7 @@ def _get_compiler_args(ctx, compilation_context, srcs):
args.extend(_prefixed(compilation_context.external_includes.to_list(), "-isystem"))
return args
-def clang_tidy_action(ctx, compilation_context, executable, srcs, stdout, exit_code):
+def clang_tidy_action(ctx, compilation_context, executable, src, stdout, exit_code):
"""Create a Bazel Action that spawns a clang-tidy process.
Adapter for wrapping Bazel around
@@ -301,14 +301,14 @@ def clang_tidy_action(ctx, compilation_context, executable, srcs, stdout, exit_c
ctx: an action context OR aspect context
compilation_context: from target
executable: struct with a clang-tidy field
- srcs: file objects to lint
+ src: file object to lint
stdout: output file containing the stdout or --output-file of clang-tidy
exit_code: output file containing the exit code of clang-tidy.
If None, then fail the build when clang-tidy exits non-zero.
"""
outputs = [stdout]
- env = _get_env(ctx, srcs)
+ env = _get_env(ctx, src)
env["CLANG_TIDY__STDOUT_STDERR_OUTPUT_FILE"] = stdout.path
if exit_code:
@@ -317,51 +317,53 @@ def clang_tidy_action(ctx, compilation_context, executable, srcs, stdout, exit_c
# pass compiler args via a params file. The command line may already be long due to
# sources, which can't go the params file, so materialize it always.
- clang_tidy_args = _get_args(ctx, compilation_context, srcs)
+ clang_tidy_args = _get_args(ctx, compilation_context, src)
compiler_args = ctx.actions.args()
- compiler_args.add_all(_get_compiler_args(ctx, compilation_context, srcs))
+ compiler_args.add_all(_get_compiler_args(ctx, compilation_context, src))
compiler_args.use_param_file("--config %s", use_always = True)
+ progress_message_identifier = src.short_path
+
ctx.actions.run_shell(
- inputs = _gather_inputs(ctx, compilation_context, srcs),
+ inputs = depset([src], transitive = [_gather_inputs(ctx, compilation_context, src), find_cpp_toolchain(ctx).all_files]),
outputs = outputs,
- tools = [executable._clang_tidy_wrapper, executable._clang_tidy, find_cpp_toolchain(ctx).all_files],
+ tools = [executable._clang_tidy_wrapper, executable._clang_tidy],
command = executable._clang_tidy_wrapper.path + " $@",
arguments = [executable._clang_tidy.path] + clang_tidy_args + ["--", compiler_args],
env = env,
mnemonic = _MNEMONIC,
- progress_message = "Linting %{label} with clang-tidy",
+ progress_message = "Linting {} with clang-tidy".format(progress_message_identifier),
)
-def clang_tidy_fix(ctx, compilation_context, executable, srcs, patch, stdout, exit_code):
+def clang_tidy_fix(ctx, compilation_context, executable, src, patch, stdout, exit_code):
"""Create a Bazel Action that spawns clang-tidy with --fix.
Args:
ctx: an action context OR aspect context
compilation_context: from target
executable: struct with a clang_tidy field
- srcs: list of file objects to lint
+ src: file object to lint
patch: output file containing the applied fixes that can be applied with the patch(1) command.
stdout: output file containing the stdout or --output-file of clang-tidy
exit_code: output file containing the exit code of clang-tidy
"""
- patch_cfg = ctx.actions.declare_file("_{}.patch_cfg".format(ctx.label.name))
- clang_tidy_args = _get_args(ctx, compilation_context, srcs)
- compiler_args = _get_compiler_args(ctx, compilation_context, srcs)
+ patch_cfg = ctx.actions.declare_file("_{}.patch_cfg".format(src.short_path))
+ clang_tidy_args = _get_args(ctx, compilation_context, [src])
+ compiler_args = _get_compiler_args(ctx, compilation_context, [src])
ctx.actions.write(
output = patch_cfg,
content = json.encode({
"linter": executable._clang_tidy_wrapper.path,
"args": [executable._clang_tidy.path, "--fix"] + clang_tidy_args + ["--"] + compiler_args,
- "env": _get_env(ctx, srcs),
- "files_to_diff": [src.path for src in srcs],
+ "env": _get_env(ctx, [src]),
+ "files_to_diff": [src.path],
"output": patch.path,
}),
)
ctx.actions.run(
- inputs = depset([patch_cfg], transitive = [_gather_inputs(ctx, compilation_context, srcs)]),
+ inputs = depset([patch_cfg], transitive = [_gather_inputs(ctx, compilation_context, [src])]),
outputs = [patch, stdout, exit_code],
executable = executable._patcher,
arguments = [patch_cfg.path],
@@ -373,7 +375,7 @@ def clang_tidy_fix(ctx, compilation_context, executable, srcs, patch, stdout, ex
},
tools = [executable._clang_tidy_wrapper, executable._clang_tidy, find_cpp_toolchain(ctx).all_files],
mnemonic = _MNEMONIC,
- progress_message = "Linting %{label} with clang-tidy",
+ progress_message = "Linting {} with clang-tidy".format(src.short_path),
)
# buildifier: disable=function-docstring
@@ -389,25 +391,36 @@ def _clang_tidy_aspect_impl(target, ctx):
[implementation_dep[CcInfo].compilation_context for implementation_dep in ctx.rule.attr.implementation_deps],
)
- if ctx.attr._options[LintOptionsInfo].fix:
- outputs, info = patch_and_output_files(_MNEMONIC, target, ctx)
- else:
- outputs, info = output_files(_MNEMONIC, target, ctx)
-
if len(files_to_lint) == 0:
+ if ctx.attr._options[LintOptionsInfo].fix:
+ outputs, info = patch_and_output_files(_MNEMONIC, target, ctx)
+ else:
+ outputs, info = output_files(_MNEMONIC, target, ctx)
+
noop_lint_action(ctx, outputs)
return [info]
- if hasattr(outputs, "patch"):
- clang_tidy_fix(ctx, compilation_context, ctx.executable, files_to_lint, outputs.patch, outputs.human.out, outputs.human.exit_code)
- else:
- clang_tidy_action(ctx, compilation_context, ctx.executable, files_to_lint, outputs.human.out, outputs.human.exit_code)
+ infos = []
+ for file in files_to_lint:
+ if ctx.attr._options[LintOptionsInfo].fix:
+ outputs, info = patch_and_output_files(_MNEMONIC, file, ctx)
+ else:
+ outputs, info = output_files(_MNEMONIC, file, ctx)
+
+ infos.append(info)
+
+ if hasattr(outputs, "patch"):
+ clang_tidy_fix(ctx, compilation_context, ctx.executable, file, outputs.patch, outputs.human.out, outputs.human.exit_code)
+ else:
+ clang_tidy_action(ctx, compilation_context, ctx.executable, file, outputs.human.out, outputs.human.exit_code)
+
+ # TODO(alex): if we run with --fix, this will report the issues that were fixed. Does a machine reader want to know about them?
+ raw_machine_report = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = file.short_path, mnemonic = _MNEMONIC, suffix = "raw_machine_report"))
+ clang_tidy_action(ctx, compilation_context, ctx.executable, file, raw_machine_report, outputs.machine.exit_code)
+ parse_to_sarif_action(ctx, _MNEMONIC, raw_machine_report, outputs.machine.out)
+
+ return infos
- # TODO(alex): if we run with --fix, this will report the issues that were fixed. Does a machine reader want to know about them?
- raw_machine_report = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = target.label.name, mnemonic = _MNEMONIC, suffix = "raw_machine_report"))
- clang_tidy_action(ctx, compilation_context, ctx.executable, files_to_lint, raw_machine_report, outputs.machine.exit_code)
- parse_to_sarif_action(ctx, _MNEMONIC, raw_machine_report, outputs.machine.out)
- return [info]
def lint_clang_tidy_aspect(binary, configs = [], global_config = [], header_filter = "", lint_target_headers = False, angle_includes_are_system = True, verbose = False):
"""A factory function to create a linter aspect.
diff --git a/lint/private/lint_aspect.bzl b/lint/private/lint_aspect.bzl
index cce11060..878476e3 100644
--- a/lint/private/lint_aspect.bzl
+++ b/lint/private/lint_aspect.bzl
@@ -54,16 +54,21 @@ def output_files(mnemonic, target, ctx):
Args:
mnemonic: used as part of the filename
- target: the target being visited by a linter aspect
+ target: the target or file being visited by a linter aspect
ctx: the aspect context
Returns:
tuple of struct() of output files, and the OutputGroupInfo provider that the rule should return
"""
- human_out = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = target.label.name, mnemonic = mnemonic, suffix = "out"))
+ if type(target) == "File":
+ identifier = "{}.{}".format(target.short_path, ctx.label.name)
+ else:
+ identifier = target.label.name
+
+ human_out = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = identifier, mnemonic = mnemonic, suffix = "out"))
# NB: named ".report" as there are existing callers depending on that
- machine_out = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = target.label.name, mnemonic = mnemonic, suffix = "report"))
+ machine_out = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = identifier, mnemonic = mnemonic, suffix = "report"))
if ctx.attr._options[LintOptionsInfo].fail_on_violation:
# Fail on violation means the exit code is reported to Bazel as the action result
@@ -73,8 +78,8 @@ def output_files(mnemonic, target, ctx):
# The exit codes should instead be provided as action outputs so the build succeeds.
# Downstream tooling like `aspect lint` will be responsible for reading the exit codes
# and interpreting them.
- human_exit_code = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = target.label.name, mnemonic = mnemonic, suffix = "out.exit_code"))
- machine_exit_code = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = target.label.name, mnemonic = mnemonic, suffix = "report.exit_code"))
+ human_exit_code = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = identifier, mnemonic = mnemonic, suffix = "out.exit_code"))
+ machine_exit_code = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = identifier, mnemonic = mnemonic, suffix = "report.exit_code"))
human_outputs = [f for f in [human_out, human_exit_code] if f]
machine_outputs = [f for f in [machine_out, machine_exit_code] if f]
@@ -98,7 +103,12 @@ def output_files(mnemonic, target, ctx):
)
def patch_file(mnemonic, target, ctx):
- patch = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = target.label.name, mnemonic = mnemonic, suffix = "patch"))
+ if type(target) == "File":
+ identifier = "{}.{}".format(target.short_path, ctx.label.name)
+ else:
+ identifier = target.label.name
+
+ patch = ctx.actions.declare_file(OUTFILE_FORMAT.format(label = identifier, mnemonic = mnemonic, suffix = "patch"))
return patch, OutputGroupInfo(rules_lint_patch = depset([patch]))
# If we return multiple OutputGroupInfo from a rule implementation, only one will get used.