clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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 while (true) {
31 if (Begin == End)
32 return StringRef(Begin, 0);
33
34 if (!isWhitespace(*Begin))
35 break;
36
37 ++Begin;
38 }
39
40 const char *WordBegin = Begin;
41
42 while (true) {
43 ++Begin;
44
45 if (Begin == End || isWhitespace(*Begin))
46 return StringRef(WordBegin, Begin - WordBegin);
47 }
48 }
49
50 // This is the StringSwitch-alike used by lexOrCompleteWord below. See that
51 // function for details.
52 template <typename T> struct QueryParser::LexOrCompleteWord {
53 StringSwitch<T> Switch;
54
55 QueryParser *P;
56 StringRef Word;
57 // Set to the completion point offset in Word, or StringRef::npos if
58 // completion point not in Word.
59 size_t WordCompletionPos;
60
61 LexOrCompleteWord(QueryParser *P, StringRef Word, size_t WCP)
62 : Switch(Word), P(P), Word(Word), WordCompletionPos(WCP) {}
63
64 template <unsigned N>
65 LexOrCompleteWord &Case(const char (&S)[N], const T &Value,
66 bool IsCompletion = true) {
67 StringRef CaseStr(S, N - 1);
68
69 if (WordCompletionPos == StringRef::npos)
70 Switch.Case(S, Value);
71 else if (N != 1 && IsCompletion && WordCompletionPos <= CaseStr.size() &&
72 CaseStr.substr(0, WordCompletionPos) ==
73 Word.substr(0, WordCompletionPos))
74 P->Completions.push_back(LineEditor::Completion(
75 (CaseStr.substr(WordCompletionPos) + " ").str(), CaseStr));
76 return *this;
77 }
78
79 T Default(const T& Value) const {
80 return Switch.Default(Value);
81 }
82 };
83
84 // Lexes a word and stores it in Word. Returns a LexOrCompleteWord<T> object
85 // that can be used like a llvm::StringSwitch<T>, but adds cases as possible
86 // completions if the lexed word contains the completion point.
87 template <typename T>
88 QueryParser::LexOrCompleteWord<T>
89 QueryParser::lexOrCompleteWord(StringRef &Word) {
90 Word = lexWord();
91 size_t WordCompletionPos = StringRef::npos;
92 if (CompletionPos && CompletionPos <= Word.data() + Word.size()) {
93 if (CompletionPos < Word.data())
94 WordCompletionPos = 0;
95 else
96 WordCompletionPos = CompletionPos - Word.data();
97 }
98 return LexOrCompleteWord<T>(this, Word, WordCompletionPos);
99 }
100
101 QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) {
102 StringRef ValStr;
103 unsigned Value = lexOrCompleteWord<unsigned>(ValStr)
104 .Case("false", 0)
105 .Case("true", 1)
106 .Default(~0u);
107 if (Value == ~0u) {
108 return new InvalidQuery("expected 'true' or 'false', got '" + ValStr + "'");
109 }
110 return new SetQuery<bool>(Var, Value);
111 }
112
113 QueryRef QueryParser::parseSetOutputKind() {
114 StringRef ValStr;
115 unsigned OutKind = lexOrCompleteWord<unsigned>(ValStr)
116 .Case("diag", OK_Diag)
117 .Case("print", OK_Print)
118 .Case("dump", OK_Dump)
119 .Default(~0u);
120 if (OutKind == ~0u) {
121 return new InvalidQuery("expected 'diag', 'print' or 'dump', got '" +
122 ValStr + "'");
123 }
124 return new SetQuery<OutputKind>(&QuerySession::OutKind, OutputKind(OutKind));
125 }
126
127 QueryRef QueryParser::endQuery(QueryRef Q) {
128 const char *Extra = Begin;
129 if (!lexWord().empty())
130 return new InvalidQuery("unexpected extra input: '" +
131 StringRef(Extra, End - Extra) + "'");
132 return Q;
133 }
134
135 namespace {
136
137 enum ParsedQueryKind {
138 PQK_Invalid,
139 PQK_NoOp,
140 PQK_Help,
141 PQK_Let,
142 PQK_Match,
143 PQK_Set,
144 PQK_Unlet,
145 PQK_Quit
146 };
147
148 enum ParsedQueryVariable {
149 PQV_Invalid,
150 PQV_Output,
151 PQV_BindRoot
152 };
153
154 QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) {
155 std::string ErrStr;
156 llvm::raw_string_ostream OS(ErrStr);
157 Diag.printToStreamFull(OS);
158 return new InvalidQuery(OS.str());
159 }
160
161 } // namespace
162
163 QueryRef QueryParser::completeMatcherExpression() {
164 std::vector<MatcherCompletion> Comps = Parser::completeExpression(
165 StringRef(Begin, End - Begin), CompletionPos - Begin, nullptr,
166 &QS.NamedValues);
167 for (std::vector<MatcherCompletion>::iterator I = Comps.begin(),
168 E = Comps.end();
169 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>(CommandStr)
178 .Case("", PQK_NoOp)
179 .Case("help", PQK_Help)
180 .Case("m", PQK_Match, /*IsCompletion=*/false)
181 .Case("let", PQK_Let)
182 .Case("match", PQK_Match)
183 .Case("set", PQK_Set)
184 .Case("unlet", PQK_Unlet)
185 .Case("quit", PQK_Quit)
186 .Default(PQK_Invalid);
187
188 switch (QKind) {
189 case PQK_NoOp:
190 return new NoOpQuery;
191
192 case PQK_Help:
193 return endQuery(new HelpQuery);
194
195 case PQK_Quit:
196 return endQuery(new QuitQuery);
197
198 case PQK_Let: {
199 StringRef Name = lexWord();
200
201 if (Name.empty())
202 return new InvalidQuery("expected variable name");
203
204 if (CompletionPos)
205 return completeMatcherExpression();
206
207 Diagnostics Diag;
208 ast_matchers::dynamic::VariantValue Value;
209 if (!Parser::parseExpression(StringRef(Begin, End - Begin), nullptr,
210 &QS.NamedValues, &Value, &Diag)) {
211 return makeInvalidQueryFromDiagnostics(Diag);
212 }
213
214 return new LetQuery(Name, Value);
215 }
216
217 case PQK_Match: {
218 if (CompletionPos)
219 return completeMatcherExpression();
220
221 Diagnostics Diag;
222 Optional<DynTypedMatcher> Matcher = Parser::parseMatcherExpression(
223 StringRef(Begin, End - Begin), nullptr, &QS.NamedValues, &Diag);
224 if (!Matcher) {
225 return makeInvalidQueryFromDiagnostics(Diag);
226 }
227 return new MatchQuery(*Matcher);
228 }
229
230 case PQK_Set: {
231 StringRef VarStr;
232 ParsedQueryVariable Var = lexOrCompleteWord<ParsedQueryVariable>(VarStr)
233 .Case("output", PQV_Output)
234 .Case("bind-root", PQV_BindRoot)
235 .Default(PQV_Invalid);
236 if (VarStr.empty())
237 return new InvalidQuery("expected variable name");
238 if (Var == PQV_Invalid)
239 return new InvalidQuery("unknown variable: '" + VarStr + "'");
240
241 QueryRef Q;
242 switch (Var) {
243 case PQV_Output:
244 Q = parseSetOutputKind();
245 break;
246 case PQV_BindRoot:
247 Q = parseSetBool(&QuerySession::BindRoot);
248 break;
249 case PQV_Invalid:
250 llvm_unreachable("Invalid query kind");
251 }
252
253 return endQuery(Q);
254 }
255
256 case PQK_Unlet: {
257 StringRef Name = lexWord();
258
259 if (Name.empty())
260 return new InvalidQuery("expected variable name");
261
262 return endQuery(new LetQuery(Name, VariantValue()));
263 }
264
265 case PQK_Invalid:
266 return new InvalidQuery("unknown command: " + CommandStr);
267 }
268
269 llvm_unreachable("Invalid query kind");
270 }
271
272 QueryRef QueryParser::parse(StringRef Line, const QuerySession &QS) {
273 return QueryParser(Line, QS).doParse();
274 }
275
276 std::vector<LineEditor::Completion>
277 QueryParser::complete(StringRef Line, size_t Pos, const QuerySession &QS) {
278 QueryParser P(Line, QS);
279 P.CompletionPos = Line.data() + Pos;
280
281 P.doParse();
282 return P.Completions;
283 }
284
285 } // namespace query
286 } // namespace clang
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
clang::query::QuerySession
Represents the state for a particular clang-query session.
Definition: QuerySession.h:25
clang::query::OK_Diag
Definition: Query.h:22
Query.h
QueryParser.h
QuerySession.h
clang::query::QueryParser::LexOrCompleteWord
Definition: QueryParser.cpp:52
clang::query::QueryRef
llvm::IntrusiveRefCntPtr< Query > QueryRef
Definition: Query.h:52
clang::query::OutputKind
OutputKind
Definition: Query.h:21
clang::query::OK_Print
Definition: Query.h:23
clang::query::QueryParser::LexOrCompleteWord::WordCompletionPos
size_t WordCompletionPos
Definition: QueryParser.cpp:59
clang::query::QueryParser::LexOrCompleteWord::Case
LexOrCompleteWord & Case(const char(&S)[N], const T &Value, bool IsCompletion=true)
Definition: QueryParser.cpp:65
clang::query::QueryParser::LexOrCompleteWord::Word
StringRef Word
Definition: QueryParser.cpp:56
clang::query::QueryParser::LexOrCompleteWord::Switch
StringSwitch< T > Switch
Definition: QueryParser.cpp:53
Line
int Line
Definition: PreprocessorTracker.cpp:527
clang::query::OK_Dump
Definition: Query.h:24
clang::query::QueryParser::LexOrCompleteWord::P
QueryParser * P
Definition: QueryParser.cpp:55
clang::query::QueryParser::LexOrCompleteWord::Default
T Default(const T &Value) const
Definition: QueryParser.cpp:79
clang::query::QueryParser
Definition: QueryParser.h:23
clang::query::QueryParser::LexOrCompleteWord::LexOrCompleteWord
LexOrCompleteWord(QueryParser *P, StringRef Word, size_t WCP)
Definition: QueryParser.cpp:61