cpython/Tools/c-analyzer/c_analyzer/match.py

213 lines
5.2 KiB
Python

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)