1   
  2   
  3   
  4   
  5   
  6  """ 
  7  defines base class for L{namespace_t} and L{class_t} classes 
  8  """ 
  9   
 10  import time 
 11  import algorithm 
 12  import filtering 
 13  import templates 
 14  import declaration 
 15  import mdecl_wrapper 
 16  from pygccxml import utils 
 17  import matcher as matcher_module 
 18   
 20      """Base class for L{namespace_t} and L{class_t} classes. 
 21   
 22      This is the base class for all declaration classes that may have 
 23      children nodes. The children can be accessed via the C{declarations} 
 24      property. 
 25   
 26      Also this class provides "get/select/find" interface. Using this class you 
 27      can get instance or instances of internal declaration(s). 
 28   
 29      You can find declaration(s) using next criteria: 
 30          1. name - declaration name, could be full qualified name 
 31          2. header_dir - directory, to which belongs file, that the declaration was declarated in. 
 32             header_dir should be absolute path. 
 33          3. header_file - file that the declaration was declarated in. 
 34          4. function - user ( your ) custom criteria. The interesting thing is that 
 35             this function will be joined with other arguments ( criteria ). 
 36          5. recursive - the search declaration range, if True will be search in 
 37            internal declarations too. 
 38   
 39      Every "select" API you can invoke and pass as first argument at declaration 
 40      name or function. This class will find out correctly what argument represents. 
 41   
 42      Example:: 
 43          ns - referrers to global namespace 
 44          ns.member_function( "do_something ) - will return reference to member 
 45          function named "do_something". If there is no such function exception 
 46          will be raised. If there is more then one function exception will be 
 47          raised too. 
 48   
 49      Example 2:: 
 50          ns - referers to global namespace 
 51          do_smths = ns.member_functions( "do_something ) - will return instance 
 52          of L{mdecl_wrapper_t} object. This object allows you few things: 
 53   
 54          1. To iterate on selected declarations 
 55          2. To set some property to desired value using one line of code only: 
 56             do_smths.call_policies = x 
 57          3. To call some function on every instance using one line of code: 
 58             do_smths.exclude() 
 59   
 60          Pay attention: you can not use "get" functions or properties. 
 61      """ 
 62   
 63      RECURSIVE_DEFAULT = True 
 64      ALLOW_EMPTY_MDECL_WRAPPER = False 
 65   
 66      declaration_not_found_t = matcher_module.matcher.declaration_not_found_t 
 67      multiple_declarations_found_t = matcher_module.matcher.multiple_declarations_found_t 
 68   
 69      _impl_matchers = {}  
 70      _impl_decl_types = {}  
 71      _impl_all_decl_types = []  
 72   
 74          declaration.declaration_t.__init__( self, name ) 
 75   
 76          self._optimized = False 
 77          self._type2decls = {} 
 78          self._type2name2decls = {} 
 79          self._type2decls_nr = {} 
 80          self._type2name2decls_nr = {} 
 81          self._all_decls = None 
 82          self._all_decls_not_recursive = None 
  83   
 86      _logger = property( _get_logger, doc="reference to C{queries_engine} logger" ) 
 87   
 89          """implementation details""" 
 90          raise NotImplementedError() 
  91   
 93          """implementation details""" 
 94          items = [] 
 95          if self._optimized: 
 96               
 97              items.append( self._sorted_list( self._all_decls_not_recursive ) ) 
 98          else: 
 99              items.append( self._sorted_list( self.declarations ) ) 
100          items.extend( self._get__cmp__scope_items() ) 
101          return items 
 102   
108           
109           
110               
111           
112           
113               
114           
115               
116   
118          raise NotImplementedError() 
 119   
121          if True == self._optimized: 
122              return self._all_decls_not_recursive 
123          else: 
124              return self._get_declarations_impl() 
 125      declarations = property( _get_declarations, doc="list of children L{declarations<declaration_t>}" ) 
126   
128          raise NotImplementedError() 
 129   
148   
150          """Cleans query optimizer state""" 
151          self._optimized = False 
152          self._type2decls = {} 
153          self._type2name2decls = {} 
154          self._type2decls_nr = {} 
155          self._type2name2decls_nr = {} 
156          self._all_decls = None 
157          self._all_decls_not_recursive = None 
158   
159          map( lambda decl: decl.clear_optimizer() 
160               , filter( lambda decl: isinstance( decl, scopedef_t ) 
161                         ,  self.declarations ) ) 
 162   
