diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 2ffae1e8..26a02931 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -128,7 +128,7 @@ $ clang-uml --add-compile-flag -Wno-implicit-const-int-float-conversion \ Please note that if your `compile_commands.json` already contains - for instance `-Wshadow` - then you also have to remove it, i.e.: -``` +```yaml add_compile_flags: - -Wno-implicit-const-int-float-conversion - -Wno-shadow diff --git a/src/class_diagram/generators/json/class_diagram_generator.cc b/src/class_diagram/generators/json/class_diagram_generator.cc index c900e67e..73c19aa1 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.cc +++ b/src/class_diagram/generators/json/class_diagram_generator.cc @@ -54,12 +54,19 @@ void to_json(nlohmann::json &j, const class_method &c) { j = dynamic_cast(c); - j["is_static"] = c.is_static(); - j["is_const"] = c.is_const(); - j["is_defaulted"] = c.is_defaulted(); j["is_pure_virtual"] = c.is_pure_virtual(); j["is_virtual"] = c.is_virtual(); - j["is_implicit"] = c.is_implicit(); + j["is_const"] = c.is_const(); + j["is_defaulted"] = c.is_defaulted(); + j["is_deleted"] = c.is_deleted(); + j["is_static"] = c.is_static(); + j["is_noexcept"] = c.is_noexcept(); + j["is_constexpr"] = c.is_constexpr(); + j["is_consteval"] = c.is_consteval(); + j["is_constructor"] = c.is_constructor(); + j["is_move_assignment"] = c.is_move_assignment(); + j["is_copy_assignment"] = c.is_copy_assignment(); + j["is_operator"] = c.is_operator(); j["parameters"] = c.parameters(); } diff --git a/src/class_diagram/generators/plantuml/class_diagram_generator.cc b/src/class_diagram/generators/plantuml/class_diagram_generator.cc index 59f831b5..929a06fc 100644 --- a/src/class_diagram/generators/plantuml/class_diagram_generator.cc +++ b/src/class_diagram/generators/plantuml/class_diagram_generator.cc @@ -189,9 +189,17 @@ void generator::generate(const class_ &c, std::ostream &ostr) const } ostr << ")"; + if (m.is_constexpr()) + ostr << " constexpr"; + else if (m.is_consteval()) + ostr << " consteval"; + if (m.is_const()) ostr << " const"; + if (m.is_noexcept()) + ostr << " noexcept"; + assert(!(m.is_pure_virtual() && m.is_defaulted())); if (m.is_pure_virtual()) @@ -199,6 +207,8 @@ void generator::generate(const class_ &c, std::ostream &ostr) const if (m.is_defaulted()) ostr << " = default"; + else if (m.is_deleted()) + ostr << " = deleted"; ostr << " : " << type; diff --git a/src/class_diagram/model/class_method.cc b/src/class_diagram/model/class_method.cc index 3a3e5868..0044026c 100644 --- a/src/class_diagram/model/class_method.cc +++ b/src/class_diagram/model/class_method.cc @@ -48,10 +48,57 @@ void class_method::is_defaulted(bool is_defaulted) is_defaulted_ = is_defaulted; } +bool class_method::is_deleted() const { return is_deleted_; } + +void class_method::is_deleted(bool is_deleted) { is_deleted_ = is_deleted; } + bool class_method::is_static() const { return is_static_; } void class_method::is_static(bool is_static) { is_static_ = is_static; } +bool class_method::is_constexpr() const { return is_constexpr_; } + +void class_method::is_constexpr(bool is_constexpr) +{ + is_constexpr_ = is_constexpr; +} + +bool class_method::is_consteval() const { return is_consteval_; } + +void class_method::is_consteval(bool is_consteval) +{ + is_consteval_ = is_consteval; +} + +bool class_method::is_noexcept() const { return is_noexcept_; } + +void class_method::is_noexcept(bool is_noexcept) { is_noexcept_ = is_noexcept; } + +bool class_method::is_constructor() const { return is_constructor_; } + +void class_method::is_constructor(bool is_constructor) +{ + is_constructor_ = is_constructor; +} + +bool class_method::is_move_assignment() const { return is_move_assignment_; } + +void class_method::is_move_assignment(bool is_move_assignment) +{ + is_move_assignment_ = is_move_assignment; +} + +bool class_method::is_copy_assignment() const { return is_copy_assignment_; } + +void class_method::is_copy_assignment(bool is_copy_assignment) +{ + is_copy_assignment_ = is_copy_assignment; +} + +bool class_method::is_operator() const { return is_operator_; } + +void class_method::is_operator(bool is_operator) { is_operator_ = is_operator; } + const std::vector &class_method::parameters() const { return parameters_; diff --git a/src/class_diagram/model/class_method.h b/src/class_diagram/model/class_method.h index 51a6d4c2..1e44aff0 100644 --- a/src/class_diagram/model/class_method.h +++ b/src/class_diagram/model/class_method.h @@ -48,9 +48,33 @@ public: bool is_defaulted() const; void is_defaulted(bool is_defaulted); + bool is_deleted() const; + void is_deleted(bool is_deleted); + bool is_static() const; void is_static(bool is_static); + bool is_constexpr() const; + void is_constexpr(bool is_constexpr); + + bool is_consteval() const; + void is_consteval(bool is_consteval); + + bool is_noexcept() const; + void is_noexcept(bool is_noexcept); + + bool is_constructor() const; + void is_constructor(bool is_constructor); + + bool is_move_assignment() const; + void is_move_assignment(bool is_move_assignment); + + bool is_copy_assignment() const; + void is_copy_assignment(bool is_copy_assignment); + + bool is_operator() const; + void is_operator(bool is_operator); + const std::vector ¶meters() const; void add_parameter(method_parameter &¶meter); @@ -61,6 +85,14 @@ private: bool is_virtual_{false}; bool is_const_{false}; bool is_defaulted_{false}; + bool is_deleted_{false}; bool is_static_{false}; + bool is_noexcept_{false}; + bool is_constexpr_{false}; + bool is_consteval_{false}; + bool is_constructor_{false}; + bool is_move_assignment_{false}; + bool is_copy_assignment_{false}; + bool is_operator_{false}; }; } // namespace clanguml::class_diagram::model diff --git a/src/class_diagram/model/method_parameter.cc b/src/class_diagram/model/method_parameter.cc index e6a66a60..95773cfc 100644 --- a/src/class_diagram/model/method_parameter.cc +++ b/src/class_diagram/model/method_parameter.cc @@ -55,8 +55,12 @@ std::string method_parameter::to_string( auto name_ns = using_namespace.relative(common::model::namespace_{name()}.to_string()); - if (default_value().empty()) + if (default_value().empty()) { + if (name_ns.empty()) + return type_ns; + return fmt::format("{} {}", type_ns, name_ns); + } return fmt::format("{} {} = {}", type_ns, name_ns, default_value()); } diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 348858c0..3e897a14 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -1283,11 +1283,21 @@ void translation_unit_visitor::process_method( class_method method{common::access_specifier_to_access_t(mf.getAccess()), util::trim(method_name), method_return_type}; + const bool is_constructor = c.name() == method_name; + method.is_pure_virtual(mf.isPure()); method.is_virtual(mf.isVirtual()); method.is_const(mf.isConst()); method.is_defaulted(mf.isDefaulted()); + method.is_deleted(mf.isDeleted()); method.is_static(mf.isStatic()); + method.is_operator(mf.isOverloadedOperator()); + method.is_constexpr(mf.isConstexprSpecified() && !is_constructor); + method.is_consteval(mf.isConsteval()); + method.is_constructor(is_constructor); + method.is_move_assignment(mf.isMoveAssignmentOperator()); + method.is_copy_assignment(mf.isCopyAssignmentOperator()); + method.is_noexcept(isNoexceptExceptionSpec(mf.getExceptionSpecType())); process_comment(mf, method); diff --git a/tests/t00003/t00003.cc b/tests/t00003/t00003.cc index d5656ce3..9aadcac1 100644 --- a/tests/t00003/t00003.cc +++ b/tests/t00003/t00003.cc @@ -12,7 +12,7 @@ public: { } A(A &&) = default; - A(const A &) = default; + A(const A &) = delete; virtual ~A() = default; void basic_method() { } @@ -20,6 +20,17 @@ public: void const_method() const { } auto auto_method() { return 1; } + A &operator++() + { + private_member++; + return *this; + } + + A &operator=(A &&other) noexcept { return *this; } + A &operator=(A &other) noexcept { return *this; } + + constexpr std::size_t size() const { return private_member; } + auto double_int(const int i) { return 2 * i; } auto sum(const double a, const double b) { return a_ + b_ + c_; } diff --git a/tests/t00003/test_case.h b/tests/t00003/test_case.h index 19b9615d..9d06bd2f 100644 --- a/tests/t00003/test_case.h +++ b/tests/t00003/test_case.h @@ -44,6 +44,10 @@ TEST_CASE("t00003", "[test-case][class]") REQUIRE_THAT(puml, !IsDependency(_A("A"), _A("A"))); REQUIRE_THAT(puml, (IsMethod("A"))); + REQUIRE_THAT(puml, (IsMethod("A", "void", "A &&"))); + REQUIRE_THAT( + puml, (IsMethod("A", "void", "const A &"))); + REQUIRE_THAT(puml, (IsMethod("~A"))); REQUIRE_THAT(puml, (IsMethod("basic_method"))); @@ -55,6 +59,9 @@ TEST_CASE("t00003", "[test-case][class]") (IsMethod("default_string", "std::string", "int i, std::string s = \"abc\""))); + REQUIRE_THAT( + puml, (IsMethod("size", "std::size_t"))); + REQUIRE_THAT(puml, (IsMethod("protected_method"))); REQUIRE_THAT(puml, (IsMethod("private_method"))); REQUIRE_THAT(puml, (IsField("public_member", "int"))); diff --git a/tests/t00051/test_case.h b/tests/t00051/test_case.h index 6471d7cd..a90f27b9 100644 --- a/tests/t00051/test_case.h +++ b/tests/t00051/test_case.h @@ -45,7 +45,7 @@ TEST_CASE("t00051", "[test-case][class]") "Function && f, Args &&... args"))); REQUIRE_THAT(puml, (IsMethod("thread", "void", - "(lambda at ../../tests/t00051/t00051.cc:59:27) && "))); + "(lambda at ../../tests/t00051/t00051.cc:59:27) &&"))); REQUIRE_THAT(puml, (IsMethod("start_thread3", "B<(lambda at ../../tests/t00051/t00051.cc:43:18),(lambda at " diff --git a/tests/t00064/test_case.h b/tests/t00064/test_case.h index 804a4f96..d10e290e 100644 --- a/tests/t00064/test_case.h +++ b/tests/t00064/test_case.h @@ -68,12 +68,14 @@ TEST_CASE("t00064", "[test-case][class]") REQUIRE_THAT(puml, (IsMethod("getp", "value_type const*", "unsigned int i"))); REQUIRE_THAT(puml, - (IsMethod("find", "unsigned int", "value_type const& v"))); + (IsMethod( + "find", "unsigned int", "value_type const& v"))); #else REQUIRE_THAT(puml, (IsMethod("getp", "const value_type *", "unsigned int i"))); REQUIRE_THAT(puml, - (IsMethod("find", "unsigned int", "const value_type & v"))); + (IsMethod( + "find", "unsigned int", "const value_type & v"))); #endif save_puml( diff --git a/tests/test_cases.h b/tests/test_cases.h index 4ebd5bdb..e3e0e5ae 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -103,8 +103,16 @@ struct Static { }; struct Const { }; +struct Constexpr { }; + +struct Consteval { }; + +struct Noexcept { }; + struct Default { }; +struct Deleted { }; + struct HasCallWithResultMatcher : ContainsMatcher { HasCallWithResultMatcher( CasedString const &comparator, CasedString const &resultComparator) @@ -530,6 +538,12 @@ ContainsMatcher IsMethod(std::string const &name, pattern += "(" + params + ")"; + if constexpr (has_type()) + pattern += " constexpr"; + + if constexpr (has_type()) + pattern += " consteval"; + if constexpr (has_type()) pattern += " const"; @@ -539,6 +553,9 @@ ContainsMatcher IsMethod(std::string const &name, if constexpr (has_type()) pattern += " = default"; + if constexpr (has_type()) + pattern += " = deleted"; + pattern += " : " + type; return ContainsMatcher(CasedString(pattern, caseSensitivity)); diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 97734d89..a2360d57 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -4,7 +4,7 @@ test_cases: title: Basic class inheritance description: - name: t00003 - title: Class field and methods + title: Class fields and methods description: - name: t00004 title: Nested classes and enums