clang: lib/Format/MacroExpander.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
16
28#include "llvm/ADT/StringSet.h"
29#include "llvm/Support/ErrorHandling.h"
30
32namespace format {
33
38
39
40
41
42
43 llvm::StringMap<size_t> ArgMap;
44
46};
47
49public:
51 assert(!Tokens.empty());
52 Current = Tokens[0];
53 }
54
55
56
58 if (Current->isNot(tok::identifier))
59 return {};
61 nextToken();
62 if (Current->is(tok::l_paren)) {
64 if (!parseParams())
65 return {};
66 }
67 if (!parseExpansion())
68 return {};
69
70 return Def;
71 }
72
73private:
74 bool parseParams() {
75 assert(Current->is(tok::l_paren));
76 nextToken();
77 while (Current->is(tok::identifier)) {
78 Def.Params.push_back(Current);
80 nextToken();
81 if (Current->isNot(tok::comma))
82 break;
83 nextToken();
84 }
85 if (Current->isNot(tok::r_paren))
86 return false;
87 nextToken();
88 return true;
89 }
90
91 bool parseExpansion() {
92 if (!Current->isOneOf(tok::equal, tok::eof))
93 return false;
94 if (Current->is(tok::equal))
95 nextToken();
96 parseTail();
97 return true;
98 }
99
100 void parseTail() {
101 while (Current->isNot(tok::eof)) {
102 Def.Body.push_back(Current);
103 nextToken();
104 }
105 Def.Body.push_back(Current);
106 }
107
108 void nextToken() {
109 if (Pos + 1 < Tokens.size())
110 ++Pos;
111 Current = Tokens[Pos];
113 }
114
115 size_t Pos = 0;
116 FormatToken *Current = nullptr;
118 ArrayRef<FormatToken *> Tokens;
119};
120
122 const std::vectorstd::string &Macros, SourceManager &SourceMgr,
124 llvm::SpecificBumpPtrAllocator &Allocator,
126 : SourceMgr(SourceMgr), Style(Style), Allocator(Allocator),
127 IdentTable(IdentTable) {
128 for (const std::string &Macro : Macros)
129 parseDefinition(Macro);
130}
131
133
134void MacroExpander::parseDefinition(const std::string &Macro) {
135 Buffers.push_back(
136 llvm::MemoryBuffer::getMemBufferCopy(Macro, ""));
137 FileID FID = SourceMgr.createFileID(Buffers.back()->getMemBufferRef());
139 Allocator, IdentTable);
140 const auto Tokens = Lex.lex();
141 if (!Tokens.empty()) {
142 DefinitionParser Parser(Tokens);
143 auto Definition = Parser.parse();
144 if (Definition.ObjectLike) {
145 ObjectLike[Definition.Name] = std::move(Definition);
146 } else {
147 FunctionLike[Definition.Name][Definition.Params.size()] =
148 std::move(Definition);
149 }
150 }
151}
152
154 return FunctionLike.contains(Name) || ObjectLike.contains(Name);
155}
156
158 return ObjectLike.contains(Name);
159}
160
162 auto it = FunctionLike.find(Name);
163 return it != FunctionLike.end() && it->second.contains(Arity);
164}
165
168 std::optional OptionalArgs) const {
169 if (OptionalArgs)
170 assert(hasArity(ID->TokenText, OptionalArgs->size()));
171 else
174 ? FunctionLike.find(ID->TokenText)
175 ->second.find(OptionalArgs.value().size())
176 ->second
177 : ObjectLike.find(ID->TokenText)->second;
178 ArgsList Args = OptionalArgs ? OptionalArgs.value() : ArgsList();
180
181 llvm::StringSet<> ExpandedArgs;
182
183
185 Tok->MacroCtx->ExpandedFrom.push_back(ID);
186 Result.push_back(Tok);
187 };
188
189
190
191 auto expandArgument = [&](FormatToken *Tok) -> bool {
192
193
194 if (Tok->isNot(tok::identifier))
195 return false;
196 if (!ExpandedArgs.insert(Tok->TokenText).second)
197 return false;
198 auto I = Def.ArgMap.find(Tok->TokenText);
199 if (I == Def.ArgMap.end())
200 return false;
201
202
203
204 if (I->getValue() >= Args.size())
205 return true;
206 for (FormatToken *Arg : Args[I->getValue()]) {
207
208
209
210
211
212 if (!Arg->MacroCtx)
214 pushToken(Arg);
215 }
216 return true;
217 };
218
219
221 if (expandArgument(Tok))
222 continue;
223
224
228
230 pushToken(New);
231 }
232 assert(Result.size() >= 1 && Result.back()->is(tok::eof));
233 if (Result.size() > 1) {
234 ++Result[0]->MacroCtx->StartOfExpansion;
235 ++Result[Result.size() - 2]->MacroCtx->EndOfExpansion;
236 } else {
237
238 Result[0]->MacroCtx->StartOfExpansion = 1;
239 Result[0]->MacroCtx->EndOfExpansion = 1;
240 }
242}
243
244}
245}
Contains functions for text encoding manipulation.
This file contains FormatTokenLexer, which tokenizes a source file into a token stream suitable for C...
This file contains the declaration of the FormatToken, a wrapper around Token with additional informa...
Various functions to configurably format source code.
This file contains the main building blocks of macro support in clang-format.
Defines the clang::Preprocessor interface.
Defines the clang::TokenKind enum and support functions.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements an efficient mapping from strings to IdentifierInfo nodes.
Parser - This implements a parser for the C family of languages.
This class handles loading and caching of source files into memory.
FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, SourceLocation::UIntTy LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
MacroExpander::Definition parse()
DefinitionParser(ArrayRef< FormatToken * > Tokens)
bool objectLike(StringRef Name) const
Returns whetherh there is an object-like overload, i.e.
SmallVector< FormatToken *, 8 > expand(FormatToken *ID, std::optional< ArgsList > OptionalArgs) const
Returns the expanded stream of format tokens for ID, where each element in Args is a positional argum...
ArrayRef< SmallVector< FormatToken *, 8 > > ArgsList
bool hasArity(StringRef Name, unsigned Arity) const
Returns whether macro Name provides an overload with the given arity.
MacroExpander(const std::vector< std::string > &Macros, SourceManager &SourceMgr, const FormatStyle &Style, llvm::SpecificBumpPtrAllocator< FormatToken > &Allocator, IdentifierTable &IdentTable)
Construct a macro expander from a set of macro definitions.
bool defined(StringRef Name) const
Returns whether any macro Name is defined, regardless of overloads.
@ MR_Hidden
The token was expanded from a macro definition, and is not visible as part of the macro call.
@ MR_ExpandedArg
The token was expanded from a macro argument when formatting the expanded token sequence.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
The FormatStyle is used to configure the formatting to follow specific guidelines.
A wrapper around a Token storing information about the whitespace characters preceding it.
StringRef TokenText
The raw text of the token.
unsigned Finalized
If true, this token has been fully formatted (indented and potentially re-formatted inside),...
std::optional< MacroExpansion > MacroCtx
bool is(tok::TokenKind Kind) const
bool isOneOf(A K1, B K2) const
void copyFrom(const FormatToken &Tok)
SmallVector< FormatToken *, 8 > Params
SmallVector< FormatToken *, 8 > Body
llvm::StringMap< size_t > ArgMap
Contains information on the token's role in a macro expansion.