From a3459035d76f18d42d43137c9d178c528f202f68 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Tue, 23 Feb 2021 22:20:00 +0100 Subject: [PATCH] Added initial abstract class rendering --- src/cx/cursor.h | 17 +++++++++++++++++ src/puml/class_diagram_generator.h | 18 +++++++++++++++--- src/uml/class_diagram_model.h | 12 ++++++++++++ src/uml/class_diagram_visitor.h | 15 ++++++++++++++- tests/t00002/t00002.cc | 21 ++++++++++++++++++++- tests/test_cases.cc | 4 ++++ 6 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/cx/cursor.h b/src/cx/cursor.h index 8a309c06..33f3f3c8 100644 --- a/src/cx/cursor.h +++ b/src/cx/cursor.h @@ -132,6 +132,23 @@ public: bool is_preprocessing() const { return clang_isPreprocessing(kind()); } + bool is_method_virtual() const + { + return clang_CXXMethod_isVirtual(m_cursor); + } + + bool is_method_const() const { return clang_CXXMethod_isConst(m_cursor); } + + bool is_method_pure_virtual() const + { + return clang_CXXMethod_isPureVirtual(m_cursor); + } + + bool is_method_defaulted() const + { + return clang_CXXMethod_isDefaulted(m_cursor); + } + CXVisibilityKind visibitity() const { return clang_getCursorVisibility(m_cursor); diff --git a/src/puml/class_diagram_generator.h b/src/puml/class_diagram_generator.h index 9c4bdefa..8d0e82d2 100644 --- a/src/puml/class_diagram_generator.h +++ b/src/puml/class_diagram_generator.h @@ -94,11 +94,23 @@ public: void generate(const class_ &c, std::ostream &ostr) const { - ostr << "Class " << c.name << " {" << std::endl; + if (c.is_abstract()) + ostr << "abstract "; + else + ostr << "class "; + + ostr << c.name << " {" << std::endl; for (const auto &m : c.methods) { - ostr << to_string(m.scope) << m.type << " " << m.name + "()" - << std::endl; + if (m.is_pure_virtual) + ostr << "{abstract} "; + + ostr << to_string(m.scope) << m.type << " " << m.name + "()"; + + if (m.is_pure_virtual) + ostr << " = 0"; + + ostr << std::endl; } for (const auto &m : c.members) { diff --git a/src/uml/class_diagram_model.h b/src/uml/class_diagram_model.h index 1c90fb12..d55b6d42 100644 --- a/src/uml/class_diagram_model.h +++ b/src/uml/class_diagram_model.h @@ -63,6 +63,10 @@ struct method_argument { struct class_method : public class_element { std::vector arguments; + bool is_pure_virtual{false}; + bool is_virtual{false}; + bool is_const{false}; + bool is_defaulted{false}; }; struct class_parent { @@ -89,6 +93,14 @@ struct class_ : public element { std::vector inner_classes; std::vector relationships; + + bool is_abstract() const + { + // TODO check if all base abstract methods are overriden + // with non-abstract methods + return std::any_of(methods.begin(), methods.end(), + [](const auto &method) { return method.is_pure_virtual; }); + } }; struct enum_ : public element { diff --git a/src/uml/class_diagram_visitor.h b/src/uml/class_diagram_visitor.h index 366e63e7..da9f3419 100644 --- a/src/uml/class_diagram_visitor.h +++ b/src/uml/class_diagram_visitor.h @@ -84,6 +84,15 @@ enum CXChildVisitResult visit_if_cursor_valid( ret = CXChildVisit_Recurse; } } + else if (cursor.is_declaration()) { + if (cursor.is_method_pure_virtual()) { + f(cursor); + ret = CXChildVisit_Continue; + } + else { + ret = CXChildVisit_Recurse; + } + } else { ret = CXChildVisit_Continue; } @@ -143,7 +152,11 @@ static enum CXChildVisitResult class_visitor( visit_if_cursor_valid(cursor, [c](cx::cursor cursor) { class_method m; m.name = cursor.spelling(); - m.type = cursor.type().spelling(); + m.type = cursor.type().result_type().spelling(); + m.is_pure_virtual = cursor.is_method_pure_virtual(); + m.is_virtual = cursor.is_method_virtual(); + m.is_const = cursor.is_method_const(); + m.is_defaulted = cursor.is_method_defaulted(); spdlog::info("Adding method {} {}::{}()", m.type, c->name, cursor.spelling()); diff --git a/tests/t00002/t00002.cc b/tests/t00002/t00002.cc index e85a9bb6..b76abf07 100644 --- a/tests/t00002/t00002.cc +++ b/tests/t00002/t00002.cc @@ -5,16 +5,35 @@ namespace t00002 { class A { public: - virtual void foo() {} + virtual void foo_a() = 0; + virtual void foo_c() = 0; }; class B : public A { +public: + virtual void foo_a() override {} }; class C : public A { +public: + virtual void foo_c() override {} }; class D : public B, public C { +public: + void foo_a() override + { + for (auto a : as) + a->foo_a(); + } + + void foo_c() override + { + for (auto a : as) + a->foo_c(); + } + +private: std::vector as; }; } diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 103358cd..0489bae8 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -152,6 +152,10 @@ TEST_CASE("Test t00002", "[unit-test]") REQUIRE_THAT(puml, StartsWith("@startuml")); REQUIRE_THAT(puml, EndsWith("@enduml\n")); + REQUIRE_THAT(puml, Contains("abstract A")); + REQUIRE_THAT(puml, Contains("class B")); + REQUIRE_THAT(puml, Contains("class C")); + REQUIRE_THAT(puml, Contains("class D")); save_puml( "./" + config.output_directory + "/" + diagram->name + ".puml", puml);