Skip to content

Commit 1275a55

Browse files
committed
Merge from 'master' to 'sycl-web' (#2)
CONFLICT (content): Merge conflict in clang/test/VFS/subframework-symlink.m
2 parents 3e5a028 + 780d306 commit 1275a55

File tree

38 files changed

+1074
-227
lines changed

38 files changed

+1074
-227
lines changed

clang-tools-extra/clang-query/Query.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,24 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const {
101101
Finder.matchAST(AST->getASTContext());
102102

103103
if (QS.PrintMatcher) {
104-
std::string prefixText = "Matcher: ";
105-
OS << "\n " << prefixText << Source << "\n";
106-
OS << " " << std::string(prefixText.size() + Source.size(), '=') << '\n';
104+
SmallVector<StringRef, 4> Lines;
105+
Source.split(Lines, "\n");
106+
auto FirstLine = Lines[0];
107+
Lines.erase(Lines.begin(), Lines.begin() + 1);
108+
while (!Lines.empty() && Lines.back().empty()) {
109+
Lines.resize(Lines.size() - 1);
110+
}
111+
unsigned MaxLength = FirstLine.size();
112+
std::string PrefixText = "Matcher: ";
113+
OS << "\n " << PrefixText << FirstLine;
114+
115+
for (auto Line : Lines) {
116+
OS << "\n" << std::string(PrefixText.size() + 2, ' ') << Line;
117+
MaxLength = std::max<int>(MaxLength, Line.rtrim().size());
118+
}
119+
120+
OS << "\n"
121+
<< " " << std::string(PrefixText.size() + MaxLength, '=') << "\n\n";
107122
}
108123

109124
for (auto MI = Matches.begin(), ME = Matches.end(); MI != ME; ++MI) {

clang-tools-extra/clang-query/Query.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct Query : llvm::RefCountedBase<Query> {
4444
/// \return false if an error occurs, otherwise return true.
4545
virtual bool run(llvm::raw_ostream &OS, QuerySession &QS) const = 0;
4646

47+
StringRef RemainingContent;
4748
const QueryKind Kind;
4849
};
4950

clang-tools-extra/clang-query/QueryParser.cpp

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,23 @@ namespace query {
2626
// is found before End, return StringRef(). Begin is adjusted to exclude the
2727
// lexed region.
2828
StringRef QueryParser::lexWord() {
29-
Line = Line.ltrim();
29+
Line = Line.drop_while([](char c) {
30+
// Don't trim newlines.
31+
return StringRef(" \t\v\f\r").contains(c);
32+
});
3033

3134
if (Line.empty())
3235
// Even though the Line is empty, it contains a pointer and
3336
// a (zero) length. The pointer is used in the LexOrCompleteWord
3437
// code completion.
3538
return Line;
3639

37-
if (Line.front() == '#') {
38-
Line = {};
39-
return StringRef();
40-
}
40+
StringRef Word;
41+
if (Line.front() == '#')
42+
Word = Line.substr(0, 1);
43+
else
44+
Word = Line.take_until(isWhitespace);
4145

42-
StringRef Word = Line.take_until(isWhitespace);
4346
Line = Line.drop_front(Word.size());
4447
return Word;
4548
}
@@ -125,9 +128,25 @@ template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
125128
}
126129

127130
QueryRef QueryParser::endQuery(QueryRef Q) {
128-
const StringRef Extra = Line;
129-
if (!lexWord().empty())
130-
return new InvalidQuery("unexpected extra input: '" + Extra + "'");
131+
StringRef Extra = Line;
132+
StringRef ExtraTrimmed = Extra.drop_while(
133+
[](char c) { return StringRef(" \t\v\f\r").contains(c); });
134+
135+
if ((!ExtraTrimmed.empty() && ExtraTrimmed[0] == '\n') ||
136+
(ExtraTrimmed.size() >= 2 && ExtraTrimmed[0] == '\r' &&
137+
ExtraTrimmed[1] == '\n'))
138+
Q->RemainingContent = Extra;
139+
else {
140+
StringRef TrailingWord = lexWord();
141+
if (!TrailingWord.empty() && TrailingWord.front() == '#') {
142+
Line = Line.drop_until([](char c) { return c == '\n'; });
143+
Line = Line.drop_while([](char c) { return c == '\n'; });
144+
return endQuery(Q);
145+
}
146+
if (!TrailingWord.empty()) {
147+
return new InvalidQuery("unexpected extra input: '" + Extra + "'");
148+
}
149+
}
131150
return Q;
132151
}
133152

@@ -193,7 +212,11 @@ QueryRef QueryParser::doParse() {
193212
switch (QKind) {
194213
case PQK_Comment:
195214
case PQK_NoOp:
196-
return new NoOpQuery;
215+
Line = Line.drop_until([](char c) { return c == '\n'; });
216+
Line = Line.drop_while([](char c) { return c == '\n'; });
217+
if (Line.empty())
218+
return new NoOpQuery;
219+
return doParse();
197220

198221
case PQK_Help:
199222
return endQuery(new HelpQuery);
@@ -217,7 +240,9 @@ QueryRef QueryParser::doParse() {
217240
return makeInvalidQueryFromDiagnostics(Diag);
218241
}
219242

220-
return new LetQuery(Name, Value);
243+
auto *Q = new LetQuery(Name, Value);
244+
Q->RemainingContent = Line;
245+
return Q;
221246
}
222247

223248
case PQK_Match: {
@@ -226,12 +251,17 @@ QueryRef QueryParser::doParse() {
226251

227252
Diagnostics Diag;
228253
auto MatcherSource = Line.trim();
254+
auto OrigMatcherSource = MatcherSource;
229255
Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
230256
MatcherSource, nullptr, &QS.NamedValues, &Diag);
231257
if (!Matcher) {
232258
return makeInvalidQueryFromDiagnostics(Diag);
233259
}
234-
return new MatchQuery(MatcherSource, *Matcher);
260+
auto ActualSource = OrigMatcherSource.slice(0, OrigMatcherSource.size() -
261+
MatcherSource.size());
262+
auto *Q = new MatchQuery(ActualSource, *Matcher);
263+
Q->RemainingContent = MatcherSource;
264+
return Q;
235265
}
236266

237267
case PQK_Set: {

clang-tools-extra/clang-query/tool/ClangQuery.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,16 @@ bool runCommandsInFile(const char *ExeName, std::string const &FileName,
6969
llvm::errs() << ExeName << ": cannot open " << FileName << "\n";
7070
return 1;
7171
}
72-
while (Input.good()) {
73-
std::string Line;
74-
std::getline(Input, Line);
7572

76-
QueryRef Q = QueryParser::parse(Line, QS);
73+
std::string FileContent((std::istreambuf_iterator<char>(Input)),
74+
std::istreambuf_iterator<char>());
75+
76+
StringRef FileContentRef(FileContent);
77+
while (!FileContentRef.empty()) {
78+
QueryRef Q = QueryParser::parse(FileContentRef, QS);
7779
if (!Q->run(llvm::outs(), QS))
7880
return true;
81+
FileContentRef = Q->RemainingContent;
7982
}
8083
return false;
8184
}

clang-tools-extra/unittests/clang-query/QueryParserTest.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,104 @@ TEST_F(QueryParserTest, Complete) {
230230
EXPECT_EQ("et ", Comps[0].TypedText);
231231
EXPECT_EQ("let", Comps[0].DisplayText);
232232
}
233+
234+
TEST_F(QueryParserTest, Multiline) {
235+
236+
// Single string with multiple commands
237+
QueryRef Q = parse(R"matcher(
238+
set bind-root false
239+
set output dump
240+
)matcher");
241+
242+
ASSERT_TRUE(isa<SetQuery<bool>>(Q));
243+
244+
Q = parse(Q->RemainingContent);
245+
ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
246+
247+
// Missing newline
248+
Q = parse(R"matcher(
249+
set bind-root false set output dump
250+
)matcher");
251+
252+
ASSERT_TRUE(isa<InvalidQuery>(Q));
253+
EXPECT_EQ("unexpected extra input: ' set output dump\n '",
254+
cast<InvalidQuery>(Q)->ErrStr);
255+
256+
// Commands which do their own parsing
257+
Q = parse(R"matcher(
258+
let fn functionDecl(hasName("foo"))
259+
match callExpr(callee(functionDecl()))
260+
)matcher");
261+
262+
ASSERT_TRUE(isa<LetQuery>(Q));
263+
264+
Q = parse(Q->RemainingContent);
265+
ASSERT_TRUE(isa<MatchQuery>(Q));
266+
267+
// Multi-line matcher
268+
Q = parse(R"matcher(
269+
match callExpr(callee(
270+
functionDecl().bind("fn")
271+
))
272+
273+
)matcher");
274+
275+
ASSERT_TRUE(isa<MatchQuery>(Q));
276+
277+
// Comment locations
278+
Q = parse(R"matcher(
279+
#nospacecomment
280+
# Leading comment
281+
match callExpr ( # Trailing comment
282+
# Comment alone on line
283+
284+
callee(
285+
functionDecl(
286+
).bind(
287+
"fn"
288+
)
289+
)) # Comment trailing close
290+
# Comment after match
291+
)matcher");
292+
293+
ASSERT_TRUE(isa<MatchQuery>(Q));
294+
295+
// \r\n
296+
Q = parse("set bind-root false\r\nset output dump");
297+
298+
ASSERT_TRUE(isa<SetQuery<bool>>(Q));
299+
300+
Q = parse(Q->RemainingContent);
301+
ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
302+
303+
// Leading and trailing space in lines
304+
Q = parse(" set bind-root false \r\n set output dump ");
305+
306+
ASSERT_TRUE(isa<SetQuery<bool>>(Q));
307+
308+
Q = parse(Q->RemainingContent);
309+
ASSERT_TRUE(isa<SetExclusiveOutputQuery>(Q));
310+
311+
// Incomplete commands
312+
Q = parse("set\nbind-root false");
313+
314+
ASSERT_TRUE(isa<InvalidQuery>(Q));
315+
EXPECT_EQ("expected variable name", cast<InvalidQuery>(Q)->ErrStr);
316+
317+
Q = parse("set bind-root\nfalse");
318+
319+
ASSERT_TRUE(isa<InvalidQuery>(Q));
320+
EXPECT_EQ("expected 'true' or 'false', got ''",
321+
cast<InvalidQuery>(Q)->ErrStr);
322+
323+
Q = parse(R"matcher(
324+
match callExpr
325+
(
326+
)
327+
)matcher");
328+
329+
ASSERT_TRUE(isa<InvalidQuery>(Q));
330+
EXPECT_EQ("1:9: Error parsing matcher. Found token <NewLine> "
331+
"while looking for '('.",
332+
cast<InvalidQuery>(Q)->ErrStr);
333+
}

clang/include/clang/ASTMatchers/Dynamic/Parser.h

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,14 @@ class Parser {
164164
/// description of the error.
165165
/// The caller takes ownership of the DynTypedMatcher object returned.
166166
static llvm::Optional<DynTypedMatcher>
167-
parseMatcherExpression(StringRef MatcherCode, Sema *S,
168-
const NamedValueMap *NamedValues,
169-
Diagnostics *Error);
167+
parseMatcherExpression(StringRef &MatcherCode, Sema *S,
168+
const NamedValueMap *NamedValues, Diagnostics *Error);
170169
static llvm::Optional<DynTypedMatcher>
171-
parseMatcherExpression(StringRef MatcherCode, Sema *S,
172-
Diagnostics *Error) {
170+
parseMatcherExpression(StringRef &MatcherCode, Sema *S, Diagnostics *Error) {
173171
return parseMatcherExpression(MatcherCode, S, nullptr, Error);
174172
}
175173
static llvm::Optional<DynTypedMatcher>
176-
parseMatcherExpression(StringRef MatcherCode, Diagnostics *Error) {
174+
parseMatcherExpression(StringRef &MatcherCode, Diagnostics *Error) {
177175
return parseMatcherExpression(MatcherCode, nullptr, Error);
178176
}
179177

@@ -189,14 +187,14 @@ class Parser {
189187
/// \param NamedValues A map of precomputed named values. This provides
190188
/// the dictionary for the <NamedValue> rule of the grammar.
191189
/// If null, it is ignored.
192-
static bool parseExpression(StringRef Code, Sema *S,
190+
static bool parseExpression(StringRef &Code, Sema *S,
193191
const NamedValueMap *NamedValues,
194192
VariantValue *Value, Diagnostics *Error);
195-
static bool parseExpression(StringRef Code, Sema *S,
196-
VariantValue *Value, Diagnostics *Error) {
193+
static bool parseExpression(StringRef &Code, Sema *S, VariantValue *Value,
194+
Diagnostics *Error) {
197195
return parseExpression(Code, S, nullptr, Value, Error);
198196
}
199-
static bool parseExpression(StringRef Code, VariantValue *Value,
197+
static bool parseExpression(StringRef &Code, VariantValue *Value,
200198
Diagnostics *Error) {
201199
return parseExpression(Code, nullptr, Value, Error);
202200
}
@@ -213,14 +211,14 @@ class Parser {
213211
/// \return The list of completions, which may be empty if there are no
214212
/// available completions or if an error occurred.
215213
static std::vector<MatcherCompletion>
216-
completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S,
214+
completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S,
217215
const NamedValueMap *NamedValues);
218216
static std::vector<MatcherCompletion>
219-
completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S) {
217+
completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S) {
220218
return completeExpression(Code, CompletionOffset, S, nullptr);
221219
}
222220
static std::vector<MatcherCompletion>
223-
completeExpression(StringRef Code, unsigned CompletionOffset) {
221+
completeExpression(StringRef &Code, unsigned CompletionOffset) {
224222
return completeExpression(Code, CompletionOffset, nullptr);
225223
}
226224

0 commit comments

Comments
 (0)