0.6.3
C++ to UML diagram generator based on Clang
Loading...
Searching...
No Matches
Namespaces | Classes | Typedefs | Enumerations | Functions
clanguml::common Namespace Reference

Detailed Description

This namespace provides common interfaces for all kinds of diagrams.

The core diagram functionality is divided into 3 groups: visitor, model and generators.

Namespaces

namespace  generators
 
namespace  jinja
 
namespace  model
 
namespace  visitor
 

Classes

class  compilation_database
 Custom compilation database class. More...
 
class  eid_t
 Universal class for representing all kinds of Id's in the diagram model. More...
 
class  optional_ref
 Simple optional reference type. More...
 
struct  or_regex
 Convenience class for configuration options with regex support. More...
 
struct  path_or_regex
 
struct  regex
 Wrapper around std::regex, which contains original pattern. More...
 

Typedefs

using compilation_database_ptr = std::unique_ptr< compilation_database >
 
template<typename T >
using opt_ref = optional_ref< T >
 
template<typename T >
using reference_vector = std::vector< std::reference_wrapper< T > >
 
template<typename T >
using reference_set = std::unordered_set< std::reference_wrapper< T > >
 
using string_or_regex = or_regex< std::string >
 
using namespace_or_regex = common::or_regex< common::model::namespace_ >
 

Enumerations

enum class  generator_type_t { plantuml , json , mermaid , graphml }
 

Functions

model::access_t access_specifier_to_access_t (clang::AccessSpecifier access_specifier)
 Convert clang::AccessSpecifier to.
 
model::access_t access_specifier_to_access_t (clang::ObjCIvarDecl::AccessControl access_specifier)
 
model::namespace_ get_tag_namespace (const clang::TagDecl &declaration)
 
model::namespace_ get_template_namespace (const clang::TemplateDecl &declaration)
 
std::string get_tag_name (const clang::TagDecl &declaration)
 Generate full qualified name for clang::TagDecl instance.
 
std::string to_string (const clang::ArrayType &array_type, const clang::ASTContext &ctx, bool try_canonical, std::vector< std::string > &dimensions)
 
std::string to_string (const clang::TemplateArgumentLoc &argLoc, const clang::ASTContext &context)
 
std::string to_string (const clang::QualType &type, const clang::ASTContext &ctx, bool try_canonical)
 
std::string to_string (const clang::RecordType &type, const clang::ASTContext &ctx, bool try_canonical)
 
std::string to_string (const clang::TemplateArgument &arg, const clang::ASTContext *ctx)
 
std::string to_string (const clang::TemplateName &templ)
 
std::string to_string (const clang::Expr *expr)
 
std::string to_string (const clang::ValueDecl *val)
 
std::string to_string (const clang::Stmt *stmt)
 
std::string to_string (const clang::FunctionTemplateDecl *decl)
 
std::string to_string (const clang::TypeConstraint *tc)
 
std::string get_source_text_raw (clang::SourceRange range, const clang::SourceManager &sm)
 Get raw text of specific source range.
 
std::string get_source_text (clang::SourceRange range, const clang::SourceManager &sm)
 Get printable range of text of specific source range.
 
std::tuple< unsigned int, unsigned int, std::string > extract_template_parameter_index (const std::string &type_parameter)
 Extract template depth and index.
 
void ensure_lambda_type_is_relative (const config::diagram &config, std::string &parameter_type)
 
bool is_subexpr_of (const clang::Stmt *parent_stmt, const clang::Stmt *sub_stmt)
 Check if an expression is contained in another expression.
 
template<>
eid_t to_id (const std::string &full_name)
 
eid_t to_id (const clang::QualType &type, const clang::ASTContext &ctx)
 
template<>
eid_t to_id (const clang::NamespaceDecl &declaration)
 
template<>
eid_t to_id (const clang::RecordDecl &declaration)
 
template<>
eid_t to_id (const clang::ObjCCategoryDecl &type)
 
template<>
eid_t to_id (const clang::ObjCInterfaceDecl &type)
 
template<>
eid_t to_id (const clang::ObjCProtocolDecl &type)
 
template<>
eid_t to_id (const clang::EnumDecl &declaration)
 
template<>
eid_t to_id (const clang::TagDecl &declaration)
 
template<>
eid_t to_id (const clang::CXXRecordDecl &declaration)
 
template<>
eid_t to_id (const clang::EnumType &t)
 
template<>
eid_t to_id (const std::filesystem::path &file)
 
template<>
eid_t to_id (const clang::TemplateArgument &template_argument)
 
std::pair< common::model::namespace_, std::string > split_ns (const std::string &full_name)
 Split qualified name to namespace and name.
 
std::vector< common::model::template_parameterparse_unexposed_template_params (const std::string &params, const std::function< std::string(const std::string &)> &ns_resolve, int depth=0)
 Parse unexposed (available as string) template params.
 
bool is_type_parameter (const std::string &t)
 
bool is_qualifier (const std::string &q)
 
bool is_bracket (const std::string &b)
 
bool is_identifier_character (char c)
 
bool is_identifier (const std::string &t)
 
bool is_keyword (const std::string &t)
 
bool is_qualified_identifier (const std::string &t)
 
bool is_type_token (const std::string &t)
 
std::string format_condition_text (const std::string &condition_text)
 
std::string get_condition_text (clang::SourceManager &sm, clang::IfStmt *stmt)
 
std::string get_condition_text (clang::SourceManager &sm, clang::WhileStmt *stmt)
 
std::string get_condition_text (clang::SourceManager &sm, clang::CXXForRangeStmt *stmt)
 
std::string get_condition_text (clang::SourceManager &sm, clang::ForStmt *stmt)
 
std::string get_condition_text (clang::SourceManager &sm, clang::DoStmt *stmt)
 
std::string get_condition_text (clang::SourceManager &sm, clang::ConditionalOperator *stmt)
 
clang::QualType dereference (clang::QualType type)
 
std::pair< clang::QualType, std::deque< common::model::context > > consume_type_context (clang::QualType type)
 Extract type context and return raw type.
 
std::vector< std::string > tokenize_unexposed_template_parameter (const std::string &t)
 
bool parse_source_location (const std::string &location_str, std::string &file, unsigned &line, unsigned &column)
 
clang::RawComment * get_expression_raw_comment (const clang::SourceManager &sm, const clang::ASTContext &context, const clang::Stmt *stmt)
 Extract a comment before or next to a statement.
 
clang::RawComment * get_declaration_raw_comment (const clang::SourceManager &sm, const clang::ASTContext &context, const clang::Decl *decl)
 
clang::RawComment * get_raw_comment (const clang::SourceManager &sm, const clang::ASTContext &context, const clang::SourceRange &source_range)
 
bool is_coroutine (const clang::FunctionDecl &decl)
 
bool is_struct (const clang::NamedDecl *decl)
 
bool has_attr (const clang::FunctionDecl *decl, clang::attr::Kind function_attr)
 
std::optional< size_t > get_array_size (const clang::ArrayType &type)
 
void set_source_location (clang::SourceManager &source_manager, const clang::SourceLocation &location, clanguml::common::model::source_location &element, std::filesystem::path tu_path, std::filesystem::path relative_to_path_)
 
const clang::Type * get_unqualified_type (const clang::TypedefDecl *decl)
 
const clang::EnumDecl * get_typedef_enum_decl (const clang::TypedefDecl *decl)
 
const clang::ConceptDecl * get_template_parameter_concept_constraint (const clang::TemplateTypeParmType *type_parameter, const clang::TemplateDecl *template_decl)
 
bool is_lambda_call (const clang::Expr *expr)
 
bool is_lambda_method (const clang::FunctionDecl *decl)
 
template<typename T >
std::string get_qualified_name (const T &declaration)
 Get qualified name of some Clang declaration.
 
