- Notifications
You must be signed in to change notification settings - Fork 15.3k
[clang-tidy] Fix handling --driver-mode= #66553
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[clang-tidy] Fix handling --driver-mode= #66553
Conversation
| @llvm/pr-subscribers-clang-tools-extra @llvm/pr-subscribers-clang-tidy ChangesDriver 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, #44701Full diff: https://github.com/llvm/llvm-project/pull/66553.diff 3 Files Affected:
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; +}; |
| If anyone see any other alternative implementations or see some potential issues, then any comments are welcome. |
3bc42b1 to d67dbfb Compare | Is there any chance this could land in the near future? CMake is currenlty passing the driver mode as extra-arg-before which, as I understand, is not utilized without this PR. I've opened an issue on cmake to pass the driver mode after the -- delimiter but not sure if this will land. I currenlty have broken checks when using cmake integration due to the compiler intrinsics (xmmintrin.h) being leaked from 3rd party lib to my codebase and without driver-mode after --, clang-tidy crashes. |
| @rsniezek If someone will review & approve it, then it will land. |
| Let's move discussion from the other topic here. I have this minimalistic reproduction example: #include <xmmintrin.h> int main() { return 0; }With CMakeLists.txt: cmake_minimum_required(VERSION 3.26) project(testexe) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) find_program(CLANGTIDY clang-tidy REQUIRED) set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY};--checks=*; -p; ${CMAKE_BINARY_DIR}) add_executable(testexe main.cpp)When I run the compilation from cmake level I get a intrinsics errors: If I bypass cmake and ninja, and invoke the clang-tidy as I expect ninja is doing, I get exact same result: adding --driver-mode=g++ after the -- doesn't change anything, still the same errors. Would your merge improve this situation? EDIT: |
| @rsniezek No thats diffrent issue, you need to use xmmintrin.h from clang, usually it should work by default, but maybe clang-tidy and clang are installed in different folders. In such case you may need to add explicitly -isystem to location of xmmintrin.h |
| you are right, when prepended path to clang headres the check don't crash even with full compile commands after the -- Can this extra path be added with the extra-args[-before]? I seem to be unable to do this correctly. |
| nevermind, managed to do it. had to split "-isystem" and the path to separate --extra-arg-before and it worked. thanks agian! |
| bump |
5chmidti left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know enough about the driver to approve this, but I read this a few times and I think that this is correct. I just added a few small and non-functional nits
b132be4 to 37ed735 Compare | bump. |
37ed735 to 96703d7 Compare | Rebased, bump |
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 --.
96703d7 to d5154cf Compare | Rebased, bump |
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 --.