summaryrefslogtreecommitdiffstats
path: root/Tools/c-analyzer/c_parser/info.py
blob: d7368b48cde355bb4d2644e0af1f33b882a5d96d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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()

    def __del__(self):
        del self._isglobal

    @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()