1 //===--- RangeSelector.cpp - RangeSelector implementations ------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
22 using namespace clang;
23 using namespace transformer;
25 using ast_matchers::MatchFinder;
26 using ast_type_traits::ASTNodeKind;
27 using ast_type_traits::DynTypedNode;
29 using llvm::StringError;
31 using MatchResult = MatchFinder::MatchResult;
33 static Error invalidArgumentError(Twine Message) {
34 return llvm::make_error<StringError>(llvm::errc::invalid_argument, Message);
37 static Error typeError(StringRef ID, const ASTNodeKind &Kind) {
38 return invalidArgumentError("mismatched type (node id=" + ID +
39 " kind=" + Kind.asStringRef() + ")");
42 static Error typeError(StringRef ID, const ASTNodeKind &Kind,
44 return invalidArgumentError("mismatched type: expected one of " +
45 ExpectedType + " (node id=" + ID +
46 " kind=" + Kind.asStringRef() + ")");
49 static Error missingPropertyError(StringRef ID, Twine Description,
51 return invalidArgumentError(Description + " requires property '" + Property +
52 "' (node id=" + ID + ")");
55 static Expected<DynTypedNode> getNode(const ast_matchers::BoundNodes &Nodes,
57 auto &NodesMap = Nodes.getMap();
58 auto It = NodesMap.find(ID);
59 if (It == NodesMap.end())
60 return invalidArgumentError("ID not bound: " + ID);
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();
71 SourceLocation BeforeStart = Start.getLocWithOffset(-1);
72 if (BeforeStart.isInvalid() || BeforeStart.isMacroID())
73 return SourceLocation();
75 return Lexer::GetBeginningOfToken(BeforeStart, SM, LangOpts);
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,
85 SourceLocation L = findPreviousTokenStart(Start, SM, LangOpts);
86 if (L.isInvalid() || L.isMacroID())
87 return SourceLocation();
90 if (Lexer::getRawToken(L, T, SM, LangOpts, /*IgnoreWhiteSpace=*/true))
91 return SourceLocation();
94 return T.getLocation();
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);
107 RangeSelector transformer::before(RangeSelector Selector) {
108 return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> {
109 Expected<CharSourceRange> SelectedRange = Selector(Result);
111 return SelectedRange.takeError();
112 return CharSourceRange::getCharRange(SelectedRange->getBegin());
116 RangeSelector transformer::after(RangeSelector Selector) {
117 return [Selector](const MatchResult &Result) -> Expected<CharSourceRange> {
118 Expected<CharSourceRange> SelectedRange = Selector(Result);
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()));
129 RangeSelector transformer::node(std::string ID) {
130 return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
131 Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
133 return Node.takeError();
134 return Node->get<Stmt>() != nullptr && Node->get<Expr>() == nullptr
135 ? tooling::getExtendedRange(*Node, tok::TokenKind::semi,
137 : CharSourceRange::getTokenRange(Node->getSourceRange());
141 RangeSelector transformer::statement(std::string ID) {
142 return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
143 Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
145 return Node.takeError();
146 return tooling::getExtendedRange(*Node, tok::TokenKind::semi,
151 RangeSelector transformer::range(RangeSelector Begin, RangeSelector End) {
152 return [Begin, End](const MatchResult &Result) -> Expected<CharSourceRange> {
153 Expected<CharSourceRange> BeginRange = Begin(Result);
155 return BeginRange.takeError();
156 Expected<CharSourceRange> EndRange = End(Result);
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");
166 return CharSourceRange(SourceRange(B, E), EndRange->isTokenRange());
170 RangeSelector transformer::range(std::string BeginID, std::string EndID) {
171 return transformer::range(node(std::move(BeginID)), node(std::move(EndID)));
174 RangeSelector transformer::member(std::string ID) {
175 return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
176 Expected<DynTypedNode> Node = getNode(Result.Nodes, ID);
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");
186 RangeSelector transformer::name(std::string ID) {
187 return [ID](const MatchResult &Result) -> Expected<CharSourceRange> {
188 Expected<DynTypedNode> N = getNode(Result.Nodes, ID);
190 return N.takeError();
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();
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);
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);
218 return typeError(ID, Node.getNodeKind(),
219 "DeclRefExpr, NamedDecl, CXXCtorInitializer");
224 // FIXME: make this available in the public API for users to easily create their
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
230 template <typename T, CharSourceRange (*Func)(const MatchResult &, const T &)>
231 class RelativeSelector {
235 RelativeSelector(std::string ID) : ID(std::move(ID)) {}
237 Expected<CharSourceRange> operator()(const MatchResult &Result) {
238 Expected<DynTypedNode> N = getNode(Result.Nodes, ID);
240 return N.takeError();
241 if (const auto *Arg = N->get<T>())
242 return Func(Result, *Arg);
243 return typeError(ID, N->getNodeKind());
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.
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),
261 RangeSelector transformer::statements(std::string ID) {
262 return RelativeSelector<CompoundStmt, getStatementsRange>(std::move(ID));
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),
276 RangeSelector transformer::callArgs(std::string ID) {
277 return RelativeSelector<CallExpr, getCallArgumentsRange>(std::move(ID));
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),
290 RangeSelector transformer::initListElements(std::string ID) {
291 return RelativeSelector<InitListExpr, getElementsRange>(std::move(ID));
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);
303 RangeSelector transformer::elseBranch(std::string ID) {
304 return RelativeSelector<IfStmt, getElseRange>(std::move(ID));
307 RangeSelector transformer::expansion(RangeSelector S) {
308 return [S](const MatchResult &Result) -> Expected<CharSourceRange> {
309 Expected<CharSourceRange> SRange = S(Result);
311 return SRange.takeError();
312 return Result.SourceManager->getExpansionRange(*SRange);