pygccxml.declarations.calldef

Package pygccxml :: Package declarations :: Module calldef |

# Source Code for Module pygccxml.declarations.calldef

      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 "callable" declarations
      8
      9  This modules contains definition for next C++ declarations:
     10      - operator
     11          - member
     12          - free
     13      - function
     14          - member
     15          - free
     16      - constructor
     17      - destructor
     18  """
     19
     20  import cpptypes
     21  import algorithm
     22  import declaration
     23  import type_traits
     24  import dependencies
     25  import call_invocation
     26
     27 -class VIRTUALITY_TYPES:
     28      """class that defines "virtuality" constants"""
     29      NOT_VIRTUAL = 'not virtual'
     30      VIRTUAL = 'virtual'
     31      PURE_VIRTUAL = 'pure virtual'
     32      ALL = [NOT_VIRTUAL, VIRTUAL, PURE_VIRTUAL]
     33  #preserving backward compatebility
     34  FUNCTION_VIRTUALITY_TYPES = VIRTUALITY_TYPES
     35
     36  #First level in hierarchy of calldef
     37 -class argument_t(object):
     38      """
     39      class, that describes argument of "callable" declaration
     40      """
     41
     42 -    def __init__( self, name='', type=None, default_value=None, attributes=None):
     43          object.__init__(self)
     44          self._name = name
     45          self._default_value = default_value
     46          self._type = type
     47          self._attributes = attributes
     48
     49 -    def clone( self, **keywd ):
     50          """constructs new argument_t instance
     51
     52          return argument_t( name=keywd.get( 'name', self.name )
     53                             , type=keywd.get( 'type', self.type )
     54                             , default_value=keywd.get( 'default_value', self.default_value )
     55                             , attributes=keywd.get( 'attributes', self.attributes ) )
     56
     57          """
     58          return argument_t( name=keywd.get( 'name', self.name )
     59                             , type=keywd.get( 'type', self.type )
     60                             , default_value=keywd.get( 'default_value', self.default_value )
     61                             , attributes=keywd.get( 'attributes', self.attributes ) )
     62
     63 -    def __str__(self):
     64          if self.ellipsis:
     65              return "..."
     66          else:
     67              if self.default_value==None:
     68                  return "%s %s"%(self.type, self.name)
     69              else:
     70                  return "%s %s=%s"%(self.type, self.name, self.default_value)
     71
     72 -    def __eq__(self, other):
     73          if not isinstance( other, self.__class__ ):
     74              return False
     75          return self.name == other.name \
     76                 and self.default_value == other.default_value \
     77                 and self.type == other.type
     78
     79 -    def __ne__( self, other):
     80          return not self.__eq__( other )
     81
     82 -    def __lt__(self, other):
     83          if not isinstance( other, self.__class__ ):
     84              return self.__class__.__name__ < other.__class__.__name__
     85          return self.name < other.name \
     86                 and self.default_value < other.default_value \
     87                 and self.type < other.type
     88
     89 -    def _get_name(self):
     90          return self._name
     91 -    def _set_name(self, name):
     92          self._name = name
     93      name = property( _get_name, _set_name
     94                       , doc="""Argument name.
     95                       @type: str""" )
     96
     97      @property
     98 -    def ellipsis(self):
     99          """bool, if True argument represents ellipsis ( "..." ) in function definition"""
    100          return isinstance( self.type, cpptypes.ellipsis_t )
    101
    102 -    def _get_default_value(self):
    103          return self._default_value
    104 -    def _set_default_value(self, default_value):
    105          self._default_value = default_value
    106      default_value = property( _get_default_value, _set_default_value
    107                                , doc="""Argument's default value or None.
    108                                @type: str""")
    109
    110 -    def _get_type(self):
    111          return self._type
    112 -    def _set_type(self, type):
    113          self._type = type
    114      type = property( _get_type, _set_type
    115                       , doc="""The type of the argument.
    116                       @type: L{type_t}""")
    117
    118 -    def _get_attributes( self ):
    119          return self._attributes
    120 -    def _set_attributes( self, attributes ):
    121          self._attributes = attributes
    122      attributes = property( _get_attributes, _set_attributes
    123                          , doc="""GCCXML attributes, set using __attribute__((gccxml("...")))
    124                          @type: str
    125                          """ )
    126
    127
    128 -class calldef_t( declaration.declaration_t ):
    129      """base class for all "callable" declarations"""
    130 -    def __init__( self, name='', arguments=None, exceptions=None, return_type=None, has_extern=False, does_throw=True ):
    131          declaration.declaration_t.__init__( self, name )
    132          if not arguments:
    133              arguments = []
    134          self._arguments = arguments
    135          if not exceptions:
    136              exceptions = []
    137          self._does_throw = does_throw
    138          self._exceptions = exceptions
    139          self._return_type = return_type
    140          self._has_extern = has_extern
    141          self._demangled_name = None
    142
    143 -    def _get__cmp__call_items(self):
    144          """implementation details"""
    145          raise NotImplementedError()
    146
    147 -    def _get__cmp__items( self ):
    148          """implementation details"""
    149          items = [ self.arguments
    150                    , self.return_type
    151                    , self.has_extern
    152                    , self.does_throw
    153                    , self._sorted_list( self.exceptions ) ]
    154          items.extend( self._get__cmp__call_items() )
    155          return items
    156
    157 -    def __eq__(self, other):
    158          if not declaration.declaration_t.__eq__( self, other ):
    159              return False
    160          return self.return_type == other.return_type \
    161                 and self.arguments == other.arguments \
    162                 and self.has_extern == other.has_extern \
    163                 and self.does_throw == other.does_throw \
    164                 and self._sorted_list( self.exceptions ) \
    165                     == other._sorted_list( other.exceptions )
    166
    167 -    def _get_arguments(self):
    168          return self._arguments
    169 -    def _set_arguments(self, arguments):
    170          self._arguments = arguments
    171      arguments = property( _get_arguments , _set_arguments
    172                            , doc="""The argument list.
    173                            @type: list of L{argument_t}""")
    174
    175      @property
    176 -    def has_ellipsis( self ):
    177          return self.arguments and self.arguments[-1].ellipsis
    178
    179      @property
    180 -    def argument_types( self ):
    181          """list of all argument types"""
    182          return [ arg.type for arg in self.arguments ]
    183
    184      @property
    185 -    def required_args(self):
    186          """list of all required arguments"""
    187          r_args = []
    188          for arg in self.arguments:
    189              if not arg.default_value:
    190                  r_args.append( arg )
    191              else:
    192                  break
    193          return r_args
    194
    195      @property
    196 -    def optional_args(self):
    197          """list of all optional arguments, the arguments that have default value"""
    198          return self.arguments[ len( self.required_args ) : ]
    199
    200 -    def _get_does_throw(self):
    201          return self._does_throw
    202 -    def _set_does_throw(self, does_throw):
    203          self._does_throw = does_throw
    204      does_throw = property( _get_does_throw, _set_does_throw,
    205                             doc="""If False, than function does not throw any exception.
    206                             In this case, function was declared with empty throw
    207                             statement.
    208                             """)
    209
    210 -    def _get_exceptions(self):
    211          return self._exceptions
    212 -    def _set_exceptions(self, exceptions):
    213          self._exceptions = exceptions
    214      exceptions = property( _get_exceptions, _set_exceptions
    215                             , doc="""The list of exceptions.
    216                             @type: list of L{declaration_t}""")
    217
    218 -    def _get_return_type(self):
    219          return self._return_type
    220 -    def _set_return_type(self, return_type):
    221          self._return_type = return_type
    222      return_type = property( _get_return_type, _set_return_type
    223                              , doc='''The type of the return value of the "callable" or None (constructors).
    224                              @type: L{type_t}
    225                              ''')
    226      @property
    227 -    def overloads(self):
    228          """A list of overloaded "callables" (i.e. other callables with the same name within the same scope.
    229
    230          @type: list of L{calldef_t}
    231          """
    232          if not self.parent:
    233              return []
    234          # finding all functions with the same name
    235          return self.parent.calldefs( name=self.name
    236                                       , function=lambda decl: not (decl is self )
    237                                       , allow_empty=True
    238                                       , recursive=False )
    239
    240 -    def _get_has_extern(self):
    241          return self._has_extern
    242 -    def _set_has_extern(self, has_extern):
    243          self._has_extern = has_extern
    244      has_extern = property( _get_has_extern, _set_has_extern,
    245                             doc="""Was this callable declared as "extern"?
    246                             @type: bool
    247                             """)
    248
    249 -    def __remove_parent_fname( self, demangled ):
    250          """implementation details"""
    251          demangled = demangled.strip()
    252          parent_fname = algorithm.full_name( self.parent )
    253          if parent_fname.startswith( '::' ) and not demangled.startswith( '::' ):
    254              parent_fname = parent_fname[2:]
    255          demangled = demangled[ len( parent_fname ): ]
    256          return demangled
    257
    258 -    def _get_demangled_name( self ):
    259          if not self.demangled:
    260              self._demangled_name = ''
    261
    262          if self._demangled_name:
    263              return self._demangled_name
    264
    265          if self._demangled_name == '':
    266              return self.name
    267
    268          demangled = self.demangled
    269          if self.return_type:
    270              return_type = type_traits.remove_alias( self.return_type ).decl_string
    271
    272              if return_type.startswith( '::' ) and not self.demangled.startswith( '::' ):
    273                  return_type = return_type[2:]
    274              demangled = self.demangled
    275              if demangled.startswith( return_type ):
    276                  demangled = demangled[ len( return_type ): ]
    277                  demangled = demangled.strip()
    278          #removing scope
    279          demangled_name = call_invocation.name( self.__remove_parent_fname( demangled ) )
    280          if demangled_name.startswith( '::' ):
    281              demangled_name = demangled_name[2:]
    282          #to be on the safe side
    283          if demangled_name.startswith( self.name ):
    284              self._demangled_name = demangled_name
    285              return self._demangled_name
    286
    287          #well, I am going to try an other strategy
    288          fname = algorithm.full_name( self )
    289          found = self.demangled.find( fname )
    290          if -1 == found:
    291              if fname.startswith( '::' ):
    292                  fname = fname[2:]
    293              found = self.demangled.find( fname )
    294              if -1 == found:
    295                  self._demangled_name = ''
    296                  return self.name
    297          demangled_name = call_invocation.name( self.demangled[ found: ] )
    298          demangled_name = self.__remove_parent_fname( demangled_name )
    299          if demangled_name.startswith( '::' ):
    300              demangled_name = demangled_name[2:]
    301          #to be on the safe side
    302          if demangled_name.startswith( self.name ):
    303              self._demangled_name = demangled_name
    304              return self._demangled_name
    305          #if -1 == found:
    306          self._demangled_name = ''
    307          return self.name
    308
    309      demangled_name = property( _get_demangled_name
    310                                , doc="returns function demangled name. It can help you to deal with function template instantiations")
    311
    312 -    def i_depend_on_them( self, recursive=True ):
    313          report_dependency = lambda *args, **keywd: dependencies.dependency_info_t( self, *args, **keywd )
    314          answer = []
    315          if self.return_type:
    316              answer.append( report_dependency( self.return_type, hint="return type" ) )
    317          map( lambda arg: answer.append( report_dependency( arg.type ) )
    318               , self.arguments )
    319          map( lambda exception: answer.append( report_dependency( exception, hint="exception" ) )
    320               , self.exceptions )
    321          return answer
    322
    323  #Second level in hierarchy of calldef
    324 -class member_calldef_t( calldef_t ):
    325      """base class for "callable" declarations that defined within C++ class or struct"""
    326 -    def __init__( self, virtuality=None, has_const=None, has_static=None, *args, **keywords ):
    327          calldef_t.__init__( self, *args, **keywords )
    328          self._virtuality = virtuality
    329          self._has_const = has_const
    330          self._has_static = has_static
    331
    332 -    def __str__(self):
    333          # Get the full name of the calldef...
    334          name = algorithm.full_name(self)
    335          if name[:2]=="::":
    336              name = name[2:]
    337          # Add the arguments...
    338          args = map(lambda a: str(a), self.arguments)
    339          res = "%s(%s)"%(name, ", ".join(args))
    340          # Add the return type...
    341          if self.return_type!=None:
    342              res = "%s %s"%(self.return_type, res)
    343          # const?
    344          if self.has_const:
    345              res += " const"
    346          # static?
    347          if self.has_static:
    348              res = "static "+res
    349          # Append the declaration class
    350          cls = self.__class__.__name__
    351          if cls[-2:]=="_t":
    352              cls = cls[:-2]
    353          cls = cls.replace( '_', ' ' )
    354          return "%s [%s]"%(res, cls)
    355
    356 -    def _get__cmp__call_items(self):
    357          """implementation details"""
    358          return [ self.virtuality, self.has_static, self.has_const ]
    359
    360 -    def __eq__(self, other):
    361          if not calldef_t.__eq__( self, other ):
    362              return False
    363          return self.virtuality == other.virtuality \
    364                 and self.has_static == other.has_static \
    365                 and self.has_const == other.has_const
    366
    367 -    def get_virtuality(self):
    368          return self._virtuality
    369 -    def set_virtuality(self, virtuality):
    370          assert virtuality in VIRTUALITY_TYPES.ALL
    371          self._virtuality = virtuality
    372      virtuality = property( get_virtuality, set_virtuality
    373                             , doc="""Describes the "virtuality" of the member (as defined by the string constants in the class L{VIRTUALITY_TYPES}).
    374                             @type: str""")
    375
    376 -    def _get_access_type(self):
    377          return self.parent.find_out_member_access_type( self )
    378      access_type = property( _get_access_type
    379                              , doc="""Return the access type of the member (as defined by the string constants in the class L{ACCESS_TYPES}.
    380                              @type: str""")
    381
    382 -    def _get_has_const(self):
    383          return self._has_const
    384 -    def _set_has_const(self, has_const):
    385          self._has_const = has_const
    386      has_const = property( _get_has_const, _set_has_const
    387                            , doc="""describes, whether "callable" has const modifier or not""")
    388
    389 -    def _get_has_static(self):
    390          return self._has_static
    391 -    def _set_has_static(self, has_static):
    392          self._has_static = has_static
    393      has_static = property( _get_has_static, _set_has_static
    394                             , doc="""describes, whether "callable" has static modifier or not""")
    395
    396 -    def function_type(self):
    397          """returns function type. See L{type_t} hierarchy"""
    398          if self.has_static:
    399              return cpptypes.free_function_type_t( return_type=self.return_type
    400                                             , arguments_types=[ arg.type for arg in self.arguments ] )
    401          else:
    402              return cpptypes.member_function_type_t( class_inst=self.parent
    403                                             , return_type=self.return_type
    404                                             , arguments_types=[ arg.type for arg in self.arguments ]
    405                                             , has_const=self.has_const )
    406
    407 -    def create_decl_string(self, with_defaults=True):
    408          f_type = self.function_type()
    409          if with_defaults:
    410              return f_type.decl_string
    411          else:
    412              return f_type.partial_decl_string
    413
    414 -class free_calldef_t( calldef_t ):
    415      """base class for "callable" declarations that defined within C++ namespace"""
    416 -    def __init__( self, *args, **keywords ):
    417          calldef_t.__init__( self, *args, **keywords )
    418
    419 -    def __str__(self):
    420          # Get the full name of the calldef...
    421          name = algorithm.full_name(self)
    422          if name[:2]=="::":
    423              name = name[2:]
    424          # Add the arguments...
    425          args = map(lambda a: str(a), self.arguments)
    426          res = "%s(%s)"%(name, ", ".join(args))
    427          # Add the return type...
    428          if self.return_type!=None:
    429              res = "%s %s"%(self.return_type, res)
    430          # extern?
    431          if self.has_extern:
    432              res = "extern "+res
    433          # Append the declaration class
    434          cls = self.__class__.__name__
    435          if cls[-2:]=="_t":
    436              cls = cls[:-2]
    437          cls = cls.replace( '_', ' ' )
    438          return "%s [%s]"%(res, cls)
    439
    440 -    def _get__cmp__call_items(self):
    441          """implementation details"""
    442          return []
    443
    444 -    def function_type(self):
    445          """returns function type. See L{type_t} hierarchy"""
    446          return cpptypes.free_function_type_t( return_type=self.return_type
    447                                       , arguments_types=[ arg.type for arg in self.arguments ] )
    448
    449 -    def create_decl_string(self, with_defaults=True):
    450          f_type = self.function_type()
    451          if with_defaults:
    452              return f_type.decl_string
    453          else:
    454              return f_type.partial_decl_string
    455
    456
    457 -class operator_t(object):
    458      """base class for "operator" declarations"""
    459      OPERATOR_WORD_LEN = len( 'operator' )
    460 -    def __init__(self):
    461          object.__init__(self)
    462
    463      @property
    464 -    def symbol(self):
    465          "operator's symbol. For example: operator+, symbol is equal to '+'"
    466          return self.name[operator_t.OPERATOR_WORD_LEN:].strip()
    467
    468  #Third level in hierarchy of calldef
    469 -class member_function_t( member_calldef_t ):
    470      """describes member function declaration"""
    471 -    def __init__( self, *args, **keywords ):
    472          member_calldef_t.__init__( self, *args, **keywords )
    473
    474 -class constructor_t( member_calldef_t ):
    475      """describes constructor declaration"""
    476 -    def __init__( self, *args, **keywords ):
    477          member_calldef_t.__init__( self, *args, **keywords )
    478
    479 -    def __str__(self):
    480          # Get the full name of the calldef...
    481          name = algorithm.full_name(self)
    482          if name[:2]=="::":
    483              name = name[2:]
    484          # Add the arguments...
    485          args = map(lambda a: str(a), self.arguments)
    486          res = "%s(%s)"%(name, ", ".join(args))
    487          # Append the declaration class
    488          cls = 'constructor'
    489          if self.is_copy_constructor:
    490              cls = 'copy ' + cls
    491          return "%s [%s]"%(res, cls)
    492
    493      @property
    494 -    def is_copy_constructor(self):
    495          """returns True if described declaration is copy constructor, otherwise False"""
    496          args = self.arguments
    497          if 1 != len( args ):
    498              return False
    499          arg = args[0]
    500          if not type_traits.is_reference( arg.type ):
    501              return False
    502          if not type_traits.is_const( arg.type.base ):
    503              return False
    504          unaliased = type_traits.remove_alias( arg.type.base )
    505          #unaliased now refers to const_t instance
    506          if not isinstance( unaliased.base, cpptypes.declarated_t ):
    507              return False
    508          return id(unaliased.base.declaration) == id(self.parent)
    509
    510      @property
    511 -    def is_trivial_constructor(self):
    512          return not bool( self.arguments )
    513
    514
    515 -class destructor_t( member_calldef_t ):
    516      """describes deconstructor declaration"""
    517 -    def __init__( self, *args, **keywords ):
    518          member_calldef_t.__init__( self, *args, **keywords )
    519
    520 -class member_operator_t( member_calldef_t, operator_t ):
    521      """describes member operator declaration"""
    522 -    def __init__( self, *args, **keywords ):
    523          member_calldef_t.__init__( self, *args, **keywords )
    524          operator_t.__init__( self, *args, **keywords )
    525          self.__class_types = None
    526
    527 -class casting_operator_t( member_calldef_t, operator_t ):
    528      """describes casting operator declaration"""
    529 -    def __init__( self, *args, **keywords ):
    530          member_calldef_t.__init__( self, *args, **keywords )
    531          operator_t.__init__( self, *args, **keywords )
    532
    533 -class free_function_t( free_calldef_t ):
    534      """describes free function declaration"""
    535 -    def __init__( self, *args, **keywords ):
    536          free_calldef_t.__init__( self, *args, **keywords )
    537
    538 -class free_operator_t( free_calldef_t, operator_t ):
    539      """describes free operator declaration"""
    540 -    def __init__( self, *args, **keywords ):
    541          free_calldef_t.__init__( self, *args, **keywords )
    542          operator_t.__init__( self, *args, **keywords )
    543          self.__class_types = None
    544
    545      @property
    546 -    def class_types( self ):
    547          """list of class/class declaration types, extracted from the operator arguments"""
    548          if None is self.__class_types:
    549              self.__class_types = []
    550              for type_ in self.argument_types:
    551                  decl = None
    552                  type_ = type_traits.remove_reference( type_ )
    553                  if type_traits.is_class( type_ ):
    554                      decl = type_traits.class_traits.get_declaration( type_ )
    555                  elif type_traits.is_class_declaration( type_ ):
    556                      decl = type_traits.class_declaration_traits.get_declaration( type_ )
    557                  else:
    558                      pass
    559                  if decl:
    560                      self.__class_types.append( decl )
    561          return self.__class_types
    562