Package pygccxml :: Package declarations :: Module type_traits |

# Source Code for Module pygccxml.declarations.type_traits

       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 few algorithms, that deals with different properties of C++ types
       8
       9  Do you aware of boost::type_traits library? pygccxml has functionality similar to
      10  it. Using functions defined in this module you can
      11      - find out some properties of the type
      12      - modify type
      13
      14  Those functions are very valuable for code generation. Almost all functions
      15  within this module works on L{type_t} class hierarchy and\\or L{class_t}.
      16  """
      17
      18  import os
      19  import types
      20  import matchers
      21  import typedef
      22  import calldef
      23  import cpptypes
      24  import variable
      25  import algorithm
      26  import namespace
      27  import templates
      28  import enumeration
      29  import class_declaration
      30  from pygccxml import utils
      31  import types as build_in_types
      32
      33 -def __remove_alias(type_):
      34      """implementation details"""
      35      if isinstance( type_, typedef.typedef_t ):
      36          return __remove_alias( type_.type )
      37      if isinstance( type_, cpptypes.declarated_t ) and isinstance( type_.declaration, typedef.typedef_t ):
      38          return __remove_alias( type_.declaration.type )
      39      if isinstance( type_, cpptypes.compound_t ):
      40          type_.base = __remove_alias( type_.base )
      41          return type_
      42      return type_
      43
      44 -def remove_alias(type_):
      45      """returns type without typedefs"""
      46      type_ref = None
      47      if isinstance( type_, cpptypes.type_t ):
      48          type_ref = type_
      49      elif isinstance( type_, typedef.typedef_t ):
      50          type_ref = type_.type
      51      else:
      52          pass #not a valid input, just return it
      53      if not type_ref:
      54          return type_
      55      if type_ref.cache.remove_alias:
      56          return type_ref.cache.remove_alias
      57      no_alias = __remove_alias( type_ref.clone() )
      58      type_ref.cache.remove_alias = no_alias
      59      return no_alias
      60
      61 -def create_cv_types( base ):
      62      """implementation details"""
      63      return [ base
      64               , cpptypes.const_t( base )
      65               , cpptypes.volatile_t( base )
      66               , cpptypes.volatile_t( cpptypes.const_t( base ) ) ]
      67
      68 -def decompose_type(tp):
      69      """implementation details"""
      70      #implementation of this function is important
      71      if isinstance( tp, cpptypes.compound_t ):
      72          return [tp] + decompose_type( tp.base )
      73      elif isinstance( tp, typedef.typedef_t ):
      74          return decompose_type( tp.type )
      75      elif isinstance( tp, cpptypes.declarated_t ) and isinstance( tp.declaration, typedef.typedef_t ):
      76          return decompose_type( tp.declaration.type )
      77      else:
      78          return [tp]
      79
      80 -def decompose_class(type):
      81      """implementation details"""
      82      types = decompose_type( type )
      83      return [ tp.__class__ for tp in types ]
      84
      85 -def base_type(type):
      86      """returns base type.
      87
      88      For C{const int} will return C{int}
      89      """
      90      types = decompose_type( type )
      91      return types[-1]
      92
      93 -def does_match_definition(given, main, secondary ):
      94      """implementation details"""
      95      assert isinstance( secondary, build_in_types.TupleType )
      96      assert 2 == len( secondary ) #general solution could be provided
      97      types = decompose_type( given )
      98      if isinstance( types[0], main ):
      99          return True
     100      elif 2 <= len( types ) and \
     101         ( ( isinstance( types[0], main ) and isinstance( types[1], secondary ) ) \
     102           or ( isinstance( types[1], main ) and isinstance( types[0], secondary ) ) ):
     103          return True
     104      elif 3 <= len( types ):
     105          classes = set( [tp.__class__ for tp in types[:3]] )
     106          desired = set( [main] + list( secondary ) )
     107          return classes == desired
     108      else:
     109          return False
     110
     111 -def is_bool( type_ ):
     112      """returns True, if type represents C{bool}, False otherwise"""
     113      return remove_alias( type_ ) in create_cv_types( cpptypes.bool_t() )
     114
     115 -def is_void( type ):
     116      """returns True, if type represents C{void}, False otherwise"""
     117      return remove_alias( type ) in create_cv_types( cpptypes.void_t() )
     118
     119 -def is_void_pointer( type ):
     120      """returns True, if type represents C{void*}, False otherwise"""
     121      return is_same( type, cpptypes.pointer_t( cpptypes.void_t() ) )
     122
     123 -def is_integral( type ):
     124      """returns True, if type represents C++ integral type, False otherwise"""
     125      integral_def = create_cv_types( cpptypes.char_t() )                    \
     126                     + create_cv_types( cpptypes.unsigned_char_t() )         \
     127                     + create_cv_types( cpptypes.signed_char_t() )           \
     128                     + create_cv_types( cpptypes.wchar_t() )                 \
     129                     + create_cv_types( cpptypes.short_int_t() )             \
     130                     + create_cv_types( cpptypes.short_unsigned_int_t() )    \
     131                     + create_cv_types( cpptypes.bool_t() )                  \
     132                     + create_cv_types( cpptypes.int_t() )                   \
     133                     + create_cv_types( cpptypes.unsigned_int_t() )          \
     134                     + create_cv_types( cpptypes.long_int_t() )              \
     135                     + create_cv_types( cpptypes.long_unsigned_int_t() )     \
     136                     + create_cv_types( cpptypes.long_long_int_t() )         \
     137                     + create_cv_types( cpptypes.long_long_unsigned_int_t() )
     138
     139      return remove_alias( type ) in integral_def
     140
     141 -def is_floating_point( type ):
     142      """returns True, if type represents C++ floating point type, False otherwise"""
     143      float_def = create_cv_types( cpptypes.float_t() )                   \
     144                  + create_cv_types( cpptypes.double_t() )                \
     145                  + create_cv_types( cpptypes.long_double_t() )
     146
     147      return remove_alias( type ) in float_def
     148
     149 -def is_arithmetic( type ):
     150      """returns True, if type represents C++ integral or floating point type, False otherwise"""
     151      return is_integral( type ) or is_floating_point( type )
     152
     153 -def is_pointer(type):
     154      """returns True, if type represents C++ pointer type, False otherwise"""
     155      return does_match_definition( type
     156                                    , cpptypes.pointer_t
     157                                    , (cpptypes.const_t, cpptypes.volatile_t) )
     158
     159 -def is_calldef_pointer(type):
     160      """returns True, if type represents pointer to free/member function, False otherwise"""
     161      if not is_pointer(type):
     162          return False
     163      nake_type = remove_alias( type )
     164      nake_type = remove_const( nake_type )
     165      nake_type = remove_volatile( nake_type )
     166      return isinstance( nake_type, cpptypes.compound_t ) \
     167             and isinstance( nake_type.base, cpptypes.calldef_type_t )
     168
     169 -def remove_pointer(type):
     170      """removes pointer from the type definition
     171
     172      If type is not pointer type, it will be returned as is.
     173      """
     174      nake_type = remove_alias( type )
     175      if not is_pointer( nake_type ):
     176          return type
     177      elif isinstance( nake_type, cpptypes.volatile_t ) and isinstance( nake_type.base, cpptypes.pointer_t ):
     178          return cpptypes.volatile_t( nake_type.base.base )
     179      elif isinstance( nake_type, cpptypes.const_t ) and isinstance( nake_type.base, cpptypes.pointer_t ):
     180          return cpptypes.const_t( nake_type.base.base )
     181      elif isinstance( nake_type.base, cpptypes.calldef_type_t ):
     182          return type
     183      else:
     184          return nake_type.base
     185
     186 -def is_reference(type):
     187      """returns True, if type represents C++ reference type, False otherwise"""
     188      nake_type = remove_alias( type )
     189      return isinstance( nake_type, cpptypes.reference_t )
     190
     191 -def is_array(type):
     192      """returns True, if type represents C++ array type, False otherwise"""
     193      nake_type = remove_alias( type )
     194      nake_type = remove_reference( nake_type )
     195      nake_type = remove_cv( nake_type )
     196      return isinstance( nake_type, cpptypes.array_t )
     197
     198 -def array_size(type):
     199      """returns array size"""
     200      nake_type = remove_alias( type )
     201      nake_type = remove_reference( nake_type )
     202      nake_type = remove_cv( nake_type )
     203      assert isinstance( nake_type, cpptypes.array_t )
     204      return nake_type.size
     205
     206 -def array_item_type(type_):
     207      """returns array item type"""
     208      if is_array(type_):
     209          type_ = remove_alias( type_ )
     210          type_ = remove_cv( type_ )
     211          return type_.base
     212      elif is_pointer( type_ ):
     213          return remove_pointer( type_ )
     214      else:
     215          assert 0
     216
     217 -def remove_reference(type):
     218      """removes reference from the type definition
     219
     220      If type is not reference type, it will be returned as is.
     221      """
     222      nake_type = remove_alias( type )
     223      if not is_reference( nake_type ):
     224          return type
     225      else:
     226          return nake_type.base
     227
     228 -def is_const(type):
     229      """returns True, if type represents C++ const type, False otherwise"""
     230      nake_type = remove_alias( type )
     231      return isinstance( nake_type, cpptypes.const_t )
     232
     233 -def remove_const(type):
     234      """removes const from the type definition
     235
     236      If type is not const type, it will be returned as is
     237      """
     238
     239      nake_type = remove_alias( type )
     240      if not is_const( nake_type ):
     241          return type
     242      else:
     243          return nake_type.base
     244
     245 -def remove_declarated( type ):
     246      """removes type-declaration class-binder L{declarated_t} from the type
     247
     248      If type is not L{declarated_t}, it will be returned as is
     249      """
     250      type = remove_alias( type )
     251      if isinstance( type, cpptypes.declarated_t ):
     252          type = type.declaration
     253      return type
     254
     255 -def is_same(type1, type2):
     256      """returns True, if type1 and type2 are same types"""
     257      nake_type1 = remove_declarated( type1 )
     258      nake_type2 = remove_declarated( type2 )
     259      return nake_type1 == nake_type2
     260
     261 -def is_volatile(type):
     262      """returns True, if type represents C++ volatile type, False otherwise"""
     263      nake_type = remove_alias( type )
     264      return isinstance( nake_type, cpptypes.volatile_t )
     265
     266 -def remove_volatile(type):
     267      """removes volatile from the type definition
     268
     269      If type is not volatile type, it will be returned as is
     270      """
     271      nake_type = remove_alias( type )
     272      if not is_volatile( nake_type ):
     273          return type
     274      else:
     275          return nake_type.base
     276
     277 -def remove_cv(type):
     278      """removes const and volatile from the type definition"""
     279
     280      nake_type = remove_alias(type)
     281      if not is_const( nake_type ) and not is_volatile( nake_type ):
     282          return type
     283      result = nake_type
     284      if is_const( nake_type ):
     285          result = nake_type.base
     286      if is_volatile( result ):
     287          result = result.base
     288      return result
     289
     290 -def is_fundamental(type):
     291      """returns True, if type represents C++ fundamental type"""
     292      return does_match_definition( type
     293                                    , cpptypes.fundamental_t
     294                                    , (cpptypes.const_t, cpptypes.volatile_t) )
     295
     296 -class declaration_xxx_traits:
     297      """this class implements the functionality needed for convinient work with
     298      declaration classes
     299
     300      Implemented functionality:
     301          - find out whether a declaration is a desired one
     302          - get reference to the declaration
     303      """
     304      sequence = [ remove_alias, remove_cv, remove_declarated ]
     305 -    def __init__( self, declaration_class ):
     306          self.declaration_class = declaration_class
     307
     308 -    def __apply_sequence( self, type ):
     309          for f in self.sequence:
     310              type = f( type )
     311          return type
     312
     313 -    def is_my_case( self, type ):
     314          """returns True, if type represents the desired declaration, False otherwise"""
     315          return isinstance( self.__apply_sequence( type ), self.declaration_class )
     316
     317 -    def get_declaration( self, type ):
     318          """returns reference to the declaration
     319
     320          Precondition: self.is_my_case( type ) == True
     321          """
     322          assert self.is_my_case( type )
     323          return self.__apply_sequence( type )
     324
     325  enum_traits = declaration_xxx_traits( enumeration.enumeration_t )
     326  """implements functionality, needed for convinient work with C++ enums"""
     327
     328  is_enum = enum_traits.is_my_case
     329  """returns True, if type represents C++ enumeration declaration, False otherwise"""
     330
     331  enum_declaration = enum_traits.get_declaration
     332  """returns reference to enum declaration"""
     333
     334  class_traits = declaration_xxx_traits( class_declaration.class_t )
     335  """implements functionality, needed for convinient work with C++ classes"""
     336
     337  is_class = class_traits.is_my_case
     338  """returns True, if type represents C++ class definition, False otherwise"""
     339
     340  class_declaration_traits = declaration_xxx_traits( class_declaration.class_declaration_t )
     341  """implements functionality, needed for convinient work with C++ class declarations"""
     342
     343  is_class_declaration = class_declaration_traits.is_my_case
     344  """returns True, if type represents C++ class declaration, False otherwise"""
     345
     346 -def find_trivial_constructor( type ):
     347      """returns reference to trivial constructor or None"""
     348      assert isinstance( type, class_declaration.class_t )
     349      return type.find_trivial_constructor()
     350
     351 -def has_trivial_constructor( class_ ):
     352      """if class has public trivial constructor, this function will return reference to it, None otherwise"""
     353      class_ = class_traits.get_declaration( class_ )
     354      trivial = class_.find_trivial_constructor()
     355      if trivial and trivial.access_type == 'public':
     356          return trivial
     357
     358 -def has_copy_constructor( class_ ):
     359      """if class has public copy constructor, this function will return reference to it, None otherwise"""
     360      class_ = class_traits.get_declaration( class_ )
     361      copy_constructor = class_.find_copy_constructor()
     362      if copy_constructor and copy_constructor.access_type == 'public':
     363          return copy_constructor
     364
     365 -def has_destructor(class_):
     366      """if class has destructor, this function will return reference to it, None otherwise"""
     367      class_ = class_traits.get_declaration( class_ )
     368      destructor = class_.decls( decl_type=calldef.destructor_t, recursive=False, allow_empty=True )
     369      if destructor:
     370          return destructor[0]
     371
     372 -def has_public_constructor(class_):
     373      """if class has any public constructor, this function will return list of them, otherwise None"""
     374      class_ = class_traits.get_declaration(class_)
     375      decls = class_.constructors( lambda c: not c.is_copy_constructor and c.access_type == 'public'
     376                                   , recursive=False, allow_empty=True )
     377      if decls:
     378          return decls
     379
     380 -def has_public_assign(class_):
     381      """returns True, if class has public assign operator, False otherwise"""
     382      class_ = class_traits.get_declaration( class_ )
     383      decls = class_.mem_opers( lambda o: o.symbol == '=' and o.access_type == 'public'
     384                                , recursive=False, allow_empty=True )
     385      return bool( decls )
     386
     387 -def has_public_destructor(type):
     388      """returns True, if class has public destructor, False otherwise"""
     389      d = has_destructor( type )
     390      return d and d.access_type == 'public'
     391
     392 -def is_base_and_derived( based, derived ):
     393      """returns True, if there is "base and derived" relationship between classes, False otherwise"""
     394      assert isinstance( based, class_declaration.class_t )
     395      assert isinstance( derived, ( class_declaration.class_t, tuple ) )
     396
     397      all_derived = None
     398      if isinstance( derived, class_declaration.class_t ):
     399          all_derived = ( [derived] )
     400      else: #tuple
     401          all_derived = derived
     402
     403      for derived_cls in all_derived:
     404          for base_desc in derived_cls.recursive_bases:
     405              if base_desc.related_class == based:
     406                  return True
     407      return False
     408
     409 -def has_any_non_copyconstructor( type):
     410      """if class has any public constructor, which is not copy constructor, this function will return list of them, otherwise None"""
     411      class_ = class_traits.get_declaration( type )
     412      decls = class_.constructors( lambda c: not c.is_copy_constructor and c.access_type == 'public'
     413                                   , recursive=False, allow_empty=True )
     414      if decls:
     415          return decls
     416
     417 -def has_public_binary_operator( type, operator_symbol ):
     418      """returns True, if type has public binary operator, otherwise False"""
     419      not_artificial = lambda decl: decl.is_artificial == False
     420      type = remove_alias( type )
     421      type = remove_cv( type )
     422      type = remove_declarated( type )
     423      assert isinstance( type, class_declaration.class_t )
     424
     425      if is_std_string( type ) or is_std_wstring( type ):
     426          #In some case compare operators of std::basic_string are not instantiated
     427          return True
     428
     429      operators = type.member_operators( function=matchers.custom_matcher_t( not_artificial ) \
     430                                                  & matchers.access_type_matcher_t( 'public' )
     431                                         , symbol=operator_symbol
     432                                         , allow_empty=True
     433                                         , recursive=False )
     434      if operators:
     435          return True
     436
     437      t = cpptypes.declarated_t( type )
     438      t = cpptypes.const_t( t )
     439      t = cpptypes.reference_t( t )
     440      operators = type.top_parent.operators( function=not_artificial
     441                                             , arg_types=[t, None]
     442                                             , symbol=operator_symbol
     443                                             , allow_empty=True
     444                                             , recursive=True )
     445      if operators:
     446          return True
     447      for bi in type.recursive_bases:
     448          assert isinstance( bi, class_declaration.hierarchy_info_t )
     449          if bi.access_type != class_declaration.ACCESS_TYPES.PUBLIC:
     450              continue
     451          operators = bi.related_class.member_operators( function=matchers.custom_matcher_t( not_artificial ) \
     452                                                               & matchers.access_type_matcher_t( 'public' )
     453                                                         , symbol=operator_symbol
     454                                                         , allow_empty=True
     455                                                         , recursive=False )
     456          if operators:
     457              return True
     458      return False
     459
     460 -def has_public_equal( type ):
     461      """returns True, if class has public operator==, otherwise False"""
     462      return has_public_binary_operator( type, '==' )
     463
     464 -def has_public_less( type ):
     465      """returns True, if class has public operator<, otherwise False"""
     466      return has_public_binary_operator( type, '<' )
     467
     468 -def is_unary_operator( oper ):
     469      """returns True, if operator is unary operator, otherwise False"""
     470      #~ definition:
     471          #~ memeber in class
     472            #~ ret-type operator symbol()
     473            #~ ret-type operator [++ --](int)
     474          #~ globally
     475            #~ ret-type operator symbol( arg )
     476            #~ ret-type operator [++ --](X&, int)
     477      symbols = [ '!', '&', '~', '*', '+', '++', '-', '--' ]
     478      if not isinstance( oper, calldef.operator_t ):
     479          return False
     480      if oper.symbol not in symbols:
     481          return False
     482      if isinstance( oper, calldef.member_operator_t ):
     483          if 0 == len( oper.arguments ):
     484              return True
     485          elif oper.symbol in [ '++', '--' ] and isinstance( oper.arguments[0].type, cpptypes.int_t ):
     486              return True
     487          else:
     488              return False
     489      else:
     490          if 1 == len( oper.arguments ):
     491              return True
     492          elif oper.symbol in [ '++', '--' ] \
     493               and 2 == len( oper.arguments ) \
     494               and isinstance( oper.arguments[1].type, cpptypes.int_t ):
     495              #may be I need to add additional check whether first argument is reference or not?
     496              return True
     497          else:
     498              return False
     499
     500 -def is_binary_operator( oper ):
     501      """returns True, if operator is binary operator, otherwise False"""
     502      #~ definition:
     503          #~ memeber in class
     504            #~ ret-type operator symbol(arg)
     505          #~ globally
     506            #~ ret-type operator symbol( arg1, arg2 )
     507      symbols = [ ',', '()', '[]', '!=', '%', '%=', '&', '&&', '&=', '*', '*=', '+', '+='
     508                  , '-', '-=', '->', '->*', '/', '/=', '<', '<<', '<<=', '<='
     509                  , '=', '==', '>', '>=', '>>', '>>=', '^', '^=', '|', '|=', '||'
     510      ]
     511      if not isinstance( oper, calldef.operator_t ):
     512          return False
     513      if oper.symbol not in symbols:
     514          return False
     515      if isinstance( oper, calldef.member_operator_t ):
     516          if 1 == len( oper.arguments ):
     517              return True
     518          else:
     519              return False
     520      else:
     521          if 2 == len( oper.arguments ):
     522              return True
     523          else:
     524              return False
     525
     526 -class __is_convertible_t:
     527      """implementation details"""
     528 -    def __init__( self, source, target ):
     529          self.__source = self.__normalize( source )
     530          self.__target = self.__normalize( target )
     531
     532 -    def __find_class_by_class_declaration( self, class_decl ):
     533          found = algorithm.find_declaration( class_decl.parent.declarations
     534                                              , name=class_decl.name
     535                                              , type=class_declaration.class_t )
     536          return found
     537
     538 -    def __normalize( self, type_ ):
     539          type_ = remove_alias( type_ )
     540          bt_of_type = base_type( type_ )
     541          if isinstance( bt_of_type, cpptypes.declarated_t ) \
     542             and isinstance( bt_of_type.declaration, class_declaration.class_declaration_t ):
     543              type_ = type_.clone()
     544              bt_of_type = base_type( type_ )
     545              bt_of_type.declaration = self.__find_class_by_class_declaration( bt_of_type.declaration )
     546          return type_
     547
     548 -    def __test_trivial( self, source, target ):
     549          if not ( source and target ):
     550              return False
     551          if is_same( source, target ):
     552              return True #X => X
     553          if is_const( target ) and is_same( source, target.base ):
     554              return True #X => const X
     555          if is_reference( target ) and is_same( source, target.base ):
     556              return True #X => X&
     557          if is_reference( target ) and is_const( target.base ) and is_same( source, target.base.base ):
     558              return True #X => const X&
     559          if is_same( target, cpptypes.pointer_t( cpptypes.void_t() ) ):
     560              if is_integral( source ) or is_enum( source ):
     561                  return False
     562              else:
     563                  return True #X => void*
     564          if is_pointer( source ) and is_pointer( target ):
     565              if is_const( target.base ) and is_same( source.base, target.base.base ):
     566                  return True#X* => const X*
     567          if is_reference( source ) and is_reference( target ):
     568              if is_const( target.base ) and is_same( source.base, target.base.base ):
     569                  return True#X& => const X&
     570          if not is_const( source ) and is_array( source ) and is_pointer( target ):
     571              if is_same( base_type(source), target.base ):
     572                  return True#X[2] => X*
     573          if is_array( source ) and is_pointer( target ) and is_const( target.base ):
     574              if is_same( base_type(source), target.base.base ):
     575                  return True
     576
     577 -    def __test_pointer_to_func_or_mv__to__func_or_mv( self, source, target ):
     578          if is_pointer( source ) \
     579             and is_reference( target ) \
     580             and isinstance( target.base
     581                             , ( cpptypes.free_function_type_t
     582                                 , cpptypes.member_function_type_t
     583                                 , cpptypes.member_variable_type_t ) ) \
     584             and is_same( source.base, target.base ):
     585                  return True
     586
     587          if is_pointer( source ) \
     588             and isinstance( target
     589                             , ( cpptypes.free_function_type_t
     590                                 , cpptypes.member_function_type_t
     591                                 , cpptypes.member_variable_type_t ) ) \
     592             and is_same( source.base, target ):
     593                  return True
     594
     595          if is_pointer( target ) \
     596             and is_reference( source ) \
     597             and isinstance( source.base
     598                             , ( cpptypes.free_function_type_t
     599                                 , cpptypes.member_function_type_t
     600                                 , cpptypes.member_variable_type_t ) ) \
     601             and is_same( source.base, target.base ):
     602                  return True
     603
     604          if is_pointer( target ) \
     605             and isinstance( source
     606                             , ( cpptypes.free_function_type_t
     607                                 , cpptypes.member_function_type_t
     608                                 , cpptypes.member_variable_type_t ) ) \
     609             and is_same( target.base, source ):
     610                  return True
     611
     612
     613 -    def __test_const_x_ref__to__x( self, source, target ):
     614          if not is_reference( source ) \
     615             or not is_const( source.base ) \
     616             or not is_same( source.base.base, target ):
     617              return False
     618          if is_fundamental( target ):
     619              return True
     620          if is_enum( target ):
     621              return True
     622          if isinstance( target, cpptypes.declarated_t ):
     623              assert isinstance( target.declaration, class_declaration.class_t )
     624              if has_copy_constructor( target.declaration ):
     625                  return True #we have copy constructor
     626          return False
     627
     628 -    def __test_const_ref_x__to__y(self, source, target):
     629          if not is_reference( source ) or not is_const( source.base ):
     630              return False
     631          if is_fundamental( source.base.base ) and is_fundamental( target ):
     632              return True
     633          if is_convertible( source.base.base, cpptypes.int_t() ) and is_enum( target ):
     634              return True
     635          if isinstance( target, cpptypes.declarated_t ):
     636              assert isinstance( target.declaration, class_declaration.class_t )
     637              if has_copy_constructor( target.declaration ):
     638                  return True #we have copy constructor
     639          return False
     640
     641 -    def __test_ref_x__to__x( self, source, target ):
     642          if not is_reference( source ) or not is_same( source.base, target ):
     643              return False
     644          if is_fundamental( target ):
     645              return True
     646          if is_enum( target ):
     647              return True
     648          if isinstance( target, cpptypes.declarated_t ):
     649              assert isinstance( target.declaration, class_declaration.class_t )
     650              if has_copy_constructor( target.declaration ):
     651                  return True #we have copy constructor
     652          return False
     653
     654 -    def __test_ref_x__to__y(self, source, target):
     655          if not is_reference( source ):
     656              return False
     657          if is_fundamental( source.base ) and is_fundamental( target ):
     658              return True
     659          if is_convertible( source.base, cpptypes.int_t() ) and is_enum( target ):
     660              return True
     661          if isinstance( target, cpptypes.declarated_t ):
     662              assert isinstance( target.declaration, class_declaration.class_t )
     663              if has_copy_constructor( target.declaration ):
     664                  return True #we have copy constructor
     665          return False
     666
     667 -    def __test_fundamental__to__fundamental(self, source, target):
     668          if not is_fundamental( base_type( source ) ) or not is_fundamental( base_type( target ) ):
     669              return False
     670          if is_void( base_type( source ) ) or is_void( base_type( target ) ):
     671              return False
     672          if is_fundamental( source ) and is_fundamental( target ):
     673              return True
     674          if not is_pointer( source ) and is_fundamental( target ):
     675              return True
     676          if not is_pointer( source ) and is_const( target ) and is_fundamental( target.base ):
     677              return True
     678          if is_fundamental( source ) \
     679             and is_reference( target ) \
     680             and is_const( target.base ) \
     681             and is_fundamental( target.base.base ):
     682              return True #X => const Y&
     683          return False
     684
     685 -    def __test_derived_to_based( self, source, target ):
     686          derived = base_type( source )
     687          base = base_type( target )
     688          if not ( isinstance( derived, cpptypes.declarated_t ) \
     689                   and isinstance( derived.declaration, class_declaration.class_t ) ):
     690              return False
     691          if not ( isinstance( base, cpptypes.declarated_t ) \
     692                   and isinstance( base.declaration, class_declaration.class_t ) ):
     693              return False
     694          base = base.declaration
     695          derived = derived.declaration
     696          if not is_base_and_derived( base, derived ):
     697              return False
     698          for b in derived.recursive_bases:
     699              if ( b.related_class is base ) and b.access_type != class_declaration.ACCESS_TYPES.PRIVATE:
     700                  break
     701          else:
     702              return False
     703
     704          base = target
     705          derived = source
     706          is_both_declarated = lambda x, y: isinstance( x, cpptypes.declarated_t ) \
     707                                            and isinstance( y, cpptypes.declarated_t )
     708          #d => b
     709          if is_both_declarated( base, derived ):
     710              return True
     711          #d* => b*
     712          if is_pointer( derived ) and is_pointer( base ) \
     713             and is_both_declarated( base.base, derived.base ):
     714              return True
     715          #const d* => const b*
     716          if is_pointer( derived ) and is_pointer( base ) \
     717             and is_const( derived.base ) and is_const( base.base ) \
     718             and is_both_declarated( base.base.base, derived.base.base ):
     719              return True
     720          #d* => const b*
     721          if is_pointer( derived ) and is_pointer( base ) \
     722             and is_const( derived.base )\
     723             and is_both_declarated( base.base.base, derived.base ):
     724              return True
     725
     726          #d& => b&
     727          if is_reference( derived ) and is_reference( base ) \
     728             and is_both_declarated( base.base, derived.base ):
     729              return True
     730          #const d& => const b&
     731          if is_reference( derived ) and is_reference( base ) \
     732             and is_const( derived.base ) and is_const( base.base ) \
     733             and is_both_declarated( base.base.base, derived.base.base ):
     734              return True
     735          #d& => const b&
     736          if is_reference( derived ) and is_reference( base ) \
     737             and is_const( derived.base )\
     738             and is_both_declarated( base.base.base, derived.base ):
     739              return True
     740          return False
     741
     742 -    def is_convertible( self ):
     743          source = self.__source
     744          target = self.__target
     745
     746          if self.__test_trivial(source, target):
     747              return True
     748          if is_array( source ) or is_array( target ):
     749              return False
     750          if self.__test_const_x_ref__to__x(source, target):
     751              return True
     752          if self.__test_const_ref_x__to__y(source, target):
     753              return True
     754          if self.__test_ref_x__to__x(source, target):
     755              return True
     756          if self.__test_ref_x__to__y(source, target):
     757              return True
     758          if self.__test_fundamental__to__fundamental( source, target ):
     759              return True
     760          if self.__test_pointer_to_func_or_mv__to__func_or_mv( source, target ):
     761              return True
     762          if self.__test_derived_to_based( source, target ):
     763              return True
     764
     765          if isinstance( source, cpptypes.declarated_t ):
     766              if isinstance( source.declaration, enumeration.enumeration_t ) \
     767                 and is_fundamental( target ) \
     768                 and not is_void( target ):
     769                  return True # enum could be converted to any integral type
     770
     771              if isinstance( source.declaration, class_declaration.class_t ):
     772                  source_inst = source.declaration
     773                  #class instance could be convertible to something else if it has operator
     774                  casting_operators = algorithm.find_all_declarations( source_inst.declarations
     775                                                                       , type=calldef.casting_operator_t
     776                                                                       , recursive=False )
     777                  if casting_operators:
     778                      for operator in casting_operators:
     779                          if is_convertible( operator.return_type, target ):
     780                              return True
     781
     782          #may be target is class too, so in this case we should check whether is
     783          #has constructor from source
     784          if isinstance( target, cpptypes.declarated_t ):
     785              if isinstance( target.declaration, class_declaration.class_t ):
     786                  constructors = algorithm.find_all_declarations( target.declaration.declarations
     787                                                                  , type=calldef.constructor_t
     788                                                                  , recursive=False )
     789                  if constructors:
     790                      for constructor in constructors:
     791                          if 1 != len( constructor.arguments ):
     792                              continue
     793                          #TODO: add test to check explicitness
     794                          if is_convertible( source, constructor.arguments[0].type ):
     795                              return True
     796
     797          return False
     798
     799 -def is_convertible( source, target ):
     800      """returns True, if source could be converted to target, otherwise False"""
     801      return __is_convertible_t( source, target ).is_convertible()
     802
     803 -def __is_noncopyable_single( class_):
     804      """implementation details"""
     805      #It is not enough to check base classes, we should also to check
     806      #member variables.
     807      logger = utils.loggers.cxx_parser
     808
     809      if has_copy_constructor( class_ ) \
     810         and has_public_constructor( class_ ) \
     811         and has_public_assign( class_ ) \
     812         and has_public_destructor( class_ ):
     813          msg = os.linesep.join([
     814              "__is_noncopyable_single - %s - COPYABLE:" % class_.decl_string
     815              , "    trivial copy constructor: yes"
     816              , "    public constructor: yes"
     817              , "    public assign: yes"
     818              , "    public destructor: yes"
     819          ])
     820          logger.debug( msg )
     821          return False
     822      if class_.find_noncopyable_vars():
     823          logger.debug( "__is_noncopyable_single(TRUE) - %s - contains noncopyable members" % class_.decl_string )
     824          return True
     825      else:
     826          logger.debug( "__is_noncopyable_single(FALSE) - %s - COPYABLE, because is doesn't contains noncopyable members" % class_.decl_string )
     827          return False
     828
     829 -def is_noncopyable( class_ ):
     830      """returns True, if class is noncopyable, False otherwise"""
     831      logger = utils.loggers.cxx_parser
     832      class_ = class_traits.get_declaration( class_ )
     833
     834      true_header = "is_noncopyable(TRUE) - %s - " % class_.decl_string
     835      false_header = "is_noncopyable(false) - %s - " % class_.decl_string
     836
     837      if class_.class_type == class_declaration.CLASS_TYPES.UNION:
     838          return False
     839
     840      if class_.is_abstract:
     841          logger.debug( true_header + "abstract client" )
     842          return True
     843
     844      #if class has public, user defined copy constructor, than this class is
     845      #copyable
     846      copy_ = class_.find_copy_constructor()
     847      if copy_ and copy_.access_type == 'public' and not copy_.is_artificial:
     848          return False
     849
     850      for base_desc in class_.recursive_bases:
     851          assert isinstance( base_desc, class_declaration.hierarchy_info_t )
     852          if base_desc.related_class.decl_string in ('::boost::noncopyable', '::boost::noncopyable_::noncopyable' ):
     853              logger.debug( true_header + "derives from boost::noncopyable" )
     854              return True
     855          if not has_copy_constructor( base_desc.related_class ):
     856              base_copy_ = base_desc.related_class.find_copy_constructor()
     857              if base_copy_:
     858                  if base_copy_.access_type == 'private':
     859                      logger.debug( true_header + "there is private copy constructor" )
     860                      return True
     861              else:
     862                  if __is_noncopyable_single( base_desc.related_class ):
     863                      logger.debug( true_header + "__is_noncopyable_single returned True" )
     864                      return True
     865          if __is_noncopyable_single( base_desc.related_class ):
     866              logger.debug( true_header + "__is_noncopyable_single returned True" )
     867              return True
     868
     869      if not has_copy_constructor( class_ ):
     870          logger.debug( true_header + "does not have trival copy constructor" )
     871          return True
     872      elif not has_public_constructor( class_ ):
     873          logger.debug( true_header + "does not have a public constructor" )
     874          return True
     875      elif has_destructor( class_ ) and not has_public_destructor( class_ ):
     876          logger.debug( true_header + "has private destructor")
     877          return True
     878      else:
     879          return __is_noncopyable_single( class_ )
     880
     881 -def is_defined_in_xxx( xxx, cls ):
     882      """small helper function, that checks whether class ( C{cls} ) is defined
     883      under C{::xxx} namespace"""
     884      if not cls.parent:
     885          return False
     886
     887      if not isinstance( cls.parent, namespace.namespace_t ):
     888          return False
     889
     890      if xxx != cls.parent.name:
     891          return False
     892
     893      xxx_ns = cls.parent
     894      if not xxx_ns.parent:
     895          return False
     896
     897      if not isinstance( xxx_ns.parent, namespace.namespace_t ):
     898          return False
     899
     900      if '::' != xxx_ns.parent.name:
     901          return False
     902
     903      global_ns = xxx_ns.parent
     904      return None is global_ns.parent
     905
     906 -class impl_details:
     907      """implementation details"""
     908      @staticmethod
     909 -    def is_defined_in_xxx( xxx, cls ):
     910          """implementation details"""
     911          if not cls.parent:
     912              return False
     913
     914          if not isinstance( cls.parent, namespace.namespace_t ):
     915              return False
     916
     917          if xxx != cls.parent.name:
     918              return False
     919
     920          xxx_ns = cls.parent
     921          if not xxx_ns.parent:
     922              return False
     923
     924          if not isinstance( xxx_ns.parent, namespace.namespace_t ):
     925              return False
     926
     927          if '::' != xxx_ns.parent.name:
     928              return False
     929
     930          global_ns = xxx_ns.parent
     931          return None is global_ns.parent
     932
     933      @staticmethod
     934 -    def find_value_type( global_ns, value_type_str ):
     935          """implementation details"""
     936          if not value_type_str.startswith( '::' ):
     937              value_type_str = '::' + value_type_str
     938          found = global_ns.decls( name=value_type_str
     939                                   , function=lambda decl: not isinstance( decl, calldef.calldef_t )
     940                                   ,  allow_empty=True )
     941          if not found:
     942              no_global_ns_value_type_str = value_type_str[2:]
     943              if cpptypes.FUNDAMENTAL_TYPES.has_key( no_global_ns_value_type_str ):
     944                  return cpptypes.FUNDAMENTAL_TYPES[ no_global_ns_value_type_str ]
     945              elif is_std_string( value_type_str ):
     946                  string_ = global_ns.typedef( '::std::string' )
     947                  return remove_declarated( string_ )
     948              elif is_std_wstring( value_type_str ):
     949                  string_ = global_ns.typedef( '::std::wstring' )
     950                  return remove_declarated( string_ )
     951              else:
     952                  value_type_str = no_global_ns_value_type_str
     953                  has_const = value_type_str.startswith( 'const ' )
     954                  if has_const:
     955                      value_type_str = value_type_str[ len('const '): ]
     956                  has_pointer = value_type_str.endswith( '*' )
     957                  if has_pointer:
     958                      value_type_str = value_type_str[:-1]
     959                  found = None
     960                  if has_const or has_pointer:
     961                      found = impl_details.find_value_type( global_ns, value_type_str )
     962                  if not found:
     963                      return None
     964                  else:
     965                      if isinstance( found, class_declaration.class_types ):
     966                          found = cpptypes.declarated_t( found )
     967                      if has_const:
     968                          found = cpptypes.const_t( found )
     969                      if has_pointer:
     970                          found = cpptypes.pointer_t( found )
     971                      return found
     972          if len( found ) == 1:
     973              return found[0]
     974          else:
     975              return None
     976
     977 -class smart_pointer_traits:
     978      """implements functionality, needed for convinient work with smart pointers"""
     979
     980      @staticmethod
     981 -    def is_smart_pointer( type ):
     982          """returns True, if type represents instantiation of C{boost::shared_ptr}, False otherwise"""
     983          type = remove_alias( type )
     984          type = remove_cv( type )
     985          type = remove_declarated( type )
     986          if not isinstance( type, ( class_declaration.class_declaration_t, class_declaration.class_t ) ):
     987              return False
     988          if not impl_details.is_defined_in_xxx( 'boost', type ):
     989              return False
     990          return type.decl_string.startswith( '::boost::shared_ptr<' )
     991
     992      @staticmethod
     993 -    def value_type( type ):
     994          """returns reference to boost::shared_ptr value type"""
     995          if not smart_pointer_traits.is_smart_pointer( type ):
     996              raise TypeError( 'Type "%s" is not instantiation of boost::shared_ptr' % type.decl_string )
     997          type = remove_alias( type )
     998          cls = remove_cv( type )
     999          cls = remove_declarated( type )
    1000          if isinstance( cls, class_declaration.class_t ):
    1001              return remove_declarated( cls.typedef( "value_type", recursive=False ).type )
    1002          elif not isinstance( cls, ( class_declaration.class_declaration_t, class_declaration.class_t ) ):
    1003              raise RuntimeError( "Unable to find out shared_ptr value type. shared_ptr class is: %s" % cls.decl_string )
    1004          else:
    1005              value_type_str = templates.args( cls.name )[0]
    1006              ref = impl_details.find_value_type( cls.top_parent, value_type_str )
    1007              if None is ref:
    1008                  raise RuntimeError( "Unable to find out shared_ptr value type. shared_ptr class is: %s" % cls.decl_string )
    1009              return ref
    1010
    1011 -class auto_ptr_traits:
    1012      """implements functionality, needed for convinient work with std::auto_ptr pointers"""
    1013
    1014      @staticmethod
    1015 -    def is_smart_pointer( type ):
    1016          """returns True, if type represents instantiation of C{boost::shared_ptr}, False otherwise"""
    1017          type = remove_alias( type )
    1018          type = remove_cv( type )
    1019          type = remove_declarated( type )
    1020          if not isinstance( type, ( class_declaration.class_declaration_t, class_declaration.class_t ) ):
    1021              return False
    1022          if not impl_details.is_defined_in_xxx( 'std', type ):
    1023              return False
    1024          return type.decl_string.startswith( '::std::auto_ptr<' )
    1025
    1026      @staticmethod
    1027 -    def value_type( type ):
    1028          """returns reference to boost::shared_ptr value type"""
    1029          if not auto_ptr_traits.is_smart_pointer( type ):
    1030              raise TypeError( 'Type "%s" is not instantiation of std::auto_ptr' % type.decl_string )
    1031          type = remove_alias( type )
    1032          cls = remove_cv( type )
    1033          cls = remove_declarated( type )
    1034          if isinstance( cls, class_declaration.class_t ):
    1035              return remove_declarated( cls.typedef( "element_type", recursive=False ).type )
    1036          elif not isinstance( cls, ( class_declaration.class_declaration_t, class_declaration.class_t ) ):
    1037              raise RuntimeError( "Unable to find out auto_ptr value type. auto_ptr class is: %s" % cls.decl_string )
    1038          else:
    1039              value_type_str = templates.args( cls.name )[0]
    1040              ref = impl_details.find_value_type( cls.top_parent, value_type_str )
    1041              if None is ref:
    1042                  raise RuntimeError( "Unable to find out auto_ptr value type. shared_ptr class is: %s" % cls.decl_string )
    1043              return ref
    1044
    1045
    1046 -def is_std_string( type ):
    1047      """returns True, if type represents C++ std::string, False otherwise"""
    1048      decl_strings = [
    1049          '::std::basic_string<char,std::char_traits<char>,std::allocator<char> >'
    1050          , '::std::basic_string<char, std::char_traits<char>, std::allocator<char> >'
    1051          , '::std::string' ]
    1052      if isinstance( type, types.StringTypes ):
    1053          return type in decl_strings
    1054      else:
    1055          type = remove_alias( type )
    1056          return remove_cv( type ).decl_string in decl_strings
    1057
    1058 -def is_std_wstring( type ):
    1059      """returns True, if type represents C++ std::wstring, False otherwise"""
    1060      decl_strings = [
    1061          '::std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >'
    1062          , '::std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >'
    1063          , '::std::wstring' ]
    1064      if isinstance( type, types.StringTypes ):
    1065          return type in decl_strings
    1066      else:
    1067          type = remove_alias( type )
    1068          return remove_cv( type ).decl_string in decl_strings
    1069
    1070 -def is_std_ostream( type ):
    1071      """returns True, if type represents C++ std::string, False otherwise"""
    1072      decl_strings = [
    1073          '::std::basic_ostream<char, std::char_traits<char> >'
    1074          , '::std::basic_ostream<char,std::char_traits<char> >'
    1075          , '::std::ostream' ]
    1076      if isinstance( type, types.StringTypes ):
    1077          return type in decl_strings
    1078      else:
    1079          type = remove_alias( type )
    1080          return remove_cv( type ).decl_string in decl_strings
    1081
    1082
    1083 -def is_std_wostream( type ):
    1084      """returns True, if type represents C++ std::string, False otherwise"""
    1085      decl_strings = [
    1086          '::std::basic_ostream<wchar_t, std::char_traits<wchar_t> >'
    1087          , '::std::basic_ostream<wchar_t,std::char_traits<wchar_t> >'
    1088          , '::std::wostream' ]
    1089      if isinstance( type, types.StringTypes ):
    1090          return type in decl_strings
    1091      else:
    1092          type = remove_alias( type )
    1093          return remove_cv( type ).decl_string in decl_strings
    1094