diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2019-09-11 18:49:45 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-11 18:49:45 (GMT) |
commit | ee536b2020b1f0baad1286dbd4345e13870324af (patch) | |
tree | 2486233603db05a76aaef863bd6639455e3dfef7 /Tools/c-analyzer/c_parser/info.py | |
parent | 9936371af298d465095ae70bc9c2943b4b16eac4 (diff) | |
download | cpython-ee536b2020b1f0baad1286dbd4345e13870324af.zip cpython-ee536b2020b1f0baad1286dbd4345e13870324af.tar.gz cpython-ee536b2020b1f0baad1286dbd4345e13870324af.tar.bz2 |
bpo-36876: Add a tool that identifies unsupported global C variables. (#15877)
Diffstat (limited to 'Tools/c-analyzer/c_parser/info.py')
-rw-r--r-- | Tools/c-analyzer/c_parser/info.py | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/Tools/c-analyzer/c_parser/info.py b/Tools/c-analyzer/c_parser/info.py new file mode 100644 index 0000000..9ab6979 --- /dev/null +++ b/Tools/c-analyzer/c_parser/info.py @@ -0,0 +1,78 @@ +from collections import namedtuple + +from c_analyzer_common import info, util +from c_analyzer_common.util import classonly, _NTBase + + +def normalize_vartype(vartype): + """Return the canonical form for a variable type (or func signature).""" + # We allow empty strring through for semantic reasons. + if vartype is None: + return None + + # XXX finish! + # XXX Return (modifiers, type, pointer)? + return str(vartype) + + +class Variable(_NTBase, + namedtuple('Variable', 'id vartype')): + """Information about a single variable declaration.""" + + __slots__ = () + _isglobal = util.Slot() + + @classonly + def from_parts(cls, filename, funcname, name, vartype, isglobal=False): + id = info.ID(filename, funcname, name) + self = cls(id, vartype) + if isglobal: + self._isglobal = True + return self + + def __new__(cls, id, vartype): + self = super().__new__( + cls, + id=info.ID.from_raw(id), + vartype=normalize_vartype(vartype) if vartype else None, + ) + return self + + def __hash__(self): + return hash(self.id) + + def __getattr__(self, name): + return getattr(self.id, name) + + def _validate_id(self): + if not self.id: + raise TypeError('missing id') + + if not self.filename or self.filename == info.UNKNOWN: + raise TypeError(f'id missing filename ({self.id})') + + if self.funcname and self.funcname == info.UNKNOWN: + raise TypeError(f'id missing funcname ({self.id})') + + self.id.validate() + + def validate(self): + """Fail if the object is invalid (i.e. init with bad data).""" + self._validate_id() + + if self.vartype is None or self.vartype == info.UNKNOWN: + raise TypeError('missing vartype') + + @property + def isglobal(self): + try: + return self._isglobal + except AttributeError: + # XXX Include extern variables. + # XXX Ignore functions. + self._isglobal = ('static' in self.vartype.split()) + return self._isglobal + + @property + def isconst(self): + return 'const' in self.vartype.split() |