scanner

package
v0.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Rendered for darwin/amd64

Overview

Package scanner drives the first phase of the code-generation pipeline.

It invokes xcrun clang with -ast-dump=json on a framework's umbrella header, unmarshals the resulting Clang JSON AST, and walks it to produce a [meta.FrameworkMeta] value that captures the framework's complete public API: classes, protocols, enums, structs, free functions, extern constants, block types, and typedefs.

Extraction is restricted to declarations whose source file belongs to the named framework's own headers (filter.go), so re-exported types from other frameworks are skipped and attributed to their true owner during the load phase.

Key entry points:

  • DumpAST — invokes xcrun clang and returns the parsed AST root node.
  • Extract — walks an AST value and returns a populated [meta.FrameworkMeta].

Index

Constants

View Source
const BackendPurego = "purego"

BackendPurego is the CLibraryDef.Backend value selecting the purego pipeline.

Variables

This section is empty.

Functions

func CLibraryBackend added in v0.19.0

func CLibraryBackend(name string) string

CLibraryBackend returns the configured binding backend for a registered C library: BackendPurego, or "" for the default CGo backend (also returned for unknown names).

func CLibraryHeader

func CLibraryHeader(sdkPath, name string) string

CLibraryHeader returns the umbrella header path for a known Apple C library. If the library definition specifies a custom Header path, that is used; otherwise the default {Name}/{Name}.h convention applies.

func CLibraryHeaderDir

func CLibraryHeaderDir(sdkPath, name string) string

CLibraryHeaderDir returns the filter path for a known Apple C library. This is the path prefix used to decide whether an AST node belongs to the library. It may be a directory (e.g. "bsm/") or an exact file (e.g. "sandbox.h") depending on how the library's headers are laid out.

func CLibraryHeaderRelative

func CLibraryHeaderRelative(name string) string

CLibraryHeaderRelative returns the umbrella header include path for a known Apple C library, relative to {SDK}/usr/include/ and slash-separated — the form used in a generated "#include <…>" directive (e.g. "compression.h", "os/log.h", "bsm/libbsm.h"). Defaults to the {Name}/{Name}.h convention when the library definition has no custom Header.

func ClangVersion

func ClangVersion() (string, error)

ClangVersion returns the version line of the clang binary that DumpAST invokes (e.g. "Apple clang version 21.0.0 (clang-2100.3.9.2)"). Recorded in scanned metadata because clang releases have changed AST output in ways that affect extraction (Clang 21 stopped emitting availability versions).

func DetectSubFrameworkNames

func DetectSubFrameworkNames(bundlePath string) []string

DetectSubFrameworkNames returns the names of sub-frameworks inside bundlePath/Frameworks/ that have a valid umbrella header. Returns nil when the framework is not an umbrella.

func DumpRecordLayouts added in v0.18.0

func DumpRecordLayouts(sdkPath, framework, arch string) (map[string]RecordLayout, error)

DumpRecordLayouts invokes xcrun clang with -fdump-record-layouts-simple on the framework's umbrella header and returns the authoritative record layouts keyed by bare record name (struct/union tag or typedef name). Record layout is target-dependent, so the target/isysroot/header args mirror DumpAST exactly. The dump lands on stdout during codegen (-emit-llvm), so stdout is parsed. A record with a non-byte-aligned field offset (a bitfield) or an unnamed tag is omitted; the emitter falls back to its computed layout for those. clang only lays out records used by value, so pointer-only-referenced structs are absent.

func Extract

func Extract(root *ASTNode, sdkPath, frameworkName, sdkVersion, arch string, layouts map[string]RecordLayout) *macosplatformmetadata.FrameworkMeta

Extract walks the Clang AST root node and produces a FrameworkMeta containing only declarations that originate from the named framework's headers.

func FrameworkBundlePath

func FrameworkBundlePath(sdkPath, name string) string

FrameworkBundlePath returns the path to a framework's .framework bundle. It handles both top-level frameworks and "Parent/Child" sub-frameworks.

func FrameworkHeader

