Add semantic parent to forward declarable entities
This commit is contained in:
parent
cf7ea80768
commit
599f2bbff8
20 changed files with 260 additions and 109 deletions
|
|
@ -205,7 +205,7 @@ namespace
|
|||
output << keyword("enum");
|
||||
if (e.is_scoped())
|
||||
output << whitespace << keyword("class");
|
||||
output << whitespace << identifier(e.name());
|
||||
output << whitespace << identifier(e.semantic_scope()) << identifier(e.name());
|
||||
if (e.has_explicit_type())
|
||||
{
|
||||
output << newl << punctuation(":");
|
||||
|
|
@ -285,6 +285,7 @@ namespace
|
|||
output << keyword("friend") << whitespace;
|
||||
output << keyword(to_string(c.class_kind())) << whitespace;
|
||||
|
||||
output << identifier(c.semantic_scope());
|
||||
if (spec)
|
||||
{
|
||||
output << spec.value().primary_template();
|
||||
|
|
@ -492,6 +493,7 @@ namespace
|
|||
output << whitespace;
|
||||
}
|
||||
|
||||
output << identifier(func.semantic_scope());
|
||||
if (spec)
|
||||
{
|
||||
output << spec.value().primary_template();
|
||||
|
|
@ -585,6 +587,7 @@ namespace
|
|||
output << whitespace;
|
||||
}
|
||||
|
||||
output << identifier(func.semantic_scope());
|
||||
if (spec)
|
||||
{
|
||||
output << spec.value().primary_template();
|
||||
|
|
@ -621,6 +624,8 @@ namespace
|
|||
else
|
||||
write_prefix_virtual(output, op.virtual_info());
|
||||
|
||||
output << identifier(op.semantic_scope());
|
||||
|
||||
auto pos = op.name().find("operator");
|
||||
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
||||
detail::write_type(output, op.return_type(), "");
|
||||
|
|
@ -645,7 +650,7 @@ namespace
|
|||
if (ctor.is_constexpr())
|
||||
output << keyword("constexpr") << whitespace;
|
||||
|
||||
output << identifier(ctor.name());
|
||||
output << identifier(ctor.semantic_scope()) << identifier(ctor.name());
|
||||
write_function_parameters(output, ctor);
|
||||
write_noexcept(output, ctor, false);
|
||||
|
||||
|
|
@ -661,7 +666,8 @@ namespace
|
|||
if (is_friended(dtor))
|
||||
output << keyword("friend") << whitespace;
|
||||
write_prefix_virtual(output, dtor.virtual_info());
|
||||
output << identifier(dtor.name()) << punctuation("(") << punctuation(")");
|
||||
output << identifier(dtor.semantic_scope()) << identifier(dtor.name())
|
||||
<< punctuation("(") << punctuation(")");
|
||||
write_noexcept(output, dtor, false);
|
||||
|
||||
write_suffix_virtual(output, dtor.virtual_info());
|
||||
|
|
|
|||
|
|
@ -9,8 +9,11 @@
|
|||
|
||||
using namespace cppast;
|
||||
|
||||
std::unique_ptr<cpp_class> cpp_class::builder::finish(const cpp_entity_index& idx, cpp_entity_id id)
|
||||
std::unique_ptr<cpp_class> cpp_class::builder::finish(
|
||||
const cpp_entity_index& idx, cpp_entity_id id,
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent)
|
||||
{
|
||||
class_->set_semantic_parent(std::move(semantic_parent));
|
||||
idx.register_definition(std::move(id), type_safe::ref(*class_));
|
||||
return std::move(class_);
|
||||
}
|
||||
|
|
@ -18,19 +21,21 @@ std::unique_ptr<cpp_class> cpp_class::builder::finish(const cpp_entity_index& id
|
|||
std::unique_ptr<cpp_class> cpp_class::builder::finish_declaration(const cpp_entity_index& idx,
|
||||
cpp_entity_id definition_id)
|
||||
{
|
||||
class_->set_definition(definition_id);
|
||||
class_->mark_declaration(definition_id);
|
||||
idx.register_forward_declaration(std::move(definition_id), type_safe::ref(*class_));
|
||||
return std::move(class_);
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_class> cpp_class::builder::finish()
|
||||
std::unique_ptr<cpp_class> cpp_class::builder::finish(
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent)
|
||||
{
|
||||
class_->set_semantic_parent(std::move(semantic_parent));
|
||||
return std::move(class_);
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_class> cpp_class::builder::finish_declaration(cpp_entity_id definition_id)
|
||||
{
|
||||
class_->set_definition(definition_id);
|
||||
class_->mark_declaration(definition_id);
|
||||
return std::move(class_);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ std::unique_ptr<cpp_variable> cpp_variable::build_declaration(cpp_entity_id defi
|
|||
{
|
||||
auto result = std::unique_ptr<cpp_variable>(
|
||||
new cpp_variable(std::move(name), std::move(type), nullptr, spec, is_constexpr));
|
||||
result->set_definition(definition_id);
|
||||
result->mark_declaration(definition_id);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,9 +99,34 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
|
|||
auto is_friend = false;
|
||||
#endif
|
||||
|
||||
auto builder = make_class_builder(cur);
|
||||
auto builder = make_class_builder(cur);
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent;
|
||||
if (!is_friend)
|
||||
{
|
||||
if (!clang_equalCursors(clang_getCursorSemanticParent(cur),
|
||||
clang_getCursorLexicalParent(cur)))
|
||||
{
|
||||
// out-of-line definition
|
||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::token_stream stream(tokenizer, cur);
|
||||
|
||||
std::string name = detail::get_cursor_name(cur).c_str();
|
||||
auto pos = name.find('<');
|
||||
if (pos != std::string::npos)
|
||||
name.erase(pos, std::string::npos);
|
||||
|
||||
std::string scope;
|
||||
while (!detail::skip_if(stream, name.c_str()))
|
||||
{
|
||||
if (!detail::append_scope(stream, scope))
|
||||
stream.bump();
|
||||
}
|
||||
if (!scope.empty())
|
||||
semantic_parent =
|
||||
cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
}
|
||||
|
||||
context.comments.match(builder.get(), cur);
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
auto kind = clang_getCursorKind(child);
|
||||
|
|
@ -123,7 +148,9 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
|
|||
}
|
||||
|
||||
if (!is_friend && clang_isCursorDefinition(cur))
|
||||
return is_templated ? builder.finish() : builder.finish(*context.idx, get_entity_id(cur));
|
||||
return is_templated ?
|
||||
builder.finish(std::move(semantic_parent)) :
|
||||
builder.finish(*context.idx, get_entity_id(cur), std::move(semantic_parent));
|
||||
else
|
||||
return is_templated ? builder.finish_declaration(detail::get_entity_id(cur)) :
|
||||
builder.finish_declaration(*context.idx, get_entity_id(cur));
|
||||
|
|
|
|||
|
|
@ -41,8 +41,10 @@ namespace
|
|||
std::move(value));
|
||||
}
|
||||
|
||||
cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur)
|
||||
cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur,
|
||||
type_safe::optional<cpp_entity_ref>& semantic_parent)
|
||||
{
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::token_stream stream(tokenizer, cur);
|
||||
|
||||
|
|
@ -51,7 +53,15 @@ namespace
|
|||
detail::skip(stream, "enum");
|
||||
auto scoped = detail::skip_if(stream, "class");
|
||||
detail::skip_attribute(stream);
|
||||
auto& name = stream.get().value();
|
||||
std::string scope;
|
||||
while (!detail::skip_if(stream, name.c_str()))
|
||||
if (!detail::append_scope(stream, scope))
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
|
||||
"unexpected tokens in enum name");
|
||||
if (!scope.empty())
|
||||
semantic_parent =
|
||||
cpp_entity_ref(detail::get_entity_id(clang_getCursorSemanticParent(cur)),
|
||||
std::move(scope));
|
||||
|
||||
// parse type
|
||||
auto type = detail::parse_type(context, cur, clang_getEnumDeclIntegerType(cur));
|
||||
|
|
@ -66,7 +76,8 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_enum(const detail::parse_context&
|
|||
{
|
||||
DEBUG_ASSERT(cur.kind == CXCursor_EnumDecl, detail::assert_handler{});
|
||||
|
||||
auto builder = make_enum_builder(context, cur);
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent;
|
||||
auto builder = make_enum_builder(context, cur, semantic_parent);
|
||||
context.comments.match(builder.get(), cur);
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
try
|
||||
|
|
@ -82,7 +93,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_enum(const detail::parse_context&
|
|||
}
|
||||
});
|
||||
if (clang_isCursorDefinition(cur))
|
||||
return builder.finish(*context.idx, get_entity_id(cur));
|
||||
return builder.finish(*context.idx, get_entity_id(cur), std::move(semantic_parent));
|
||||
else
|
||||
return builder.finish_declaration(*context.idx, get_entity_id(cur));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,9 +75,12 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_friend(const detail::parse_context
|
|||
else if (clang_isDeclaration(kind))
|
||||
{
|
||||
entity = parse_entity(context, child);
|
||||
// steal comment
|
||||
comment = type_safe::copy(entity->comment()).value_or("");
|
||||
entity->set_comment(type_safe::nullopt);
|
||||
if (entity)
|
||||
{
|
||||
// steal comment
|
||||
comment = type_safe::copy(entity->comment()).value_or("");
|
||||
entity->set_comment(type_safe::nullopt);
|
||||
}
|
||||
}
|
||||
else if (inst_builder && clang_isExpression(kind))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -86,10 +86,10 @@ namespace
|
|||
// just the tokens occurring in the prefix
|
||||
struct prefix_info
|
||||
{
|
||||
std::string scope_name;
|
||||
bool is_constexpr = false;
|
||||
bool is_virtual = false;
|
||||
bool is_explicit = false;
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent;
|
||||
bool is_constexpr = false;
|
||||
bool is_virtual = false;
|
||||
bool is_explicit = false;
|
||||
};
|
||||
|
||||
bool prefix_end(detail::token_stream& stream, const char* name, bool is_ctor)
|
||||
|
|
@ -153,38 +153,18 @@ namespace
|
|||
result.is_explicit = true;
|
||||
scope.clear();
|
||||
}
|
||||
// add identifiers and "::" to current scope name,
|
||||
// clear if there is any other token in between, or mismatched combination
|
||||
else if (stream.peek().kind() == CXToken_Identifier)
|
||||
{
|
||||
if (!scope.empty() && scope.back() != ':')
|
||||
scope.clear();
|
||||
scope += stream.get().c_str();
|
||||
}
|
||||
else if (stream.peek() == "::")
|
||||
{
|
||||
if (!scope.empty() && scope.back() == ':')
|
||||
scope.clear();
|
||||
scope += stream.get().c_str();
|
||||
}
|
||||
else if (stream.peek() == "<")
|
||||
{
|
||||
auto iter = detail::find_closing_bracket(stream);
|
||||
scope += detail::to_string(stream, iter);
|
||||
if (!detail::skip_if(stream, ">>"))
|
||||
detail::skip(stream, ">");
|
||||
scope += ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
else if (!detail::append_scope(stream, scope))
|
||||
stream.bump();
|
||||
scope.clear();
|
||||
}
|
||||
}
|
||||
DEBUG_ASSERT(!stream.done(), detail::parse_error_handler{}, stream.cursor(),
|
||||
"unable to find end of function prefix");
|
||||
if (!scope.empty() && scope.back() == ':')
|
||||
result.scope_name = std::move(scope);
|
||||
{
|
||||
result.semantic_parent =
|
||||
cpp_entity_ref(detail::get_entity_id(
|
||||
clang_getCursorSemanticParent(stream.cursor())),
|
||||
std::move(scope));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -392,7 +372,7 @@ namespace
|
|||
DEBUG_ASSERT(!prefix.is_virtual && !prefix.is_explicit, detail::parse_error_handler{}, cur,
|
||||
"free function cannot be virtual or explicit");
|
||||
|
||||
cpp_function::builder builder(prefix.scope_name + name.c_str(),
|
||||
cpp_function::builder builder(name.c_str(),
|
||||
detail::parse_type(context, cur,
|
||||
clang_getCursorResultType(cur)));
|
||||
context.comments.match(builder.get(), cur);
|
||||
|
|
@ -413,9 +393,11 @@ namespace
|
|||
builder.noexcept_condition(std::move(suffix.noexcept_condition));
|
||||
|
||||
if (is_templated_cursor(cur))
|
||||
return builder.finish(detail::get_entity_id(cur), suffix.body_kind);
|
||||
return builder.finish(detail::get_entity_id(cur), suffix.body_kind,
|
||||
std::move(prefix.semantic_parent));
|
||||
else
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind,
|
||||
std::move(prefix.semantic_parent));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,6 +407,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_function(const detail::parse_conte
|
|||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_FunctionDecl
|
||||
|| clang_getTemplateCursorKind(cur) == CXCursor_FunctionDecl,
|
||||
detail::assert_handler{});
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent;
|
||||
return parse_cpp_function_impl(context, cur, false);
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +493,8 @@ namespace
|
|||
template <class Builder>
|
||||
std::unique_ptr<cpp_entity> handle_suffix(const detail::parse_context& context,
|
||||
const CXCursor& cur, Builder& builder,
|
||||
detail::token_stream& stream, bool is_virtual)
|
||||
detail::token_stream& stream, bool is_virtual,
|
||||
type_safe::optional<cpp_entity_ref> semantic_parent)
|
||||
{
|
||||
auto allow_qualifiers = set_qualifier(0, builder, cpp_cv_none, cpp_ref_none);
|
||||
|
||||
|
|
@ -522,9 +506,11 @@ namespace
|
|||
builder.virtual_info(virt.value());
|
||||
|
||||
if (is_templated_cursor(cur))
|
||||
return builder.finish(detail::get_entity_id(cur), suffix.body_kind);
|
||||
return builder.finish(detail::get_entity_id(cur), suffix.body_kind,
|
||||
std::move(semantic_parent));
|
||||
else
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind,
|
||||
std::move(semantic_parent));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -543,7 +529,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_member_function(const detail::pars
|
|||
DEBUG_ASSERT(!prefix.is_explicit, detail::parse_error_handler{}, cur,
|
||||
"member function cannot be explicit");
|
||||
|
||||
cpp_member_function::builder builder(prefix.scope_name + name.c_str(),
|
||||
cpp_member_function::builder builder(name.c_str(),
|
||||
detail::parse_type(context, cur,
|
||||
clang_getCursorResultType(cur)));
|
||||
context.comments.match(builder.get(), cur);
|
||||
|
|
@ -555,7 +541,8 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_member_function(const detail::pars
|
|||
builder.is_constexpr();
|
||||
|
||||
skip_parameters(stream);
|
||||
return handle_suffix(context, cur, builder, stream, prefix.is_virtual);
|
||||
return handle_suffix(context, cur, builder, stream, prefix.is_virtual,
|
||||
std::move(prefix.semantic_parent));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_context& context,
|
||||
|
|
@ -604,7 +591,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_
|
|||
detail::skip(stream, ")");
|
||||
|
||||
auto type = clang_getCursorResultType(cur);
|
||||
cpp_conversion_op::builder builder(prefix.scope_name + "operator " + type_spelling,
|
||||
cpp_conversion_op::builder builder("operator " + type_spelling,
|
||||
detail::parse_type(context, cur, type));
|
||||
context.comments.match(builder.get(), cur);
|
||||
if (prefix.is_explicit)
|
||||
|
|
@ -612,7 +599,8 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_
|
|||
else if (prefix.is_constexpr)
|
||||
builder.is_constexpr();
|
||||
|
||||
return handle_suffix(context, cur, builder, stream, prefix.is_virtual);
|
||||
return handle_suffix(context, cur, builder, stream, prefix.is_virtual,
|
||||
std::move(prefix.semantic_parent));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_constructor(const detail::parse_context& context,
|
||||
|
|
@ -633,7 +621,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_constructor(const detail::parse_co
|
|||
DEBUG_ASSERT(!prefix.is_virtual, detail::parse_error_handler{}, cur,
|
||||
"constructor cannot be virtual");
|
||||
|
||||
cpp_constructor::builder builder(prefix.scope_name + name.c_str());
|
||||
cpp_constructor::builder builder(name.c_str());
|
||||
context.comments.match(builder.get(), cur);
|
||||
add_parameters(context, builder, cur);
|
||||
if (clang_Cursor_isVariadic(cur))
|
||||
|
|
@ -650,9 +638,11 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_constructor(const detail::parse_co
|
|||
builder.noexcept_condition(std::move(suffix.noexcept_condition));
|
||||
|
||||
if (is_templated_cursor(cur))
|
||||
return builder.finish(detail::get_entity_id(cur), suffix.body_kind);
|
||||
return builder.finish(detail::get_entity_id(cur), suffix.body_kind,
|
||||
std::move(prefix.semantic_parent));
|
||||
else
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind,
|
||||
std::move(prefix.semantic_parent));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_destructor(const detail::parse_context& context,
|
||||
|
|
@ -671,5 +661,5 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_destructor(const detail::parse_con
|
|||
|
||||
detail::skip(stream, "(");
|
||||
detail::skip(stream, ")");
|
||||
return handle_suffix(context, cur, builder, stream, is_virtual);
|
||||
return handle_suffix(context, cur, builder, stream, is_virtual, type_safe::nullopt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,3 +389,35 @@ std::string detail::to_string(token_stream& stream, token_iterator end)
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool detail::append_scope(detail::token_stream& stream, std::string& scope)
|
||||
{
|
||||
// add identifiers and "::" to current scope name,
|
||||
// clear if there is any other token in between, or mismatched combination
|
||||
if (stream.peek().kind() == CXToken_Identifier)
|
||||
{
|
||||
if (!scope.empty() && scope.back() != ':')
|
||||
scope.clear();
|
||||
scope += stream.get().c_str();
|
||||
}
|
||||
else if (stream.peek() == "::")
|
||||
{
|
||||
if (!scope.empty() && scope.back() == ':')
|
||||
scope.clear();
|
||||
scope += stream.get().c_str();
|
||||
}
|
||||
else if (stream.peek() == "<")
|
||||
{
|
||||
auto iter = detail::find_closing_bracket(stream);
|
||||
scope += detail::to_string(stream, iter);
|
||||
if (!detail::skip_if(stream, ">>"))
|
||||
detail::skip(stream, ">");
|
||||
scope += ">";
|
||||
}
|
||||
else
|
||||
{
|
||||
scope.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,6 +191,12 @@ namespace cppast
|
|||
|
||||
// converts a token range to a string, adding whitespace where necessary
|
||||
std::string to_string(token_stream& stream, token_iterator end);
|
||||
|
||||
// appends token to scope, if it is still valid
|
||||
// else clears it
|
||||
// note: does not consume the token if it is not valid,
|
||||
// returns false in that case
|
||||
bool append_scope(token_stream& stream, std::string& scope);
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue