12#include "clang/ASTMatchers/Dynamic/Parser.h"
13#include "clang/Basic/CharInfo.h"
14#include "clang/Tooling/NodeIntrospection.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/ADT/StringSwitch.h"
21using namespace clang::ast_matchers::dynamic;
30StringRef QueryParser::lexWord() {
32 Line = Line.ltrim(
" \t\v\f\r");
41 if (Line.front() ==
'#')
42 Word = Line.substr(0, 1);
44 Word = Line.take_until(isWhitespace);
46 Line = Line.drop_front(
Word.size());
68 if (
P->CompletionPos &&
P->CompletionPos <=
Word.data() +
Word.size()) {
69 if (
P->CompletionPos <
Word.data())
77 bool IsCompletion =
true) {
80 Switch.Case(CaseStr, Value);
81 else if (CaseStr.size() != 0 && IsCompletion &&
WordCompletionPos <= CaseStr.size() &&
84 P->Completions.push_back(LineEditor::Completion(
86 std::string(CaseStr)));
95 unsigned Value = LexOrCompleteWord<unsigned>(
this, ValStr)
100 return new InvalidQuery(
"expected 'true' or 'false', got '" + ValStr +
"'");
102 return new SetQuery<bool>(Var, Value);
105template <
typename QueryType>
QueryRef QueryParser::parseSetOutputKind() {
107 bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport();
109 LexOrCompleteWord<unsigned>(
this, ValStr)
113 .Case(
"srcloc",
OK_SrcLoc, HasIntrospection)
116 if (OutKind == ~0u) {
117 return new InvalidQuery(
"expected 'diag', 'print', 'detailed-ast'" +
118 StringRef(HasIntrospection ?
", 'srcloc'" :
"") +
119 " or 'dump', got '" + ValStr +
"'");
130 if (HasIntrospection)
132 return new InvalidQuery(
"'srcloc' output support is not available.");
135 llvm_unreachable(
"Invalid output kind");
138QueryRef QueryParser::parseSetTraversalKind(TraversalKind QuerySession::*Var) {
141 LexOrCompleteWord<unsigned>(
this, ValStr)
142 .Case(
"AsIs", TK_AsIs)
143 .Case(
"IgnoreUnlessSpelledInSource", TK_IgnoreUnlessSpelledInSource)
146 return new InvalidQuery(
"expected traversal kind, got '" + ValStr +
"'");
148 return new SetQuery<TraversalKind>(Var,
static_cast<TraversalKind
>(Value));
152 StringRef Extra = Line;
153 StringRef ExtraTrimmed = Extra.ltrim(
" \t\v\f\r");
155 if ((!ExtraTrimmed.empty() && ExtraTrimmed[0] ==
'\n') ||
156 (ExtraTrimmed.size() >= 2 && ExtraTrimmed[0] ==
'\r' &&
157 ExtraTrimmed[1] ==
'\n'))
158 Q->RemainingContent = Extra;
160 StringRef TrailingWord = lexWord();
161 if (!TrailingWord.empty() && TrailingWord.front() ==
'#') {
162 Line = Line.drop_until([](
char c) {
return c ==
'\n'; });
163 Line = Line.drop_while([](
char c) {
return c ==
'\n'; });
166 if (!TrailingWord.empty()) {
167 return new InvalidQuery(
"unexpected extra input: '" + Extra +
"'");
175enum ParsedQueryKind {
189enum ParsedQueryVariable {
199 llvm::raw_string_ostream
OS(ErrStr);
200 Diag.printToStreamFull(
OS);
201 return new InvalidQuery(
OS.str());
206QueryRef QueryParser::completeMatcherExpression() {
207 std::vector<MatcherCompletion> Comps = Parser::completeExpression(
208 Line, CompletionPos - Line.begin(),
nullptr, &QS.
NamedValues);
209 for (
auto I = Comps.begin(),
E = Comps.end(); I !=
E; ++I) {
210 Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
216 StringRef CommandStr;
217 ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(
this, CommandStr)
219 .Case(
"#", PQK_Comment,
false)
220 .Case(
"help", PQK_Help)
221 .Case(
"l", PQK_Let,
false)
222 .Case(
"let", PQK_Let)
223 .Case(
"m", PQK_Match,
false)
224 .Case(
"match", PQK_Match)
225 .Case(
"q", PQK_Quit,
false)
226 .Case(
"quit", PQK_Quit)
227 .Case(
"set", PQK_Set)
228 .Case(
"enable", PQK_Enable)
229 .Case(
"disable", PQK_Disable)
230 .Case(
"unlet", PQK_Unlet)
231 .Default(PQK_Invalid);
236 Line = Line.drop_until([](
char c) {
return c ==
'\n'; });
237 Line = Line.drop_while([](
char c) {
return c ==
'\n'; });
239 return new NoOpQuery;
243 return endQuery(
new HelpQuery);
246 return endQuery(
new QuitQuery);
249 StringRef
Name = lexWord();
252 return new InvalidQuery(
"expected variable name");
255 return completeMatcherExpression();
258 ast_matchers::dynamic::VariantValue Value;
259 if (!Parser::parseExpression(Line,
nullptr, &QS.
NamedValues, &Value,
261 return makeInvalidQueryFromDiagnostics(Diag);
264 auto *Q =
new LetQuery(
Name, Value);
265 Q->RemainingContent = Line;
271 return completeMatcherExpression();
274 auto MatcherSource = Line.ltrim();
275 auto OrigMatcherSource = MatcherSource;
276 std::optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
279 return makeInvalidQueryFromDiagnostics(Diag);
281 auto ActualSource = OrigMatcherSource.slice(0, OrigMatcherSource.size() -
282 MatcherSource.size());
283 auto *Q =
new MatchQuery(ActualSource, *Matcher);
284 Q->RemainingContent = MatcherSource;
290 ParsedQueryVariable Var =
291 LexOrCompleteWord<ParsedQueryVariable>(
this, VarStr)
292 .Case(
"output", PQV_Output)
293 .Case(
"bind-root", PQV_BindRoot)
294 .Case(
"print-matcher", PQV_PrintMatcher)
295 .Case(
"traversal", PQV_Traversal)
296 .Default(PQV_Invalid);
298 return new InvalidQuery(
"expected variable name");
299 if (Var == PQV_Invalid)
300 return new InvalidQuery(
"unknown variable: '" + VarStr +
"'");
305 Q = parseSetOutputKind<SetExclusiveOutputQuery>();
310 case PQV_PrintMatcher:
317 llvm_unreachable(
"Invalid query kind");
325 ParsedQueryVariable Var =
326 LexOrCompleteWord<ParsedQueryVariable>(
this, VarStr)
327 .Case(
"output", PQV_Output)
328 .Default(PQV_Invalid);
330 return new InvalidQuery(
"expected variable name");
331 if (Var == PQV_Invalid)
332 return new InvalidQuery(
"unknown variable: '" + VarStr +
"'");
336 if (QKind == PQK_Enable)
337 Q = parseSetOutputKind<EnableOutputQuery>();
338 else if (QKind == PQK_Disable)
339 Q = parseSetOutputKind<DisableOutputQuery>();
341 llvm_unreachable(
"Invalid query kind");
346 StringRef
Name = lexWord();
349 return new InvalidQuery(
"expected variable name");
351 return endQuery(
new LetQuery(
Name, VariantValue()));
355 return new InvalidQuery(
"unknown command: " + CommandStr);
358 llvm_unreachable(
"Invalid query kind");
365std::vector<LineEditor::Completion>
368 P.CompletionPos =
Line.data() +
Pos;
371 return P.Completions;
llvm::SmallString< 256U > Name
WantDiagnostics Diagnostics
llvm::raw_string_ostream OS
static QueryRef parse(StringRef Line, const QuerySession &QS)
Parse Line as a query.
static std::vector< llvm::LineEditor::Completion > complete(StringRef Line, size_t Pos, const QuerySession &QS)
Compute a list of completions for Line assuming a cursor at.
Represents the state for a particular clang-query session.
llvm::StringMap< ast_matchers::dynamic::VariantValue > NamedValues
llvm::IntrusiveRefCntPtr< Query > QueryRef
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
Any query which resulted in a parse error. The error message is in ErrStr.
LexOrCompleteWord & Case(llvm::StringLiteral CaseStr, const T &Value, bool IsCompletion=true)
LexOrCompleteWord(QueryParser *P, StringRef &OutWord)