func FrameworkHeader(sdkPath, framework string) string

FrameworkHeader returns the path to the umbrella header for a framework. framework may be "Name" (top-level) or "Parent/Child" (sub-framework). Falls back to the C library header path for known Apple C libraries. A per-framework ScanConfig.HeaderOverride (SDK-relative slash path) takes precedence over the default <Framework>.h naming convention, allowing frameworks that ship no conventional umbrella (e.g. IOKit) to be scanned.

func FrameworkHeaderDir

func FrameworkHeaderDir(sdkPath, framework string) string

FrameworkHeaderDir returns the directory containing all headers for a framework. framework may be "Name" (top-level) or "Parent/Child" (sub-framework). Falls back to the C library header directory for known Apple C libraries.

func IsCLibrary

func IsCLibrary(sdkPath, name string) bool

IsCLibrary reports whether name is a known Apple C library whose umbrella header exists on the filesystem.

func IsCLibraryName

func IsCLibraryName(name string) bool

IsCLibraryName reports whether name is registered as a known Apple C library, without performing any filesystem check. Use this when an SDK path is not available (e.g. when constructing metadata output paths during a scan).

func IsSubFramework

func IsSubFramework(name string) bool

IsSubFramework reports whether name uses "Parent/Child" sub-framework notation.

func IsSwiftOnly

func IsSwiftOnly(bundlePath string) bool

IsSwiftOnly reports whether the framework at bundlePath has no ObjC surface and is implemented entirely in Swift (indicated by a .swiftmodule directory).

func ListCLibraries

func ListCLibraries(sdkPath string) ([]string, error)

ListCLibraries returns the sorted names of known Apple C libraries present in sdkPath. If sdkPath is empty it is auto-detected via xcrun.

func ListFrameworks

func ListFrameworks(sdkPath string) ([]string, error)

ListFrameworks returns the sorted names of all frameworks available in sdkPath that have a valid umbrella header (Framework.framework/Headers/Framework.h). If sdkPath is empty it is auto-detected via xcrun. Sub-frameworks nested inside umbrella frameworks (e.g. Carbon/HIToolbox) are included using "Parent/Child" notation so the scanner can locate them.

func LoadCLibrariesFile

func LoadCLibrariesFile(path string) (bool, error)

LoadCLibrariesFile replaces the active C library registry with the contents of a JSON config file (map of library name → CLibraryDef). Adding a new Apple C library is then a data change plus re-scan, not a Go change. Returns false without error when the file does not exist.

func LoadScanConfigFile

func LoadScanConfigFile(path string) (bool, error)

LoadScanConfigFile replaces the active per-framework scan configuration with the contents of a JSON config file (map of framework name → ScanConfig). Returns false without error when the file does not exist.

func SDKPath

func SDKPath() (string, error)

SDKPath returns the path to the active macOS SDK via xcrun.

func SDKVersion

func SDKVersion() (string, error)

SDKVersion returns the macOS SDK version string (e.g. "26.5").

func SubFrameworkParts

func SubFrameworkParts(name string) (parent, child string)

SubFrameworkParts splits a "Parent/Child" name into parent and child.

func XcodeVersion

func XcodeVersion() (string, error)

XcodeVersion returns the active Xcode version and build, joined on one line (e.g. "Xcode 26.0 Build version 17A321"). Recorded in scanned metadata as toolchain provenance.

Types

type ASTNode

