0.6.0
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)
 
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 146 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 788 of file clang_utils.cc.

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

◆ dereference()

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

Definition at line 771 of file clang_utils.cc.

772{
773 auto res = type;
774
775 while (true) {
776 if (res->isReferenceType())
777 res = res.getNonReferenceType();
778 else if (res->isPointerType())
779 res = res->getPointeeType();
780 else
781 break;
782 }
783
784 return res;
785}

◆ ensure_lambda_type_is_relative()

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

Definition at line 414 of file clang_utils.cc.

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

◆ 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 395 of file clang_utils.cc.

396{
397 assert(type_parameter.find("type-parameter-") == 0);
398
399 auto type_parameter_and_suffix = util::split(type_parameter, " ");
400
401 auto toks = util::split(
402 type_parameter_and_suffix.front().substr(strlen("type-parameter-")),
403 "-");
404
405 std::string qualifier;
406
407 if (type_parameter_and_suffix.size() > 1) {
408 qualifier = type_parameter_and_suffix.at(1);
409 }
410
411 return {std::stoi(toks.at(0)), std::stoi(toks.at(1)), std::move(qualifier)};
412}

◆ format_condition_text()

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

Definition at line 702 of file clang_utils.cc.

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

◆ 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 1066 of file clang_utils.cc.

1067{
1068 if (const auto *constant_array =
1069 clang::dyn_cast<clang::ConstantArrayType>(&type);
1070 constant_array != nullptr) {
1071 return {constant_array->getSize().getZExtValue()};
1072 }
1073
1074 return {};
1075}

◆ get_condition_text() [1/6]

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

Definition at line 763 of file clang_utils.cc.

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

◆ get_condition_text() [2/6]

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

Definition at line 740 of file clang_utils.cc.

742{
743 auto condition_range = stmt->getRangeStmt()->getSourceRange();
744
745 return format_condition_text(get_source_text(condition_range, sm));
746}

◆ get_condition_text() [3/6]

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

Definition at line 756 of file clang_utils.cc.

757{
758 auto condition_range = stmt->getCond()->getSourceRange();
759
760 return format_condition_text(get_source_text(condition_range, sm));
761}

◆ get_condition_text() [4/6]

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

Definition at line 748 of file clang_utils.cc.

749{
750 auto condition_range =
751 clang::SourceRange(stmt->getLParenLoc(), stmt->getRParenLoc());
752
753 return format_condition_text(get_source_text(condition_range, sm));
754}

◆ get_condition_text() [5/6]

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

Definition at line 724 of file clang_utils.cc.

725{
726 auto condition_range =
727 clang::SourceRange(stmt->getLParenLoc(), stmt->getRParenLoc());
728
729 return format_condition_text(get_source_text(condition_range, sm));
730}

◆ get_condition_text() [6/6]

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

Definition at line 732 of file clang_utils.cc.

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

◆ 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 1004 of file clang_utils.cc.

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

◆ 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 998 of file clang_utils.cc.

1000{
1001 return get_raw_comment(sm, context, stmt->getSourceRange());
1002}

◆ 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 1010 of file clang_utils.cc.

1012{
1013 auto expr_begin = source_range.getBegin();
1014 const auto expr_begin_line = sm.getSpellingLineNumber(expr_begin);
1015
1016 std::string file_Path = sm.getFilename(expr_begin).str();
1017
1018 auto file_id = sm.getFileID(expr_begin);
1019
1020 if (!context.Comments.empty() &&
1021 context.Comments.getCommentsInFile(file_id) != nullptr) {
1022 for (const auto [offset, raw_comment] :
1023 *context.Comments.getCommentsInFile(sm.getFileID(expr_begin))) {
1024 const auto comment_end_line = sm.getSpellingLineNumber(
1025 raw_comment->getSourceRange().getEnd());
1026
1027 if (expr_begin_line == comment_end_line ||
1028 expr_begin_line == comment_end_line + 1)
1029 return raw_comment;
1030 }
1031 }
1032
1033 return {};
1034}

◆ 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 382 of file clang_utils.cc.

384{
385 const clang::LangOptions lo;
386
387 auto start_loc = sm.getSpellingLoc(range.getBegin());
388 auto last_token_loc = sm.getSpellingLoc(range.getEnd());
389 auto end_loc = clang::Lexer::getLocForEndOfToken(last_token_loc, 0, sm, lo);
390 auto printable_range = clang::SourceRange{start_loc, end_loc};
391 return get_source_text_raw(printable_range, sm);
392}

◆ 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 374 of file clang_utils.cc.

376{
377 return clang::Lexer::getSourceText(
378 clang::CharSourceRange::getCharRange(range), sm, clang::LangOptions())
379 .str();
380}

◆ 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_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 1147 of file clang_utils.cc.

1148{
1149 if (decl == nullptr)
1150 return nullptr;
1151
1152 const clang::Type *unqualified_type = get_unqualified_type(decl);
1153
1154 if (unqualified_type->getTypeClass() == clang::Type::Elaborated) {
1155 const auto *tag_decl =
1156 clang::cast<clang::ElaboratedType>(unqualified_type)
1157 ->getNamedType()
1158 ->getAsTagDecl();
1159
1160 if (tag_decl == nullptr)
1161 return nullptr;
1162
1163 const auto *enum_decl = clang::dyn_cast<clang::EnumDecl>(tag_decl);
1164 if (enum_decl != nullptr && enum_decl->getIdentifier() == nullptr)
1165 return enum_decl;
1166 }
1167
1168 return nullptr;
1169}

◆ 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 1137 of file clang_utils.cc.

