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