template<typename T >
eid_t to_id (const T &declaration)
 
template<>
eid_t to_id (const std::string &full_name)
 
template<>
eid_t to_id (const clang::NamespaceDecl &declaration)
 
template<>
eid_t to_id (const clang::CXXRecordDecl &declaration)
 
template<>
eid_t to_id (const clang::RecordDecl &declaration)
 
template<>
eid_t to_id (const clang::ObjCCategoryDecl &type)
 
template<>
eid_t to_id (const clang::ObjCInterfaceDecl &type)
 
template<>
eid_t to_id (const clang::ObjCProtocolDecl &type)
 
template<>
eid_t to_id (const clang::EnumDecl &declaration)
 
template<>
eid_t to_id (const clang::TagDecl &declaration)
 
template<>
eid_t to_id (const clang::EnumType &type)
 
template<>
eid_t to_id (const clang::TemplateSpecializationType &type)
 
template<>
eid_t to_id (const std::filesystem::path &type)
 
template<typename T , typename P , typename F >
void if_dyn_cast (P pointer, F &&func)
 
bool operator== (const eid_t &lhs, const eid_t &rhs)
 
bool operator== (const eid_t &lhs, const uint64_t &v)
 
bool operator!= (const eid_t &lhs, const uint64_t &v)
 
bool operator!= (const eid_t &lhs, const eid_t &rhs)
 
bool operator< (const eid_t &lhs, const eid_t &rhs)
 
std::string to_string (const bool v)
 
std::string to_string (const std::string &s)
 
std::string to_string (const string_or_regex &sr)
 
std::string to_string (const std::filesystem::path &p)
 
std::string to_string (const generator_type_t type)
 
YAML::Emitter & operator<< (YAML::Emitter &out, const string_or_regex &m)
 

Typedef Documentation

◆ compilation_database_ptr

Definition at line 143 of file compilation_database.h.

◆ namespace_or_regex

Definition at line 347 of file types.h.

◆ opt_ref

template<typename T >
using clanguml::common::opt_ref = typedef optional_ref<T>

Definition at line 229 of file types.h.

◆ reference_set

template<typename T >
using clanguml::common::reference_set = typedef std::unordered_set<std::reference_wrapper<T> >

Definition at line 235 of file types.h.

◆ reference_vector

template<typename T >
using clanguml::common::reference_vector = typedef std::vector<std::reference_wrapper<T> >

Definition at line 232 of file types.h.

◆ string_or_regex

using clanguml::common::string_or_regex = typedef or_regex<std::string>

Definition at line 343 of file types.h.

Enumeration Type Documentation

◆ generator_type_t

Type of output diagram format generator.

Enumerator
plantuml 

Diagrams will be generated in PlantUML format

json 

Diagrams will be generated in JSON format

mermaid 

Diagrams will be generated in MermaidJS format

graphml 

Diagrams will be generated in GraphML format

Definition at line 86 of file types.h.

86 {
87 plantuml, /*!< Diagrams will be generated in PlantUML format */
88 json, /*!< Diagrams will be generated in JSON format */
89 mermaid, /*!< Diagrams will be generated in MermaidJS format */
90 graphml /*!< Diagrams will be generated in GraphML format */
91};

Function Documentation

◆ access_specifier_to_access_t() [1/2]

model::access_t clanguml::common::access_specifier_to_access_t ( clang::AccessSpecifier  access_specifier)

Convert clang::AccessSpecifier to.

See also
clanguml::model::access_t
Parameters
access_specifierClang member access specifier
Returns
Enum value of
See also
clanguml::model::access_t

Definition at line 25 of file clang_utils.cc.

27{
28 auto access = model::access_t::kPublic;
29 switch (access_specifier) {
30 case clang::AccessSpecifier::AS_public:
31 access = model::access_t::kPublic;
32 break;
33 case clang::AccessSpecifier::AS_private:
34 access = model::access_t::kPrivate;
35 break;
36 case clang::AccessSpecifier::AS_protected:
37 access = model::access_t::kProtected;
38 break;
39 default:
40 break;
41 }
42
43 return access;
44}

◆ access_specifier_to_access_t() [2/2]

model::access_t clanguml::common::access_specifier_to_access_t ( clang::ObjCIvarDecl::AccessControl  access_specifier)

Definition at line 46 of file clang_utils.cc.

48{
49 auto access = model::access_t::kPublic;
50 switch (access_specifier) {
51 case clang::ObjCIvarDecl::AccessControl::Public:
52 access = model::access_t::kPublic;
53 break;
54 case clang::ObjCIvarDecl::AccessControl::Private:
55 access = model::access_t::kPrivate;
56 break;
57 case clang::ObjCIvarDecl::AccessControl::Protected:
58 access = model::access_t::kProtected;
59 break;
60 default:
61 break;
62 }
63
64 return access;
65}

◆ consume_type_context()

std::pair< clang::QualType, std::deque< common::model::context > > clanguml::common::consume_type_context ( clang::QualType  type)

Extract type context and return raw type.

This function removes the context for a type, for example for: std::string const& it will return (std::string, [const&])

Parameters
typeType to process
Returns
(type, [qualifiers])

Definition at line 794 of file clang_utils.cc.

795{
796 std::deque<common::model::context> res;
797
798 while (true) {
799 bool try_again{false};
801
802 if (type.isConstQualified()) {
803 ctx.is_const = true;
804 try_again = true;
805 }
806
807 if (type.isVolatileQualified()) {
808 ctx.is_volatile = true;
809 try_again = true;
810 }
811
812 if (type->isPointerType() || type->isReferenceType()) {
813 if (type.isConstQualified() || type.isVolatileQualified()) {
814 ctx.is_ref_const = type.isConstQualified();
815 ctx.is_ref_volatile = type.isVolatileQualified();
816
817 try_again = true;
818 }
819 }
820
821 if (type->isLValueReferenceType()) {
822 ctx.pr = common::model::rpqualifier::kLValueReference;
823 try_again = true;
824 }
825 else if (type->isRValueReferenceType()) {
826 ctx.pr = common::model::rpqualifier::kRValueReference;
827 try_again = true;
828 }
829 else if (type->isMemberFunctionPointerType() &&
830 type->getPointeeType()->getAs<clang::FunctionProtoType>() !=
831 nullptr) {
832 const auto ref_qualifier =
833 type->getPointeeType() // NOLINT
834 ->getAs<clang::FunctionProtoType>() // NOLINT
835 ->getRefQualifier();
836
837 if (ref_qualifier == clang::RefQualifierKind::RQ_RValue) {
838 ctx.pr = common::model::rpqualifier::kRValueReference;
839 try_again = true;
840 }
841 else if (ref_qualifier == clang::RefQualifierKind::RQ_LValue) {
842 ctx.pr = common::model::rpqualifier::kLValueReference;
843 try_again = true;
844 }
845 }
846 else if (type->isPointerType()) {
847 ctx.pr = common::model::rpqualifier::kPointer;
848 try_again = true;
849 }
850
851 if (try_again) {
852 if (type->isPointerType()) {
853 if (type->getPointeeType().isConstQualified())
854 ctx.is_const = true;
855 if (type->getPointeeType().isVolatileQualified())
856 ctx.is_volatile = true;
857
858 type = type->getPointeeType().getUnqualifiedType();
859 }
860 else if (type->isReferenceType()) {
861 if (type.getNonReferenceType().isConstQualified())
862 ctx.is_const = true;
863 if (type.getNonReferenceType().isVolatileQualified())
864 ctx.is_volatile = true;
865
866 type = type.getNonReferenceType().getUnqualifiedType();
867 }
868 else if (type.isConstQualified() || type.isVolatileQualified()) {
869 ctx.is_const = type.isConstQualified();
870 ctx.is_volatile = type.isVolatileQualified();
871 type = type.getUnqualifiedType();
872 }
873
874 res.push_front(ctx);
875
876 if (type->isMemberFunctionPointerType())
877 return std::make_pair(type, res);
878 }
879 else
880 return std::make_pair(type, res);
881 }
882}

