Skip to content

Commit d5154cf

Browse files
committed
[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 --.
1 parent 63d9ef5 commit d5154cf

File tree

3 files changed

+157
-7
lines changed

3 files changed

+157
-7
lines changed

clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,20 @@
1919
#include "../ClangTidyForceLinker.h"
2020
#include "../GlobList.h"
2121
#include "clang/Tooling/CommonOptionsParser.h"
22+
#include "clang/Tooling/Tooling.h"
23+
#include "llvm/ADT/STLExtras.h"
2224
#include "llvm/ADT/StringSet.h"
2325
#include "llvm/Support/InitLLVM.h"
2426
#include "llvm/Support/PluginLoader.h"
2527
#include "llvm/Support/Process.h"
2628
#include "llvm/Support/Signals.h"
2729
#include "llvm/Support/TargetSelect.h"
2830
#include "llvm/Support/WithColor.h"
31+
#include <algorithm>
32+
#include <iterator>
2933
#include <optional>
34+
#include <string>
35+
#include <vector>
3036

3137
using namespace clang::tooling;
3238
using namespace llvm;
@@ -476,7 +482,7 @@ static StringRef closest(StringRef Value, const StringSet<> &Allowed) {
476482
return Closest;
477483
}
478484

479-
static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n";
485+
static constexpr StringRef VerifyConfigWarningEnd = " [-verify-config]\n";
480486

481487
static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob,
482488
StringRef Source) {
@@ -551,9 +557,92 @@ static llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> createBaseFS() {
551557
return BaseFS;
552558
}
553559

560+
static void recreateOptionsParserIfNeeded(
561+
llvm::Expected<CommonOptionsParser> &OptionsParser,
562+
llvm::ArrayRef<const char *> Args,
563+
const ClangTidyOptions &EffectiveOptions) {
564+
565+
if (Args.empty())
566+
return;
567+
568+
const auto DoubleDashIt = llvm::find(Args, StringRef("--"));
569+
570+
// Exit if we don't have any compiler arguments
571+
if (DoubleDashIt == Args.end() || Args.back() == StringRef("--"))
572+
return;
573+
574+
auto IsDriverMode = [](StringRef Argument) {
575+
return Argument.starts_with("--driver-mode=");
576+
};
577+
578+
// Exit if --driver-mode= is explicitly passed in compiler arguments
579+
if (Args.end() !=
580+
std::find_if(std::next(DoubleDashIt), Args.end(), IsDriverMode))
581+
return;
582+
583+
std::vector<std::string> CommandArguments(std::next(DoubleDashIt),
584+
Args.end());
585+
586+
// Add clang-tool as program name if not added
587+
if (CommandArguments.empty() ||
588+
llvm::StringRef(CommandArguments.front()).starts_with("-"))
589+
CommandArguments.insert(CommandArguments.begin(), "clang-tool");
590+
591+
// Apply --extra-arg and --extra-arg-before to compiler arguments
592+
CommandArguments =
593+
OptionsParser->getArgumentsAdjuster()(CommandArguments, "");
594+
595+
// Apply ExtraArgsBefore from clang-tidy config to compiler arguments
596+
if (EffectiveOptions.ExtraArgsBefore)
597+
CommandArguments = tooling::getInsertArgumentAdjuster(
598+
*EffectiveOptions.ExtraArgsBefore,
599+
tooling::ArgumentInsertPosition::BEGIN)(CommandArguments, "");
600+
601+
// Apply ExtraArgs from clang-tidy config to compiler arguments
602+
if (EffectiveOptions.ExtraArgs)
603+
CommandArguments = tooling::getInsertArgumentAdjuster(
604+
*EffectiveOptions.ExtraArgs,
605+
tooling::ArgumentInsertPosition::END)(CommandArguments, "");
606+
607+
// Check if now we have --driver-mode=
608+
auto DriverModeIt = std::find_if(CommandArguments.begin(),
609+
CommandArguments.end(), IsDriverMode);
610+
if (DriverModeIt == CommandArguments.end()) {
611+
// Try to detect and add --driver-mode=
612+
const std::string ExeName = CommandArguments.front();
613+
tooling::addTargetAndModeForProgramName(CommandArguments, ExeName);
614+
DriverModeIt = llvm::find_if(CommandArguments, IsDriverMode);
615+
}
616+
617+
// Exit if there is no --driver-mode= at this stage
618+
if (DriverModeIt == CommandArguments.end())
619+
return;
620+
621+
std::vector<const char *> NewArgs = Args.vec();
622+
623+
// Find place to insert --driver-mode= into new args, best after program name.
624+
auto InsertIt =
625+
NewArgs.begin() + std::distance(Args.begin(), DoubleDashIt) + 1U;
626+
if (!StringRef(*InsertIt).starts_with("-"))
627+
++InsertIt;
628+
NewArgs.insert(InsertIt, DriverModeIt->c_str());
629+
630+
// Re-create CommonOptionsParser with assumption that
631+
// FixedCompilationDatabase::loadFromCommandLine will be now called with
632+
// proper --driver-mode=
633+
int ArgC = NewArgs.size();
634+
const char **ArgV = NewArgs.data();
635+
OptionsParser = CommonOptionsParser::create(ArgC, ArgV, ClangTidyCategory,
636+
cl::ZeroOrMore);
637+
}
638+
554639
int clangTidyMain(int argc, const char **argv) {
555640
llvm::InitLLVM X(argc, argv);
556641

642+
// Save original arguments because CommonOptionsParser::create will change
643+
// `argc`.
644+
llvm::ArrayRef<const char *> Args(argv, argc);
645+
557646
// Enable help for -load option, if plugins are enabled.
558647
if (cl::Option *LoadOpt = cl::getRegisteredOptions().lookup("load"))
559648
LoadOpt->addCategory(ClangTidyCategory);
@@ -586,6 +675,12 @@ int clangTidyMain(int argc, const char **argv) {
586675
SmallString<256> FilePath = makeAbsolute(FileName);
587676
ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath);
588677

678+
recreateOptionsParserIfNeeded(OptionsParser, Args, EffectiveOptions);
679+
if (!OptionsParser) {
680+
llvm::WithColor::error() << llvm::toString(OptionsParser.takeError());
681+
return 1;
682+
}
683+
589684
std::vector<std::string> EnabledChecks =
590685
getCheckNames(EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers);
591686

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,10 @@ Improvements to clang-query
106106
Improvements to clang-tidy
107107
--------------------------
108108

109-
- Improved :program:`clang-tidy`'s `--verify-config` flag by adding support for
110-
the configuration options of the `Clang Static Analyzer Checks
111-
<https://clang.llvm.org/docs/analyzer/checkers.html>`_.
112-
113-
- Improved :program:`run-clang-tidy.py` script. Fixed minor shutdown noise
114-
happening on certain platforms when interrupting the script.
109+
- Improved handling of `--driver-mode=`, now automatically deducing it from
110+
the compiler name after `--`, or properly utilizing it when passed as an
111+
extra argument during :program:`clang-tidy` invocation with explicit compiler
112+
arguments.
115113

116114
New checks
117115
^^^^^^^^^^
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// REQUIRES: shell
2+
// RUN: rm -rf "%t"
3+
// RUN: mkdir "%t"
4+
// RUN: cp "%s" "%t/code.cpp"
5+
// RUN: echo '' > "%t/.clang-tidy"
6+
7+
// Compile commands tests (explicit --driver-mode):
8+
// RUN: echo '[{"directory":"%t/","file":"code.cpp","command":"dummy-compiler /W4 code.cpp"}]' > "%t/compile_commands.json"
9+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
10+
// RUN: --extra-arg=--driver-mode=cl 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
11+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
12+
// RUN: --extra-arg-before=--driver-mode=cl 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
13+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
14+
// RUN: --config='{ExtraArgs: ["--driver-mode=cl"]}' 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
15+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
16+
// RUN: --config='{ExtraArgsBefore: ["--driver-mode=cl"]}' 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
17+
18+
// Compile commands tests (implicit --driver-mode):
19+
// RUN: echo '[{"directory":"%t/","file":"code.cpp","command":"cl.exe /W4 code.cpp"}]' > "%t/compile_commands.json"
20+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
21+
// RUN: 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
22+
23+
// Compile commands tests (negative)
24+
// RUN: echo '[{"directory":"%t/","file":"code.cpp","command":"dummy-compiler -MT /W4 code.cpp"}]' > "%t/compile_commands.json"
25+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
26+
// RUN: 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' --check-prefix=NEGATIVE_CHECK --allow-empty %s
27+
28+
// Command line tests (explicit --driver-mode):
29+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" "%t/code.cpp" \
30+
// RUN: -- --driver-mode=cl -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
31+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" "%t/code.cpp" \
32+
// RUN: --extra-arg=--driver-mode=cl -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
33+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" "%t/code.cpp" \
34+
// RUN: --extra-arg-before=--driver-mode=cl -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
35+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
36+
// RUN: --config='{ExtraArgs: ["--driver-mode=cl"]}' -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
37+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
38+
// RUN: --config='{ExtraArgsBefore: ["--driver-mode=cl"]}' -- -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
39+
40+
// Command line tests (implicit --driver-mode):
41+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
42+
// RUN: -- cl.exe -MD /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
43+
44+
// Command line tests (negative)
45+
// RUN: clang-tidy --checks="-*,clang-diagnostic-reorder-ctor,readability-redundant-string-cstr" -p="%t" "%t/code.cpp" \
46+
// RUN: -- dummy-compiler -MT /W4 code.cpp 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' --check-prefix=NEGATIVE_CHECK --allow-empty %s
47+
48+
struct string {};
49+
50+
struct A {
51+
A(string aa, string bb) : b(bb), a(aa) {}
52+
// CHECK: code.cpp:[[@LINE-1]]:31: warning: field 'b' will be initialized after field 'a' [clang-diagnostic-reorder-ctor]
53+
// NEGATIVE_CHECK-NOT: warning: field 'b' will be initialized after field 'a' [clang-diagnostic-reorder-ctor]
54+
55+
string a;
56+
string b;
57+
};

0 commit comments

Comments
 (0)