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