Skip to content

Commit 5ebc002

Browse files
committed
Disable setter generation for field of types with a deleted or private assigment operator
1 parent 15dbf22 commit 5ebc002

File tree

5 files changed

+96
-7
lines changed

5 files changed

+96
-7
lines changed

src/CodeTree.cpp

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,41 @@ namespace codetree{
7878
//Replace all '::' occurences by '!':
7979
return std::regex_replace(cpp_name, std::regex("::"), "!");
8080
}
81+
82+
bool isAssignable(CXCursor type_def){
83+
if(verbose > 3) std::cerr << __FUNCTION__ << "(" << type_def << ")\n";
84+
85+
struct data_t {
86+
bool copy_assignment_deleted;
87+
bool copy_assignment_defined;
88+
bool move_assignment_deleted;
89+
} data = {false, false, false};
90+
91+
clang_visitChildren(type_def, [](CXCursor cursor, CXCursor, CXClientData data_){
92+
auto& data = *static_cast<data_t*>(data_);
93+
const auto& access = clang_getCXXAccessSpecifier(cursor);
94+
if(clang_CXXMethod_isCopyAssignmentOperator(cursor)){
95+
if(clang_CXXMethod_isDeleted(cursor) || access != CX_CXXPublic){
96+
data.copy_assignment_deleted = true;
97+
} else{
98+
data.copy_assignment_defined = true;
99+
}
100+
}
101+
102+
if(clang_CXXMethod_isMoveAssignmentOperator(cursor)
103+
&& (clang_CXXMethod_isDeleted(cursor) || access != CX_CXXPublic)){
104+
data.move_assignment_deleted = true;
105+
}
106+
return CXChildVisit_Continue;
107+
}, &data);
108+
109+
bool not_assignable = data.copy_assignment_deleted
110+
|| (data.move_assignment_deleted && !data.copy_assignment_defined) ;
111+
return !not_assignable;
112+
}
81113
}
82114

115+
83116
CXCursor
84117
CodeTree::getParentClassForWrapper(CXCursor cursor) const{
85118
if(verbose > 5) std::cerr << "Calling getParentClassForWrapper("
@@ -474,11 +507,13 @@ CodeTree::generate_cxx_for_type(std::ostream& o,
474507
if(accessor_gen != accessor_mode_t::none){
475508
//skip field with anomymous struct types:
476509
bool anonymous = false;
510+
bool assignable = true;
477511
CXType field_type = clang_getCursorType(f);
478512
if(field_type.kind != CXType_Invalid){
479513
auto def = clang_getTypeDeclaration(field_type);
480-
if(!clang_Cursor_isNull(def) && clang_Cursor_isAnonymous(def)){
481-
anonymous = true;
514+
if(!clang_Cursor_isNull(def)){
515+
anonymous = clang_Cursor_isAnonymous(def);
516+
assignable = isAssignable(def);
482517
}
483518
}
484519
if(anonymous){
@@ -487,7 +522,8 @@ CodeTree::generate_cxx_for_type(std::ostream& o,
487522
<< " because its type is anonymous.\n";
488523
}
489524
} else{
490-
generate_accessor_cxx(o, &t, f, accessor_gen == accessor_mode_t::getter, 2);
525+
bool getter_only = (accessor_gen == accessor_mode_t::getter || !assignable);
526+
generate_accessor_cxx(o, &t, f, getter_only, 2);
491527
}
492528
}
493529
}
@@ -925,9 +961,10 @@ void CodeTree::set_type_rcd_ctor_info(TypeRcd& rcd){
925961
bool explicit_def_ctor;
926962
bool implicit_def_ctor;
927963
bool public_dtor;
964+
int assignable;
928965
int n_def_ctor_decls;
929966
const CodeTree* tree;
930-
} data = {false, true, true, 0, this};
967+
} data = {false, true, true, true, 0, this};
931968

932969
clang_visitChildren(rcd.cursor, [](CXCursor cursor, CXCursor, CXClientData data_){
933970
auto& data = *static_cast<data_t*>(data_);
@@ -950,9 +987,10 @@ void CodeTree::set_type_rcd_ctor_info(TypeRcd& rcd){
950987
data.public_dtor = false;
951988
}
952989
}
990+
953991
return CXChildVisit_Continue;
954992
}, &data);
955-
993+
956994
bool finalize_vetoed = false;
957995
auto it = find(finalizers_to_veto_.begin(), finalizers_to_veto_.end(), rcd.type_name);
958996
if(it != finalizers_to_veto_.end()){
@@ -3174,3 +3212,5 @@ void CodeTree::set_mapped_types(const std::vector<std::string>& name_map){
31743212
}
31753213
}
31763214
}
3215+
3216+

