/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Format/MacroExpander.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- MacroExpander.cpp - Format C++ code --------------------*- C++ -*-===// |
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 | | /// \file |
10 | | /// This file contains the implementation of MacroExpander, which handles macro |
11 | | /// configuration and expansion while formatting. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "Macros.h" |
16 | | |
17 | | #include "Encoding.h" |
18 | | #include "FormatToken.h" |
19 | | #include "FormatTokenLexer.h" |
20 | | #include "clang/Basic/TokenKinds.h" |
21 | | #include "clang/Format/Format.h" |
22 | | #include "clang/Lex/HeaderSearch.h" |
23 | | #include "clang/Lex/HeaderSearchOptions.h" |
24 | | #include "clang/Lex/Lexer.h" |
25 | | #include "clang/Lex/ModuleLoader.h" |
26 | | #include "clang/Lex/Preprocessor.h" |
27 | | #include "clang/Lex/PreprocessorOptions.h" |
28 | | #include "llvm/ADT/StringSet.h" |
29 | | #include "llvm/Support/ErrorHandling.h" |
30 | | |
31 | | namespace clang { |
32 | | namespace format { |
33 | | |
34 | | struct MacroExpander::Definition { |
35 | | StringRef Name; |
36 | | SmallVector<FormatToken *, 8> Params; |
37 | | SmallVector<FormatToken *, 8> Body; |
38 | | |
39 | | // Map from each argument's name to its position in the argument list. |
40 | | // With "M(x, y) x + y": |
41 | | // x -> 0 |
42 | | // y -> 1 |
43 | | llvm::StringMap<size_t> ArgMap; |
44 | | |
45 | | bool ObjectLike = true; |
46 | | }; |
47 | | |
48 | | class MacroExpander::DefinitionParser { |
49 | | public: |
50 | 38 | DefinitionParser(ArrayRef<FormatToken *> Tokens) : Tokens(Tokens) { |
51 | 38 | assert(!Tokens.empty()); |
52 | 0 | Current = Tokens[0]; |
53 | 38 | } |
54 | | |
55 | | // Parse the token stream and return the corresponding Definition object. |
56 | | // Returns an empty definition object with a null-Name on error. |
57 | 38 | MacroExpander::Definition parse() { |
58 | 38 | if (!Current->is(tok::identifier)) |
59 | 0 | return {}; |
60 | 38 | Def.Name = Current->TokenText; |
61 | 38 | nextToken(); |
62 | 38 | if (Current->is(tok::l_paren)) { |
63 | 31 | Def.ObjectLike = false; |
64 | 31 | if (!parseParams()) |
65 | 7 | return {}; |
66 | 31 | } |
67 | 31 | if (!parseExpansion()) |
68 | 0 | return {}; |
69 | | |
70 | 31 | return Def; |
71 | 31 | } |
72 | | |
73 | | private: |
74 | 31 | bool parseParams() { |
75 | 31 | assert(Current->is(tok::l_paren)); |
76 | 0 | nextToken(); |
77 | 44 | while (Current->is(tok::identifier)) { |
78 | 39 | Def.Params.push_back(Current); |
79 | 39 | Def.ArgMap[Def.Params.back()->TokenText] = Def.Params.size() - 1; |
80 | 39 | nextToken(); |
81 | 39 | if (Current->isNot(tok::comma)) |
82 | 26 | break; |
83 | 13 | nextToken(); |
84 | 13 | } |
85 | 31 | if (Current->isNot(tok::r_paren)) |
86 | 7 | return false; |
87 | 24 | nextToken(); |
88 | 24 | return true; |
89 | 31 | } |
90 | | |
91 | 31 | bool parseExpansion() { |
92 | 31 | if (!Current->isOneOf(tok::equal, tok::eof)) |
93 | 0 | return false; |
94 | 31 | if (Current->is(tok::equal)) |
95 | 28 | nextToken(); |
96 | 31 | parseTail(); |
97 | 31 | return true; |
98 | 31 | } |
99 | | |
100 | 31 | void parseTail() { |
101 | 127 | while (Current->isNot(tok::eof)) { |
102 | 96 | Def.Body.push_back(Current); |
103 | 96 | nextToken(); |
104 | 96 | } |
105 | 31 | Def.Body.push_back(Current); |
106 | 31 | } |
107 | | |
108 | 269 | void nextToken() { |
109 | 269 | if (Pos + 1 < Tokens.size()) |
110 | 269 | ++Pos; |
111 | 269 | Current = Tokens[Pos]; |
112 | 269 | Current->Finalized = true; |
113 | 269 | } |
114 | | |
115 | | size_t Pos = 0; |
116 | | FormatToken *Current = nullptr; |
117 | | Definition Def; |
118 | | ArrayRef<FormatToken *> Tokens; |
119 | | }; |
120 | | |
121 | | MacroExpander::MacroExpander( |
122 | | const std::vector<std::string> &Macros, clang::SourceManager &SourceMgr, |
123 | | const FormatStyle &Style, |
124 | | llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator, |
125 | | IdentifierTable &IdentTable) |
126 | | : SourceMgr(SourceMgr), Style(Style), Allocator(Allocator), |
127 | 23 | IdentTable(IdentTable) { |
128 | 23 | for (const std::string &Macro : Macros) |
129 | 38 | parseDefinition(Macro); |
130 | 23 | } |
131 | | |
132 | 23 | MacroExpander::~MacroExpander() = default; |
133 | | |
134 | 38 | void MacroExpander::parseDefinition(const std::string &Macro) { |
135 | 38 | Buffers.push_back( |
136 | 38 | llvm::MemoryBuffer::getMemBufferCopy(Macro, "<scratch space>")); |
137 | 38 | clang::FileID FID = SourceMgr.createFileID(Buffers.back()->getMemBufferRef()); |
138 | 38 | FormatTokenLexer Lex(SourceMgr, FID, 0, Style, encoding::Encoding_UTF8, |
139 | 38 | Allocator, IdentTable); |
140 | 38 | const auto Tokens = Lex.lex(); |
141 | 38 | if (!Tokens.empty()) { |
142 | 38 | DefinitionParser Parser(Tokens); |
143 | 38 | auto Definition = Parser.parse(); |
144 | 38 | Definitions[Definition.Name] = std::move(Definition); |
145 | 38 | } |
146 | 38 | } |
147 | | |
148 | 51 | bool MacroExpander::defined(llvm::StringRef Name) const { |
149 | 51 | return Definitions.find(Name) != Definitions.end(); |
150 | 51 | } |
151 | | |
152 | 4 | bool MacroExpander::objectLike(llvm::StringRef Name) const { |
153 | 4 | return Definitions.find(Name)->second.ObjectLike; |
154 | 4 | } |
155 | | |
156 | | llvm::SmallVector<FormatToken *, 8> MacroExpander::expand(FormatToken *ID, |
157 | 37 | ArgsList Args) const { |
158 | 37 | assert(defined(ID->TokenText)); |
159 | 0 | SmallVector<FormatToken *, 8> Result; |
160 | 37 | const Definition &Def = Definitions.find(ID->TokenText)->second; |
161 | | |
162 | | // Expand each argument at most once. |
163 | 37 | llvm::StringSet<> ExpandedArgs; |
164 | | |
165 | | // Adds the given token to Result. |
166 | 222 | auto pushToken = [&](FormatToken *Tok) { |
167 | 222 | Tok->MacroCtx->ExpandedFrom.push_back(ID); |
168 | 222 | Result.push_back(Tok); |
169 | 222 | }; |
170 | | |
171 | | // If Tok references a parameter, adds the corresponding argument to Result. |
172 | | // Returns false if Tok does not reference a parameter. |
173 | 148 | auto expandArgument = [&](FormatToken *Tok) -> bool { |
174 | | // If the current token references a parameter, expand the corresponding |
175 | | // argument. |
176 | 148 | if (!Tok->is(tok::identifier) || ExpandedArgs.contains(Tok->TokenText)51 ) |
177 | 99 | return false; |
178 | 49 | ExpandedArgs.insert(Tok->TokenText); |
179 | 49 | auto I = Def.ArgMap.find(Tok->TokenText); |
180 | 49 | if (I == Def.ArgMap.end()) |
181 | 11 | return false; |
182 | | // If there are fewer arguments than referenced parameters, treat the |
183 | | // parameter as empty. |
184 | | // FIXME: Potentially fully abort the expansion instead. |
185 | 38 | if (I->getValue() >= Args.size()) |
186 | 1 | return true; |
187 | 112 | for (FormatToken *Arg : Args[I->getValue()])37 { |
188 | | // A token can be part of a macro argument at multiple levels. |
189 | | // For example, with "ID(x) x": |
190 | | // in ID(ID(x)), 'x' is expanded first as argument to the inner |
191 | | // ID, then again as argument to the outer ID. We keep the macro |
192 | | // role the token had from the inner expansion. |
193 | 112 | if (!Arg->MacroCtx) |
194 | 70 | Arg->MacroCtx = MacroExpansion(MR_ExpandedArg); |
195 | 112 | pushToken(Arg); |
196 | 112 | } |
197 | 37 | return true; |
198 | 38 | }; |
199 | | |
200 | | // Expand the definition into Result. |
201 | 148 | for (FormatToken *Tok : Def.Body) { |
202 | 148 | if (expandArgument(Tok)) |
203 | 38 | continue; |
204 | | // Create a copy of the tokens from the macro body, i.e. were not provided |
205 | | // by user code. |
206 | 110 | FormatToken *New = new (Allocator.Allocate()) FormatToken; |
207 | 110 | New->copyFrom(*Tok); |
208 | 110 | assert(!New->MacroCtx); |
209 | | // Tokens that are not part of the user code are not formatted. |
210 | 0 | New->MacroCtx = MacroExpansion(MR_Hidden); |
211 | 110 | pushToken(New); |
212 | 110 | } |
213 | 37 | assert(Result.size() >= 1 && Result.back()->is(tok::eof)); |
214 | 37 | if (Result.size() > 1) { |
215 | 34 | ++Result[0]->MacroCtx->StartOfExpansion; |
216 | 34 | ++Result[Result.size() - 2]->MacroCtx->EndOfExpansion; |
217 | 34 | } |
218 | 37 | return Result; |
219 | 37 | } |
220 | | |
221 | | } // namespace format |
222 | | } // namespace clang |