0.6.0
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-2025 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 *, clang::ObjCMessageExpr *>;
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 void update(clang::ObjCInterfaceDecl *cls);
81 void update(clang::ObjCProtocolDecl *cls);
82
83 /**
84 * @brief Set the current context to a class template specialization.
85 *
86 * @param clst Class template specialization declaration.
87 */
88 void update(clang::ClassTemplateSpecializationDecl *clst);
89
90 /**
91 * @brief Set the current context to a class template.
92 *
93 * @param clst Class template declaration.
94 */
95 void update(clang::ClassTemplateDecl *clst);
96
97 /**
98 * @brief Set the current context to a class method.
99 *
100 * @param method Class method declaration.
101 */
102 void update(clang::CXXMethodDecl *method);
103 void update(clang::ObjCMethodDecl *method);
104
105 /**
106 * @brief Set the current context to a function.
107 *
108 * @param function Function declaration.
109 */
110 void update(clang::FunctionDecl *function);
111
112 /**
113 * @brief Set the current context to a function template.
114 *
115 * @param function_template Function template declaration.
116 */
117 void update(clang::FunctionTemplateDecl *function_template);
118
119 /**
120 * @brief Set current caller to id of the current participant.
121 *
122 * @param id Set current caller id.
123 */
124 void set_caller_id(eid_t id);
125
126 /**
127 * @brief Get current caller id
128 *
129 * @return Id of the current caller participant
130 */
131 eid_t caller_id() const;
132
133 /**
134 * @brief Get the id of the current lambda caller.
135 *
136 * Since lambdas can be nested within methods and functions, they have
137 * a separate caller id field.
138 *
139 * @return Current lambda caller id, or 0 if current caller is not lambda.
140 */
141 std::optional<eid_t> lambda_caller_id() const;
142
143 /**
144 * @brief Enter a lambda expression
145 *
146 * @param id Lambda id
147 */
149
150 /**
151 * @brief Leave current lambda expression
152 */
154
155 /**
156 * @brief Get current `if` statement block
157 *
158 * @return `if` statement block.
159 */
160 clang::IfStmt *current_ifstmt() const;
161
162 /**
163 * @brief Enter `if` statement block
164 *
165 * @param stmt `if` statement block
166 */
167 void enter_ifstmt(clang::IfStmt *stmt);
168
169 /**
170 * @brief Leave `if` statement block
171 */
172 void leave_ifstmt();
173
174 /**
175 * @brief Enter `else if` statement block
176 *
177 * @param stmt `if` statement block
178 */
179 void enter_elseifstmt(clang::IfStmt *stmt);
180
181 /**
182 * @brief Get current `else if` statement block
183 *
184 * @return `if` statement block.
185 */
186 clang::IfStmt *current_elseifstmt() const;
187
188 /**
189 * @brief Get current loop statement block
190 *
191 * @return Loop statement block.
192 */
193 clang::Stmt *current_loopstmt() const;
194
195 /**
196 * @brief Enter loop statement block
197 *
198 * @param stmt Loop statement block
199 */
200 void enter_loopstmt(clang::Stmt *stmt);
201
202 /**
203 * @brief Leave loop statement block
204 */
205 void leave_loopstmt();
206
207 /**
208 * @brief Get current `try` statement block
209 *
210 * @return `try` statement block.
211 */
212 clang::Stmt *current_trystmt() const;
213
214 /**
215 * @brief Enter `try` statement block
216 *
217 * @param stmt `try` statement block
218 */
219 void enter_trystmt(clang::Stmt *stmt);
220
221 /**
222 * @brief Leave `try` statement block
223 */
224 void leave_trystmt();
225
226 /**
227 * @brief Get current `switch` statement block
228 *
229 * @return `switch` statement block.
230 */
231 clang::SwitchStmt *current_switchstmt() const;
232
233 /**
234 * @brief Enter `switch` statement block
235 *
236 * @param stmt `switch` statement block
237 */
238 void enter_switchstmt(clang::SwitchStmt *stmt);
239
240 /**
241 * @brief Leave `switch` statement block
242 */
243 void leave_switchstmt();
244
245 /**
246 * @brief Get current `:?` statement block
247 *
248 * @return `:?` statement block.
249 */
250 clang::ConditionalOperator *current_conditionaloperator() const;
251
252 /**
253 * @brief Enter `:?` statement block
254 *
255 * @param stmt `:?` statement block
256 */
257 void enter_conditionaloperator(clang::ConditionalOperator *stmt);
258
259 /**
260 * @brief Leave `:?` statement block
261 */
263
264 /**
265 * @brief Get current call expression
266 *
267 * @return Call expression
268 */
270
271 /**
272 * @brief Enter a call expression
273 *
274 * @param expr Call expression
275 */
276 void enter_callexpr(clang::CallExpr *expr);
277
278 /**
279 * @brief Enter a constructor call expression
280 *
281 * @param expr Constructor call expression
282 */
283 void enter_callexpr(clang::CXXConstructExpr *expr);
284 void enter_callexpr(clang::ObjCMessageExpr *expr);
285
286 /**
287 * @brief Leave call expression
288 */
289 void leave_callexpr();
290
291 /**
292 * @brief Check, if a statement is contained in a control statement
293 *
294 * This method is used to check if `stmt` is contained in control
295 * statement of a block, for instance:
296 *
297 * ```cpp
298 * if(a.method1()) {}
299 * ```
300 * it will return `true` for `stmt` representing `method1()` call
301 * expression.
302 *
303 * @param stmt Statement
304 * @return True, if `stmt` is contained in control expression of a
305 * statement block
306 */
308 const clang::Stmt *stmt) const;
309
310 /**
311 * @brief Print the current call expression stack for debugging.
312 */
313 void dump();
314
315 clang::CXXRecordDecl *current_class_decl_{nullptr};
316 clang::ClassTemplateDecl *current_class_template_decl_{nullptr};
317 clang::ClassTemplateSpecializationDecl
319 clang::CXXMethodDecl *current_method_decl_{nullptr};
320 clang::ObjCMethodDecl *current_objc_method_decl_{nullptr};
321 clang::FunctionDecl *current_function_decl_{nullptr};
322 clang::FunctionTemplateDecl *current_function_template_decl_{nullptr};
323 clang::ObjCInterfaceDecl *objc_interface_decl_{nullptr};
324 clang::ObjCProtocolDecl *objc_protocol_decl_{nullptr};
325
326private:
328 std::stack<eid_t> current_lambda_caller_id_;
329
330 std::stack<callexpr_stack_t> call_expr_stack_;
331
332 std::stack<clang::IfStmt *> if_stmt_stack_;
333 std::map<clang::IfStmt *, std::stack<clang::IfStmt *>> elseif_stmt_stacks_;
334
335 std::stack<clang::Stmt *> loop_stmt_stack_;
336 std::stack<clang::Stmt *> try_stmt_stack_;
337 std::stack<clang::SwitchStmt *> switch_stmt_stack_;
338 std::stack<clang::ConditionalOperator *> conditional_operator_stack_;
339};
340
341} // namespace clanguml::sequence_diagram::visitor