diff --git a/CMakeLists.txt b/CMakeLists.txt index f72fd95d..743c636f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ message(STATUS "LLVM library dir: ${LLVM_LIBRARY_DIR}") if(MSVC) # LLVM_BUILD_LLVM_DYLIB is not available on Windows set(LINK_LLVM_SHARED NO) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif(MSVC) if(LINK_LLVM_SHARED) diff --git a/src/class_diagram/visitor/translation_unit_visitor.cc b/src/class_diagram/visitor/translation_unit_visitor.cc index 7206e50f..ea11207d 100644 --- a/src/class_diagram/visitor/translation_unit_visitor.cc +++ b/src/class_diagram/visitor/translation_unit_visitor.cc @@ -763,11 +763,10 @@ void translation_unit_visitor::process_class_children( // Static fields have to be processed by iterating over variable // declarations -#ifndef _MSC_VER for (const auto *decl : cls->decls()) { if (decl->getKind() == clang::Decl::Var) { const clang::VarDecl *variable_declaration{ - dynamic_cast(decl)}; + clang::dyn_cast_or_null(decl)}; if ((variable_declaration != nullptr) && variable_declaration->isStaticDataMember()) { process_static_field(*variable_declaration, c); @@ -789,7 +788,7 @@ void translation_unit_visitor::process_class_children( } } } -#endif + if (cls->isCompleteDefinition()) for (const auto *friend_declaration : cls->friends()) { if (friend_declaration != nullptr) diff --git a/src/common/generators/plantuml/generator.h b/src/common/generators/plantuml/generator.h index 9b62a281..70067bb9 100644 --- a/src/common/generators/plantuml/generator.h +++ b/src/common/generators/plantuml/generator.h @@ -569,6 +569,7 @@ template void generator::init_env() auto element_opt = m_model.get_with_namespace( args[0]->get(), m_config.using_namespace()); + if (!element_opt.has_value()) throw clanguml::error::uml_alias_missing( args[0]->get()); diff --git a/src/common/model/diagram.h b/src/common/model/diagram.h index e669fd10..b36a7ead 100644 --- a/src/common/model/diagram.h +++ b/src/common/model/diagram.h @@ -47,7 +47,7 @@ public: /// \brief Find element in diagram which can have full name or be /// relative to ns - common::optional_ref + virtual common::optional_ref get_with_namespace(const std::string &name, const namespace_ &ns) const; diagram(const diagram &) = delete; diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index bac06e6b..34154ca5 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -374,6 +374,8 @@ paths_filter::paths_filter(filter_t type, const std::filesystem::path &root, continue; } + absolute_path.make_preferred(); + paths_.emplace_back(std::move(absolute_path)); } } @@ -386,13 +388,15 @@ tvl::value_t paths_filter::match( } // Matching source paths doesn't make sens if they are not absolute - if (!p.is_absolute()) + if (!p.is_absolute()) { return {}; + } auto pp = p.fs_path(root_); for (const auto &path : paths_) { if (pp.root_name().string() == path.root_name().string() && - util::starts_with(pp, path)) { + util::starts_with(pp.relative_path(), path.relative_path())) { + return true; } } diff --git a/src/common/model/source_file.h b/src/common/model/source_file.h index 108e29ec..fbc00778 100644 --- a/src/common/model/source_file.h +++ b/src/common/model/source_file.h @@ -56,10 +56,12 @@ public: explicit source_file(const std::filesystem::path &p) { - set_path({p.parent_path().string()}); - set_name(p.filename().string()); - is_absolute_ = p.is_absolute(); - set_id(common::to_id(p)); + auto preferred = p; + preferred.make_preferred(); + set_path({preferred.parent_path().string()}); + set_name(preferred.filename().string()); + is_absolute_ = preferred.is_absolute(); + set_id(common::to_id(preferred)); } void set_path(const filesystem_path &p) { path_ = p; } @@ -118,6 +120,17 @@ public: return res.lexically_normal(); } + inja::json context() const override + { + inja::json ctx = diagram_element::context(); + + std::filesystem::path fullNamePath{ctx["full_name"].get()}; + fullNamePath.make_preferred(); + ctx["full_name"] = fullNamePath.string(); + + return ctx; + } + private: filesystem_path path_; source_file_t type_{source_file_t::kDirectory}; diff --git a/src/include_diagram/model/diagram.cc b/src/include_diagram/model/diagram.cc index f58f0bfb..dfd73bae 100644 --- a/src/include_diagram/model/diagram.cc +++ b/src/include_diagram/model/diagram.cc @@ -89,8 +89,12 @@ void diagram::add_file(std::unique_ptr &&f) common::optional_ref diagram::get_file( const std::string &name) const { + // Convert the name to the OS preferred path + std::filesystem::path namePath{name}; + namePath.make_preferred(); + for (const auto &p : files_) { - if (p.get().full_name(false) == name) { + if (p.get().full_name(false) == namePath.string()) { return {p}; } } @@ -135,6 +139,25 @@ diagram::files() const return files_; } +common::optional_ref +diagram::get_with_namespace(const std::string &name, const common::model::namespace_ &ns) const +{ + // Convert to preferred OS path + std::filesystem::path namePath{name}; + auto namePreferred = namePath.make_preferred().string(); + + auto element_opt = get(namePreferred); + + if (!element_opt) { + // If no element matches, try to prepend the 'using_namespace' + // value to the element and search again + auto fully_qualified_name = ns | namePreferred; + element_opt = get(fully_qualified_name.to_string()); + } + + return element_opt; +} + inja::json diagram::context() const { inja::json ctx; diff --git a/src/include_diagram/model/diagram.h b/src/include_diagram/model/diagram.h index df2f94b6..97692d7c 100644 --- a/src/include_diagram/model/diagram.h +++ b/src/include_diagram/model/diagram.h @@ -59,6 +59,9 @@ public: const common::reference_vector &files() const; + common::optional_ref + get_with_namespace(const std::string &name, const common::model::namespace_ &ns) const override; + inja::json context() const override; private: diff --git a/src/package_diagram/visitor/translation_unit_visitor.cc b/src/package_diagram/visitor/translation_unit_visitor.cc index 30349496..feb2d7f0 100644 --- a/src/package_diagram/visitor/translation_unit_visitor.cc +++ b/src/package_diagram/visitor/translation_unit_visitor.cc @@ -220,18 +220,16 @@ void translation_unit_visitor::process_class_children( // Static fields have to be processed by iterating over variable // declarations -#ifndef _MSC_VER for (const auto *decl : cls.decls()) { if (decl->getKind() == clang::Decl::Var) { const clang::VarDecl *variable_declaration{ - dynamic_cast(decl)}; + clang::dyn_cast_or_null(decl)}; if ((variable_declaration != nullptr) && variable_declaration->isStaticDataMember()) { process_static_field(*variable_declaration, relationships); } } } -#endif if (cls.isCompleteDefinition()) for (const auto *friend_declaration : cls.friends()) { diff --git a/tests/test_cases.cc b/tests/test_cases.cc index 2fb79ecb..03e575b0 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "test_cases.h" #include "common/generators/plantuml/generator.h" diff --git a/tests/test_model.cc b/tests/test_model.cc index 05ebd01e..0857422f 100644 --- a/tests/test_model.cc +++ b/tests/test_model.cc @@ -21,6 +21,7 @@ #include "common/model/namespace.h" + TEST_CASE("Test namespace_", "[unit-test]") { using clanguml::common::model::namespace_;