0.5.4
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
call_expression_context.h
Go to the documentation of this file.
1/**
2 * @file src/sequence_diagram/visitor/call_expression_context.h
3 *
4 * Copyright (c) 2021-2024 Bartek Kryza <bkryza@gmail.com>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18#pragma once
19
20#include "common/clang_utils.h"
21#include "util/util.h"
22
23#include <clang/AST/Expr.h>
24#include <clang/AST/RecursiveASTVisitor.h>
25#include <clang/Basic/SourceManager.h>
26
27#include <stack>
28
30
32
33/**
34 * @brief This class is used to track current context of the call expressions.
35 *
36 * When traversing AST for call expressions, we need to keep the state of
37 * the current context, for instance whether we are in a `for` loop or
38 * an `if` block, as well as the current parent of the call expression
39 * e.g. a class method or function.
40 */
42 /**
43 * In Clang, call to a class constructor is represented by
44 * `clang::CXXConstructExpr`, which does inherit from `clang::CallExpr`.
45 * So to enable to track calls to constructors, we need to be able
46 * to add to the call stack either type.
47 */
48 using callexpr_stack_t = std::variant<std::monostate, clang::CallExpr *,
49 clang::CXXConstructExpr *>;
50
52
53 /**
54 * @brief Reset call expression context to the original state.
55 */
56 void reset();
57
58 /**
59 * @brief Verify that the context is in a valid state.
60 *
61 * Context can only be in a single state (for instance inside a function).
62 *
63 * @return True, if the context is in a valid state.
64 */
65 bool valid() const;
66
67 /**
68 * @brief
69 *
70 * @return Current AST context
71 */
72 clang::ASTContext *get_ast_context() const;
73
74 /**
75 * @brief Set the current context to a class.
76 *
77 * @param cls Class declaration.
78 */
79 void update(clang::CXXRecordDecl *cls);
80
81 /**
82 * @brief Set the current context to a class template specialization.
83 *
84 * @param clst Class template specialization declaration.
85 */
86 void update(clang::ClassTemplateSpecializationDecl *clst);
87
88 /**
89 * @brief Set the current context to a class template.
90 *
91 * @param clst Class template declaration.
92 */
93 void update(clang::ClassTemplateDecl *clst);
94
95 /**
96 * @brief Set the current context to a class method.
97 *
98 * @param method Class method declaration.
99 */
100 void update(clang::CXXMethodDecl *method);
101
102 /**
103 * @brief Set the current context to a function.
104 *
105 * @param function Function declaration.
106 */
107 void update(clang::FunctionDecl *function);
108
109 /**
110 * @brief Set the current context to a function template.
111 *
112 * @param function_template Function template declaration.
113 */
114 void update(clang::FunctionTemplateDecl *function_template);
115
116 /**
117 * @brief Set current caller to id of the current participant.
118 *
119 * @param id Set current caller id.
120 */
121 void set_caller_id(eid_t id);
122
123 /**
124 * @brief Get current caller id
125 *
126 * @return Id of the current caller participant
127 */
128 eid_t caller_id() const;
129
130 /**
131 * @brief Get the id of the current lambda caller.
132 *
133 * Since lambdas can be nested within methods and functions, they have
134 * a separate caller id field.
135 *
136 * @return Current lambda caller id, or 0 if current caller is not lambda.
137 */
138 std::optional<eid_t> lambda_caller_id() const;
139
140 /**
141 * @brief Enter a lambda expression
142 *
143 * @param id Lambda id
144 */
146
147 /**
148 * @brief Leave current lambda expression
149 */
151
152 /**
153 * @brief Get current `if` statement block
154 *
155 * @return `if` statement block.
156 */
157 clang::IfStmt *current_ifstmt() const;
158
159 /**
160 * @brief Enter `if` statement block
161 *
162 * @param stmt `if` statement block
163 */
164 void enter_ifstmt(clang::IfStmt *stmt);
165
166 /**
167 * @brief Leave `if` statement block
168 */
169 void leave_ifstmt();
170
171 /**
172 * @brief Enter `else if` statement block
173 *
174 * @param stmt `if` statement block
175 */
176 void enter_elseifstmt(clang::IfStmt *stmt);
177
178 /**
179 * @brief Get current `else if` statement block
180 *
181 * @return `if` statement block.
182 */
183 clang::IfStmt *current_elseifstmt() const;
184
185 /**
186 * @brief Get current loop statement block
187 *
188 * @return Loop statement block.
189 */
190 clang::Stmt *current_loopstmt() const;
191
192 /**
193 * @brief Enter loop statement block
194 *
195 * @param stmt Loop statement block
196 */
197 void enter_loopstmt(clang::Stmt *stmt);
198
199 /**
200 * @brief Leave loop statement block
201 */
202 void leave_loopstmt();
203
204 /**
205 * @brief Get current `try` statement block
206 *
207 * @return `try` statement block.
208 */
209 clang::Stmt *current_trystmt() const;
210
211 /**
212 * @brief Enter `try` statement block
213 *
214 * @param stmt `try` statement block
215 */
216 void enter_trystmt(clang::Stmt *stmt);
217
218 /**
219 * @brief Leave `try` statement block
220 */
221 void leave_trystmt();
222
223 /**
224 * @brief Get current `switch` statement block
225 *
226 * @return `switch` statement block.
227 */
228 clang::SwitchStmt *current_switchstmt() const;
229
230 /**
231 * @brief Enter `switch` statement block
232 *
233 * @param stmt `switch` statement block
234 */
235 void enter_switchstmt(clang::SwitchStmt *stmt);
236
237 /**
238 * @brief Leave `switch` statement block
239 */
240 void leave_switchstmt();
241
242 /**
243 * @brief Get current `:?` statement block
244 *
245 * @return `:?` statement block.
246 */
247 clang::ConditionalOperator *current_conditionaloperator() const;
248
249 /**
250 * @brief Enter `:?` statement block
251 *
252 * @param stmt `:?` statement block
253 */
254 void enter_conditionaloperator(clang::ConditionalOperator *stmt);
255
256 /**
257 * @brief Leave `:?` statement block
258 */
260
261 /**
262 * @brief Get current call expression
263 *
264 * @return Call expression
265 */
267
268 /**
269 * @brief Enter a call expression
270 *
271 * @param expr Call expression
272 */
273 void enter_callexpr(clang::CallExpr *expr);
274
275 /**
276 * @brief Enter a constructor call expression
277 *
278 * @param expr Constructor call expression
279 */
280 void enter_callexpr(clang::CXXConstructExpr *expr);
281
282 /**
283 * @brief Leave call expression
284 */
285 void leave_callexpr();
286
287 /**
288 * @brief Check, if a statement is contained in a control statement
289 *
290 * This method is used to check if `stmt` is contained in control
291 * statement of a block, for instance:
292 *
293 * ```cpp
294 * if(a.method1()) {}
295 * ```
296 * it will return `true` for `stmt` representing `method1()` call
297 * expression.
298 *
299 * @param stmt Statement
300 * @return True, if `stmt` is contained in control expression of a
301 * statement block
302 */
304 const clang::Stmt *stmt) const;
305
306 /**
307 * @brief Print the current call expression stack for debugging.
308 */
309 void dump();
310
311 clang::CXXRecordDecl *current_class_decl_{nullptr};
312 clang::ClassTemplateDecl *current_class_template_decl_{nullptr};
313 clang::ClassTemplateSpecializationDecl
315 clang::CXXMethodDecl *current_method_decl_{nullptr};
316 clang::FunctionDecl *current_function_decl_{nullptr};
317 clang::FunctionTemplateDecl *current_function_template_decl_{nullptr};
318
319private:
321 std::stack<eid_t> current_lambda_caller_id_;
322
323 std::stack<callexpr_stack_t> call_expr_stack_;
324
325 std::stack<clang::IfStmt *> if_stmt_stack_;
326 std::map<clang::IfStmt *, std::stack<clang::IfStmt *>> elseif_stmt_stacks_;
327
328 std::stack<clang::Stmt *> loop_stmt_stack_;
329 std::stack<clang::Stmt *> try_stmt_stack_;
330 std::stack<clang::SwitchStmt *> switch_stmt_stack_;
331 std::stack<clang::ConditionalOperator *> conditional_operator_stack_;
332};
333
334} // namespace clanguml::sequence_diagram::visitor