Expand description
Byte-level scanners for the two Erlang attributes that drive
HeaderFileMissing and BehaviourModuleMissing.
Both attributes have stable, line-oriented shapes:
-behaviour(custom_ct_hook).(also spelled-behavior(...)in OTP-style sources)-include("rel/path.hrl").and-include_lib("app/include/file.hrl").
We scan the source byte by byte, balancing strings, char literals,
and % line comments. Anything more complex (macro-substituted
attributes, parse_transform-injected values) is not visible to the
scanner: those cases are left to a follow-up
--deep-helper-resolution pass.
Structs§
- Behaviour
Ref - One scanned
-behaviour(M)declaration, with the line number for the user-facing report. - Exported
Type - A type a module exports, and the line its entry sits on.
- Function
Signature - One
name(Args)occurrence: a clause head when followed by->orwhen, a call otherwise. Arity is the top-level argument count. - Imported
Function - A function brought into a module’s namespace by
-import(Module, [f/a, ...]). The module is retained so a patch-added import can be resolved as the cross-module referencem:f/ait actually is. - Include
Ref - One scanned
-include(...)or-include_lib(...)declaration, with the line number for the user-facing report. - Macro
Def - Scanned
Use - One scanned
?MACROor#recorduse, with its line for the report. - Surface
- A set of keys the source lists, together with whether the list is
the whole truth.
lookupis the only way to ask about a key: there is nocontains,iter, orDerefto the listed set, so a reader cannot take a plainboolfrom an incomplete surface by accident.
Enums§
- Exported
Types - A module’s
-export_type([t/a, ...])list, either readable in full or not: nothing looks a type up in it, the axis walks it, so the list is read as a whole rather than key by key. - Presence
- Whether a key is in a
Surface. - Types
Unreadable - Why an exported-type list cannot be read from source.
-compile(export_all)exports functions, not types, so it has no arm here. - Unreadable
- Why an export surface cannot be fully read from source.
Functions§
- behaviour_
resolves - Resolve
behaviouragainst the target tree using the sametest_helper_search_pathsglobs as the SUITE helper resolver. - declares_
parse_ transform - True when the module declares a
parse_transform, which can inject functions the scanner cannot see: the caller suppresses local-call flagging for such a module. - extract_
behaviours - Extract every
-behaviour(M)/-behavior(M)declaration insrc. Macro-valued and parse-transform-injected attributes are invisible to the syntactic walk. - extract_
callbacks - A behaviour module’s
-callback name(Args) -> Ret.signatures, keyed by(function, arity). Same walker and grammar asextract_specs. - extract_
defined_ macro_ values - Every
-defineinsrcwith its normalized body, keyed by name. A name defined more than once (-ifdefbranches, or coexisting object-like and function-like forms) keeps every definition, so the caller can withhold instead of guessing which one is live. - extract_
defined_ macros - Macro names defined via
-define(NAME, ...)or-define(NAME(Args), ...). Conditional nesting is ignored: a macro with any-definecounts as present, so the resolver never false-flags a defined macro (the rare inactive-branch define is the one documented miss). - extract_
defined_ records - Record names defined via
-record(name, {...}). - extract_
defined_ types - The types a module declares. Walks form starts, not parenthesised
attribute bodies:
-type t() :: term().is not an-attr(...)form, though the equivalent-type(t() :: term()).is also legal. - extract_
exported_ types - The types a module exports. An entry whose name fails newtype validation is dropped: it would not compile, so nothing resolves against it.
- extract_
exports - Functions a module exports via
-export([f/a, ...]). The surface is unreadable under-compile(export_all)(ornowarn_export_all), a declaredparse_transform(which can inject exports), or an-exportentry naming a macro the scanner cannot expand. - extract_
function_ signatures - Every scanned
name(Args)occurrence, classified into definitions and calls. Qualified (mod:f(), macro (?f(), andfun name(forms are skipped, as are reserved words. Variables (Var(...)) and attribute or spec forms (-export(...),-spec ... term()) hold no local calls, so they are consumed without emitting a signature. - extract_
function_ signatures_ with_ context extract_function_signaturesfor an added-lines blob, with each blob line’s hunk-walked classification. The byte-level attribute tracking alone misreads a blob whose attribute opener or terminator sits on a dropped context line;ctxis authoritative at each line start and the intra-line transitions still apply within a line.- extract_
imports - The functions imported via
-import(mod, [f/a, ...]), each carrying its source module. An entry whose module or name fails newtype validation is dropped: it would not compile, so nothing resolves against it. - extract_
includes - Extract every
-include("…")and-include_lib("app/…")declaration insrc. Only literal string arguments are recognised;-include(?MACRO)is skipped. - extract_
macro_ uses - Every
?MACROreference insrc, comments and strings skipped.??NAME(stringify) counts as a use ofNAME. - extract_
optional_ callbacks - The
(function, arity)pairs a behaviour lists in-optional_callbacks([f/a, ...]). - extract_
record_ uses - Every
#recorduse insrc(creation, match, update, field access), comments and strings skipped.#{...}maps have no name and are ignored. - extract_
specs - A module’s
-spec name(Args) -> Ret.signatures, keyed by(function, arity). Parsing isbackhopper-erlang-scan’sparse_callable_signature: the same grammar the snapshot pipeline uses, so the live axis and the snapshot axis cannot disagree on what a spec is or which arity it has. Module-qualified forms parse toNoneand are simply absent, which withholds downstream. - has_
macro_ expanded_ attribute - True when the source declares a macro-expanded attribute form
(
-?PROTOCOL_TYPE(t()).), which can expand to any attribute:rabbit_framingdeclares its whole type surface this way. No attribute-derived set from such a file is knowable. - is_
predefined_ macro erlcpredefines these, so a reference to one is never undefined.- resolve_
include - Try to find the on-target path the include directive points at.
Returns
Ok(found)on resolution,Err(attempted_paths)when none of the candidate target paths exist.
Type Aliases§
- Export
Surface - A module’s exported
f/asurface. - Spec
Table - A module’s
-specsignatures, keyed by(function, arity).