1138{
1139 const auto *type_source_info = decl->getTypeSourceInfo();
1140
1141 if (type_source_info == nullptr)
1142 return nullptr;
1143
1144 return type_source_info->getType().split().Ty;
1145}

◆ 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 1059 of file clang_utils.cc.

1060{
1061 return std::any_of(decl->attrs().begin(), decl->attrs().end(),
1062 [function_attr](
1063 auto &&attr) { return attr->getKind() == function_attr; });
1064}

◆ 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 653 of file clang_utils.cc.

654{
655 return b == "(" || b == ")" || b == "[" || b == "]";
656}

◆ 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 1036 of file clang_utils.cc.

1037{
1038 const auto *body = decl.getBody();
1039 return clang::isa_and_nonnull<clang::CoroutineBodyStmt>(body);
1040}

◆ is_identifier()

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

Definition at line 663 of file clang_utils.cc.

664{
665 return std::all_of(t.begin(), t.end(),
666 [](const char c) { return is_identifier_character(c); });
667}

◆ is_identifier_character()

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

Definition at line 658 of file clang_utils.cc.

659{
660 return std::isalnum(c) != 0 || c == '_';
661}

◆ is_keyword()

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

Definition at line 669 of file clang_utils.cc.

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

◆ is_qualified_identifier()

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

Definition at line 688 of file clang_utils.cc.

689{
690 return std::isalpha(t.at(0)) != 0 &&
691 std::all_of(t.begin(), t.end(), [](const char c) {
692 return is_identifier_character(c) || c == ':';
693 });
694}

◆ is_qualifier()

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

Definition at line 648 of file clang_utils.cc.

649{
650 return q == "&" || q == "&&" || q == "const&";
651}

◆ 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 1042 of file clang_utils.cc.

1043{
1044 if (decl == nullptr)
1045 return false;
1046
1047 if (const auto *record = clang::dyn_cast<clang::CXXRecordDecl>(decl);
1048 record) {
1049 return record->isStruct();
1050 }
1051
1052 if (const auto *tag = clang::dyn_cast<clang::TagDecl>(decl); tag) {
1053 return tag->isStruct();
1054 }
1055
1056 return false;
1057}

◆ 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 448 of file clang_utils.cc.

449{
450 if (parent_stmt == nullptr || sub_stmt == nullptr)
451 return false;
452
453 if (parent_stmt == sub_stmt)
454 return true;
455
456 return std::any_of(parent_stmt->child_begin(), parent_stmt->child_end(),
457 [sub_stmt](const auto *e) { return is_subexpr_of(e, sub_stmt); });
458}

◆ is_type_parameter()

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

Definition at line 643 of file clang_utils.cc.

644{
645 return t.find("type-parameter-") == 0;
646}

◆ is_type_token()

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

Definition at line 696 of file clang_utils.cc.

697{
698 return is_type_parameter(t) ||
699 (is_identifier(t) && !is_qualifier(t) && !is_bracket(t));
700}

◆ 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 961 of file clang_utils.cc.

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

◆ 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 551 of file clang_utils.cc.

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

◆ 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 1077 of file clang_utils.cc.

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

◆ 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 538 of file clang_utils.cc.

540{
541 assert(!full_name.empty());
542
543 auto name_before_template = ::clanguml::util::split(full_name, "<")[0];
545 ::clanguml::util::split(name_before_template, "::")};
546 auto name = ns.name();
547 ns.pop_back();
548 return {ns, name};
549}

◆ to_id()

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

Definition at line 521 of file clang_utils.cc.

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

◆ 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 308 of file clang_utils.cc.

309{
310 const clang::LangOptions lang_options;
311 std::string result;
312 llvm::raw_string_ostream ostream(result);
313 expr->printPretty(ostream, nullptr, clang::PrintingPolicy(lang_options));
314
315 return result;
316}

◆ to_string() [4/16]

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

Definition at line 333 of file clang_utils.cc.

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

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

◆ to_string() [6/16]

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

Definition at line 265 of file clang_utils.cc.

267{
268 return to_string(type.desugar(), ctx, try_canonical);
269}

◆ to_string() [7/16]

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

Definition at line 323 of file clang_utils.cc.

324{
325 const clang::LangOptions lang_options;
326 std::string result;
327 llvm::raw_string_ostream ostream(result);
328 stmt->printPretty(ostream, nullptr, clang::PrintingPolicy(lang_options));
329
330 return result;
331}

◆ to_string() [8/16]

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

Definition at line 271 of file clang_utils.cc.

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

◆ 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 294 of file clang_utils.cc.

295{
296 if (templ.getAsTemplateDecl() != nullptr) {
297 return templ.getAsTemplateDecl()->getQualifiedNameAsString();
298 }
299
300 std::string result;
301 const clang::LangOptions lang_options;
302 llvm::raw_string_ostream ostream(result);
303 templ.print(ostream, clang::PrintingPolicy(lang_options));
304
305 return result;
306}

◆ to_string() [11/16]

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

Definition at line 359 of file clang_utils.cc.

360{
361 if (tc == nullptr)
362 return {};
363
364 const clang::PrintingPolicy print_policy(
365 tc->getNamedConcept()->getASTContext().getLangOpts());
366
367 std::string ostream_buf;
368 llvm::raw_string_ostream ostream{ostream_buf};
369 tc->print(ostream, print_policy);
370
371 return ostream.str();
372}

◆ to_string() [12/16]

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

Definition at line 318 of file clang_utils.cc.

319{
320 return val->getQualifiedNameAsString();
321}

◆ 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 878 of file clang_utils.cc.

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