type ASTNode struct {
	ID          string    `json:"id"`
	Kind        string    `json:"kind"`
	Loc         *Location `json:"loc"`
	Range       *SrcRange `json:"range"`
	Name        string    `json:"name"`
	MangledName string    `json:"mangledName"`
	Type        *ASTType  `json:"type"`
	ReturnType  *ASTType  `json:"returnType"`
	Inner       []ASTNode `json:"inner"`

	// PreviousDecl is the hex ID string of the previous declaration of this
	// name in the same translation unit. When set, this node is a redeclaration
	// (e.g. @class Foo; repeated after the canonical @interface Foo...@end, or
	// an empty @class Foo; that precedes the canonical definition). Used in
	// extractClass to distinguish canonical definitions from foreign-class
	// forward declarations.
	PreviousDecl string `json:"previousDecl"`

	// ObjCInterfaceDecl / ObjCCategoryDecl
	Super     *ASTRef  `json:"super"`
	Protocols []ASTRef `json:"protocols"`
	// ObjCCategoryDecl: the class this category extends
	Interface *ASTRef `json:"interface"`

	// ObjCMethodDecl — Clang uses "instance": true for instance methods,
	// absence of the field (or false) means class method.
	IsInstance bool `json:"instance"`
	IsVariadic bool `json:"variadic"`
	IsImplicit bool `json:"implicit"`

	// ObjCPropertyDecl
	Getter *ASTRef `json:"getter"`
	Setter *ASTRef `json:"setter"`
	// property attribute flags: "readonly", "copy", "weak", "assign", etc.
	PropertyAttributes []string `json:"propertyAttributes"`

	// EnumDecl
	FixedUnderlyingType *ASTType `json:"fixedUnderlyingType"`

	// RecordDecl (struct/union)
	TagUsed            string `json:"tagUsed"`            // "struct" or "union"
	CompleteDefinition bool   `json:"completeDefinition"` // true for full record decl, false/missing for forward decl

	// VarDecl
	StorageClass string `json:"storageClass"` // "extern"

	// IntegerLiteral / FloatingLiteral / ConstantExpr
	// Clang emits numeric literals as JSON numbers; use RawMessage to handle both
	// number and string variants uniformly.
	Value RawValue `json:"value"`

	// Availability
	Availability []ASTNode `json:"availability"` // AvailabilityAttr nodes

	// AvailabilityAttr fields
	Platform   string `json:"platform"` // "macos", "ios"
	Introduced string `json:"introduced"`
	Deprecated string `json:"deprecated"`
	Obsoleted  string `json:"obsoleted"`
	Message    string `json:"message"`

	// ObjCTypeParamDecl — generic type params on a class
	// appears as inner nodes of ObjCInterfaceDecl
	Bound *ASTType `json:"bound"` // upper bound (usually "id")

	// Nullability qualifier attached to a type
	NullabilityQual string `json:"nullabilityQual"` // "nullable", "nonnull", "unspecified"

	// SwiftNameAttr carries the NS_SWIFT_NAME value; appears as an inner node.
	SwiftName string `json:"swiftName,omitempty"`
}

ASTNode is a node in the Clang JSON AST produced by clang -ast-dump=json. Only fields we actually use are decoded; unknown fields are silently ignored.

func DumpAST

func DumpAST(sdkPath, framework, arch string) (*ASTNode, error)

DumpAST invokes xcrun clang -ast-dump=json on the framework's umbrella header and returns the parsed top-level ASTNode. The arch parameter should be "arm64" or "x86_64".

type ASTRef

type ASTRef struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type ASTType

type ASTType struct {
	QualType          string `json:"qualType"` // e.g. "NSArray<ObjectType> *", "NSUInteger"
	TypeAliasDeclID   string `json:"typeAliasDeclId"`
	DesugaredQualType string `json:"desugaredQualType"` // after typedef expansion
}

type CLibraryDef

