https://github.com/PiotrZSL created https://github.com/llvm/llvm-project/pull/66553
Driver mode passed as an extra argument (command line or config) were not utilized for removing invalid arguments in stripPositionalArgs function, and even if passed as config driver mode were not used for dependency file striping leading to invalid handling of -MD. Additionally driver mode were needed even if user already added cl.exe after --. Fixes: #65108, #53674, #52687, #44701 >From 3bc42b19b245e3497aadfc7642957cd349712723 Mon Sep 17 00:00:00 2001 From: Piotr Zegar <[email protected]> Date: Fri, 15 Sep 2023 21:39:17 +0000 Subject: [PATCH] [clang-tidy] Fix handling --driver-mode= Driver mode passed as an extra argument (command line or config) were not utilized for removing invalid arguments in stripPositionalArgs function, and even if passed as config driver mode were not used for dependency file striping leading to invalid handling of -MD. Additionally driver mode were needed even if user already added cl.exe after --. --- .../clang-tidy/tool/ClangTidyMain.cpp | 127 ++++++++++++++---- clang-tools-extra/docs/ReleaseNotes.rst | 5 + .../clang-tidy/infrastructure/driver-mode.cpp | 57 ++++++++ 3 files changed, 164 insertions(+), 25 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/infrastructure/driver-mode.cpp diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index dd7f8141a694e2a..152bfbf6bc61f99 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -19,6 +19,7 @@ #include "../ClangTidyForceLinker.h" #include "../GlobList.h" #include "clang/Tooling/CommonOptionsParser.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/PluginLoader.h" @@ -26,6 +27,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/WithColor.h" +#include <algorithm> #include <optional> using namespace clang::tooling; @@ -450,7 +452,7 @@ static StringRef closest(StringRef Value, const StringSet<> &Allowed) { return Closest; } -static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n"; +static constexpr StringRef VerifyConfigWarningEnd = " [-verify-config]\n"; static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob, StringRef Source) { @@ -525,8 +527,95 @@ static bool verifyFileExtensions( return AnyInvalid; } +static SmallString<256> makeAbsolute(llvm::StringRef Input) { + if (Input.empty()) + return {}; + SmallString<256> AbsolutePath(Input); + if (std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath)) { + llvm::errs() << "Can't make absolute path from " << Input << ": " + << EC.message() << "\n"; + } + return AbsolutePath; +} + +static llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> createBaseFS() { + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + + if (!VfsOverlay.empty()) { + IntrusiveRefCntPtr<vfs::FileSystem> VfsFromFile = + getVfsFromFile(VfsOverlay, BaseFS); + if (!VfsFromFile) + return nullptr; + BaseFS->pushOverlay(std::move(VfsFromFile)); + } + return BaseFS; +} + +static llvm::Expected<CommonOptionsParser> +recreateOptionsParserIfNeeded(llvm::ArrayRef<const char *> Args, + llvm::Expected<CommonOptionsParser> OptionsParser, + const ClangTidyOptions &EffectiveOptions) { + + auto DoubleDashIt = std::find(Args.begin(), Args.end(), StringRef("--")); + if (DoubleDashIt == Args.end() || Args.empty() || + Args.back() == StringRef("--")) + return OptionsParser; + + auto IsDriverMode = [](StringRef Argument) { + return Argument.startswith("--driver-mode="); + }; + + if (Args.end() != + std::find_if(std::next(DoubleDashIt), Args.end(), IsDriverMode)) + return OptionsParser; + + std::vector<std::string> CommandArguments(std::next(DoubleDashIt), + Args.end()); + if (CommandArguments.empty() || + llvm::StringRef(CommandArguments.front()).startswith("-")) + CommandArguments.insert(CommandArguments.begin(), "clang-tool"); + + CommandArguments = + OptionsParser->getArgumentsAdjuster()(CommandArguments, ""); + if (EffectiveOptions.ExtraArgsBefore) + CommandArguments = tooling::getInsertArgumentAdjuster( + *EffectiveOptions.ExtraArgsBefore, + tooling::ArgumentInsertPosition::BEGIN)(CommandArguments, ""); + + if (EffectiveOptions.ExtraArgs) + CommandArguments = tooling::getInsertArgumentAdjuster( + *EffectiveOptions.ExtraArgs, + tooling::ArgumentInsertPosition::END)(CommandArguments, ""); + + auto DriverModeIt = std::find_if(CommandArguments.begin(), + CommandArguments.end(), IsDriverMode); + if (DriverModeIt == CommandArguments.end()) { + std::string ExeName = CommandArguments.front(); + tooling::addTargetAndModeForProgramName(CommandArguments, ExeName); + DriverModeIt = std::find_if(CommandArguments.begin(), + CommandArguments.end(), IsDriverMode); + } + + if (DriverModeIt == CommandArguments.end()) + return OptionsParser; + + std::vector<const char *> NewArgs(Args.begin(), Args.end()); + auto InsertIt = + NewArgs.begin() + std::distance(Args.begin(), DoubleDashIt) + 1U; + if (!StringRef(*InsertIt).startswith("-")) + ++InsertIt; + NewArgs.insert(InsertIt, DriverModeIt->c_str()); + + int ArgC = NewArgs.size(); + const char **ArgV = NewArgs.data(); + return CommonOptionsParser::create(ArgC, ArgV, ClangTidyCategory, + cl::ZeroOrMore); +} + int clangTidyMain(int argc, const char **argv) { llvm::InitLLVM X(argc, argv); + llvm::ArrayRef<const char *> Args(argv, argc); // Enable help for -load option, if plugins are enabled. if (cl::Option *LoadOpt = cl::getRegisteredOptions().lookup("load")) @@ -540,34 +629,16 @@ int clangTidyMain(int argc, const char **argv) { return 1; } - llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS( - new vfs::OverlayFileSystem(vfs::getRealFileSystem())); - - if (!VfsOverlay.empty()) { - IntrusiveRefCntPtr<vfs::FileSystem> VfsFromFile = - getVfsFromFile(VfsOverlay, BaseFS); - if (!VfsFromFile) - return 1; - BaseFS->pushOverlay(std::move(VfsFromFile)); - } + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS = createBaseFS(); + if (!BaseFS) + return 1; auto OwningOptionsProvider = createOptionsProvider(BaseFS); auto *OptionsProvider = OwningOptionsProvider.get(); if (!OptionsProvider) return 1; - auto MakeAbsolute = [](const std::string &Input) -> SmallString<256> { - if (Input.empty()) - return {}; - SmallString<256> AbsolutePath(Input); - if (std::error_code EC = llvm::sys::fs::make_absolute(AbsolutePath)) { - llvm::errs() << "Can't make absolute path from " << Input << ": " - << EC.message() << "\n"; - } - return AbsolutePath; - }; - - SmallString<256> ProfilePrefix = MakeAbsolute(StoreCheckProfile); + SmallString<256> ProfilePrefix = makeAbsolute(StoreCheckProfile); StringRef FileName("dummy"); auto PathList = OptionsParser->getSourcePathList(); @@ -575,9 +646,15 @@ int clangTidyMain(int argc, const char **argv) { FileName = PathList.front(); } - SmallString<256> FilePath = MakeAbsolute(std::string(FileName)); - + SmallString<256> FilePath = makeAbsolute(FileName); ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath); + OptionsParser = recreateOptionsParserIfNeeded(Args, std::move(OptionsParser), + EffectiveOptions); + if (!OptionsParser) { + llvm::WithColor::error() << llvm::toString(OptionsParser.takeError()); + return 1; + } + std::vector<std::string> EnabledChecks = getCheckNames(EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers); diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 19c977977f9044c..013f09f97e18ded 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -122,6 +122,11 @@ Improvements to clang-tidy if any :program:`clang-tidy` subprocess exits with a non-zero code or if exporting fixes fails. +- Improved handling of `--driver-mode=`, now automatically deducing it from + the compiler name after `--`, or properly utilizing it when passed as an + extra argument during :program:`clang-tidy` invocation with explicit compiler + arguments. + New checks ^^^^^^^^^^ diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/driver-mode.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/driver-mode.cpp new file mode 100644 index 000000000000000..fed017e5de09f23 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/infrastructure/driver-mode.cpp @@ -0,0 +1,57 @@ +// REQUIRES: shell +// RUN: rm -rf "%t" +// RUN: mkdir "%t" +// RUN: cp "%s" "%t/code.cpp" +// RUN: echo '' > "%t/.clang-tidy" + +// Compile commands tests (explicit --driver-mode): +// RUN: echo '[{"directory":"%t/","file":"code.cpp","command":"dummy-compiler /W4 code.cpp"}]' > "%t/compile_commands.json" +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: --extra-arg=--driver-mode=cl 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: --extra-arg-before=--driver-mode=cl 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: --config='{ExtraArgs: ["--driver-mode=cl"]}' 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: --config='{ExtraArgsBefore: ["--driver-mode=cl"]}' 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s + +// Compile commands tests (implicit --driver-mode): +// RUN: echo '[{"directory":"%t/","file":"code.cpp","command":"cl.exe /W4 code.cpp"}]' > "%t/compile_commands.json" +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s + +// Compile commands tests (negative) +// RUN: echo '[{"directory":"%t/","file":"code.cpp","command":"dummy-compiler -MT /W4 code.cpp"}]' > "%t/compile_commands.json" +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' --check-prefix=NEGATIVE_CHECK --allow-empty %s + +// Command line tests (explicit --driver-mode): +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" "%t/code.cpp" \ +// RUN: -- --driver-mode=cl -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" "%t/code.cpp" \ +// RUN: --extra-arg=--driver-mode=cl -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" "%t/code.cpp" \ +// RUN: --extra-arg-before=--driver-mode=cl -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: --config='{ExtraArgs: ["--driver-mode=cl"]}' -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: --config='{ExtraArgsBefore: ["--driver-mode=cl"]}' -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s + +// Command line tests (implicit --driver-mode): +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: -- cl.exe -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s + +// Command line tests (negative) +// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \ +// RUN: -- dummy-compiler -MT /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' --check-prefix=NEGATIVE_CHECK --allow-empty %s + +struct string {}; + +struct A { + A(string aa, string bb) : b(bb), a(aa) {} +// CHECK: code.cpp:[[@LINE-1]]:31: warning: field 'b' will be initialized after field 'a' [clang-diagnostic-reorder-ctor] +// NEGATIVE_CHECK-NOT: warning: field 'b' will be initialized after field 'a' [clang-diagnostic-reorder-ctor] + + string a; + string b; +}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