164          """Initializes query optimizer state. 
165          There are 4 internals hash tables: 
166              1. from type to declarations 
167              2. from type to declarations for non-recursive queries 
168              3. from type to name to declarations 
169              4. from type to name to declarations for non-recursive queries 
170   
171          Almost every query includes declaration type information. Also very 
172          common query is to search some declaration(s) by name or full name. 
173          Those hashtables allows to search declaration very quick. 
174          """ 
175          if self.name == '::': 
176              self._logger.debug( "preparing data structures for query optimizer - started" ) 
177          start_time = time.clock() 
178   
179          self.clear_optimizer() 
180   
181          for dtype in scopedef_t._impl_all_decl_types: 
182              self._type2decls[ dtype ] = [] 
183              self._type2decls_nr[ dtype ] = [] 
184              self._type2name2decls[ dtype ] = {} 
185              self._type2name2decls_nr[ dtype ] = {} 
186   
187          self._all_decls_not_recursive = self.declarations 
188          self._all_decls = algorithm.make_flatten( self._all_decls_not_recursive ) 
189          for decl in self._all_decls: 
190              types = self.__decl_types( decl ) 
191              for type_ in types: 
192                  self._type2decls[ type_ ].append( decl ) 
193                  name2decls = self._type2name2decls[ type_ ] 
194                  if not name2decls.has_key( decl.name ): 
195                      name2decls[ decl.name ] = [] 
196                  name2decls[ decl.name ].append( decl ) 
197                  if self is decl.parent: 
198                      self._type2decls_nr[ type_ ].append( decl ) 
199                      name2decls_nr = self._type2name2decls_nr[ type_ ] 
200                      if not name2decls_nr.has_key( decl.name ): 
201                          name2decls_nr[ decl.name ] = [] 
202                      name2decls_nr[ decl.name ].append( decl ) 
203   
204          map( lambda decl: decl.init_optimizer() 
205               , filter( lambda decl: isinstance( decl, scopedef_t ) 
206                         ,  self._all_decls_not_recursive ) ) 
207          if self.name == '::': 
208              self._logger.debug( "preparing data structures for query optimizer - done( %f seconds ). " 
209                                  % ( time.clock() - start_time ) ) 
210          self._optimized = True 
 211   
217   
219          """implementation details""" 
220          def add_operator( sym ): 
221              if 'new' in sym or 'delete' in sym: 
222                  return 'operator ' + sym 
223              else: 
224                  return 'operator'+ sym 
 225          if callable( name ) and None is function: 
226              name = None 
227          if name: 
228              if not 'operator' in name: 
229                 name = add_operator( name ) 
230              return name 
231          elif symbol: 
232              return add_operator( symbol ) 
233          return name  
 234   
238           
239           
240           
241           
242           
243           
244   
246          """implementation details""" 
247          if callable( keywds['name'] ) and None is keywds['function']: 
248              keywds['function'] = keywds['name'] 
249              keywds['name'] = None 
250          return keywds 
 251   
253          """implementation details""" 
254          if None is keywds[ 'recursive' ]: 
255              return self.RECURSIVE_DEFAULT 
256          else: 
257              return keywds[ 'recursive' ] 
 258   
260          """implementation details""" 
261          if None is keywds[ 'allow_empty' ]: 
262              return self.ALLOW_EMPTY_MDECL_WRAPPER 
263          else: 
264              return keywds[ 'allow_empty' ] 
 265   
267          """implementation details""" 
268          if keywds.has_key( 'decl_type' ): 
269              return keywds['decl_type'] 
270   
271          matcher_args = keywds.copy() 
272          del matcher_args['function'] 
273          del matcher_args['recursive'] 
274          if matcher_args.has_key('allow_empty'): 
275              del matcher_args['allow_empty'] 
276   
277          matcher = match_class( **matcher_args ) 
278          if matcher.decl_type: 
279              return matcher.decl_type 
280          return None 
 281   
283          """implementation details""" 
284          matcher_args = keywds.copy() 
285          del matcher_args['function'] 
286          del matcher_args['recursive'] 
287          if matcher_args.has_key('allow_empty'): 
288              del matcher_args['allow_empty'] 
289   
290          matcher = match_class( **matcher_args ) 
291          if keywds['function']: 
292              self._logger.debug( 'running query: %s and <user defined function>' % str( matcher ) ) 
293              return lambda decl: matcher( decl ) and keywds['function'](decl) 
294          else: 
295              self._logger.debug( 'running query: %s' % str( matcher ) ) 
296              return matcher 
 297   
