@@ -152,12 +152,18 @@ def find_copy_constructor(type_):
152
152
return None
153
153
154
154
155
- def find_noncopyable_vars (type_ ):
155
+ def find_noncopyable_vars (type_ , already_visited_cls_vars = None ):
156
156
"""
157
157
Returns list of all `noncopyable` variables.
158
158
159
+ If an already_visited_cls_vars list is provided as argument, the returned
160
+ list will not contain these variables. This list will be extended with
161
+ whatever variables pointing to classes have been found.
162
+
159
163
Args:
160
164
type_ (declarations.class_t): the class to be searched.
165
+ already_visited_cls_vars (list): optional list of vars that should not
166
+ be checked a second time, to prevent infinite recursions.
161
167
162
168
Returns:
163
169
list: list of all `noncopyable` variables.
@@ -172,6 +178,9 @@ def find_noncopyable_vars(type_):
172
178
allow_empty = True )
173
179
noncopyable_vars = []
174
180
181
+ if already_visited_cls_vars is None :
182
+ already_visited_cls_vars = []
183
+
175
184
message = (
176
185
"__contains_noncopyable_mem_var - %s - TRUE - " +
177
186
"contains const member variable" )
@@ -196,7 +205,13 @@ def find_noncopyable_vars(type_):
196
205
if class_traits .is_my_case (type_ ):
197
206
198
207
cls = class_traits .get_declaration (type_ )
199
- if is_noncopyable (cls ):
208
+
209
+ # Exclude classes that have already been visited.
210
+ if cls in already_visited_cls_vars :
211
+ continue
212
+ already_visited_cls_vars .append (cls )
213
+
214
+ if is_noncopyable (cls , already_visited_cls_vars ):
200
215
logger .debug ((message + " - class that is not copyable" )
201
216
% type_ .decl_string )
202
217
noncopyable_vars .append (mvar )
@@ -632,8 +647,20 @@ def is_convertible(source, target):
632
647
return __is_convertible_t (source , target ).is_convertible ()
633
648
634
649
635
- def __is_noncopyable_single (class_ ):
636
- """implementation details"""
650
+ def __is_noncopyable_single (class_ , already_visited_cls_vars = None ):
651
+ """
652
+ Implementation detail.
653
+
654
+ Checks if the class is non copyable, without considering the base classes.
655
+
656
+ Args:
657
+ class_ (declarations.class_t): the class to be checked
658
+ already_visited_cls_vars (list): optional list of vars that should not
659
+ be checked a second time, to prevent infinite recursions.
660
+
661
+ Returns:
662
+ bool: if the class is non copyable
663
+ """
637
664
# It is not enough to check base classes, we should also to check
638
665
# member variables.
639
666
logger = utils .loggers .cxx_parser
@@ -650,7 +677,11 @@ def __is_noncopyable_single(class_):
650
677
" public destructor: yes" ])
651
678
logger .debug (msg )
652
679
return False
653
- if find_noncopyable_vars (class_ ):
680
+
681
+ if already_visited_cls_vars is None :
682
+ already_visited_cls_vars = []
683
+
684
+ if find_noncopyable_vars (class_ , already_visited_cls_vars ):
654
685
logger .debug (
655
686
("__is_noncopyable_single(TRUE) - %s - contains noncopyable " +
656
687
"members" ) % class_ .decl_string )
@@ -662,9 +693,22 @@ def __is_noncopyable_single(class_):
662
693
return False
663
694
664
695
665
- def is_noncopyable (class_ ):
666
- """returns True, if class is noncopyable, False otherwise"""
696
+ def is_noncopyable (class_ , already_visited_cls_vars = None ):
697
+ """
698
+ Checks if class is non copyable
699
+
700
+ Args:
701
+ class_ (declarations.class_t): the class to be checked
702
+ already_visited_cls_vars (list): optional list of vars that should not
703
+ be checked a second time, to prevent infinite recursions.
704
+ In general you can ignore this argument, it is mainly used during
705
+ recursive calls of is_noncopyable() done by pygccxml.
706
+
707
+ Returns:
708
+ bool: if the class is non copyable
709
+ """
667
710
logger = utils .loggers .cxx_parser
711
+
668
712
class_decl = class_traits .get_declaration (class_ )
669
713
670
714
true_header = "is_noncopyable(TRUE) - %s - " % class_ .decl_string
@@ -683,6 +727,9 @@ def is_noncopyable(class_):
683
727
if copy_ and copy_ .access_type == 'public' and not copy_ .is_artificial :
684
728
return False
685
729
730
+ if already_visited_cls_vars is None :
731
+ already_visited_cls_vars = []
732
+
686
733
for base_desc in class_decl .recursive_bases :
687
734
assert isinstance (base_desc , class_declaration .hierarchy_info_t )
688
735
@@ -700,13 +747,15 @@ def is_noncopyable(class_):
700
747
true_header +
701
748
"there is private copy constructor" )
702
749
return True
703
- elif __is_noncopyable_single (base_desc .related_class ):
750
+ elif __is_noncopyable_single (
751
+ base_desc .related_class , already_visited_cls_vars ):
704
752
logger .debug (
705
753
true_header +
706
754
"__is_noncopyable_single returned True" )
707
755
return True
708
756
709
- if __is_noncopyable_single (base_desc .related_class ):
757
+ if __is_noncopyable_single (
758
+ base_desc .related_class , already_visited_cls_vars ):
710
759
logger .debug (
711
760
true_header +
712
761
"__is_noncopyable_single returned True" )
@@ -722,7 +771,7 @@ def is_noncopyable(class_):
722
771
logger .debug (true_header + "has private destructor" )
723
772
return True
724
773
else :
725
- return __is_noncopyable_single (class_decl )
774
+ return __is_noncopyable_single (class_decl , already_visited_cls_vars )
726
775
727
776
728
777
def is_unary_operator (oper ):
0 commit comments