clang-tools 8.0.0

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