1e5dd7070Spatrick //===- ArgumentsAdjusters.cpp - Command line arguments adjuster -----------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file contains definitions of classes which implement ArgumentsAdjuster
10e5dd7070Spatrick // interface.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/Tooling/ArgumentsAdjusters.h"
15e5dd7070Spatrick #include "clang/Basic/LLVM.h"
16e5dd7070Spatrick #include "llvm/ADT/STLExtras.h"
17e5dd7070Spatrick #include "llvm/ADT/StringRef.h"
18e5dd7070Spatrick #include <cstddef>
19e5dd7070Spatrick #include <vector>
20e5dd7070Spatrick
21e5dd7070Spatrick namespace clang {
22e5dd7070Spatrick namespace tooling {
23e5dd7070Spatrick
getDriverMode(const CommandLineArguments & Args)24a9ac8606Spatrick static StringRef getDriverMode(const CommandLineArguments &Args) {
25a9ac8606Spatrick for (const auto &Arg : Args) {
26a9ac8606Spatrick StringRef ArgRef = Arg;
27a9ac8606Spatrick if (ArgRef.consume_front("--driver-mode=")) {
28a9ac8606Spatrick return ArgRef;
29a9ac8606Spatrick }
30a9ac8606Spatrick }
31a9ac8606Spatrick return StringRef();
32a9ac8606Spatrick }
33a9ac8606Spatrick
34e5dd7070Spatrick /// Add -fsyntax-only option and drop options that triggers output generation.
getClangSyntaxOnlyAdjuster()35e5dd7070Spatrick ArgumentsAdjuster getClangSyntaxOnlyAdjuster() {
36e5dd7070Spatrick return [](const CommandLineArguments &Args, StringRef /*unused*/) {
37e5dd7070Spatrick CommandLineArguments AdjustedArgs;
38e5dd7070Spatrick bool HasSyntaxOnly = false;
39ec727ea7Spatrick constexpr llvm::StringRef OutputCommands[] = {
40e5dd7070Spatrick // FIXME: Add other options that generate output.
41e5dd7070Spatrick "-save-temps",
42e5dd7070Spatrick "--save-temps",
43e5dd7070Spatrick };
44e5dd7070Spatrick for (size_t i = 0, e = Args.size(); i < e; ++i) {
45e5dd7070Spatrick StringRef Arg = Args[i];
46e5dd7070Spatrick // Skip output commands.
47e5dd7070Spatrick if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) {
48e5dd7070Spatrick return Arg.startswith(OutputCommand);
49e5dd7070Spatrick }))
50e5dd7070Spatrick continue;
51e5dd7070Spatrick
52e5dd7070Spatrick if (!Arg.startswith("-fcolor-diagnostics") &&
53e5dd7070Spatrick !Arg.startswith("-fdiagnostics-color"))
54e5dd7070Spatrick AdjustedArgs.push_back(Args[i]);
55e5dd7070Spatrick // If we strip a color option, make sure we strip any preceeding `-Xclang`
56e5dd7070Spatrick // option as well.
57e5dd7070Spatrick // FIXME: This should be added to most argument adjusters!
58e5dd7070Spatrick else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang")
59e5dd7070Spatrick AdjustedArgs.pop_back();
60e5dd7070Spatrick
61e5dd7070Spatrick if (Arg == "-fsyntax-only")
62e5dd7070Spatrick HasSyntaxOnly = true;
63e5dd7070Spatrick }
64e5dd7070Spatrick if (!HasSyntaxOnly)
65a9ac8606Spatrick AdjustedArgs =
66a9ac8606Spatrick getInsertArgumentAdjuster("-fsyntax-only")(AdjustedArgs, "");
67e5dd7070Spatrick return AdjustedArgs;
68e5dd7070Spatrick };
69e5dd7070Spatrick }
70e5dd7070Spatrick
getClangStripOutputAdjuster()71e5dd7070Spatrick ArgumentsAdjuster getClangStripOutputAdjuster() {
72e5dd7070Spatrick return [](const CommandLineArguments &Args, StringRef /*unused*/) {
73e5dd7070Spatrick CommandLineArguments AdjustedArgs;
74e5dd7070Spatrick for (size_t i = 0, e = Args.size(); i < e; ++i) {
75e5dd7070Spatrick StringRef Arg = Args[i];
76e5dd7070Spatrick if (!Arg.startswith("-o"))
77e5dd7070Spatrick AdjustedArgs.push_back(Args[i]);
78e5dd7070Spatrick
79e5dd7070Spatrick if (Arg == "-o") {
80e5dd7070Spatrick // Output is specified as -o foo. Skip the next argument too.
81e5dd7070Spatrick ++i;
82e5dd7070Spatrick }
83e5dd7070Spatrick // Else, the output is specified as -ofoo. Just do nothing.
84e5dd7070Spatrick }
85e5dd7070Spatrick return AdjustedArgs;
86e5dd7070Spatrick };
87e5dd7070Spatrick }
88e5dd7070Spatrick
getClangStripDependencyFileAdjuster()89e5dd7070Spatrick ArgumentsAdjuster getClangStripDependencyFileAdjuster() {
90e5dd7070Spatrick return [](const CommandLineArguments &Args, StringRef /*unused*/) {
91a9ac8606Spatrick auto UsingClDriver = (getDriverMode(Args) == "cl");
92a9ac8606Spatrick
93e5dd7070Spatrick CommandLineArguments AdjustedArgs;
94e5dd7070Spatrick for (size_t i = 0, e = Args.size(); i < e; ++i) {
95e5dd7070Spatrick StringRef Arg = Args[i];
96a9ac8606Spatrick
97a9ac8606Spatrick // These flags take an argument: -MX foo. Skip the next argument also.
98a9ac8606Spatrick if (!UsingClDriver && (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ")) {
99a9ac8606Spatrick ++i;
100e5dd7070Spatrick continue;
101e5dd7070Spatrick }
102a9ac8606Spatrick // When not using the cl driver mode, dependency file generation options
103a9ac8606Spatrick // begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and
104a9ac8606Spatrick // -MMD.
105a9ac8606Spatrick if (!UsingClDriver && Arg.startswith("-M"))
106a9ac8606Spatrick continue;
107a9ac8606Spatrick // Under MSVC's cl driver mode, dependency file generation is controlled
108a9ac8606Spatrick // using /showIncludes
109a9ac8606Spatrick if (Arg.startswith("/showIncludes") || Arg.startswith("-showIncludes"))
110a9ac8606Spatrick continue;
111e5dd7070Spatrick
112a9ac8606Spatrick AdjustedArgs.push_back(Args[i]);
113e5dd7070Spatrick }
114e5dd7070Spatrick return AdjustedArgs;
115e5dd7070Spatrick };
116e5dd7070Spatrick }
117e5dd7070Spatrick
getInsertArgumentAdjuster(const CommandLineArguments & Extra,ArgumentInsertPosition Pos)118e5dd7070Spatrick ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra,
119e5dd7070Spatrick ArgumentInsertPosition Pos) {
120e5dd7070Spatrick return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) {
121e5dd7070Spatrick CommandLineArguments Return(Args);
122e5dd7070Spatrick
123e5dd7070Spatrick CommandLineArguments::iterator I;
124e5dd7070Spatrick if (Pos == ArgumentInsertPosition::END) {
125*12c85518Srobert I = llvm::find(Return, "--");
126e5dd7070Spatrick } else {
127e5dd7070Spatrick I = Return.begin();
128e5dd7070Spatrick ++I; // To leave the program name in place
129e5dd7070Spatrick }
130e5dd7070Spatrick
131e5dd7070Spatrick Return.insert(I, Extra.begin(), Extra.end());
132e5dd7070Spatrick return Return;
133e5dd7070Spatrick };
134e5dd7070Spatrick }
135e5dd7070Spatrick
getInsertArgumentAdjuster(const char * Extra,ArgumentInsertPosition Pos)136e5dd7070Spatrick ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra,
137e5dd7070Spatrick ArgumentInsertPosition Pos) {
138e5dd7070Spatrick return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos);
139e5dd7070Spatrick }
140e5dd7070Spatrick
combineAdjusters(ArgumentsAdjuster First,ArgumentsAdjuster Second)141e5dd7070Spatrick ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First,
142e5dd7070Spatrick ArgumentsAdjuster Second) {
143e5dd7070Spatrick if (!First)
144e5dd7070Spatrick return Second;
145e5dd7070Spatrick if (!Second)
146e5dd7070Spatrick return First;
147e5dd7070Spatrick return [First, Second](const CommandLineArguments &Args, StringRef File) {
148e5dd7070Spatrick return Second(First(Args, File), File);
149e5dd7070Spatrick };
150e5dd7070Spatrick }
151e5dd7070Spatrick
getStripPluginsAdjuster()152e5dd7070Spatrick ArgumentsAdjuster getStripPluginsAdjuster() {
153e5dd7070Spatrick return [](const CommandLineArguments &Args, StringRef /*unused*/) {
154e5dd7070Spatrick CommandLineArguments AdjustedArgs;
155e5dd7070Spatrick for (size_t I = 0, E = Args.size(); I != E; I++) {
156e5dd7070Spatrick // According to https://clang.llvm.org/docs/ClangPlugins.html
157e5dd7070Spatrick // plugin arguments are in the form:
158e5dd7070Spatrick // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin}
159e5dd7070Spatrick // -Xclang <arbitrary-argument>
160e5dd7070Spatrick if (I + 4 < E && Args[I] == "-Xclang" &&
161e5dd7070Spatrick (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" ||
162e5dd7070Spatrick llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") ||
163e5dd7070Spatrick Args[I + 1] == "-add-plugin") &&
164e5dd7070Spatrick Args[I + 2] == "-Xclang") {
165e5dd7070Spatrick I += 3;
166e5dd7070Spatrick continue;
167e5dd7070Spatrick }
168e5dd7070Spatrick AdjustedArgs.push_back(Args[I]);
169e5dd7070Spatrick }
170e5dd7070Spatrick return AdjustedArgs;
171e5dd7070Spatrick };
172e5dd7070Spatrick }
173e5dd7070Spatrick
174e5dd7070Spatrick } // end namespace tooling
175e5dd7070Spatrick } // end namespace clang
176