299          """implementation details""" 
300          if not self._optimized: 
301              self._logger.debug( 'running non optimized query - optimization has not been done' ) 
302              decls = self.declarations 
303              if recursive: 
304                  decls = algorithm.make_flatten( self.declarations ) 
305              if decl_type: 
306                  decls = filter( lambda d: isinstance( d, decl_type ), decls ) 
307              return decls 
308   
309          if name and templates.is_instantiation( name ): 
310               
311               
312              name = None 
313           
314          if name and decl_type: 
315              matcher = scopedef_t._impl_matchers[ scopedef_t.decl ]( name=name ) 
316              if matcher.is_full_name(): 
317                  name = matcher.decl_name_only 
318              if recursive: 
319                  self._logger.debug( 'query has been optimized on type and name' ) 
320                  if self._type2name2decls[decl_type].has_key( name ): 
321                      return self._type2name2decls[decl_type][name] 
322                  else: 
323                      return [] 
324              else: 
325                  self._logger.debug( 'non recursive query has been optimized on type and name' ) 
326                  if self._type2name2decls_nr[decl_type].has_key( name ): 
327                      return self._type2name2decls_nr[decl_type][name] 
328                  else: 
329                      return [] 
330          elif decl_type: 
331              if recursive: 
332                  self._logger.debug( 'query has been optimized on type' ) 
333                  return self._type2decls[ decl_type ] 
334              else: 
335                  self._logger.debug( 'non recursive query has been optimized on type' ) 
336                  return self._type2decls_nr[ decl_type ] 
337          else: 
338              if recursive: 
339                  self._logger.debug( 'query has not been optimized ( hint: query does not contain type and/or name )' ) 
340                  return self._all_decls 
341              else: 
342                  self._logger.debug( 'non recursive query has not been optimized ( hint: query does not contain type and/or name )' ) 
343                  return self._all_decls_not_recursive 
 344   
346          """implementation details""" 
347          self._logger.debug( 'find single query execution - started' ) 
348          start_time = time.clock() 
349          norm_keywds = self.__normalize_args( **keywds ) 
350          matcher = self.__create_matcher( match_class, **norm_keywds ) 
351          dtype = self.__findout_decl_type( match_class, **norm_keywds ) 
352          recursive_ = self.__findout_recursive( **norm_keywds ) 
353          decls = self.__findout_range( norm_keywds['name'], dtype, recursive_ ) 
354          found = matcher_module.matcher.get_single( matcher, decls, False ) 
355          self._logger.debug( 'find single query execution - done( %f seconds )' % ( time.clock() - start_time ) ) 
356          return found 
 357   
359          """implementation details""" 
360          self._logger.debug( 'find all query execution - started' ) 
361          start_time = time.clock() 
362          norm_keywds = self.__normalize_args( **keywds ) 
363          matcher = self.__create_matcher( match_class, **norm_keywds ) 
364          dtype = self.__findout_decl_type( match_class, **norm_keywds ) 
365          recursive_ = self.__findout_recursive( **norm_keywds ) 
366          allow_empty = self.__findout_allow_empty( **norm_keywds ) 
367          decls = self.__findout_range( norm_keywds['name'], dtype, recursive_ ) 
368          found = matcher_module.matcher.find( matcher, decls, False ) 
369          mfound = mdecl_wrapper.mdecl_wrapper_t( found ) 
370          self._logger.debug( '%d declaration(s) that match query' % len(mfound) ) 
371          self._logger.debug( 'find single query execution - done( %f seconds )' 
372                       % ( time.clock() - start_time ) ) 
373          if not mfound and not allow_empty: 
374              raise RuntimeError( "Multi declaration query returned 0 declarations." ) 
375          return mfound 
 376   
377 -    def decl( self, name=None, function=None, decl_type=None, header_dir=None, header_file=None, recursive=None ): 
 386   
