mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
bpo-36876: Small adjustments to the C-analyzer tool. (GH-23045)
This is a little bit of clean-up, small fixes, and additional helpers prior to building an updated & accurate list of globals to eliminate.
This commit is contained in:
parent
b9ee4af4c6
commit
4fe72090de
16 changed files with 632 additions and 217 deletions
212
Tools/c-analyzer/c_analyzer/match.py
Normal file
212
Tools/c-analyzer/c_analyzer/match.py
Normal file
|
@ -0,0 +1,212 @@
|
|||
import os.path
|
||||
|
||||
from c_parser import (
|
||||
info as _info,
|
||||
match as _match,
|
||||
)
|
||||
|
||||
|
||||
_KIND = _info.KIND
|
||||
|
||||
|
||||
# XXX Use known.tsv for these?
|
||||
SYSTEM_TYPES = {
|
||||
'int8_t',
|
||||
'uint8_t',
|
||||
'int16_t',
|
||||
'uint16_t',
|
||||
'int32_t',
|
||||
'uint32_t',
|
||||
'int64_t',
|
||||
'uint64_t',
|
||||
'size_t',
|
||||
'ssize_t',
|
||||
'intptr_t',
|
||||
'uintptr_t',
|
||||
'wchar_t',
|
||||
'',
|
||||
# OS-specific
|
||||
'pthread_cond_t',
|
||||
'pthread_mutex_t',
|
||||
'pthread_key_t',
|
||||
'atomic_int',
|
||||
'atomic_uintptr_t',
|
||||
'',
|
||||
# lib-specific
|
||||
'WINDOW', # curses
|
||||
'XML_LChar',
|
||||
'XML_Size',
|
||||
'XML_Parser',
|
||||
'enum XML_Error',
|
||||
'enum XML_Status',
|
||||
'',
|
||||
}
|
||||
|
||||
|
||||
def is_system_type(typespec):
|
||||
return typespec in SYSTEM_TYPES
|
||||
|
||||
|
||||
##################################
|
||||
# decl matchers
|
||||
|
||||
def is_public(decl):
|
||||
if not decl.filename.endswith('.h'):
|
||||
return False
|
||||
if 'Include' not in decl.filename.split(os.path.sep):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_process_global(vardecl):
|
||||
kind, storage, _, _, _ = _info.get_parsed_vartype(vardecl)
|
||||
if kind is not _KIND.VARIABLE:
|
||||
raise NotImplementedError(vardecl)
|
||||
if 'static' in (storage or ''):
|
||||
return True
|
||||
|
||||
if hasattr(vardecl, 'parent'):
|
||||
parent = vardecl.parent
|
||||
else:
|
||||
parent = vardecl.get('parent')
|
||||
return not parent
|
||||
|
||||
|
||||
def is_fixed_type(vardecl):
|
||||
if not vardecl:
|
||||
return None
|
||||
_, _, _, typespec, abstract = _info.get_parsed_vartype(vardecl)
|
||||
if 'typeof' in typespec:
|
||||
raise NotImplementedError(vardecl)
|
||||
elif not abstract:
|
||||
return True
|
||||
|
||||
if '*' not in abstract:
|
||||
# XXX What about []?
|
||||
return True
|
||||
elif _match._is_funcptr(abstract):
|
||||
return True
|
||||
else:
|
||||
for after in abstract.split('*')[1:]:
|
||||
if not after.lstrip().startswith('const'):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def is_immutable(vardecl):
|
||||
if not vardecl:
|
||||
return None
|
||||
if not is_fixed_type(vardecl):
|
||||
return False
|
||||
_, _, typequal, _, _ = _info.get_parsed_vartype(vardecl)
|
||||
# If there, it can only be "const" or "volatile".
|
||||
return typequal == 'const'
|
||||
|
||||
|
||||
def is_public_api(decl):
|
||||
if not is_public(decl):
|
||||
return False
|
||||
if decl.kind is _KIND.TYPEDEF:
|
||||
return True
|
||||
elif _match.is_type_decl(decl):
|
||||
return not _match.is_forward_decl(decl)
|
||||
else:
|
||||
return _match.is_external_reference(decl)
|
||||
|
||||
|
||||
def is_public_declaration(decl):
|
||||
if not is_public(decl):
|
||||
return False
|
||||
if decl.kind is _KIND.TYPEDEF:
|
||||
return True
|
||||
elif _match.is_type_decl(decl):
|
||||
return _match.is_forward_decl(decl)
|
||||
else:
|
||||
return _match.is_external_reference(decl)
|
||||
|
||||
|
||||
def is_public_definition(decl):
|
||||
if not is_public(decl):
|
||||
return False
|
||||
if decl.kind is _KIND.TYPEDEF:
|
||||
return True
|
||||
elif _match.is_type_decl(decl):
|
||||
return not _match.is_forward_decl(decl)
|
||||
else:
|
||||
return not _match.is_external_reference(decl)
|
||||
|
||||
|
||||
def is_public_impl(decl):
|
||||
if not _KIND.is_decl(decl.kind):
|
||||
return False
|
||||
# See filter_forward() about "is_public".
|
||||
return getattr(decl, 'is_public', False)
|
||||
|
||||
|
||||
def is_module_global_decl(decl):
|
||||
if is_public_impl(decl):
|
||||
return False
|
||||
if _match.is_forward_decl(decl):
|
||||
return False
|
||||
return not _match.is_local_var(decl)
|
||||
|
||||
|
||||
##################################
|
||||
# filtering with matchers
|
||||
|
||||
def filter_forward(items, *, markpublic=False):
|
||||
if markpublic:
|
||||
public = set()
|
||||
actual = []
|
||||
for item in items:
|
||||
if is_public_api(item):
|
||||
public.add(item.id)
|
||||
elif not _match.is_forward_decl(item):
|
||||
actual.append(item)
|
||||
else:
|
||||
# non-public duplicate!
|
||||
# XXX
|
||||
raise Exception(item)
|
||||
for item in actual:
|
||||
_info.set_flag(item, 'is_public', item.id in public)
|
||||
yield item
|
||||
else:
|
||||
for item in items:
|
||||
if _match.is_forward_decl(item):
|
||||
continue
|
||||
yield item
|
||||
|
||||
|
||||
##################################
|
||||
# grouping with matchers
|
||||
|
||||
def group_by_storage(decls, **kwargs):
|
||||
def is_module_global(decl):
|
||||
if not is_module_global_decl(decl):
|
||||
return False
|
||||
if decl.kind == _KIND.VARIABLE:
|
||||
if _info.get_effective_storage(decl) == 'static':
|
||||
# This is covered by is_static_module_global().
|
||||
return False
|
||||
return True
|
||||
def is_static_module_global(decl):
|
||||
if not _match.is_global_var(decl):
|
||||
return False
|
||||
return _info.get_effective_storage(decl) == 'static'
|
||||
def is_static_local(decl):
|
||||
if not _match.is_local_var(decl):
|
||||
return False
|
||||
return _info.get_effective_storage(decl) == 'static'
|
||||
#def is_local(decl):
|
||||
# if not _match.is_local_var(decl):
|
||||
# return False
|
||||
# return _info.get_effective_storage(decl) != 'static'
|
||||
categories = {
|
||||
#'extern': is_extern,
|
||||
'published': is_public_impl,
|
||||
'module-global': is_module_global,
|
||||
'static-module-global': is_static_module_global,
|
||||
'static-local': is_static_local,
|
||||
}
|
||||
return _match.group_by_category(decls, categories, **kwargs)
|
Loading…
Add table
Add a link
Reference in a new issue