Add and parse cpp_friend

Only works in clang>=4.
This commit is contained in:
Jonathan Müller 2017-04-06 11:45:17 +02:00
commit c3d1d97892
18 changed files with 629 additions and 92 deletions

View file

@ -89,29 +89,40 @@ namespace
}
std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context& context,
const CXCursor& cur)
const CXCursor& cur, const CXCursor& parent_cur)
{
auto builder = make_class_builder(cur);
context.comments.match(builder.get(), cur);
detail::visit_children(cur, [&](const CXCursor& child) {
auto kind = clang_getCursorKind(child);
if (kind == CXCursor_CXXAccessSpecifier)
add_access_specifier(builder, child);
else if (kind == CXCursor_CXXBaseSpecifier)
add_base_class(builder, context, child, cur);
else if (kind == CXCursor_CXXFinalAttr)
builder.is_final();
else if (kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|| kind == CXCursor_TemplateTemplateParameter || clang_isExpression(kind)
|| clang_isReference(kind))
// other children due to templates and stuff
return;
else if (auto entity = parse_entity(context, child))
builder.add_child(std::move(entity));
});
auto is_templated = (clang_getTemplateCursorKind(cur) != CXCursor_NoDeclFound
|| !clang_Cursor_isNull(clang_getSpecializedCursorTemplate(cur)));
if (clang_isCursorDefinition(cur))
#if CPPAST_CINDEX_HAS_FRIEND
auto is_friend = clang_getCursorKind(parent_cur) == CXCursor_FriendDecl;
#else
auto is_friend = false;
#endif
auto builder = make_class_builder(cur);
if (!is_friend)
{
context.comments.match(builder.get(), cur);
detail::visit_children(cur, [&](const CXCursor& child) {
auto kind = clang_getCursorKind(child);
if (kind == CXCursor_CXXAccessSpecifier)
add_access_specifier(builder, child);
else if (kind == CXCursor_CXXBaseSpecifier)
add_base_class(builder, context, child, cur);
else if (kind == CXCursor_CXXFinalAttr)
builder.is_final();
else if (kind == CXCursor_TemplateTypeParameter
|| kind == CXCursor_NonTypeTemplateParameter
|| kind == CXCursor_TemplateTemplateParameter || clang_isExpression(kind)
|| clang_isReference(kind))
// other children due to templates and stuff
return;
else if (auto entity = parse_entity(context, child))
builder.add_child(std::move(entity));
});
}
if (!is_friend && clang_isCursorDefinition(cur))
return is_templated ? builder.finish() : builder.finish(*context.idx, get_entity_id(cur));
else
return is_templated ? builder.finish_declaration(detail::get_entity_id(cur)) :

View file

@ -0,0 +1,107 @@
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.
#include <cppast/cpp_friend.hpp>
#include <cppast/cpp_template_parameter.hpp>
#include <cppast/cpp_template.hpp>
#include "parse_functions.hpp"
#include "libclang_visitor.hpp"
using namespace cppast;
#if CPPAST_CINDEX_HAS_FRIEND
std::unique_ptr<cpp_entity> detail::parse_cpp_friend(const detail::parse_context& context,
const CXCursor& cur)
{
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_FriendDecl, detail::assert_handler{});
std::string comment;
std::unique_ptr<cpp_entity> entity;
std::unique_ptr<cpp_type> type;
std::string namespace_str;
type_safe::optional<cpp_template_instantiation_type::builder> inst_builder;
detail::visit_children(cur, [&](const CXCursor& child) {
auto kind = clang_getCursorKind(child);
if (kind == CXCursor_TypeRef)
{
auto referenced = clang_getCursorReferenced(child);
if (inst_builder)
{
namespace_str.clear();
inst_builder.value().add_argument(
detail::parse_type(context, referenced, clang_getCursorType(referenced)));
}
else if (clang_getCursorKind(referenced) == CXCursor_TemplateTypeParameter)
// parse template parameter type
type = cpp_template_parameter_type::build(
cpp_template_type_parameter_ref(detail::get_entity_id(referenced),
detail::get_cursor_name(child).c_str()));
else if (!namespace_str.empty())
{
// parse as user defined type
// we can't use the other branch here,
// as then the class name would be wrong
auto name = detail::get_cursor_name(referenced);
type =
cpp_user_defined_type::build(cpp_type_ref(detail::get_entity_id(referenced),
namespace_str + "::" + name.c_str()));
}
else
{
// for some reason libclang gives a type ref here
// we actually need a class decl cursor, so parse the referenced one
// this might be a definition, so give friend information to the parser
entity = parse_entity(context, referenced, cur);
comment = type_safe::copy(entity->comment()).value_or("");
}
}
else if (kind == CXCursor_NamespaceRef)
namespace_str += detail::get_cursor_name(child).c_str();
else if (kind == CXCursor_TemplateRef)
{
if (!namespace_str.empty())
namespace_str += "::";
auto templ = cpp_template_ref(detail::get_entity_id(clang_getCursorReferenced(child)),
namespace_str + detail::get_cursor_name(child).c_str());
namespace_str.clear();
if (!inst_builder)
inst_builder = cpp_template_instantiation_type::builder(std::move(templ));
else
inst_builder.value().add_argument(std::move(templ));
}
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);
}
else if (inst_builder && clang_isExpression(kind))
{
namespace_str.clear();
inst_builder.value().add_argument(detail::parse_expression(context, child));
}
});
std::unique_ptr<cpp_entity> result;
if (entity)
result = cpp_friend::build(std::move(entity));
else if (type)
result = cpp_friend::build(std::move(type));
else if (inst_builder)
result = cpp_friend::build(inst_builder.value().finish());
else
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur,
"unknown child entity of friend declaration");
if (!comment.empty())
// set comment of entity...
result->set_comment(std::move(comment));
// ... but override if this finds a different comment
// due to clang_getCursorReferenced(), this may happen
context.comments.match(*result, cur);
return result;
}
#endif

