2
2
#include " pystring.h"
3
3
#include " clang/AST/ASTContext.h"
4
4
#include " clang/AST/Decl.h"
5
+ #include " clang/AST/PrettyPrinter.h"
5
6
#include " clang/AST/DeclCXX.h"
6
7
#include " clang/AST/DeclTemplate.h"
7
8
#include " clang/AST/GlobalDecl.h"
10
11
#include " clang/ASTMatchers/ASTMatchers.h"
11
12
#include " clang/Basic/LLVM.h"
12
13
#include " llvm/Support/Casting.h"
14
+ #include " llvm/Support/raw_ostream.h"
13
15
#include < cassert>
14
16
#include < cstdint>
15
17
#include < memory>
@@ -28,6 +30,7 @@ namespace fs = ghc::filesystem;
28
30
29
31
#include " ast.hpp"
30
32
#include " ast_utils.hpp"
33
+ #include " base64.hpp"
31
34
32
35
using namespace clang ;
33
36
using namespace clang ::ast_matchers;
@@ -131,7 +134,7 @@ QType process_qtype(const QualType& qt) {
131
134
NodeId id;
132
135
if (it == NODE_MAP.end ()) {
133
136
const ConstantArrayType* cat =
134
- dyn_cast<ConstantArrayType>(qt.getTypePtr ());
137
+ dyn_cast<ConstantArrayType>(qt.getCanonicalType (). getTypePtr ());
135
138
QType element_type = process_qtype (cat->getElementType ());
136
139
id = NODES.size ();
137
140
auto node_type = std::make_unique<NodeConstantArrayType>(
@@ -157,13 +160,12 @@ QType process_qtype(const QualType& qt) {
157
160
const std::string pointer_type_name =
158
161
qt.getCanonicalType ().getAsString ();
159
162
const std::string pointer_type_node_name = " TYPE:" + pointer_type_name;
160
-
163
+
161
164
auto it = NODE_MAP.find (pointer_type_name);
162
165
NodeId id;
163
166
if (it == NODE_MAP.end ()) {
164
167
// need to create the pointer type, create the pointee type first
165
- QType pointee_qtype =
166
- process_qtype (qt->getPointeeType ());
168
+ QType pointee_qtype = process_qtype (qt->getPointeeType ());
167
169
168
170
// now create the pointer type
169
171
id = NODES.size ();
@@ -203,7 +205,7 @@ QType process_qtype(const QualType& qt) {
203
205
type_node_name = " TYPE:" + mangled_name;
204
206
}
205
207
206
- // FIXME: hack to work around unsigned long being different sizes on
208
+ // FIXME: hack to work around unsigned long being different sizes on
207
209
// windows and *nix
208
210
if (qt->isBuiltinType () && type_name == " unsigned long" ) {
209
211
const auto * tdt = qt->getAs <TypedefType>();
@@ -213,13 +215,15 @@ QType process_qtype(const QualType& qt) {
213
215
} else if (tdt && tdt->getDecl ()->getNameAsString () == " size_t" ) {
214
216
type_name = " size_t" ;
215
217
type_node_name = " TYPE:size_t" ;
216
- } else if (tdt && tdt->getDecl ()->getNameAsString () == " size_type" ) {
218
+ } else if (tdt &&
219
+ tdt->getDecl ()->getNameAsString () == " size_type" ) {
217
220
// FIXME: Nasty hack here to get e.g. std::string::size_type
218
221
// will this bite us?
219
222
type_name = " size_t" ;
220
223
type_node_name = " TYPE:size_t" ;
221
224
} else if (tdt) {
222
- /* SPDLOG_WARN("Unhandled unsigned long typedef {}", tdt->getDecl()->getNameAsString()); */
225
+ /* SPDLOG_WARN("Unhandled unsigned long typedef {}",
226
+ * tdt->getDecl()->getNameAsString()); */
223
227
// If we're some other typedef of unsigned long, try desugaring
224
228
// recursively until we get to a typedef we can handle
225
229
QualType ds_type = tdt->desugar ();
@@ -230,7 +234,8 @@ QType process_qtype(const QualType& qt) {
230
234
if (tdt && tdt->getDecl ()->getNameAsString () == " int64_t" ) {
231
235
type_name = " int64_t" ;
232
236
type_node_name = " TYPE:int64_t" ;
233
- } else if (tdt && tdt->getDecl ()->getNameAsString () == " ptrdiff_t" ) {
237
+ } else if (tdt &&
238
+ tdt->getDecl ()->getNameAsString () == " ptrdiff_t" ) {
234
239
type_name = " ptrdiff_t" ;
235
240
type_node_name = " TYPE:ptrdiff_t" ;
236
241
}
@@ -450,11 +455,20 @@ bool has_noexcept_attr(const std::vector<std::string>& attrs) {
450
455
attrs.end ();
451
456
}
452
457
453
- bool has_manual_attr (const std::vector<std::string>& attrs) {
454
- return std::find (attrs.begin (), attrs.end (), " cppmm|manual" ) !=
458
+ bool has_copy_ctor_attr (const std::vector<std::string>& attrs) {
459
+ return std::find (attrs.begin (), attrs.end (), " cppmm|copy_constructor" ) !=
460
+ attrs.end ();
461
+ }
462
+
463
+ bool has_move_ctor_attr (const std::vector<std::string>& attrs) {
464
+ return std::find (attrs.begin (), attrs.end (), " cppmm|move_constructor" ) !=
455
465
attrs.end ();
456
466
}
457
467
468
+ bool has_manual_attr (const std::vector<std::string>& attrs) {
469
+ return std::find (attrs.begin (), attrs.end (), " cppmm|manual" ) != attrs.end ();
470
+ }
471
+
458
472
// / Create a new node for the given method decl and return it
459
473
NodePtr process_method_decl (const CXXMethodDecl* cmd,
460
474
std::vector<std::string> attrs,
@@ -1003,6 +1017,10 @@ bool has_opaquebytes_attr(const std::vector<std::string>& attrs) {
1003
1017
attrs.end ();
1004
1018
}
1005
1019
1020
+ bool has_impl_attr (const std::vector<std::string>& attrs) {
1021
+ return std::find (attrs.begin (), attrs.end (), " cppmm|impl" ) != attrs.end ();
1022
+ }
1023
+
1006
1024
bool is_public_copy_ctor (const Decl* cmd) {
1007
1025
if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
1008
1026
SPDLOG_DEBUG (" ctor {}" , cd->getQualifiedNameAsString ());
@@ -1016,6 +1034,24 @@ bool is_public_copy_ctor(const Decl* cmd) {
1016
1034
}
1017
1035
}
1018
1036
1037
+ bool is_inaccessible_copy_ctor (const Decl* cmd) {
1038
+ if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
1039
+ return cd->isCopyConstructor () && (cd->getAccess () != AS_public ||
1040
+ cd->isDeleted ());
1041
+ } else {
1042
+ return false ;
1043
+ }
1044
+ }
1045
+
1046
+ bool is_inaccessible_move_ctor (const Decl* cmd) {
1047
+ if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
1048
+ return cd->isMoveConstructor () && (cd->getAccess () != AS_public ||
1049
+ cd->isDeleted ());
1050
+ } else {
1051
+ return false ;
1052
+ }
1053
+ }
1054
+
1019
1055
bool is_public_move_ctor (const Decl* cmd) {
1020
1056
if (const CXXConstructorDecl* cd = dyn_cast<CXXConstructorDecl>(cmd)) {
1021
1057
SPDLOG_DEBUG (" ctor {}" , cd->getQualifiedNameAsString ());
@@ -1029,13 +1065,63 @@ bool is_public_move_ctor(const Decl* cmd) {
1029
1065
}
1030
1066
}
1031
1067
1068
+ bool has_forbidden_copy_ctor (const CXXRecordDecl* crd) {
1069
+ for (const Decl* d: crd->decls ()) {
1070
+ if (is_inaccessible_copy_ctor (d)) {
1071
+ return true ;
1072
+ }
1073
+ }
1074
+
1075
+
1076
+ for (const auto base : crd->bases ()) {
1077
+ if (const CXXRecordDecl* base_crd =
1078
+ base.getType ()->getAsCXXRecordDecl ()) {
1079
+ if (has_forbidden_copy_ctor (base_crd)) {
1080
+ return true ;
1081
+ }
1082
+ }
1083
+ }
1084
+
1085
+ return false ;
1086
+ }
1087
+
1088
+ bool has_forbidden_move_ctor (const CXXRecordDecl* crd) {
1089
+ for (const Decl* d: crd->decls ()) {
1090
+ if (is_inaccessible_move_ctor (d)) {
1091
+ return true ;
1092
+ }
1093
+ }
1094
+
1095
+
1096
+ for (const auto base : crd->bases ()) {
1097
+ if (const CXXRecordDecl* base_crd =
1098
+ base.getType ()->getAsCXXRecordDecl ()) {
1099
+ if (has_forbidden_move_ctor (base_crd)) {
1100
+ return true ;
1101
+ }
1102
+ }
1103
+ }
1104
+
1105
+ return false ;
1106
+ }
1107
+
1032
1108
void has_public_copy_move_ctor (const CXXRecordDecl* crd,
1033
1109
bool & has_public_copy_ctor,
1034
1110
bool & has_public_move_ctor) {
1035
- for (const Decl* d : crd->decls ()) {
1036
- has_public_copy_ctor |= is_public_copy_ctor (d);
1037
- has_public_move_ctor |= is_public_move_ctor (d);
1038
- }
1111
+ // for (const Decl* d : crd->decls()) {
1112
+ // // has_public_copy_ctor |= is_public_copy_ctor(d);
1113
+ // // has_public_move_ctor |= is_public_move_ctor(d);
1114
+ // has_public_copy_ctor |= is_inaccessible_copy_ctor(d);
1115
+ // has_public_move_ctor |= is_inaccessible_move_ctor(d);
1116
+ // }
1117
+ // has_public_copy_ctor = !has_public_copy_ctor;
1118
+ // has_public_move_ctor = !has_public_move_ctor;
1119
+
1120
+ // has_public_copy_ctor = crd->hasTrivialCopyConstructor() || crd->hasNonTrivialCopyConstructor();
1121
+ has_public_move_ctor = (crd->hasTrivialMoveConstructor () || crd->hasNonTrivialMoveConstructor ()) && !has_forbidden_move_ctor (crd);
1122
+
1123
+ has_public_copy_ctor = !has_forbidden_copy_ctor (crd);
1124
+ // has_public_move_ctor = !has_forbidden_move_ctor(crd);
1039
1125
}
1040
1126
1041
1127
std::vector<std::string> get_properties (const std::vector<std::string>& attrs) {
@@ -1192,10 +1278,13 @@ void process_concrete_record(const CXXRecordDecl* crd, std::string filename,
1192
1278
for (NodePtr& method : binding_methods) {
1193
1279
NodeMethod* mptr = (NodeMethod*)method.get ();
1194
1280
if (has_manual_attr (mptr->attrs )) {
1195
- mptr->in_binding = true ;
1281
+ mptr->in_binding = true ;
1196
1282
mptr->is_noexcept |= has_noexcept_attr (mptr->attrs );
1197
1283
function_map[mptr->_function_id ] = mptr;
1198
1284
1285
+ mptr->is_copy_constructor = has_copy_ctor_attr (mptr->attrs );
1286
+ mptr->is_move_constructor = has_move_ctor_attr (mptr->attrs );
1287
+
1199
1288
NodeId id = NODES.size ();
1200
1289
NODE_MAP[method->qualified_name ] = id;
1201
1290
NODES.emplace_back (std::move (method));
@@ -1213,16 +1302,16 @@ void process_concrete_record(const CXXRecordDecl* crd, std::string filename,
1213
1302
record_name, node_tu->qualified_name , *m);
1214
1303
}
1215
1304
}
1305
+ }
1216
1306
1217
- for (const auto & n : binding_methods) {
1218
- const auto * m = (NodeMethod*)n.get ();
1219
- if (m && m->is_user_provided && !m->in_library &&
1220
- !m->is_deleted && !has_manual_attr (m->attrs )) {
1221
- SPDLOG_WARN (" [{}]({}) - \n "
1222
- " {} is declared in the binding but not present "
1223
- " in the library" ,
1224
- record_name, node_tu->qualified_name , *m);
1225
- }
1307
+ for (const auto & n : binding_methods) {
1308
+ const auto * m = (NodeMethod*)n.get ();
1309
+ if (m && m->is_user_provided && !m->in_library && !m->is_deleted &&
1310
+ !has_manual_attr (m->attrs )) {
1311
+ SPDLOG_WARN (" [{}]({}) - \n "
1312
+ " {} is declared in the binding but not present "
1313
+ " in the library" ,
1314
+ record_name, node_tu->qualified_name , *m);
1226
1315
}
1227
1316
}
1228
1317
@@ -1285,7 +1374,14 @@ void process_concrete_record(const CXXRecordDecl* crd, std::string filename,
1285
1374
void handle_cxx_record_decl (const CXXRecordDecl* crd) {
1286
1375
ASTContext& ctx = crd->getASTContext ();
1287
1376
SourceManager& sm = ctx.getSourceManager ();
1288
- const auto & loc = crd->getLocation ();
1377
+ auto loc = crd->getLocation ();
1378
+
1379
+ // we don't care about locations in macros, we always want their expansions
1380
+ // if we're using macros to generate functions
1381
+ if (loc.isMacroID ()) {
1382
+ auto range = sm.getExpansionRange (loc);
1383
+ loc = range.getBegin ();
1384
+ }
1289
1385
1290
1386
const auto mng_ctx = ctx.createMangleContext ();
1291
1387
@@ -1415,7 +1511,13 @@ void handle_binding_function(const FunctionDecl* fd) {
1415
1511
1416
1512
ASTContext& ctx = fd->getASTContext ();
1417
1513
SourceManager& sm = ctx.getSourceManager ();
1418
- const auto & loc = fd->getLocation ();
1514
+ auto loc = fd->getLocation ();
1515
+ // we don't care about locations in macros, we always want their expansions
1516
+ // if we're using macros to generate functions
1517
+ if (loc.isMacroID ()) {
1518
+ auto range = sm.getExpansionRange (loc);
1519
+ loc = range.getBegin ();
1520
+ }
1419
1521
std::string filename = sm.getFilename (loc).str ();
1420
1522
1421
1523
// Get the translation unit node we're going to add this Function to
@@ -1428,6 +1530,29 @@ void handle_binding_function(const FunctionDecl* fd) {
1428
1530
process_function_parameters (fd, return_qtype, params);
1429
1531
auto exceptions = get_exceptions (attrs);
1430
1532
1533
+ // If we've marked the function as being an implementation with CPPMM_IMPL,
1534
+ // and it has a valid function body, grab the entire function definition,
1535
+ // base64-encode it and bung it into NodeFunction, then add the node to the
1536
+ // translation unit. It will then be picked up in asttoc, and the function
1537
+ // body spat out as an inline function that asttoc will wrap.
1538
+ std::string body;
1539
+ if (has_impl_attr (attrs)) {
1540
+ if (fd->isThisDeclarationADefinition ()) {
1541
+ std::string s;
1542
+ llvm::raw_string_ostream sos (s);
1543
+ fd->print (sos);
1544
+
1545
+ auto function_spelling = s;
1546
+ auto remove_macro = ps::replace (function_spelling, " __attribute__((annotate(\" cppmm|impl\" )))" , " " );
1547
+ auto rename_function = ps::replace (remove_macro, function_short_name + " (" , function_short_name + " _impl(" );
1548
+ body = base64::base64_encode (rename_function);
1549
+
1550
+ } else {
1551
+ SPDLOG_ERROR (" Function {} marked as impl but could not get body" ,
1552
+ fd->getQualifiedNameAsString ());
1553
+ }
1554
+ }
1555
+
1431
1556
const std::vector<NodeId> namespaces =
1432
1557
get_namespaces (fd->getParent (), node_tu);
1433
1558
@@ -1437,12 +1562,35 @@ void handle_binding_function(const FunctionDecl* fd) {
1437
1562
function_short_name, return_qtype, std::move (params),
1438
1563
std::move (namespaces), get_comment_base64 (fd), std::move (exceptions));
1439
1564
1440
- SPDLOG_DEBUG ( " Adding binding function {} " , node_function) ;
1565
+ node_function. definition = body ;
1441
1566
1442
- if (it != binding_functions.end ()) {
1443
- it->second .emplace_back (std::move (node_function));
1567
+ if (body.empty ()) {
1568
+ if (it != binding_functions.end ()) {
1569
+ it->second .emplace_back (std::move (node_function));
1570
+ } else {
1571
+ binding_functions[function_qual_name] = {node_function};
1572
+ }
1444
1573
} else {
1445
- binding_functions[function_qual_name] = {node_function};
1574
+ // Rename our function to _impl and give the original name to the C
1575
+ // function as an alias
1576
+ node_function.attrs .push_back (" cppmm|rename|" + node_function.short_name );
1577
+ node_function.short_name = node_function.short_name + " _impl" ;
1578
+ node_function.qualified_name = node_function.qualified_name + " _impl" ;
1579
+
1580
+ auto fnptr =
1581
+ std::make_unique<NodeFunction>(std::move (node_function));
1582
+ NodeId id = NODES.size ();
1583
+ fnptr->id = id;
1584
+ // add the function to its TU
1585
+ auto * node_tu =
1586
+ (NodeTranslationUnit*)NODES.at (node_function.context ).get ();
1587
+ // process the namespaces again to make sure we've got the
1588
+ // namespaces in the TU
1589
+ const std::vector<NodeId> namespaces =
1590
+ get_namespaces (fd->getParent (), node_tu);
1591
+ fnptr->context = node_tu->id ;
1592
+ node_tu->children .push_back (id);
1593
+ NODES.emplace_back (std::move (fnptr));
1446
1594
}
1447
1595
}
1448
1596
0 commit comments