◆ dereference()

clang::QualType clanguml::common::dereference ( clang::QualType  type)

Definition at line 777 of file clang_utils.cc.

778{
779 auto res = type;
780
781 while (true) {
782 if (res->isReferenceType())
783 res = res.getNonReferenceType();
784 else if (res->isPointerType())
785 res = res->getPointeeType();
786 else
787 break;
788 }
789
790 return res;
791}

◆ ensure_lambda_type_is_relative()

void clanguml::common::ensure_lambda_type_is_relative ( const config::diagram config,
std::string &  parameter_type 
)

Definition at line 420 of file clang_utils.cc.

422{
423#ifdef _MSC_VER
424 auto root_name =
425 fmt::format("{}", std::filesystem::current_path().root_name().string());
426#else
427 auto root_name = std::string{"/"};
428#endif
429
430 std::string lambda_prefix{fmt::format("(lambda at {}", root_name)};
431
432 while (parameter_type.find(lambda_prefix) != std::string::npos) {
433 auto lambda_begin = parameter_type.find(lambda_prefix);
434 auto lambda_prefix_size = lambda_prefix.size();
435#ifdef _MSC_VER
436 // Skip the `\` or `/` after drive letter and semicolon
437 lambda_prefix_size++;
438#endif
439 auto absolute_lambda_path_end =
440 parameter_type.find(':', lambda_begin + lambda_prefix_size);
441 auto absolute_lambda_path = parameter_type.substr(
442 lambda_begin + lambda_prefix_size - 1,
443 absolute_lambda_path_end - (lambda_begin + lambda_prefix_size - 1));
444
445 auto relative_lambda_path = util::path_to_url(
446 config.make_path_relative(absolute_lambda_path).string());
447
448 parameter_type = fmt::format("{}(lambda at {}{}",
449 parameter_type.substr(0, lambda_begin), relative_lambda_path,
450 parameter_type.substr(absolute_lambda_path_end));
451 }
452}

◆ extract_template_parameter_index()

std::tuple< unsigned int, unsigned int, std::string > clanguml::common::extract_template_parameter_index ( const std::string &  type_parameter)

Extract template depth and index.

This function extracts template depth and index values from Clang's type-parameter- names.

Parameters
type_parameterClang's type parameter string
Returns
(depth, index, qualifier)

Definition at line 401 of file clang_utils.cc.

402{
403 assert(type_parameter.find("type-parameter-") == 0);
404
405 auto type_parameter_and_suffix = util::split(type_parameter, " ");
406
407 auto toks = util::split(
408 type_parameter_and_suffix.front().substr(strlen("type-parameter-")),
409 "-");
410
411 std::string qualifier;
412
413 if (type_parameter_and_suffix.size() > 1) {
414 qualifier = type_parameter_and_suffix.at(1);
415 }
416
417 return {std::stoi(toks.at(0)), std::stoi(toks.at(1)), std::move(qualifier)};
418}

◆ format_condition_text()

std::string clanguml::common::format_condition_text ( const std::string &  condition_text)

Definition at line 708 of file clang_utils.cc.

709{
710 std::string result{condition_text};
711
712 if (result.size() < 2)
713 return {};
714
715 std::vector<std::string> text_lines = util::split(result, "\n", true);
716
717 // Trim each line
718 for (auto &line : text_lines) {
719 line = util::trim(line);
720 }
721
722 result = util::join(" ", text_lines);
723
724 if (result.at(0) == '(' && result.back() == ')')
725 return result.substr(1, result.size() - 2);
726
727 return result;
728}

◆ get_array_size()

std::optional< size_t > clanguml::common::get_array_size ( const clang::ArrayType &  type)

If type is a constant array, return it's number of elements. Otherwise nothing.

Parameters
type
Returns
Number of elements in the array.

Definition at line 1072 of file clang_utils.cc.

1073{
1074 if (const auto *constant_array =
1075 clang::dyn_cast<clang::ConstantArrayType>(&type);
1076 constant_array != nullptr) {
1077 return {constant_array->getSize().getZExtValue()};
1078 }
1079
1080 return {};
1081}

◆ get_condition_text() [1/6]

std::string clanguml::common::get_condition_text ( clang::SourceManager &  sm,
clang::ConditionalOperator *  stmt 
)

Definition at line 769 of file clang_utils.cc.

771{
772 auto condition_range = stmt->getCond()->getSourceRange();
773
774 return format_condition_text(get_source_text(condition_range, sm));
775}

◆ get_condition_text() [2/6]

std::string clanguml::common::get_condition_text ( clang::SourceManager &  sm,
clang::CXXForRangeStmt *  stmt 
)

Definition at line 746 of file clang_utils.cc.

748{
749 auto condition_range = stmt->getRangeStmt()->getSourceRange();
750
751 return format_condition_text(get_source_text(condition_range, sm));
752}

◆ get_condition_text() [3/6]

std::string clanguml::common::get_condition_text ( clang::SourceManager &  sm,
clang::DoStmt *  stmt 
)

Definition at line 762 of file clang_utils.cc.

763{
764 auto condition_range = stmt->getCond()->getSourceRange();
765
766 return format_condition_text(get_source_text(condition_range, sm));
767}

◆ get_condition_text() [4/6]

std::string clanguml::common::get_condition_text ( clang::SourceManager &  sm,
clang::ForStmt *  stmt 
)

Definition at line 754 of file clang_utils.cc.

755{
756 auto condition_range =
757 clang::SourceRange(stmt->getLParenLoc(), stmt->getRParenLoc());
758
759 return format_condition_text(get_source_text(condition_range, sm));
760}

◆ get_condition_text() [5/6]

std::string clanguml::common::get_condition_text ( clang::SourceManager &  sm,
clang::IfStmt *  stmt 
)

Definition at line 730 of file clang_utils.cc.

731{
732 auto condition_range =
733 clang::SourceRange(stmt->getLParenLoc(), stmt->getRParenLoc());
734
735 return format_condition_text(get_source_text(condition_range, sm));
736}

◆ get_condition_text() [6/6]

std::string clanguml::common::get_condition_text ( clang::SourceManager &  sm,
clang::WhileStmt *  stmt 
)

Definition at line 738 of file clang_utils.cc.

739{
740 auto condition_range =
741 clang::SourceRange(stmt->getLParenLoc(), stmt->getRParenLoc());
742
743 return format_condition_text(get_source_text(condition_range, sm));
744}

◆ get_declaration_raw_comment()

clang::RawComment * clanguml::common::get_declaration_raw_comment ( const clang::SourceManager &  sm,
const clang::ASTContext &  context,
const clang::Decl *  decl 
)

Definition at line 1010 of file clang_utils.cc.

1012{
1013 return get_raw_comment(sm, context, decl->getSourceRange());
1014}

◆ get_expression_raw_comment()

clang::RawComment * clanguml::common::get_expression_raw_comment ( const clang::SourceManager &  sm,
const clang::ASTContext &  context,
const clang::Stmt *  stmt 
)

Extract a comment before or next to a statement.

Parameters
smclang::SourceManager reference
contextclang::ASTContext reference
stmtPointer to the current clang::Stmt
Returns
Pointer to a clang::RawComment* or nullptr

Definition at line 1004 of file clang_utils.cc.

1006{
1007 return get_raw_comment(sm, context, stmt->getSourceRange());
1008}

◆ get_qualified_name()

template<typename T >
std::string clanguml::common::get_qualified_name ( const T &  declaration)

Get qualified name of some Clang declaration.

This template is convenient for getting qualified name of various types of clang declarations.

