/// The result of analyzing a GIR repository against a `GenerationConfig`. /// /// Contains the resolved class hierarchy, the classification of each type /// (generate, manual, or ignore), and any per-type or per-function overrides /// from the configuration. This result drives the subsequent code-generation /// phase. public struct AnalysisResult { /// Maps each type name to its parent type name, forming an inheritance tree. /// /// Keys are fully-qualified type names (e.g. `"Gtk.Widget"`); values are the /// fully-qualified parent name. public var classHierarchy: [String: String] /// The set of fully-qualified type names that should have Swift bindings generated. public var generatedTypes: Set /// The set of fully-qualified type names that are implemented manually and /// should be excluded from generation. public var manualTypes: Set /// The set of fully-qualified type names that should be skipped entirely. public var ignoredTypes: Set /// Per-type overrides keyed by fully-qualified type name. public var classOverrides: [String: ObjectOverrides] /// Per-function overrides keyed by `"ClassName.functionName"`. public var functionOverrides: [String: FunctionOverrides] /// Signal overrides keyed by `"ClassName.signalName"`. public var signalOverrides: [String: SignalOverrides] /// Property overrides keyed by `"ClassName.propertyName"`. public var propertyOverrides: [String: PropertyOverrides] /// Function pattern (glob-style) rename rules. public var functionPatterns: [FunctionPatternEntry] /// Maps class name (e.g., `"Gtk.Button"`) to the set of instance method /// and static function names inherited from ancestor classes in the /// same namespace. Used to emit `override` for subclass declarations /// that shadow parent members. Does not include constructors or /// cross-namespace ancestors (those are not real Swift superclasses). public var inheritedMethodNames: [String: Set] /// Set of fully-qualified type names (e.g. `"Gtk.Widget"`) that have /// at least one subclass in the same namespace. public var typesWithSubclasses: Set = [] /// A function pattern rename rule extracted from the config. public struct FunctionPatternEntry { /// The fully-qualified type name this pattern applies to. public let typeName: String /// The glob-style pattern to match function names against. public let pattern: String /// The rename rule to apply to matching functions. public let rename: RenameRule /// Creates a function pattern entry. /// /// - Parameters: /// - typeName: The fully-qualified type name. /// - pattern: The glob-style pattern to match function names. /// - rename: The rename rule to apply. public init(typeName: String, pattern: String, rename: RenameRule) { self.typeName = typeName self.pattern = pattern self.rename = rename } } /// Creates an analysis result from the given component values. /// /// - Parameters: /// - classHierarchy: Inheritance map from each type to its parent. /// - generatedTypes: Types that should be generated. /// - manualTypes: Types that are implemented manually. /// - ignoredTypes: Types that should be omitted. /// - classOverrides: Per-type override configuration. /// - functionOverrides: Per-function override configuration. /// - signalOverrides: Per-signal override configuration. /// - propertyOverrides: Per-property override configuration. /// - functionPatterns: Glob-style function rename rules. /// - inheritedMethodNames: Map from each class to the set of method /// names it inherits transitively from its parent class chain. /// - typesWithSubclasses: Set of fully-qualified type names that have /// at least one same-namespace subclass. public init(classHierarchy: [String: String] = [:], generatedTypes: Set = [], manualTypes: Set = [], ignoredTypes: Set = [], classOverrides: [String: ObjectOverrides] = [:], functionOverrides: [String: FunctionOverrides] = [:], signalOverrides: [String: SignalOverrides] = [:], propertyOverrides: [String: PropertyOverrides] = [:], functionPatterns: [FunctionPatternEntry] = [], inheritedMethodNames: [String: Set] = [:], typesWithSubclasses: Set = []) { self.classHierarchy = classHierarchy self.generatedTypes = generatedTypes self.manualTypes = manualTypes self.ignoredTypes = ignoredTypes self.classOverrides = classOverrides self.functionOverrides = functionOverrides self.signalOverrides = signalOverrides self.propertyOverrides = propertyOverrides self.functionPatterns = functionPatterns self.inheritedMethodNames = inheritedMethodNames self.typesWithSubclasses = typesWithSubclasses } } /// Analyzes a GIR repository against a `GenerationConfig` to produce an `AnalysisResult`. /// /// The analyzer walks the repository's type hierarchy and applies the /// configuration's generate/manual/ignore lists and per-type overrides. public struct Analyzer { /// The generation configuration that guides the analysis. public let config: GenerationConfig /// Creates an analyzer with the given generation configuration. /// /// - Parameter config: The configuration specifying which types to /// generate, handle manually, or ignore, along with any overrides. public init(config: GenerationConfig) { self.config = config } /// Analyzes the provided GIR repository and returns the classification result. /// /// The analysis builds a class inheritance hierarchy from the repository, /// classifies each type according to the configuration's `generate`, /// `manual`, and `ignore` lists, and extracts per-type and per-function /// overrides. /// /// - Parameter repository: The parsed GIR repository to analyze. /// - Returns: An `AnalysisResult` containing the resolved hierarchy, type /// classifications, and overrides. public func analyze(repository: Repository) -> AnalysisResult { var classHierarchy: [String: String] = [:] var generatedTypes: Set = [] var manualTypes: Set = [] var ignoredTypes: Set = [] var classOverrides: [String: ObjectOverrides] = [:] var functionOverrides: [String: FunctionOverrides] = [:] var signalOverrides: [String: SignalOverrides] = [:] var propertyOverrides: [String: PropertyOverrides] = [:] var functionPatterns: [AnalysisResult.FunctionPatternEntry] = [] // Build a lookup: class name (e.g. "Gtk.Widget") -> namespace + class // object. Used to walk the inheritance chain and collect method names. var classesByFullName: [String: Class] = [:] for ns in repository.namespaces { for cls in ns.classes { classesByFullName["\(ns.name).\(cls.name)"] = cls } } for ns in repository.namespaces { for cls in ns.classes { let fullName = "\(ns.name).\(cls.name)" if let parent = cls.parent { let parentFullName = parent.contains(".") ? parent : "\(ns.name).\(parent)" classHierarchy[fullName] = parentFullName } } } // Invert the hierarchy to find parents that have at least one // same-namespace subclass. Only same-namespace children are real // Swift subclasses for the purpose of the "final" rule. var typesWithSubclasses: Set = [] for ns in repository.namespaces { for cls in ns.classes { let fullName = "\(ns.name).\(cls.name)" guard let parentFullName = classHierarchy[fullName] else { continue } let parentNs = parentFullName.split(separator: ".").first.map(String.init) ?? "" if parentNs == ns.name { typesWithSubclasses.insert(parentFullName) } } } // Build the inherited-method-name set for each class by walking the // class hierarchy transitively. A subclass inherits the union of all // method names declared by its parent, grandparent, etc. var inheritedMethodNames: [String: Set] = [:] for ns in repository.namespaces { for cls in ns.classes { let fullName = "\(ns.name).\(cls.name)" guard let parentFullName = classHierarchy[fullName] else { continue } var inherited = Set() // Walk up the hierarchy, stopping at cross-namespace boundaries. // A cross-namespace parent (e.g. "GObject.InitiallyUnowned") is // not a real Swift superclass — the child is a Swift root. var currentParent: String? = parentFullName let childNs = fullName.split(separator: ".").first.map(String.init) ?? "" while let p = currentParent, let pCls = classesByFullName[p] { let pNs = p.split(separator: ".").first.map(String.init) ?? "" if pNs != childNs { break } for method in pCls.methods { inherited.insert(method.name) } for fn in pCls.functions { inherited.insert(fn.name) } currentParent = classHierarchy[p] } inheritedMethodNames[fullName] = inherited } } for fullName in config.generate { generatedTypes.insert(fullName) } for fullName in config.manual { manualTypes.insert(fullName) } for fullName in config.ignore { ignoredTypes.insert(fullName) } for objConfig in config.objects { switch objConfig { case .object(let name, let overrides): classOverrides[name] = overrides if let status = overrides.status { switch status { case .generate: generatedTypes.insert(name) case .manual: manualTypes.insert(name) case .ignore: ignoredTypes.insert(name) } } case .function(let className, let functionName, let overrides): let key = "\(className).\(functionName)" functionOverrides[key] = overrides case .functionPattern(let type, let pattern, let rename): functionPatterns.append(AnalysisResult.FunctionPatternEntry(typeName: type, pattern: pattern, rename: rename)) case .signal(let type, let name, let overrides): signalOverrides["\(type).\(name)"] = overrides case .property(let type, let name, let overrides): propertyOverrides["\(type).\(name)"] = overrides } } return AnalysisResult( classHierarchy: classHierarchy, generatedTypes: generatedTypes, manualTypes: manualTypes, ignoredTypes: ignoredTypes, classOverrides: classOverrides, functionOverrides: functionOverrides, signalOverrides: signalOverrides, propertyOverrides: propertyOverrides, functionPatterns: functionPatterns, inheritedMethodNames: inheritedMethodNames, typesWithSubclasses: typesWithSubclasses ) } }