Coverage Report

Created: 2023-11-11 10:31

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