https://github.com/dzbarsky updated https://github.com/llvm/llvm-project/pull/201743
>From a62d3f9b516be935905127dc498447e41df6fd50 Mon Sep 17 00:00:00 2001 From: David Zbarsky <[email protected]> Date: Thu, 4 Jun 2026 23:38:43 -0400 Subject: [PATCH] Port clang-tidy to Opts.td and multicall --- .../clang-tidy/tool/CMakeLists.txt | 8 + .../clang-tidy/tool/ClangTidyMain.cpp | 622 +++++++++--------- .../clang-tidy/tool/ClangTidyMain.h | 2 +- .../clang-tidy/tool/ClangTidyToolMain.cpp | 3 +- clang-tools-extra/clang-tidy/tool/Opts.td | 245 +++++++ clang-tools-extra/docs/clang-tidy/index.rst | 331 +++++----- .../infrastructure/invalid-command-line.cpp | 3 +- .../clang-tools-extra/clang-tidy/BUILD.bazel | 22 +- .../llvm-project-overlay/llvm/driver.bzl | 1 + 9 files changed, 738 insertions(+), 499 deletions(-) create mode 100644 clang-tools-extra/clang-tidy/tool/Opts.td diff --git a/clang-tools-extra/clang-tidy/tool/CMakeLists.txt b/clang-tools-extra/clang-tidy/tool/CMakeLists.txt index 0d4501d1eac06..da007f49c934a 100644 --- a/clang-tools-extra/clang-tidy/tool/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/tool/CMakeLists.txt @@ -3,10 +3,15 @@ set(LLVM_LINK_COMPONENTS AllTargetsDescs AllTargetsInfos FrontendOpenMP + Option TargetParser support ) +set(LLVM_TARGET_DEFINITIONS Opts.td) +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(ClangTidyOptsTableGen) + # Needed by LLVM's CMake checks because this file defines multiple targets. set(LLVM_OPTIONAL_SOURCES ClangTidyMain.cpp ClangTidyToolMain.cpp) @@ -20,6 +25,7 @@ add_clang_library(clangTidyMain STATIC DEPENDS omp_gen ClangDriverOptions + ClangTidyOptsTableGen ) clang_target_link_libraries(clangTidyMain @@ -42,6 +48,8 @@ add_clang_tool(clang-tidy DEPENDS clang-resource-headers ${support_plugins} + + GENERATE_DRIVER ) clang_target_link_libraries(clang-tidy PRIVATE diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index 949a88f0fd50d..89ae0f497abeb 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -18,13 +18,22 @@ #include "../ClangTidy.h" #include "../ClangTidyForceLinker.h" // IWYU pragma: keep #include "../GlobList.h" +#include "clang/Basic/Version.h" #include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/InitLLVM.h" +#define DONT_GET_PLUGIN_LOADER_OPTION #include "llvm/Support/PluginLoader.h" // IWYU pragma: keep #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" #include "llvm/TargetParser/Host.h" @@ -33,17 +42,62 @@ using namespace clang::tooling; using namespace llvm; -static cl::desc desc(StringRef Description) { return {Description.ltrim()}; } - -static cl::OptionCategory ClangTidyCategory("clang-tidy options"); - -static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage); -static cl::extrahelp ClangTidyParameterFileHelp(R"( +namespace { +using namespace llvm::opt; + +enum ID { + OPT_INVALID = 0, +#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), +#include "Opts.inc" +#undef OPTION +}; + +#define OPTTABLE_STR_TABLE_CODE +#include "Opts.inc" +#undef OPTTABLE_STR_TABLE_CODE + +#define OPTTABLE_PREFIXES_TABLE_CODE +#include "Opts.inc" +#undef OPTTABLE_PREFIXES_TABLE_CODE + +static constexpr opt::OptTable::Info InfoTable[] = { +#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), +#include "Opts.inc" +#undef OPTION +}; + +class ClangTidyOptTable : public opt::GenericOptTable { +public: + ClangTidyOptTable() + : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {} +}; + +static constexpr llvm::StringLiteral CommonHelp = R"( +-p <build-path> is used to read a compile command database. + + For example, it can be a CMake build directory in which a file named + compile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + CMake option to get this output). When no build path is specified, + a search for compile_commands.json will be attempted through all + parent paths of the first input file. See: + https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an + example of setting up Clang Tooling on a source tree. + +<source0> ... specify the paths of source files. These paths are + looked up in the compile command database. If the path of a file is + absolute, it needs to point into CMake's source tree. If the path is + relative, the current working directory needs to be in the CMake + source tree and the file must be in a subdirectory of the current + working directory. "./" prefixes in the relative files will be + automatically removed, but the rest of a relative path must be a + suffix of a path in the compile command database. +)"; +static constexpr llvm::StringLiteral ClangTidyParameterFileHelp = R"( Parameters files: A large number of options or source files can be passed as parameter files by use '@parameter-file' in the command line. -)"); -static cl::extrahelp ClangTidyHelp(R"( +)"; +static constexpr llvm::StringLiteral ClangTidyHelp = R"( Configuration files: clang-tidy attempts to read configuration for each source file from a .clang-tidy file located in the closest parent directory of the source @@ -102,270 +156,221 @@ Configuration files: some-check.SomeOption: 'some value' ... -)"); +)"; const char DefaultChecks[] = // Enable these checks by default: "clang-diagnostic-*"; // * compiler diagnostics -static cl::opt<std::string> Checks("checks", desc(R"( -Comma-separated list of globs with optional '-' -prefix. Globs are processed in order of -appearance in the list. Globs without '-' -prefix add checks with matching names to the -set, globs with the '-' prefix remove checks -with matching names from the set of enabled -checks. This option's value is appended to the -value of the 'Checks' option in .clang-tidy -file, if any. -)"), - cl::init(""), cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> WarningsAsErrors("warnings-as-errors", desc(R"( -Upgrades warnings to errors. Same format as -'-checks'. -This option's value is appended to the value of -the 'WarningsAsErrors' option in .clang-tidy -file, if any. -)"), - cl::init(""), - cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> HeaderFilter("header-filter", desc(R"( -Regular expression matching the names of the -headers to output diagnostics from. The default -value is '.*', i.e. diagnostics from all non-system -headers are displayed by default. Diagnostics -from the main file of each translation unit are -always displayed. -Can be used together with -line-filter. -This option overrides the 'HeaderFilterRegex' -option in .clang-tidy file, if any. -)"), - cl::init(".*"), - cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> ExcludeHeaderFilter("exclude-header-filter", - desc(R"( -Regular expression matching the names of the -headers to exclude diagnostics from. Diagnostics -from the main file of each translation unit are -always displayed. -Must be used together with --header-filter. -Can be used together with -line-filter. -This option overrides the 'ExcludeHeaderFilterRegex' -option in .clang-tidy file, if any. -)"), - cl::init(""), - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> SystemHeaders("system-headers", desc(R"( -Display the errors from system headers. -This option overrides the 'SystemHeaders' option -in .clang-tidy file, if any. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> LineFilter("line-filter", desc(R"( -List of files and line ranges to output diagnostics from. -The range is inclusive on both ends. Can be used together -with -header-filter. The format of the list is a JSON -array of objects. For example: - - [ - {"name":"file1.cpp","lines":[[1,3],[5,7]]}, - {"name":"file2.h"} - ] - -This will output diagnostics from 'file1.cpp' only for -the line ranges [1,3] and [5,7], as well as all from the -entire 'file2.h'. -)"), - cl::init(""), - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> Fix("fix", desc(R"( -Apply suggested fixes. Without -fix-errors -clang-tidy will bail out if any compilation -errors were found. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> FixErrors("fix-errors", desc(R"( -Apply suggested fixes even if compilation -errors were found. If compiler errors have -attached fix-its, clang-tidy will apply them as -well. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> FixNotes("fix-notes", desc(R"( -If a warning has no fix, but a single fix can -be found through an associated diagnostic note, -apply the fix. -Specifying this flag will implicitly enable the -'--fix' flag. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> FormatStyle("format-style", desc(R"( -Style for formatting code around applied fixes: - - 'none' (default) turns off formatting - - 'file' (literally 'file', not a placeholder) - uses .clang-format file in the closest parent - directory - - '{ <json> }' specifies options inline, e.g. - -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' - - 'llvm', 'google', 'webkit', 'mozilla' -See clang-format documentation for the up-to-date -information about formatting styles and options. -This option overrides the 'FormatStyle` option in -.clang-tidy file, if any. -)"), - cl::init("none"), - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> ListChecks("list-checks", desc(R"( -List all enabled checks and exit. Use with --checks=* to list all available checks. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> ExplainConfig("explain-config", desc(R"( -For each enabled check explains, where it is -enabled, i.e. in clang-tidy binary, command -line or a specific configuration file. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> Config("config", desc(R"( -Specifies a configuration in YAML/JSON format: - -config="{Checks: '*', - CheckOptions: {x: y}}" -When the value is empty, clang-tidy will -attempt to find a file named .clang-tidy for -each source file in its parent directories. -)"), - cl::init(""), cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> ConfigFile("config-file", desc(R"( -Specify the path of .clang-tidy or custom config file: - e.g. --config-file=/some/path/myTidyConfigFile -This option internally works exactly the same way as - --config option after reading specified config file. -Use either --config-file or --config, not both. -)"), - cl::init(""), - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> DumpConfig("dump-config", desc(R"( -Dumps configuration in the YAML format to -stdout. This option can be used along with a -file name (and '--' if the file is outside of a -project with configured compilation database). -The configuration used for this file will be -printed. -Use along with -checks=* to include -configuration of all checks. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> EnableCheckProfile("enable-check-profile", desc(R"( -Enable per-check timing profiles, and print a -report to stderr. -)"), - cl::init(false), - cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> StoreCheckProfile("store-check-profile", desc(R"( -By default reports are printed in tabulated -format to stderr. When this option is passed, -these per-TU profiles are instead stored as JSON. -)"), - cl::value_desc("prefix"), - cl::cat(ClangTidyCategory)); - -/// This option allows enabling the experimental alpha checkers from the static -/// analyzer. This option is set to false and not visible in help, because it is -/// highly not recommended for users. -static cl::opt<bool> - AllowEnablingAnalyzerAlphaCheckers("allow-enabling-analyzer-alpha-checkers", - cl::init(false), cl::Hidden, - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> EnableModuleHeadersParsing("enable-module-headers-parsing", - desc(R"( -Enables preprocessor-level module header parsing -for C++20 and above, empowering specific checks -to detect macro definitions within modules. This -feature may cause performance and parsing issues -and is therefore considered experimental. -)"), - cl::init(false), - cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> ExportFixes("export-fixes", desc(R"( -YAML file to store suggested fixes in. The -stored fixes can be applied to the input source -code with clang-apply-replacements. -)"), - cl::value_desc("filename"), - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> Quiet("quiet", desc(R"( -Run clang-tidy in quiet mode. This suppresses -printing statistics about ignored warnings and -warnings treated as errors if the respective -options are specified. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<std::string> VfsOverlay("vfsoverlay", desc(R"( -Overlay the virtual filesystem described by file -over the real file system. -)"), - cl::value_desc("filename"), - cl::cat(ClangTidyCategory)); - -static cl::opt<bool> UseColor("use-color", desc(R"( -Use colors in diagnostics. If not set, colors -will be used if the terminal connected to -standard output supports colors. -This option overrides the 'UseColor' option in -.clang-tidy file, if any. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> VerifyConfig("verify-config", desc(R"( -Check the config files to ensure each check and -option is recognized without running any checks. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> AllowNoChecks("allow-no-checks", desc(R"( -Allow empty enabled checks. This suppresses -the "no checks enabled" error when disabling -all of the checks. -)"), - cl::init(false), cl::cat(ClangTidyCategory)); - -static cl::opt<bool> ExperimentalCustomChecks("experimental-custom-checks", - desc(R"( -Enable experimental clang-query based -custom checks. -see https://clang.llvm.org/extra/clang-tidy/QueryBasedCustomChecks.html. -)"), - cl::init(false), - cl::cat(ClangTidyCategory)); - -static cl::list<std::string> 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 analyzed 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)); +static std::string Checks; +static bool ChecksSpecified; +static std::string WarningsAsErrors; +static bool WarningsAsErrorsSpecified; +static std::string HeaderFilter; +static bool HeaderFilterSpecified; +static std::string ExcludeHeaderFilter; +static bool ExcludeHeaderFilterSpecified; +static bool SystemHeaders; +static bool SystemHeadersSpecified; +static std::string LineFilter; +static bool Fix; +static bool FixErrors; +static bool FixNotes; +static std::string FormatStyle; +static bool FormatStyleSpecified; +static bool ListChecks; +static bool ExplainConfig; +static std::string Config; +static bool ConfigSpecified; +static std::string ConfigFile; +static bool ConfigFileSpecified; +static bool DumpConfig; +static bool EnableCheckProfile; +static std::string StoreCheckProfile; +static bool AllowEnablingAnalyzerAlphaCheckers; +static bool EnableModuleHeadersParsing; +static std::string ExportFixes; +static bool Quiet; +static std::string VfsOverlay; +static bool UseColor; +static bool UseColorSpecified; +static bool VerifyConfig; +static bool AllowNoChecks; +static bool ExperimentalCustomChecks; +static std::vector<std::string> RemovedArgs; +static bool RemovedArgsSpecified; + +static void printHelp(bool ShowHidden = false) { + ClangTidyOptTable Tbl; + Tbl.printHelp(outs(), + "clang-tidy [options] <source0> [... <sourceN>] " + "[-- <compiler arguments>]", + "clang-tidy", ShowHidden); + outs() << CommonHelp << ClangTidyParameterFileHelp << ClangTidyHelp; +} + +static bool parseBoolArg(const opt::Arg *A, unsigned ValueID, bool &Value) { + if (!A->getOption().matches(ValueID)) { + Value = true; + return true; + } + std::optional<bool> Parsed = StringSwitch<std::optional<bool>>(A->getValue()) + .CaseLower("true", true) + .Case("1", true) + .CaseLower("false", false) + .Case("0", false) + .Default(std::nullopt); + if (Parsed) { + Value = *Parsed; + return true; + } + errs() << "clang-tidy: invalid value '" << A->getValue() << "' for option '" + << A->getSpelling() << "'\n"; + return false; +} + +static bool parseBoolArg(const opt::InputArgList &Args, unsigned FlagID, + unsigned ValueID, bool &Value, + bool *Specified = nullptr) { + const opt::Arg *A = Args.getLastArg(FlagID, ValueID); + if (Specified) + *Specified = A != nullptr; + Value = false; + return !A || parseBoolArg(A, ValueID, Value); +} + +static bool parseCommandLine(int argc, char **argv, BumpPtrAllocator &Allocator, + StringSaver &Saver, ClangTidyOptTable &Tbl, + opt::InputArgList &Args, + std::unique_ptr<CompilationDatabase> &Compilations, + std::vector<std::string> &SourcePaths) { + SmallVector<const char *> ExpandedArgs(argv, argv + argc); + cl::TokenizerCallback Tokenizer = + Triple(sys::getProcessTriple()).isOSWindows() + ? cl::TokenizeWindowsCommandLine + : cl::TokenizeGNUCommandLine; + cl::ExpansionContext ECtx(Allocator, Tokenizer); + if (Error Err = ECtx.expandResponseFiles(ExpandedArgs)) { + WithColor::error() << toString(std::move(Err)) << "\n"; + return false; + } + + int ToolArgc = static_cast<int>(ExpandedArgs.size()); + std::string FixedDatabaseError; + Compilations = FixedCompilationDatabase::loadFromCommandLine( + ToolArgc, ExpandedArgs.data(), FixedDatabaseError); + + SmallVector<char *> ToolArgv; + ToolArgv.reserve(ToolArgc); + for (const char *Arg : ArrayRef(ExpandedArgs).take_front(ToolArgc)) + ToolArgv.push_back(const_cast<char *>(Arg)); + + bool HasError = false; + Args = Tbl.parseArgs(ToolArgc, ToolArgv.data(), OPT_UNKNOWN, Saver, + [&](StringRef Message) { + errs() << "clang-tidy: " << Message << '\n'; + HasError = true; + }); + if (HasError) { + if (!FixedDatabaseError.empty()) + errs() << FixedDatabaseError; + return false; + } + + Checks = Args.getLastArgValue(OPT_checks_EQ); + ChecksSpecified = Args.hasArg(OPT_checks_EQ); + WarningsAsErrors = Args.getLastArgValue(OPT_warnings_as_errors_EQ); + WarningsAsErrorsSpecified = Args.hasArg(OPT_warnings_as_errors_EQ); + HeaderFilter = Args.getLastArgValue(OPT_header_filter_EQ, ".*"); + HeaderFilterSpecified = Args.hasArg(OPT_header_filter_EQ); + ExcludeHeaderFilter = Args.getLastArgValue(OPT_exclude_header_filter_EQ); + ExcludeHeaderFilterSpecified = Args.hasArg(OPT_exclude_header_filter_EQ); + LineFilter = Args.getLastArgValue(OPT_line_filter_EQ); + FormatStyle = Args.getLastArgValue(OPT_format_style_EQ, "none"); + FormatStyleSpecified = Args.hasArg(OPT_format_style_EQ); + Config = Args.getLastArgValue(OPT_config_EQ); + ConfigSpecified = Args.hasArg(OPT_config_EQ); + ConfigFile = Args.getLastArgValue(OPT_config_file_EQ); + ConfigFileSpecified = Args.hasArg(OPT_config_file_EQ); + StoreCheckProfile = Args.getLastArgValue(OPT_store_check_profile_EQ); + ExportFixes = Args.getLastArgValue(OPT_export_fixes_EQ); + VfsOverlay = Args.getLastArgValue(OPT_vfsoverlay_EQ); + RemovedArgs = Args.getAllArgValues(OPT_removed_arg_EQ); + RemovedArgsSpecified = Args.hasArg(OPT_removed_arg_EQ); + SourcePaths = Args.getAllArgValues(OPT_INPUT); + + if (!parseBoolArg(Args, OPT_system_headers, OPT_system_headers_EQ, + SystemHeaders, &SystemHeadersSpecified) || + !parseBoolArg(Args, OPT_fix, OPT_fix_EQ, Fix) || + !parseBoolArg(Args, OPT_fix_errors, OPT_fix_errors_EQ, FixErrors) || + !parseBoolArg(Args, OPT_fix_notes, OPT_fix_notes_EQ, FixNotes) || + !parseBoolArg(Args, OPT_list_checks, OPT_list_checks_EQ, ListChecks) || + !parseBoolArg(Args, OPT_explain_config, OPT_explain_config_EQ, + ExplainConfig) || + !parseBoolArg(Args, OPT_dump_config, OPT_dump_config_EQ, DumpConfig) || + !parseBoolArg(Args, OPT_enable_check_profile, OPT_enable_check_profile_EQ, + EnableCheckProfile) || + !parseBoolArg(Args, OPT_allow_enabling_analyzer_alpha_checkers, + OPT_allow_enabling_analyzer_alpha_checkers_EQ, + AllowEnablingAnalyzerAlphaCheckers) || + !parseBoolArg(Args, OPT_enable_module_headers_parsing, + OPT_enable_module_headers_parsing_EQ, + EnableModuleHeadersParsing) || + !parseBoolArg(Args, OPT_quiet, OPT_quiet_EQ, Quiet) || + !parseBoolArg(Args, OPT_use_color, OPT_use_color_EQ, UseColor, + &UseColorSpecified) || + !parseBoolArg(Args, OPT_verify_config, OPT_verify_config_EQ, + VerifyConfig) || + !parseBoolArg(Args, OPT_allow_no_checks, OPT_allow_no_checks_EQ, + AllowNoChecks) || + !parseBoolArg(Args, OPT_experimental_custom_checks, + OPT_experimental_custom_checks_EQ, + ExperimentalCustomChecks)) + return false; + + for (StringRef Plugin : Args.getAllArgValues(OPT_load_EQ)) { + PluginLoader Loader; + Loader = Plugin.str(); + } + + if (SourcePaths.empty()) { + if (!Compilations) + Compilations = std::make_unique<FixedCompilationDatabase>( + ".", std::vector<std::string>()); + return true; + } + + if (!Compilations) { + std::string ErrorMessage; + StringRef BuildPath = Args.getLastArgValue(OPT_p); + if (!BuildPath.empty()) + Compilations = + CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage); + else + Compilations = CompilationDatabase::autoDetectFromSource( + SourcePaths.front(), ErrorMessage); + if (!Compilations) { + errs() << "Error while trying to load a compilation database:\n" + << ErrorMessage << "Running without flags.\n"; + Compilations = std::make_unique<FixedCompilationDatabase>( + ".", std::vector<std::string>()); + } + } + + auto AdjustingCompilations = + std::make_unique<ArgumentsAdjustingCompilations>(std::move(Compilations)); + ArgumentsAdjuster Adjuster = + getInsertArgumentAdjuster(Args.getAllArgValues(OPT_extra_arg_before_EQ), + ArgumentInsertPosition::BEGIN); + Adjuster = combineAdjusters( + std::move(Adjuster), + getInsertArgumentAdjuster(Args.getAllArgValues(OPT_extra_arg_EQ), + ArgumentInsertPosition::END)); + AdjustingCompilations->appendArgumentsAdjuster(std::move(Adjuster)); + Compilations = std::move(AdjustingCompilations); + return true; +} + +} // namespace namespace clang::tidy { @@ -402,7 +407,7 @@ createOptionsProvider(llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) { ClangTidyGlobalOptions GlobalOptions; if (const std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) { llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n"; - llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true); + printHelp(); return nullptr; } @@ -419,21 +424,21 @@ createOptionsProvider(llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) { DefaultOptions.User = llvm::sys::Process::GetEnv("USERNAME"); ClangTidyOptions OverrideOptions; - if (Checks.getNumOccurrences() > 0) + if (ChecksSpecified) OverrideOptions.Checks = Checks; - if (WarningsAsErrors.getNumOccurrences() > 0) + if (WarningsAsErrorsSpecified) OverrideOptions.WarningsAsErrors = WarningsAsErrors; - if (HeaderFilter.getNumOccurrences() > 0) + if (HeaderFilterSpecified) OverrideOptions.HeaderFilterRegex = HeaderFilter; - if (ExcludeHeaderFilter.getNumOccurrences() > 0) + if (ExcludeHeaderFilterSpecified) OverrideOptions.ExcludeHeaderFilterRegex = ExcludeHeaderFilter; - if (SystemHeaders.getNumOccurrences() > 0) + if (SystemHeadersSpecified) OverrideOptions.SystemHeaders = SystemHeaders; - if (FormatStyle.getNumOccurrences() > 0) + if (FormatStyleSpecified) OverrideOptions.FormatStyle = FormatStyle; - if (UseColor.getNumOccurrences() > 0) + if (UseColorSpecified) OverrideOptions.UseColor = UseColor; - if (RemovedArgs.getNumOccurrences() > 0) + if (RemovedArgsSpecified) OverrideOptions.RemovedArgs = RemovedArgs; auto LoadConfig = @@ -451,8 +456,8 @@ createOptionsProvider(llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) { return nullptr; }; - if (ConfigFile.getNumOccurrences() > 0) { - if (Config.getNumOccurrences() > 0) { + if (ConfigFileSpecified) { + if (ConfigSpecified) { llvm::errs() << "Error: --config-file and --config are " "mutually exclusive. Specify only one.\n"; return nullptr; @@ -469,7 +474,7 @@ createOptionsProvider(llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) { return LoadConfig((*Text)->getBuffer(), ConfigFile); } - if (Config.getNumOccurrences() > 0) + if (ConfigSpecified) return LoadConfig(Config, "<command-line-config>"); return std::make_unique<FileOptionsProvider>( @@ -511,7 +516,8 @@ static StringRef closest(StringRef Value, const StringSet<> &Allowed) { return Closest; } -static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n"; +static constexpr llvm::StringLiteral VerifyConfigWarningEnd = + " [-verify-config]\n"; static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob, StringRef Source) { @@ -604,34 +610,25 @@ static llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> createBaseFS() { return BaseFS; } -int clangTidyMain(int argc, const char **argv) { - const llvm::InitLLVM X(argc, argv); - SmallVector<const char *> Args{argv, argv + argc}; - - // expand parameters file to argc and argv. - llvm::BumpPtrAllocator Alloc; - llvm::cl::TokenizerCallback Tokenizer = - llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows() - ? llvm::cl::TokenizeWindowsCommandLine - : llvm::cl::TokenizeGNUCommandLine; - llvm::cl::ExpansionContext ECtx(Alloc, Tokenizer); - if (llvm::Error Err = ECtx.expandResponseFiles(Args)) { - llvm::WithColor::error() << llvm::toString(std::move(Err)) << "\n"; +int clangTidyMain(int argc, char **argv) { + BumpPtrAllocator Alloc; + StringSaver Saver(Alloc); + ClangTidyOptTable Tbl; + opt::InputArgList Args; + std::unique_ptr<CompilationDatabase> Compilations; + std::vector<std::string> PathList; + if (!parseCommandLine(argc, argv, Alloc, Saver, Tbl, Args, Compilations, + PathList)) return 1; + + if (Args.hasArg(OPT_help, OPT_help_hidden)) { + printHelp(Args.hasArg(OPT_help_hidden)); + return 0; } - argc = static_cast<int>(Args.size()); - argv = Args.data(); - - // Enable help for -load option, if plugins are enabled. - if (cl::Option *LoadOpt = cl::getRegisteredOptions().lookup("load")) - LoadOpt->addCategory(ClangTidyCategory); - - llvm::Expected<CommonOptionsParser> OptionsParser = - CommonOptionsParser::create(argc, argv, ClangTidyCategory, - cl::ZeroOrMore); - if (!OptionsParser) { - llvm::WithColor::error() << llvm::toString(OptionsParser.takeError()); - return 1; + + if (Args.hasArg(OPT_version)) { + outs() << clang::getClangToolFullVersion("clang-tidy") << '\n'; + return 0; } const llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS = @@ -647,7 +644,6 @@ int clangTidyMain(int argc, const char **argv) { const SmallString<256> ProfilePrefix = makeAbsolute(StoreCheckProfile); StringRef FileName("dummy"); - auto PathList = OptionsParser->getSourcePathList(); if (!PathList.empty()) FileName = PathList.front(); @@ -720,13 +716,13 @@ int clangTidyMain(int argc, const char **argv) { if (EnabledChecks.empty() && !AllowNoChecks) { llvm::errs() << "Error: no checks enabled.\n"; - llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true); + printHelp(); return 1; } if (PathList.empty()) { llvm::errs() << "Error: no input files specified.\n"; - llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true); + printHelp(); return 1; } @@ -738,8 +734,8 @@ int clangTidyMain(int argc, const char **argv) { std::move(OwningOptionsProvider), AllowEnablingAnalyzerAlphaCheckers, EnableModuleHeadersParsing, ExperimentalCustomChecks); std::vector<ClangTidyError> Errors = - runClangTidy(Context, OptionsParser->getCompilations(), PathList, BaseFS, - FixNotes, EnableCheckProfile, ProfilePrefix, Quiet); + runClangTidy(Context, *Compilations, PathList, BaseFS, FixNotes, + EnableCheckProfile, ProfilePrefix, Quiet); const bool FoundErrors = llvm::any_of(Errors, [](const ClangTidyError &E) { return E.DiagLevel == ClangTidyError::Error; }); diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.h b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.h index 44b7a379e5277..1ea728ed29571 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.h +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.h @@ -19,7 +19,7 @@ namespace clang::tidy { -int clangTidyMain(int argc, const char **argv); +int clangTidyMain(int argc, char **argv); } // namespace clang::tidy diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyToolMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyToolMain.cpp index a2ba638ea15e8..086bfb6af32c5 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyToolMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyToolMain.cpp @@ -15,7 +15,8 @@ //===----------------------------------------------------------------------===// #include "ClangTidyMain.h" +#include "llvm/Support/LLVMDriver.h" -int main(int argc, const char **argv) { +int clang_tidy_main(int argc, char **argv, const llvm::ToolContext &) { return clang::tidy::clangTidyMain(argc, argv); } diff --git a/clang-tools-extra/clang-tidy/tool/Opts.td b/clang-tools-extra/clang-tidy/tool/Opts.td new file mode 100644 index 0000000000000..6610d5fe5cd97 --- /dev/null +++ b/clang-tools-extra/clang-tidy/tool/Opts.td @@ -0,0 +1,245 @@ +include "llvm/Option/OptParser.td" + +def clang_tidy_group : OptionGroup<"clang-tidy">, + HelpText<"clang-tidy options">; +def generic_group : OptionGroup<"generic">, HelpText<"Generic Options">; + +class F<string name, string help> + : Flag<["--", "-"], name>, HelpText<help>, Group<clang_tidy_group>; + +multiclass B<string name, string help> { + def NAME : F<name, help>; + def NAME #_EQ : Joined<["--", "-"], name #"=">, + MetaVarName<"<true|false>">, + Group<clang_tidy_group>, Flags<[HelpHidden]>; +} + +multiclass BH<string name> { + def NAME : Flag<["--", "-"], name>, Group<clang_tidy_group>, + Flags<[HelpHidden]>; + def NAME #_EQ : Joined<["--", "-"], name #"=">, + MetaVarName<"<true|false>">, + Group<clang_tidy_group>, Flags<[HelpHidden]>; +} + +multiclass Eq<string name, string metavar, string help> { + def NAME #_EQ : Joined<["--", "-"], name #"=">, + HelpText<help>, MetaVarName<metavar>, + Group<clang_tidy_group>; + def : Separate<["--", "-"], name>, Alias<!cast<Joined>(NAME #_EQ)>; +} + +class GF<string name, string help> + : Flag<["--", "-"], name>, HelpText<help>, Group<generic_group>; + +def help : GF<"help", "Display available options (--help-hidden for more)">; +def help_hidden : GF<"help-hidden", + "Display all available options, including hidden options">, + Flags<[HelpHidden]>; +def help_list + : GF<"help-list", + "Display list of available options (--help-list-hidden for more)">, + Alias<help>; +def help_list_hidden + : GF<"help-list-hidden", "Display list of all available options">, + Alias<help_hidden>, Flags<[HelpHidden]>; +def version : GF<"version", "Display the version of this program">; +def h : GF<"h", "Alias for --help">, Alias<help>, Flags<[HelpHidden]>; + +defm checks : Eq<"checks", "<string>", + "Comma-separated list of globs with optional '-'\n" + "prefix. Globs are processed in order of\n" + "appearance in the list. Globs without '-'\n" + "prefix add checks with matching names to the\n" + "set, globs with the '-' prefix remove checks\n" + "with matching names from the set of enabled\n" + "checks. This option's value is appended to the\n" + "value of the 'Checks' option in .clang-tidy\n" + "file, if any.">; +defm warnings_as_errors + : Eq<"warnings-as-errors", "<string>", + "Upgrades warnings to errors. Same format as\n" + "'-checks'.\n" + "This option's value is appended to the value of\n" + "the 'WarningsAsErrors' option in .clang-tidy\n" + "file, if any.">; +defm header_filter + : Eq<"header-filter", "<string>", + "Regular expression matching the names of the\n" + "headers to output diagnostics from. The default\n" + "value is '.*', i.e. diagnostics from all non-system\n" + "headers are displayed by default. Diagnostics\n" + "from the main file of each translation unit are\n" + "always displayed.\n" + "Can be used together with -line-filter.\n" + "This option overrides the 'HeaderFilterRegex'\n" + "option in .clang-tidy file, if any.">; +defm exclude_header_filter + : Eq<"exclude-header-filter", "<string>", + "Regular expression matching the names of the\n" + "headers to exclude diagnostics from. Diagnostics\n" + "from the main file of each translation unit are\n" + "always displayed.\n" + "Must be used together with --header-filter.\n" + "Can be used together with -line-filter.\n" + "This option overrides the 'ExcludeHeaderFilterRegex'\n" + "option in .clang-tidy file, if any.">; +defm system_headers + : B<"system-headers", + "Display the errors from system headers.\n" + "This option overrides the 'SystemHeaders' option\n" + "in .clang-tidy file, if any.">; +defm line_filter + : Eq<"line-filter", "<string>", + "List of files and line ranges to output diagnostics from.\n" + "The range is inclusive on both ends. Can be used together\n" + "with -header-filter. The format of the list is a JSON\n" + "array of objects. For example:\n" + " [\n" + " {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n" + " {\"name\":\"file2.h\"}\n" + " ]\n" + "This will output diagnostics from 'file1.cpp' only for\n" + "the line ranges [1,3] and [5,7], as well as all from the\n" + "entire 'file2.h'.">; +defm fix + : B<"fix", "Apply suggested fixes. Without -fix-errors\n" + "clang-tidy will bail out if any compilation\n" + "errors were found.">; +defm fix_errors + : B<"fix-errors", + "Apply suggested fixes even if compilation\n" + "errors were found. If compiler errors have\n" + "attached fix-its, clang-tidy will apply them as\n" + "well.">; +defm fix_notes + : B<"fix-notes", + "If a warning has no fix, but a single fix can\n" + "be found through an associated diagnostic note,\n" + "apply the fix.\n" + "Specifying this flag will implicitly enable the\n" + "'--fix' flag.">; +defm format_style + : Eq<"format-style", "<string>", + "Style for formatting code around applied fixes:\n" + " - 'none' (default) turns off formatting\n" + " - 'file' (literally 'file', not a placeholder)\n" + " uses .clang-format file in the closest parent\n" + " directory\n" + " - '{ <json> }' specifies options inline, e.g.\n" + " -format-style='{BasedOnStyle: llvm, IndentWidth: 8}'\n" + " - 'llvm', 'google', 'webkit', 'mozilla'\n" + "See clang-format documentation for the up-to-date\n" + "information about formatting styles and options.\n" + "This option overrides the 'FormatStyle` option in\n" + ".clang-tidy file, if any.">; +defm list_checks + : B<"list-checks", + "List all enabled checks and exit. Use with\n" + "-checks=* to list all available checks.">; +defm explain_config + : B<"explain-config", + "For each enabled check explains, where it is\n" + "enabled, i.e. in clang-tidy binary, command\n" + "line or a specific configuration file.">; +defm config + : Eq<"config", "<string>", + "Specifies a configuration in YAML/JSON format:\n" + " -config=\"{Checks: '*',\n" + " CheckOptions: {x: y}}\"\n" + "When the value is empty, clang-tidy will\n" + "attempt to find a file named .clang-tidy for\n" + "each source file in its parent directories.">; +defm config_file + : Eq<"config-file", "<filename>", + "Specify the path of .clang-tidy or custom config file:\n" + " e.g. --config-file=/some/path/myTidyConfigFile\n" + "This option internally works exactly the same way as\n" + " --config option after reading specified config file.\n" + "Use either --config-file or --config, not both.">; +defm dump_config + : B<"dump-config", + "Dumps configuration in the YAML format to\n" + "stdout. This option can be used along with a\n" + "file name (and '--' if the file is outside of a\n" + "project with configured compilation database).\n" + "The configuration used for this file will be\n" + "printed.\n" + "Use along with -checks=* to include\n" + "configuration of all checks.">; +defm enable_check_profile + : B<"enable-check-profile", + "Enable per-check timing profiles, and print a\n" + "report to stderr.">; +defm store_check_profile + : Eq<"store-check-profile", "<prefix>", + "By default reports are printed in tabulated\n" + "format to stderr. When this option is passed,\n" + "these per-TU profiles are instead stored as JSON.">; +defm allow_enabling_analyzer_alpha_checkers + : BH<"allow-enabling-analyzer-alpha-checkers">; +defm enable_module_headers_parsing + : B<"enable-module-headers-parsing", + "Enables preprocessor-level module header parsing\n" + "for C++20 and above, empowering specific checks\n" + "to detect macro definitions within modules. This\n" + "feature may cause performance and parsing issues\n" + "and is therefore considered experimental.">; +defm export_fixes + : Eq<"export-fixes", "<filename>", + "YAML file to store suggested fixes in. The\n" + "stored fixes can be applied to the input source\n" + "code with clang-apply-replacements.">; +defm quiet + : B<"quiet", + "Run clang-tidy in quiet mode. This suppresses\n" + "printing statistics about ignored warnings and\n" + "warnings treated as errors if the respective\n" + "options are specified.">; +defm vfsoverlay + : Eq<"vfsoverlay", "<filename>", + "Overlay the virtual filesystem described by file\n" + "over the real file system.">; +defm use_color + : B<"use-color", + "Use colors in diagnostics. If not set, colors\n" + "will be used if the terminal connected to\n" + "standard output supports colors.\n" + "This option overrides the 'UseColor' option in\n" + ".clang-tidy file, if any.">; +defm verify_config + : B<"verify-config", + "Check the config files to ensure each check and\n" + "option is recognized without running any checks.">; +defm allow_no_checks + : B<"allow-no-checks", + "Allow empty enabled checks. This suppresses\n" + "the \"no checks enabled\" error when disabling\n" + "all of the checks.">; +defm experimental_custom_checks + : B<"experimental-custom-checks", + "Enable experimental clang-query based\n" + "custom checks.\n" + "see https://clang.llvm.org/extra/clang-tidy/" + "QueryBasedCustomChecks.html.">; +defm removed_arg + : Eq<"removed-arg", "<arg>", + "List of arguments to remove from the command\n" + "line sent to the compiler. Please note that\n" + "removing arguments might change the semantic\n" + "of the analyzed code, possibly leading to\n" + "compiler errors, false positives or\n" + "false negatives. This option is applied\n" + "before --extra-arg and --extra-arg-before">; + +defm extra_arg + : Eq<"extra-arg", "<arg>", + "Additional argument to append to the compiler command line">; +defm extra_arg_before + : Eq<"extra-arg-before", "<arg>", + "Additional argument to prepend to the compiler command line">; +def p : Separate<["-", "--"], "p">, HelpText<"Build path">, + MetaVarName<"<build-path>">, Group<clang_tidy_group>; +def p_EQ : Joined<["-", "--"], "p=">, Alias<p>, Flags<[HelpHidden]>; +defm load + : Eq<"load", "<pluginfilename>", "Load the specified plugin">; diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst index 908dee6c18a7f..8b61e6fcd56ad 100644 --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -80,6 +80,7 @@ Name prefix Description ``darwin-`` Checks related to Darwin coding conventions. ``fuchsia-`` Checks related to Fuchsia coding conventions. ``google-`` Checks related to Google coding conventions. +``hicpp-`` Checks related to High Integrity C++ Coding Standard. ``linuxkernel-`` Checks related to the Linux Kernel coding conventions. ``llvm-`` Checks related to the LLVM coding conventions. ``llvmlibc-`` Checks related to the LLVM-libc coding standards. @@ -126,156 +127,161 @@ An overview of all the command-line options: .. code-block:: console $ clang-tidy --help - USAGE: clang-tidy [options] <source0> [... <sourceN>] + OVERVIEW: clang-tidy - OPTIONS: + USAGE: clang-tidy [options] <source0> [... <sourceN>] [-- <compiler arguments>] Generic Options: - - --help - Display available options (--help-hidden for more) - --help-list - Display list of available options (--help-list-hidden for more) - --version - Display the version of this program + --help-list Display list of available options (--help-list-hidden for more) + --help Display available options (--help-hidden for more) + --version Display the version of this program clang-tidy options: - - --allow-no-checks - Allow empty enabled checks. This suppresses - the "no checks enabled" error when disabling - all of the checks. - --checks=<string> - Comma-separated list of globs with optional '-' - prefix. Globs are processed in order of - appearance in the list. Globs without '-' - prefix add checks with matching names to the - set, globs with the '-' prefix remove checks - with matching names from the set of enabled - checks. This option's value is appended to the - value of the 'Checks' option in .clang-tidy - file, if any. - --config=<string> - Specifies a configuration in YAML/JSON format: - -config="{Checks: '*', - CheckOptions: {x: y}}" - When the value is empty, clang-tidy will - attempt to find a file named .clang-tidy for - each source file in its parent directories. - --config-file=<string> - Specify the path of .clang-tidy or custom config file: - e.g. --config-file=/some/path/myTidyConfigFile - This option internally works exactly the same way as - --config option after reading specified config file. - Use either --config-file or --config, not both. - --dump-config - Dumps configuration in the YAML format to - stdout. This option can be used along with a - file name (and '--' if the file is outside of a - project with configured compilation database). - The configuration used for this file will be - printed. - Use along with -checks=* to include - configuration of all checks. - --enable-check-profile - Enable per-check timing profiles, and print a - report to stderr. - --enable-module-headers-parsing - Enables preprocessor-level module header parsing - for C++20 and above, empowering specific checks - to detect macro definitions within modules. This - feature may cause performance and parsing issues - and is therefore considered experimental. - --exclude-header-filter=<string> - Regular expression matching the names of the - headers to exclude diagnostics from. Diagnostics - from the main file of each translation unit are - always displayed. - Must be used together with --header-filter. - Can be used together with -line-filter. - This option overrides the 'ExcludeHeaderFilterRegex' - option in .clang-tidy file, if any. - --experimental-custom-checks - Enable experimental clang-query based - custom checks. - see https://clang.llvm.org/extra/clang-tidy/QueryBasedCustomChecks.html. - --explain-config - For each enabled check explains, where it is - enabled, i.e. in clang-tidy binary, command - line or a specific configuration file. - --export-fixes=<filename> - YAML file to store suggested fixes in. The - stored fixes can be applied to the input source - code with clang-apply-replacements. - --extra-arg=<string> - Additional argument to append to the compiler command line - --extra-arg-before=<string> - Additional argument to prepend to the compiler command line - --fix - Apply suggested fixes. Without -fix-errors - clang-tidy will bail out if any compilation - errors were found. - --fix-errors - Apply suggested fixes even if compilation - errors were found. If compiler errors have - attached fix-its, clang-tidy will apply them as - well. - --fix-notes - If a warning has no fix, but a single fix can - be found through an associated diagnostic note, - apply the fix. - Specifying this flag will implicitly enable the - '--fix' flag. - --format-style=<string> - Style for formatting code around applied fixes: - - 'none' (default) turns off formatting - - 'file' (literally 'file', not a placeholder) - uses .clang-format file in the closest parent - directory - - '{ <json> }' specifies options inline, e.g. - -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' - - 'llvm', 'google', 'webkit', 'mozilla' - See clang-format documentation for the up-to-date - information about formatting styles and options. - This option overrides the 'FormatStyle` option in - .clang-tidy file, if any. - --header-filter=<string> - Regular expression matching the names of the - headers to output diagnostics from. The default - value is '.*', i.e. diagnostics from all non-system - headers are displayed by default. Diagnostics - from the main file of each translation unit are - always displayed. - Can be used together with -line-filter. - This option overrides the 'HeaderFilterRegex' - option in .clang-tidy file, if any. - --line-filter=<string> - List of files and line ranges to output diagnostics from. - The range is inclusive on both ends. Can be used together - with -header-filter. The format of the list is a JSON - array of objects. For example: - - [ - {"name":"file1.cpp","lines":[[1,3],[5,7]]}, - {"name":"file2.h"} - ] - - This will output diagnostics from 'file1.cpp' only for - the line ranges [1,3] and [5,7], as well as all from the - entire 'file2.h'. - --list-checks - List all enabled checks and exit. Use with - -checks=* to list all available checks. - --load=<pluginfilename> - Load the specified plugin - -p <string> - Build path - --quiet - Run clang-tidy in quiet mode. This suppresses - printing statistics about ignored warnings and - warnings treated as errors if the respective - options are specified. - --removed-arg=<string> - List of arguments to remove from the command - line sent to the compiler. Please note that - removing arguments might change the semantic - of the analyzed code, possibly leading to - compiler errors, false positives or - false negatives. This option is applied - before --extra-arg and --extra-arg-before - --store-check-profile=<prefix> - By default reports are printed in tabulated - format to stderr. When this option is passed, - these per-TU profiles are instead stored as JSON. - --system-headers - Display the errors from system headers. - This option overrides the 'SystemHeaders' option - in .clang-tidy file, if any. - --use-color - Use colors in diagnostics. If not set, colors - will be used if the terminal connected to - standard output supports colors. - This option overrides the 'UseColor' option in - .clang-tidy file, if any. - --verify-config - Check the config files to ensure each check and - option is recognized without running any checks. - --vfsoverlay=<filename> - Overlay the virtual filesystem described by file - over the real file system. - --warnings-as-errors=<string> - Upgrades warnings to errors. Same format as - '-checks'. - This option's value is appended to the value of - the 'WarningsAsErrors' option in .clang-tidy - file, if any. + --allow-no-checks Allow empty enabled checks. This suppresses + the "no checks enabled" error when disabling + all of the checks. + --checks=<string> Comma-separated list of globs with optional '-' + prefix. Globs are processed in order of + appearance in the list. Globs without '-' + prefix add checks with matching names to the + set, globs with the '-' prefix remove checks + with matching names from the set of enabled + checks. This option's value is appended to the + value of the 'Checks' option in .clang-tidy + file, if any. + --config-file=<filename> + Specify the path of .clang-tidy or custom config file: + e.g. --config-file=/some/path/myTidyConfigFile + This option internally works exactly the same way as + --config option after reading specified config file. + Use either --config-file or --config, not both. + --config=<string> Specifies a configuration in YAML/JSON format: + -config="{Checks: '*', + CheckOptions: {x: y}}" + When the value is empty, clang-tidy will + attempt to find a file named .clang-tidy for + each source file in its parent directories. + --dump-config Dumps configuration in the YAML format to + stdout. This option can be used along with a + file name (and '--' if the file is outside of a + project with configured compilation database). + The configuration used for this file will be + printed. + Use along with -checks=* to include + configuration of all checks. + --enable-check-profile Enable per-check timing profiles, and print a + report to stderr. + --enable-module-headers-parsing + Enables preprocessor-level module header parsing + for C++20 and above, empowering specific checks + to detect macro definitions within modules. This + feature may cause performance and parsing issues + and is therefore considered experimental. + --exclude-header-filter=<string> + Regular expression matching the names of the + headers to exclude diagnostics from. Diagnostics + from the main file of each translation unit are + always displayed. + Must be used together with --header-filter. + Can be used together with -line-filter. + This option overrides the 'ExcludeHeaderFilterRegex' + option in .clang-tidy file, if any. + --experimental-custom-checks + Enable experimental clang-query based + custom checks. + see https://clang.llvm.org/extra/clang-tidy/QueryBasedCustomChecks.html. + --explain-config For each enabled check explains, where it is + enabled, i.e. in clang-tidy binary, command + line or a specific configuration file. + --export-fixes=<filename> + YAML file to store suggested fixes in. The + stored fixes can be applied to the input source + code with clang-apply-replacements. + --extra-arg-before=<arg> + Additional argument to prepend to the compiler command line + --extra-arg=<arg> Additional argument to append to the compiler command line + --fix-errors Apply suggested fixes even if compilation + errors were found. If compiler errors have + attached fix-its, clang-tidy will apply them as + well. + --fix-notes If a warning has no fix, but a single fix can + be found through an associated diagnostic note, + apply the fix. + Specifying this flag will implicitly enable the + '--fix' flag. + --fix Apply suggested fixes. Without -fix-errors + clang-tidy will bail out if any compilation + errors were found. + --format-style=<string> Style for formatting code around applied fixes: + - 'none' (default) turns off formatting + - 'file' (literally 'file', not a placeholder) + uses .clang-format file in the closest parent + directory + - '{ <json> }' specifies options inline, e.g. + -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' + - 'llvm', 'google', 'webkit', 'mozilla' + See clang-format documentation for the up-to-date + information about formatting styles and options. + This option overrides the 'FormatStyle` option in + .clang-tidy file, if any. + --header-filter=<string> + Regular expression matching the names of the + headers to output diagnostics from. The default + value is '.*', i.e. diagnostics from all non-system + headers are displayed by default. Diagnostics + from the main file of each translation unit are + always displayed. + Can be used together with -line-filter. + This option overrides the 'HeaderFilterRegex' + option in .clang-tidy file, if any. + --line-filter=<string> List of files and line ranges to output diagnostics from. + The range is inclusive on both ends. Can be used together + with -header-filter. The format of the list is a JSON + array of objects. For example: + [ + {"name":"file1.cpp","lines":[[1,3],[5,7]]}, + {"name":"file2.h"} + ] + This will output diagnostics from 'file1.cpp' only for + the line ranges [1,3] and [5,7], as well as all from the + entire 'file2.h'. + --list-checks List all enabled checks and exit. Use with + -checks=* to list all available checks. + --load=<pluginfilename> Load the specified plugin + -p <build-path> Build path + --quiet Run clang-tidy in quiet mode. This suppresses + printing statistics about ignored warnings and + warnings treated as errors if the respective + options are specified. + --removed-arg=<arg> List of arguments to remove from the command + line sent to the compiler. Please note that + removing arguments might change the semantic + of the analyzed code, possibly leading to + compiler errors, false positives or + false negatives. This option is applied + before --extra-arg and --extra-arg-before + --store-check-profile=<prefix> + By default reports are printed in tabulated + format to stderr. When this option is passed, + these per-TU profiles are instead stored as JSON. + --system-headers Display the errors from system headers. + This option overrides the 'SystemHeaders' option + in .clang-tidy file, if any. + --use-color Use colors in diagnostics. If not set, colors + will be used if the terminal connected to + standard output supports colors. + This option overrides the 'UseColor' option in + .clang-tidy file, if any. + --verify-config Check the config files to ensure each check and + option is recognized without running any checks. + --vfsoverlay=<filename> Overlay the virtual filesystem described by file + over the real file system. + --warnings-as-errors=<string> + Upgrades warnings to errors. Same format as + '-checks'. + This option's value is appended to the value of + the 'WarningsAsErrors' option in .clang-tidy + file, if any. -p <build-path> is used to read a compile command database. @@ -283,7 +289,7 @@ An overview of all the command-line options: compile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON CMake option to get this output). When no build path is specified, a search for compile_commands.json will be attempted through all - parent paths of the first input file . See: + parent paths of the first input file. See: https://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an example of setting up Clang Tooling on a source tree. @@ -358,39 +364,6 @@ An overview of all the command-line options: some-check.SomeOption: 'some value' ... -Running Clang-Tidy on CUDA Files --------------------------------- - -:program:`clang-tidy` supports analyzing CUDA source files. To ensure correct -header resolution, it is important to specify the CUDA toolkit path using -``--cuda-path``. For more details on how Clang handles CUDA, see -`Compiling CUDA with Clang <https://llvm.org/docs/CompileCudaWithLLVM.html>`_. - -If you are using a GCC + NVCC build setup, the compiler command database will -contain NVCC-specific flags that :program:`clang-tidy` does not understand. - -In this case, you should use the ``RemovedArgs`` configuration option (or -``--removed-arg`` command-line option) to remove these flags, and -``ExtraArgs`` (or ``--extra-arg``) to provide the ``--cuda-path``. - -For example, to remove the NVCC-specific ``-gencode`` flag and provide the -CUDA path: - -.. code-block:: console - - $ clang-tidy source.cu --removed-arg="-gencode" --removed-arg="arch=.." --extra-arg="--cuda-path=/path/to/cuda" - -By default, :program:`clang-tidy` will analyze both host and device code. -To restrict the analysis to a specific side and specifically choose device -compilation flags, use the ``--extra-arg`` flag to pass the arguments. - -For example, to perform device analysis only, use -the ``--cuda-device-only`` flag: - -.. code-block:: console - - $ clang-tidy source.cu --extra-arg="--cuda-device-only" --extra-arg="--cuda-path=/path/to/cuda" - Clang-Tidy Automation ===================== 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 80540411e53e3..a389fec9070a6 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,3 @@ // 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 '--removed-arg'? +// CHECK: clang-tidy: unknown argument '--invalid-arg' diff --git a/utils/bazel/llvm-project-overlay/clang-tools-extra/clang-tidy/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang-tools-extra/clang-tidy/BUILD.bazel index a4e30d615a39a..aa72d0e1fd3d4 100644 --- a/utils/bazel/llvm-project-overlay/clang-tools-extra/clang-tidy/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/clang-tools-extra/clang-tidy/BUILD.bazel @@ -6,6 +6,8 @@ load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@bazel_skylib//rules:native_binary.bzl", "native_binary") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("//llvm:driver.bzl", "llvm_driver_cc_binary") +load("//mlir:tblgen.bzl", "gentbl_cc_library") load("defs.bzl", "clang_tidy_library") package( @@ -385,22 +387,36 @@ CHECKS = [ "//conditions:default": [], }) +gentbl_cc_library( + name = "ClangTidyOptsTableGen", + strip_include_prefix = "tool", + tbl_outs = {"tool/Opts.inc": ["-gen-opt-parser-defs"]}, + tblgen = "//llvm:llvm-tblgen", + td_file = "tool/Opts.td", + deps = ["//llvm:OptParserTdFiles"], +) + cc_library( name = "tool", - srcs = ["tool/ClangTidyMain.cpp"], + srcs = [ + "tool/ClangTidyMain.cpp", + "tool/ClangTidyToolMain.cpp", + ], hdrs = ["tool/ClangTidyMain.h"], deps = CHECKS + [ + ":ClangTidyOptsTableGen", ":lib", ":utils", + "//clang:basic", "//clang:tooling", + "//llvm:Option", "//llvm:Support", "//llvm:TargetParser", ], ) -cc_binary( +llvm_driver_cc_binary( name = "clang-tidy", - srcs = ["tool/ClangTidyToolMain.cpp"], stamp = 0, deps = [":tool"], ) diff --git a/utils/bazel/llvm-project-overlay/llvm/driver.bzl b/utils/bazel/llvm-project-overlay/llvm/driver.bzl index 43c7b5c241f02..d6033d3cecd9d 100644 --- a/utils/bazel/llvm-project-overlay/llvm/driver.bzl +++ b/utils/bazel/llvm-project-overlay/llvm/driver.bzl @@ -10,6 +10,7 @@ load("@rules_cc//cc:defs.bzl", "CcInfo", "cc_binary") # Mapping from every tool to the cc_library that implements the tool's entrypoint. _TOOLS = { + "clang-tidy": "//clang-tools-extra/clang-tidy:tool", "clang-scan-deps": "//clang:clang-scan-deps-lib", "clang": "//clang:clang-driver", "dsymutil": "//llvm:dsymutil-lib", _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
