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