View file

@ -384,7 +384,7 @@ namespace
builder.noexcept_condition(std::move(suffix.noexcept_condition));
if (is_templated_cursor(cur))
return builder.finish(suffix.body_kind);
return builder.finish(detail::get_entity_id(cur), suffix.body_kind);
else
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
}
@ -493,7 +493,7 @@ namespace
builder.virtual_info(virt.value());
if (is_templated_cursor(cur))
return builder.finish(suffix.body_kind);
return builder.finish(detail::get_entity_id(cur), suffix.body_kind);
else
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
}
@ -618,7 +618,7 @@ 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(suffix.body_kind);
return builder.finish(detail::get_entity_id(cur), suffix.body_kind);
else
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
}

View file

@ -72,7 +72,7 @@ void detail::comment_context::match(cpp_entity& e, unsigned line) const
std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& context,
const CXCursor& cur,
const CXCursor& template_cur) try
const CXCursor& parent_cur) try
{
auto kind = clang_getCursorKind(cur);
switch (kind)
@ -94,7 +94,7 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
case CXCursor_TypeAliasDecl:
case CXCursor_TypedefDecl:
return parse_cpp_type_alias(context, cur, template_cur);
return parse_cpp_type_alias(context, cur, parent_cur);
case CXCursor_EnumDecl:
return parse_cpp_enum(context, cur);
case CXCursor_ClassDecl:
@ -102,7 +102,7 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
case CXCursor_UnionDecl:
if (auto spec = try_parse_full_cpp_class_template_specialization(context, cur))
return spec;
return parse_cpp_class(context, cur);
return parse_cpp_class(context, cur, parent_cur);
case CXCursor_VarDecl:
return parse_cpp_variable(context, cur);
@ -130,6 +130,11 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
case CXCursor_Destructor:
return parse_cpp_destructor(context, cur);
#if CPPAST_CINDEX_HAS_FRIEND
case CXCursor_FriendDecl:
return parse_cpp_friend(context, cur);
#endif
case CXCursor_TypeAliasTemplateDecl:
return parse_cpp_alias_template(context, cur);
case CXCursor_FunctionTemplate:

View file

@ -13,6 +13,12 @@
#include "parse_error.hpp" // for convenience
#include "preprocessor.hpp"
#if CINDEX_VERSION_MINOR >= 36
#define CPPAST_CINDEX_HAS_FRIEND 1
#else
#define CPPAST_CINDEX_HAS_FRIEND 0
#endif
namespace cppast
{
class cpp_expression;
@ -118,7 +124,8 @@ namespace cppast
std::unique_ptr<cpp_entity> parse_cpp_enum(const parse_context& context,
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_class(const parse_context& context,
const CXCursor& cur);
const CXCursor& cur,
const CXCursor& parent_cur);
std::unique_ptr<cpp_entity> parse_cpp_variable(const parse_context& context,
const CXCursor& cur);
@ -137,6 +144,9 @@ namespace cppast
std::unique_ptr<cpp_entity> parse_cpp_destructor(const parse_context& context,
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_friend(const parse_context& context,
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_alias_template(const parse_context& context,
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_function_template(const parse_context& context,
@ -146,10 +156,10 @@ namespace cppast
std::unique_ptr<cpp_entity> parse_cpp_class_template_specialization(
const parse_context& context, const CXCursor& cur);
// as_template: true, iff currently parsing a template
// parent_cur: used when parsing templates or friends
std::unique_ptr<cpp_entity> parse_entity(
const parse_context& context, const CXCursor& cur,
const CXCursor& template_cur = clang_getNullCursor());
const CXCursor& parent_cur = clang_getNullCursor());
}
} // namespace cppast::detail

View file

@ -333,7 +333,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class_template(const detail::parse
{
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_ClassTemplate, detail::assert_handler{});
auto c = detail::parse_cpp_class(context, cur);
auto c = detail::parse_cpp_class(context, cur, clang_getNullCursor());
if (!c)
return nullptr;
@ -373,7 +373,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class_template_specialization(
detail::assert_handler{});
auto primary = clang_getSpecializedCursorTemplate(cur);
auto c = detail::parse_cpp_class(context, cur);
auto c = detail::parse_cpp_class(context, cur, clang_getNullCursor());
if (!c)
return nullptr;