Template Parameters
TType of Clang's declaration, e.g. clang::TagDecl
Parameters
declarationReference to a clang declaration
Returns
Fully qualified name

Definition at line 71 of file clang_utils.h.

72{
73 auto qualified_name = declaration.getQualifiedNameAsString();
74 util::replace_all(qualified_name, "(anonymous namespace)", "");
75 util::replace_all(qualified_name, "::::", "::");
76
77 if constexpr (std::is_base_of_v<clang::TagDecl, T>) {
78 auto base_name = get_tag_name(declaration);
79 model::namespace_ ns{qualified_name};
80 ns.pop_back();
81 ns = ns | base_name;
82
83 return ns.to_string();
84 }
85
86 return qualified_name;
87}

◆ get_raw_comment()

clang::RawComment * clanguml::common::get_raw_comment ( const clang::SourceManager &  sm,
const clang::ASTContext &  context,
const clang::SourceRange &  source_range 
)

Definition at line 1016 of file clang_utils.cc.

1018{
1019 auto expr_begin = sm.getExpansionLoc(source_range.getBegin());
1020 const auto expr_begin_line = sm.getExpansionLineNumber(expr_begin);
1021
1022 auto file_id = sm.getFileID(expr_begin);
1023
1024 const auto has_comments = !context.Comments.empty();
1025 const auto *comments = context.Comments.getCommentsInFile(file_id);
1026
1027 if (has_comments && comments != nullptr) {
1028 for (const auto [offset, raw_comment] :
1029 *context.Comments.getCommentsInFile(sm.getFileID(expr_begin))) {
1030 const auto comment_end_line = sm.getExpansionLineNumber(
1031 raw_comment->getSourceRange().getEnd());
1032
1033 if (expr_begin_line == comment_end_line ||
1034 expr_begin_line == comment_end_line + 1)
1035 return raw_comment;
1036 }
1037 }
1038
1039 return {};
1040}

◆ get_source_text()

std::string clanguml::common::get_source_text ( clang::SourceRange  range,
const clang::SourceManager &  sm 
)

Get printable range of text of specific source range.

Parameters
rangeSource range
smSource manager reference
Returns
Printable source text

Definition at line 388 of file clang_utils.cc.

390{
391 const clang::LangOptions lo;
392
393 auto start_loc = sm.getSpellingLoc(range.getBegin());
394 auto last_token_loc = sm.getSpellingLoc(range.getEnd());
395 auto end_loc = clang::Lexer::getLocForEndOfToken(last_token_loc, 0, sm, lo);
396 auto printable_range = clang::SourceRange{start_loc, end_loc};
397 return get_source_text_raw(printable_range, sm);
398}

◆ get_source_text_raw()

std::string clanguml::common::get_source_text_raw ( clang::SourceRange  range,
const clang::SourceManager &  sm 
)

Get raw text of specific source range.

Parameters
rangeSource range
smSource manager reference
Returns
Raw source text

Definition at line 380 of file clang_utils.cc.

382{
383 return clang::Lexer::getSourceText(
384 clang::CharSourceRange::getCharRange(range), sm, clang::LangOptions())
385 .str();
386}

◆ get_tag_name()

std::string clanguml::common::get_tag_name ( const clang::TagDecl &  declaration)

Generate full qualified name for clang::TagDecl instance.

Parameters
declarationInput declaration
Returns
String representation including any templates, parameters and attribtues

Definition at line 105 of file clang_utils.cc.

106{
107 auto base_name = declaration.getNameAsString();
108
109 if (base_name.empty()) {
110 base_name =
111 fmt::format("(anonymous_{})", std::to_string(declaration.getID()));
112 }
113
114 if ((declaration.getParent() != nullptr) &&
115 declaration.getParent()->isRecord()) {
116 // If the record is nested within another record (e.g. class or struct)
117 // we have to maintain a containment namespace in order to ensure
118 // unique names within the diagram
119 std::deque<std::string> record_parent_names;
120 record_parent_names.push_front(base_name);
121
122 const auto *cls_parent{declaration.getParent()};
123 while (cls_parent->isRecord()) {
124 if (const auto *record_decl =
125 clang::dyn_cast<clang::RecordDecl>(cls_parent);
126 record_decl != nullptr) {
127 record_parent_names.push_front(record_decl->getNameAsString());
128 }
129 cls_parent = cls_parent->getParent();
130 }
131 return fmt::format("{}", fmt::join(record_parent_names, "##"));
132 }
133
134 return base_name;
135}

◆ get_tag_namespace()

model::namespace_ clanguml::common::get_tag_namespace ( const clang::TagDecl &  declaration)

Get namespace of a specific clang::TagDecl

Parameters
declarationReference to clang::TagDecl
Returns
Namespace instance

Definition at line 67 of file clang_utils.cc.

68{
70
71 const auto *parent{declaration.getParent()};
72
73 // First walk up to the nearest namespace, e.g. from nested class or enum
74 while ((parent != nullptr) && !parent->isNamespace()) {
75 parent = parent->getParent();
76 }
77
78 // Now build up the namespace
79 std::deque<std::string> namespace_tokens;
80 while ((parent != nullptr) && parent->isNamespace()) {
81 if (const auto *ns_decl = clang::dyn_cast<clang::NamespaceDecl>(parent);
82 ns_decl != nullptr) {
83 if (!ns_decl->isInline() && !ns_decl->isAnonymousNamespace())
84 namespace_tokens.push_front(ns_decl->getNameAsString());
85 }
86
87 parent = parent->getParent();
88 }
89
90 for (const auto &ns_token : namespace_tokens) {
91 ns |= ns_token;
92 }
93
94 return ns;
95}

◆ get_template_namespace()

model::namespace_ clanguml::common::get_template_namespace ( const clang::TemplateDecl &  declaration)

Get namespace of a specific clang::TemplateDecl

Parameters
declarationReference to clang::TemplateDecl
Returns
Namespace instance

Definition at line 97 of file clang_utils.cc.

98{
99 model::namespace_ ns{declaration.getQualifiedNameAsString()};
100 ns.pop_back();
101
102 return ns;
103}

◆ get_template_parameter_concept_constraint()

const clang::ConceptDecl * clanguml::common::get_template_parameter_concept_constraint ( const clang::TemplateTypeParmType *  type_parameter,
const clang::TemplateDecl *  template_decl 
)

Definition at line 1190 of file clang_utils.cc.

1193{
1194 clang::TemplateTypeParmDecl *template_type_parameter{nullptr};
1195
1196#if LLVM_VERSION_MAJOR >= 22
1197 // In LLVM 22+, getDecl() on a TemplateTypeParmType used in a base class
1198 // may return the outer template's parameter (carrying an inherited concept
1199 // constraint) instead of the base template's own parameter. Prefer the
1200 // template_decl's own parameter at the matching index to avoid spuriously
1201 // inheriting constraints (e.g. HList<T...> becoming HList<IsArithmetic
1202 // T...> when used as base of Arithmetic<IsArithmetic T...>).
1203 if (template_decl->getTemplateParameters()->size() >
1204 type_parameter->getIndex()) {
1205 template_type_parameter = clang::dyn_cast<clang::TemplateTypeParmDecl>(
1206 template_decl->getTemplateParameters()->getParam(
1207 type_parameter->getIndex()));
1208 }
1209 if (template_type_parameter == nullptr &&
1210 type_parameter->getDecl() != nullptr) {
1211 template_type_parameter = type_parameter->getDecl();
1212 }
1213#else
1214 if (type_parameter->getDecl() != nullptr) {
1215 template_type_parameter = type_parameter->getDecl();
1216 }
1217 else if (template_decl->getTemplateParameters()->size() >
1218 type_parameter->getIndex()) {
1219 template_type_parameter = clang::dyn_cast<clang::TemplateTypeParmDecl>(
1220 template_decl->getTemplateParameters()->getParam(
1221 type_parameter->getIndex()));
1222 }
1223#endif
1224
1225 if (template_type_parameter == nullptr ||
1226 template_type_parameter->getTypeConstraint() == nullptr)
1227 return nullptr;
1228
1229#if LLVM_VERSION_MAJOR < 22
1230 return template_type_parameter->getTypeConstraint()->getNamedConcept();
1231#else
1232 return clang::cast<clang::ConceptDecl>(
1233 template_type_parameter->getTypeConstraint()->getNamedConcept());
1234#endif
1235}

◆ get_typedef_enum_decl()

const clang::EnumDecl * clanguml::common::get_typedef_enum_decl ( const clang::TypedefDecl *  decl)

Get pointer to enum decl in typedef decl

Parameters
decltypedef decl
Returns
Pointer to enum decl inside typedef

Definition at line 1153 of file clang_utils.cc.

1154{
1155 if (decl == nullptr)
1156 return nullptr;
1157
1158 const clang::Type *unqualified_type = get_unqualified_type(decl);
1159
1160#if LLVM_VERSION_MAJOR < 22
1161 if (unqualified_type->getTypeClass() == clang::Type::Elaborated) {
1162 const auto *tag_decl =
1163 clang::cast<clang::ElaboratedType>(unqualified_type)
1164 ->getNamedType()
1165 ->getAsTagDecl();
1166
1167 if (tag_decl == nullptr)
1168 return nullptr;
1169
1170 const auto *enum_decl = clang::dyn_cast<clang::EnumDecl>(tag_decl);
1171 if (enum_decl != nullptr && enum_decl->getIdentifier() == nullptr)
1172 return enum_decl;
1173 }
1174#else
1175 {
1176 const auto *tag_decl = unqualified_type->getAsTagDecl();
1177
1178 if (tag_decl == nullptr)
1179 return nullptr;
1180
1181 const auto *enum_decl = clang::dyn_cast<clang::EnumDecl>(tag_decl);
1182 if (enum_decl != nullptr && enum_decl->getIdentifier() == nullptr)
1183 return enum_decl;
1184 }
1185#endif
1186
1187 return nullptr;
1188}

◆ get_unqualified_type()

const clang::Type * clanguml::common::get_unqualified_type ( const clang::TypedefDecl *  decl)

Get the unqualified type of typedef decl

Parameters
decltypedef decl
Returns
Pointer to underlying type or nullptr

Definition at line 1143 of file clang_utils.cc.

1144{
1145 const auto *type_source_info = decl->getTypeSourceInfo();
1146
1147 if (type_source_info == nullptr)
1148 return nullptr;
1149
1150 return type_source_info->getType().split().Ty;
1151}

◆ has_attr()

bool clanguml::common::has_attr ( const clang::FunctionDecl *  decl,
clang::attr::Kind  function_attr 
)

Check if function declaration contains specified attributed

Parameters
declFunction declaration
function_attrClang function attribute
Returns
True, if decl contains specified function attribute

Definition at line 1065 of file clang_utils.cc.

1066{
1067 return std::any_of(decl->attrs().begin(), decl->attrs().end(),
1068 [function_attr](
1069 auto &&attr) { return attr->getKind() == function_attr; });
1070}

◆ if_dyn_cast()

template<typename T , typename P , typename F >
void clanguml::common::if_dyn_cast ( pointer,
F &&  func 
)

Definition at line 241 of file clang_utils.h.

242{
243 if (pointer == nullptr)
244 return;
245
246 if (const auto *dyn_cast_value = clang::dyn_cast<T>(pointer);
247 dyn_cast_value) {
248 std::forward<F>(func)(dyn_cast_value);
249 }
250}

◆ is_bracket()

bool clanguml::common::is_bracket ( const std::string &  b)

Definition at line 659 of file clang_utils.cc.

660{
661 return b == "(" || b == ")" || b == "[" || b == "]";
662}

◆ is_coroutine()

bool clanguml::common::is_coroutine ( const clang::FunctionDecl &  decl)

Check if function or method declaration is a C++20 coroutine.

Parameters
declFunction declaration
Returns
True, if the function is a C++20 coroutine.

Definition at line 1042 of file clang_utils.cc.

1043{
1044 const auto *body = decl.getBody();
1045 return clang::isa_and_nonnull<clang::CoroutineBodyStmt>(body);
1046}

◆ is_identifier()

bool clanguml::common::is_identifier ( const std::string &  t)

Definition at line 669 of file clang_utils.cc.

670{
671 return std::all_of(t.begin(), t.end(),
672 [](const char c) { return is_identifier_character(c); });
673}

◆ is_identifier_character()

bool clanguml::common::is_identifier_character ( char  c)

Definition at line 664 of file clang_utils.cc.

665{
666 return std::isalnum(c) != 0 || c == '_';
667}

◆ is_keyword()

bool clanguml::common::is_keyword ( const std::string &  t)

Definition at line 675 of file clang_utils.cc.

676{
677 static std::vector<std::string> keywords{"alignas", "alignof", "asm",
678 "auto", "bool", "break", "case", "catch", "char", "char16_t",
679 "char32_t", "class", "concept", "const", "constexpr", "const_cast",
680 "continue", "decltype", "default", "delete", "do", "double",
681 "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
682 "float", "for", "friend", "goto", "if", "inline", "int", "long",
683 "mutable", "namespace", "new", "noexcept", "nullptr", "operator",
684 "private", "protected", "public", "register", "reinterpret_cast",
685 "return", "requires", "short", "signed", "sizeof", "static",
686 "static_assert", "static_cast", "struct", "switch", "template", "this",
687 "thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
688 "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
689 "while"};
690
691 return util::contains(keywords, t);
692}

◆ is_lambda_call()

bool clanguml::common::is_lambda_call ( const clang::Expr *  callExpr)

Check if clang::Expr is a call on lambda operator()

Parameters
callExpr
Returns
True, if the expression points to lambda invocation

Definition at line 1237 of file clang_utils.cc.

1238{
1239 const auto *call_expr = clang::dyn_cast<clang::CallExpr>(expr);
1240
1241 if (call_expr == nullptr)
1242 return false;
1243
1244 if (clang::dyn_cast_or_null<clang::LambdaExpr>(call_expr->getCallee()) !=
1245 nullptr) {
1246 return true;
1247 }
1248
1249 const auto *function_callee = call_expr->getDirectCallee();
1250 if (function_callee != nullptr) {
1251
1252 const auto *method_decl =
1253 clang::dyn_cast<clang::CXXMethodDecl>(function_callee);
1254 if (method_decl == nullptr)
1255 return false;
1256
1257 if (method_decl->getParent()->isLambda() &&
1258 method_decl->getOverloadedOperator() == clang::OO_Call) {
1259 return true;
1260 }
1261 }
1262
1263 return false;
1264}

◆ is_lambda_method()

bool clanguml::common::is_lambda_method ( const clang::FunctionDecl *  decl)

Definition at line 1266 of file clang_utils.cc.

1267{
1268 if (decl == nullptr)
1269 return false;
1270
1271 if (const auto *method = clang::dyn_cast<clang::CXXMethodDecl>(decl);
1272 method != nullptr) {
1273 if (method->getParent() != nullptr && method->getParent()->isLambda())
1274 return true;
1275 }
1276
1277 return false;
1278}

◆ is_qualified_identifier()

bool clanguml::common::is_qualified_identifier ( const std::string &  t)

Definition at line 694 of file clang_utils.cc.

695{
696 return std::isalpha(t.at(0)) != 0 &&
697 std::all_of(t.begin(), t.end(), [](const char c) {
698 return is_identifier_character(c) || c == ':';
699 });
700}

◆ is_qualifier()

bool clanguml::common::is_qualifier ( const std::string &  q)

