1# Copyright 2014-2017 Insight Software Consortium. 2# Copyright 2004-2009 Roman Yakovenko. 3# Distributed under the Boost Software License, Version 1.0. 4# See http://www.boost.org/LICENSE_1_0.txt 5 6"""Defines :class:`scopedef_t` class""" 7 8import timeit 9try: 10 from collections.abc import Callable 11except ImportError: 12 from collections import Callable 13 14from . import algorithm 15from . import templates 16from . import declaration 17from . import mdecl_wrapper 18from . import byte_info 19from . import elaborated_info 20from . import runtime_errors 21from .. import utils 22 23 24class matcher(object): 25 26 """Class-namespace, contains implementation of a few "find" algorithms""" 27 28 @staticmethod 29 def find(decl_matcher, decls, recursive=True): 30 """ 31 Returns a list of declarations that match `decl_matcher` defined 32 criteria or None 33 34 :param decl_matcher: Python callable object, that takes one argument - 35 reference to a declaration 36 :param decls: the search scope, :class:declaration_t object or 37 :class:declaration_t objects list t 38 :param recursive: boolean, if True, the method will run `decl_matcher` 39 on the internal declarations too 40 """ 41 42 where = [] 43 if isinstance(decls, list): 44 where.extend(decls) 45 else: 46 where.append(decls) 47 if recursive: 48 where = make_flatten(where) 49 return list(filter(decl_matcher, where)) 50 51 @staticmethod 52 def find_single(decl_matcher, decls, recursive=True): 53 """ 54 Returns a reference to the declaration, that match `decl_matcher` 55 defined criteria. 56 57 if a unique declaration could not be found the method will return None. 58 59 :param decl_matcher: Python callable object, that takes one argument - 60 reference to a declaration 61 :param decls: the search scope, :class:declaration_t object or 62 :class:declaration_t objects list t 63 :param recursive: boolean, if True, the method will run `decl_matcher` 64 on the internal declarations too 65 """ 66 answer = matcher.find(decl_matcher, decls, recursive) 67 if len(answer) == 1: 68 return answer[0] 69 70 @staticmethod 71 def get_single(decl_matcher, decls, recursive=True): 72 """ 73 Returns a reference to declaration, that match `decl_matcher` defined 74 criteria. 75 76 If a unique declaration could not be found, an appropriate exception 77 will be raised. 78 79 :param decl_matcher: Python callable object, that takes one argument - 80 reference to a declaration 81 :param decls: the search scope, :class:declaration_t object or 82 :class:declaration_t objects list t 83 :param recursive: boolean, if True, the method will run `decl_matcher` 84 on the internal declarations too 85 """ 86 answer = matcher.find(decl_matcher, decls, recursive) 87 if len(answer) == 1: 88 return answer[0] 89 elif not answer: 90 raise runtime_errors.declaration_not_found_t(decl_matcher) 91 else: 92 raise runtime_errors.multiple_declarations_found_t(decl_matcher) 93 94 95class scopedef_t(declaration.declaration_t): 96 97 """ 98 Base class for :class:`namespace_t` and :class:`class_t` classes. 99 100 This is the base class for all declaration classes that may have 101 children nodes. The children can be accessed via the 102 :attr:`scopedef_t.declarations` property. 103 104 Also this class provides "get/select/find" interface. Using this class you 105 can get instance or instances of internal declaration(s). 106 107 You can find declaration(s) using next criteria: 108 109 1. ``name`` - declaration name, could be full qualified name 110 111 2. ``header_dir`` - directory, to which belongs file, that the 112 declaration was declared in. ``header_dir`` should be absolute path. 113 114 3. ``header_file`` - file that the declaration was declared in. 115 116 4. ``function`` - user ( your ) custom criteria. The interesting 117 thing is that this function will be joined with 118 other arguments (criteria). 119 120 5. ``recursive`` - the search declaration range, if True will be search 121 in internal declarations too. 122 123 Every ""query"" API, takes name or function as the first argument. 124 125 .. code-block:: python 126 127 global_namespace.member_function("do_something) 128 129 the statement returns reference to member function named "do_something". 130 If there the function doesn't exist or more than one function exists, 131 an exception is raised. 132 133 If you want to query for many declarations, use other function(s): 134 135 .. code-block:: python 136 137 do_something = global_namespace.member_functions("do_something") 138 139 the statement returns :class:`mdecl_wrapper_t` instance. That object will 140 save you writing `for` loops. For more information see 141 :class:`the class <mdecl_wrapper_t>` documentation. 142 """ 143 144 RECURSIVE_DEFAULT = True 145 ALLOW_EMPTY_MDECL_WRAPPER = False 146 147 # this class variable is used to prevent recursive imports 148 _impl_matchers = {} 149 # this class variable is used to prevent recursive imports 150 _impl_decl_types = {} 151 # this class variable is used to prevent recursive imports 152 _impl_all_decl_types = [] 153 154 def __init__(self, name=''): 155 declaration.declaration_t.__init__(self, name) 156 157 self._optimized = False 158 self._type2decls = {} 159 self._type2name2decls = {} 160 self._type2decls_nr = {} 161 self._type2name2decls_nr = {} 162 self._all_decls = None 163 self._all_decls_not_recursive = [] 164 165 @property 166 def _logger(self): 167 """reference to :attr:`pygccxml.utils.loggers.queries_engine` logger""" 168 return utils.loggers.queries_engine 169 170 def _get__cmp__scope_items(self): 171 """implementation details""" 172 raise NotImplementedError() 173 174 def _get__cmp__items(self): 175 """implementation details""" 176 items = [] 177 if self._optimized: 178 # in this case we don't need to build class internal declarations 179 # list 180 items.append(self._all_decls_not_recursive.sort()) 181 else: 182 items.append(self.declarations.sort()) 183 items.extend(self._get__cmp__scope_items()) 184 return items 185 186 def __eq__(self, other): 187 if not declaration.declaration_t.__eq__(self, other): 188 return False 189 return self.declarations[:].sort() == other.declarations[:].sort() 190 191 __hash__ = declaration.declaration_t.__hash__ 192 193 def _get_declarations_impl(self): 194 raise NotImplementedError() 195 196 @property 197 def declarations(self): 198 """ 199 List of children declarations. 200 201 Returns: 202 List[declarations.declaration_t] 203 """ 204 if self._optimized: 205 return self._all_decls_not_recursive 206 207 return self._get_declarations_impl() 208 209 @declarations.setter 210 def declarations(self, declarations): 211 """ 212 Set list of all declarations defined in the namespace. 213 214 Args: 215 List[declarations.declaration_t]: list of declarations 216 217 Not implemented. 218 219 """ 220 raise NotImplementedError() 221 222 def remove_declaration(self, decl): 223 raise NotImplementedError() 224 225 @staticmethod 226 def __decl_types(decl): 227 """implementation details""" 228 types = [] 229 bases = list(decl.__class__.__bases__) 230 if 'pygccxml' in decl.__class__.__module__: 231 types.append(decl.__class__) 232 while bases: 233 base = bases.pop() 234 if base is declaration.declaration_t: 235 continue 236 if base is byte_info.byte_info: 237 continue 238 if base is elaborated_info.elaborated_info: 239 continue 240 if 'pygccxml' not in base.__module__: 241 continue 242 types.append(base) 243 bases.extend(base.__bases__) 244 return types 245 246 def clear_optimizer(self): 247 """Cleans query optimizer state""" 248 self._optimized = False 249 self._type2decls = {} 250 self._type2name2decls = {} 251 self._type2decls_nr = {} 252 self._type2name2decls_nr = {} 253 self._all_decls = None 254 self._all_decls_not_recursive = None 255 256 for decl in self.declarations: 257 if isinstance(decl, scopedef_t): 258 decl.clear_optimizer() 259 260 def init_optimizer(self): 261 """ 262 Initializes query optimizer state. 263 264 There are 4 internals hash tables: 265 1. from type to declarations 266 2. from type to declarations for non-recursive queries 267 3. from type to name to declarations 268 4. from type to name to declarations for non-recursive queries 269 270 Almost every query includes declaration type information. Also very 271 common query is to search some declaration(s) by name or full name. 272 Those hash tables allows to search declaration very quick. 273 """ 274 if self.name == '::': 275 self._logger.debug( 276 "preparing data structures for query optimizer - started") 277 start_time = timeit.default_timer() 278 279 self.clear_optimizer() 280 281 for dtype in scopedef_t._impl_all_decl_types: 282 self._type2decls[dtype] = [] 283 self._type2decls_nr[dtype] = [] 284 self._type2name2decls[dtype] = {} 285 self._type2name2decls_nr[dtype] = {} 286 287 self._all_decls_not_recursive = self.declarations 288 self._all_decls = make_flatten( 289 self._all_decls_not_recursive) 290 for decl in self._all_decls: 291 types = self.__decl_types(decl) 292 for type_ in types: 293 self._type2decls[type_].append(decl) 294 name2decls = self._type2name2decls[type_] 295 if decl.name not in name2decls: 296 name2decls[decl.name] = [] 297 name2decls[decl.name].append(decl) 298 if self is decl.parent: 299 self._type2decls_nr[type_].append(decl) 300 name2decls_nr = self._type2name2decls_nr[type_] 301 if decl.name not in name2decls_nr: 302 name2decls_nr[decl.name] = [] 303 name2decls_nr[decl.name].append(decl) 304 305 for decl in self._all_decls_not_recursive: 306 if isinstance(decl, scopedef_t): 307 decl.init_optimizer() 308 if self.name == '::': 309 self._logger.debug(( 310 "preparing data structures for query optimizer - " + 311 "done( %f seconds ). "), (timeit.default_timer() - start_time)) 312 self._optimized = True 313 314 @staticmethod 315 def _build_operator_function(name, function): 316 if isinstance(name, Callable): 317 return name 318 319 return function 320 321 @staticmethod 322 def _build_operator_name(name, function, symbol): 323 """implementation details""" 324 def add_operator(sym): 325 if 'new' in sym or 'delete' in sym: 326 return 'operator ' + sym 327 return 'operator' + sym 328 if isinstance(name, Callable) and None is function: 329 name = None 330 if name: 331 if 'operator' not in name: 332 name = add_operator(name) 333 return name 334 elif symbol: 335 return add_operator(symbol) 336 return name # both name and symbol are None 337 338 def _on_rename(self): 339 for decl in self.decls(allow_empty=True): 340 decl.cache.reset_name_based() 341 # I am not sure whether to introduce this or not? 342 # It could be very time consuming operation + it changes optimize query 343 # data structures. 344 # if self.parent: 345 # if self.parent._optimized: 346 # self.parent.init_optimizer() 347 348 @staticmethod 349 def __normalize_args(**keywds): 350 """implementation details""" 351 if isinstance(keywds['name'], Callable) and \ 352 None is keywds['function']: 353 keywds['function'] = keywds['name'] 354 keywds['name'] = None 355 return keywds 356 357 def __findout_recursive(self, **keywds): 358 """implementation details""" 359 if None is keywds['recursive']: 360 return self.RECURSIVE_DEFAULT 361 362 return keywds['recursive'] 363 364 def __findout_allow_empty(self, **keywds): 365 """implementation details""" 366 if None is keywds['allow_empty']: 367 return self.ALLOW_EMPTY_MDECL_WRAPPER 368 369 return keywds['allow_empty'] 370 371 @staticmethod 372 def __findout_decl_type(match_class, **keywds): 373 """implementation details""" 374 if 'decl_type' in keywds: 375 return keywds['decl_type'] 376 377 matcher_args = keywds.copy() 378 del matcher_args['function'] 379 del matcher_args['recursive'] 380 if 'allow_empty' in matcher_args: 381 del matcher_args['allow_empty'] 382 383 decl_matcher = match_class(**matcher_args) 384 if decl_matcher.decl_type: 385 return decl_matcher.decl_type 386 return None 387 388 def __create_matcher(self, match_class, **keywds): 389 """implementation details""" 390 matcher_args = keywds.copy() 391 del matcher_args['function'] 392 del matcher_args['recursive'] 393 if 'allow_empty' in matcher_args: 394 del matcher_args['allow_empty'] 395 396 decl_matcher = decl_matcher = match_class(**matcher_args) 397 if keywds['function']: 398 self._logger.debug( 399 'running query: %s and <user defined function>', 400 str(decl_matcher)) 401 return lambda decl: decl_matcher(decl) and keywds['function'](decl) 402 403 self._logger.debug('running query: %s', str(decl_matcher)) 404 return decl_matcher 405 406 def __findout_range(self, name, decl_type, recursive): 407 """implementation details""" 408 if not self._optimized: 409 self._logger.debug( 410 'running non optimized query - optimization has not been done') 411 decls = self.declarations 412 if recursive: 413 decls = make_flatten(self.declarations) 414 if decl_type: 415 decls = [d for d in decls if isinstance(d, decl_type)] 416 return decls 417 418 if name and templates.is_instantiation(name): 419 # templates has tricky mode to compare them, so lets check the 420 # whole range 421 name = None 422 423 if name and decl_type: 424 impl_match = scopedef_t._impl_matchers[scopedef_t.decl](name=name) 425 if impl_match.is_full_name(): 426 name = impl_match.decl_name_only 427 if recursive: 428 self._logger.debug( 429 'query has been optimized on type and name') 430 return self._type2name2decls[decl_type].get(name, []) 431 432 self._logger.debug( 433 'non recursive query has been optimized on type and name') 434 return self._type2name2decls_nr[decl_type].get(name, []) 435 elif decl_type: 436 if recursive: 437 self._logger.debug('query has been optimized on type') 438 return self._type2decls[decl_type] 439 440 self._logger.debug( 441 'non recursive query has been optimized on type') 442 return self._type2decls_nr[decl_type] 443 else: 444 if recursive: 445 self._logger.debug(( 446 'query has not been optimized ( hint: query does not ' + 447 'contain type and/or name )')) 448 return self._all_decls 449 450 self._logger.debug(( 451 'non recursive query has not been optimized ( hint: ' + 452 'query does not contain type and/or name )')) 453 return self._all_decls_not_recursive 454 455 def _find_single(self, match_class, **keywds): 456 """implementation details""" 457 self._logger.debug('find single query execution - started') 458 start_time = timeit.default_timer() 459 norm_keywds = self.__normalize_args(**keywds) 460 decl_matcher = self.__create_matcher(match_class, **norm_keywds) 461 dtype = self.__findout_decl_type(match_class, **norm_keywds) 462 recursive_ = self.__findout_recursive(**norm_keywds) 463 decls = self.__findout_range(norm_keywds['name'], dtype, recursive_) 464 found = matcher.get_single(decl_matcher, decls, False) 465 self._logger.debug( 466 'find single query execution - done( %f seconds )', 467 (timeit.default_timer() - start_time)) 468 return found 469 470 def _find_multiple(self, match_class, **keywds): 471 """implementation details""" 472 self._logger.debug('find all query execution - started') 473 start_time = timeit.default_timer() 474 norm_keywds = self.__normalize_args(**keywds) 475 decl_matcher = self.__create_matcher(match_class, **norm_keywds) 476 dtype = self.__findout_decl_type(match_class, **norm_keywds) 477 recursive_ = self.__findout_recursive(**norm_keywds) 478 allow_empty = self.__findout_allow_empty(**norm_keywds) 479 decls = self.__findout_range(norm_keywds['name'], dtype, recursive_) 480 found = matcher.find(decl_matcher, decls, False) 481 mfound = mdecl_wrapper.mdecl_wrapper_t(found) 482 self._logger.debug('%d declaration(s) that match query', len(mfound)) 483 self._logger.debug( 484 'find single query execution - done( %f seconds )', 485 (timeit.default_timer() - start_time)) 486 if not mfound and not allow_empty: 487 raise RuntimeError( 488 "Multi declaration query returned 0 declarations.") 489 return mfound 490 491 def decl( 492 self, 493 name=None, 494 function=None, 495 decl_type=None, 496 header_dir=None, 497 header_file=None, 498 recursive=None): 499 """returns reference to declaration, that is matched defined 500 criteria""" 501 return ( 502 self._find_single( 503 self._impl_matchers[ 504 scopedef_t.decl], 505 name=name, 506 function=function, 507 decl_type=decl_type, 508 header_dir=header_dir, 509 header_file=header_file, 510 recursive=recursive) 511 ) 512 513 def decls( 514 self, 515 name=None, 516 function=None, 517 decl_type=None, 518 header_dir=None, 519 header_file=None, 520 recursive=None, 521 allow_empty=None): 522 """returns a set of declarations, that are matched defined criteria""" 523 return ( 524 self._find_multiple( 525 self._impl_matchers[ 526 scopedef_t.decl], 527 name=name, 528 function=function, 529 decl_type=decl_type, 530 header_dir=header_dir, 531 header_file=header_file, 532 recursive=recursive, 533 allow_empty=allow_empty) 534 ) 535 536 def class_( 537 self, 538 name=None, 539 function=None, 540 header_dir=None, 541 header_file=None, 542 recursive=None): 543 """returns reference to class declaration, that is matched defined 544 criteria""" 545 return ( 546 self._find_single( 547 self._impl_matchers[scopedef_t.class_], 548 name=name, 549 function=function, 550 decl_type=self._impl_decl_types[ 551 scopedef_t.class_], 552 header_dir=header_dir, 553 header_file=header_file, 554 recursive=recursive) 555 ) 556 557 def classes( 558 self, 559 name=None, 560 function=None, 561 header_dir=None, 562 header_file=None, 563 recursive=None, 564 allow_empty=None): 565 """returns a set of class declarations, that are matched defined 566 criteria""" 567 return ( 568 self._find_multiple( 569 self._impl_matchers[scopedef_t.class_], 570 name=name, 571 function=function, 572 decl_type=self._impl_decl_types[ 573 scopedef_t.class_], 574 header_dir=header_dir, 575 header_file=header_file, 576 recursive=recursive, 577 allow_empty=allow_empty) 578 ) 579 580 def variable( 581 self, 582 name=None, 583 function=None, 584 decl_type=None, 585 header_dir=None, 586 header_file=None, 587 recursive=None): 588 """returns reference to variable declaration, that is matched defined 589 criteria""" 590 591 return ( 592 self._find_single( 593 self._impl_matchers[ 594 scopedef_t.variable], 595 name=name, 596 function=function, 597 decl_type=decl_type, 598 header_dir=header_dir, 599 header_file=header_file, 600 recursive=recursive) 601 ) 602 603 def variables( 604 self, 605 name=None, 606 function=None, 607 decl_type=None, 608 header_dir=None, 609 header_file=None, 610 recursive=None, 611 allow_empty=None): 612 613 """returns a set of variable declarations, that are matched defined 614 criteria""" 615 return ( 616 self._find_multiple( 617 self._impl_matchers[ 618 scopedef_t.variable], 619 name=name, 620 function=function, 621 decl_type=decl_type, 622 header_dir=header_dir, 623 header_file=header_file, 624 recursive=recursive, 625 allow_empty=allow_empty) 626 ) 627 628 def calldef( 629 self, 630 name=None, 631 function=None, 632 return_type=None, 633 arg_types=None, 634 header_dir=None, 635 header_file=None, 636 recursive=None): 637 """returns reference to "calldef" declaration, that is matched defined 638 criteria""" 639 return ( 640 self._find_single( 641 self._impl_matchers[scopedef_t.calldef], 642 name=name, 643 function=function, 644 decl_type=self._impl_decl_types[ 645 scopedef_t.calldef], 646 return_type=return_type, 647 arg_types=arg_types, 648 header_dir=header_dir, 649 header_file=header_file, 650 recursive=recursive) 651 ) 652 653 def calldefs( 654 self, 655 name=None, 656 function=None, 657 return_type=None, 658 arg_types=None, 659 header_dir=None, 660 header_file=None, 661 recursive=None, 662 allow_empty=None): 663 """returns a set of :class:`calldef_t` declarations, that are matched 664 defined criteria""" 665 return ( 666 self._find_multiple( 667 self._impl_matchers[scopedef_t.calldef], 668 name=name, 669 function=function, 670 decl_type=self._impl_decl_types[ 671 scopedef_t.calldef], 672 return_type=return_type, 673 arg_types=arg_types, 674 header_dir=header_dir, 675 header_file=header_file, 676 recursive=recursive, 677 allow_empty=allow_empty) 678 ) 679 680 def operator( 681 self, 682 name=None, 683 function=None, 684 symbol=None, 685 return_type=None, 686 arg_types=None, 687 header_dir=None, 688 header_file=None, 689 recursive=None): 690 """returns reference to operator declaration, that is matched 691 defined criteria""" 692 return ( 693 self._find_single( 694 self._impl_matchers[scopedef_t.operator], 695 name=self._build_operator_name(name, 696 function, 697 symbol), 698 symbol=symbol, 699 function=self._build_operator_function(name, 700 function), 701 decl_type=self._impl_decl_types[scopedef_t.operator], 702 return_type=return_type, 703 arg_types=arg_types, 704 header_dir=header_dir, 705 header_file=header_file, 706 recursive=recursive) 707 ) 708 709 def operators( 710 self, 711 name=None, 712 function=None, 713 symbol=None, 714 return_type=None, 715 arg_types=None, 716 header_dir=None, 717 header_file=None, 718 recursive=None, 719 allow_empty=None): 720 """returns a set of operator declarations, that are matched 721 defined criteria""" 722 return ( 723 self._find_multiple( 724 self._impl_matchers[scopedef_t.operator], 725 name=self._build_operator_name(name, 726 function, 727 symbol), 728 symbol=symbol, 729 function=self._build_operator_function(name, 730 function), 731 decl_type=self._impl_decl_types[scopedef_t.operator], 732 return_type=return_type, 733 arg_types=arg_types, 734 header_dir=header_dir, 735 header_file=header_file, 736 recursive=recursive, 737 allow_empty=allow_empty) 738 ) 739 740 def member_function( 741 self, 742 name=None, 743 function=None, 744 return_type=None, 745 arg_types=None, 746 header_dir=None, 747 header_file=None, 748 recursive=None): 749 """returns reference to member declaration, that is matched 750 defined criteria""" 751 return ( 752 self._find_single( 753 self._impl_matchers[scopedef_t.member_function], 754 name=name, 755 function=function, 756 decl_type=self._impl_decl_types[ 757 scopedef_t.member_function], 758 return_type=return_type, 759 arg_types=arg_types, 760 header_dir=header_dir, 761 header_file=header_file, 762 recursive=recursive) 763 ) 764 765 def member_functions( 766 self, 767 name=None, 768 function=None, 769 return_type=None, 770 arg_types=None, 771 header_dir=None, 772 header_file=None, 773 recursive=None, 774 allow_empty=None): 775 """returns a set of member function declarations, that are matched 776 defined criteria""" 777 return ( 778 self._find_multiple( 779 self._impl_matchers[scopedef_t.member_function], 780 name=name, 781 function=function, 782 decl_type=self._impl_decl_types[ 783 scopedef_t.member_function], 784 return_type=return_type, 785 arg_types=arg_types, 786 header_dir=header_dir, 787 header_file=header_file, 788 recursive=recursive, 789 allow_empty=allow_empty) 790 ) 791 792 def constructor( 793 self, 794 name=None, 795 function=None, 796 return_type=None, 797 arg_types=None, 798 header_dir=None, 799 header_file=None, 800 recursive=None): 801 """returns reference to constructor declaration, that is matched 802 defined criteria""" 803 return ( 804 self._find_single( 805 self._impl_matchers[scopedef_t.constructor], 806 name=name, 807 function=function, 808 decl_type=self._impl_decl_types[ 809 scopedef_t.constructor], 810 return_type=return_type, 811 arg_types=arg_types, 812 header_dir=header_dir, 813 header_file=header_file, 814 recursive=recursive) 815 ) 816 817 def constructors( 818 self, 819 name=None, 820 function=None, 821 return_type=None, 822 arg_types=None, 823 header_dir=None, 824 header_file=None, 825 recursive=None, 826 allow_empty=None): 827 """returns a set of constructor declarations, that are matched 828 defined criteria""" 829 return ( 830 self._find_multiple( 831 self._impl_matchers[scopedef_t.constructor], 832 name=name, 833 function=function, 834 decl_type=self._impl_decl_types[ 835 scopedef_t.constructor], 836 return_type=return_type, 837 arg_types=arg_types, 838 header_dir=header_dir, 839 header_file=header_file, 840 recursive=recursive, 841 allow_empty=allow_empty) 842 ) 843 844 def member_operator( 845 self, 846 name=None, 847 function=None, 848 symbol=None, 849 return_type=None, 850 arg_types=None, 851 header_dir=None, 852 header_file=None, 853 recursive=None): 854 """returns reference to member operator declaration, that is matched 855 defined criteria""" 856 return ( 857 self._find_single( 858 self._impl_matchers[scopedef_t.member_operator], 859 name=self._build_operator_name(name, 860 function, 861 symbol), 862 symbol=symbol, 863 function=self._build_operator_function(name, 864 function), 865 decl_type=self._impl_decl_types[scopedef_t.member_operator], 866 return_type=return_type, 867 arg_types=arg_types, 868 header_dir=header_dir, 869 header_file=header_file, 870 recursive=recursive) 871 ) 872 873 def member_operators( 874 self, 875 name=None, 876 function=None, 877 symbol=None, 878 return_type=None, 879 arg_types=None, 880 header_dir=None, 881 header_file=None, 882 recursive=None, 883 allow_empty=None): 884 """returns a set of member operator declarations, that are matched 885 defined criteria""" 886 return ( 887 self._find_multiple( 888 self._impl_matchers[scopedef_t.member_operator], 889 name=self._build_operator_name(name, 890 function, 891 symbol), 892 symbol=symbol, 893 function=self._build_operator_function(name, 894 function), 895 decl_type=self._impl_decl_types[scopedef_t.member_operator], 896 return_type=return_type, 897 arg_types=arg_types, 898 header_dir=header_dir, 899 header_file=header_file, 900 recursive=recursive, 901 allow_empty=allow_empty) 902 ) 903 904 def casting_operator( 905 self, 906 name=None, 907 function=None, 908 return_type=None, 909 arg_types=None, 910 header_dir=None, 911 header_file=None, 912 recursive=None): 913 """returns reference to casting operator declaration, that is matched 914 defined criteria""" 915 return ( 916 self._find_single( 917 self._impl_matchers[scopedef_t.casting_operator], 918 name=name, 919 function=function, 920 decl_type=self._impl_decl_types[ 921 scopedef_t.casting_operator], 922 return_type=return_type, 923 arg_types=arg_types, 924 header_dir=header_dir, 925 header_file=header_file, 926 recursive=recursive) 927 ) 928 929 def casting_operators( 930 self, 931 name=None, 932 function=None, 933 return_type=None, 934 arg_types=None, 935 header_dir=None, 936 header_file=None, 937 recursive=None, 938 allow_empty=None): 939 """returns a set of casting operator declarations, that are matched 940 defined criteria""" 941 return ( 942 self._find_multiple( 943 self._impl_matchers[scopedef_t.casting_operator], 944 name=name, 945 function=function, 946 decl_type=self._impl_decl_types[ 947 scopedef_t.casting_operator], 948 return_type=return_type, 949 arg_types=arg_types, 950 header_dir=header_dir, 951 header_file=header_file, 952 recursive=recursive, 953 allow_empty=allow_empty) 954 ) 955 956 def enumeration( 957 self, 958 name=None, 959 function=None, 960 header_dir=None, 961 header_file=None, 962 recursive=None): 963 """returns reference to enumeration declaration, that is matched 964 defined criteria""" 965 return ( 966 self._find_single( 967 self._impl_matchers[scopedef_t.enumeration], 968 name=name, 969 function=function, 970 decl_type=self._impl_decl_types[ 971 scopedef_t.enumeration], 972 header_dir=header_dir, 973 header_file=header_file, 974 recursive=recursive) 975 ) 976 977 def enumerations( 978 self, 979 name=None, 980 function=None, 981 header_dir=None, 982 header_file=None, 983 recursive=None, 984 allow_empty=None): 985 """returns a set of enumeration declarations, that are matched 986 defined criteria""" 987 return ( 988 self._find_multiple( 989 self._impl_matchers[scopedef_t.enumeration], 990 name=name, 991 function=function, 992 decl_type=self._impl_decl_types[ 993 scopedef_t.enumeration], 994 header_dir=header_dir, 995 header_file=header_file, 996 recursive=recursive, 997 allow_empty=allow_empty) 998 ) 999 1000 def typedef( 1001 self, 1002 name=None, 1003 function=None, 1004 header_dir=None, 1005 header_file=None, 1006 recursive=None): 1007 """returns reference to typedef declaration, that is matched 1008 defined criteria""" 1009 return ( 1010 self._find_single( 1011 self._impl_matchers[scopedef_t.typedef], 1012 name=name, 1013 function=function, 1014 decl_type=self._impl_decl_types[ 1015 scopedef_t.typedef], 1016 header_dir=header_dir, 1017 header_file=header_file, 1018 recursive=recursive) 1019 ) 1020 1021 def typedefs( 1022 self, 1023 name=None, 1024 function=None, 1025 header_dir=None, 1026 header_file=None, 1027 recursive=None, 1028 allow_empty=None): 1029 """returns a set of typedef declarations, that are matched 1030 defined criteria""" 1031 return ( 1032 self._find_multiple( 1033 self._impl_matchers[scopedef_t.typedef], 1034 name=name, 1035 function=function, 1036 decl_type=self._impl_decl_types[ 1037 scopedef_t.typedef], 1038 header_dir=header_dir, 1039 header_file=header_file, 1040 recursive=recursive, 1041 allow_empty=allow_empty) 1042 ) 1043 1044 def __getitem__(self, name_or_function): 1045 """ 1046 Allow simple name based find of declarations. Internally just calls 1047 `decls` method. 1048 :param name_or_function: Name of `decl` to lookup or finder function. 1049 """ 1050 return self.decls(name_or_function) 1051 1052 def i_depend_on_them(self, recursive=True): 1053 raise NotImplementedError() 1054 1055 1056def make_flatten(decl_or_decls): 1057 """ 1058 Converts tree representation of declarations to flatten one. 1059 1060 :param decl_or_decls: reference to list of declaration's or single 1061 declaration 1062 :type decl_or_decls: :class:`declaration_t` or [ :class:`declaration_t` ] 1063 :rtype: [ all internal declarations ] 1064 1065 """ 1066 1067 def proceed_single(decl): 1068 answer = [decl] 1069 if not isinstance(decl, scopedef_t): 1070 return answer 1071 for elem in decl.declarations: 1072 if isinstance(elem, scopedef_t): 1073 answer.extend(proceed_single(elem)) 1074 else: 1075 answer.append(elem) 1076 return answer 1077 1078 decls = [] 1079 if isinstance(decl_or_decls, list): 1080 decls.extend(decl_or_decls) 1081 else: 1082 decls.append(decl_or_decls) 1083 answer = [] 1084 for decl in decls: 1085 answer.extend(proceed_single(decl)) 1086 return answer 1087 1088 1089def find_all_declarations( 1090 declarations, 1091 decl_type=None, 1092 name=None, 1093 parent=None, 1094 recursive=True, 1095 fullname=None): 1096 """ 1097 Returns a list of all declarations that match criteria, defined by 1098 developer. 1099 1100 For more information about arguments see :class:`match_declaration_t` 1101 class. 1102 1103 :rtype: [ matched declarations ] 1104 1105 """ 1106 1107 if recursive: 1108 decls = make_flatten(declarations) 1109 else: 1110 decls = declarations 1111 1112 return list( 1113 filter( 1114 algorithm.match_declaration_t( 1115 decl_type=decl_type, 1116 name=name, 1117 fullname=fullname, 1118 parent=parent), 1119 decls)) 1120 1121 1122def find_declaration( 1123 declarations, 1124 decl_type=None, 1125 name=None, 1126 parent=None, 1127 recursive=True, 1128 fullname=None): 1129 """ 1130 Returns single declaration that match criteria, defined by developer. 1131 If more the one declaration was found None will be returned. 1132 1133 For more information about arguments see :class:`match_declaration_t` 1134 class. 1135 1136 :rtype: matched declaration :class:`declaration_t` or None 1137 1138 """ 1139 1140 decl = find_all_declarations( 1141 declarations, 1142 decl_type=decl_type, 1143 name=name, 1144 parent=parent, 1145 recursive=recursive, 1146 fullname=fullname) 1147 if len(decl) == 1: 1148 return decl[0] 1149 1150 1151def find_first_declaration( 1152 declarations, 1153 decl_type=None, 1154 name=None, 1155 parent=None, 1156 recursive=True, 1157 fullname=None): 1158 """ 1159 Returns first declaration that match criteria, defined by developer. 1160 1161 For more information about arguments see :class:`match_declaration_t` 1162 class. 1163 1164 :rtype: matched declaration :class:`declaration_t` or None 1165 1166 """ 1167 1168 decl_matcher = algorithm.match_declaration_t( 1169 decl_type=decl_type, 1170 name=name, 1171 fullname=fullname, 1172 parent=parent) 1173 if recursive: 1174 decls = make_flatten(declarations) 1175 else: 1176 decls = declarations 1177 for decl in decls: 1178 if decl_matcher(decl): 1179 return decl 1180 return None 1181 1182 1183def declaration_files(decl_or_decls): 1184 """ 1185 Returns set of files 1186 1187 Every declaration is declared in some file. This function returns set, that 1188 contains all file names of declarations. 1189 1190 :param decl_or_decls: reference to list of declaration's or single 1191 declaration 1192 :type decl_or_decls: :class:`declaration_t` or [:class:`declaration_t`] 1193 :rtype: set(declaration file names) 1194 1195 """ 1196 1197 files = set() 1198 decls = make_flatten(decl_or_decls) 1199 for decl in decls: 1200 if decl.location: 1201 files.add(decl.location.file_name) 1202 return files 1203