type CLibraryDef struct {
	// LinkLib is the dylib name passed to -l (e.g. "EndpointSecurity" → -lEndpointSecurity).
	LinkLib string `json:"link_lib"`
	// Header is the umbrella header path relative to {SDK}/usr/include/.
	// Empty means use the default {Name}/{Name}.h convention.
	Header string `json:"header,omitempty"`
	// HeaderDir is the filter path relative to {SDK}/usr/include/ used to decide
	// whether an AST node belongs to this library. Empty means derive from Header.
	// Use a directory path (e.g. "bsm/") to accept all headers under that directory,
	// or a file path (e.g. "sandbox.h") to match only that exact file.
	HeaderDir string `json:"header_dir,omitempty"`
	// ShimHeader is a repo-relative path to a hand-maintained prototype header
	// for libraries that ship a linkable .tbd stub in the SDK but no public
	// header (private dylibs such as IOReport). When set it takes precedence
	// over Header/HeaderDir: the scan parses this file, the node filter accepts
	// only declarations made in it, and the bridge emitter ships a copy inside
	// the generated package's bridge/ directory.
	ShimHeader string `json:"shim_header,omitempty"`
	// Backend selects the binding backend for this library: "cgo" (default when
	// empty) emits the ObjC-shim bridge via the CGo pipeline; "purego" emits
	// dlopen/RegisterLibFunc bindings via the purego frameworks pipeline. The
	// per-library key is the migration ratchet — libraries flip one at a time.
	Backend string `json:"backend,omitempty"`
}

CLibraryDef describes a known Apple C library under {SDK}/usr/include/.

type IncludedFromRef

type IncludedFromRef struct {
	File string `json:"file"`
}

IncludedFromRef holds the file that directly includes the file containing a source location. Clang emits this when the declaration file is not the translation unit root.

type Location

type Location struct {
	FilePath string `json:"file"`
	Line     int    `json:"line"`
	Col      int    `json:"col"`
	// When the loc is a macro expansion the actual file is in ExpansionLoc
	ExpansionLoc *Location `json:"expansionLoc"`
	// Spelling location (pre-macro-expansion)
	SpellingLoc *Location `json:"spellingLoc"`
	// IncludedFrom is the file that directly includes the file this loc is in.
	// Present when loc.file is absent (Clang cursor optimisation) or when Clang
	// wants to indicate the include chain.
	IncludedFrom *IncludedFromRef `json:"includedFrom"`
}

func (*Location) IncludedFromFile

func (l *Location) IncludedFromFile() string

IncludedFromFile returns the path of the file that directly includes the file this location is in, or "" if none was recorded. Used by the framework filter to determine true framework ownership when loc.file is absent.

func (*Location) ResolvedFile

func (l *Location) ResolvedFile() string

ResolvedFile returns the most useful file path from this location, unwrapping macro expansions to find the real header file. For macro-expanded declarations (NS_ENUM, NS_OPTIONS, etc.) the expansion location is the call site in the SDK header, while the spelling location is the macro definition inside CoreFoundation. We want the call site.

func (*Location) ResolvedLine

func (l *Location) ResolvedLine() int

ResolvedLine returns the source line number, preferring spellingLoc over expansionLoc.

type RawValue

type RawValue string

RawValue holds an AST literal value which Clang may emit as a JSON number or as a JSON string. It normalises both to a plain string.

func (RawValue) MarshalJSON

func (r RawValue) MarshalJSON() ([]byte, error)

MarshalJSON writes the value as a JSON string.

func (RawValue) String

func (r RawValue) String() string

String returns the value as a plain Go string.

func (*RawValue) UnmarshalJSON

func (r *RawValue) UnmarshalJSON(data []byte) error

type RecordLayout added in v0.18.0

type RecordLayout struct {
	Size         int
	Align        int
	FieldOffsets []int
}

RecordLayout is a C record's authoritative ABI layout from clang: the total size and each field's offset, in BYTES.

type ScanConfig

type ScanConfig struct {
	// ExtraIncludeDirs lists additional directories (relative to the SDK root,
	// slash-separated) whose headers count as belonging to this framework.
	ExtraIncludeDirs []string `json:"extra_include_dirs,omitempty"`
	// HeaderOverride is the SDK-relative slash-separated path to the entry
	// header to pass to clang, for frameworks that do not ship a conventional
	// <Framework>.framework/Headers/<Framework>.h umbrella (e.g. IOKit, which
	// only exposes individual headers). When set it overrides the default
	// umbrella path computed by FrameworkHeader.
	HeaderOverride string `json:"header_override,omitempty"`
}

ScanConfig holds per-framework scan customisations.

type SrcRange

type SrcRange struct {
	Begin Location `json:"begin"`
	End   Location `json:"end"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL