summaryrefslogtreecommitdiffstats
path: root/Tools/c-analyzer/cpython/find.py
blob: a7bc0b477b839cbff6f28154d50b80e35368b6d7 (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
92
93
94
95
96
97
98
99
100
101
import os.path

from c_analyzer.common import files
from c_analyzer.common.info import UNKNOWN, ID
from c_analyzer.variables import find as _common

from . import SOURCE_DIRS, PYTHON, REPO_ROOT
from .known import (
    from_file as known_from_file,
    DATA_FILE as KNOWN_FILE,
    )
from .supported import (
        ignored_from_file, IGNORED_FILE, is_supported, _is_object,
        )

# XXX need tests:
# * vars_from_binary()
# * vars_from_source()
# * supported_vars()


def _handle_id(filename, funcname, name, *,
               _relpath=os.path.relpath,
               ):
    filename = _relpath(filename, REPO_ROOT)
    return ID(filename, funcname, name)


def vars_from_binary(*,
                     known=KNOWN_FILE,
                     _known_from_file=known_from_file,
                     _iter_files=files.iter_files_by_suffix,
                     _iter_vars=_common.vars_from_binary,
                     ):
    """Yield a Variable for each found Symbol.

    Details are filled in from the given "known" variables and types.
    """
    if isinstance(known, str):
        known = _known_from_file(known)
    dirnames = SOURCE_DIRS
    suffixes = ('.c',)
    filenames = _iter_files(dirnames, suffixes)
    # XXX For now we only use known variables (no source lookup).
    filenames = None
    yield from _iter_vars(PYTHON,
                          known=known,
                          filenames=filenames,
                          handle_id=_handle_id,
                          check_filename=(lambda n: True),
                          )


def vars_from_source(*,
                     preprocessed=None,
                     known=KNOWN_FILE,
                     _known_from_file=known_from_file,
                     _iter_files=files.iter_files_by_suffix,
                     _iter_vars=_common.vars_from_source,
                     ):
    """Yield a Variable for each declaration in the raw source code.

    Details are filled in from the given "known" variables and types.
    """
    if isinstance(known, str):
        known = _known_from_file(known)
    dirnames = SOURCE_DIRS
    suffixes = ('.c',)
    filenames = _iter_files(dirnames, suffixes)
    yield from _iter_vars(filenames,
                          preprocessed=preprocessed,
                          known=known,
                          handle_id=_handle_id,
                          )


def supported_vars(*,
                   known=KNOWN_FILE,
                   ignored=IGNORED_FILE,
                   skip_objects=False,
                   _known_from_file=known_from_file,
                   _ignored_from_file=ignored_from_file,
                   _iter_vars=vars_from_binary,
                   _is_supported=is_supported,
                   ):
    """Yield (var, is supported) for each found variable."""
    if isinstance(known, str):
        known = _known_from_file(known)
    if isinstance(ignored, str):
        ignored = _ignored_from_file(ignored)

    for var in _iter_vars(known=known):
        if not var.isglobal:
            continue
        elif var.vartype == UNKNOWN:
            yield var, None
        # XXX Support proper filters instead.
        elif skip_objects and _is_object(found.vartype):
            continue
        else:
            yield var, _is_supported(var, ignored, known)