|
19 | 19 | #include "../ClangTidyForceLinker.h" |
20 | 20 | #include "../GlobList.h" |
21 | 21 | #include "clang/Tooling/CommonOptionsParser.h" |
| 22 | +#include "clang/Tooling/Tooling.h" |
| 23 | +#include "llvm/ADT/STLExtras.h" |
22 | 24 | #include "llvm/ADT/StringSet.h" |
23 | 25 | #include "llvm/Support/InitLLVM.h" |
24 | 26 | #include "llvm/Support/PluginLoader.h" |
25 | 27 | #include "llvm/Support/Process.h" |
26 | 28 | #include "llvm/Support/Signals.h" |
27 | 29 | #include "llvm/Support/TargetSelect.h" |
28 | 30 | #include "llvm/Support/WithColor.h" |
| 31 | +#include <algorithm> |
| 32 | +#include <iterator> |
29 | 33 | #include <optional> |
| 34 | +#include <string> |
| 35 | +#include <vector> |
30 | 36 |
|
31 | 37 | using namespace clang::tooling; |
32 | 38 | using namespace llvm; |
@@ -476,7 +482,7 @@ static StringRef closest(StringRef Value, const StringSet<> &Allowed) { |
476 | 482 | return Closest; |
477 | 483 | } |
478 | 484 |
|
479 | | -static constexpr StringLiteral VerifyConfigWarningEnd = " [-verify-config]\n"; |
| 485 | +static constexpr StringRef VerifyConfigWarningEnd = " [-verify-config]\n"; |
480 | 486 |
|
481 | 487 | static bool verifyChecks(const StringSet<> &AllChecks, StringRef CheckGlob, |
482 | 488 | StringRef Source) { |
@@ -551,9 +557,92 @@ static llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> createBaseFS() { |
551 | 557 | return BaseFS; |
552 | 558 | } |
553 | 559 |
|
| 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 | + |
554 | 639 | int clangTidyMain(int argc, const char **argv) { |
555 | 640 | llvm::InitLLVM X(argc, argv); |
556 | 641 |
|
| 642 | + // Save original arguments because CommonOptionsParser::create will change |
| 643 | + // `argc`. |
| 644 | + llvm::ArrayRef<const char *> Args(argv, argc); |
| 645 | + |
557 | 646 | // Enable help for -load option, if plugins are enabled. |
558 | 647 | if (cl::Option *LoadOpt = cl::getRegisteredOptions().lookup("load")) |
559 | 648 | LoadOpt->addCategory(ClangTidyCategory); |
@@ -586,6 +675,12 @@ int clangTidyMain(int argc, const char **argv) { |
586 | 675 | SmallString<256> FilePath = makeAbsolute(FileName); |
587 | 676 | ClangTidyOptions EffectiveOptions = OptionsProvider->getOptions(FilePath); |
588 | 677 |
|
| 678 | + recreateOptionsParserIfNeeded(OptionsParser, Args, EffectiveOptions); |
| 679 | + if (!OptionsParser) { |
| 680 | + llvm::WithColor::error() << llvm::toString(OptionsParser.takeError()); |
| 681 | + return 1; |
| 682 | + } |
| 683 | + |
589 | 684 | std::vector<std::string> EnabledChecks = |
590 | 685 | getCheckNames(EffectiveOptions, AllowEnablingAnalyzerAlphaCheckers); |
591 | 686 |
|
|
0 commit comments