Fixed dependency generation for template specializations
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
@@ -51,8 +53,10 @@ struct diagram {
|
||||
|
||||
plantuml puml;
|
||||
|
||||
bool should_include(const std::string &name) const
|
||||
bool should_include(const std::string &name_) const
|
||||
{
|
||||
auto name = clanguml::util::unqualify(name_);
|
||||
|
||||
for (const auto &ex : exclude.namespaces) {
|
||||
if (name.find(ex) == 0)
|
||||
return false;
|
||||
@@ -68,6 +72,8 @@ struct diagram {
|
||||
return true;
|
||||
}
|
||||
|
||||
spdlog::debug("Skipping from diagram: {}", name);
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,5 +38,13 @@ std::string type::instantiation_template() const
|
||||
|
||||
return cur.fully_qualified();
|
||||
}
|
||||
|
||||
bool type::is_template_instantiation() const
|
||||
{
|
||||
auto s = spelling();
|
||||
auto it = s.find('<');
|
||||
return it != std::string::npos &&
|
||||
referenced().type_declaration().kind() != CXCursor_ClassTemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,12 +205,7 @@ public:
|
||||
return clang_Type_getCXXRefQualifier(m_type);
|
||||
}
|
||||
|
||||
bool is_template_instantiation() const
|
||||
{
|
||||
auto s = spelling();
|
||||
auto it = s.find('<');
|
||||
return it != std::string::npos;
|
||||
}
|
||||
bool is_template_instantiation() const;
|
||||
|
||||
std::string instantiation_template() const;
|
||||
|
||||
@@ -221,18 +216,7 @@ public:
|
||||
*/
|
||||
std::string unqualified() const
|
||||
{
|
||||
auto toks = clanguml::util::split(spelling(), " ");
|
||||
const std::vector<std::string> qualifiers = {
|
||||
"static", "const", "volatile", "register", "mutable"};
|
||||
|
||||
toks.erase(toks.begin(),
|
||||
std::find_if(
|
||||
toks.begin(), toks.end(), [&qualifiers](const auto &t) {
|
||||
return std::count(
|
||||
qualifiers.begin(), qualifiers.end(), t) == 0;
|
||||
}));
|
||||
|
||||
return fmt::format("{}", fmt::join(toks, " "));
|
||||
return clanguml::util::unqualify(spelling());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -183,7 +183,8 @@ enum CXChildVisitResult method_parameter_visitor(
|
||||
switch (cursor.kind()) {
|
||||
case CXCursor_ParmDecl: {
|
||||
spdlog::debug("Analyzing method parameter: {}, {}, {}", cursor,
|
||||
cursor.type(), cursor.type().named_type());
|
||||
cursor.type().referenced(),
|
||||
cursor.type().referenced().type_declaration());
|
||||
|
||||
auto t = cursor.type();
|
||||
method_parameter mp;
|
||||
@@ -198,6 +199,10 @@ enum CXChildVisitResult method_parameter_visitor(
|
||||
if (t.is_template_instantiation()) {
|
||||
rdestination = t.referenced().instantiation_template();
|
||||
}
|
||||
else if (t.spelling().find('<') != std::string::npos) {
|
||||
rdestination =
|
||||
t.referenced().type_declaration().fully_qualified();
|
||||
}
|
||||
else {
|
||||
rdestination = t.referenced().spelling();
|
||||
}
|
||||
@@ -205,18 +210,43 @@ enum CXChildVisitResult method_parameter_visitor(
|
||||
if (ctx->ctx->config.should_include(rdestination) &&
|
||||
rdestination != ctx->parent_class->name) {
|
||||
|
||||
spdlog::debug("ADDING DEPENDENCY TO {} \n\tCURSOR={} "
|
||||
spdlog::debug("Adding dependency to {} \n\tCURSOR={} "
|
||||
"\n\tREFTYPE={} \n\tTYPEDECL={}",
|
||||
rdestination, cursor, t.referenced(),
|
||||
t.referenced().type_declaration().usr());
|
||||
t.referenced().spelling(), cursor, t.referenced(),
|
||||
t.referenced().type_declaration());
|
||||
|
||||
class_relationship r;
|
||||
r.type = relationship_t::kDependency;
|
||||
r.destination = t.referenced().type_declaration().usr();
|
||||
|
||||
if (t.referenced().is_template_instantiation() &&
|
||||
(t.referenced().type_declaration().kind() !=
|
||||
CXCursor_InvalidFile ||
|
||||
t.referenced()
|
||||
.type_declaration()
|
||||
.specialized_cursor_template()
|
||||
.kind() != CXCursor_InvalidFile)) {
|
||||
class_ tinst = build_template_instantiation(
|
||||
cursor, t.referenced());
|
||||
|
||||
class_relationship ri;
|
||||
ri.destination = tinst.base_template_usr;
|
||||
ri.type = relationship_t::kInstantiation;
|
||||
ri.label = "";
|
||||
|
||||
tinst.add_relationship(std::move(ri));
|
||||
|
||||
r.destination = t.referenced().unqualified();
|
||||
|
||||
ctx->d.classes.emplace_back(std::move(tinst));
|
||||
}
|
||||
else
|
||||
r.destination = t.referenced().type_declaration().usr();
|
||||
|
||||
assert(ctx->parent_class != nullptr);
|
||||
|
||||
ctx->parent_class->add_relationship(std::move(r));
|
||||
if ((r.destination != ctx->parent_class->name) &&
|
||||
(r.destination != ctx->parent_class->usr))
|
||||
ctx->parent_class->add_relationship(std::move(r));
|
||||
}
|
||||
|
||||
ret = CXChildVisit_Continue;
|
||||
@@ -500,7 +530,7 @@ bool process_template_specialization_class_field(
|
||||
cx::cursor cursor, cx::type t, class_ *parent, struct tu_context *ctx)
|
||||
{
|
||||
auto tr = t.referenced();
|
||||
if (tr.is_template_instantiation() &&
|
||||
if (tr.spelling().find('<') != std::string::npos &&
|
||||
(tr.type_declaration().kind() != CXCursor_InvalidFile ||
|
||||
tr.type_declaration().specialized_cursor_template().kind() !=
|
||||
CXCursor_InvalidFile)) {
|
||||
@@ -537,7 +567,7 @@ bool process_template_specialization_class_field(
|
||||
|
||||
parent->relationships.emplace_back(std::move(a));
|
||||
|
||||
tinst.relationships.emplace_back(std::move(r));
|
||||
tinst.add_relationship(std::move(r));
|
||||
|
||||
ctx->d.classes.emplace_back(std::move(tinst));
|
||||
return true;
|
||||
@@ -756,4 +786,3 @@ enum CXChildVisitResult translation_unit_visitor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
#include "util.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace clanguml {
|
||||
namespace util {
|
||||
|
||||
@@ -85,5 +87,19 @@ std::string ns_relative(
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string unqualify(const std::string &s)
|
||||
{
|
||||
auto toks = clanguml::util::split(s, " ");
|
||||
const std::vector<std::string> qualifiers = {
|
||||
"static", "const", "volatile", "register", "mutable", "struct", "enum"};
|
||||
|
||||
toks.erase(toks.begin(),
|
||||
std::find_if(toks.begin(), toks.end(), [&qualifiers](const auto &t) {
|
||||
return std::count(qualifiers.begin(), qualifiers.end(), t) == 0;
|
||||
}));
|
||||
|
||||
return fmt::format("{}", fmt::join(toks, " "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,5 +60,14 @@ std::vector<std::string> split(std::string str, std::string delimiter);
|
||||
*/
|
||||
std::string ns_relative(
|
||||
const std::vector<std::string> &namespaces, const std::string &n);
|
||||
|
||||
/**
|
||||
* @brief Remove any qualifiers (e.g. const) from type.
|
||||
*
|
||||
* @param s String spelling of the type.
|
||||
*
|
||||
* @return Unqualified type spelling.
|
||||
*/
|
||||
std::string unqualify(const std::string &s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ TEST_CASE("t00003", "[test-case][class]")
|
||||
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||
REQUIRE_THAT(puml, IsClass(_A("A")));
|
||||
|
||||
REQUIRE_THAT(puml, !IsDependency(_A("A"), _A("A")));
|
||||
|
||||
REQUIRE_THAT(puml, IsMethod(Default(Public("A"))));
|
||||
REQUIRE_THAT(puml, IsMethod(Default(Public("~A"))));
|
||||
|
||||
|
||||
@@ -47,9 +47,12 @@ public:
|
||||
int get_d2(D &&d) { return d.d; }
|
||||
|
||||
template <typename T> T get_e(E<T> &e) { return e.e; }
|
||||
int get_int_e(E<int> &e) { return e.e; }
|
||||
int get_int_e(const E<int> &e) { return e.e; }
|
||||
|
||||
template <typename T> T get_f(const F<T> &f) { return f.f; }
|
||||
|
||||
private:
|
||||
mutable E<std::string> estring;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +46,16 @@ TEST_CASE("t00013", "[test-case][class]")
|
||||
REQUIRE_THAT(puml, IsClass(_A("B")));
|
||||
REQUIRE_THAT(puml, IsClass(_A("C")));
|
||||
REQUIRE_THAT(puml, IsClass(_A("D")));
|
||||
REQUIRE_THAT(puml, !IsDependency(_A("R"), _A("R")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("A")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("B")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("C")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("D")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("E<T>")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("E<int>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("E<T>"), _A("E<int>")));
|
||||
REQUIRE_THAT(puml, IsInstantiation(_A("E<T>"), _A("E<std::string>")));
|
||||
REQUIRE_THAT(puml, IsComposition(_A("R"), _A("E<std::string>"), "estring"));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("R"), _A("ABCD::F<T>")));
|
||||
REQUIRE_THAT(puml, IsDependency(_A("D"), _A("R")));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user