Improved unexposed template parameter tokenization

This commit is contained in:
Bartek Kryza
2023-04-23 19:29:02 +02:00
parent 7f9d698afc
commit 0aa4eb732d
11 changed files with 530 additions and 155 deletions

View File

@@ -459,4 +459,125 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
return res;
}
bool is_type_parameter(const std::string &t)
{
return t.find("type-parameter-") == 0;
}
bool is_qualifier(const std::string &q)
{
return q == "&" || q == "&&" || q == "const&";
}
bool is_bracket(const std::string &b)
{
return b == "(" || b == ")" || b == "[" || b == "]";
}
bool is_identifier_character(char c) { return std::isalnum(c) || c == '_'; }
bool is_identifier(const std::string &t)
{
return std::isalpha(t.at(0)) &&
std::all_of(t.begin(), t.end(),
[](const char c) { return is_identifier_character(c); });
}
bool is_keyword(const std::string &t)
{
static std::vector<std::string> keywords {"alignas", "alignof", "asm",
"auto", "bool", "break", "case", "catch", "char", "char16_t",
"char32_t", "class", "concept", "const", "constexpr", "const_cast",
"continue", "decltype", "default", "delete", "do", "double",
"dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
"float", "for", "friend", "goto", "if", "inline", "int", "long",
"mutable", "namespace", "new", "noexcept", "nullptr", "operator",
"private", "protected", "public", "register", "reinterpret_cast",
"return", "requires", "short", "signed", "sizeof", "static",
"static_assert", "static_cast", "struct", "switch", "template", "this",
"thread_local", "throw", "true", "try", "typedef", "typeid", "typename",
"union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t",
"while"};
return util::contains(keywords, t);
}
bool is_qualified_identifier(const std::string &t)
{
return std::isalpha(t.at(0)) &&
std::all_of(t.begin(), t.end(), [](const char c) {
return is_identifier_character(c) || c == ':';
});
}
bool is_type_token(const std::string &t)
{
return is_type_parameter(t) ||
(is_identifier(t) && !is_qualifier(t) && !is_bracket(t));
}
std::vector<std::string> tokenize_unexposed_template_parameter(
const std::string &t)
{
std::vector<std::string> result;
auto spaced_out = util::split(t, " ");
for (const auto &word : spaced_out) {
if (is_qualified_identifier(word)) {
if (word != "class" && word != "templated" && word != "struct")
result.push_back(word);
continue;
}
std::string tok;
for (const char c : word) {
if (c == '(' || c == ')' || c == '[' || c == ']') {
if (!tok.empty())
result.push_back(tok);
result.push_back(std::string{c});
tok.clear();
}
else if (c == ':') {
if (!tok.empty() && tok != ":") {
result.push_back(tok);
tok = ":";
}
else {
tok += ':';
}
}
else if (c == ',') {
if (!tok.empty()) {
result.push_back(tok);
}
result.push_back(",");
tok.clear();
}
else if (c == '*') {
if (!tok.empty()) {
result.push_back(tok);
}
result.push_back("*");
tok.clear();
}
else {
tok += c;
}
}
tok = util::trim(tok);
if (!tok.empty()) {
if (tok != "class" && tok != "typename" && word != "struct")
result.push_back(tok);
tok.clear();
}
}
return result;
}
} // namespace clanguml::common

View File

@@ -153,6 +153,9 @@ std::vector<common::model::template_parameter> parse_unexposed_template_params(
const std::function<std::string(const std::string &)> &ns_resolve,
int depth = 0);
std::vector<std::string> tokenize_unexposed_template_parameter(
const std::string &t);
template <typename T, typename P, typename F>
void if_dyn_cast(P pointer, F &&func)
{
@@ -164,4 +167,19 @@ void if_dyn_cast(P pointer, F &&func)
std::forward<F>(func)(dyn_cast_value);
}
}
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_qualified_identifier(const std::string &t);
bool is_type_token(const std::string &t);
} // namespace clanguml::common

View File

@@ -113,6 +113,20 @@ int template_parameter::calculate_specialization_match(
{
int res{0};
if (qualifier() != base_template_parameter.qualifier())
return 0;
if (is_template_parameter() &&
base_template_parameter.is_template_parameter() &&
template_params().empty() &&
base_template_parameter.template_params().empty() &&
is_variadic() == is_variadic() &&
is_function_template() ==
base_template_parameter.is_function_template() &&
is_method_template() == base_template_parameter.is_method_template()) {
return 1;
}
auto maybe_base_template_parameter_type = base_template_parameter.type();
auto maybe_template_parameter_type = type();
@@ -132,6 +146,9 @@ int template_parameter::calculate_specialization_match(
!is_function_template())
return 0;
if (base_template_parameter.is_method_template() && !is_method_template())
return 0;
if (!base_template_parameter.template_params().empty() &&
!template_params().empty()) {
auto params_match = calculate_template_params_specialization_match(
@@ -216,10 +233,29 @@ std::string template_parameter::to_string(
}
if (is_method_template()) {
assert(template_params().size() == 2);
assert(template_params().size() > 1);
return fmt::format("{} {}::*{}", template_params().at(0).name().value(),
template_params().at(1).name().value(), method_qualifier());
if (template_params().size() == 2) {
return fmt::format("{} {}::*{}",
template_params().at(0).to_string(using_namespace, relative),
template_params().at(1).to_string(using_namespace, relative),
qualifier());
}
else {
auto it = template_params().begin();
auto return_type = it->to_string(using_namespace, relative);
it++;
auto class_type = it->to_string(using_namespace, relative);
it++;
std::vector<std::string> args;
for (; it != template_params().end(); it++) {
args.push_back(it->to_string(using_namespace, relative));
}
return fmt::format("{} ({}::*)({}){}", return_type, class_type,
fmt::join(args, ","), qualifier());
}
}
std::string res;
@@ -271,6 +307,9 @@ std::string template_parameter::to_string(
res += fmt::format("<{}>", fmt::join(params, ","));
}
if (!qualifier().empty())
res += " " + qualifier();
const auto &maybe_default_value = default_value();
if (maybe_default_value) {
res += "=";
@@ -342,6 +381,12 @@ int calculate_template_params_specialization_match(
{
int res{0};
if (specialization_params.size() != template_params.size() &&
!std::any_of(template_params.begin(), template_params.end(),
[](const auto &t) { return t.is_variadic(); })) {
return 0;
}
if (!specialization_params.empty() && !template_params.empty()) {
auto template_index{0U};
auto arg_index{0U};

View File

@@ -186,9 +186,9 @@ public:
bool is_method_template() const { return is_method_template_; }
void set_method_qualifier(const std::string &q) { method_qualifier_ = q; }
void set_qualifier(const std::string &q) { qualifier_ = q; }
const std::string &method_qualifier() const { return method_qualifier_; }
const std::string &qualifier() const { return qualifier_; }
private:
template_parameter() = default;
@@ -220,7 +220,7 @@ private:
bool is_method_template_{false};
std::string method_qualifier_;
std::string qualifier_;
/// Stores optional fully qualified name of constraint for this template
/// parameter