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