387 -    def decls( self, name=None, function=None, decl_type=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 397   
398 -    def class_( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ): 
 407   
408 -    def classes( self, name=None, function=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 418   
419 -    def variable( self, name=None, function=None, type=None, header_dir=None, header_file=None, recursive=None ): 
 428      var = variable  
429   
430 -    def variables( self, name=None, function=None, type=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 440      vars = variables  
441   
442 -    def calldef( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ): 
 453   
454 -    def calldefs( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 455          """returns a set of calldef declarations, that are matched defined criterias""" 
456          return self._find_multiple( self._impl_matchers[ scopedef_t.calldef ] 
457                                      , name=name 
458                                      , function=function 
459                                      , decl_type=self._impl_decl_types[ scopedef_t.calldef ] 
460                                      , return_type=return_type 
461                                      , arg_types=arg_types 
462                                      , header_dir=header_dir 
463                                      , header_file=header_file 
464                                      , recursive=recursive 
465                                      , allow_empty=allow_empty) 
 466   
467 -    def operator( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ): 
 468          """returns reference to operator declaration, that is matched defined criterias""" 
469          return self._find_single( self._impl_matchers[ scopedef_t.operator ] 
470                                    , name=self._build_operator_name( name, function, symbol ) 
471                                    , symbol=symbol 
472                                    , function=self._build_operator_function( name, function ) 
473                                    , decl_type=self._impl_decl_types[ scopedef_t.operator ] 
474                                    , return_type=return_type 
475                                    , arg_types=arg_types 
476                                    , header_dir=header_dir 
477                                    , header_file=header_file 
478                                    , recursive=recursive ) 
 479   
480 -    def operators( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 481          """returns a set of operator declarations, that are matched defined criterias""" 
482          return self._find_multiple( self._impl_matchers[ scopedef_t.operator ] 
483                                      , name=self._build_operator_name( name, function, symbol ) 
484                                      , symbol=symbol 
485                                      , function=self._build_operator_function( name, function ) 
486                                      , decl_type=self._impl_decl_types[ scopedef_t.operator ] 
487                                      , return_type=return_type 
488                                      , arg_types=arg_types 
489                                      , header_dir=header_dir 
490                                      , header_file=header_file 
491                                      , recursive=recursive 
492                                      , allow_empty=allow_empty) 
 493   
494 -    def member_function( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ): 
 505      mem_fun = member_function 
506   
507 -    def member_functions( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 508          """returns a set of member function declarations, that are matched defined criterias""" 
509          return self._find_multiple( self._impl_matchers[ scopedef_t.member_function ] 
510                                      , name=name 
511                                      , function=function 
512                                      , decl_type=self._impl_decl_types[ scopedef_t.member_function ] 
513                                      , return_type=return_type 
514                                      , arg_types=arg_types 
515                                      , header_dir=header_dir 
516                                      , header_file=header_file 
517                                      , recursive=recursive 
518                                      , allow_empty=allow_empty) 
 519      mem_funs = member_functions 
520   
521 -    def constructor( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ): 
 532   
533 -    def constructors( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 534          """returns a set of constructor declarations, that are matched defined criterias""" 
535          return self._find_multiple( self._impl_matchers[ scopedef_t.constructor ] 
536                                      , name=name 
537                                      , function=function 
538                                      , decl_type=self._impl_decl_types[ scopedef_t.constructor ] 
539                                      , return_type=return_type 
540                                      , arg_types=arg_types 
541                                      , header_dir=header_dir 
542                                      , header_file=header_file 
543                                      , recursive=recursive 
544                                      , allow_empty=allow_empty) 
 545   
546 -    def member_operator( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ): 
 547          """returns reference to member operator declaration, that is matched defined criterias""" 
548          return self._find_single( self._impl_matchers[ scopedef_t.member_operator ] 
549                                    , name=self._build_operator_name( name, function, symbol ) 
550                                    , symbol=symbol 
551                                    , function=self._build_operator_function( name, function ) 
552                                    , decl_type=self._impl_decl_types[ scopedef_t.member_operator ] 
553                                    , return_type=return_type 
554                                    , arg_types=arg_types 
555                                    , header_dir=header_dir 
556                                    , header_file=header_file 
557                                    , recursive=recursive ) 
 558      mem_oper = member_operator 
559 -    def member_operators( self, name=None, function=None, symbol=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 560          """returns a set of member operator declarations, that are matched defined criterias""" 
561          return self._find_multiple( self._impl_matchers[ scopedef_t.member_operator ] 
562                                      , name=self._build_operator_name( name, function, symbol ) 
563                                      , symbol=symbol 
564                                      , function=self._build_operator_function( name, function ) 
565                                      , decl_type=self._impl_decl_types[ scopedef_t.member_operator ] 
566                                      , return_type=return_type 
567                                      , arg_types=arg_types 
568                                      , header_dir=header_dir 
569                                      , header_file=header_file 
570                                      , recursive=recursive 
571                                      , allow_empty=allow_empty) 
 572      mem_opers = member_operators 
573   
574 -    def casting_operator( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None ): 
 585   
586 -    def casting_operators( self, name=None, function=None, return_type=None, arg_types=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 587          """returns a set of casting operator declarations, that are matched defined criterias""" 
588          return self._find_multiple( self._impl_matchers[ scopedef_t.casting_operator ] 
589                                      , name=name 
590                                      , function=function 
591                                      , decl_type=self._impl_decl_types[ scopedef_t.casting_operator ] 
592                                      , return_type=return_type 
593                                      , arg_types=arg_types 
594                                      , header_dir=header_dir 
595                                      , header_file=header_file 
596                                      , recursive=recursive 
597                                      , allow_empty=allow_empty) 
 598   
599 -    def enumeration( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ): 
 608   
609      enum = enumeration 
610      """adding small aliase to enumeration method""" 
611   
612 -    def enumerations( self, name=None, function=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 622       
623      enums = enumerations 
624   
625 -    def typedef( self, name=None, function=None, header_dir=None, header_file=None, recursive=None ): 
 634   
635 -    def typedefs( self, name=None, function=None, header_dir=None, header_file=None, recursive=None, allow_empty=None ): 
 645   
647          """ Allow simple name based find of decls.  Internally just calls decls() method. 
648              @param name_or_function  Name of decl to lookup or finder function. 
649          """ 
650          return self.decls(name_or_function) 
 651