Definition at line 654 of file clang_utils.cc.

655{
656 return q == "&" || q == "&&" || q == "const&";
657}

◆ is_struct()

bool clanguml::common::is_struct ( const clang::NamedDecl *  decl)

Check if named declaration is a C++ struct.

Parameters
declDeclaration to check
Returns
True, if declaration represents a struct.

Definition at line 1048 of file clang_utils.cc.

1049{
1050 if (decl == nullptr)
1051 return false;
1052
1053 if (const auto *record = clang::dyn_cast<clang::CXXRecordDecl>(decl);
1054 record) {
1055 return record->isStruct();
1056 }
1057
1058 if (const auto *tag = clang::dyn_cast<clang::TagDecl>(decl); tag) {
1059 return tag->isStruct();
1060 }
1061
1062 return false;
1063}

◆ is_subexpr_of()

bool clanguml::common::is_subexpr_of ( const clang::Stmt *  parent_stmt,
const clang::Stmt *  sub_stmt 
)

Check if an expression is contained in another expression.

This method returns true if sub_stmt is equal to or is contained in the AST subtree of parent_stmt

Parameters
parent_stmtParent statement
sub_stmtSub statement
Returns

Definition at line 454 of file clang_utils.cc.

455{
456 if (parent_stmt == nullptr || sub_stmt == nullptr)
457 return false;
458
459 if (parent_stmt == sub_stmt)
460 return true;
461
462 return std::any_of(parent_stmt->child_begin(), parent_stmt->child_end(),
463 [sub_stmt](const auto *e) { return is_subexpr_of(e, sub_stmt); });
464}

◆ is_type_parameter()

bool clanguml::common::is_type_parameter ( const std::string &  t)

Definition at line 649 of file clang_utils.cc.

650{
651 return t.find("type-parameter-") == 0;
652}

◆ is_type_token()

bool clanguml::common::is_type_token ( const std::string &  t)

Definition at line 702 of file clang_utils.cc.

703{
704 return is_type_parameter(t) ||
705 (is_identifier(t) && !is_qualifier(t) && !is_bracket(t));
706}

◆ operator!=() [1/2]

bool clanguml::common::operator!= ( const eid_t lhs,
const eid_t rhs 
)

Definition at line 66 of file types.cc.

66{ return !(lhs == rhs); }

◆ operator!=() [2/2]

bool clanguml::common::operator!= ( const eid_t lhs,
const uint64_t &  v 
)

Definition at line 59 of file types.cc.

60{
61 assert(v != 0);
62
63 return lhs.value_ != v;
64}

◆ operator<()

bool clanguml::common::operator< ( const eid_t lhs,
const eid_t rhs 
)

Definition at line 68 of file types.cc.

69{
70 if (lhs.is_global_ != rhs.is_global_) {
71 return lhs.value_ < rhs.value_ + 1;
72 }
73
74 return lhs.value_ < rhs.value_; // Compare values if is_global_ are the same
75}

◆ operator<<()

YAML::Emitter & clanguml::common::operator<< ( YAML::Emitter &  out,
const string_or_regex m 
)

Definition at line 23 of file yaml_emitters.cc.

24{
25 if (std::holds_alternative<std::string>(m.value())) {
26 out << std::get<std::string>(m.value());
27 }
28 else {
29 out << YAML::BeginMap;
30 out << YAML::Key << "r" << YAML::Value
31 << std::get<regex>(m.value()).pattern;
32 out << YAML::EndMap;
33 }
34
35 return out;
36}

◆ operator==() [1/2]

bool clanguml::common::operator== ( const eid_t lhs,
const eid_t rhs 
)

Definition at line 52 of file types.cc.

53{
54 return (lhs.is_global_ == rhs.is_global_) && (lhs.value_ == rhs.value_);
55}

◆ operator==() [2/2]

bool clanguml::common::operator== ( const eid_t lhs,
const uint64_t &  v 
)

Definition at line 57 of file types.cc.

57{ return lhs.value_ == v; }

◆ parse_source_location()

bool clanguml::common::parse_source_location ( const std::string &  location_str,
std::string &  file,
unsigned &  line,
unsigned &  column 
)

Definition at line 967 of file clang_utils.cc.

969{
970 auto tokens = util::split(location_str, ":");
971
972 if (tokens.size() < 3)
973 return false;
974
975 if (tokens.size() == 4) {
976 // Handle Windows paths
977 decltype(tokens) tmp_tokens{};
978 tmp_tokens.emplace_back(
979 fmt::format("{}:{}", tokens.at(0), tokens.at(1)));
980 tmp_tokens.emplace_back(tokens.at(2));
981 tmp_tokens.emplace_back(tokens.at(3));
982
983 tokens = std::move(tmp_tokens);
984 }
985
986 file = tokens.at(0);
987 try {
988 line = std::stoi(tokens.at(1));
989 }
990 catch (std::invalid_argument &e) {
991 return false;
992 }
993
994 try {
995 column = std::stoi(tokens.at(2));
996 }
997 catch (std::invalid_argument &e) {
998 column = 0;
999 }
1000
1001 return true;
1002}

◆ parse_unexposed_template_params()

std::vector< common::model::template_parameter > clanguml::common::parse_unexposed_template_params ( const std::string &  params,
const std::function< std::string(const std::string &)> &  ns_resolve,
int  depth = 0 
)

Parse unexposed (available as string) template params.

Parameters
paramsString parameters as provided by Clang
ns_resolveNamespace resolver function
depthCurrent depth in the template specification
Returns
Parsed template parameter

Definition at line 557 of file clang_utils.cc.

561{
563
564 std::vector<template_parameter> res;
565
566 auto it = params.begin();
567 while (std::isspace(*it) != 0)
568 ++it;
569
570 std::string type{};
571 std::vector<template_parameter> nested_params;
572 bool complete_class_template_argument{false};
573
574 while (it != params.end()) {
575 if (*it == '<') {
576 int nested_level{0};
577 auto bracket_match_begin = it + 1;
578 auto bracket_match_end = bracket_match_begin;
579 while (bracket_match_end != params.end()) {
580 if (*bracket_match_end == '<') {
581 nested_level++;
582 }
583 else if (*bracket_match_end == '>') {
584 if (nested_level > 0)
585 nested_level--;
586 else
587 break;
588 }
589 else {
590 }
591 bracket_match_end++;
592 }
593
594 std::string nested_params_str(
595 bracket_match_begin, bracket_match_end);
596
597 nested_params = parse_unexposed_template_params(
598 nested_params_str, ns_resolve, depth + 1);
599
600 if (nested_params.empty()) {
601 // We couldn't extract any nested template parameters from
602 // `nested_params_str` so just add it as type of template
603 // argument as is
604 nested_params.emplace_back(
605 template_parameter::make_unexposed_argument(
606 nested_params_str));
607 }
608
609 it = bracket_match_end - 1;
610 }
611 else if (*it == '>') {
612 complete_class_template_argument = true;
613 if (depth == 0) {
614 break;
615 }
616 }
617 else if (*it == ',') {
618 complete_class_template_argument = true;
619 }
620 else {
621 type += *it;
622 }
623 if (complete_class_template_argument) {
624 auto t = template_parameter::make_unexposed_argument(
625 ns_resolve(clanguml::util::trim_typename(type)));
626 type = "";
627 for (auto &&param : nested_params)
628 t.add_template_param(std::move(param));
629
630 res.emplace_back(std::move(t));
631 complete_class_template_argument = false;
632 }
633 it++;
634 }
635
636 if (!type.empty()) {
637 auto t = template_parameter::make_unexposed_argument(
638 ns_resolve(clanguml::util::trim_typename(type)));
639 type = "";
640 for (auto &&param : nested_params)
641 t.add_template_param(std::move(param));
642
643 res.emplace_back(std::move(t));
644 }
645
646 return res;
647}

