0.6.1
C++ to UML diagram generator based on Clang
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
call_expression_context.cc
Go to the documentation of this file.
1/**
2 * @file src/sequence_diagram/visitor/call_expression_context.cc
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
20
22
24
26{
28 current_class_decl_ = nullptr;
31 current_method_decl_ = nullptr;
32 current_function_decl_ = nullptr;
34 objc_interface_decl_ = nullptr;
35 objc_protocol_decl_ = nullptr;
36}
37
39{
40 LOG_DBG("current_caller_id_ = {}", current_caller_id_);
41 LOG_DBG("current_class_decl_ = {}", (void *)current_class_decl_);
42 LOG_DBG("current_class_template_decl_ = {}",
44 LOG_DBG("current_class_template_specialization_decl_ = {}",
46 LOG_DBG("current_method_decl_ = {}", (void *)current_method_decl_);
47 LOG_DBG("current_function_decl_ = {}", (void *)current_function_decl_);
48 LOG_DBG("current_function_template_decl_ = {}",
50 LOG_DBG("objc_interface_decl_ = {}", (void *)objc_interface_decl_);
51 LOG_DBG(
52 "current_objc_method_decl_ = {}", (void *)current_objc_method_decl_);
53 LOG_DBG("objc_protocol_decl_ = {}", (void *)objc_protocol_decl_);
54}
55
57{
58 return (current_class_decl_ != nullptr) ||
59 (current_class_template_decl_ != nullptr) ||
61 (current_method_decl_ != nullptr) ||
62 (current_function_decl_ != nullptr) ||
64 (objc_interface_decl_ != nullptr) ||
65 (current_objc_method_decl_ != nullptr) ||
66 (objc_protocol_decl_ != nullptr);
67}
68
70{
72 return &current_class_template_specialization_decl_->getASTContext();
73
74 if (current_class_template_decl_ != nullptr)
75 return &current_class_template_decl_->getASTContext();
76
77 if (current_class_decl_ != nullptr)
78 return &current_class_decl_->getASTContext();
79
81 return &current_function_template_decl_->getASTContext();
82
83 if (current_function_decl_ != nullptr) {
84 return &current_function_decl_->getASTContext();
85 }
86
87 if (current_method_decl_ != nullptr) {
88 return &current_method_decl_->getASTContext();
89 }
90
91 if (objc_interface_decl_ != nullptr) {
92 return &objc_interface_decl_->getASTContext();
93 }
94
95 if (objc_protocol_decl_ != nullptr) {
96 return &objc_protocol_decl_->getASTContext();
97 }
98
99 if (current_objc_method_decl_ != nullptr) {
100 return &current_objc_method_decl_->getASTContext();
101 }
102
103 return nullptr;
104}
105
106void call_expression_context::update(clang::CXXRecordDecl *cls)
107{
109}
110
111void call_expression_context::update(clang::ObjCInterfaceDecl *cls)
112{
114}
115
116void call_expression_context::update(clang::ObjCProtocolDecl *cls)
117{
119}
120
122 clang::ClassTemplateSpecializationDecl *clst)
123{
125}
126
127void call_expression_context::update(clang::ClassTemplateDecl *clst)
128{
130}
131
132void call_expression_context::update(clang::CXXMethodDecl *method)
133{
134 current_method_decl_ = method;
135}
136
137void call_expression_context::update(clang::ObjCMethodDecl *method)
138{
140}
141
142void call_expression_context::update(clang::FunctionDecl *function)
143{
144 if (!function->isCXXClassMember())
145 reset();
146
147 current_function_decl_ = function;
148
149 // Check if this function is a part of template function declaration,
150 // If no - reset the current_function_template_decl_
151 if ((current_function_template_decl_ != nullptr) &&
152 current_function_template_decl_->getQualifiedNameAsString() !=
153 function->getQualifiedNameAsString()) {
155 }
156}
157
159 clang::FunctionTemplateDecl *function_template)
160{
161 current_function_template_decl_ = function_template;
162
163 if (!function_template->isCXXClassMember())
164 current_class_decl_ = nullptr;
165
166 current_function_template_decl_ = function_template;
167}
168
170{
171 if (lambda_caller_id().has_value()) {
172 // Handle a case when local class is defined inside a lambda
173 if (!is_local_class())
174 return *lambda_caller_id(); // NOLINT
175 }
176
177 return current_caller_id_;
178}
179
181{
182 return current_class_decl_ != nullptr &&
183 current_class_decl_->isLocalClass() != nullptr;
184}
185
187{
188 if (current_lambda_caller_id_.empty())
189 return {};
190
191 return current_lambda_caller_id_.top();
192}
193
195{
196 LOG_DBG("Setting current caller id to {}", id);
198}
199
201{
202 LOG_DBG("Setting current lambda caller id to {}", id);
203
204 assert(id.value() != 0);
205
206 current_lambda_caller_id_.emplace(id);
207}
208
210{
211 if (current_lambda_caller_id_.empty())
212 return;
213
214 LOG_DBG("Leaving current lambda expression id to {}",
216
218}
219
221{
222 if (if_stmt_stack_.empty())
223 return nullptr;
224
225 return if_stmt_stack_.top();
226}
227
229{
230 if_stmt_stack_.emplace(stmt);
231}
232
234{
235 if (!if_stmt_stack_.empty()) {
237 if_stmt_stack_.pop();
238 }
239}
240
242{
243 assert(current_ifstmt() != nullptr);
244
245 elseif_stmt_stacks_[current_ifstmt()].emplace(stmt);
246}
247
249{
250 assert(current_ifstmt() != nullptr);
251
252 if (elseif_stmt_stacks_.count(current_ifstmt()) == 0 ||
254 return nullptr;
255
256 return elseif_stmt_stacks_.at(current_ifstmt()).top();
257}
258
260{
261 if (loop_stmt_stack_.empty())
262 return nullptr;
263
264 return loop_stmt_stack_.top();
265}
266
268{
269 loop_stmt_stack_.emplace(stmt);
270}
271
273{
274 if (!loop_stmt_stack_.empty())
275 return loop_stmt_stack_.pop();
276}
277
280{
281 if (call_expr_stack_.empty())
282 return {};
283
284 return call_expr_stack_.top();
285}
286
288{
289 call_expr_stack_.emplace(expr);
290}
291
292void call_expression_context::enter_callexpr(clang::CXXConstructExpr *expr)
293{
294 call_expr_stack_.emplace(expr);
295}
296
297void call_expression_context::enter_callexpr(clang::ObjCMessageExpr *expr)
298{
299 call_expr_stack_.emplace(expr);
300}
301
302void call_expression_context::enter_callexpr(clang::ReturnStmt *stmt)
303{
304 call_expr_stack_.emplace(stmt);
305}
306
307void call_expression_context::enter_callexpr(clang::CoreturnStmt *stmt)
308{
309 call_expr_stack_.emplace(stmt);
310}
311
312void call_expression_context::enter_callexpr(clang::CoyieldExpr *expr)
313{
314 call_expr_stack_.emplace(expr);
315}
316
317void call_expression_context::enter_callexpr(clang::CoawaitExpr *expr)
318{
319 call_expr_stack_.emplace(expr);
320}
321
323{
324 if (!call_expr_stack_.empty()) {
325 return call_expr_stack_.pop();
326 }
327}
328
330{
331 if (try_stmt_stack_.empty())
332 return nullptr;
333
334 return try_stmt_stack_.top();
335}
336
338{
339 try_stmt_stack_.emplace(stmt);
340}
341
343{
344 if (try_stmt_stack_.empty())
345 try_stmt_stack_.pop();
346}
347
349{
350 if (switch_stmt_stack_.empty())
351 return nullptr;
352
353 return switch_stmt_stack_.top();
354}
355
356void call_expression_context::enter_switchstmt(clang::SwitchStmt *stmt)
357{
358 switch_stmt_stack_.emplace(stmt);
359}
360
362{
363 if (switch_stmt_stack_.empty())
364 switch_stmt_stack_.pop();
365}
366
367clang::ConditionalOperator *
369{
370 if (conditional_operator_stack_.empty())
371 return nullptr;
372
373 return conditional_operator_stack_.top();
374}
375
377 clang::ConditionalOperator *stmt)
378{
379 conditional_operator_stack_.emplace(stmt);
380}
381
383{
384 if (!conditional_operator_stack_.empty())
386}
387
389 const clang::Stmt *stmt) const
390{
391 if (current_ifstmt() != nullptr) {
392 if (common::is_subexpr_of(current_ifstmt()->getCond(), stmt))
393 return true;
394
395 if (const auto *condition_decl_stmt = current_ifstmt()->getInit();
396 condition_decl_stmt != nullptr) {
397 if (common::is_subexpr_of(condition_decl_stmt, stmt))
398 return true;
399 }
400
401 if (current_elseifstmt() != nullptr) {
402 if (common::is_subexpr_of(current_elseifstmt()->getCond(), stmt))
403 return true;
404 }
405 }
406
407 if (current_conditionaloperator() != nullptr) {
409 current_conditionaloperator()->getCond(), stmt))
410 return true;
411 }
412
413 if (const auto *loop_stmt = current_loopstmt(); loop_stmt != nullptr) {
414 if (const auto *for_stmt = clang::dyn_cast<clang::ForStmt>(loop_stmt);
415 for_stmt != nullptr) {
416 if (common::is_subexpr_of(for_stmt->getCond(), stmt)) {
417 return true;
418 }
419 if (common::is_subexpr_of(for_stmt->getInit(), stmt)) {
420 return true;
421 }
422 if (common::is_subexpr_of(for_stmt->getInc(), stmt)) {
423 return true;
424 }
425 }
426
427 if (const auto *range_for_stmt =
428 clang::dyn_cast<clang::CXXForRangeStmt>(loop_stmt);
429 range_for_stmt != nullptr) {
430 if (common::is_subexpr_of(range_for_stmt->getRangeInit(), stmt)) {
431 return true;
432 }
433 }
434
435 if (const auto *while_stmt =
436 clang::dyn_cast<clang::WhileStmt>(loop_stmt);
437 while_stmt != nullptr) {
438 if (common::is_subexpr_of(while_stmt->getCond(), stmt)) {
439 return true;
440 }
441 }
442
443 if (const auto *do_stmt = clang::dyn_cast<clang::DoStmt>(loop_stmt);
444 do_stmt != nullptr) {
445 if (common::is_subexpr_of(do_stmt->getCond(), stmt)) {
446 return true;
447 }
448 }
449
450 if (current_conditionaloperator() != nullptr) {
452 current_conditionaloperator()->getCond(), stmt)) {
453 return true;
454 }
455 }
456 }
457
458 return false;
459}
460
461} // namespace clanguml::sequence_diagram::visitor