diff --git a/src/class_diagram/visitor/translation_unit_context.cc b/src/class_diagram/visitor/translation_unit_context.cc index ae2fe3fb..3e200753 100644 --- a/src/class_diagram/visitor/translation_unit_context.cc +++ b/src/class_diagram/visitor/translation_unit_context.cc @@ -196,4 +196,17 @@ translation_unit_context::get_current_package() const return current_package_; } +void translation_unit_context::add_using_namespace_directive( + common::model::namespace_ ns) +{ + using_ns_declarations_[ns_.to_string()].insert(std::move(ns)); +} + +const std::set & +translation_unit_context::using_namespace_directive( + const common::model::namespace_ &ns) const +{ + return using_ns_declarations_.at(ns.to_string()); +} + } diff --git a/src/class_diagram/visitor/translation_unit_context.h b/src/class_diagram/visitor/translation_unit_context.h index 7775d89d..188eb1cf 100644 --- a/src/class_diagram/visitor/translation_unit_context.h +++ b/src/class_diagram/visitor/translation_unit_context.h @@ -78,10 +78,21 @@ public: type_safe::optional_ref get_current_package() const; + void add_using_namespace_directive(common::model::namespace_ ns); + + const std::set &using_namespace_directive( + const common::model::namespace_ &ns) const; + private: // Current visitor namespace common::model::namespace_ ns_; + // A map of 'using namespace' declared within a given namespace scope + // This is necessary to properly establish the namespace of a given entity + // for instance in unexposed template parameters + std::map> + using_ns_declarations_; + // Reference to the cppast entity index cppast::cpp_entity_index &entity_index_; diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 82cfc8cf..10394118 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -187,6 +187,8 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file) if (ns_ref.get(ctx.entity_index()).size() > 0) { auto full_ns = cx::util::full_name(ctx.get_namespace(), ns_ref.get(ctx.entity_index()).at(0).get()); + + ctx.add_using_namespace_directive(full_ns); } } }); diff --git a/src/common/model/namespace.cc b/src/common/model/namespace.cc index 8980eb12..37f42a5f 100644 --- a/src/common/model/namespace.cc +++ b/src/common/model/namespace.cc @@ -185,6 +185,11 @@ bool operator==(const namespace_ &left, const namespace_ &right) return left.namespace_path_ == right.namespace_path_; } +bool operator<(const namespace_ &left, const namespace_ &right) +{ + return std::hash{}(left) < std::hash{}(right); +} + std::string namespace_::name() const { assert(size() > 0); diff --git a/src/common/model/namespace.h b/src/common/model/namespace.h index a6fc88a6..e8c19c82 100644 --- a/src/common/model/namespace.h +++ b/src/common/model/namespace.h @@ -23,9 +23,9 @@ namespace clanguml::common::model { class namespace_ { +public: using container_type = std::vector; -public: namespace_() = default; namespace_(const std::string &ns); @@ -42,6 +42,7 @@ public: namespace_ &operator=(namespace_ &&right) noexcept = default; friend bool operator==(const namespace_ &left, const namespace_ &right); + friend bool operator<(const namespace_ &left, const namespace_ &right); namespace_(std::initializer_list ns); @@ -85,4 +86,23 @@ private: container_type namespace_path_; }; +} + +namespace std { + +template <> struct hash { + std::size_t operator()(const clanguml::common::model::namespace_ &key) const + { + using clanguml::common::model::namespace_; + + std::size_t seed = key.size(); + for (const auto &ns : key) { + seed ^= std::hash{}(ns) + 0x6a3712b5 + (seed << 6) + + (seed >> 2); + } + + return seed; + } +}; + } \ No newline at end of file