1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "clang/Lex/MacroArgs.h" |
14 | #include "clang/Lex/LexDiagnostic.h" |
15 | #include "clang/Lex/MacroInfo.h" |
16 | #include "clang/Lex/Preprocessor.h" |
17 | #include "llvm/ADT/SmallString.h" |
18 | #include "llvm/Support/SaveAndRestore.h" |
19 | #include <algorithm> |
20 | |
21 | using namespace clang; |
22 | |
23 | |
24 | MacroArgs *MacroArgs::create(const MacroInfo *MI, |
25 | ArrayRef<Token> UnexpArgTokens, |
26 | bool VarargsElided, Preprocessor &PP) { |
27 | (0) . __assert_fail ("MI->isFunctionLike() && \"Can't have args for an object-like macro!\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 28, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(MI->isFunctionLike() && |
28 | (0) . __assert_fail ("MI->isFunctionLike() && \"Can't have args for an object-like macro!\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 28, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Can't have args for an object-like macro!"); |
29 | MacroArgs **ResultEnt = nullptr; |
30 | unsigned ClosestMatch = ~0U; |
31 | |
32 | |
33 | |
34 | for (MacroArgs **Entry = &PP.MacroArgCache; *Entry; |
35 | Entry = &(*Entry)->ArgCache) { |
36 | if ((*Entry)->NumUnexpArgTokens >= UnexpArgTokens.size() && |
37 | (*Entry)->NumUnexpArgTokens < ClosestMatch) { |
38 | ResultEnt = Entry; |
39 | |
40 | |
41 | if ((*Entry)->NumUnexpArgTokens == UnexpArgTokens.size()) |
42 | break; |
43 | |
44 | ClosestMatch = (*Entry)->NumUnexpArgTokens; |
45 | } |
46 | } |
47 | MacroArgs *Result; |
48 | if (!ResultEnt) { |
49 | |
50 | |
51 | Result = new ( |
52 | llvm::safe_malloc(totalSizeToAlloc<Token>(UnexpArgTokens.size()))) |
53 | MacroArgs(UnexpArgTokens.size(), VarargsElided, MI->getNumParams()); |
54 | } else { |
55 | Result = *ResultEnt; |
56 | |
57 | *ResultEnt = Result->ArgCache; |
58 | Result->NumUnexpArgTokens = UnexpArgTokens.size(); |
59 | Result->VarargsElided = VarargsElided; |
60 | Result->NumMacroArgs = MI->getNumParams(); |
61 | } |
62 | |
63 | |
64 | if (!UnexpArgTokens.empty()) { |
65 | static_assert(std::is_trivial<Token>::value, |
66 | "assume trivial copyability if copying into the " |
67 | "uninitialized array (as opposed to reusing a cached " |
68 | "MacroArgs)"); |
69 | std::copy(UnexpArgTokens.begin(), UnexpArgTokens.end(), |
70 | Result->getTrailingObjects<Token>()); |
71 | } |
72 | |
73 | return Result; |
74 | } |
75 | |
76 | |
77 | |
78 | void MacroArgs::destroy(Preprocessor &PP) { |
79 | StringifiedArgs.clear(); |
80 | |
81 | |
82 | |
83 | for (unsigned i = 0, e = PreExpArgTokens.size(); i != e; ++i) |
84 | PreExpArgTokens[i].clear(); |
85 | |
86 | |
87 | ArgCache = PP.MacroArgCache; |
88 | PP.MacroArgCache = this; |
89 | } |
90 | |
91 | |
92 | |
93 | MacroArgs *MacroArgs::deallocate() { |
94 | MacroArgs *Next = ArgCache; |
95 | |
96 | |
97 | this->~MacroArgs(); |
98 | |
99 | static_assert(std::is_trivially_destructible<Token>::value, |
100 | "assume trivially destructible and forego destructors"); |
101 | free(this); |
102 | |
103 | return Next; |
104 | } |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | unsigned MacroArgs::getArgLength(const Token *ArgPtr) { |
111 | unsigned NumArgTokens = 0; |
112 | for (; ArgPtr->isNot(tok::eof); ++ArgPtr) |
113 | ++NumArgTokens; |
114 | return NumArgTokens; |
115 | } |
116 | |
117 | |
118 | |
119 | |
120 | const Token *MacroArgs::getUnexpArgument(unsigned Arg) const { |
121 | |
122 | (0) . __assert_fail ("Arg < getNumMacroArguments() && \"Invalid arg #\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 122, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Arg < getNumMacroArguments() && "Invalid arg #"); |
123 | |
124 | |
125 | const Token *Start = getTrailingObjects<Token>(); |
126 | const Token *Result = Start; |
127 | |
128 | |
129 | for (; Arg; ++Result) { |
130 | (0) . __assert_fail ("Result < Start+NumUnexpArgTokens && \"Invalid arg #\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 130, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Result < Start+NumUnexpArgTokens && "Invalid arg #"); |
131 | if (Result->is(tok::eof)) |
132 | --Arg; |
133 | } |
134 | (0) . __assert_fail ("Result < Start+NumUnexpArgTokens && \"Invalid arg #\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 134, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Result < Start+NumUnexpArgTokens && "Invalid arg #"); |
135 | return Result; |
136 | } |
137 | |
138 | |
139 | |
140 | |
141 | |
142 | bool MacroArgs::invokedWithVariadicArgument(const MacroInfo *const MI) const { |
143 | if (!MI->isVariadic()) |
144 | return false; |
145 | const int VariadicArgIndex = getNumMacroArguments() - 1; |
146 | return getUnexpArgument(VariadicArgIndex)->isNot(tok::eof); |
147 | } |
148 | |
149 | |
150 | |
151 | bool MacroArgs::ArgNeedsPreexpansion(const Token *ArgTok, |
152 | Preprocessor &PP) const { |
153 | |
154 | |
155 | for (; ArgTok->isNot(tok::eof); ++ArgTok) |
156 | if (IdentifierInfo *II = ArgTok->getIdentifierInfo()) |
157 | if (II->hasMacroDefinition()) |
158 | |
159 | |
160 | return true; |
161 | return false; |
162 | } |
163 | |
164 | |
165 | |
166 | const std::vector<Token> &MacroArgs::getPreExpArgument(unsigned Arg, |
167 | Preprocessor &PP) { |
168 | (0) . __assert_fail ("Arg < getNumMacroArguments() && \"Invalid argument number!\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 168, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Arg < getNumMacroArguments() && "Invalid argument number!"); |
169 | |
170 | |
171 | if (PreExpArgTokens.size() < getNumMacroArguments()) |
172 | PreExpArgTokens.resize(getNumMacroArguments()); |
173 | |
174 | std::vector<Token> &Result = PreExpArgTokens[Arg]; |
175 | if (!Result.empty()) return Result; |
176 | |
177 | SaveAndRestore<bool> PreExpandingMacroArgs(PP.InMacroArgPreExpansion, true); |
178 | |
179 | const Token *AT = getUnexpArgument(Arg); |
180 | unsigned NumToks = getArgLength(AT)+1; |
181 | |
182 | |
183 | |
184 | |
185 | |
186 | PP.EnterTokenStream(AT, NumToks, false , |
187 | false ); |
188 | |
189 | |
190 | do { |
191 | Result.push_back(Token()); |
192 | Token &Tok = Result.back(); |
193 | PP.Lex(Tok); |
194 | } while (Result.back().isNot(tok::eof)); |
195 | |
196 | |
197 | |
198 | |
199 | |
200 | |
201 | if (PP.InCachingLexMode()) |
202 | PP.ExitCachingLexMode(); |
203 | PP.RemoveTopOfLexerStack(); |
204 | return Result; |
205 | } |
206 | |
207 | |
208 | |
209 | |
210 | |
211 | |
212 | |
213 | Token MacroArgs::StringifyArgument(const Token *ArgToks, |
214 | Preprocessor &PP, bool Charify, |
215 | SourceLocation ExpansionLocStart, |
216 | SourceLocation ExpansionLocEnd) { |
217 | Token Tok; |
218 | Tok.startToken(); |
219 | Tok.setKind(Charify ? tok::char_constant : tok::string_literal); |
220 | |
221 | const Token *ArgTokStart = ArgToks; |
222 | |
223 | |
224 | SmallString<128> Result; |
225 | Result += "\""; |
226 | |
227 | bool isFirst = true; |
228 | for (; ArgToks->isNot(tok::eof); ++ArgToks) { |
229 | const Token &Tok = *ArgToks; |
230 | if (!isFirst && (Tok.hasLeadingSpace() || Tok.isAtStartOfLine())) |
231 | Result += ' '; |
232 | isFirst = false; |
233 | |
234 | |
235 | |
236 | if (tok::isStringLiteral(Tok.getKind()) || |
237 | Tok.is(tok::char_constant) || |
238 | Tok.is(tok::wide_char_constant) || |
239 | Tok.is(tok::utf8_char_constant) || |
240 | Tok.is(tok::utf16_char_constant) || |
241 | Tok.is(tok::utf32_char_constant)) { |
242 | bool Invalid = false; |
243 | std::string TokStr = PP.getSpelling(Tok, &Invalid); |
244 | if (!Invalid) { |
245 | std::string Str = Lexer::Stringify(TokStr); |
246 | Result.append(Str.begin(), Str.end()); |
247 | } |
248 | } else if (Tok.is(tok::code_completion)) { |
249 | PP.CodeCompleteNaturalLanguage(); |
250 | } else { |
251 | |
252 | |
253 | unsigned CurStrLen = Result.size(); |
254 | Result.resize(CurStrLen+Tok.getLength()); |
255 | const char *BufPtr = Result.data() + CurStrLen; |
256 | bool Invalid = false; |
257 | unsigned ActualTokLen = PP.getSpelling(Tok, BufPtr, &Invalid); |
258 | |
259 | if (!Invalid) { |
260 | |
261 | |
262 | if (ActualTokLen && BufPtr != &Result[CurStrLen]) |
263 | memcpy(&Result[CurStrLen], BufPtr, ActualTokLen); |
264 | |
265 | |
266 | if (ActualTokLen != Tok.getLength()) |
267 | Result.resize(CurStrLen+ActualTokLen); |
268 | } |
269 | } |
270 | } |
271 | |
272 | |
273 | |
274 | if (Result.back() == '\\') { |
275 | |
276 | |
277 | unsigned FirstNonSlash = Result.size()-2; |
278 | |
279 | while (Result[FirstNonSlash] == '\\') |
280 | --FirstNonSlash; |
281 | if ((Result.size()-1-FirstNonSlash) & 1) { |
282 | |
283 | PP.Diag(ArgToks[-1], diag::pp_invalid_string_literal); |
284 | Result.pop_back(); |
285 | } |
286 | } |
287 | Result += '"'; |
288 | |
289 | |
290 | |
291 | if (Charify) { |
292 | |
293 | Result[0] = '\''; |
294 | Result[Result.size()-1] = '\''; |
295 | |
296 | |
297 | bool isBad = false; |
298 | if (Result.size() == 3) |
299 | isBad = Result[1] == '\''; |
300 | else |
301 | isBad = (Result.size() != 4 || Result[1] != '\\'); |
302 | |
303 | if (isBad) { |
304 | PP.Diag(ArgTokStart[0], diag::err_invalid_character_to_charify); |
305 | Result = "' '"; |
306 | } |
307 | } |
308 | |
309 | PP.CreateString(Result, Tok, |
310 | ExpansionLocStart, ExpansionLocEnd); |
311 | return Tok; |
312 | } |
313 | |
314 | |
315 | |
316 | const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, |
317 | Preprocessor &PP, |
318 | SourceLocation ExpansionLocStart, |
319 | SourceLocation ExpansionLocEnd) { |
320 | (0) . __assert_fail ("ArgNo < getNumMacroArguments() && \"Invalid argument number!\"", "/home/seafit/code_projects/clang_source/clang/lib/Lex/MacroArgs.cpp", 320, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(ArgNo < getNumMacroArguments() && "Invalid argument number!"); |
321 | if (StringifiedArgs.empty()) |
322 | StringifiedArgs.resize(getNumMacroArguments(), {}); |
323 | |
324 | if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) |
325 | StringifiedArgs[ArgNo] = StringifyArgument(getUnexpArgument(ArgNo), PP, |
326 | , |
327 | ExpansionLocStart, |
328 | ExpansionLocEnd); |
329 | return StringifiedArgs[ArgNo]; |
330 | } |
331 | |