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 32a7dea167SDimitry Andric static Error invalidArgumentError(Twine Message) { 33a7dea167SDimitry Andric return llvm::make_error<StringError>(llvm::errc::invalid_argument, Message); 34a7dea167SDimitry Andric } 35a7dea167SDimitry Andric 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 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 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 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. 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. 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 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 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 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 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 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 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 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 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: 252a7dea167SDimitry Andric RelativeSelector(std::string ID) : ID(std::move(ID)) {} 253a7dea167SDimitry Andric 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). 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 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 284*0fca6ea1SDimitry Andric SourceLocation getRLoc(const CallExpr &E) { return E.getRParenLoc(); } 285*0fca6ea1SDimitry Andric 286*0fca6ea1SDimitry Andric SourceLocation getRLoc(const CXXConstructExpr &E) { 287*0fca6ea1SDimitry Andric return E.getParenOrBraceRange().getEnd(); 288*0fca6ea1SDimitry Andric } 289*0fca6ea1SDimitry Andric 290*0fca6ea1SDimitry Andric tok::TokenKind getStartToken(const CallExpr &E) { 291*0fca6ea1SDimitry Andric return tok::TokenKind::l_paren; 292*0fca6ea1SDimitry Andric } 293*0fca6ea1SDimitry Andric 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> 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> 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 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 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. 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 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. 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 352a7dea167SDimitry Andric RangeSelector transformer::elseBranch(std::string ID) { 353a7dea167SDimitry Andric return RelativeSelector<IfStmt, getElseRange>(std::move(ID)); 354a7dea167SDimitry Andric } 355a7dea167SDimitry Andric 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