/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Transformer/RangeSelector.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- RangeSelector.cpp - RangeSelector implementations ------*- 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 | | #include "clang/Tooling/Transformer/RangeSelector.h" |
10 | | #include "clang/AST/Expr.h" |
11 | | #include "clang/AST/TypeLoc.h" |
12 | | #include "clang/ASTMatchers/ASTMatchFinder.h" |
13 | | #include "clang/Basic/SourceLocation.h" |
14 | | #include "clang/Lex/Lexer.h" |
15 | | #include "clang/Tooling/Transformer/SourceCode.h" |
16 | | #include "llvm/ADT/StringRef.h" |
17 | | #include "llvm/Support/Errc.h" |
18 | | #include "llvm/Support/Error.h" |
19 | | #include <string> |
20 | | #include <utility> |
21 | | #include <vector> |
22 | | |
23 | | using namespace clang; |
24 | | using namespace transformer; |
25 | | |
26 | | using ast_matchers::MatchFinder; |
27 | | using llvm::Error; |
28 | | using llvm::StringError; |
29 | | |
30 | | using MatchResult = MatchFinder::MatchResult; |
31 | | |
32 | 13 | static Error invalidArgumentError(Twine Message) { |
33 | 13 | return llvm::make_error<StringError>(llvm::errc::invalid_argument, Message); |
34 | 13 | } |
35 | | |
36 | 3 | static Error typeError(StringRef ID, const ASTNodeKind &Kind) { |
37 | 3 | return invalidArgumentError("mismatched type (node id=" + ID + |
38 | 3 | " kind=" + Kind.asStringRef() + ")"); |
39 | 3 | } |
40 | | |
41 | | static Error typeError(StringRef ID, const ASTNodeKind &Kind, |
42 | 1 | Twine ExpectedType) { |
43 | 1 | return invalidArgumentError("mismatched type: expected one of " + |
44 | 1 | ExpectedType + " (node id=" + ID + |
45 | 1 | " kind=" + Kind.asStringRef() + ")"); |
46 | 1 | } |
47 | | |
48 | | static Error missingPropertyError(StringRef ID, Twine Description, |
49 | 3 | StringRef Property) { |
50 | 3 | return invalidArgumentError(Description + " requires property '" + Property + |
51 | 3 | "' (node id=" + ID + ")"); |
52 | 3 | } |
53 | | |
54 | | static Expected<DynTypedNode> getNode(const ast_matchers::BoundNodes &Nodes, |
55 | 252 | StringRef ID) { |
56 | 252 | auto &NodesMap = Nodes.getMap(); |
57 | 252 | auto It = NodesMap.find(ID); |
58 | 252 | if (It == NodesMap.end()) |
59 | 6 | return invalidArgumentError("ID not bound: " + ID); |
60 | 246 | return It->second; |
61 | 252 | } |
62 | | |
63 | | // FIXME: handling of macros should be configurable. |
64 | | static SourceLocation findPreviousTokenStart(SourceLocation Start, |
65 | | const SourceManager &SM, |
66 | 24 | const LangOptions &LangOpts) { |
67 | 24 | if (Start.isInvalid() || Start.isMacroID()) |
68 | 0 | return SourceLocation(); |
69 | | |
70 | 24 | SourceLocation BeforeStart = Start.getLocWithOffset(-1); |
71 | 24 | if (BeforeStart.isInvalid() || BeforeStart.isMacroID()) |
72 | 0 | return SourceLocation(); |
73 | | |
74 | 24 | return Lexer::GetBeginningOfToken(BeforeStart, SM, LangOpts); |
75 | 24 | } |
76 | | |
77 | | // Finds the start location of the previous token of kind \p TK. |
78 | | // FIXME: handling of macros should be configurable. |
79 | | static SourceLocation findPreviousTokenKind(SourceLocation Start, |
80 | | const SourceManager &SM, |
81 | | const LangOptions &LangOpts, |
82 | 7 | tok::TokenKind TK) { |
83 | 24 | while (true) { |
84 | 24 | SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts); |
85 | 24 | if (L.isInvalid() || L.isMacroID()) |
86 | 0 | return SourceLocation(); |
87 | | |
88 | 24 | Token T; |
89 | 24 | if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true)) |
90 | 0 | return SourceLocation(); |
91 | | |
92 | 24 | if (T.is(TK)) |
93 | 7 | return T.getLocation(); |
94 | | |
95 | 17 | Start = L; |
96 | 17 | } |
97 | 7 | } |
98 | | |
99 | | static SourceLocation findOpenParen(const CallExpr &E, const SourceManager &SM, |
100 | 7 | const LangOptions &LangOpts) { |
101 | 7 | SourceLocation EndLoc = |
102 | 7 | E.getNumArgs() == 0 ? E.getRParenLoc()2 : E.getArg(0)->getBeginLoc()5 ; |
103 | 7 | return findPreviousTokenKind(EndLoc, SM, LangOpts, tok::TokenKind::l_paren); |
104 | 7 | } |
105 | | |
106 | 8 | RangeSelector transformer::before(RangeSelector Selector) { |
107 | 11 | return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> { |
108 | 11 | Expected<CharSourceRange> SelectedRange = Selector(Result); |
109 | 11 | if (!SelectedRange) |
110 | 0 | return SelectedRange.takeError(); |
111 | 11 | return CharSourceRange::getCharRange(SelectedRange->getBegin()); |
112 | 11 | }; |
113 | 8 | } |
114 | | |
115 | 10 | RangeSelector transformer::after(RangeSelector Selector) { |
116 | 10 | return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> { |
117 | 10 | Expected<CharSourceRange> SelectedRange = Selector(Result); |
118 | 10 | if (!SelectedRange) |
119 | 0 | return SelectedRange.takeError(); |
120 | 10 | SourceLocation End = SelectedRange->getEnd(); |
121 | 10 | if (SelectedRange->isTokenRange()) { |
122 | | // We need to find the actual (exclusive) end location from which to |
123 | | // create a new source range. However, that's not guaranteed to be valid, |
124 | | // even if the token location itself is valid. So, we create a token range |
125 | | // consisting only of the last token, then map that range back to the |
126 | | // source file. If that succeeds, we have a valid location for the end of |
127 | | // the generated range. |
128 | 9 | CharSourceRange Range = Lexer::makeFileCharRange( |
129 | 9 | CharSourceRange::getTokenRange(SelectedRange->getEnd()), |
130 | 9 | *Result.SourceManager, Result.Context->getLangOpts()); |
131 | 9 | if (Range.isInvalid()) |
132 | 0 | return invalidArgumentError( |
133 | 0 | "after: can't resolve sub-range to valid source range"); |
134 | 9 | End = Range.getEnd(); |
135 | 9 | } |
136 | | |
137 | 10 | return CharSourceRange::getCharRange(End); |
138 | 10 | }; |
139 | 10 | } |
140 | | |
141 | 111 | RangeSelector transformer::node(std::string ID) { |
142 | 170 | return [ID](const MatchResult &Result) -> Expected<CharSourceRange> { |
143 | 170 | Expected<DynTypedNode> Node = getNode(Result.Nodes, ID); |
144 | 170 | if (!Node) |
145 | 2 | return Node.takeError(); |
146 | 168 | return (Node->get<Decl>() != nullptr || |
147 | 168 | (137 Node->get<Stmt>() != nullptr137 && Node->get<Expr>() == nullptr133 )) |
148 | 168 | ? tooling::getExtendedRange(*Node, tok::TokenKind::semi, |
149 | 38 | *Result.Context) |
150 | 168 | : CharSourceRange::getTokenRange(Node->getSourceRange())130 ; |
151 | 170 | }; |
152 | 111 | } |
153 | | |
154 | 16 | RangeSelector transformer::statement(std::string ID) { |
155 | 16 | return [ID](const MatchResult &Result) -> Expected<CharSourceRange> { |
156 | 16 | Expected<DynTypedNode> Node = getNode(Result.Nodes, ID); |
157 | 16 | if (!Node) |
158 | 0 | return Node.takeError(); |
159 | 16 | return tooling::getExtendedRange(*Node, tok::TokenKind::semi, |
160 | 16 | *Result.Context); |
161 | 16 | }; |
162 | 16 | } |
163 | | |
164 | 10 | RangeSelector transformer::enclose(RangeSelector Begin, RangeSelector End) { |
165 | 22 | return [Begin, End](const MatchResult &Result) -> Expected<CharSourceRange> { |
166 | 22 | Expected<CharSourceRange> BeginRange = Begin(Result); |
167 | 22 | if (!BeginRange) |
168 | 0 | return BeginRange.takeError(); |
169 | 22 | Expected<CharSourceRange> EndRange = End(Result); |
170 | 22 | if (!EndRange) |
171 | 0 | return EndRange.takeError(); |
172 | 22 | SourceLocation B = BeginRange->getBegin(); |
173 | 22 | SourceLocation E = EndRange->getEnd(); |
174 | | // Note: we are precluding the possibility of sub-token ranges in the case |
175 | | // that EndRange is a token range. |
176 | 22 | if (Result.SourceManager->isBeforeInTranslationUnit(E, B)) { |
177 | 0 | return invalidArgumentError("Bad range: out of order"); |
178 | 0 | } |
179 | 22 | return CharSourceRange(SourceRange(B, E), EndRange->isTokenRange()); |
180 | 22 | }; |
181 | 10 | } |
182 | | |
183 | | RangeSelector transformer::encloseNodes(std::string BeginID, |
184 | 3 | std::string EndID) { |
185 | 3 | return transformer::enclose(node(std::move(BeginID)), node(std::move(EndID))); |
186 | 3 | } |
187 | | |
188 | 7 | RangeSelector transformer::member(std::string ID) { |
189 | 8 | return [ID](const MatchResult &Result) -> Expected<CharSourceRange> { |
190 | 8 | Expected<DynTypedNode> Node = getNode(Result.Nodes, ID); |
191 | 8 | if (!Node) |
192 | 0 | return Node.takeError(); |
193 | 8 | if (auto *M = Node->get<clang::MemberExpr>()) |
194 | 8 | return CharSourceRange::getTokenRange( |
195 | 8 | M->getMemberNameInfo().getSourceRange()); |
196 | 0 | return typeError(ID, Node->getNodeKind(), "MemberExpr"); |
197 | 8 | }; |
198 | 7 | } |
199 | | |
200 | 21 | RangeSelector transformer::name(std::string ID) { |
201 | 39 | return [ID](const MatchResult &Result) -> Expected<CharSourceRange> { |
202 | 39 | Expected<DynTypedNode> N = getNode(Result.Nodes, ID); |
203 | 39 | if (!N) |
204 | 1 | return N.takeError(); |
205 | 38 | auto &Node = *N; |
206 | 38 | if (const auto *D = Node.get<NamedDecl>()) { |
207 | 23 | if (!D->getDeclName().isIdentifier()) |
208 | 0 | return missingPropertyError(ID, "name", "identifier"); |
209 | 23 | SourceLocation L = D->getLocation(); |
210 | 23 | auto R = CharSourceRange::getTokenRange(L, L); |
211 | | // Verify that the range covers exactly the name. |
212 | | // FIXME: extend this code to support cases like `operator +` or |
213 | | // `foo<int>` for which this range will be too short. Doing so will |
214 | | // require subcasing `NamedDecl`, because it doesn't provide virtual |
215 | | // access to the \c DeclarationNameInfo. |
216 | 23 | if (tooling::getText(R, *Result.Context) != D->getName()) |
217 | 2 | return CharSourceRange(); |
218 | 21 | return R; |
219 | 23 | } |
220 | 15 | if (const auto *E = Node.get<DeclRefExpr>()) { |
221 | 9 | if (!E->getNameInfo().getName().isIdentifier()) |
222 | 3 | return missingPropertyError(ID, "name", "identifier"); |
223 | 6 | SourceLocation L = E->getLocation(); |
224 | 6 | return CharSourceRange::getTokenRange(L, L); |
225 | 9 | } |
226 | 6 | if (const auto *I = Node.get<CXXCtorInitializer>()) { |
227 | 1 | if (!I->isMemberInitializer() && I->isWritten()0 ) |
228 | 0 | return missingPropertyError(ID, "name", "explicit member initializer"); |
229 | 1 | SourceLocation L = I->getMemberLocation(); |
230 | 1 | return CharSourceRange::getTokenRange(L, L); |
231 | 1 | } |
232 | 5 | if (const auto *T = Node.get<TypeLoc>()) { |
233 | 4 | TypeLoc Loc = *T; |
234 | 4 | auto ET = Loc.getAs<ElaboratedTypeLoc>(); |
235 | 4 | if (!ET.isNull()) |
236 | 4 | Loc = ET.getNamedTypeLoc(); |
237 | 4 | if (auto SpecLoc = Loc.getAs<TemplateSpecializationTypeLoc>(); |
238 | 4 | !SpecLoc.isNull()) |
239 | 1 | return CharSourceRange::getTokenRange(SpecLoc.getTemplateNameLoc()); |
240 | 3 | return CharSourceRange::getTokenRange(Loc.getSourceRange()); |
241 | 4 | } |
242 | 1 | return typeError(ID, Node.getNodeKind(), |
243 | 1 | "DeclRefExpr, NamedDecl, CXXCtorInitializer, TypeLoc"); |
244 | 5 | }; |
245 | 21 | } |
246 | | |
247 | | namespace { |
248 | | // FIXME: make this available in the public API for users to easily create their |
249 | | // own selectors. |
250 | | |
251 | | // Creates a selector from a range-selection function \p Func, which selects a |
252 | | // range that is relative to a bound node id. \c T is the node type expected by |
253 | | // \p Func. |
254 | | template <typename T, CharSourceRange (*Func)(const MatchResult &, const T &)> |
255 | | class RelativeSelector { |
256 | | std::string ID; |
257 | | |
258 | | public: |
259 | 19 | RelativeSelector(std::string ID) : ID(std::move(ID)) {} RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::CompoundStmt, &((anonymous namespace)::getStatementsRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::CompoundStmt const&))>::RelativeSelector(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 259 | 4 | RelativeSelector(std::string ID) : ID(std::move(ID)) {} |
RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::CallExpr, &((anonymous namespace)::getCallArgumentsRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::CallExpr const&))>::RelativeSelector(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 259 | 9 | RelativeSelector(std::string ID) : ID(std::move(ID)) {} |
RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::InitListExpr, &((anonymous namespace)::getElementsRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::InitListExpr const&))>::RelativeSelector(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 259 | 4 | RelativeSelector(std::string ID) : ID(std::move(ID)) {} |
RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::IfStmt, &((anonymous namespace)::getElseRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::IfStmt const&))>::RelativeSelector(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 259 | 2 | RelativeSelector(std::string ID) : ID(std::move(ID)) {} |
|
260 | | |
261 | 19 | Expected<CharSourceRange> operator()(const MatchResult &Result) { |
262 | 19 | Expected<DynTypedNode> N = getNode(Result.Nodes, ID); |
263 | 19 | if (!N) |
264 | 3 | return N.takeError(); |
265 | 16 | if (const auto *Arg = N->get<T>()) |
266 | 13 | return Func(Result, *Arg); |
267 | 3 | return typeError(ID, N->getNodeKind()); |
268 | 16 | } RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::CompoundStmt, &((anonymous namespace)::getStatementsRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::CompoundStmt const&))>::operator()(clang::ast_matchers::MatchFinder::MatchResult const&) Line | Count | Source | 261 | 4 | Expected<CharSourceRange> operator()(const MatchResult &Result) { | 262 | 4 | Expected<DynTypedNode> N = getNode(Result.Nodes, ID); | 263 | 4 | if (!N) | 264 | 1 | return N.takeError(); | 265 | 3 | if (const auto *Arg = N->get<T>()) | 266 | 2 | return Func(Result, *Arg); | 267 | 1 | return typeError(ID, N->getNodeKind()); | 268 | 3 | } |
RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::CallExpr, &((anonymous namespace)::getCallArgumentsRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::CallExpr const&))>::operator()(clang::ast_matchers::MatchFinder::MatchResult const&) Line | Count | Source | 261 | 9 | Expected<CharSourceRange> operator()(const MatchResult &Result) { | 262 | 9 | Expected<DynTypedNode> N = getNode(Result.Nodes, ID); | 263 | 9 | if (!N) | 264 | 1 | return N.takeError(); | 265 | 8 | if (const auto *Arg = N->get<T>()) | 266 | 7 | return Func(Result, *Arg); | 267 | 1 | return typeError(ID, N->getNodeKind()); | 268 | 8 | } |
RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::InitListExpr, &((anonymous namespace)::getElementsRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::InitListExpr const&))>::operator()(clang::ast_matchers::MatchFinder::MatchResult const&) Line | Count | Source | 261 | 4 | Expected<CharSourceRange> operator()(const MatchResult &Result) { | 262 | 4 | Expected<DynTypedNode> N = getNode(Result.Nodes, ID); | 263 | 4 | if (!N) | 264 | 1 | return N.takeError(); | 265 | 3 | if (const auto *Arg = N->get<T>()) | 266 | 2 | return Func(Result, *Arg); | 267 | 1 | return typeError(ID, N->getNodeKind()); | 268 | 3 | } |
RangeSelector.cpp:(anonymous namespace)::RelativeSelector<clang::IfStmt, &((anonymous namespace)::getElseRange(clang::ast_matchers::MatchFinder::MatchResult const&, clang::IfStmt const&))>::operator()(clang::ast_matchers::MatchFinder::MatchResult const&) Line | Count | Source | 261 | 2 | Expected<CharSourceRange> operator()(const MatchResult &Result) { | 262 | 2 | Expected<DynTypedNode> N = getNode(Result.Nodes, ID); | 263 | 2 | if (!N) | 264 | 0 | return N.takeError(); | 265 | 2 | if (const auto *Arg = N->get<T>()) | 266 | 2 | return Func(Result, *Arg); | 267 | 0 | return typeError(ID, N->getNodeKind()); | 268 | 2 | } |
|
269 | | }; |
270 | | } // namespace |
271 | | |
272 | | // FIXME: Change the following functions from being in an anonymous namespace |
273 | | // to static functions, after the minimum Visual C++ has _MSC_VER >= 1915 |
274 | | // (equivalent to Visual Studio 2017 v15.8 or higher). Using the anonymous |
275 | | // namespace works around a bug in earlier versions. |
276 | | namespace { |
277 | | // Returns the range of the statements (all source between the braces). |
278 | | CharSourceRange getStatementsRange(const MatchResult &, |
279 | 2 | const CompoundStmt &CS) { |
280 | 2 | return CharSourceRange::getCharRange(CS.getLBracLoc().getLocWithOffset(1), |
281 | 2 | CS.getRBracLoc()); |
282 | 2 | } |
283 | | } // namespace |
284 | | |
285 | 4 | RangeSelector transformer::statements(std::string ID) { |
286 | 4 | return RelativeSelector<CompoundStmt, getStatementsRange>(std::move(ID)); |
287 | 4 | } |
288 | | |
289 | | namespace { |
290 | | // Returns the range of the source between the call's parentheses. |
291 | | CharSourceRange getCallArgumentsRange(const MatchResult &Result, |
292 | 7 | const CallExpr &CE) { |
293 | 7 | return CharSourceRange::getCharRange( |
294 | 7 | findOpenParen(CE, *Result.SourceManager, Result.Context->getLangOpts()) |
295 | 7 | .getLocWithOffset(1), |
296 | 7 | CE.getRParenLoc()); |
297 | 7 | } |
298 | | } // namespace |
299 | | |
300 | 9 | RangeSelector transformer::callArgs(std::string ID) { |
301 | 9 | return RelativeSelector<CallExpr, getCallArgumentsRange>(std::move(ID)); |
302 | 9 | } |
303 | | |
304 | | namespace { |
305 | | // Returns the range of the elements of the initializer list. Includes all |
306 | | // source between the braces. |
307 | | CharSourceRange getElementsRange(const MatchResult &, |
308 | 2 | const InitListExpr &E) { |
309 | 2 | return CharSourceRange::getCharRange(E.getLBraceLoc().getLocWithOffset(1), |
310 | 2 | E.getRBraceLoc()); |
311 | 2 | } |
312 | | } // namespace |
313 | | |
314 | 4 | RangeSelector transformer::initListElements(std::string ID) { |
315 | 4 | return RelativeSelector<InitListExpr, getElementsRange>(std::move(ID)); |
316 | 4 | } |
317 | | |
318 | | namespace { |
319 | | // Returns the range of the else branch, including the `else` keyword. |
320 | 2 | CharSourceRange getElseRange(const MatchResult &Result, const IfStmt &S) { |
321 | 2 | return tooling::maybeExtendRange( |
322 | 2 | CharSourceRange::getTokenRange(S.getElseLoc(), S.getEndLoc()), |
323 | 2 | tok::TokenKind::semi, *Result.Context); |
324 | 2 | } |
325 | | } // namespace |
326 | | |
327 | 2 | RangeSelector transformer::elseBranch(std::string ID) { |
328 | 2 | return RelativeSelector<IfStmt, getElseRange>(std::move(ID)); |
329 | 2 | } |
330 | | |
331 | 6 | RangeSelector transformer::expansion(RangeSelector S) { |
332 | 6 | return [S](const MatchResult &Result) -> Expected<CharSourceRange> { |
333 | 6 | Expected<CharSourceRange> SRange = S(Result); |
334 | 6 | if (!SRange) |
335 | 0 | return SRange.takeError(); |
336 | 6 | return Result.SourceManager->getExpansionRange(*SRange); |
337 | 6 | }; |
338 | 6 | } |