Coverage Report

Created: 2021-08-24 07:12

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