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