◆ set_source_location()

void clanguml::common::set_source_location ( clang::SourceManager &  source_manager,
const clang::SourceLocation &  location,
clanguml::common::model::source_location element,
std::filesystem::path  tu_path,
std::filesystem::path  relative_to_path_ 
)

Definition at line 1083 of file clang_utils.cc.

1087{
1088 namespace fs = std::filesystem;
1089
1090 std::string file;
1091 unsigned line{};
1092 unsigned column{};
1093
1094 if (location.isValid()) {
1095 file =
1096 source_manager.getFilename(source_manager.getSpellingLoc(location))
1097 .str();
1098 line = source_manager.getSpellingLineNumber(location);
1099 column = source_manager.getSpellingColumnNumber(location);
1100
1101 if (file.empty()) {
1102 // Why do I have to do this?
1103 parse_source_location(
1104 location.printToString(source_manager), file, line, column);
1105 }
1106 }
1107 else {
1108 auto success = parse_source_location(
1109 location.printToString(source_manager), file, line, column);
1110 if (!success) {
1111 LOG_DBG("Failed to extract source location for element from {}",
1112 location.printToString(source_manager));
1113 return;
1114 }
1115 }
1116
1117 // ensure the path is absolute
1118 fs::path file_path{file};
1119 if (!file_path.is_absolute()) {
1120 file_path = fs::absolute(file_path);
1121 }
1122
1123 file_path = weakly_canonical(file_path);
1124
1125 file = file_path.string();
1126
1127 element.set_file(file);
1128
1129 if (util::is_relative_to(file_path, relative_to_path_)) {
1130 element.set_file_relative(util::path_to_url(
1131 fs::path{element.file()}.lexically_relative(relative_to_path_)));
1132 }
1133 else {
1134 element.set_file_relative("");
1135 }
1136
1137 element.set_translation_unit(tu_path.string());
1138 element.set_line(line);
1139 element.set_column(column);
1140 element.set_location_id(location.getHashValue());
1141}

◆ split_ns()

std::pair< common::model::namespace_, std::string > clanguml::common::split_ns ( const std::string &  full_name)

Split qualified name to namespace and name.

Parameters
full_nameFully qualified element name
Returns
(namespace, name)

Definition at line 544 of file clang_utils.cc.

546{
547 assert(!full_name.empty());
548
549 auto name_before_template = ::clanguml::util::split(full_name, "<")[0];
551 ::clanguml::util::split(name_before_template, "::")};
552 auto name = ns.name();
553 ns.pop_back();
554 return {ns, name};
555}

◆ to_id()

template<>
eid_t clanguml::common::to_id ( const clang::TemplateArgument &  template_argument)

Definition at line 527 of file clang_utils.cc.

528{
529 if (template_argument.getKind() == clang::TemplateArgument::Type) {
530 if (const auto *enum_type =
531 template_argument.getAsType()->getAs<clang::EnumType>();
532 enum_type != nullptr)
533 return to_id(*enum_type->getAsTagDecl());
534
535 if (const auto *record_type =
536 template_argument.getAsType()->getAs<clang::RecordType>();
537 record_type != nullptr)
538 return to_id(*record_type->getAsRecordDecl());
539 }
540
541 throw std::runtime_error("Cannot generate id for template argument");
542}

◆ to_string() [1/16]

std::string clanguml::common::to_string ( const bool  v)

Definition at line 86 of file types.cc.

86{ return v ? "true" : "false"; }

◆ to_string() [2/16]

std::string clanguml::common::to_string ( const clang::ArrayType &  array_type,
const clang::ASTContext &  ctx,
bool  try_canonical,
std::vector< std::string > &  dimensions 
)

Definition at line 137 of file clang_utils.cc.

140{
141 auto maybe_size = get_array_size(array_type);
142 std::string array_size =
143 maybe_size.has_value() ? std::to_string(maybe_size.value()) : "";
144 dimensions.emplace_back(std::move(array_size));
145
146 const auto underlying_type = array_type.getElementType();
147
148 if (underlying_type->isArrayType())
149 return to_string(*underlying_type->getAsArrayTypeUnsafe(), ctx,
150 try_canonical, dimensions);
151
152 std::string dimensions_str;
153 for (const auto &d : dimensions) {
154 dimensions_str += fmt::format("[{}]", d);
155 }
156 return fmt::format(
157 "{}{}", to_string(underlying_type, ctx, try_canonical), dimensions_str);
158}

◆ to_string() [3/16]

std::string clanguml::common::to_string ( const clang::Expr *  expr)

Definition at line 314 of file clang_utils.cc.

315{
316 const clang::LangOptions lang_options;
317 std::string result;
318 llvm::raw_string_ostream ostream(result);
319 expr->printPretty(ostream, nullptr, clang::PrintingPolicy(lang_options));
320
321 return result;
322}

◆ to_string() [4/16]

std::string clanguml::common::to_string ( const clang::FunctionTemplateDecl *  decl)

Definition at line 339 of file clang_utils.cc.

340{
341 std::vector<std::string> template_parameters;
342 // Handle template function
343 for (const auto *parameter : *decl->getTemplateParameters()) {
344 if (clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter) !=
345 nullptr) {
346 const auto *template_type_parameter =
347 clang::dyn_cast_or_null<clang::TemplateTypeParmDecl>(parameter);
348
349 std::string template_parameter{
350 template_type_parameter->getNameAsString()};
351
352 if (template_type_parameter->isParameterPack())
353 template_parameter += "...";
354
355 template_parameters.emplace_back(std::move(template_parameter));
356 }
357 else {
358 // TODO
359 }
360 }
361 return fmt::format("{}<{}>({})", decl->getQualifiedNameAsString(),
362 fmt::join(template_parameters, ","), "");
363}

◆ to_string() [5/16]

std::string clanguml::common::to_string ( const clang::QualType &  type,
const clang::ASTContext &  ctx,
bool  try_canonical 
)

Definition at line 181 of file clang_utils.cc.

183{
184 if (type->isArrayType()) {
185 std::vector<std::string> dimensions;
186 return to_string(
187 *type->getAsArrayTypeUnsafe(), ctx, try_canonical, dimensions);
188 }
189
190 clang::PrintingPolicy print_policy(ctx.getLangOpts());
191 print_policy.SuppressScope = 0;
192#if LLVM_VERSION_MAJOR < 21
193 print_policy.PrintCanonicalTypes = 0;
194#else
195 print_policy.PrintAsCanonical = 0;
196#endif
197
198 std::string result;
199
200 result = type.getAsString(print_policy);
201
202 if (try_canonical && result.find('<') != std::string::npos) {
203 auto canonical_type_name =
204 type.getCanonicalType().getAsString(print_policy);
205
206 auto result_qualified_template_name =
207 result.substr(0, result.find('<'));
208 auto result_template_arguments = result.substr(result.find('<'));
209
210 auto canonical_qualified_template_name =
211 canonical_type_name.substr(0, canonical_type_name.find('<'));
212
213 // Choose the longer name (why do I have to do this?)
214 if (result_qualified_template_name.size() <
215 canonical_qualified_template_name.size()) {
216
217 result =
218 canonical_qualified_template_name + result_template_arguments;
219 }
220 }
221
222 // If for any reason clang reports the type as empty string, make sure
223 // it has some default name
224 if (result.empty())
225 result = "(anonymous)";
226 else if (util::contains(result, "unnamed struct") ||
227 util::contains(result, "unnamed union") ||
228 util::contains(result, "struct (unnamed") ||
229 util::contains(result, "union (unnamed")) {
230 const auto *declarationTag = type->getAsTagDecl();
231 if (declarationTag == nullptr) {
232 result = "(unnamed undeclared)";
233 }
234 else {
235 result = common::get_tag_name(*declarationTag);
236 }
237 }
238 else if (util::contains(result, "anonymous struct") ||
239 util::contains(result, "anonymous union")) {
240 result = common::get_tag_name(*type->getAsTagDecl());
241 }
242
243 // Remove trailing spaces after commas in template arguments
244 clanguml::util::replace_all(result, ", ", ",");
245 clanguml::util::replace_all(result, "> >", ">>");
246
247 // Try to get rid of 'type-parameter-X-Y' ugliness
248 if (result.find("type-parameter-") != std::string::npos) {
249 util::if_not_null(
250 common::dereference(type)->getAs<clang::TypedefType>(),
251 [&result, &type](auto *p) {
252 auto [unqualified_type, context] =
253 common::consume_type_context(type);
254 result = p->getDecl()->getNameAsString();
255 if (!context.empty()) {
256 std::vector<std::string> deduced_contexts;
257
258 for (const auto &c : context) {
259 deduced_contexts.push_back(c.to_string());
260 }
261
262 result = fmt::format(
263 "{} {}", result, fmt::join(deduced_contexts, " "));
264 }
265 });
266 }
267
268 return result;
269}

