3"""The data ``check_annotations.py`` builds from a parse and then reasons over.
5Four records, no behaviour: the symbol table entry, a call site, the evidence
6that the parse actually happened, and a finding. They live apart from both
7the walk that fills them and the rules that read them so that neither side can
8quietly redefine the other's shape -- and so the rules stay testable without
12from __future__
import annotations
14from dataclasses
import dataclass, field
19 """One function, keyed by USR, with whatever ra8_* annotations it carries.
21 Every function declaration and definition the walk sees lands here,
22 annotated or not: the linkage rule has to reason about the functions
23 that carry *no* annotation, which is precisely the set an
24 annotations-only table cannot see.
26 The table is keyed by USR rather than by name. C lets every
27 translation unit have its own ``static`` helper with the same name,
28 and this repo does exactly that -- three unrelated
29 ``internal_zero_bytes`` live in net_pal, usb_hmsc and usb_pmsc. A
30 name-keyed table merges them into one entry whose annotations are the
31 union of all three and whose file is whichever definition happened to
32 be parsed last, so an annotation on one namesake is enforced against
33 the callers of another.
39 annotations: list[str] = field(default_factory=list)
42 is_static: bool =
False
46 has_internal_linkage: bool =
False
47 has_inline: bool =
False
48 section: str |
None =
None
54 has_pointer_param: bool =
False
60 is_defined: bool =
False
65 decl_files: set[str] = field(default_factory=set)
70 """One data definition relevant to the ``s_`` naming contract.
72 The naming rule distinguishes file-scope objects with internal linkage
73 from automatic locals and externally-linked globals. Libclang exposes
74 all three as ``VAR_DECL`` cursors, so preserving the scope and linkage
75 here avoids guessing from source text.
82 has_internal_linkage: bool
87 """A direct CallExpr discovered during AST traversal."""
100 in_address_of: bool =
False
101 parent_loop_label: str |
None =
None
102 preceding_comment: str =
""
107 """Evidence that the parse saw the code it was asked to analyse."""
112 calls_resolved: int = 0
114 missing_includes: set[tuple[str, str]] = field(default_factory=set)
116 unparsed: list[str] = field(default_factory=list)
121 """Collections filled by one or more translation-unit AST walks."""
123 symbols: dict[str, AnnotatedSymbol] = field(default_factory=dict)
124 data_symbols: dict[str, DataSymbol] = field(default_factory=dict)
125 calls: list[CallSite] = field(default_factory=list)
126 vector_entries: set[str] = field(default_factory=set)
127 stats: ParseStats = field(default_factory=ParseStats)
132 """One finding. ``warn_only`` entries are reported but never fail the gate."""
138 warn_only: bool =
False