Coverage Report

Created: 2020-02-15 09:57

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