Fix type parser for types with keyword prefix

E.g. a type `constant` would become `const ant`.
This commit is contained in:
Jonathan Müller 2017-10-09 09:20:35 +02:00
commit 8e6c5ccf71
2 changed files with 54 additions and 21 deletions

View file

@ -33,10 +33,23 @@ namespace
str.erase(0, 1); str.erase(0, 1);
} }
bool remove_suffix(std::string& str, const char* suffix) bool can_extend_suffix(const std::string& str, std::size_t suffix_length)
{
if (str.length() <= suffix_length + 1u)
{
auto c = str[str.length() - suffix_length - 1u];
return std::isalnum(c) || c == '_';
}
else
return false;
}
// if identifier only removes maximal suffix according to tokenization
bool remove_suffix(std::string& str, const char* suffix, bool is_identifier)
{ {
auto length = std::strlen(suffix); auto length = std::strlen(suffix);
if (str.length() >= length && str.compare(str.length() - length, length, suffix) == 0) if (str.length() >= length && str.compare(str.length() - length, length, suffix) == 0
&& (!is_identifier || !can_extend_suffix(str, length)))
{ {
str.erase(str.length() - length); str.erase(str.length() - length);
remove_trailing_ws(str); remove_trailing_ws(str);
@ -46,10 +59,23 @@ namespace
return false; return false;
} }
bool remove_prefix(std::string& str, const char* prefix) bool can_extend_prefix(const std::string& str, std::size_t prefix_length)
{
if (prefix_length < str.size())
{
auto c = str[prefix_length];
return std::isalnum(c) || c == '_';
}
else
return false;
}
// if identifier only removes maximal suffix according to tokenization
bool remove_prefix(std::string& str, const char* prefix, bool is_identifier)
{ {
auto length = std::strlen(prefix); auto length = std::strlen(prefix);
if (str.length() >= length && str.compare(0u, length, prefix) == 0) if (str.length() >= length && str.compare(0u, length, prefix) == 0
&& (!is_identifier || !can_extend_prefix(str, length)))
{ {
str.erase(0u, length); str.erase(0u, length);
remove_leading_ws(str); remove_leading_ws(str);
@ -69,16 +95,16 @@ namespace
cpp_cv suffix_cv(std::string& spelling) cpp_cv suffix_cv(std::string& spelling)
{ {
auto cv = cpp_cv_none; auto cv = cpp_cv_none;
if (remove_suffix(spelling, "const")) if (remove_suffix(spelling, "const", true))
{ {
if (remove_suffix(spelling, "volatile")) if (remove_suffix(spelling, "volatile", true))
cv = cpp_cv_const_volatile; cv = cpp_cv_const_volatile;
else else
cv = cpp_cv_const; cv = cpp_cv_const;
} }
else if (remove_suffix(spelling, "volatile")) else if (remove_suffix(spelling, "volatile", true))
{ {
if (remove_suffix(spelling, "const")) if (remove_suffix(spelling, "const", true))
cv = cpp_cv_const_volatile; cv = cpp_cv_const_volatile;
else else
cv = cpp_cv_volatile; cv = cpp_cv_volatile;
@ -88,20 +114,19 @@ namespace
} }
// const/volatile at the beginning // const/volatile at the beginning
// (weird that the better version is less performant, isn't it?)
cpp_cv prefix_cv(std::string& spelling) cpp_cv prefix_cv(std::string& spelling)
{ {
auto cv = cpp_cv_none; auto cv = cpp_cv_none;
if (remove_prefix(spelling, "const")) if (remove_prefix(spelling, "const", true))
{ {
if (remove_prefix(spelling, "volatile")) if (remove_prefix(spelling, "volatile", true))
cv = cpp_cv_const_volatile; cv = cpp_cv_const_volatile;
else else
cv = cpp_cv_const; cv = cpp_cv_const;
} }
else if (remove_prefix(spelling, "volatile")) else if (remove_prefix(spelling, "volatile", true))
{ {
if (remove_prefix(spelling, "const")) if (remove_prefix(spelling, "const", true))
cv = cpp_cv_const_volatile; cv = cpp_cv_const_volatile;
else else
cv = cpp_cv_volatile; cv = cpp_cv_volatile;
@ -172,9 +197,9 @@ namespace
// remove struct/class/union prefix on inline type definition // remove struct/class/union prefix on inline type definition
// i.e. C's typedef struct idiom // i.e. C's typedef struct idiom
remove_prefix(spelling, "struct"); remove_prefix(spelling, "struct", true);
remove_prefix(spelling, "class"); remove_prefix(spelling, "class", true);
remove_prefix(spelling, "union"); remove_prefix(spelling, "union", true);
auto entity = b(std::move(spelling)); auto entity = b(std::move(spelling));
if (!entity) if (!entity)
@ -277,9 +302,9 @@ namespace
cpp_reference member_function_ref_qualifier(std::string& spelling) cpp_reference member_function_ref_qualifier(std::string& spelling)
{ {
if (remove_suffix(spelling, "&&")) if (remove_suffix(spelling, "&&", false))
return cpp_ref_rvalue; return cpp_ref_rvalue;
else if (remove_suffix(spelling, "&")) else if (remove_suffix(spelling, "&", false))
return cpp_ref_lvalue; return cpp_ref_lvalue;
return cpp_ref_none; return cpp_ref_none;
} }
@ -453,9 +478,9 @@ namespace
return nullptr; // don't use decltype here return nullptr; // don't use decltype here
return make_leave_type(type, [&](std::string&& spelling) -> std::unique_ptr<cpp_type> { return make_leave_type(type, [&](std::string&& spelling) -> std::unique_ptr<cpp_type> {
if (!remove_prefix(spelling, "decltype(")) if (!remove_prefix(spelling, "decltype(", false))
return nullptr; return nullptr;
remove_suffix(spelling, "..."); // variadic decltype. fun remove_suffix(spelling, "...", false); // variadic decltype. fun
DEBUG_ASSERT(!spelling.empty() && spelling.back() == ')', detail::parse_error_handler{}, DEBUG_ASSERT(!spelling.empty() && spelling.back() == ')', detail::parse_error_handler{},
type, "unexpected spelling"); type, "unexpected spelling");
spelling.pop_back(); spelling.pop_back();
@ -652,7 +677,7 @@ namespace
case CXType_Typedef: case CXType_Typedef:
return make_leave_type(type, [&](std::string&& spelling) { return make_leave_type(type, [&](std::string&& spelling) {
auto decl = clang_getTypeDeclaration(type); auto decl = clang_getTypeDeclaration(type);
if (remove_prefix(spelling, "(anonymous")) if (remove_prefix(spelling, "(anonymous", false))
spelling = ""; // anonymous type spelling = ""; // anonymous type
return cpp_user_defined_type::build( return cpp_user_defined_type::build(
cpp_type_ref(detail::get_entity_id(decl), std::move(spelling))); cpp_type_ref(detail::get_entity_id(decl), std::move(spelling)));

View file

@ -19,6 +19,10 @@ template<template<typename>class... T>
struct templated{ struct templated{
}; };
using struct_=int;
struct_ var2;
struct foo{ struct foo{
int a; int a;
@ -56,6 +60,10 @@ struct templated
{ {
}; };
using struct_ = int;
struct_ var2;
struct foo struct foo
{ {
int a; int a;