forked from standardese/cppast
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclass_parser.cpp
More file actions
190 lines (164 loc) · 6.77 KB
/
Copy pathclass_parser.cpp
File metadata and controls
190 lines (164 loc) · 6.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// Copyright (C) 2017-2023 Jonathan Müller and cppast contributors
// SPDX-License-Identifier: MIT
#include <clang-c/Index.h>
#include <cppast/cpp_class.hpp>
#include "libclang_visitor.hpp"
#include "parse_functions.hpp"
using namespace cppast;
namespace
{
cpp_class_kind parse_class_kind(detail::cxtoken_stream& stream)
{
auto kind = clang_getTemplateCursorKind(stream.cursor());
if (kind == CXCursor_NoDeclFound)
kind = clang_getCursorKind(stream.cursor());
if (detail::skip_if(stream, "template"))
{
// skip template parameters
if (!stream.done() && *stream.cur() == "<")
detail::skip_brackets(stream);
}
detail::skip_if(stream, "friend");
if (detail::skip_if(stream, "extern"))
// extern template
detail::skip(stream, "template");
switch (kind)
{
case CXCursor_ClassDecl:
detail::skip(stream, "class");
return cpp_class_kind::class_t;
case CXCursor_StructDecl:
detail::skip(stream, "struct");
return cpp_class_kind::struct_t;
case CXCursor_UnionDecl:
detail::skip(stream, "union");
return cpp_class_kind::union_t;
default:
break;
}
DEBUG_UNREACHABLE(detail::assert_handler{});
return cpp_class_kind::class_t;
}
cpp_class::builder make_class_builder(const detail::parse_context& context, const CXCursor& cur)
{
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
detail::cxtoken_stream stream(tokenizer, cur);
auto kind = parse_class_kind(stream);
auto attributes = detail::parse_attributes(stream);
auto name = detail::get_cursor_name(cur);
auto result = cpp_class::builder(name.c_str(), kind);
result.get().add_attribute(attributes);
return result;
}
cpp_access_specifier_kind convert_access(const CXCursor& cur)
{
switch (clang_getCXXAccessSpecifier(cur))
{
case CX_CXXInvalidAccessSpecifier:
break;
case CX_CXXPublic:
return cpp_public;
case CX_CXXProtected:
return cpp_protected;
case CX_CXXPrivate:
return cpp_private;
}
DEBUG_UNREACHABLE(detail::assert_handler{});
return cpp_public;
}
void add_access_specifier(cpp_class::builder& builder, const CXCursor& cur)
{
DEBUG_ASSERT(cur.kind == CXCursor_CXXAccessSpecifier, detail::assert_handler{});
builder.access_specifier(convert_access(cur));
}
void add_base_class(cpp_class::builder& builder, const detail::parse_context& context,
const CXCursor& cur, const CXCursor& class_cur)
{
DEBUG_ASSERT(cur.kind == CXCursor_CXXBaseSpecifier, detail::assert_handler{});
auto access = convert_access(cur);
auto is_virtual = clang_isVirtualBase(cur) != 0u;
detail::cxtokenizer tokenizer(context.tu, context.file, cur);
detail::cxtoken_stream stream(tokenizer, cur);
// [<attribute>] [virtual] [<access>] <name>
// or
// [<attribute>] [<access>] [virtual] <name>
// can't use spelling to get the name
auto attributes = detail::parse_attributes(stream);
if (is_virtual)
{
if (detail::skip_if(stream, "virtual"))
detail::skip_if(stream, to_string(access));
else
{
detail::skip_if(stream, to_string(access));
detail::skip(stream, "virtual");
}
}
else
detail::skip_if(stream, to_string(access));
auto name = detail::to_string(stream, stream.end(), false).as_string();
auto type = detail::parse_type(context, class_cur, clang_getCursorType(cur));
auto& base = builder.base_class(std::move(name), std::move(type), access, is_virtual);
base.add_attribute(attributes);
}
} // namespace
std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context& context,
const CXCursor& cur, const CXCursor& parent_cur)
{
auto is_templated = (clang_getTemplateCursorKind(cur) != CXCursor_NoDeclFound
|| !clang_Cursor_isNull(clang_getSpecializedCursorTemplate(cur)));
auto is_friend = clang_getCursorKind(parent_cur) == CXCursor_FriendDecl;
auto builder = make_class_builder(context, 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::cxtokenizer tokenizer(context.tu, context.file, cur);
detail::cxtoken_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);
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 || kind == CXCursor_ParmDecl
|| clang_isExpression(kind) || clang_isReference(kind)
|| kind == CXCursor_UnexposedAttr) // I have no idea what this is, but happens
// on Windows
// other children due to templates and stuff
return;
else if (auto entity = parse_entity(context, &builder.get(), child))
builder.add_child(std::move(entity));
});
}
if (!is_friend && clang_isCursorDefinition(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));
}