xref: /llvm-project/clang/lib/Tooling/Transformer/RangeSelector.cpp (revision 6b931ab516616127ce4cd5a0ad5e37d5a1d1696b)
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