[clang-tools-extra] [clang-tidy] Fix handling --driver-mode= (PR #66553)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 15 14:48:00 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tidy
<details>
<summary>Changes</summary>
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
---
Full diff: https://github.com/llvm/llvm-project/pull/66553.diff
3 Files Affected:
- (modified) clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp (+102-25)
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5)
- (added) clang-tools-extra/test/clang-tidy/infrastructure/driver-mode.cpp (+57)
``````````diff
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;
+};
``````````
</details>
https://github.com/llvm/llvm-project/pull/66553
More information about the cfe-commits
mailing list