From 1b7e069f276380bb054a24c910bef36c3308a961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= Date: Mon, 7 Oct 2024 19:22:44 -0400 Subject: [PATCH] [clang-tidy] New option to remove arguments from the command line When using clang-tidy from a compilation database, some options might not be recognized by clang if the compilation database was generated for another compiler. This forces the user to add conditional code in their CMakeLists.txt to remove those arguments when using clang-tidy. A new option was added to the .clang-tidy config to remove those unknown flags without the need to generate a second compilation_commands.json Fixes #108455 --- clang-tools-extra/clang-tidy/ClangTidy.cpp | 18 ++++++++++++++++++ .../clang-tidy/ClangTidyOptions.cpp | 3 +++ .../clang-tidy/ClangTidyOptions.h | 5 ++++- .../clang-tidy/tool/ClangTidyMain.cpp | 14 ++++++++++++++ .../clang-tidy/tool/clang-tidy-diff.py | 9 +++++++++ .../clang-tidy/tool/run-clang-tidy.py | 12 ++++++++++++ clang-tools-extra/docs/ReleaseNotes.rst | 5 +++++ clang-tools-extra/docs/clang-tidy/index.rst | 1 + .../infrastructure/invalid-command-line.cpp | 2 +- .../clang-tidy/infrastructure/removed-args.cpp | 8 ++++++++ 10 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/infrastructure/removed-args.cpp diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 870f5169cf7c7..5ea6c78a16e59 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -586,6 +586,24 @@ runClangTidy(clang::tidy::ClangTidyContext &Context, return AdjustedArgs; }; + // Remove unwanted arguments passed to the compiler + ArgumentsAdjuster PerFileArgumentRemover = + [&Context](const CommandLineArguments &Args, StringRef Filename) { + ClangTidyOptions Opts = Context.getOptionsForFile(Filename); + CommandLineArguments AdjustedArgs = Args; + + if (Opts.RemovedArgs) { + for (StringRef ArgToRemove : *Opts.RemovedArgs) { + AdjustedArgs.erase(std::remove(AdjustedArgs.begin(), + AdjustedArgs.end(), ArgToRemove), + AdjustedArgs.end()); + } + } + + return AdjustedArgs; + }; + + Tool.appendArgumentsAdjuster(PerFileArgumentRemover); Tool.appendArgumentsAdjuster(PerFileExtraArgumentsInserter); Tool.appendArgumentsAdjuster(getStripPluginsAdjuster()); Context.setEnableProfiling(EnableCheckProfile); diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index 550f7809d75f9..bf48824c65c4b 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -230,6 +230,7 @@ template <> struct MappingTraits { IO.mapOptional("CheckOptions", Options.CheckOptions); IO.mapOptional("ExtraArgs", Options.ExtraArgs); IO.mapOptional("ExtraArgsBefore", Options.ExtraArgsBefore); + IO.mapOptional("RemovedArgs", Options.RemovedArgs); IO.mapOptional("InheritParentConfig", Options.InheritParentConfig); IO.mapOptional("UseColor", Options.UseColor); IO.mapOptional("SystemHeaders", Options.SystemHeaders); @@ -252,6 +253,7 @@ ClangTidyOptions ClangTidyOptions::getDefaults() { Options.SystemHeaders = false; Options.FormatStyle = "none"; Options.User = std::nullopt; + Options.RemovedArgs = std::nullopt; for (const ClangTidyModuleRegistry::entry &Module : ClangTidyModuleRegistry::entries()) Options.mergeWith(Module.instantiate()->getModuleOptions(), 0); @@ -295,6 +297,7 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other, overrideValue(UseColor, Other.UseColor); mergeVectors(ExtraArgs, Other.ExtraArgs); mergeVectors(ExtraArgsBefore, Other.ExtraArgsBefore); + mergeVectors(RemovedArgs, Other.RemovedArgs); // FIXME: how to handle duplicate names check? mergeVectors(CustomChecks, Other.CustomChecks); for (const auto &KeyValue : Other.CheckOptions) { diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h index 4c97c5ba801f0..97daed448063b 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h @@ -85,7 +85,7 @@ struct ClangTidyOptions { /// main files will always be displayed. std::optional HeaderFilterRegex; - /// \brief Exclude warnings from headers matching this filter, even if they + /// Exclude warnings from headers matching this filter, even if they /// match \c HeaderFilterRegex. std::optional ExcludeHeaderFilterRegex; @@ -151,6 +151,9 @@ struct ClangTidyOptions { /// Add extra compilation arguments to the start of the list. std::optional ExtraArgsBefore; + /// Remove command line arguments sent to the compiler matching this. + std::optional RemovedArgs; + /// Only used in the FileOptionsProvider and ConfigOptionsProvider. If true /// and using a FileOptionsProvider, it will take a configuration file in the /// parent directory (if any exists) and apply this config file on top of the diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index f5e4bf020bd68..87c1fc4959859 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -18,6 +18,7 @@ #include "../ClangTidy.h" #include "../ClangTidyForceLinker.h" #include "../GlobList.h" +#include "../utils/OptionsUtils.h" #include "clang/Tooling/CommonOptionsParser.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/CommandLine.h" @@ -77,6 +78,7 @@ Configuration files: (if any exists) will be taken and the current config file will be applied on top of the parent one. + RemovedArgs - Same as '--removed-arg'. SystemHeaders - Same as '--system-headers'. UseColor - Same as '--use-color'. User - Specifies the name or e-mail of the user @@ -357,6 +359,16 @@ see https://clang.llvm.org/extra/clang-tidy/QueryBasedCustomChecks.html. cl::init(false), cl::cat(ClangTidyCategory)); +static cl::list RemovedArgs("removed-arg", desc(R"( +List of arguments to remove from the command +line sent to the compiler. Please note that +removing arguments might change the semantic +of the analzed code, possibly leading to +compiler errors, false positives or +false negatives. This option is applied +before --extra-arg and --extra-arg-before)"), + cl::cat(ClangTidyCategory)); + namespace clang::tidy { static void printStats(const ClangTidyStats &Stats) { @@ -423,6 +435,8 @@ createOptionsProvider(llvm::IntrusiveRefCntPtr FS) { OverrideOptions.FormatStyle = FormatStyle; if (UseColor.getNumOccurrences() > 0) OverrideOptions.UseColor = UseColor; + if (RemovedArgs.getNumOccurrences() > 0) + OverrideOptions.RemovedArgs = RemovedArgs; auto LoadConfig = [&](StringRef Configuration, diff --git a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py index 5daa93dca2a99..c090bdc1151df 100755 --- a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py +++ b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py @@ -228,6 +228,13 @@ def main(): default=[], help="Additional argument to prepend to the compiler " "command line.", ) + parser.add_argument( + "-removed-arg", + dest="removed_arg", + action="append", + default=[], + help="Arguments to remove from the compiler command line.", + ) parser.add_argument( "-quiet", action="store_true", @@ -378,6 +385,8 @@ def main(): common_clang_tidy_args.append("-extra-arg=%s" % arg) for arg in args.extra_arg_before: common_clang_tidy_args.append("-extra-arg-before=%s" % arg) + for arg in args.removed_arg: + common_clang_tidy_args.append("-removed-arg=%s" % arg) for plugin in args.plugins: common_clang_tidy_args.append("-load=%s" % plugin) if args.warnings_as_errors: diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py index f495f449b5b30..59523fd131185 100755 --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -96,6 +96,7 @@ def get_tidy_invocation( allow_enabling_alpha_checkers: bool, extra_arg: List[str], extra_arg_before: List[str], + removed_arg: List[str], quiet: bool, config_file_path: str, config: str, @@ -135,6 +136,8 @@ def get_tidy_invocation( start.append(f"-extra-arg={arg}") for arg in extra_arg_before: start.append(f"-extra-arg-before={arg}") + for arg in removed_arg: + start.append(f"-removed-arg={arg}") start.append(f"-p={build_path}") if quiet: start.append("-quiet") @@ -377,6 +380,7 @@ async def run_tidy( args.allow_enabling_alpha_checkers, args.extra_arg, args.extra_arg_before, + args.removed_arg, args.quiet, args.config_file, args.config, @@ -551,6 +555,13 @@ async def main() -> None: default=[], help="Additional argument to prepend to the compiler command line.", ) + parser.add_argument( + "-removed-arg", + dest="removed_arg", + action="append", + default=[], + help="Arguments to remove from the compiler command line.", + ) parser.add_argument( "-quiet", action="store_true", help="Run clang-tidy in quiet mode." ) @@ -638,6 +649,7 @@ async def main() -> None: args.allow_enabling_alpha_checkers, args.extra_arg, args.extra_arg_before, + args.removed_arg, args.quiet, args.config_file, args.config, diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 666865cfb2fcd..876f900ef341c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -177,6 +177,11 @@ Improvements to clang-tidy scripts by adding the `-hide-progress` option to suppress progress and informational messages. +- Improved :program:`clang-tidy` by adding the `--removed-arg` option to remove + arguments sent to the compiler when invoking Clang-Tidy. This option was also + added to :program:`run-clang-tidy.py` and :program:`clang-tidy-diff.py` and + can be configured in the config file through the `RemovedArgs` option. + - Deprecated the :program:`clang-tidy` ``zircon`` module. All checks have been moved to the ``fuchsia`` module instead. The ``zircon`` module will be removed in the 24th release. diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst index 6ff82bf230f4b..8dcab354161d8 100644 --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -331,6 +331,7 @@ An overview of all the command-line options: example, to place the correct user name in TODO() comments in the relevant check. WarningsAsErrors - Same as '--warnings-as-errors'. + RemovedArgs - Same as '--removed-arg' The effective configuration can be inspected using --dump-config: diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/invalid-command-line.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/invalid-command-line.cpp index 4bdca50af32ca..80540411e53e3 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/invalid-command-line.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/invalid-command-line.cpp @@ -1,4 +1,4 @@ // RUN: not clang-tidy --invalid-arg 2>&1 | FileCheck %s // CHECK: error: clang-tidy{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-tidy{{(\.exe)?}} --help' -// CHECK-NEXT: clang-tidy{{(\.exe)?}}: Did you mean '--extra-arg'? +// CHECK-NEXT: clang-tidy{{(\.exe)?}}: Did you mean '--removed-arg'? diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/removed-args.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/removed-args.cpp new file mode 100644 index 0000000000000..dd97b45dda1bb --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/removed-args.cpp @@ -0,0 +1,8 @@ +// RUN: not clang-tidy %s -- -fnot-an-option | FileCheck %s -check-prefix=INVALID-A +// RUN: clang-tidy %s --config="{RemovedArgs: ['-fnot-an-option']}" -- -fnot-an-option +// RUN: clang-tidy %s --config="{RemovedArgs: ['-fnot-another-option', '-fnot-an-option']}" -- -fnot-an-option -fnot-another-option +// RUN: clang-tidy %s --removed-arg="-fnot-an-option" -- -fnot-an-option +// RUN: not clang-tidy %s --removed-arg="-fnot-an-option" -- -fnot-an-option -fnot-another-option | FileCheck %s -check-prefix=INVALID-B + +// INVALID-A: error: unknown argument: '-fnot-an-option' [clang-diagnostic-error] +// INVALID-B: error: unknown argument: '-fnot-another-option' [clang-diagnostic-error]