Package pygccxml :: Package declarations :: Module class_declaration

Source Code for Module pygccxml.declarations.class_declaration

  1  # Copyright 2004-2008 Roman Yakovenko. 
  2  # Distributed under the Boost Software License, Version 1.0. (See 
  3  # accompanying file LICENSE_1_0.txt or copy at 
  4  # http://www.boost.org/LICENSE_1_0.txt) 
  5   
  6  """ 
  7  defines classes, that describes C++ classes 
  8   
  9  This modules contains definition for next C++ declarations: 
 10      - class definition 
 11      - class declaration 
 12      - small helper class for describing C++ class hierarchy 
 13  """ 
 14   
 15  import scopedef 
 16  import itertools 
 17  import compilers 
 18  import algorithm 
 19  import declaration 
 20  import dependencies 
 21  from pygccxml import utils 
22 23 -class ACCESS_TYPES:
24 """class that defines "access" constants""" 25 PUBLIC = "public" 26 PRIVATE = "private" 27 PROTECTED = "protected" 28 ALL = [ PUBLIC, PRIVATE, PROTECTED ]
29
30 -class CLASS_TYPES:
31 """class that defines "class" type constants""" 32 CLASS = "class" 33 STRUCT = "struct" 34 UNION = "union" 35 ALL = [ CLASS, STRUCT, UNION ]
36
37 -def get_partial_name( name ):
38 import templates 39 import container_traits #prevent cyclic dependencies 40 ct = container_traits.find_container_traits( name ) 41 if ct: 42 return ct.remove_defaults( name ) 43 elif templates.is_instantiation( name ): 44 tmpl_name, args = templates.split( name ) 45 for i, arg_name in enumerate( args ): 46 args[i] = get_partial_name( arg_name.strip() ) 47 return templates.join( tmpl_name, args ) 48 else: 49 return name
50
51 52 -class hierarchy_info_t( object ):
53 """describes class relationship"""
54 - def __init__(self, related_class=None, access=None, is_virtual=False ):
55 """creates class that contains partial information about class relationship""" 56 if related_class: 57 assert( isinstance( related_class, class_t ) ) 58 self._related_class = related_class 59 if access: 60 assert( access in ACCESS_TYPES.ALL) 61 self._access=access 62 self._is_virtual = is_virtual
63
64 - def __eq__(self, other):
65 if not isinstance( other, hierarchy_info_t ): 66 return False 67 return algorithm.declaration_path( self.related_class ) == algorithm.declaration_path( other.related_class ) \ 68 and self.access == other.access \ 69 and self.is_virtual == other.is_virtual
70
71 - def __ne__( self, other):
72 return not self.__eq__( other )
73
74 - def __lt__(self, other):
75 if not isinstance( other, self.__class__ ): 76 return self.__class__.__name__ < other.__class__.__name__ 77 return ( algorithm.declaration_path( self.related_class ), self.access, self.is_virtual ) \ 78 < ( algorithm.declaration_path( other.related_class ), other.access, self.is_virtual )
79 86 related_class = property( _get_related_class, _set_related_class 87 , doc="reference to base or derived L{class<class_t>}") 88
89 - def _get_access(self):
90 return self._access
91 - def _set_access(self, new_access):
92 assert( new_access in ACCESS_TYPES.ALL ) 93 self._access = new_access
94 access = property( _get_access, _set_access ) 95 access_type = property( _get_access, _set_access 96 , doc="describes L{hierarchy type<ACCESS_TYPES>}") 97 98 #TODO: check whether GCC XML support this and if so parser this information
99 - def _get_is_virtual(self):
100 return self._is_virtual
101 - def _set_is_virtual(self, new_is_virtual):
102 self._is_virtual = new_is_virtual
103 is_virtual = property( _get_is_virtual, _set_is_virtual 104 , doc="indicates whether the inheritance is virtual or not")
105
106 107 -class class_declaration_t( declaration.declaration_t ):
108 """describes class declaration"""
109 - def __init__( self, name='' ):
110 """creates class that describes C++ class declaration( and not definition )""" 111 declaration.declaration_t.__init__( self, name ) 112 self._aliases = [] 113 self._container_traits = None 114 self._container_traits_set = False
115
116 - def _get__cmp__items(self):
117 """implementation details""" 118 return []
119
120 - def i_depend_on_them( self, recursive=True ):
121 return []
122
123 - def _get_aliases(self):
124 return self._aliases
125 - def _set_aliases( self, new_aliases ):
126 self._aliases = new_aliases
127 aliases = property( _get_aliases, _set_aliases 128 , doc="List of L{aliases<typedef_t>} to this instance") 129 130 @property
131 - def container_traits( self ):
132 """reference to L{container traits<container_traits.py>} or None""" 133 if self._container_traits_set == False: 134 import container_traits #prevent cyclic dependencies 135 self._container_traits_set = True 136 self._container_traits = container_traits.find_container_traits( self ) 137 return self._container_traits
138
139 - def _get_partial_name_impl( self ):
140 return get_partial_name( self.name )
141
142 -class class_t( scopedef.scopedef_t ):
143 """describes class definition""" 144 145 USE_DEMANGLED_AS_NAME = True
146 - def __init__( self, name='', class_type=CLASS_TYPES.CLASS, is_abstract=False ):
147 """creates class that describes C++ class definition""" 148 scopedef.scopedef_t.__init__( self, name ) 149 if class_type: 150 assert( class_type in CLASS_TYPES.ALL ) 151 self._class_type = class_type 152 self._bases = [] 153 self._derived = [] 154 self._is_abstract = is_abstract 155 self._public_members = [] 156 self._private_members = [] 157 self._protected_members = [] 158 self._aliases = [] 159 self._byte_size = 0 160 self._byte_align = 0 161 self._container_traits = None 162 self._container_traits_set = False 163 self._recursive_bases = None 164 self._recursive_derived = None
165
166 - def _get_name_impl( self ):
167 if not self._name: #class with empty name 168 return self._name 169 elif class_t.USE_DEMANGLED_AS_NAME and self.demangled and 'GCC' in self.compiler: 170 if not self.cache.demangled_name: 171 fname = algorithm.full_name( self.parent ) 172 if fname.startswith( '::' ) and not self.demangled.startswith( '::' ): 173 fname = fname[2:] 174 if self.demangled.startswith( fname ): 175 tmp = self.demangled[ len( fname ): ] #demangled::name 176 if tmp.startswith( '::' ): 177 tmp = tmp[2:] 178 if '<' not in tmp and '<' in self._name: 179 #we have template class, but for some reason demangled 180 #name doesn't contain any template 181 #This happens for std::string class, but this breaks 182 #other cases, because this behaviour is not consistent 183 self.cache.demangled_name = self._name 184 return self.cache.demangled_name 185 else: 186 self.cache.demangled_name = tmp 187 return tmp 188 else: 189 self.cache.demangled_name = self._name 190 return self._name 191 else: 192 return self.cache.demangled_name 193 else: 194 return self._name
195
196 - def __str__(self):
197 name = algorithm.full_name(self) 198 if name[:2]=="::": 199 name = name[2:] 200 return "%s [%s]"%(name, self.class_type)
201
202 - def _get__cmp__scope_items(self):
203 """implementation details""" 204 return [ self.class_type 205 , self._sorted_list( [ algorithm.declaration_path( base.related_class ) for base in self.bases ] ) 206 , self._sorted_list( [ algorithm.declaration_path( derive.related_class ) for derive in self.derived ] ) 207 , self.is_abstract 208 , self._sorted_list( self.public_members ) 209 , self._sorted_list( self.private_members ) 210 , self._sorted_list( self.protected_members ) ]
211
212 - def __eq__(self, other):
213 if not scopedef.scopedef_t.__eq__( self, other ): 214 return False 215 return self.class_type == other.class_type \ 216 and self._sorted_list( [ algorithm.declaration_path( base.related_class ) for base in self.bases ] ) \ 217 == other._sorted_list( [ algorithm.declaration_path( base.related_class ) for base in other.bases ] ) \ 218 and self._sorted_list( [ algorithm.declaration_path( derive.related_class ) for derive in self.derived ] ) \ 219 == other._sorted_list( [ algorithm.declaration_path( derive.related_class ) for derive in other.derived ] ) \ 220 and self.is_abstract == other.is_abstract \ 221 and self._sorted_list( self.public_members ) \ 222 == other._sorted_list( other.public_members ) \ 223 and self._sorted_list( self.private_members ) \ 224 == other._sorted_list( other.private_members ) \ 225 and self._sorted_list( self.protected_members ) \ 226 == self._sorted_list( other.protected_members )
227
228 - def _get_class_type(self):
229 return self._class_type
230 - def _set_class_type( self, new_class_type):
231 if new_class_type: 232 assert( new_class_type in CLASS_TYPES.ALL ) 233 self._class_type = new_class_type
234 class_type = property( _get_class_type, _set_class_type 235 , doc="describes class L{type<CLASS_TYPES>}") 236
237 - def _get_bases(self):
238 return self._bases
239 - def _set_bases( self, new_bases ):
240 self._bases = new_bases
241 bases = property( _get_bases, _set_bases 242 , doc="list of L{base classes<hierarchy_info_t>}") 243 244 @property
245 - def recursive_bases(self):
246 """list of all L{base classes<hierarchy_info_t>}""" 247 if self._recursive_bases is None: 248 to_go = self.bases[:] 249 all_bases = [] 250 while to_go: 251 base = to_go.pop() 252 if base not in all_bases: 253 all_bases.append( base ) 254 to_go.extend( base.related_class.bases ) 255 self._recursive_bases = all_bases 256 return self._recursive_bases
257
258 - def _get_derived(self):
259 return self._derived
260 - def _set_derived( self, new_derived ):
261 self._derived = new_derived
262 derived = property( _get_derived, _set_derived 263 , doc="list of L{derived classes<hierarchy_info_t>}") 264 265 @property
266 - def recursive_derived(self):
267 """list of all L{derive classes<hierarchy_info_t>}""" 268 if self._recursive_derived is None: 269 to_go = self.derived[:] 270 all_derived = [] 271 while to_go: 272 derive = to_go.pop() 273 if derive not in all_derived: 274 all_derived.append( derive ) 275 to_go.extend( derive.related_class.derived ) 276 self._recursive_derived = all_derived 277 return self._recursive_derived
278
279 - def _get_is_abstract(self):
280 if self.compiler == compilers.MSVC_PDB_9: 281 #prevent cyclic dependencies 282 import calldef 283 import function_traits 284 from matchers import virtuality_type_matcher_t as vtmatcher_t 285 filter_pv = vtmatcher_t( calldef.VIRTUALITY_TYPES.PURE_VIRTUAL ) 286 if self.calldefs( filter_pv, recursive=False, allow_empty=True ): 287 return True 288 filter_npv = vtmatcher_t( calldef.VIRTUALITY_TYPES.VIRTUAL ) \ 289 | vtmatcher_t( calldef.VIRTUALITY_TYPES.NOT_VIRTUAL ) 290 pv_calldefs = [] 291 npv_calldefs = [] 292 293 npv_calldefs.extend( self.calldefs( filter_npv, recursive=False, allow_empty=True ) ) 294 for base in self.recursive_bases: 295 cls = base.related_class 296 pv_calldefs.extend( cls.calldefs( filter_pv, recursive=False, allow_empty=True ) ) 297 npv_calldefs.extend( cls.calldefs( filter_npv, recursive=False, allow_empty=True ) ) 298 299 for pure_virtual in pv_calldefs: 300 impl_found = filter( lambda f: function_traits.is_same_function( pure_virtual, f ) 301 , npv_calldefs ) 302 if not impl_found: 303 return True 304 return False 305 else: 306 return self._is_abstract
307 - def _set_is_abstract( self, is_abstract ):
308 self._is_abstract = is_abstract
309 is_abstract = property( _get_is_abstract, _set_is_abstract 310 ,doc="describes whether class abstract or not" ) 311
312 - def _get_public_members(self):
313 return self._public_members
314 - def _set_public_members( self, new_public_members ):
315 self._public_members = new_public_members
316 public_members = property( _get_public_members, _set_public_members 317 , doc="list of all public L{members<declaration_t>}") 318
319 - def _get_private_members(self):
320 return self._private_members
321 - def _set_private_members( self, new_private_members ):
322 self._private_members = new_private_members
323 private_members = property( _get_private_members, _set_private_members 324 , doc="list of all private L{members<declaration_t>}") 325
326 - def _get_protected_members(self):
327 return self._protected_members
328 - def _set_protected_members( self, new_protected_members ):
329 self._protected_members = new_protected_members
330 protected_members = property( _get_protected_members, _set_protected_members 331 , doc="list of all protected L{members<declaration_t>}" ) 332
333 - def _get_aliases(self):
334 return self._aliases
335 - def _set_aliases( self, new_aliases ):
336 self._aliases = new_aliases
337 aliases = property( _get_aliases, _set_aliases 338 , doc="List of L{aliases<typedef_t>} to this instance") 339
340 - def _get_byte_size(self):
341 return self._byte_size
342 - def _set_byte_size( self, new_byte_size ):
343 self._byte_size = new_byte_size
344 byte_size = property( _get_byte_size, _set_byte_size 345 , doc="Size of this class in bytes @type: int") 346
347 - def _get_byte_align(self):
348 if self.compiler == compilers.MSVC_PDB_9: 349 compilers.on_missing_functionality( self.compiler, "byte align" ) 350 return self._byte_align
351 - def _set_byte_align( self, new_byte_align ):
352 self._byte_align = new_byte_align
353 byte_align = property( _get_byte_align, _set_byte_align 354 , doc="Alignment of this class in bytes @type: int") 355
356 - def _get_declarations_impl(self):
357 return self.get_members()
358
359 - def get_members( self, access=None):
360 """ 361 returns list of members according to access type 362 363 If access equals to None, then returned list will contain all members. 364 You should not modify the list content, otherwise different optimization 365 data will stop work and may to give you wrong results. 366 367 @param access: describes desired members 368 @type access: L{ACCESS_TYPES} 369 370 @return: [ members ] 371 """ 372 if access == ACCESS_TYPES.PUBLIC: 373 return self.public_members 374 elif access == ACCESS_TYPES.PROTECTED: 375 return self.protected_members 376 elif access == ACCESS_TYPES.PRIVATE: 377 return self.private_members 378 else: 379 all_members = [] 380 all_members.extend( self.public_members ) 381 all_members.extend( self.protected_members ) 382 all_members.extend( self.private_members ) 383 return all_members
384
385 - def adopt_declaration( self, decl, access ):
386 """adds new declaration to the class 387 388 @param decl: reference to a L{declaration<declaration_t>} 389 390 @param access: member access type 391 @type access: L{ACCESS_TYPES} 392 """ 393 if access == ACCESS_TYPES.PUBLIC: 394 self.public_members.append( decl ) 395 elif access == ACCESS_TYPES.PROTECTED: 396 self.protected_members.append( decl ) 397 elif access == ACCESS_TYPES.PRIVATE: 398 self.private_members.append( decl ) 399 else: 400 raise RuntimeError( "Invalid access type: %s." % access ) 401 decl.parent = self 402 decl.cache.reset() 403 decl.cache.access_type = access
404
405 - def remove_declaration( self, decl ):
406 """ 407 removes decl from members list 408 409 @param decl: declaration to be removed 410 @type decl: L{declaration_t} 411 """ 412 container = None 413 access_type = self.find_out_member_access_type( decl ) 414 if access_type == ACCESS_TYPES.PUBLIC: 415 container = self.public_members 416 elif access_type == ACCESS_TYPES.PROTECTED: 417 container = self.protected_members 418 else: #decl.cache.access_type == ACCESS_TYPES.PRVATE 419 container = self.private_members 420 del container[ container.index( decl ) ] 421 decl.cache.reset()
422
423 - def find_out_member_access_type( self, member ):
424 """ 425 returns member access type 426 427 @param member: member of the class 428 @type member: L{declaration_t} 429 430 @return: L{ACCESS_TYPES} 431 """ 432 assert member.parent is self 433 if not member.cache.access_type: 434 access_type = None 435 if member in self.public_members: 436 access_type = ACCESS_TYPES.PUBLIC 437 elif member in self.protected_members: 438 access_type = ACCESS_TYPES.PROTECTED 439 elif member in self.private_members: 440 access_type = ACCESS_TYPES.PRIVATE 441 else: 442 raise RuntimeError( "Unable to find member within internal members list." ) 443 member.cache.access_type = access_type 444 return access_type 445 else: 446 return member.cache.access_type
447
448 - def __find_out_member_dependencies( self, access_type ):
449 members = self.get_members( access_type ) 450 answer = [] 451 map( lambda mem: answer.extend( mem.i_depend_on_them(recursive=True) ), members ) 452 member_ids = set( map( lambda m: id( m ), members ) ) 453 for dependency in answer: 454 if id( dependency.declaration ) in member_ids: 455 dependency.access_type = access_type 456 return answer
457
458 - def i_depend_on_them( self, recursive=True ):
459 report_dependency = lambda *args: dependencies.dependency_info_t( self, *args ) 460 461 answer = [] 462 463 map( lambda base: answer.append( report_dependency( base.related_class, base.access_type, "base class" ) ) 464 , self.bases ) 465 466 if recursive: 467 map( lambda access_type: answer.extend( self.__find_out_member_dependencies( access_type ) ) 468 , ACCESS_TYPES.ALL ) 469 470 return answer
471 472 @property
473 - def container_traits( self ):
474 """reference to L{container traits<container_traits.py>} or None""" 475 if self._container_traits_set == False: 476 import container_traits #prevent cyclic dependencies 477 self._container_traits_set = True 478 self._container_traits = container_traits.find_container_traits( self ) 479 return self._container_traits
480
481 - def find_copy_constructor( self ):
482 copy_ = self.constructors( lambda x: x.is_copy_constructor, recursive=False, allow_empty=True ) 483 if copy_: 484 return copy_[0] 485 else: 486 return None
487
488 - def find_trivial_constructor( self ):
489 trivial = self.constructors( lambda x: x.is_trivial_constructor, recursive=False, allow_empty=True ) 490 if trivial: 491 return trivial[0] 492 else: 493 return None
494
495 - def _get_partial_name_impl( self ):
496 import type_traits #prevent cyclic dependencies 497 if type_traits.is_std_string( self ): 498 return 'string' 499 elif type_traits.is_std_wstring( self ): 500 return 'wstring' 501 else: 502 return get_partial_name( self.name )
503
504 - def find_noncopyable_vars( self ):
505 """returns list of all noncopyable variables""" 506 import type_traits as tt#prevent cyclic dependencies 507 logger = utils.loggers.cxx_parser 508 mvars = self.vars( lambda v: not v.type_qualifiers.has_static, recursive=False, allow_empty=True ) 509 noncopyable_vars = [] 510 for mvar in mvars: 511 type_ = tt.remove_reference( mvar.type ) 512 if tt.is_const( type_ ): 513 no_const = tt.remove_const( type_ ) 514 if tt.is_fundamental( no_const ) or tt.is_enum( no_const): 515 logger.debug( "__contains_noncopyable_mem_var - %s - TRUE - containes const member variable - fundamental or enum" % self.decl_string ) 516 noncopyable_vars.append( mvar ) 517 if tt.is_class( no_const ): 518 logger.debug( "__contains_noncopyable_mem_var - %s - TRUE - containes const member variable - class" % self.decl_string ) 519 noncopyable_vars.append( mvar ) 520 if tt.is_array( no_const ): 521 logger.debug( "__contains_noncopyable_mem_var - %s - TRUE - containes const member variable - array" % self.decl_string ) 522 noncopyable_vars.append( mvar ) 523 if tt.class_traits.is_my_case( type_ ): 524 cls = tt.class_traits.get_declaration( type_ ) 525 if tt.is_noncopyable( cls ): 526 logger.debug( "__contains_noncopyable_mem_var - %s - TRUE - containes member variable - class that is not copyable" % self.decl_string ) 527 noncopyable_vars.append( mvar ) 528 logger.debug( "__contains_noncopyable_mem_var - %s - false - doesn't contains noncopyable members" % self.decl_string ) 529 return noncopyable_vars
530 531 532 class_types = ( class_t, class_declaration_t ) 533