src/libclang-ext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,4 @@ bool same_type(CXType t1, CXType t2){
267267
//Falling back to name comparison:
268268
return (fully_qualified_name(t1) == fully_qualified_name(t2));
269269
}
270+

test/TestVarField/A.cxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ int global_int = 1;
55
A global_A(10);
66
const A global_A_const(11);
77
C global_C(1);
8-
8+
NotAssignale global_NotAssignable;
9+
NotAssignale2 global_NotAssignable2;
10+
NoCopyCtor global_NoCopyCtor;
11+
PrivateCopyOp global_PrivateCopyOp;
12+
NoMoveAssignment global_NoMoveAssignment;
913

1014
namespace ns{
1115
int A::static_field = 2;

test/TestVarField/A.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@ struct B{
55
int field;
66
};
77

8+
struct NotAssignale {
9+
NotAssignale& operator=(const NotAssignale& a) = delete;
10+
};
11+
12+
struct NotAssignale2 {
13+
NotAssignale2& operator=(const NotAssignale2&& a) = delete;
14+
};
15+
16+
struct NoCopyCtor {
17+
NoCopyCtor() {}
18+
NoCopyCtor(const NoCopyCtor&) = delete;
19+
};
20+
21+
struct NoMoveAssignment {
22+
NoMoveAssignment& operator=(NoMoveAssignment&&) = delete;
23+
NoMoveAssignment& operator=(const NoMoveAssignment&) { return *this; };
24+
};
25+
26+
class PrivateCopyOp {
27+
PrivateCopyOp& operator=(const PrivateCopyOp& a){
28+
return *this;
29+
}
30+
};
31+
832

933
struct A {
1034
A(int x = 1): field_int(x), field_int_const(3), field_B(2*x){}
@@ -24,6 +48,12 @@ extern int global_int;
2448
extern A global_A;
2549
extern const A global_A_const;
2650
extern C global_C;
51+
extern NotAssignale global_NotAssignable;
52+
extern NotAssignale2 global_NotAssignable2;
53+
extern NoMoveAssignment global_NoMoveAssignment;
54+
extern NoCopyCtor global_NoCopyCtor;
55+
extern PrivateCopyOp global_PrivateCopyOp;
56+
2757

2858
namespace ns{
2959
struct A {

test/TestVarField/runTestVarFieldOn.jl

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,21 @@ function runtest()
1313
@test :C names(TestVarFieldOn, all=true)
1414
@test :global_C names(TestVarFieldOn, all=true)
1515
@test :global_C! names(TestVarFieldOn, all=true)
16-
16+
17+
@test :global_NoCopyCtor names(TestVarFieldOn, all=true)
18+
@test :global_NoCopyCtor! names(TestVarFieldOn, all=true)
19+
20+
@test :global_NotAssignable names(TestVarFieldOn, all=true)
21+
@test :global_NotAssignable! names(TestVarFieldOn, all=true)
22+
23+
@test :global_NotAssignable2 names(TestVarFieldOn, all=true)
24+
@test :global_NotAssignable2! names(TestVarFieldOn, all=true)
25+
26+
@test :global_PrivateCopyOp names(TestVarFieldOn, all=true)
27+
@test :global_PrivateCopyOp! names(TestVarFieldOn, all=true)
28+
29+
@test :global_NoMoveAssignment names(TestVarFieldOn, all=true)
30+
1731
a = TestVarFieldOn.A()
1832

1933
@test TestVarFieldOn.field_int(a) == 1

0 commit comments

Comments
 (0)