xref: /freebsd-src/contrib/llvm-project/clang/lib/Tooling/ArgumentsAdjusters.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- ArgumentsAdjusters.cpp - Command line arguments adjuster -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains definitions of classes which implement ArgumentsAdjuster
100b57cec5SDimitry Andric // interface.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/Tooling/ArgumentsAdjusters.h"
150b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
16480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
180b57cec5SDimitry Andric #include <cstddef>
19480093f4SDimitry Andric #include <vector>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace clang {
220b57cec5SDimitry Andric namespace tooling {
230b57cec5SDimitry Andric 
getDriverMode(const CommandLineArguments & Args)24e8d8bef9SDimitry Andric static StringRef getDriverMode(const CommandLineArguments &Args) {
25e8d8bef9SDimitry Andric   for (const auto &Arg : Args) {
26e8d8bef9SDimitry Andric     StringRef ArgRef = Arg;
27e8d8bef9SDimitry Andric     if (ArgRef.consume_front("--driver-mode=")) {
28e8d8bef9SDimitry Andric       return ArgRef;
29e8d8bef9SDimitry Andric     }
30e8d8bef9SDimitry Andric   }
31e8d8bef9SDimitry Andric   return StringRef();
32e8d8bef9SDimitry Andric }
33e8d8bef9SDimitry Andric 
34480093f4SDimitry Andric /// Add -fsyntax-only option and drop options that triggers output generation.
getClangSyntaxOnlyAdjuster()350b57cec5SDimitry Andric ArgumentsAdjuster getClangSyntaxOnlyAdjuster() {
360b57cec5SDimitry Andric   return [](const CommandLineArguments &Args, StringRef /*unused*/) {
370b57cec5SDimitry Andric     CommandLineArguments AdjustedArgs;
380b57cec5SDimitry Andric     bool HasSyntaxOnly = false;
395ffd83dbSDimitry Andric     constexpr llvm::StringRef OutputCommands[] = {
40480093f4SDimitry Andric         // FIXME: Add other options that generate output.
41480093f4SDimitry Andric         "-save-temps",
42480093f4SDimitry Andric         "--save-temps",
43480093f4SDimitry Andric     };
440b57cec5SDimitry Andric     for (size_t i = 0, e = Args.size(); i < e; ++i) {
450b57cec5SDimitry Andric       StringRef Arg = Args[i];
46480093f4SDimitry Andric       // Skip output commands.
47480093f4SDimitry Andric       if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) {
48*5f757f3fSDimitry Andric             return Arg.starts_with(OutputCommand);
49480093f4SDimitry Andric           }))
50480093f4SDimitry Andric         continue;
51480093f4SDimitry Andric 
52*5f757f3fSDimitry Andric       if (!Arg.starts_with("-fcolor-diagnostics") &&
53*5f757f3fSDimitry Andric           !Arg.starts_with("-fdiagnostics-color"))
540b57cec5SDimitry Andric         AdjustedArgs.push_back(Args[i]);
5547395794SDimitry Andric       // If we strip a color option, make sure we strip any preceeding `-Xclang`
5647395794SDimitry Andric       // option as well.
5747395794SDimitry Andric       // FIXME: This should be added to most argument adjusters!
5847395794SDimitry Andric       else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang")
5947395794SDimitry Andric         AdjustedArgs.pop_back();
6047395794SDimitry Andric 
610b57cec5SDimitry Andric       if (Arg == "-fsyntax-only")
620b57cec5SDimitry Andric         HasSyntaxOnly = true;
630b57cec5SDimitry Andric     }
640b57cec5SDimitry Andric     if (!HasSyntaxOnly)
65fe6060f1SDimitry Andric       AdjustedArgs =
66fe6060f1SDimitry Andric           getInsertArgumentAdjuster("-fsyntax-only")(AdjustedArgs, "");
670b57cec5SDimitry Andric     return AdjustedArgs;
680b57cec5SDimitry Andric   };
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
getClangStripOutputAdjuster()710b57cec5SDimitry Andric ArgumentsAdjuster getClangStripOutputAdjuster() {
720b57cec5SDimitry Andric   return [](const CommandLineArguments &Args, StringRef /*unused*/) {
730b57cec5SDimitry Andric     CommandLineArguments AdjustedArgs;
740b57cec5SDimitry Andric     for (size_t i = 0, e = Args.size(); i < e; ++i) {
750b57cec5SDimitry Andric       StringRef Arg = Args[i];
76*5f757f3fSDimitry Andric       if (!Arg.starts_with("-o"))
770b57cec5SDimitry Andric         AdjustedArgs.push_back(Args[i]);
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric       if (Arg == "-o") {
800b57cec5SDimitry Andric         // Output is specified as -o foo. Skip the next argument too.
810b57cec5SDimitry Andric         ++i;
820b57cec5SDimitry Andric       }
830b57cec5SDimitry Andric       // Else, the output is specified as -ofoo. Just do nothing.
840b57cec5SDimitry Andric     }
850b57cec5SDimitry Andric     return AdjustedArgs;
860b57cec5SDimitry Andric   };
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
getClangStripDependencyFileAdjuster()890b57cec5SDimitry Andric ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
900b57cec5SDimitry Andric   return [](const CommandLineArguments &Args, StringRef /*unused*/) {
91e8d8bef9SDimitry Andric     auto UsingClDriver = (getDriverMode(Args) == "cl");
92e8d8bef9SDimitry Andric 
930b57cec5SDimitry Andric     CommandLineArguments AdjustedArgs;
940b57cec5SDimitry Andric     for (size_t i = 0, e = Args.size(); i < e; ++i) {
950b57cec5SDimitry Andric       StringRef Arg = Args[i];
96e8d8bef9SDimitry Andric 
97e8d8bef9SDimitry Andric       // These flags take an argument: -MX foo. Skip the next argument also.
98e8d8bef9SDimitry Andric       if (!UsingClDriver && (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ")) {
99e8d8bef9SDimitry Andric         ++i;
1000b57cec5SDimitry Andric         continue;
1010b57cec5SDimitry Andric       }
102e8d8bef9SDimitry Andric       // When not using the cl driver mode, dependency file generation options
103e8d8bef9SDimitry Andric       // begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and
104e8d8bef9SDimitry Andric       // -MMD.
105*5f757f3fSDimitry Andric       if (!UsingClDriver && Arg.starts_with("-M"))
106e8d8bef9SDimitry Andric         continue;
107e8d8bef9SDimitry Andric       // Under MSVC's cl driver mode, dependency file generation is controlled
108e8d8bef9SDimitry Andric       // using /showIncludes
109*5f757f3fSDimitry Andric       if (Arg.starts_with("/showIncludes") || Arg.starts_with("-showIncludes"))
110e8d8bef9SDimitry Andric         continue;
1110b57cec5SDimitry Andric 
112e8d8bef9SDimitry Andric       AdjustedArgs.push_back(Args[i]);
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric     return AdjustedArgs;
1150b57cec5SDimitry Andric   };
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric 
getInsertArgumentAdjuster(const CommandLineArguments & Extra,ArgumentInsertPosition Pos)1180b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
1190b57cec5SDimitry Andric                                             ArgumentInsertPosition Pos) {
1200b57cec5SDimitry Andric   return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) {
1210b57cec5SDimitry Andric     CommandLineArguments Return(Args);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     CommandLineArguments::iterator I;
1240b57cec5SDimitry Andric     if (Pos == ArgumentInsertPosition::END) {
125bdd1243dSDimitry Andric       I = llvm::find(Return, "--");
1260b57cec5SDimitry Andric     } else {
1270b57cec5SDimitry Andric       I = Return.begin();
1280b57cec5SDimitry Andric       ++I; // To leave the program name in place
1290b57cec5SDimitry Andric     }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric     Return.insert(I, Extra.begin(), Extra.end());
1320b57cec5SDimitry Andric     return Return;
1330b57cec5SDimitry Andric   };
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
getInsertArgumentAdjuster(const char * Extra,ArgumentInsertPosition Pos)1360b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra,
1370b57cec5SDimitry Andric                                             ArgumentInsertPosition Pos) {
1380b57cec5SDimitry Andric   return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos);
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
combineAdjusters(ArgumentsAdjuster First,ArgumentsAdjuster Second)1410b57cec5SDimitry Andric ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
1420b57cec5SDimitry Andric                                    ArgumentsAdjuster Second) {
1430b57cec5SDimitry Andric   if (!First)
1440b57cec5SDimitry Andric     return Second;
1450b57cec5SDimitry Andric   if (!Second)
1460b57cec5SDimitry Andric     return First;
1470b57cec5SDimitry Andric   return [First, Second](const CommandLineArguments &Args, StringRef File) {
1480b57cec5SDimitry Andric     return Second(First(Args, File), File);
1490b57cec5SDimitry Andric   };
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
getStripPluginsAdjuster()1520b57cec5SDimitry Andric ArgumentsAdjuster getStripPluginsAdjuster() {
1530b57cec5SDimitry Andric   return [](const CommandLineArguments &Args, StringRef /*unused*/) {
1540b57cec5SDimitry Andric     CommandLineArguments AdjustedArgs;
1550b57cec5SDimitry Andric     for (size_t I = 0, E = Args.size(); I != E; I++) {
1560b57cec5SDimitry Andric       // According to https://clang.llvm.org/docs/ClangPlugins.html
1570b57cec5SDimitry Andric       // plugin arguments are in the form:
1580b57cec5SDimitry Andric       // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin}
1590b57cec5SDimitry Andric       // -Xclang <arbitrary-argument>
1600b57cec5SDimitry Andric       if (I + 4 < E && Args[I] == "-Xclang" &&
1610b57cec5SDimitry Andric           (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" ||
162*5f757f3fSDimitry Andric            llvm::StringRef(Args[I + 1]).starts_with("-plugin-arg-") ||
1630b57cec5SDimitry Andric            Args[I + 1] == "-add-plugin") &&
1640b57cec5SDimitry Andric           Args[I + 2] == "-Xclang") {
1650b57cec5SDimitry Andric         I += 3;
1660b57cec5SDimitry Andric         continue;
1670b57cec5SDimitry Andric       }
1680b57cec5SDimitry Andric       AdjustedArgs.push_back(Args[I]);
1690b57cec5SDimitry Andric     }
1700b57cec5SDimitry Andric     return AdjustedArgs;
1710b57cec5SDimitry Andric   };
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric } // end namespace tooling
1750b57cec5SDimitry Andric } // end namespace clang
176