clang-tools  9.0.0
QueryParser.cpp
Go to the documentation of this file.
1 //===---- QueryParser.cpp - clang-query command parser --------------------===//
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 "QueryParser.h"
10 #include "Query.h"
11 #include "QuerySession.h"
12 #include "clang/ASTMatchers/Dynamic/Parser.h"
13 #include "clang/Basic/CharInfo.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include <set>
17 
18 using namespace llvm;
19 using namespace clang::ast_matchers::dynamic;
20 
21 namespace clang {
22 namespace query {
23 
24 // Lex any amount of whitespace followed by a "word" (any sequence of
25 // non-whitespace characters) from the start of region [Begin,End). If no word
26 // is found before End, return StringRef(). Begin is adjusted to exclude the
27 // lexed region.
28 StringRef QueryParser::lexWord() {
29  Line = Line.ltrim();
30 
31  if (Line.empty())
32  // Even though the Line is empty, it contains a pointer and
33  // a (zero) length. The pointer is used in the LexOrCompleteWord
34  // code completion.
35  return Line;
36 
37  if (Line.front() == '#') {
38  Line = {};
39  return StringRef();
40  }
41 
42  StringRef Word = Line.take_until(isWhitespace);
43  Line = Line.drop_front(Word.size());
44  return Word;
45 }
46 
47 // This is the StringSwitch-alike used by lexOrCompleteWord below. See that
48 // function for details.
49 template <typename T> struct QueryParser::LexOrCompleteWord {
50  StringRef Word;
51  StringSwitch<T> Switch;
52 
54  // Set to the completion point offset in Word, or StringRef::npos if
55  // completion point not in Word.
57 
58  // Lexes a word and stores it in Word. Returns a LexOrCompleteWord<T> object
59  // that can be used like a llvm::StringSwitch<T>, but adds cases as possible
60  // completions if the lexed word contains the completion point.
61  LexOrCompleteWord(QueryParser *P, StringRef &OutWord)
62  : Word(P->lexWord()), Switch(Word), P(P),
63  WordCompletionPos(StringRef::npos) {
64  OutWord = Word;
65  if (P->CompletionPos && P->CompletionPos <= Word.data() + Word.size()) {
66  if (P->CompletionPos < Word.data())
67  WordCompletionPos = 0;
68  else
69  WordCompletionPos = P->CompletionPos - Word.data();
70  }
71  }
72 
73  LexOrCompleteWord &Case(llvm::StringLiteral CaseStr, const T &Value,
74  bool IsCompletion = true) {
75 
76  if (WordCompletionPos == StringRef::npos)
77  Switch.Case(CaseStr, Value);
78  else if (CaseStr.size() != 0 && IsCompletion && WordCompletionPos <= CaseStr.size() &&
79  CaseStr.substr(0, WordCompletionPos) ==
80  Word.substr(0, WordCompletionPos))
81  P->Completions.push_back(LineEditor::Completion(
82  (CaseStr.substr(WordCompletionPos) + " ").str(), CaseStr));
83  return *this;
84  }
85 
86  T Default(T Value) { return Switch.Default(Value); }
87 };
88 
89 QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
90  StringRef ValStr;
91  unsigned Value = LexOrCompleteWord<unsigned>(this, ValStr)
92  .Case("false", 0)
93  .Case("true", 1)
94  .Default(~0u);
95  if (Value == ~0u) {
96  return new InvalidQuery("expected 'true' or 'false', got '" + ValStr + "'");
97  }
98  return new SetQuery<bool>(Var, Value);
99 }
100 
101 template <typename QueryType> QueryRef QueryParser::parseSetOutputKind() {
102  StringRef ValStr;
103  unsigned OutKind = LexOrCompleteWord<unsigned>(this, ValStr)
104  .Case("diag", OK_Diag)
105  .Case("print", OK_Print)
106  .Case("detailed-ast", OK_DetailedAST)
107  .Case("dump", OK_DetailedAST)
108  .Default(~0u);
109  if (OutKind == ~0u) {
110  return new InvalidQuery(
111  "expected 'diag', 'print', 'detailed-ast' or 'dump', got '" + ValStr +
112  "'");
113  }
114 
115  switch (OutKind) {
116  case OK_DetailedAST:
117  return new QueryType(&QuerySession::DetailedASTOutput);
118  case OK_Diag:
119  return new QueryType(&QuerySession::DiagOutput);
120  case OK_Print:
121  return new QueryType(&QuerySession::PrintOutput);
122  }
123 
124  llvm_unreachable("Invalid output kind");
125 }
126 
127 QueryRef QueryParser::endQuery(QueryRef Q) {
128  const StringRef Extra = Line;
129  if (!lexWord().empty())
130  return new InvalidQuery("unexpected extra input: '" + Extra + "'");
131  return Q;
132 }
133 
134 namespace {
135 
137  PQK_Invalid,
138  PQK_Comment,
139  PQK_NoOp,
140  PQK_Help,
141  PQK_Let,
142  PQK_Match,
143  PQK_Set,
144  PQK_Unlet,
145  PQK_Quit,
146  PQK_Enable,
147  PQK_Disable
148 };
149 
151  PQV_Invalid,
152  PQV_Output,
153  PQV_BindRoot,
154  PQV_PrintMatcher
155 };
156 
157 QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
158  std::string ErrStr;
159  llvm::raw_string_ostream OS(ErrStr);
160  Diag.printToStreamFull(OS);
161  return new InvalidQuery(OS.str());
162 }
163 
164 } // namespace
165 
166 QueryRef QueryParser::completeMatcherExpression() {
167  std::vector<MatcherCompletion> Comps = Parser::completeExpression(
168  Line, CompletionPos - Line.begin(), nullptr, &QS.NamedValues);
169  for (auto I = Comps.begin(), E = Comps.end(); I != E; ++I) {
170  Completions.push_back(LineEditor::Completion(I->TypedText, I->MatcherDecl));
171  }
172  return QueryRef();
173 }
174 
175 QueryRef QueryParser::doParse() {
176  StringRef CommandStr;
177  ParsedQueryKind QKind = LexOrCompleteWord<ParsedQueryKind>(this, CommandStr)
178  .Case("", PQK_NoOp)
179  .Case("#", PQK_Comment, /*IsCompletion=*/false)
180  .Case("help", PQK_Help)
181  .Case("l", PQK_Let, /*IsCompletion=*/false)
182  .Case("let", PQK_Let)
183  .Case("m", PQK_Match, /*IsCompletion=*/false)
184  .Case("match", PQK_Match)
185  .Case("q", PQK_Quit, /*IsCompletion=*/false)
186  .Case("quit", PQK_Quit)
187  .Case("set", PQK_Set)
188  .Case("enable", PQK_Enable)
189  .Case("disable", PQK_Disable)
190  .Case("unlet", PQK_Unlet)
191  .Default(PQK_Invalid);
192 
193  switch (QKind) {
194  case PQK_Comment:
195  case PQK_NoOp:
196  return new NoOpQuery;
197 
198  case PQK_Help:
199  return endQuery(new HelpQuery);
200 
201  case PQK_Quit:
202  return endQuery(new QuitQuery);
203 
204  case PQK_Let: {
205  StringRef Name = lexWord();
206 
207  if (Name.empty())
208  return new InvalidQuery("expected variable name");
209 
210  if (CompletionPos)
211  return completeMatcherExpression();
212 
213  Diagnostics Diag;
214  ast_matchers::dynamic::VariantValue Value;
215  if (!Parser::parseExpression(Line, nullptr, &QS.NamedValues, &Value,
216  &Diag)) {
217  return makeInvalidQueryFromDiagnostics(Diag);
218  }
219 
220  return new LetQuery(Name, Value);
221  }
222 
223  case PQK_Match: {
224  if (CompletionPos)
225  return completeMatcherExpression();
226 
227  Diagnostics Diag;
228  auto MatcherSource = Line.trim();
229  Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
230  MatcherSource, nullptr, &QS.NamedValues, &Diag);
231  if (!Matcher) {
232  return makeInvalidQueryFromDiagnostics(Diag);
233  }
234  return new MatchQuery(MatcherSource, *Matcher);
235  }
236 
237  case PQK_Set: {
238  StringRef VarStr;
239  ParsedQueryVariable Var =
240  LexOrCompleteWord<ParsedQueryVariable>(this, VarStr)
241  .Case("output", PQV_Output)
242  .Case("bind-root", PQV_BindRoot)
243  .Case("print-matcher", PQV_PrintMatcher)
244  .Default(PQV_Invalid);
245  if (VarStr.empty())
246  return new InvalidQuery("expected variable name");
247  if (Var == PQV_Invalid)
248  return new InvalidQuery("unknown variable: '" + VarStr + "'");
249 
250  QueryRef Q;
251  switch (Var) {
252  case PQV_Output:
253  Q = parseSetOutputKind<SetExclusiveOutputQuery>();
254  break;
255  case PQV_BindRoot:
256  Q = parseSetBool(&QuerySession::BindRoot);
257  break;
258  case PQV_PrintMatcher:
259  Q = parseSetBool(&QuerySession::PrintMatcher);
260  break;
261  case PQV_Invalid:
262  llvm_unreachable("Invalid query kind");
263  }
264 
265  return endQuery(Q);
266  }
267  case PQK_Enable:
268  case PQK_Disable: {
269  StringRef VarStr;
270  ParsedQueryVariable Var =
271  LexOrCompleteWord<ParsedQueryVariable>(this, VarStr)
272  .Case("output", PQV_Output)
273  .Default(PQV_Invalid);
274  if (VarStr.empty())
275  return new InvalidQuery("expected variable name");
276  if (Var == PQV_Invalid)
277  return new InvalidQuery("unknown variable: '" + VarStr + "'");
278 
279  QueryRef Q;
280 
281  if (QKind == PQK_Enable)
282  Q = parseSetOutputKind<EnableOutputQuery>();
283  else if (QKind == PQK_Disable)
284  Q = parseSetOutputKind<DisableOutputQuery>();
285  else
286  llvm_unreachable("Invalid query kind");
287  return endQuery(Q);
288  }
289 
290  case PQK_Unlet: {
291  StringRef Name = lexWord();
292 
293  if (Name.empty())
294  return new InvalidQuery("expected variable name");
295 
296  return endQuery(new LetQuery(Name, VariantValue()));
297  }
298 
299  case PQK_Invalid:
300  return new InvalidQuery("unknown command: " + CommandStr);
301  }
302 
303  llvm_unreachable("Invalid query kind");
304 }
305 
306 QueryRef QueryParser::parse(StringRef Line, const QuerySession &QS) {
307  return QueryParser(Line, QS).doParse();
308 }
309 
310 std::vector<LineEditor::Completion>
311 QueryParser::complete(StringRef Line, size_t Pos, const QuerySession &QS) {
312  QueryParser P(Line, QS);
313  P.CompletionPos = Line.data() + Pos;
314 
315  P.doParse();
316  return P.Completions;
317 }
318 
319 } // namespace query
320 } // namespace clang
Some operations such as code completion produce a set of candidates.
No-op query (i.e. a blank line).
Definition: Query.h:63
Represents the state for a particular clang-query session.
Definition: QuerySession.h:23
Any query which resulted in a parse error. The error message is in ErrStr.
Definition: Query.h:53
llvm::IntrusiveRefCntPtr< Query > QueryRef
Definition: Query.h:50
Query for "match MATCHER".
Definition: Query.h:87
static constexpr llvm::StringLiteral Name
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Query for "quit".
Definition: Query.h:79
LexOrCompleteWord & Case(llvm::StringLiteral CaseStr, const T &Value, bool IsCompletion=true)
Definition: QueryParser.cpp:73
Query for "set VAR VALUE".
Definition: Query.h:122
LexOrCompleteWord(QueryParser *P, StringRef &OutWord)
Definition: QueryParser.cpp:61
Query for "help".
Definition: Query.h:71
std::string Word