summaryrefslogtreecommitdiff
path: root/Tools/c-analyzer/c_analyzer/variables/known.py
blob: aa2934a069e16b70a7f67adcd76a1fd736bbade0 (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
82
83
84
85
86
87
88
89
90
91
import csv

from ..common.info import ID, UNKNOWN
from ..common.util import read_tsv
from .info import Variable


# XXX need tests:
# * read_file()
# * look_up_variable()


COLUMNS = ('filename', 'funcname', 'name', 'kind', 'declaration')
HEADER = '\t'.join(COLUMNS)


def read_file(infile, *,
              _read_tsv=read_tsv,
              ):
    """Yield (kind, id, decl) for each row in the data file.

    The caller is responsible for validating each row.
    """
    for row in _read_tsv(infile, HEADER):
        filename, funcname, name, kind, declaration = row
        if not funcname or funcname == '-':
            funcname = None
        id = ID(filename, funcname, name)
        yield kind, id, declaration


def from_file(infile, *,
              handle_var=Variable.from_id,
              _read_file=read_file,
              ):
    """Return the info for known declarations in the given file."""
    known = {
        'variables': {},
        #'types': {},
        #'constants': {},
        #'macros': {},
        }
    for kind, id, decl in _read_file(infile):
        if kind == 'variable':
            values = known['variables']
            value = handle_var(id, decl)
        else:
            raise ValueError(f'unsupported kind in row {row}')
        value.validate()
        values[id] = value
    return known


def look_up_variable(varid, knownvars, *,
                     match_files=(lambda f1, f2: f1 == f2),
                     ):
    """Return the known Variable matching the given ID.

    "knownvars" is a mapping of ID to Variable.

    "match_files" is used to verify if two filenames point to
    the same file.

    If no match is found then None is returned.
    """
    if not knownvars:
        return None

    if varid.funcname == UNKNOWN:
        if not varid.filename or varid.filename == UNKNOWN:
            for varid in knownvars:
                if not varid.funcname:
                    continue
                if varid.name == varid.name:
                    return knownvars[varid]
            else:
                return None
        else:
            for varid in knownvars:
                if not varid.funcname:
                    continue
                if not match_files(varid.filename, varid.filename):
                    continue
                if varid.name == varid.name:
                    return knownvars[varid]
            else:
                return None
    elif not varid.filename or varid.filename == UNKNOWN:
        raise NotImplementedError
    else:
        return knownvars.get(varid.id)