Coverage Report

Created: 2020-10-24 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Tooling/Transformer/Parsing.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- Parsing.cpp - Parsing function 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/Parsing.h"
10
#include "clang/AST/Expr.h"
11
#include "clang/ASTMatchers/ASTMatchFinder.h"
12
#include "clang/Basic/CharInfo.h"
13
#include "clang/Basic/SourceLocation.h"
14
#include "clang/Lex/Lexer.h"
15
#include "clang/Tooling/Transformer/RangeSelector.h"
16
#include "clang/Tooling/Transformer/SourceCode.h"
17
#include "llvm/ADT/None.h"
18
#include "llvm/ADT/StringMap.h"
19
#include "llvm/ADT/StringRef.h"
20
#include "llvm/Support/Errc.h"
21
#include "llvm/Support/Error.h"
22
#include <string>
23
#include <utility>
24
#include <vector>
25
26
using namespace clang;
27
using namespace transformer;
28
29
// FIXME: This implementation is entirely separate from that of the AST
30
// matchers. Given the similarity of the languages and uses of the two parsers,
31
// the two should share a common parsing infrastructure, as should other
32
// Transformer types. We intend to unify this implementation soon to share as
33
// much as possible with the AST Matchers parsing.
34
35
namespace {
36
using llvm::Error;
37
using llvm::Expected;
38
39
template <typename... Ts> using RangeSelectorOp = RangeSelector (*)(Ts...);
40
41
struct ParseState {
42
  // The remaining input to be processed.
43
  StringRef Input;
44
  // The original input. Not modified during parsing; only for reference in
45
  // error reporting.
46
  StringRef OriginalInput;
47
};
48
49
// Represents an intermediate result returned by a parsing function. Functions
50
// that don't generate values should use `llvm::None`
51
template <typename ResultType> struct ParseProgress {
52
  ParseState State;
53
  // Intermediate result generated by the Parser.
54
  ResultType Value;
55
};
56
57
template <typename T> using ExpectedProgress = llvm::Expected<ParseProgress<T>>;
58
template <typename T> using ParseFunction = ExpectedProgress<T> (*)(ParseState);
59
60
class ParseError : public llvm::ErrorInfo<ParseError> {
61
public:
62
  // Required field for all ErrorInfo derivatives.
63
  static char ID;
64
65
  ParseError(size_t Pos, std::string ErrorMsg, std::string InputExcerpt)
66
      : Pos(Pos), ErrorMsg(std::move(ErrorMsg)),
67
0
        Excerpt(std::move(InputExcerpt)) {}
68
69
0
  void log(llvm::raw_ostream &OS) const override {
70
0
    OS << "parse error at position (" << Pos << "): " << ErrorMsg
71
0
       << ": " + Excerpt;
72
0
  }
73
74
0
  std::error_code convertToErrorCode() const override {
75
0
    return llvm::inconvertibleErrorCode();
76
0
  }
77
78
  // Position of the error in the input string.
79
  size_t Pos;
80
  std::string ErrorMsg;
81
  // Excerpt of the input starting at the error position.
82
  std::string Excerpt;
83
};
84
85
char ParseError::ID;
86
} // namespace
87
88
static const llvm::StringMap<RangeSelectorOp<std::string>> &
89
8
getUnaryStringSelectors() {
90
8
  static const llvm::StringMap<RangeSelectorOp<std::string>> M = {
91
8
      {"name", name},
92
8
      {"node", node},
93
8
      {"statement", statement},
94
8
      {"statements", statements},
95
8
      {"member", member},
96
8
      {"callArgs", callArgs},
97
8
      {"elseBranch", elseBranch},
98
8
      {"initListElements", initListElements}};
99
8
  return M;
100
8
}
101
102
static const llvm::StringMap<RangeSelectorOp<RangeSelector>> &
103
4
getUnaryRangeSelectors() {
104
4
  static const llvm::StringMap<RangeSelectorOp<RangeSelector>> M = {
105
4
      {"before", before}, {"after", after}, {"expansion", expansion}};
106
4
  return M;
107
4
}
108
109
static const llvm::StringMap<RangeSelectorOp<std::string, std::string>> &
110
3
getBinaryStringSelectors() {
111
3
  static const llvm::StringMap<RangeSelectorOp<std::string, std::string>> M = {
112
3
      {"encloseNodes", encloseNodes}};
113
3
  return M;
114
3
}
115
116
static const llvm::StringMap<RangeSelectorOp<RangeSelector, RangeSelector>> &
117
1
getBinaryRangeSelectors() {
118
1
  static const llvm::StringMap<RangeSelectorOp<RangeSelector, RangeSelector>>
119
1
      M = {{"enclose", enclose}, {"between", between}};
120
1
  return M;
121
1
}
122
123
template <typename Element>
124
llvm::Optional<Element> findOptional(const llvm::StringMap<Element> &Map,
125
16
                                     llvm::StringRef Key) {
126
16
  auto it = Map.find(Key);
127
16
  if (it == Map.end())
128
8
    return llvm::None;
129
8
  return it->second;
130
8
}
llvm::Optional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)> findOptional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)>(llvm::StringMap<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >), llvm::MallocAllocator> const&, llvm::StringRef)
Line
Count
Source
125
8
                                     llvm::StringRef Key) {
126
8
  auto it = Map.find(Key);
127
8
  if (it == Map.end())
128
4
    return llvm::None;
129
4
  return it->second;
130
4
}
llvm::Optional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>)> findOptional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>)>(llvm::StringMap<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>), llvm::MallocAllocator> const&, llvm::StringRef)
Line
Count
Source
125
4
                                     llvm::StringRef Key) {
126
4
  auto it = Map.find(Key);
127
4
  if (it == Map.end())
128
3
    return llvm::None;
129
1
  return it->second;
130
1
}
llvm::Optional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)> findOptional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)>(llvm::StringMap<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >), llvm::MallocAllocator> const&, llvm::StringRef)
Line
Count
Source
125
3
                                     llvm::StringRef Key) {
126
3
  auto it = Map.find(Key);
127
3
  if (it == Map.end())
128
1
    return llvm::None;
129
2
  return it->second;
130
2
}
llvm::Optional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>, std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>)> findOptional<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>, std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>)>(llvm::StringMap<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>, std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>), llvm::MallocAllocator> const&, llvm::StringRef)
Line
Count
Source
125
1
                                     llvm::StringRef Key) {
126
1
  auto it = Map.find(Key);
127
1
  if (it == Map.end())
128
0
    return llvm::None;
129
1
  return it->second;
130
1
}
131
132
template <typename ResultType>
133
ParseProgress<ResultType> makeParseProgress(ParseState State,
134
43
                                            ResultType Result) {
135
43
  return ParseProgress<ResultType>{State, std::move(Result)};
136
43
}
Parsing.cpp:(anonymous namespace)::ParseProgress<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > makeParseProgress<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >((anonymous namespace)::ParseState, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)
Line
Count
Source
134
16
                                            ResultType Result) {
135
16
  return ParseProgress<ResultType>{State, std::move(Result)};
136
16
}
Parsing.cpp:(anonymous namespace)::ParseProgress<llvm::NoneType> makeParseProgress<llvm::NoneType>((anonymous namespace)::ParseState, llvm::NoneType)
Line
Count
Source
134
19
                                            ResultType Result) {
135
19
  return ParseProgress<ResultType>{State, std::move(Result)};
136
19
}
Parsing.cpp:(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > makeParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> >((anonymous namespace)::ParseState, std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>)
Line
Count
Source
134
8
                                            ResultType Result) {
135
8
  return ParseProgress<ResultType>{State, std::move(Result)};
136
8
}
137
138
0
static llvm::Error makeParseError(const ParseState &S, std::string ErrorMsg) {
139
0
  size_t Pos = S.OriginalInput.size() - S.Input.size();
140
0
  return llvm::make_error<ParseError>(Pos, std::move(ErrorMsg),
141
0
                                      S.OriginalInput.substr(Pos, 20).str());
142
0
}
143
144
// Returns a new ParseState that advances \c S by \c N characters.
145
35
static ParseState advance(ParseState S, size_t N) {
146
35
  S.Input = S.Input.drop_front(N);
147
35
  return S;
148
35
}
149
150
40
static StringRef consumeWhitespace(StringRef S) {
151
38
  return S.drop_while([](char c) { return isASCII(c) && isWhitespace(c); });
152
40
}
153
154
// Parses a single expected character \c c from \c State, skipping preceding
155
// whitespace.  Error if the expected character isn't found.
156
19
static ExpectedProgress<llvm::NoneType> parseChar(char c, ParseState State) {
157
19
  State.Input = consumeWhitespace(State.Input);
158
19
  if (State.Input.empty() || State.Input.front() != c)
159
0
    return makeParseError(State,
160
0
                          ("expected char not found: " + llvm::Twine(c)).str());
161
19
  return makeParseProgress(advance(State, 1), llvm::None);
162
19
}
163
164
// Parses an identitifer "token" -- handles preceding whitespace.
165
8
static ExpectedProgress<std::string> parseId(ParseState State) {
166
8
  State.Input = consumeWhitespace(State.Input);
167
8
  auto Id = State.Input.take_while(
168
66
      [](char c) { return isASCII(c) && isIdentifierBody(c); });
169
8
  if (Id.empty())
170
0
    return makeParseError(State, "failed to parse name");
171
8
  return makeParseProgress(advance(State, Id.size()), Id.str());
172
8
}
173
174
// For consistency with the AST matcher parser and C++ code, node ids are
175
// written as strings. However, we do not support escaping in the string.
176
8
static ExpectedProgress<std::string> parseStringId(ParseState State) {
177
8
  State.Input = consumeWhitespace(State.Input);
178
8
  if (State.Input.empty())
179
0
    return makeParseError(State, "unexpected end of input");
180
8
  if (!State.Input.consume_front("\""))
181
0
    return makeParseError(
182
0
        State,
183
0
        "expecting string, but encountered other character or end of input");
184
185
26
  
StringRef Id = State.Input.take_until([](char c) 8
{ return c == '"'; });
186
8
  if (State.Input.size() == Id.size())
187
0
    return makeParseError(State, "unterminated string");
188
  // Advance past the trailing quote as well.
189
8
  return makeParseProgress(advance(State, Id.size() + 1), Id.str());
190
8
}
191
192
// Parses a single element surrounded by parens. `Op` is applied to the parsed
193
// result to create the result of this function call.
194
template <typename T>
195
ExpectedProgress<RangeSelector> parseSingle(ParseFunction<T> ParseElement,
196
                                            RangeSelectorOp<T> Op,
197
5
                                            ParseState State) {
198
5
  auto P = parseChar('(', State);
199
5
  if (!P)
200
0
    return P.takeError();
201
202
5
  auto E = ParseElement(P->State);
203
5
  if (!E)
204
0
    return E.takeError();
205
206
5
  P = parseChar(')', E->State);
207
5
  if (!P)
208
0
    return P.takeError();
209
210
5
  return makeParseProgress(P->State, Op(std::move(E->Value)));
211
5
}
Parsing.cpp:llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > > parseSingle<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > (*)((anonymous namespace)::ParseState), std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >), (anonymous namespace)::ParseState)
Line
Count
Source
197
4
                                            ParseState State) {
198
4
  auto P = parseChar('(', State);
199
4
  if (!P)
200
0
    return P.takeError();
201
202
4
  auto E = ParseElement(P->State);
203
4
  if (!E)
204
0
    return E.takeError();
205
206
4
  P = parseChar(')', E->State);
207
4
  if (!P)
208
0
    return P.takeError();
209
210
4
  return makeParseProgress(P->State, Op(std::move(E->Value)));
211
4
}
Parsing.cpp:llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > > parseSingle<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> >(llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > > (*)((anonymous namespace)::ParseState), std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>), (anonymous namespace)::ParseState)
Line
Count
Source
197
1
                                            ParseState State) {
198
1
  auto P = parseChar('(', State);
199
1
  if (!P)
200
0
    return P.takeError();
201
202
1
  auto E = ParseElement(P->State);
203
1
  if (!E)
204
0
    return E.takeError();
205
206
1
  P = parseChar(')', E->State);
207
1
  if (!P)
208
0
    return P.takeError();
209
210
1
  return makeParseProgress(P->State, Op(std::move(E->Value)));
211
1
}
212
213
// Parses a pair of elements surrounded by parens and separated by comma. `Op`
214
// is applied to the parsed results to create the result of this function call.
215
template <typename T>
216
ExpectedProgress<RangeSelector> parsePair(ParseFunction<T> ParseElement,
217
                                          RangeSelectorOp<T, T> Op,
218
3
                                          ParseState State) {
219
3
  auto P = parseChar('(', State);
220
3
  if (!P)
221
0
    return P.takeError();
222
223
3
  auto Left = ParseElement(P->State);
224
3
  if (!Left)
225
0
    return Left.takeError();
226
227
3
  P = parseChar(',', Left->State);
228
3
  if (!P)
229
0
    return P.takeError();
230
231
3
  auto Right = ParseElement(P->State);
232
3
  if (!Right)
233
0
    return Right.takeError();
234
235
3
  P = parseChar(')', Right->State);
236
3
  if (!P)
237
0
    return P.takeError();
238
239
3
  return makeParseProgress(P->State,
240
3
                           Op(std::move(Left->Value), std::move(Right->Value)));
241
3
}
Parsing.cpp:llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > > parsePair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > (*)((anonymous namespace)::ParseState), std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >), (anonymous namespace)::ParseState)
Line
Count
Source
218
2
                                          ParseState State) {
219
2
  auto P = parseChar('(', State);
220
2
  if (!P)
221
0
    return P.takeError();
222
223
2
  auto Left = ParseElement(P->State);
224
2
  if (!Left)
225
0
    return Left.takeError();
226
227
2
  P = parseChar(',', Left->State);
228
2
  if (!P)
229
0
    return P.takeError();
230
231
2
  auto Right = ParseElement(P->State);
232
2
  if (!Right)
233
0
    return Right.takeError();
234
235
2
  P = parseChar(')', Right->State);
236
2
  if (!P)
237
0
    return P.takeError();
238
239
2
  return makeParseProgress(P->State,
240
2
                           Op(std::move(Left->Value), std::move(Right->Value)));
241
2
}
Parsing.cpp:llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > > parsePair<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> >(llvm::Expected<(anonymous namespace)::ParseProgress<std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> > > (*)((anonymous namespace)::ParseState), std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)> (*)(std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>, std::__1::function<llvm::Expected<clang::CharSourceRange> (clang::ast_matchers::MatchFinder::MatchResult const&)>), (anonymous namespace)::ParseState)
Line
Count
Source
218
1
                                          ParseState State) {
219
1
  auto P = parseChar('(', State);
220
1
  if (!P)
221
0
    return P.takeError();
222
223
1
  auto Left = ParseElement(P->State);
224
1
  if (!Left)
225
0
    return Left.takeError();
226
227
1
  P = parseChar(',', Left->State);
228
1
  if (!P)
229
0
    return P.takeError();
230
231
1
  auto Right = ParseElement(P->State);
232
1
  if (!Right)
233
0
    return Right.takeError();
234
235
1
  P = parseChar(')', Right->State);
236
1
  if (!P)
237
0
    return P.takeError();
238
239
1
  return makeParseProgress(P->State,
240
1
                           Op(std::move(Left->Value), std::move(Right->Value)));
241
1
}
242
243
// Parses input for a stencil operator(single arg ops like AsValue, MemberOp or
244
// Id operator). Returns StencilType representing the operator on success and
245
// error if it fails to parse input for an operator.
246
static ExpectedProgress<RangeSelector>
247
8
parseRangeSelectorImpl(ParseState State) {
248
8
  auto Id = parseId(State);
249
8
  if (!Id)
250
0
    return Id.takeError();
251
252
8
  std::string OpName = std::move(Id->Value);
253
8
  if (auto Op = findOptional(getUnaryStringSelectors(), OpName))
254
4
    return parseSingle(parseStringId, *Op, Id->State);
255
256
4
  if (auto Op = findOptional(getUnaryRangeSelectors(), OpName))
257
1
    return parseSingle(parseRangeSelectorImpl, *Op, Id->State);
258
259
3
  if (auto Op = findOptional(getBinaryStringSelectors(), OpName))
260
2
    return parsePair(parseStringId, *Op, Id->State);
261
262
1
  if (auto Op = findOptional(getBinaryRangeSelectors(), OpName))
263
1
    return parsePair(parseRangeSelectorImpl, *Op, Id->State);
264
265
0
  return makeParseError(State, "unknown selector name: " + OpName);
266
0
}
267
268
5
Expected<RangeSelector> transformer::parseRangeSelector(llvm::StringRef Input) {
269
5
  ParseState State = {Input, Input};
270
5
  ExpectedProgress<RangeSelector> Result = parseRangeSelectorImpl(State);
271
5
  if (!Result)
272
0
    return Result.takeError();
273
5
  State = Result->State;
274
  // Discard any potentially trailing whitespace.
275
5
  State.Input = consumeWhitespace(State.Input);
276
5
  if (State.Input.empty())
277
5
    return Result->Value;
278
0
  return makeParseError(State, "unexpected input after selector");
279
0
}