◆ to_string() [6/16]

std::string clanguml::common::to_string ( const clang::RecordType &  type,
const clang::ASTContext &  ctx,
bool  try_canonical 
)

Definition at line 271 of file clang_utils.cc.

273{
274 return to_string(type.desugar(), ctx, try_canonical);
275}

◆ to_string() [7/16]

std::string clanguml::common::to_string ( const clang::Stmt *  stmt)

Definition at line 329 of file clang_utils.cc.

330{
331 const clang::LangOptions lang_options;
332 std::string result;
333 llvm::raw_string_ostream ostream(result);
334 stmt->printPretty(ostream, nullptr, clang::PrintingPolicy(lang_options));
335
336 return result;
337}

◆ to_string() [8/16]

std::string clanguml::common::to_string ( const clang::TemplateArgument &  arg,
const clang::ASTContext *  ctx 
)

Definition at line 277 of file clang_utils.cc.

279{
280 switch (arg.getKind()) {
281 case clang::TemplateArgument::Expression:
282 return to_string(arg.getAsExpr());
283 case clang::TemplateArgument::Type:
284 return to_string(arg.getAsType(), *ctx, false);
285 case clang::TemplateArgument::Null:
286 return "";
287 case clang::TemplateArgument::NullPtr:
288 return "nullptr";
289 case clang::TemplateArgument::Integral:
290 return std::to_string(arg.getAsIntegral().getExtValue());
291 case clang::TemplateArgument::Template:
292 return to_string(arg.getAsTemplate());
293 case clang::TemplateArgument::TemplateExpansion:
294 return to_string(arg.getAsTemplateOrTemplatePattern());
295 default:
296 return "";
297 }
298}

◆ to_string() [9/16]

std::string clanguml::common::to_string ( const clang::TemplateArgumentLoc &  argLoc,
const clang::ASTContext &  context 
)

Definition at line 160 of file clang_utils.cc.

162{
163 std::string result;
164 llvm::raw_string_ostream stream(result);
165
166 clang::PrintingPolicy policy(context.getLangOpts());
167
168 const clang::TemplateArgument &arg = argLoc.getArgument();
169
170#if LLVM_VERSION_MAJOR > 18
171 arg.print(policy, stream, false);
172#else
173 arg.dump(stream);
174#endif
175
176 stream.flush();
177
178 return result;
179}

◆ to_string() [10/16]

std::string clanguml::common::to_string ( const clang::TemplateName &  templ)

Definition at line 300 of file clang_utils.cc.

301{
302 if (templ.getAsTemplateDecl() != nullptr) {
303 return templ.getAsTemplateDecl()->getQualifiedNameAsString();
304 }
305
306 std::string result;
307 const clang::LangOptions lang_options;
308 llvm::raw_string_ostream ostream(result);
309 templ.print(ostream, clang::PrintingPolicy(lang_options));
310
311 return result;
312}

◆ to_string() [11/16]

std::string clanguml::common::to_string ( const clang::TypeConstraint *  tc)

Definition at line 365 of file clang_utils.cc.

366{
367 if (tc == nullptr)
368 return {};
369
370 const clang::PrintingPolicy print_policy(
371 tc->getNamedConcept()->getASTContext().getLangOpts());
372
373 std::string ostream_buf;
374 llvm::raw_string_ostream ostream{ostream_buf};
375 tc->print(ostream, print_policy);
376
377 return ostream.str();
378}

◆ to_string() [12/16]

std::string clanguml::common::to_string ( const clang::ValueDecl *  val)

Definition at line 324 of file clang_utils.cc.

325{
326 return val->getQualifiedNameAsString();
327}

◆ to_string() [13/16]

std::string clanguml::common::to_string ( const generator_type_t  type)

Definition at line 94 of file types.cc.

95{
96 switch (type) {
97 case generator_type_t::plantuml:
98 return "plantuml";
99 case generator_type_t::mermaid:
100 return "mermaid";
101 case generator_type_t::json:
102 return "json";
103 case generator_type_t::graphml:
104 return "graphml";
105 default:
106 return "<unknown>";
107 }
108}

◆ to_string() [14/16]

std::string clanguml::common::to_string ( const std::filesystem::path &  p)

Definition at line 92 of file types.cc.

92{ return p.string(); }

◆ to_string() [15/16]

std::string clanguml::common::to_string ( const std::string &  s)

Definition at line 88 of file types.cc.

88{ return s; }

◆ to_string() [16/16]

std::string clanguml::common::to_string ( const string_or_regex sr)

Definition at line 90 of file types.cc.

90{ return sr.to_string(); }

◆ tokenize_unexposed_template_parameter()

std::vector< std::string > clanguml::common::tokenize_unexposed_template_parameter ( const std::string &  t)

Definition at line 884 of file clang_utils.cc.

886{
887 std::vector<std::string> result;
888
889 auto spaced_out = util::split(t, " ");
890
891 for (const auto &word : spaced_out) {
892 if (is_qualified_identifier(word)) {
893 if (word != "class" && word != "templated" && word != "struct")
894 result.emplace_back(word);
895 continue;
896 }
897
898 std::string tok;
899
900 for (const char c : word) {
901 if (c == '(' || c == ')' || c == '[' || c == ']' || c == '<' ||
902 c == '>') {
903 if (!tok.empty())
904 result.emplace_back(tok);
905 result.emplace_back(std::string{c});
906 tok.clear();
907 }
908 else if (c == ':') {
909 if (!tok.empty() && tok != ":") {
910 result.emplace_back(tok);
911 tok = ":";
912 }
913 else if (tok == ":") {
914 result.emplace_back("::");
915 tok = "";
916 }
917 else {
918 tok += ':';
919 }
920 }
921 else if (c == ',') {
922 if (!tok.empty()) {
923 result.emplace_back(tok);
924 }
925 result.emplace_back(",");
926 tok.clear();
927 }
928 else if (c == '*') {
929 if (!tok.empty()) {
930 result.emplace_back(tok);
931 }
932 result.emplace_back("*");
933 tok.clear();
934 }
935 else if (c == '.') {
936 // This can only be the case if we have a variadic template,
937 // right?
938 if (tok == "..") {
939 result.emplace_back("...");
940 tok.clear();
941 }
942 else if (tok == ".") {
943 tok = "..";
944 }
945 else if (!tok.empty()) {
946 result.emplace_back(tok);
947 tok = ".";
948 }
949 }
950 else {
951 tok += c;
952 }
953 }
954
955 tok = util::trim(tok);
956
957 if (!tok.empty()) {
958 if (tok != "class" && tok != "typename" && word != "struct")
959 result.emplace_back(tok);
960 tok.clear();
961 }
962 }
963
964 return result;
965}