summaryrefslogtreecommitdiffstats
path: root/Tools/c-analyzer/c_analyzer/__init__.py
blob: b83ffc087a08d83ea886859e2bfb259ab9e6af29 (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
102
103
104
105
from c_parser import (
    parse_files as _parse_files,
)
from c_parser.info import (
    KIND,
    TypeDeclaration,
    resolve_parsed,
)
from c_parser.match import (
    filter_by_kind,
    group_by_kinds,
)
from . import (
    analyze as _analyze,
    datafiles as _datafiles,
)
from .info import Analysis


def analyze(filenmes, **kwargs):
    results = iter_analysis_results(filenames, **kwargs)
    return Analysis.from_results(results)


def iter_analysis_results(filenmes, *,
                          known=None,
                          **kwargs
                          ):
    decls = iter_decls(filenames, **kwargs)
    yield from analyze_decls(decls, known)


def iter_decls(filenames, *,
               kinds=None,
               parse_files=_parse_files,
               **kwargs
               ):
    kinds = KIND.DECLS if kinds is None else (KIND.DECLS & set(kinds))
    parse_files = parse_files or _parse_files

    parsed = parse_files(filenames, **kwargs)
    parsed = filter_by_kind(parsed, kinds)
    for item in parsed:
        yield resolve_parsed(item)


def analyze_decls(decls, known, *,
                  analyze_resolved=None,
                  handle_unresolved=True,
                  relroot=None,
                  ):
    knowntypes, knowntypespecs = _datafiles.get_known(
        known,
        handle_unresolved=handle_unresolved,
        analyze_resolved=analyze_resolved,
        relroot=relroot,
    )

    decls = list(decls)
    collated = group_by_kinds(decls)

    types = {decl: None for decl in collated['type']}
    typespecs = _analyze.get_typespecs(types)

    def analyze_decl(decl):
        return _analyze.analyze_decl(
            decl,
            typespecs,
            knowntypespecs,
            types,
            knowntypes,
            analyze_resolved=analyze_resolved,
        )
    _analyze.analyze_type_decls(types, analyze_decl, handle_unresolved)
    for decl in decls:
        if decl in types:
            resolved = types[decl]
        else:
            resolved = analyze_decl(decl)
            if resolved and handle_unresolved:
                typedeps, _ = resolved
                if not isinstance(typedeps, TypeDeclaration):
                    if not typedeps or None in typedeps:
                        raise NotImplementedError((decl, resolved))

        yield decl, resolved


#######################################
# checks

def check_all(analysis, checks, *, failfast=False):
    for check in checks or ():
        for data, failure in check(analysis):
            if failure is None:
                continue

            yield data, failure
            if failfast:
                yield None, None
                break
        else:
            continue
        # We failed fast.
        break