diff --git a/src/puml/class_diagram_generator.h b/src/puml/class_diagram_generator.h index 9acbd718..245eea7b 100644 --- a/src/puml/class_diagram_generator.h +++ b/src/puml/class_diagram_generator.h @@ -129,7 +129,7 @@ public: ostr << class_type << " \"" << c.full_name(m_config.using_namespace); - ostr << "\" as " << c.alias() << std::endl; + ostr << "\" as " << c.alias() << '\n'; } void generate_alias(const enum_ &e, std::ostream &ostr) const @@ -137,7 +137,7 @@ public: ostr << "enum" << " \"" << e.full_name(m_config.using_namespace); - ostr << "\" as " << e.alias() << std::endl; + ostr << "\" as " << e.alias() << '\n'; } void generate(const class_ &c, std::ostream &ostr) const @@ -149,7 +149,7 @@ public: if (c.is_abstract()) class_type = "abstract"; - ostr << class_type << " " << c.alias() << " {" << std::endl; + ostr << class_type << " " << c.alias() << " {" << '\n'; // // Process methods @@ -192,7 +192,7 @@ public: ostr << " : " << ns_relative(uns, type); - ostr << std::endl; + ostr << '\n'; } // @@ -234,7 +234,7 @@ public: rendered_relations.emplace(r.label); } - relstr << std::endl; + relstr << '\n'; all_relations_str << relstr.str(); } @@ -260,10 +260,10 @@ public: ostr << "{static} "; ostr << to_string(m.scope) << m.name << " : " - << ns_relative(uns, m.type) << std::endl; + << ns_relative(uns, m.type) << '\n'; } - ostr << "}" << std::endl; + ostr << "}" << '\n'; if (m_config.should_include_relationship("inheritance")) for (const auto &b : c.bases) { @@ -273,7 +273,7 @@ public: << " <|-- " << m_model.to_alias( uns, ns_relative(uns, c.full_name(uns))) - << std::endl; + << '\n'; ostr << relstr.str(); } catch (error::uml_alias_missing &e) { @@ -283,19 +283,30 @@ public: } } + // + // Process notes + // + for (auto decorator : c.decorators) { + auto note = std::dynamic_pointer_cast(decorator); + if (note) { + ostr << "note " << note->position << " of " << c.alias() + << " : " << note->text << '\n'; + } + } + // Print relationships ostr << all_relations_str.str(); } void generate(const enum_ &e, std::ostream &ostr) const { - ostr << "enum " << e.alias() << " {" << std::endl; + ostr << "enum " << e.alias() << " {" << '\n'; for (const auto &enum_constant : e.constants) { - ostr << enum_constant << std::endl; + ostr << enum_constant << '\n'; } - ostr << "}" << std::endl; + ostr << "}" << '\n'; for (const auto &r : e.relationships) { if (!m_config.should_include_relationship(name(r.type))) @@ -327,7 +338,7 @@ public: if (!r.label.empty()) relstr << " : " << r.label; - relstr << std::endl; + relstr << '\n'; ostr << relstr.str(); } catch (error::uml_alias_missing &ex) { @@ -340,7 +351,7 @@ public: void generate(std::ostream &ostr) const { - ostr << "@startuml" << std::endl; + ostr << "@startuml" << '\n'; for (const auto &b : m_config.puml.before) { std::string note{b}; @@ -352,7 +363,7 @@ public: note.replace( std::get<1>(alias_match), std::get<2>(alias_match), alias); } - ostr << note << std::endl; + ostr << note << '\n'; } if (m_config.should_include_entities("classes")) { @@ -361,14 +372,14 @@ public: !m_config.should_include(c.name)) continue; generate_alias(c, ostr); - ostr << std::endl; + ostr << '\n'; } for (const auto &e : m_model.enums) { if (!m_config.should_include(e.name)) continue; generate_alias(e, ostr); - ostr << std::endl; + ostr << '\n'; } for (const auto &c : m_model.classes) { @@ -376,14 +387,14 @@ public: !m_config.should_include(c.name)) continue; generate(c, ostr); - ostr << std::endl; + ostr << '\n'; } } if (m_config.should_include_entities("enums")) for (const auto &e : m_model.enums) { generate(e, ostr); - ostr << std::endl; + ostr << '\n'; } // Process aliases in any of the puml directives @@ -397,10 +408,10 @@ public: note.replace( std::get<1>(alias_match), std::get<2>(alias_match), alias); } - ostr << note << std::endl; + ostr << note << '\n'; } - ostr << "@enduml" << std::endl; + ostr << "@enduml" << '\n'; } friend std::ostream &operator<<(std::ostream &os, const generator &g); diff --git a/src/uml/class_diagram_model.h b/src/uml/class_diagram_model.h index 096ba0f2..014eb9f6 100644 --- a/src/uml/class_diagram_model.h +++ b/src/uml/class_diagram_model.h @@ -19,6 +19,7 @@ #include "util/error.h" #include "util/util.h" +#include "decorators.h" #include #include @@ -61,6 +62,7 @@ public: } std::string name; std::vector namespace_; + std::vector> decorators; std::string alias() const { return fmt::format("C_{:010}", m_id); } diff --git a/src/uml/class_diagram_visitor.cc b/src/uml/class_diagram_visitor.cc index b129b325..1a617ea9 100644 --- a/src/uml/class_diagram_visitor.cc +++ b/src/uml/class_diagram_visitor.cc @@ -229,6 +229,10 @@ void tu_visitor::process_class_declaration(const cppast::cpp_class &cls, cppast::cpp_access_specifier_kind last_access_specifier = cppast::cpp_access_specifier_kind::cpp_private; + // Process class documentation comment + if(cls.comment().has_value()) + c.decorators = decorators::parse(cls.comment().value()); + // Process class child entities if (c.is_struct) last_access_specifier = cppast::cpp_access_specifier_kind::cpp_public; diff --git a/src/uml/decorators.cc b/src/uml/decorators.cc index c5495c6d..c26cbeb1 100644 --- a/src/uml/decorators.cc +++ b/src/uml/decorators.cc @@ -36,12 +36,12 @@ std::shared_ptr decorator::from_string(std::string_view c) if (c.find(note::label) == 0) { return note::from_string(c); } - else if (c.find(skip::label) == 0) { - return skip::from_string(c); - } else if (c.find(skip_relationship::label) == 0) { return skip_relationship::from_string(c); } + else if (c.find(skip::label) == 0) { + return skip::from_string(c); + } else if (c.find(style::label) == 0) { return style::from_string(c); } @@ -58,17 +58,25 @@ std::shared_ptr note::from_string(std::string_view c) auto it = c.begin(); std::advance(it, note::label.size()); - if (*it != '[') - return {}; + if (*it == '[') { + std::advance(it, 1); - std::advance(it, 1); + auto pos = std::distance(c.begin(), it); + auto note_position = c.substr(pos, c.find("]", pos) - pos); + if (!note_position.empty()) + res->position = note_position; + + std::advance(it, note_position.size() + 1); + } + else if (*it == ' ') { + std::advance(it, 1); + } + else { + LOG_WARN("Invalid note decorator: {}", c); + return {}; + } auto pos = std::distance(c.begin(), it); - res->position = c.substr(pos, c.find("]", pos) - pos); - - std::advance(it, res->position.size() + 1); - - pos = std::distance(c.begin(), it); res->text = c.substr(pos, c.find("}", pos) - pos); res->position = util::trim(res->position); diff --git a/src/uml/decorators.h b/src/uml/decorators.h index 38870519..2ffac0b6 100644 --- a/src/uml/decorators.h +++ b/src/uml/decorators.h @@ -17,7 +17,6 @@ */ #pragma once -#include "config/config.h" #include #include #include @@ -34,7 +33,7 @@ struct decorator { struct note : public decorator { static const std::string label; - std::string position; + std::string position{"left"}; std::string text; static std::shared_ptr from_string(std::string_view c);