diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index bc81ce8d..fd3be159 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -73,6 +73,8 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const assert(!full_name.empty()); + print_debug(c, ostr); + ostr << class_type << " \"" << m_config.simplify_template_type(render_name(full_name)); @@ -84,6 +86,8 @@ void generator::generate_alias(const class_ &c, std::ostream &ostr) const void generator::generate_alias(const enum_ &e, std::ostream &ostr) const { + print_debug(e, ostr); + if (m_config.generate_packages()) ostr << "enum" << " \"" << e.name(); @@ -127,6 +131,8 @@ void generator::generate(const class_ &c, std::ostream &ostr) const if (!m_model.should_include(m.access())) continue; + print_debug(m, ostr); + if (m.is_pure_virtual()) ostr << "{abstract} "; @@ -237,6 +243,8 @@ void generator::generate(const class_ &c, std::ostream &ostr) const rendered_relations.find(m.name()) != rendered_relations.end()) continue; + print_debug(m, ostr); + if (m.is_static()) ostr << "{static} "; @@ -424,6 +432,7 @@ void generator::generate(const package &p, std::ostream &ostr) const // Don't generate packages from namespaces filtered out by // using_namespace if (!uns.starts_with({p.full_name(false)})) { + print_debug(p, ostr); ostr << "package [" << p.name() << "] "; ostr << "as " << p.alias(); diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index c7a09737..7ed6db42 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -140,9 +140,11 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm) // If not, check if the parent template declaration is in the model if (!id_opt) { - local_id = parent_record_decl->getDescribedTemplate()->getID(); - if (parent_record_decl->getDescribedTemplate() != nullptr) + if (parent_record_decl->getDescribedTemplate() != nullptr) { + local_id = + parent_record_decl->getDescribedTemplate()->getID(); id_opt = get_ast_local_id(local_id); + } } } } @@ -429,9 +431,11 @@ std::unique_ptr translation_unit_visitor::create_class_declaration( // If not, check if the parent template declaration is in the model if (!id_opt) { - local_id = parent_record_decl->getDescribedTemplate()->getID(); - if (parent_record_decl->getDescribedTemplate() != nullptr) + if (parent_record_decl->getDescribedTemplate() != nullptr) { + local_id = + parent_record_decl->getDescribedTemplate()->getID(); id_opt = get_ast_local_id(local_id); + } } } } diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index b37211a6..92935fbe 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -124,6 +124,14 @@ public: template void generate_link(std::ostream &ostr, const E &e) const; + /** + * @brief Print debug information in diagram comments + * + * @param m Diagram element to describe + * @param ostr Output stream + */ + void print_debug( + const common::model::source_location &e, std::ostream &ostr) const; /** * @brief Update diagram Jinja context * @@ -345,6 +353,14 @@ void generator::generate_link(std::ostream &ostr, const E &e) const ostr << "]]"; } +template +void generator::print_debug( + const common::model::source_location &e, std::ostream &ostr) const +{ + if (m_config.debug_mode()) + ostr << "' " << e.file() << ":" << e.line() << '\n'; +} + template class diagram_ast_consumer : public clang::ASTConsumer { diff --git a/src/common/visitor/translation_unit_visitor.cc b/src/common/visitor/translation_unit_visitor.cc index 729234a6..37c6b6ed 100644 --- a/src/common/visitor/translation_unit_visitor.cc +++ b/src/common/visitor/translation_unit_visitor.cc @@ -75,6 +75,13 @@ void translation_unit_visitor::set_source_location( set_source_location(expr.getBeginLoc(), element); } +void translation_unit_visitor::set_source_location( + const clang::Stmt &stmt, clanguml::common::model::source_location &element) +{ + set_source_location(stmt.getBeginLoc(), element); +} + + void translation_unit_visitor::set_source_location( const clang::SourceLocation &location, clanguml::common::model::source_location &element) diff --git a/src/common/visitor/translation_unit_visitor.h b/src/common/visitor/translation_unit_visitor.h index 0a61e13c..be84d64e 100644 --- a/src/common/visitor/translation_unit_visitor.h +++ b/src/common/visitor/translation_unit_visitor.h @@ -79,6 +79,9 @@ protected: void set_source_location(const clang::Expr &expr, clanguml::common::model::source_location &element); + void set_source_location(const clang::Stmt &stmt, + clanguml::common::model::source_location &element); + /** * @brief Set source location in diagram element * diff --git a/src/config/config.cc b/src/config/config.cc index 8d7bd707..c8809682 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -102,6 +102,7 @@ void inheritable_diagram_options::inherit( comment_parser.override(parent.comment_parser); combine_free_functions_into_file_participants.override( combine_free_functions_into_file_participants); + debug_mode.override(parent.debug_mode); } std::string inheritable_diagram_options::simplify_template_type( @@ -551,6 +552,7 @@ template bool decode_diagram(const Node &node, T &rhs) get_option(node, rhs.generate_links); get_option(node, rhs.type_aliases); get_option(node, rhs.comment_parser); + get_option(node, rhs.debug_mode); return true; } @@ -734,6 +736,7 @@ template <> struct convert { get_option(node, rhs.generate_links); get_option(node, rhs.generate_system_headers); get_option(node, rhs.git); + get_option(node, rhs.debug_mode); rhs.base_directory.set(node["__parent_path"].as()); get_option(node, rhs.relative_to); diff --git a/src/config/config.h b/src/config/config.h index 5bd8d477..9c136568 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -145,6 +145,7 @@ struct inheritable_diagram_options { option combine_free_functions_into_file_participants{ "combine_free_functions_into_file_participants", false}; option> participants_order{"participants_order"}; + option debug_mode{"debug_mode", false}; void inherit(const inheritable_diagram_options &parent); diff --git a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc index 875b66c1..81cc5352 100644 --- a/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc +++ b/src/sequence_diagram/generators/plantuml/sequence_diagram_generator.cc @@ -86,6 +86,8 @@ void generator::generate_call(const message &m, std::ostream &ostr) const const std::string from_alias = generate_alias(from.value()); const std::string to_alias = generate_alias(to.value()); + print_debug(m, ostr); + ostr << from_alias << " " << common::generators::plantuml::to_plantuml(message_t::kCall) << " "; @@ -169,57 +171,70 @@ void generator::generate_activity(const activity &a, std::ostream &ostr, visited.pop_back(); } else if (m.type() == message_t::kIf) { + print_debug(m, ostr); ostr << "alt\n"; } else if (m.type() == message_t::kElseIf) { + print_debug(m, ostr); ostr << "else\n"; } else if (m.type() == message_t::kElse) { + print_debug(m, ostr); ostr << "else\n"; } else if (m.type() == message_t::kIfEnd) { ostr << "end\n"; } else if (m.type() == message_t::kWhile) { + print_debug(m, ostr); ostr << "loop\n"; } else if (m.type() == message_t::kWhileEnd) { ostr << "end\n"; } else if (m.type() == message_t::kFor) { + print_debug(m, ostr); ostr << "loop\n"; } else if (m.type() == message_t::kForEnd) { ostr << "end\n"; } else if (m.type() == message_t::kDo) { + print_debug(m, ostr); ostr << "loop\n"; } else if (m.type() == message_t::kDoEnd) { ostr << "end\n"; } else if (m.type() == message_t::kTry) { + print_debug(m, ostr); ostr << "group try\n"; } else if (m.type() == message_t::kCatch) { + print_debug(m, ostr); ostr << "else " << m.message_name() << '\n'; } else if (m.type() == message_t::kTryEnd) { + print_debug(m, ostr); ostr << "end\n"; } else if (m.type() == message_t::kSwitch) { + print_debug(m, ostr); ostr << "group switch\n"; } else if (m.type() == message_t::kCase) { + print_debug(m, ostr); ostr << "else " << m.message_name() << '\n'; } else if (m.type() == message_t::kSwitchEnd) { ostr << "end\n"; } else if (m.type() == message_t::kConditional) { + print_debug(m, ostr); ostr << "alt\n"; } else if (m.type() == message_t::kElse) { + print_debug(m, ostr); ostr << "else\n"; } else if (m.type() == message_t::kConditionalEnd) { @@ -279,6 +294,8 @@ void generator::generate_participant( const auto &class_participant = m_model.get_participant(class_id).value(); + print_debug(class_participant, ostr); + ostr << "participant \"" << render_name(m_config.using_namespace().relative( class_participant.full_name(false))) @@ -325,6 +342,8 @@ void generator::generate_participant( generated_participants_.emplace(file_id); } else { + print_debug(participant, ostr); + ostr << "participant \"" << m_config.using_namespace().relative( participant.full_name(false))