Refactored comment parsing to clang comments
This commit is contained in:
@@ -66,7 +66,7 @@ access_t access_specifier_to_access_t(clang::AccessSpecifier access_specifier)
|
|||||||
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
||||||
clanguml::class_diagram::model::diagram &diagram,
|
clanguml::class_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::class_diagram &config)
|
const clanguml::config::class_diagram &config)
|
||||||
: source_manager_{sm}
|
: common::visitor::translation_unit_visitor{sm, config}
|
||||||
, diagram_{diagram}
|
, diagram_{diagram}
|
||||||
, config_{config}
|
, config_{config}
|
||||||
{
|
{
|
||||||
@@ -81,7 +81,7 @@ bool translation_unit_visitor::VisitNamespaceDecl(clang::NamespaceDecl *ns)
|
|||||||
|
|
||||||
LOG_DBG("= Visiting namespace declaration {} at {}",
|
LOG_DBG("= Visiting namespace declaration {} at {}",
|
||||||
ns->getQualifiedNameAsString(),
|
ns->getQualifiedNameAsString(),
|
||||||
ns->getLocation().printToString(source_manager_));
|
ns->getLocation().printToString(source_manager()));
|
||||||
|
|
||||||
auto package_path = namespace_{common::get_qualified_name(*ns)};
|
auto package_path = namespace_{common::get_qualified_name(*ns)};
|
||||||
auto package_parent = package_path;
|
auto package_parent = package_path;
|
||||||
@@ -138,7 +138,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
|
|||||||
|
|
||||||
LOG_DBG("= Visiting enum declaration {} at {}",
|
LOG_DBG("= Visiting enum declaration {} at {}",
|
||||||
enm->getQualifiedNameAsString(),
|
enm->getQualifiedNameAsString(),
|
||||||
enm->getLocation().printToString(source_manager_));
|
enm->getLocation().printToString(source_manager()));
|
||||||
|
|
||||||
auto e_ptr = std::make_unique<enum_>(config_.using_namespace());
|
auto e_ptr = std::make_unique<enum_>(config_.using_namespace());
|
||||||
auto &e = *e_ptr;
|
auto &e = *e_ptr;
|
||||||
@@ -217,7 +217,7 @@ bool translation_unit_visitor::VisitEnumDecl(clang::EnumDecl *enm)
|
|||||||
bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
|
bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
|
||||||
clang::ClassTemplateSpecializationDecl *cls)
|
clang::ClassTemplateSpecializationDecl *cls)
|
||||||
{
|
{
|
||||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
||||||
@@ -225,7 +225,7 @@ bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
|
|||||||
|
|
||||||
LOG_DBG("= Visiting template specialization declaration {} at {}",
|
LOG_DBG("= Visiting template specialization declaration {} at {}",
|
||||||
cls->getQualifiedNameAsString(),
|
cls->getQualifiedNameAsString(),
|
||||||
cls->getLocation().printToString(source_manager_));
|
cls->getLocation().printToString(source_manager()));
|
||||||
|
|
||||||
// TODO: Add support for classes defined in function/method bodies
|
// TODO: Add support for classes defined in function/method bodies
|
||||||
if (cls->isLocalClass())
|
if (cls->isLocalClass())
|
||||||
@@ -264,7 +264,7 @@ bool translation_unit_visitor::VisitClassTemplateSpecializationDecl(
|
|||||||
bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
|
bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
|
||||||
clang::TypeAliasTemplateDecl *cls)
|
clang::TypeAliasTemplateDecl *cls)
|
||||||
{
|
{
|
||||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
||||||
@@ -272,7 +272,7 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
|
|||||||
|
|
||||||
LOG_DBG("= Visiting template type alias declaration {} at {}",
|
LOG_DBG("= Visiting template type alias declaration {} at {}",
|
||||||
cls->getQualifiedNameAsString(),
|
cls->getQualifiedNameAsString(),
|
||||||
cls->getLocation().printToString(source_manager_));
|
cls->getLocation().printToString(source_manager()));
|
||||||
|
|
||||||
auto *template_type_specialization_ptr =
|
auto *template_type_specialization_ptr =
|
||||||
cls->getTemplatedDecl()
|
cls->getTemplatedDecl()
|
||||||
@@ -303,7 +303,7 @@ bool translation_unit_visitor::VisitTypeAliasTemplateDecl(
|
|||||||
bool translation_unit_visitor::VisitClassTemplateDecl(
|
bool translation_unit_visitor::VisitClassTemplateDecl(
|
||||||
clang::ClassTemplateDecl *cls)
|
clang::ClassTemplateDecl *cls)
|
||||||
{
|
{
|
||||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
||||||
@@ -311,7 +311,7 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
|
|||||||
|
|
||||||
LOG_DBG("= Visiting class template declaration {} at {}",
|
LOG_DBG("= Visiting class template declaration {} at {}",
|
||||||
cls->getQualifiedNameAsString(),
|
cls->getQualifiedNameAsString(),
|
||||||
cls->getLocation().printToString(source_manager_));
|
cls->getLocation().printToString(source_manager()));
|
||||||
|
|
||||||
auto c_ptr = create_class_declaration(cls->getTemplatedDecl());
|
auto c_ptr = create_class_declaration(cls->getTemplatedDecl());
|
||||||
|
|
||||||
@@ -352,7 +352,7 @@ bool translation_unit_visitor::VisitClassTemplateDecl(
|
|||||||
bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
||||||
{
|
{
|
||||||
// Skip system headers
|
// Skip system headers
|
||||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
if (!diagram().should_include(cls->getQualifiedNameAsString()))
|
||||||
@@ -360,7 +360,7 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
|||||||
|
|
||||||
LOG_DBG("= Visiting class declaration {} at {}",
|
LOG_DBG("= Visiting class declaration {} at {}",
|
||||||
cls->getQualifiedNameAsString(),
|
cls->getQualifiedNameAsString(),
|
||||||
cls->getLocation().printToString(source_manager_));
|
cls->getLocation().printToString(source_manager()));
|
||||||
|
|
||||||
LOG_DBG(
|
LOG_DBG(
|
||||||
"== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
|
"== getQualifiedNameAsString() = {}", cls->getQualifiedNameAsString());
|
||||||
@@ -1004,7 +1004,7 @@ void translation_unit_visitor::process_function_parameter(
|
|||||||
const auto *default_arg = p.getDefaultArg();
|
const auto *default_arg = p.getDefaultArg();
|
||||||
if (default_arg != nullptr) {
|
if (default_arg != nullptr) {
|
||||||
auto default_arg_str = common::get_source_text(
|
auto default_arg_str = common::get_source_text(
|
||||||
default_arg->getSourceRange(), source_manager_);
|
default_arg->getSourceRange(), source_manager());
|
||||||
parameter.set_default_value(default_arg_str);
|
parameter.set_default_value(default_arg_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1241,7 +1241,7 @@ void translation_unit_visitor::process_template_specialization_argument(
|
|||||||
// them from raw source code...
|
// them from raw source code...
|
||||||
if (type_name.find("type-parameter-") == 0) {
|
if (type_name.find("type-parameter-") == 0) {
|
||||||
auto declaration_text = common::get_source_text_raw(
|
auto declaration_text = common::get_source_text_raw(
|
||||||
cls->getSourceRange(), source_manager_);
|
cls->getSourceRange(), source_manager());
|
||||||
|
|
||||||
declaration_text = declaration_text.substr(
|
declaration_text = declaration_text.substr(
|
||||||
declaration_text.find(cls->getNameAsString()) +
|
declaration_text.find(cls->getNameAsString()) +
|
||||||
@@ -1282,7 +1282,7 @@ void translation_unit_visitor::process_template_specialization_argument(
|
|||||||
}
|
}
|
||||||
else if (type_name.find("type-parameter-") == 0) {
|
else if (type_name.find("type-parameter-") == 0) {
|
||||||
auto declaration_text = common::get_source_text_raw(
|
auto declaration_text = common::get_source_text_raw(
|
||||||
cls->getSourceRange(), source_manager_);
|
cls->getSourceRange(), source_manager());
|
||||||
|
|
||||||
declaration_text = declaration_text.substr(
|
declaration_text = declaration_text.substr(
|
||||||
declaration_text.find(cls->getNameAsString()) +
|
declaration_text.find(cls->getNameAsString()) +
|
||||||
@@ -1327,14 +1327,14 @@ void translation_unit_visitor::process_template_specialization_argument(
|
|||||||
template_parameter argument;
|
template_parameter argument;
|
||||||
argument.is_template_parameter(false);
|
argument.is_template_parameter(false);
|
||||||
argument.set_type(common::get_source_text(
|
argument.set_type(common::get_source_text(
|
||||||
arg.getAsExpr()->getSourceRange(), source_manager_));
|
arg.getAsExpr()->getSourceRange(), source_manager()));
|
||||||
template_instantiation.add_template(std::move(argument));
|
template_instantiation.add_template(std::move(argument));
|
||||||
}
|
}
|
||||||
else if (argument_kind == clang::TemplateArgument::TemplateExpansion) {
|
else if (argument_kind == clang::TemplateArgument::TemplateExpansion) {
|
||||||
template_parameter argument;
|
template_parameter argument;
|
||||||
argument.is_template_parameter(true);
|
argument.is_template_parameter(true);
|
||||||
|
|
||||||
cls->getLocation().dump(source_manager_);
|
cls->getLocation().dump(source_manager());
|
||||||
}
|
}
|
||||||
else if (argument_kind == clang::TemplateArgument::Pack) {
|
else if (argument_kind == clang::TemplateArgument::Pack) {
|
||||||
// This will only work for now if pack is at the end
|
// This will only work for now if pack is at the end
|
||||||
@@ -1347,7 +1347,7 @@ void translation_unit_visitor::process_template_specialization_argument(
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG_ERROR("Unsupported template argument kind {} [{}]", arg.getKind(),
|
LOG_ERROR("Unsupported template argument kind {} [{}]", arg.getKind(),
|
||||||
cls->getLocation().printToString(source_manager_));
|
cls->getLocation().printToString(source_manager()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1888,7 +1888,7 @@ void translation_unit_visitor::
|
|||||||
|
|
||||||
argument.is_template_parameter(false);
|
argument.is_template_parameter(false);
|
||||||
argument.set_type(common::get_source_text(
|
argument.set_type(common::get_source_text(
|
||||||
arg.getAsExpr()->getSourceRange(), source_manager_));
|
arg.getAsExpr()->getSourceRange(), source_manager()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::
|
void translation_unit_visitor::
|
||||||
@@ -2128,16 +2128,6 @@ void translation_unit_visitor::process_field(
|
|||||||
c.add_member(std::move(field));
|
c.add_member(std::move(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::set_source_location(
|
|
||||||
const clang::Decl &decl, clanguml::common::model::source_location &element)
|
|
||||||
{
|
|
||||||
if (decl.getLocation().isValid()) {
|
|
||||||
element.set_file(source_manager_.getFilename(decl.getLocation()).str());
|
|
||||||
element.set_line(
|
|
||||||
source_manager_.getSpellingLineNumber(decl.getLocation()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void translation_unit_visitor::add_incomplete_forward_declarations()
|
void translation_unit_visitor::add_incomplete_forward_declarations()
|
||||||
{
|
{
|
||||||
for (auto &[id, c] : forward_declarations_) {
|
for (auto &[id, c] : forward_declarations_) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "class_diagram/model/class.h"
|
#include "class_diagram/model/class.h"
|
||||||
#include "class_diagram/model/diagram.h"
|
#include "class_diagram/model/diagram.h"
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
|
#include "common/visitor/translation_unit_visitor.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
|
|
||||||
#include <clang/AST/RecursiveASTVisitor.h>
|
#include <clang/AST/RecursiveASTVisitor.h>
|
||||||
@@ -38,7 +39,8 @@ using found_relationships_t =
|
|||||||
common::model::relationship_t>>;
|
common::model::relationship_t>>;
|
||||||
|
|
||||||
class translation_unit_visitor
|
class translation_unit_visitor
|
||||||
: public clang::RecursiveASTVisitor<translation_unit_visitor> {
|
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
|
||||||
|
public common::visitor::translation_unit_visitor {
|
||||||
public:
|
public:
|
||||||
explicit translation_unit_visitor(clang::SourceManager &sm,
|
explicit translation_unit_visitor(clang::SourceManager &sm,
|
||||||
clanguml::class_diagram::model::diagram &diagram,
|
clanguml::class_diagram::model::diagram &diagram,
|
||||||
@@ -130,9 +132,6 @@ private:
|
|||||||
const found_relationships_t &relationships,
|
const found_relationships_t &relationships,
|
||||||
bool break_on_first_aggregation = false);
|
bool break_on_first_aggregation = false);
|
||||||
|
|
||||||
void set_source_location(const clang::Decl &decl,
|
|
||||||
clanguml::common::model::source_location &element);
|
|
||||||
|
|
||||||
std::unique_ptr<clanguml::class_diagram::model::class_>
|
std::unique_ptr<clanguml::class_diagram::model::class_>
|
||||||
build_template_instantiation(
|
build_template_instantiation(
|
||||||
const clang::TemplateSpecializationType &template_type,
|
const clang::TemplateSpecializationType &template_type,
|
||||||
@@ -199,20 +198,6 @@ private:
|
|||||||
const clanguml::class_diagram::model::template_parameter &ct,
|
const clanguml::class_diagram::model::template_parameter &ct,
|
||||||
found_relationships_t &relationships);
|
found_relationships_t &relationships);
|
||||||
|
|
||||||
template <typename ClangDecl>
|
|
||||||
void process_comment(
|
|
||||||
const ClangDecl &decl, clanguml::common::model::decorated_element &e)
|
|
||||||
{
|
|
||||||
const auto *comment =
|
|
||||||
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
|
|
||||||
|
|
||||||
if (comment != nullptr) {
|
|
||||||
e.set_comment(comment->getFormattedText(
|
|
||||||
source_manager_, decl.getASTContext().getDiagnostics()));
|
|
||||||
e.add_decorators(decorators::parse(e.comment().value()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_incomplete_forward_declarations();
|
void add_incomplete_forward_declarations();
|
||||||
|
|
||||||
void resolve_local_to_global_ids();
|
void resolve_local_to_global_ids();
|
||||||
@@ -229,8 +214,6 @@ private:
|
|||||||
std::optional<common::model::diagram_element::id_t> get_ast_local_id(
|
std::optional<common::model::diagram_element::id_t> get_ast_local_id(
|
||||||
int64_t local_id) const;
|
int64_t local_id) const;
|
||||||
|
|
||||||
clang::SourceManager &source_manager_;
|
|
||||||
|
|
||||||
// Reference to the output diagram model
|
// Reference to the output diagram model
|
||||||
clanguml::class_diagram::model::diagram &diagram_;
|
clanguml::class_diagram::model::diagram &diagram_;
|
||||||
|
|
||||||
|
|||||||
@@ -133,10 +133,7 @@ inja::json generator<C, D>::element_context(const E &e) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e.comment().has_value()) {
|
if (e.comment().has_value()) {
|
||||||
std::string c = e.comment().value();
|
ctx["element"]["comment"] = e.comment().value();
|
||||||
if (!c.empty()) {
|
|
||||||
ctx["element"]["comment"] = util::trim(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
@@ -186,27 +183,35 @@ void generator<C, D>::generate_plantuml_directives(
|
|||||||
using common::model::namespace_;
|
using common::model::namespace_;
|
||||||
|
|
||||||
for (const auto &d : directives) {
|
for (const auto &d : directives) {
|
||||||
// Render the directive with template engine first
|
try {
|
||||||
std::string directive{env().render(std::string_view{d}, context())};
|
// Render the directive with template engine first
|
||||||
|
std::string directive{env().render(std::string_view{d}, context())};
|
||||||
|
|
||||||
// Now search for alias @A() directives in the text
|
// Now search for alias @A() directives in the text
|
||||||
std::tuple<std::string, size_t, size_t> alias_match;
|
// (this is deprecated)
|
||||||
while (util::find_element_alias(directive, alias_match)) {
|
std::tuple<std::string, size_t, size_t> alias_match;
|
||||||
const auto full_name =
|
while (util::find_element_alias(directive, alias_match)) {
|
||||||
m_config.using_namespace() | std::get<0>(alias_match);
|
const auto full_name =
|
||||||
auto element_opt = m_model.get(full_name.to_string());
|
m_config.using_namespace() | std::get<0>(alias_match);
|
||||||
|
auto element_opt = m_model.get(full_name.to_string());
|
||||||
|
|
||||||
if (element_opt)
|
if (element_opt)
|
||||||
directive.replace(std::get<1>(alias_match),
|
directive.replace(std::get<1>(alias_match),
|
||||||
std::get<2>(alias_match), element_opt.value().alias());
|
std::get<2>(alias_match), element_opt.value().alias());
|
||||||
else {
|
else {
|
||||||
LOG_ERROR("Cannot find clang-uml alias for element {}",
|
LOG_ERROR("Cannot find clang-uml alias for element {}",
|
||||||
full_name.to_string());
|
full_name.to_string());
|
||||||
directive.replace(std::get<1>(alias_match),
|
directive.replace(std::get<1>(alias_match),
|
||||||
std::get<2>(alias_match), "UNKNOWN_ALIAS");
|
std::get<2>(alias_match), "UNKNOWN_ALIAS");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ostr << directive << '\n';
|
||||||
|
}
|
||||||
|
catch (const inja::json::exception &e) {
|
||||||
|
LOG_ERROR("Failed to render PlantUML directive: \n{}\n due to: {}",
|
||||||
|
d, e.what());
|
||||||
}
|
}
|
||||||
ostr << directive << '\n';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,10 +438,14 @@ template <typename C, typename D> void generator<C, D>::init_env()
|
|||||||
// {{ element("clanguml::t00050::A").comment }}
|
// {{ element("clanguml::t00050::A").comment }}
|
||||||
//
|
//
|
||||||
m_env.add_callback("element", 1, [this](inja::Arguments &args) {
|
m_env.add_callback("element", 1, [this](inja::Arguments &args) {
|
||||||
|
inja::json res{};
|
||||||
auto element_opt = m_model.get_with_namespace(
|
auto element_opt = m_model.get_with_namespace(
|
||||||
args[0]->get<std::string>(), m_config.using_namespace());
|
args[0]->get<std::string>(), m_config.using_namespace());
|
||||||
|
|
||||||
return element_opt.value().context();
|
if (element_opt.has_value())
|
||||||
|
res = element_opt.value().context();
|
||||||
|
|
||||||
|
return res;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Convert C++ entity to PlantUML alias, e.g.
|
// Convert C++ entity to PlantUML alias, e.g.
|
||||||
@@ -457,15 +466,17 @@ template <typename C, typename D> void generator<C, D>::init_env()
|
|||||||
// {{ element("A").comment }}
|
// {{ element("A").comment }}
|
||||||
//
|
//
|
||||||
m_env.add_callback("comment", 1, [this](inja::Arguments &args) {
|
m_env.add_callback("comment", 1, [this](inja::Arguments &args) {
|
||||||
std::string res{};
|
inja::json res{};
|
||||||
auto element = m_model.get_with_namespace(
|
auto element = m_model.get_with_namespace(
|
||||||
args[0]->get<std::string>(), m_config.using_namespace());
|
args[0]->get<std::string>(), m_config.using_namespace());
|
||||||
|
|
||||||
if (element.has_value()) {
|
if (element.has_value()) {
|
||||||
auto comment = element.value().comment();
|
auto comment = element.value().comment();
|
||||||
|
|
||||||
if (comment.has_value())
|
if (comment.has_value()) {
|
||||||
|
assert(comment.value().is_object());
|
||||||
res = comment.value();
|
res = comment.value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -88,10 +88,7 @@ void decorated_element::append(const decorated_element &de)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> decorated_element::comment() const
|
std::optional<comment_t> decorated_element::comment() const { return comment_; }
|
||||||
{
|
|
||||||
return comment_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void decorated_element::set_comment(const std::string &c) { comment_ = c; }
|
void decorated_element::set_comment(const comment_t &c) { comment_ = c; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,14 +20,20 @@
|
|||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
|
|
||||||
#include "decorators/decorators.h"
|
#include "decorators/decorators.h"
|
||||||
|
#include "inja/inja.hpp"
|
||||||
|
|
||||||
|
#include <any>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace clanguml::common::model {
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
|
using comment_t = inja::json;
|
||||||
|
|
||||||
class decorated_element {
|
class decorated_element {
|
||||||
public:
|
public:
|
||||||
bool skip() const;
|
bool skip() const;
|
||||||
@@ -46,13 +52,13 @@ public:
|
|||||||
|
|
||||||
void append(const decorated_element &de);
|
void append(const decorated_element &de);
|
||||||
|
|
||||||
std::optional<std::string> comment() const;
|
std::optional<comment_t> comment() const;
|
||||||
|
|
||||||
void set_comment(const std::string &c);
|
void set_comment(const comment_t &c);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<decorators::decorator>> decorators_;
|
std::vector<std::shared_ptr<decorators::decorator>> decorators_;
|
||||||
std::optional<std::string> comment_;
|
std::optional<comment_t> comment_;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "decorated_element.h"
|
#include "decorated_element.h"
|
||||||
#include "relationship.h"
|
#include "relationship.h"
|
||||||
|
#include "source_location.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
||||||
#include <inja/inja.hpp>
|
#include <inja/inja.hpp>
|
||||||
@@ -30,7 +31,7 @@
|
|||||||
|
|
||||||
namespace clanguml::common::model {
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
class diagram_element : public decorated_element {
|
class diagram_element : public decorated_element, public source_location {
|
||||||
public:
|
public:
|
||||||
using id_t = int64_t;
|
using id_t = int64_t;
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,9 @@ inja::json element::context() const
|
|||||||
ctx["alias"] = alias();
|
ctx["alias"] = alias();
|
||||||
ctx["full_name"] = full_name(false);
|
ctx["full_name"] = full_name(false);
|
||||||
ctx["namespace"] = get_namespace().to_string();
|
ctx["namespace"] = get_namespace().to_string();
|
||||||
if (comment().has_value())
|
if (comment().has_value()) {
|
||||||
ctx["comment"] = comment().value();
|
ctx["comment"] = comment().value();
|
||||||
|
}
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
namespace clanguml::common::model {
|
namespace clanguml::common::model {
|
||||||
|
|
||||||
class element : public diagram_element, public source_location {
|
class element : public diagram_element {
|
||||||
public:
|
public:
|
||||||
element(const namespace_ &using_namespace);
|
element(const namespace_ &using_namespace);
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ using filesystem_path = common::model::path<fs_path_sep>;
|
|||||||
class source_file
|
class source_file
|
||||||
: public common::model::diagram_element,
|
: public common::model::diagram_element,
|
||||||
public common::model::stylable_element,
|
public common::model::stylable_element,
|
||||||
public source_location,
|
|
||||||
public common::model::nested_trait<common::model::source_file,
|
public common::model::nested_trait<common::model::source_file,
|
||||||
filesystem_path> {
|
filesystem_path> {
|
||||||
public:
|
public:
|
||||||
|
|||||||
221
src/common/visitor/comment/clang_visitor.cc
Normal file
221
src/common/visitor/comment/clang_visitor.cc
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/comment/clang_visitor.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "clang_visitor.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor::comment {
|
||||||
|
|
||||||
|
clang_visitor::clang_visitor(clang::SourceManager &source_manager)
|
||||||
|
: comment_visitor{source_manager}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void clang_visitor::visit(
|
||||||
|
const clang::NamedDecl &decl, common::model::decorated_element &e)
|
||||||
|
{
|
||||||
|
const auto *comment =
|
||||||
|
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
|
||||||
|
|
||||||
|
if (comment == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto raw_comment = comment->getRawText(source_manager());
|
||||||
|
|
||||||
|
auto formatted_comment = comment->getFormattedText(
|
||||||
|
source_manager(), decl.getASTContext().getDiagnostics());
|
||||||
|
|
||||||
|
common::model::comment_t cmt = inja::json::object();
|
||||||
|
cmt["raw"] = raw_comment;
|
||||||
|
cmt["formatted"] = formatted_comment;
|
||||||
|
|
||||||
|
using clang::comments::BlockCommandComment;
|
||||||
|
using clang::comments::Comment;
|
||||||
|
using clang::comments::FullComment;
|
||||||
|
using clang::comments::ParagraphComment;
|
||||||
|
using clang::comments::ParamCommandComment;
|
||||||
|
using clang::comments::TextComment;
|
||||||
|
using clang::comments::TParamCommandComment;
|
||||||
|
|
||||||
|
FullComment *full_comment =
|
||||||
|
comment->parse(decl.getASTContext(), nullptr, &decl);
|
||||||
|
|
||||||
|
const auto &traits = decl.getASTContext().getCommentCommandTraits();
|
||||||
|
|
||||||
|
for (const auto *block : full_comment->getBlocks()) {
|
||||||
|
const auto block_kind = block->getCommentKind();
|
||||||
|
if (block_kind == Comment::ParagraphCommentKind) {
|
||||||
|
std::string paragraph_text;
|
||||||
|
|
||||||
|
visit_paragraph(clang::dyn_cast<ParagraphComment>(block), traits,
|
||||||
|
paragraph_text);
|
||||||
|
if (!cmt.contains("text"))
|
||||||
|
cmt["text"] = "";
|
||||||
|
|
||||||
|
cmt["text"] =
|
||||||
|
cmt["text"].get<std::string>() + "\n" + paragraph_text;
|
||||||
|
}
|
||||||
|
else if (block_kind == Comment::TextCommentKind) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
else if (block_kind == Comment::ParamCommandCommentKind) {
|
||||||
|
visit_param_command(
|
||||||
|
clang::dyn_cast<ParamCommandComment>(block), traits, cmt);
|
||||||
|
}
|
||||||
|
else if (block_kind == Comment::TParamCommandCommentKind) {
|
||||||
|
visit_tparam_command(
|
||||||
|
clang::dyn_cast<TParamCommandComment>(block), traits, cmt);
|
||||||
|
}
|
||||||
|
else if (block_kind == Comment::BlockCommandCommentKind) {
|
||||||
|
auto *command = clang::dyn_cast<BlockCommandComment>(block);
|
||||||
|
auto command_info = traits.getCommandInfo(command->getCommandID());
|
||||||
|
|
||||||
|
if (command_info->IsBlockCommand && command_info->NumArgs == 0) {
|
||||||
|
// Visit block command with a single text argument, e.g.:
|
||||||
|
// \brief text
|
||||||
|
// \todo text
|
||||||
|
// ...
|
||||||
|
visit_block_command(command, traits, cmt);
|
||||||
|
}
|
||||||
|
else if (command_info->IsParamCommand) {
|
||||||
|
// Visit function param block:
|
||||||
|
// \param arg text
|
||||||
|
visit_param_command(
|
||||||
|
clang::dyn_cast<ParamCommandComment>(command), traits, cmt);
|
||||||
|
}
|
||||||
|
else if (command_info->IsTParamCommand) {
|
||||||
|
// Visit template param block:
|
||||||
|
// \tparam typename text
|
||||||
|
visit_tparam_command(
|
||||||
|
clang::dyn_cast<TParamCommandComment>(command), traits,
|
||||||
|
cmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.set_comment(cmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clang_visitor::visit_block_command(
|
||||||
|
const clang::comments::BlockCommandComment *command,
|
||||||
|
const clang::comments::CommandTraits &traits, common::model::comment_t &cmt)
|
||||||
|
{
|
||||||
|
using clang::comments::Comment;
|
||||||
|
using clang::comments::ParagraphComment;
|
||||||
|
using clang::comments::TextComment;
|
||||||
|
|
||||||
|
std::string command_text;
|
||||||
|
|
||||||
|
for (auto paragraph_it = command->child_begin();
|
||||||
|
paragraph_it != command->child_end(); ++paragraph_it) {
|
||||||
|
|
||||||
|
if ((*paragraph_it)->getCommentKind() ==
|
||||||
|
Comment::ParagraphCommentKind) {
|
||||||
|
visit_paragraph(clang::dyn_cast<ParagraphComment>(*paragraph_it),
|
||||||
|
traits, command_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto command_name = command->getCommandName(traits).str();
|
||||||
|
if (!command_text.empty()) {
|
||||||
|
if (!cmt.contains(command_name))
|
||||||
|
cmt[command_name] = inja::json::array();
|
||||||
|
|
||||||
|
cmt[command_name].push_back(command_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clang_visitor::visit_param_command(
|
||||||
|
const clang::comments::ParamCommandComment *command,
|
||||||
|
const clang::comments::CommandTraits &traits, common::model::comment_t &cmt)
|
||||||
|
{
|
||||||
|
using clang::comments::Comment;
|
||||||
|
using clang::comments::ParagraphComment;
|
||||||
|
using clang::comments::TextComment;
|
||||||
|
|
||||||
|
std::string description;
|
||||||
|
|
||||||
|
const auto name = command->getParamNameAsWritten().str();
|
||||||
|
|
||||||
|
for (auto it = command->child_begin(); it != command->child_end(); ++it) {
|
||||||
|
|
||||||
|
if ((*it)->getCommentKind() == Comment::ParagraphCommentKind) {
|
||||||
|
visit_paragraph(
|
||||||
|
clang::dyn_cast<ParagraphComment>(*it), traits, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name.empty()) {
|
||||||
|
if (!cmt.contains("param"))
|
||||||
|
cmt["param"] = inja::json::array();
|
||||||
|
|
||||||
|
inja::json param = inja::json::object();
|
||||||
|
param["name"] = name;
|
||||||
|
param["description"] = description;
|
||||||
|
cmt["param"].push_back(std::move(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clang_visitor::visit_tparam_command(
|
||||||
|
const clang::comments::TParamCommandComment *command,
|
||||||
|
const clang::comments::CommandTraits &traits, common::model::comment_t &cmt)
|
||||||
|
{
|
||||||
|
using clang::comments::Comment;
|
||||||
|
using clang::comments::ParagraphComment;
|
||||||
|
using clang::comments::TextComment;
|
||||||
|
|
||||||
|
std::string description;
|
||||||
|
|
||||||
|
const auto name = command->getParamNameAsWritten().str();
|
||||||
|
|
||||||
|
for (auto it = command->child_begin(); it != command->child_end(); ++it) {
|
||||||
|
if ((*it)->getCommentKind() == Comment::ParagraphCommentKind) {
|
||||||
|
visit_paragraph(
|
||||||
|
clang::dyn_cast<ParagraphComment>(*it), traits, description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name.empty()) {
|
||||||
|
if (!cmt.contains("tparam"))
|
||||||
|
cmt["tparam"] = inja::json::array();
|
||||||
|
|
||||||
|
inja::json param = inja::json::object();
|
||||||
|
param["name"] = name;
|
||||||
|
param["description"] = description;
|
||||||
|
cmt["tparam"].push_back(std::move(param));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clang_visitor::visit_paragraph(
|
||||||
|
const clang::comments::ParagraphComment *paragraph,
|
||||||
|
const clang::comments::CommandTraits &traits, std::string &text)
|
||||||
|
{
|
||||||
|
using clang::comments::Comment;
|
||||||
|
using clang::comments::TextComment;
|
||||||
|
|
||||||
|
for (auto text_it = paragraph->child_begin();
|
||||||
|
text_it != paragraph->child_end(); ++text_it) {
|
||||||
|
|
||||||
|
if ((*text_it)->getCommentKind() == Comment::TextCommentKind) {
|
||||||
|
// Merge paragraph lines into a single string
|
||||||
|
text += clang::dyn_cast<TextComment>((*text_it))->getText();
|
||||||
|
text += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
54
src/common/visitor/comment/clang_visitor.h
Normal file
54
src/common/visitor/comment/clang_visitor.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/comment/clang_visitor.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <clang/AST/ASTContext.h>
|
||||||
|
#include <clang/AST/Comment.h>
|
||||||
|
#include <clang/Basic/SourceManager.h>
|
||||||
|
|
||||||
|
#include "comment_visitor.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor::comment {
|
||||||
|
|
||||||
|
class clang_visitor : public comment_visitor {
|
||||||
|
public:
|
||||||
|
clang_visitor(clang::SourceManager &source_manager);
|
||||||
|
|
||||||
|
void visit(const clang::NamedDecl &decl,
|
||||||
|
common::model::decorated_element &e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void visit_block_command(
|
||||||
|
const clang::comments::BlockCommandComment *command,
|
||||||
|
const clang::comments::CommandTraits &traits,
|
||||||
|
common::model::comment_t &cmt);
|
||||||
|
|
||||||
|
void visit_param_command(
|
||||||
|
const clang::comments::ParamCommandComment *command,
|
||||||
|
const clang::comments::CommandTraits &traits,
|
||||||
|
common::model::comment_t &cmt);
|
||||||
|
|
||||||
|
void visit_tparam_command(
|
||||||
|
const clang::comments::TParamCommandComment *command,
|
||||||
|
const clang::comments::CommandTraits &traits,
|
||||||
|
common::model::comment_t &cmt);
|
||||||
|
|
||||||
|
void visit_paragraph(const clang::comments::ParagraphComment *paragraph,
|
||||||
|
const clang::comments::CommandTraits &traits, std::string &text);
|
||||||
|
};
|
||||||
|
}
|
||||||
33
src/common/visitor/comment/comment_visitor.cc
Normal file
33
src/common/visitor/comment/comment_visitor.cc
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/comment/comment_visitor.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "comment_visitor.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor::comment {
|
||||||
|
|
||||||
|
comment_visitor::comment_visitor(clang::SourceManager &source_manager)
|
||||||
|
: source_manager_{source_manager}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::SourceManager &comment_visitor::source_manager()
|
||||||
|
{
|
||||||
|
return source_manager_;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/common/visitor/comment/comment_visitor.h
Normal file
41
src/common/visitor/comment/comment_visitor.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/comment/comment_visitor.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <clang/AST/Comment.h>
|
||||||
|
#include <clang/Basic/SourceManager.h>
|
||||||
|
|
||||||
|
#include "common/model/decorated_element.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor::comment {
|
||||||
|
|
||||||
|
class comment_visitor {
|
||||||
|
public:
|
||||||
|
comment_visitor(clang::SourceManager &source_manager);
|
||||||
|
|
||||||
|
virtual ~comment_visitor() = default;
|
||||||
|
|
||||||
|
virtual void visit(
|
||||||
|
const clang::NamedDecl &decl, common::model::decorated_element &e) = 0;
|
||||||
|
|
||||||
|
clang::SourceManager &source_manager();
|
||||||
|
|
||||||
|
private:
|
||||||
|
clang::SourceManager &source_manager_;
|
||||||
|
};
|
||||||
|
}
|
||||||
50
src/common/visitor/comment/plain_visitor.cc
Normal file
50
src/common/visitor/comment/plain_visitor.cc
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/comment/plain_visitor.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "plain_visitor.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor::comment {
|
||||||
|
|
||||||
|
plain_visitor::plain_visitor(clang::SourceManager &source_manager)
|
||||||
|
: comment_visitor{source_manager}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void plain_visitor::visit(
|
||||||
|
const clang::NamedDecl &decl, common::model::decorated_element &e)
|
||||||
|
{
|
||||||
|
const auto *comment =
|
||||||
|
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
|
||||||
|
|
||||||
|
if (comment == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto raw_comment = comment->getRawText(source_manager());
|
||||||
|
|
||||||
|
auto formatted_comment = comment->getFormattedText(
|
||||||
|
source_manager(), decl.getASTContext().getDiagnostics());
|
||||||
|
|
||||||
|
common::model::comment_t cmt = inja::json::object();
|
||||||
|
cmt["raw"] = raw_comment;
|
||||||
|
cmt["formatted"] = formatted_comment;
|
||||||
|
|
||||||
|
e.set_comment(cmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
src/common/visitor/comment/plain_visitor.h
Normal file
35
src/common/visitor/comment/plain_visitor.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/comment/plain_visitor.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <clang/AST/ASTContext.h>
|
||||||
|
#include <clang/AST/Comment.h>
|
||||||
|
#include <clang/Basic/SourceManager.h>
|
||||||
|
|
||||||
|
#include "comment_visitor.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor::comment {
|
||||||
|
|
||||||
|
class plain_visitor : public comment_visitor {
|
||||||
|
public:
|
||||||
|
plain_visitor(clang::SourceManager &source_manager);
|
||||||
|
|
||||||
|
void visit(const clang::NamedDecl &decl,
|
||||||
|
common::model::decorated_element &e) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
76
src/common/visitor/translation_unit_visitor.cc
Normal file
76
src/common/visitor/translation_unit_visitor.cc
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/translation_unit_visitor.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "translation_unit_visitor.h"
|
||||||
|
|
||||||
|
#include "comment/clang_visitor.h"
|
||||||
|
#include "comment/plain_visitor.h"
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor {
|
||||||
|
|
||||||
|
translation_unit_visitor::translation_unit_visitor(
|
||||||
|
clang::SourceManager &sm, const clanguml::config::diagram &config)
|
||||||
|
: source_manager_{sm}
|
||||||
|
, config_{config}
|
||||||
|
{
|
||||||
|
if (config.comment_parser() == config::comment_parser_t::plain) {
|
||||||
|
comment_visitor_ =
|
||||||
|
std::make_unique<comment::plain_visitor>(source_manager_);
|
||||||
|
}
|
||||||
|
else if (config.comment_parser() == config::comment_parser_t::clang) {
|
||||||
|
comment_visitor_ =
|
||||||
|
std::make_unique<comment::clang_visitor>(source_manager_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clang::SourceManager &translation_unit_visitor::source_manager() const
|
||||||
|
{
|
||||||
|
return source_manager_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::process_comment(
|
||||||
|
const clang::NamedDecl &decl, clanguml::common::model::decorated_element &e)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(comment_visitor_.get() != nullptr);
|
||||||
|
|
||||||
|
comment_visitor_->visit(decl, e);
|
||||||
|
|
||||||
|
const auto *comment =
|
||||||
|
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
|
||||||
|
|
||||||
|
if (comment != nullptr) {
|
||||||
|
// Process clang-uml decorators in the comments
|
||||||
|
// TODO: Refactor to use standard block comments processable by clang
|
||||||
|
// comments
|
||||||
|
e.add_decorators(decorators::parse(comment->getFormattedText(
|
||||||
|
source_manager_, decl.getASTContext().getDiagnostics())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void translation_unit_visitor::set_source_location(
|
||||||
|
const clang::Decl &decl, clanguml::common::model::source_location &element)
|
||||||
|
{
|
||||||
|
if (decl.getLocation().isValid()) {
|
||||||
|
element.set_file(source_manager_.getFilename(decl.getLocation()).str());
|
||||||
|
element.set_line(
|
||||||
|
source_manager_.getSpellingLineNumber(decl.getLocation()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
62
src/common/visitor/translation_unit_visitor.h
Normal file
62
src/common/visitor/translation_unit_visitor.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* src/common/visitor/translation_unit_visitor.h
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021-2022 Bartek Kryza <bkryza@gmail.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "comment/comment_visitor.h"
|
||||||
|
#include "config/config.h"
|
||||||
|
|
||||||
|
#include <clang/AST/Comment.h>
|
||||||
|
#include <clang/Basic/SourceManager.h>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace clanguml::common::visitor {
|
||||||
|
|
||||||
|
using found_relationships_t =
|
||||||
|
std::vector<std::pair<clanguml::common::model::diagram_element::id_t,
|
||||||
|
common::model::relationship_t>>;
|
||||||
|
|
||||||
|
class translation_unit_visitor {
|
||||||
|
public:
|
||||||
|
explicit translation_unit_visitor(
|
||||||
|
clang::SourceManager &sm, const clanguml::config::diagram &config);
|
||||||
|
|
||||||
|
clang::SourceManager &source_manager() const;
|
||||||
|
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_source_location(const clang::Decl &decl,
|
||||||
|
clanguml::common::model::source_location &element);
|
||||||
|
|
||||||
|
void process_comment(const clang::NamedDecl &decl,
|
||||||
|
clanguml::common::model::decorated_element &e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
clang::SourceManager &source_manager_;
|
||||||
|
|
||||||
|
// Reference to diagram config
|
||||||
|
const clanguml::config::diagram &config_;
|
||||||
|
|
||||||
|
std::unique_ptr<comment::comment_visitor> comment_visitor_;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -100,6 +100,7 @@ void inheritable_diagram_options::inherit(
|
|||||||
git.override(parent.git);
|
git.override(parent.git);
|
||||||
base_directory.override(parent.base_directory);
|
base_directory.override(parent.base_directory);
|
||||||
relative_to.override(parent.relative_to);
|
relative_to.override(parent.relative_to);
|
||||||
|
comment_parser.override(parent.comment_parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string inheritable_diagram_options::simplify_template_type(
|
std::string inheritable_diagram_options::simplify_template_type(
|
||||||
@@ -284,6 +285,21 @@ void get_option<method_arguments>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void get_option<clanguml::config::comment_parser_t>(const Node &node,
|
||||||
|
clanguml::config::option<clanguml::config::comment_parser_t> &option)
|
||||||
|
{
|
||||||
|
if (node[option.name]) {
|
||||||
|
const auto &val = node[option.name].as<std::string>();
|
||||||
|
if (val == "plain")
|
||||||
|
option.set(clanguml::config::comment_parser_t::plain);
|
||||||
|
else if (val == "clang")
|
||||||
|
option.set(clanguml::config::comment_parser_t::clang);
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid comment_parser value: " + val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<clanguml::config::diagram> parse_diagram_config(const Node &d)
|
std::shared_ptr<clanguml::config::diagram> parse_diagram_config(const Node &d)
|
||||||
{
|
{
|
||||||
const auto diagram_type = d["type"].as<std::string>();
|
const auto diagram_type = d["type"].as<std::string>();
|
||||||
@@ -532,6 +548,8 @@ template <typename T> bool decode_diagram(const Node &node, T &rhs)
|
|||||||
get_option(node, rhs.puml);
|
get_option(node, rhs.puml);
|
||||||
get_option(node, rhs.git);
|
get_option(node, rhs.git);
|
||||||
get_option(node, rhs.generate_links);
|
get_option(node, rhs.generate_links);
|
||||||
|
get_option(node, rhs.type_aliases);
|
||||||
|
get_option(node, rhs.comment_parser);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -552,6 +570,7 @@ template <> struct convert<class_diagram> {
|
|||||||
get_option(node, rhs.generate_packages);
|
get_option(node, rhs.generate_packages);
|
||||||
get_option(node, rhs.relationship_hints);
|
get_option(node, rhs.relationship_hints);
|
||||||
get_option(node, rhs.type_aliases);
|
get_option(node, rhs.type_aliases);
|
||||||
|
// get_option(node, rhs.comment_parser);
|
||||||
|
|
||||||
rhs.initialize_relationship_hints();
|
rhs.initialize_relationship_hints();
|
||||||
rhs.initialize_type_aliases();
|
rhs.initialize_type_aliases();
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ namespace config {
|
|||||||
|
|
||||||
enum class method_arguments { full, abbreviated, none };
|
enum class method_arguments { full, abbreviated, none };
|
||||||
|
|
||||||
|
enum class comment_parser_t { plain, clang };
|
||||||
|
|
||||||
struct plantuml {
|
struct plantuml {
|
||||||
std::vector<std::string> before;
|
std::vector<std::string> before;
|
||||||
std::vector<std::string> after;
|
std::vector<std::string> after;
|
||||||
@@ -138,6 +140,8 @@ struct inheritable_diagram_options {
|
|||||||
option<bool> generate_system_headers{"generate_system_headers", false};
|
option<bool> generate_system_headers{"generate_system_headers", false};
|
||||||
option<relationship_hints_t> relationship_hints{"relationship_hints"};
|
option<relationship_hints_t> relationship_hints{"relationship_hints"};
|
||||||
option<type_aliases_t> type_aliases{"type_aliases"};
|
option<type_aliases_t> type_aliases{"type_aliases"};
|
||||||
|
option<comment_parser_t> comment_parser{
|
||||||
|
"comment_parser", comment_parser_t::plain};
|
||||||
|
|
||||||
void inherit(const inheritable_diagram_options &parent);
|
void inherit(const inheritable_diagram_options &parent);
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ translation_unit_visitor::include_visitor::include_visitor(
|
|||||||
clang::SourceManager &sm,
|
clang::SourceManager &sm,
|
||||||
clanguml::include_diagram::model::diagram &diagram,
|
clanguml::include_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::include_diagram &config)
|
const clanguml::config::include_diagram &config)
|
||||||
: source_manager_{sm}
|
: common::visitor::translation_unit_visitor{sm, config}
|
||||||
, diagram_{diagram}
|
, diagram_{diagram}
|
||||||
, config_{config}
|
, config_{config}
|
||||||
{
|
{
|
||||||
@@ -55,7 +55,7 @@ void translation_unit_visitor::include_visitor::InclusionDirective(
|
|||||||
using common::model::source_file_t;
|
using common::model::source_file_t;
|
||||||
|
|
||||||
auto current_file =
|
auto current_file =
|
||||||
std::filesystem::path{source_manager_.getFilename(hash_loc).str()};
|
std::filesystem::path{source_manager().getFilename(hash_loc).str()};
|
||||||
current_file = std::filesystem::absolute(current_file);
|
current_file = std::filesystem::absolute(current_file);
|
||||||
current_file = current_file.lexically_normal();
|
current_file = current_file.lexically_normal();
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
#include "common/model/package.h"
|
#include "common/model/package.h"
|
||||||
|
#include "common/visitor/translation_unit_visitor.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "include_diagram/model/diagram.h"
|
#include "include_diagram/model/diagram.h"
|
||||||
|
|
||||||
@@ -39,7 +40,8 @@ class translation_unit_visitor
|
|||||||
public:
|
public:
|
||||||
// This is an internal class for convenience to be able to access the
|
// This is an internal class for convenience to be able to access the
|
||||||
// include_visitor type from translation_unit_visitor type
|
// include_visitor type from translation_unit_visitor type
|
||||||
class include_visitor : public clang::PPCallbacks {
|
class include_visitor : public clang::PPCallbacks,
|
||||||
|
public common::visitor::translation_unit_visitor {
|
||||||
public:
|
public:
|
||||||
include_visitor(clang::SourceManager &sm,
|
include_visitor(clang::SourceManager &sm,
|
||||||
clanguml::include_diagram::model::diagram &diagram,
|
clanguml::include_diagram::model::diagram &diagram,
|
||||||
@@ -74,8 +76,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
clang::SourceManager &source_manager_;
|
|
||||||
|
|
||||||
// Reference to the output diagram model
|
// Reference to the output diagram model
|
||||||
clanguml::include_diagram::model::diagram &diagram_;
|
clanguml::include_diagram::model::diagram &diagram_;
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ using clanguml::package_diagram::model::diagram;
|
|||||||
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
translation_unit_visitor::translation_unit_visitor(clang::SourceManager &sm,
|
||||||
clanguml::package_diagram::model::diagram &diagram,
|
clanguml::package_diagram::model::diagram &diagram,
|
||||||
const clanguml::config::package_diagram &config)
|
const clanguml::config::package_diagram &config)
|
||||||
: source_manager_{sm}
|
: common::visitor::translation_unit_visitor{sm, config}
|
||||||
, diagram_{diagram}
|
, diagram_{diagram}
|
||||||
, config_{config}
|
, config_{config}
|
||||||
{
|
{
|
||||||
@@ -107,7 +107,7 @@ bool translation_unit_visitor::VisitFunctionDecl(
|
|||||||
assert(function_declaration != nullptr);
|
assert(function_declaration != nullptr);
|
||||||
|
|
||||||
// Skip system headers
|
// Skip system headers
|
||||||
if (source_manager_.isInSystemHeader(
|
if (source_manager().isInSystemHeader(
|
||||||
function_declaration->getSourceRange().getBegin()))
|
function_declaration->getSourceRange().getBegin()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ bool translation_unit_visitor::VisitCXXRecordDecl(clang::CXXRecordDecl *cls)
|
|||||||
assert(cls != nullptr);
|
assert(cls != nullptr);
|
||||||
|
|
||||||
// Skip system headers
|
// Skip system headers
|
||||||
if (source_manager_.isInSystemHeader(cls->getSourceRange().getBegin()))
|
if (source_manager().isInSystemHeader(cls->getSourceRange().getBegin()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Templated records are handled by VisitClassTemplateDecl()
|
// Templated records are handled by VisitClassTemplateDecl()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/visitor/translation_unit_visitor.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "package_diagram/model/diagram.h"
|
#include "package_diagram/model/diagram.h"
|
||||||
|
|
||||||
@@ -37,7 +38,8 @@ using found_relationships_t =
|
|||||||
common::model::relationship_t>>;
|
common::model::relationship_t>>;
|
||||||
|
|
||||||
class translation_unit_visitor
|
class translation_unit_visitor
|
||||||
: public clang::RecursiveASTVisitor<translation_unit_visitor> {
|
: public clang::RecursiveASTVisitor<translation_unit_visitor>,
|
||||||
|
public common::visitor::translation_unit_visitor {
|
||||||
public:
|
public:
|
||||||
translation_unit_visitor(clang::SourceManager &sm,
|
translation_unit_visitor(clang::SourceManager &sm,
|
||||||
clanguml::package_diagram::model::diagram &diagram,
|
clanguml::package_diagram::model::diagram &diagram,
|
||||||
@@ -88,33 +90,6 @@ private:
|
|||||||
void add_relationships(
|
void add_relationships(
|
||||||
clang::DeclContext *cls, found_relationships_t &relationships);
|
clang::DeclContext *cls, found_relationships_t &relationships);
|
||||||
|
|
||||||
template <typename ClangDecl>
|
|
||||||
void process_comment(
|
|
||||||
const ClangDecl &decl, clanguml::common::model::decorated_element &e)
|
|
||||||
{
|
|
||||||
const auto *comment =
|
|
||||||
decl.getASTContext().getRawCommentForDeclNoCache(&decl);
|
|
||||||
|
|
||||||
if (comment != nullptr) {
|
|
||||||
e.set_comment(comment->getFormattedText(
|
|
||||||
source_manager_, decl.getASTContext().getDiagnostics()));
|
|
||||||
e.add_decorators(decorators::parse(e.comment().value()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_source_location(const clang::Decl &decl,
|
|
||||||
clanguml::common::model::source_location &element)
|
|
||||||
{
|
|
||||||
if (decl.getLocation().isValid()) {
|
|
||||||
element.set_file(
|
|
||||||
source_manager_.getFilename(decl.getLocation()).str());
|
|
||||||
element.set_line(
|
|
||||||
source_manager_.getSpellingLineNumber(decl.getLocation()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clang::SourceManager &source_manager_;
|
|
||||||
|
|
||||||
// Reference to the output diagram model
|
// Reference to the output diagram model
|
||||||
clanguml::package_diagram::model::diagram &diagram_;
|
clanguml::package_diagram::model::diagram &diagram_;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ diagrams:
|
|||||||
type: class
|
type: class
|
||||||
glob:
|
glob:
|
||||||
- ../../tests/t00002/t00002.cc
|
- ../../tests/t00002/t00002.cc
|
||||||
|
comment_parser: clang
|
||||||
using_namespace:
|
using_namespace:
|
||||||
- clanguml::t00002
|
- clanguml::t00002
|
||||||
include:
|
include:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
namespace t00002 {
|
namespace t00002 {
|
||||||
|
|
||||||
/// This is class A
|
/// \brief This is class A
|
||||||
class A {
|
class A {
|
||||||
public:
|
public:
|
||||||
/// Abstract foo_a
|
/// Abstract foo_a
|
||||||
@@ -12,7 +12,7 @@ public:
|
|||||||
virtual void foo_c() = 0;
|
virtual void foo_c() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is class B
|
/// \brief This is class B
|
||||||
class B : public A {
|
class B : public A {
|
||||||
public:
|
public:
|
||||||
virtual void foo_a() override { }
|
virtual void foo_a() override { }
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ diagrams:
|
|||||||
type: class
|
type: class
|
||||||
glob:
|
glob:
|
||||||
- ../../tests/t00050/t00050.cc
|
- ../../tests/t00050/t00050.cc
|
||||||
|
comment_parser: clang
|
||||||
include:
|
include:
|
||||||
namespaces:
|
namespaces:
|
||||||
- clanguml::t00050
|
- clanguml::t00050
|
||||||
@@ -12,32 +13,49 @@ diagrams:
|
|||||||
plantuml:
|
plantuml:
|
||||||
after:
|
after:
|
||||||
- >
|
- >
|
||||||
note left of {{ alias("A") }}
|
note left of {{ alias("A") }}
|
||||||
{{ comment("clanguml::t00050::A") }}
|
{{ comment("clanguml::t00050::A").formatted }}
|
||||||
end note
|
end note
|
||||||
|
|
||||||
- >
|
- >
|
||||||
note right of {{ element("clanguml::t00050::A").alias }}
|
note right of {{ element("clanguml::t00050::A").alias }}
|
||||||
{{ element("A").comment }}
|
{% set e=element("clanguml::t00050::A") %} {{ e.comment.formatted }}
|
||||||
|
end note
|
||||||
|
- >
|
||||||
|
note left of {{ alias("C") }} #AABBCC
|
||||||
|
{{ trim(comment("clanguml::t00050::C").text) }}
|
||||||
end note
|
end note
|
||||||
|
|
||||||
- >
|
- >
|
||||||
{% for element in diagram.elements %}
|
{# Render brief comments and todos, if any were written for an element #}
|
||||||
{% if element.type == "class" and existsIn(element, "comment") %}
|
{% for e in diagram.elements %}
|
||||||
|
{% if existsIn(e, "comment") and existsIn(e.comment, "brief") %}
|
||||||
note top of {{ element.alias }}
|
|
||||||
{{ element.comment }}
|
note top of {{ e.alias }} {% if e.type == "class" %} #22AA22 {% else %} #2222AA {% endif %}
|
||||||
|
{% set c=e.comment %} {{ c.brief.0 }}
|
||||||
end note
|
end note
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% if existsIn(e, "comment") and existsIn(e.comment, "todo") %}
|
||||||
|
{% set c=e.comment %}
|
||||||
|
{% for t in c.todo %}
|
||||||
|
note top of {{ e.alias }} #882222
|
||||||
|
**TODO**
|
||||||
|
{{ t }}
|
||||||
|
end note
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{# Render template paramete if any #}
|
||||||
|
{% if existsIn(e, "comment") and existsIn(e.comment, "tparam") %}
|
||||||
|
{% set c=e.comment %}
|
||||||
|
|
||||||
|
note top of {{ e.alias }} #AAAAFF
|
||||||
|
**Template parameters**
|
||||||
|
{% for tp in c.tparam %}
|
||||||
|
//{{ tp.name }}// {{ trim(tp.description) }}
|
||||||
|
{% endfor %}
|
||||||
|
end note
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
- >
|
|
||||||
{% for element in diagram.elements %}
|
|
||||||
{% if element.type == "enum" and existsIn(element, "comment") %}
|
|
||||||
|
|
||||||
note bottom of {{ element.alias }}
|
|
||||||
{{ element.comment }}
|
|
||||||
end note
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
@@ -11,15 +11,23 @@ class A {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* \brief Lorem ipsum
|
||||||
|
*
|
||||||
* Lorem ipsum dolor sit amet consectetur adipiscing elit, urna consequat felis
|
* Lorem ipsum dolor sit amet consectetur adipiscing elit, urna consequat felis
|
||||||
* vehicula class ultricies mollis dictumst, aenean non a in donec nulla.
|
* vehicula class ultricies mollis dictumst, aenean non a in donec nulla.
|
||||||
* Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam,
|
* Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam,
|
||||||
* integer placerat et turpis mi eros nec lobortis taciti, vehicula nisl litora
|
* integer placerat et turpis mi eros nec lobortis taciti, vehicula nisl litora
|
||||||
* tellus ligula porttitor metus.
|
* tellus ligula porttitor metus.
|
||||||
|
*
|
||||||
|
* \todo 1. Write meaningful comment
|
||||||
|
* \todo 2. Write tests
|
||||||
|
* \todo 3. Implement
|
||||||
*/
|
*/
|
||||||
class B {
|
class B {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Long comment example
|
||||||
|
///
|
||||||
/// Lorem ipsum dolor sit amet consectetur adipiscing elit, urna consequat felis
|
/// Lorem ipsum dolor sit amet consectetur adipiscing elit, urna consequat felis
|
||||||
/// vehicula class ultricies mollis dictumst, aenean non a in donec nulla.
|
/// vehicula class ultricies mollis dictumst, aenean non a in donec nulla.
|
||||||
/// Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam,
|
/// Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam,
|
||||||
@@ -56,6 +64,8 @@ namespace utils {
|
|||||||
/// Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam,
|
/// Phasellus ante pellentesque erat cum risus consequat imperdiet aliquam,
|
||||||
/// integer placerat et turpis mi eros nec lobortis taciti, vehicula nisl litora
|
/// integer placerat et turpis mi eros nec lobortis taciti, vehicula nisl litora
|
||||||
/// tellus ligula porttitor metus.
|
/// tellus ligula porttitor metus.
|
||||||
|
///
|
||||||
|
/// \todo Implement...
|
||||||
class D {
|
class D {
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,6 +74,20 @@ class D {
|
|||||||
/// Mollis pretium lorem primis
|
/// Mollis pretium lorem primis
|
||||||
enum class E { E1, E2, E3 };
|
enum class E { E1, E2, E3 };
|
||||||
|
|
||||||
|
/// \brief Simple array wrapper.
|
||||||
|
///
|
||||||
|
/// This class is just for testing tparam parsing, it serves no other
|
||||||
|
/// purpose.
|
||||||
|
///
|
||||||
|
/// \tparam T Type of array elements.
|
||||||
|
/// \tparam V Type of regular element.
|
||||||
|
/// \tparam N Size of T array.
|
||||||
|
///
|
||||||
|
template <typename T, typename V, int N> class F {
|
||||||
|
T t[N];
|
||||||
|
V v;
|
||||||
|
};
|
||||||
|
|
||||||
class NoComment {
|
class NoComment {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ TEST_CASE("t00050", "[test-case][class]")
|
|||||||
REQUIRE_THAT(puml, IsEnum(_A("E")));
|
REQUIRE_THAT(puml, IsEnum(_A("E")));
|
||||||
|
|
||||||
REQUIRE_THAT(puml, HasNote(_A("A"), "left"));
|
REQUIRE_THAT(puml, HasNote(_A("A"), "left"));
|
||||||
REQUIRE_THAT(puml, HasNote(_A("A"), "top"));
|
|
||||||
REQUIRE_THAT(puml, HasNote(_A("A"), "right"));
|
REQUIRE_THAT(puml, HasNote(_A("A"), "right"));
|
||||||
REQUIRE_THAT(puml, HasNote(_A("B"), "top"));
|
REQUIRE_THAT(puml, HasNote(_A("B"), "top"));
|
||||||
REQUIRE_THAT(puml, HasNote(_A("C"), "top"));
|
REQUIRE_THAT(puml, HasNote(_A("C"), "top"));
|
||||||
REQUIRE_THAT(puml, HasNote(_A("utils::D"), "top"));
|
REQUIRE_THAT(puml, HasNote(_A("utils::D"), "top"));
|
||||||
REQUIRE_THAT(puml, HasNote(_A("E"), "bottom"));
|
REQUIRE_THAT(puml, !HasNote(_A("E"), "bottom"));
|
||||||
REQUIRE_THAT(puml, !HasNote(_A("NoComment"), "top"));
|
REQUIRE_THAT(puml, !HasNote(_A("NoComment"), "top"));
|
||||||
|
REQUIRE_THAT(puml, HasNote(_A("F<T,V,int N>"), "top"));
|
||||||
|
|
||||||
save_puml(
|
save_puml(
|
||||||
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
"./" + config.output_directory() + "/" + diagram->name + ".puml", puml);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ void inject_diagram_options(std::shared_ptr<clanguml::config::diagram> diagram)
|
|||||||
// Inject links config to all test cases
|
// Inject links config to all test cases
|
||||||
clanguml::config::generate_links_config links_config{
|
clanguml::config::generate_links_config links_config{
|
||||||
R"(https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }})",
|
R"(https://github.com/bkryza/clang-uml/blob/{{ git.commit }}/{{ element.source.path }}#L{{ element.source.line }})",
|
||||||
R"({% if "comment" in element %}{{ abbrv(trim(replace(element.comment, "\n+", " ")), 256) }}{% else %}{{ element.name }}{% endif %})"};
|
R"({% if existsIn(element, "comment") and existsIn(element.comment, "brief") %}{{ abbrv(trim(replace(element.comment.brief.0, "\n+", " ")), 256) }}{% else %}{{ element.name }}{% endif %})"};
|
||||||
|
|
||||||
diagram->generate_links.set(links_config);
|
diagram->generate_links.set(links_config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ TEST_CASE("Test config simple", "[unit-test]")
|
|||||||
"element.source.file }}#L{{ element.source.line }}");
|
"element.source.file }}#L{{ element.source.line }}");
|
||||||
CHECK(diagram.generate_links().tooltip == "{{ element.comment }}");
|
CHECK(diagram.generate_links().tooltip == "{{ element.comment }}");
|
||||||
|
|
||||||
|
CHECK(
|
||||||
|
diagram.comment_parser() == clanguml::config::comment_parser_t::clang);
|
||||||
|
|
||||||
CHECK(contains(diagram.include().access, access_t::kPublic));
|
CHECK(contains(diagram.include().access, access_t::kPublic));
|
||||||
CHECK(contains(diagram.include().access, access_t::kProtected));
|
CHECK(contains(diagram.include().access, access_t::kProtected));
|
||||||
CHECK(contains(diagram.include().access, access_t::kPrivate));
|
CHECK(contains(diagram.include().access, access_t::kPrivate));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ diagrams:
|
|||||||
glob:
|
glob:
|
||||||
- src/**/*.cc
|
- src/**/*.cc
|
||||||
- src/**/*.h
|
- src/**/*.h
|
||||||
|
comment_parser: clang
|
||||||
using_namespace: clanguml
|
using_namespace: clanguml
|
||||||
generate_method_arguments: full
|
generate_method_arguments: full
|
||||||
generate_packages: true
|
generate_packages: true
|
||||||
|
|||||||
Reference in New Issue
Block a user