1 | //===--- Query.h - clang-query ----------------------------------*- C++ -*-===// |
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 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_H |
10 | #define |
11 | |
12 | #include "QuerySession.h" |
13 | #include "clang/ASTMatchers/Dynamic/VariantValue.h" |
14 | #include "llvm/ADT/IntrusiveRefCntPtr.h" |
15 | #include <string> |
16 | |
17 | namespace clang { |
18 | namespace query { |
19 | |
20 | enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST }; |
21 | |
22 | enum QueryKind { |
23 | QK_Invalid, |
24 | QK_NoOp, |
25 | QK_Help, |
26 | QK_Let, |
27 | QK_Match, |
28 | QK_SetBool, |
29 | QK_SetOutputKind, |
30 | QK_SetTraversalKind, |
31 | QK_EnableOutputKind, |
32 | QK_DisableOutputKind, |
33 | QK_Quit, |
34 | QK_File |
35 | }; |
36 | |
37 | class QuerySession; |
38 | |
39 | struct Query : llvm::RefCountedBase<Query> { |
40 | Query(QueryKind Kind) : Kind(Kind) {} |
41 | virtual ~Query(); |
42 | |
43 | /// Perform the query on \p QS and print output to \p OS. |
44 | /// |
45 | /// \return false if an error occurs, otherwise return true. |
46 | virtual bool run(llvm::raw_ostream &OS, QuerySession &QS) const = 0; |
47 | |
48 | StringRef RemainingContent; |
49 | const QueryKind Kind; |
50 | }; |
51 | |
52 | typedef llvm::IntrusiveRefCntPtr<Query> QueryRef; |
53 | |
54 | /// Any query which resulted in a parse error. The error message is in ErrStr. |
55 | struct InvalidQuery : Query { |
56 | InvalidQuery(const Twine &ErrStr) : Query(QK_Invalid), ErrStr(ErrStr.str()) {} |
57 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
58 | |
59 | std::string ErrStr; |
60 | |
61 | static bool classof(const Query *Q) { return Q->Kind == QK_Invalid; } |
62 | }; |
63 | |
64 | /// No-op query (i.e. a blank line). |
65 | struct NoOpQuery : Query { |
66 | NoOpQuery() : Query(QK_NoOp) {} |
67 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
68 | |
69 | static bool classof(const Query *Q) { return Q->Kind == QK_NoOp; } |
70 | }; |
71 | |
72 | /// Query for "help". |
73 | struct HelpQuery : Query { |
74 | HelpQuery() : Query(QK_Help) {} |
75 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
76 | |
77 | static bool classof(const Query *Q) { return Q->Kind == QK_Help; } |
78 | }; |
79 | |
80 | /// Query for "quit". |
81 | struct QuitQuery : Query { |
82 | QuitQuery() : Query(QK_Quit) {} |
83 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
84 | |
85 | static bool classof(const Query *Q) { return Q->Kind == QK_Quit; } |
86 | }; |
87 | |
88 | /// Query for "match MATCHER". |
89 | struct MatchQuery : Query { |
90 | MatchQuery(StringRef Source, |
91 | const ast_matchers::dynamic::DynTypedMatcher &Matcher) |
92 | : Query(QK_Match), Matcher(Matcher), Source(Source) {} |
93 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
94 | |
95 | ast_matchers::dynamic::DynTypedMatcher Matcher; |
96 | |
97 | StringRef Source; |
98 | |
99 | static bool classof(const Query *Q) { return Q->Kind == QK_Match; } |
100 | }; |
101 | |
102 | struct LetQuery : Query { |
103 | LetQuery(StringRef Name, const ast_matchers::dynamic::VariantValue &Value) |
104 | : Query(QK_Let), Name(Name), Value(Value) {} |
105 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
106 | |
107 | std::string Name; |
108 | ast_matchers::dynamic::VariantValue Value; |
109 | |
110 | static bool classof(const Query *Q) { return Q->Kind == QK_Let; } |
111 | }; |
112 | |
113 | template <typename T> struct SetQueryKind {}; |
114 | |
115 | template <> struct SetQueryKind<bool> { |
116 | static const QueryKind value = QK_SetBool; |
117 | }; |
118 | |
119 | template <> struct SetQueryKind<OutputKind> { |
120 | static const QueryKind value = QK_SetOutputKind; |
121 | }; |
122 | |
123 | template <> struct SetQueryKind<TraversalKind> { |
124 | static const QueryKind value = QK_SetTraversalKind; |
125 | }; |
126 | |
127 | /// Query for "set VAR VALUE". |
128 | template <typename T> struct SetQuery : Query { |
129 | SetQuery(T QuerySession::*Var, T Value) |
130 | : Query(SetQueryKind<T>::value), Var(Var), Value(Value) {} |
131 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override { |
132 | QS.*Var = Value; |
133 | return true; |
134 | } |
135 | |
136 | static bool classof(const Query *Q) { |
137 | return Q->Kind == SetQueryKind<T>::value; |
138 | } |
139 | |
140 | T QuerySession::*Var; |
141 | T Value; |
142 | }; |
143 | |
144 | // Implements the exclusive 'set output dump|diag|print' options. |
145 | struct SetExclusiveOutputQuery : Query { |
146 | SetExclusiveOutputQuery(bool QuerySession::*Var) |
147 | : Query(QK_SetOutputKind), Var(Var) {} |
148 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override { |
149 | QS.DiagOutput = false; |
150 | QS.DetailedASTOutput = false; |
151 | QS.PrintOutput = false; |
152 | QS.*Var = true; |
153 | return true; |
154 | } |
155 | |
156 | static bool classof(const Query *Q) { return Q->Kind == QK_SetOutputKind; } |
157 | |
158 | bool QuerySession::*Var; |
159 | }; |
160 | |
161 | // Implements the non-exclusive 'set output dump|diag|print' options. |
162 | struct SetNonExclusiveOutputQuery : Query { |
163 | SetNonExclusiveOutputQuery(QueryKind Kind, bool QuerySession::*Var, |
164 | bool Value) |
165 | : Query(Kind), Var(Var), Value(Value) {} |
166 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override { |
167 | QS.*Var = Value; |
168 | return true; |
169 | } |
170 | |
171 | bool QuerySession::*Var; |
172 | bool Value; |
173 | }; |
174 | |
175 | struct EnableOutputQuery : SetNonExclusiveOutputQuery { |
176 | EnableOutputQuery(bool QuerySession::*Var) |
177 | : SetNonExclusiveOutputQuery(QK_EnableOutputKind, Var, true) {} |
178 | |
179 | static bool classof(const Query *Q) { return Q->Kind == QK_EnableOutputKind; } |
180 | }; |
181 | |
182 | struct DisableOutputQuery : SetNonExclusiveOutputQuery { |
183 | DisableOutputQuery(bool QuerySession::*Var) |
184 | : SetNonExclusiveOutputQuery(QK_DisableOutputKind, Var, false) {} |
185 | |
186 | static bool classof(const Query *Q) { |
187 | return Q->Kind == QK_DisableOutputKind; |
188 | } |
189 | }; |
190 | |
191 | struct FileQuery : Query { |
192 | FileQuery(StringRef File, StringRef Prefix = StringRef()) |
193 | : Query(QK_File), File(File), |
194 | Prefix(!Prefix.empty() ? std::optional<std::string>(Prefix) |
195 | : std::nullopt) {} |
196 | |
197 | bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; |
198 | |
199 | static bool classof(const Query *Q) { return Q->Kind == QK_File; } |
200 | |
201 | private: |
202 | std::string File; |
203 | std::optional<std::string> Prefix; |
204 | }; |
205 | |
206 | } // namespace query |
207 | } // namespace clang |
208 | |
209 | #endif |
210 | |