Skip to content

swift_analyzer

Full name: tenets.core.analysis.implementations.swift_analyzer

swift_analyzer

Swift code analyzer with iOS/macOS and SwiftUI support.

This module provides comprehensive analysis for Swift source files, including support for iOS/macOS development, SwiftUI, UIKit, async/await, and modern Swift features.

Classes

SwiftAnalyzer

Python
SwiftAnalyzer()

Bases: LanguageAnalyzer

Swift code analyzer with iOS/macOS and SwiftUI support.

Provides comprehensive analysis for Swift files including: - Import statements - Classes, structs, enums, protocols - Extensions and protocol conformance - Optionals and optional chaining - Guard statements and if-let bindings - Async/await and actors - Property wrappers (@State, @Published, etc.) - Result builders (@ViewBuilder, etc.) - SwiftUI views and modifiers - UIKit components - Combine framework usage - Access control levels - Generics and associated types

Supports Swift 5.x features and Apple platform development.

Initialize the Swift analyzer with logger.

Source code in tenets/core/analysis/implementations/swift_analyzer.py
Python
def __init__(self):
    """Initialize the Swift analyzer with logger."""
    self.logger = get_logger(__name__)
Functions
extract_imports
Python
extract_imports(content: str, file_path: Path) -> List[ImportInfo]

Extract import statements from Swift code.

Handles: - import statements: import Foundation - Targeted imports: import struct Swift.Array - Conditional imports: @_exported import, @testable import - Module aliasing (limited in Swift)

PARAMETERDESCRIPTION
content

Swift source code

TYPE:str

file_path

Path to the file being analyzed

TYPE:Path

RETURNSDESCRIPTION
List[ImportInfo]

List of ImportInfo objects with import details

Source code in tenets/core/analysis/implementations/swift_analyzer.py
Python
def extract_imports(self, content: str, file_path: Path) -> List[ImportInfo]:
    """Extract import statements from Swift code.

    Handles:
    - import statements: import Foundation
    - Targeted imports: import struct Swift.Array
    - Conditional imports: @_exported import, @testable import
    - Module aliasing (limited in Swift)

    Args:
        content: Swift source code
        file_path: Path to the file being analyzed

    Returns:
        List of ImportInfo objects with import details
    """
    imports = []
    lines = content.split("\n")

    for i, line in enumerate(lines, 1):
        # Skip comments
        if line.strip().startswith("//"):
            continue

        # Basic import
        import_pattern = r"^\s*(?:(@\w+)\s+)?import\s+(?:(struct|class|enum|protocol|func|var|let|typealias)\s+)?([.\w]+)"
        match = re.match(import_pattern, line)
        if match:
            attribute = match.group(1)
            import_kind = match.group(2)
            module = match.group(3)

            # Determine import type
            import_type = "import"
            is_testable = False
            is_exported = False

            if attribute:
                if attribute == "@testable":
                    is_testable = True
                    import_type = "testable_import"
                elif attribute == "@_exported":
                    is_exported = True
                    import_type = "exported_import"

            # Categorize the import
            category = self._categorize_import(module)
            is_apple_framework = self._is_apple_framework(module)

            imports.append(
                ImportInfo(
                    module=module,
                    line=i,
                    type=import_type,
                    is_relative=False,
                    category=category,
                    is_apple_framework=is_apple_framework,
                    is_testable=is_testable,
                    is_exported=is_exported,
                    import_kind=import_kind,  # struct, class, etc.
                )
            )

    return imports
extract_exports
Python
extract_exports(content: str, file_path: Path) -> List[Dict[str, Any]]

Extract exported symbols from Swift code.

In Swift, exports are determined by access control: - public: Accessible from any module - open: Subclassable from any module (classes only) - internal: Default, accessible within module - fileprivate: Accessible within file - private: Accessible within scope

PARAMETERDESCRIPTION
content

Swift source code

TYPE:str

file_path

Path to the file being analyzed

TYPE:Path

RETURNSDESCRIPTION
List[Dict[str, Any]]

List of exported symbols (public/open declarations)

Source code in tenets/core/analysis/implementations/swift_analyzer.py
Python
def extract_exports(self, content: str, file_path: Path) -> List[Dict[str, Any]]:
    """Extract exported symbols from Swift code.

    In Swift, exports are determined by access control:
    - public: Accessible from any module
    - open: Subclassable from any module (classes only)
    - internal: Default, accessible within module
    - fileprivate: Accessible within file
    - private: Accessible within scope

    Args:
        content: Swift source code
        file_path: Path to the file being analyzed

    Returns:
        List of exported symbols (public/open declarations)
    """
    exports = []

    # Classes (reference types)
    class_pattern = r"^\s*(?:(public|open|internal|fileprivate|private)\s+)?(?:(final|abstract)\s+)?class\s+(\w+)"
    for match in re.finditer(class_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access in ["public", "open"]:
            exports.append(
                {
                    "name": match.group(3),
                    "type": "class",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                    "is_final": match.group(2) == "final",
                    "is_open": access == "open",
                }
            )

    # Structs (value types)
    struct_pattern = r"^\s*(?:(public|internal|fileprivate|private)\s+)?struct\s+(\w+)"
    for match in re.finditer(struct_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            exports.append(
                {
                    "name": match.group(2),
                    "type": "struct",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                }
            )

    # Enums
    enum_pattern = (
        r"^\s*(?:(public|internal|fileprivate|private)\s+)?(?:(indirect)\s+)?enum\s+(\w+)"
    )
    for match in re.finditer(enum_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            exports.append(
                {
                    "name": match.group(3),
                    "type": "enum",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                    "is_indirect": match.group(2) == "indirect",
                }
            )

    # Protocols
    protocol_pattern = r"^\s*(?:(public|internal|fileprivate|private)\s+)?protocol\s+(\w+)"
    for match in re.finditer(protocol_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            exports.append(
                {
                    "name": match.group(2),
                    "type": "protocol",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                }
            )

    # Actors
    actor_pattern = r"^\s*(?:(public|internal|fileprivate|private)\s+)?actor\s+(\w+)"
    for match in re.finditer(actor_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            exports.append(
                {
                    "name": match.group(2),
                    "type": "actor",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                }
            )

    # Functions
    func_pattern = r"^\s*(?:(public|open|internal|fileprivate|private)\s+)?(?:((?:static|class|mutating|async|throws|rethrows)\s+)*)func\s+(\w+)"
    for match in re.finditer(func_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access in ["public", "open"]:
            modifier_string = match.group(2).strip() if match.group(2) else ""
            modifiers = modifier_string.split() if modifier_string else []
            # Scan ahead to include post-parameter modifiers (e.g., "async throws") before the function body
            ahead = content[match.end() :]
            brace_match = re.search(r"\{", ahead)
            sig_tail = ahead[: brace_match.start()] if brace_match else ahead[:200]
            is_async = ("async" in modifiers) or bool(re.search(r"\basync\b", sig_tail))
            is_throwing = ("throws" in modifiers or "rethrows" in modifiers) or bool(
                re.search(r"\b(?:throws|rethrows)\b", sig_tail)
            )
            exports.append(
                {
                    "name": match.group(3),
                    "type": "function",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                    "modifiers": modifiers,
                    "is_async": is_async,
                    "is_throwing": is_throwing,
                }
            )

    # Properties
    prop_pattern = r"^\s*(?:(public|internal|fileprivate|private)\s+)?(?:(static|class|lazy|weak|unowned)\s+)?(let|var)\s+(\w+)"
    for match in re.finditer(prop_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            modifiers = match.group(2)
            prop_kind = match.group(3)
            prop_name = match.group(4)

            # Skip if it looks like a local variable
            if not self._is_likely_property(content, match.start()):
                continue

            exports.append(
                {
                    "name": prop_name,
                    "type": "property",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                    "is_constant": prop_kind == "let",
                    "is_variable": prop_kind == "var",
                    "modifier": modifiers,
                }
            )

    # Type aliases
    typealias_pattern = r"^\s*(?:(public|internal|fileprivate|private)\s+)?typealias\s+(\w+)"
    for match in re.finditer(typealias_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            exports.append(
                {
                    "name": match.group(2),
                    "type": "typealias",
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                }
            )

    # Extensions (public extensions export their methods)
    extension_pattern = r"^\s*(?:(public|internal|fileprivate|private)\s+)?extension\s+(\w+)"
    for match in re.finditer(extension_pattern, content, re.MULTILINE):
        access = match.group(1) or "internal"
        if access == "public":
            exports.append(
                {
                    "name": f"extension_{match.group(2)}",
                    "type": "extension",
                    "extended_type": match.group(2),
                    "line": content[: match.start()].count("\n") + 1,
                    "access_level": access,
                }
            )

    return exports
extract_structure
Python
extract_structure(content: str, file_path: Path) -> CodeStructure

Extract code structure from Swift file.

Extracts: - Classes, structs, enums, protocols, actors - Methods and properties - Extensions and protocol conformance - SwiftUI views and modifiers - UIKit components - Async/await patterns - Property wrappers - Computed properties and property observers

PARAMETERDESCRIPTION
content

Swift source code

TYPE:str

file_path

Path to the file being analyzed

TYPE:Path

RETURNSDESCRIPTION
CodeStructure

CodeStructure object with extracted elements

Source code in tenets/core/analysis/implementations/swift_analyzer.py
Python
def extract_structure(self, content: str, file_path: Path) -> CodeStructure:
    """Extract code structure from Swift file.

    Extracts:
    - Classes, structs, enums, protocols, actors
    - Methods and properties
    - Extensions and protocol conformance
    - SwiftUI views and modifiers
    - UIKit components
    - Async/await patterns
    - Property wrappers
    - Computed properties and property observers

    Args:
        content: Swift source code
        file_path: Path to the file being analyzed

    Returns:
        CodeStructure object with extracted elements
    """
    structure = CodeStructure()

    # Detect platform
    structure.is_ios = self._is_ios_file(content)
    structure.is_swiftui = self._is_swiftui_file(content)
    structure.is_uikit = self._is_uikit_file(content)

    # Extract classes
    class_pattern = r"""
        ^\s*(?:(public|open|internal|fileprivate|private)\s+)?
        (?:(final)\s+)?
        class\s+(\w+)
        (?:<([^>]+)>)?  # Generic parameters
        (?:\s*:\s*([^{]+?))?  # Inheritance/conformance
        \s*\{
    """

    for match in re.finditer(class_pattern, content, re.VERBOSE | re.MULTILINE):
        access = match.group(1) or "internal"
        is_final = match.group(2) == "final"
        class_name = match.group(3)
        generics = match.group(4)
        inheritance = match.group(5)

        # Parse inheritance and protocol conformance
        superclass = None
        protocols = []
        if inheritance:
            inherited = self._parse_inheritance(inheritance)
            # First item might be superclass (for classes)
            if inherited and not self._is_protocol(inherited[0]):
                superclass = inherited[0]
                protocols = inherited[1:]
            else:
                protocols = inherited

        # Extract class body
        class_body = self._extract_body(content, match.end())

        if class_body:
            methods = self._extract_methods(class_body)
            properties = self._extract_properties(class_body)
            nested_types = self._extract_nested_types(class_body)
        else:
            methods = []
            properties = []
            nested_types = []

        # Check for UIKit/SwiftUI types
        ui_type = None
        if structure.is_ios:
            if superclass:
                if "ViewController" in superclass:
                    ui_type = "view_controller"
                elif "View" in superclass and "UI" in superclass:
                    ui_type = "uiview"
                elif "ViewModel" in class_name:
                    ui_type = "view_model"

        class_info = ClassInfo(
            name=class_name,
            line=content[: match.start()].count("\n") + 1,
            access_level=access,
            is_final=is_final,
            is_open=access == "open",
            generics=generics,
            superclass=superclass,
            protocols=protocols,
            methods=methods,
            properties=properties,
            nested_types=nested_types,
            ui_type=ui_type,
        )

        structure.classes.append(class_info)

    # Extract structs
    struct_pattern = r"""
        ^\s*(?:(public|internal|fileprivate|private)\s+)?
        struct\s+(\w+)
        (?:<([^>]+)>)?
        (?:\s*:\s*([^{]+?))?
        \s*\{
    """

    for match in re.finditer(struct_pattern, content, re.VERBOSE | re.MULTILINE):
        struct_name = match.group(2)
        struct_body = self._extract_body(content, match.end())

        # Check if it's a SwiftUI View
        is_swiftui_view = False
        if match.group(4):
            protocols = self._parse_inheritance(match.group(4))
            is_swiftui_view = "View" in protocols

        structure.structs.append(
            {
                "name": struct_name,
                "line": content[: match.start()].count("\n") + 1,
                "access_level": match.group(1) or "internal",
                "generics": match.group(3),
                "protocols": self._parse_inheritance(match.group(4)) if match.group(4) else [],
                "methods": self._extract_methods(struct_body) if struct_body else [],
                "properties": self._extract_properties(struct_body) if struct_body else [],
                "is_swiftui_view": is_swiftui_view,
            }
        )

    # Extract enums
    enum_pattern = r"""
        ^\s*(?:(public|internal|fileprivate|private)\s+)?
        (?:(indirect)\s+)?
        enum\s+(\w+)
        (?:<([^>]+)>)?
        (?:\s*:\s*([^{]+?))?
        \s*\{
    """

    for match in re.finditer(enum_pattern, content, re.VERBOSE | re.MULTILINE):
        enum_name = match.group(3)
        enum_body = self._extract_body(content, match.end())

        # Parse raw value type or conformance
        raw_type = None
        protocols = []
        if match.group(5):
            inherited = self._parse_inheritance(match.group(5))
            # Check for raw value types
            if inherited and inherited[0] in ["Int", "String", "Double", "Float", "Character"]:
                raw_type = inherited[0]
                protocols = inherited[1:]
            else:
                protocols = inherited

        structure.enums.append(
            {
                "name": enum_name,
                "line": content[: match.start()].count("\n") + 1,
                "access_level": match.group(1) or "internal",
                "is_indirect": match.group(2) == "indirect",
                "generics": match.group(4),
                "raw_type": raw_type,
                "protocols": protocols,
                "cases": self._extract_enum_cases(enum_body) if enum_body else [],
                "methods": self._extract_methods(enum_body) if enum_body else [],
            }
        )

    # Extract protocols
    protocol_pattern = r"""
        ^\s*(?:(public|internal|fileprivate|private)\s+)?
        protocol\s+(\w+)
        (?:\s*:\s*([^{]+?))?
        \s*\{
    """

    for match in re.finditer(protocol_pattern, content, re.VERBOSE | re.MULTILINE):
        protocol_body = self._extract_body(content, match.end())

        structure.protocols.append(
            {
                "name": match.group(2),
                "line": content[: match.start()].count("\n") + 1,
                "access_level": match.group(1) or "internal",
                "inherited_protocols": (
                    self._parse_inheritance(match.group(3)) if match.group(3) else []
                ),
                "requirements": (
                    self._extract_protocol_requirements(protocol_body) if protocol_body else []
                ),
            }
        )

    # Extract actors
    actor_pattern = r"""
        ^\s*(?:(public|internal|fileprivate|private)\s+)?
        actor\s+(\w+)
        (?:\s*:\s*([^{]+?))?
        \s*\{
    """

    for match in re.finditer(actor_pattern, content, re.MULTILINE | re.VERBOSE):
        actor_body = self._extract_body(content, match.end())

        structure.actors.append(
            {
                "name": match.group(2),
                "line": content[: match.start()].count("\n") + 1,
                "access_level": match.group(1) or "internal",
                "protocols": self._parse_inheritance(match.group(3)) if match.group(3) else [],
                "methods": self._extract_methods(actor_body) if actor_body else [],
                "properties": self._extract_properties(actor_body) if actor_body else [],
            }
        )

    # Extract extensions
    extension_pattern = r"""
        ^\s*(?:(public|internal|fileprivate|private)\s+)?
        extension\s+(\w+)
        (?:\s*:\s*([^{]+?))?
        (?:\s+where\s+([^{]+?))?
        \s*\{
    """

    for match in re.finditer(extension_pattern, content, re.VERBOSE | re.MULTILINE):
        extension_body = self._extract_body(content, match.end())

        structure.extensions.append(
            {
                "extended_type": match.group(2),
                "line": content[: match.start()].count("\n") + 1,
                "access_level": match.group(1) or "internal",
                "protocols": self._parse_inheritance(match.group(3)) if match.group(3) else [],
                "where_clause": match.group(4),
                "methods": self._extract_methods(extension_body) if extension_body else [],
                "properties": (
                    self._extract_properties(extension_body) if extension_body else []
                ),
            }
        )

    # Extract global functions (including operators)
    func_pattern = r"""
        ^\s*(?:(public|internal|fileprivate|private)\s+)?
        (?:(static|class|mutating|async|throws|rethrows|prefix|postfix|infix)\s+)*
        func\s+(\w+|[+\-*/%=<>!&|^~?]+)  # Include operator symbols
        (?:<([^>]+)>)?  # Generic parameters
        \s*\([^)]*\)  # Parameters
        (?:\s*(?:async\s+)?(?:throws|rethrows))?  # Post-parameter modifiers
        (?:\s*->\s*([^{]+?))?  # Return type
        (?:\s+where\s+([^{]+?))?  # Where clause
        \s*\{
    """

    for match in re.finditer(func_pattern, content, re.VERBOSE | re.MULTILINE):
        # Simple check: if the function is not heavily indented, it's likely global
        line_start = content.rfind("\n", 0, match.start()) + 1
        line_content = content[line_start : match.start()]
        indent = len(line_content) - len(line_content.lstrip())

        # Functions with small indent (0-4 spaces) are likely global
        if indent <= 4:
            func_info = FunctionInfo(
                name=match.group(3),
                line=content[: match.start()].count("\n") + 1,
                access_level=match.group(1) or "internal",
                is_async="async" in content[match.start() : match.end()],
                is_throwing="throws" in content[match.start() : match.end()],
                generics=match.group(4),
                return_type=match.group(5).strip() if match.group(5) else "Void",
                where_clause=match.group(6),
            )
            structure.functions.append(func_info)

    # Count Swift-specific patterns
    structure.optional_count = len(re.findall(r"\w+\?(?:\s|,|\)|>)", content))
    structure.force_unwrap_count = len(re.findall(r"!(?:\.|,|\s|\))", content))
    structure.optional_chaining_count = len(re.findall(r"\?\.", content))
    structure.nil_coalescing_count = len(re.findall(r"\?\?", content))
    structure.guard_count = len(re.findall(r"\bguard\s+", content))
    structure.if_let_count = len(re.findall(r"\bif\s+let\s+", content))
    structure.guard_let_count = len(re.findall(r"\bguard\s+let\s+", content))

    # Count async/await
    structure.async_functions = len(
        re.findall(r"\basync\s+func\b|\bfunc\s+\w+[^{]*\basync\b", content)
    )
    structure.await_count = len(re.findall(r"\bawait\s+", content))

    # Count tasks more comprehensively
    task_patterns = [
        r"\bTask\s*\{",
        r"\bTask\.detached\s*\{",
        r"group\.addTask\s*\{",
    ]
    task_count = 0
    for pattern in task_patterns:
        task_count += len(re.findall(pattern, content))
    structure.task_count = task_count

    structure.actor_count = len(structure.actors)

    # Count property wrappers
    structure.property_wrappers = len(
        re.findall(
            r"@(?:State|StateObject|ObservedObject|Published|Binding|Environment|EnvironmentObject|AppStorage|SceneStorage|FocusState|GestureState)\b",
            content,
        )
    )

    # Count result builders
    structure.result_builders = len(
        re.findall(
            r"@(?:ViewBuilder|SceneBuilder|CommandsBuilder|ToolbarContentBuilder)\b", content
        )
    )

    # Count Combine usage
    structure.combine_publishers = len(
        re.findall(
            r"(?:Published|PassthroughSubject|CurrentValueSubject|AnyPublisher)", content
        )
    )
    structure.combine_operators = len(
        re.findall(
            r"\.(?:sink|map|filter|flatMap|combineLatest|merge|zip|debounce|throttle)\s*(?:\{|\()",
            content,
        )
    )

    # SwiftUI specific
    if structure.is_swiftui:
        structure.swiftui_views = len(
            [s for s in structure.structs if s.get("is_swiftui_view")]
        )
        structure.view_modifiers = len(
            re.findall(
                r"\.(?:padding|frame|background|foregroundColor|font|cornerRadius|shadow|overlay|offset|opacity|scaleEffect|rotationEffect|animation|transition)\s*\(",
                content,
            )
        )
        structure.body_count = len(re.findall(r"\bvar\s+body\s*:\s*some\s+View\s*\{", content))

    # Detect test file
    structure.is_test_file = (
        "Test" in file_path.name
        or file_path.name.endswith("Tests.swift")
        or any(part in ["Tests", "UITests", "test"] for part in file_path.parts)
    )

    # Detect main app entry
    structure.has_main = bool(
        re.search(r"@main\b", content)
        or re.search(r"@UIApplicationMain\b", content)
        or re.search(r"@NSApplicationMain\b", content)
    )

    return structure
calculate_complexity
Python
calculate_complexity(content: str, file_path: Path) -> ComplexityMetrics

Calculate complexity metrics for Swift code.

Calculates: - Cyclomatic complexity - Cognitive complexity - Optional handling complexity - Async/await complexity - SwiftUI/UIKit specific complexity - Protocol-oriented complexity

PARAMETERDESCRIPTION
content

Swift source code

TYPE:str

file_path

Path to the file being analyzed

TYPE:Path

RETURNSDESCRIPTION
ComplexityMetrics

ComplexityMetrics object with calculated metrics

Source code in tenets/core/analysis/implementations/swift_analyzer.py
Python
def calculate_complexity(self, content: str, file_path: Path) -> ComplexityMetrics:
    """Calculate complexity metrics for Swift code.

    Calculates:
    - Cyclomatic complexity
    - Cognitive complexity
    - Optional handling complexity
    - Async/await complexity
    - SwiftUI/UIKit specific complexity
    - Protocol-oriented complexity

    Args:
        content: Swift source code
        file_path: Path to the file being analyzed

    Returns:
        ComplexityMetrics object with calculated metrics
    """
    metrics = ComplexityMetrics()

    # Calculate cyclomatic complexity
    complexity = 1

    decision_keywords = [
        r"\bif\b",
        r"\belse\s+if\b",
        r"\belse\b",
        r"\bswitch\b",
        r"\bcase\b",
        r"\bfor\b",
        r"\bwhile\b",
        r"\brepeat\b",
        r"\bguard\b",
        r"\bcatch\b",
        r"&&",
        r"\|\|",
        r"\?\?",  # Nil coalescing
    ]

    for keyword in decision_keywords:
        complexity += len(re.findall(keyword, content))

    metrics.cyclomatic = complexity

    # Calculate cognitive complexity
    cognitive = 0
    nesting_level = 0
    max_nesting = 0

    lines = content.split("\n")
    for line in lines:
        # Skip comments
        if line.strip().startswith("//"):
            continue

        # Track nesting
        opening_braces = line.count("{")
        closing_braces = line.count("}")
        nesting_level += opening_braces - closing_braces
        max_nesting = max(max_nesting, nesting_level)

        # Control structures with nesting penalty
        control_patterns = [
            (r"\bif\b", 1),
            (r"\belse\s+if\b", 1),
            (r"\belse\b", 0),
            (r"\bswitch\b", 2),
            (r"\bfor\b", 1),
            (r"\bwhile\b", 1),
            (r"\brepeat\b", 1),
            (r"\bguard\b", 1),
            (r"\bcatch\b", 1),
        ]

        for pattern, weight in control_patterns:
            if re.search(pattern, line):
                cognitive += weight * (1 + max(0, nesting_level - 1))

    metrics.cognitive = cognitive
    metrics.max_depth = max_nesting

    # Count code elements
    metrics.line_count = len(lines)
    metrics.code_lines = len([l for l in lines if l.strip() and not l.strip().startswith("//")])
    metrics.comment_lines = len([l for l in lines if l.strip().startswith("//")])
    metrics.comment_ratio = (
        metrics.comment_lines / metrics.line_count if metrics.line_count > 0 else 0
    )

    # Count types
    metrics.class_count = len(re.findall(r"\bclass\s+\w+", content))
    metrics.struct_count = len(re.findall(r"\bstruct\s+\w+", content))
    metrics.enum_count = len(re.findall(r"\benum\s+\w+", content))
    metrics.protocol_count = len(re.findall(r"\bprotocol\s+\w+", content))
    metrics.extension_count = len(re.findall(r"\bextension\s+\w+", content))
    metrics.actor_count = len(re.findall(r"\bactor\s+\w+", content))

    # Optional handling metrics
    # Count optional type declarations more comprehensively
    optional_type_patterns = [
        r"\w+\?\s*(?:[,\)\]>=\n]|$)",  # Type? (more permissive ending)
        r"\w+!\s*(?:[,\)\]>=\n]|$)",  # Type! (implicitly unwrapped)
        r":\s*\w+\?\s*(?:[,=\{\n]|$)",  # : Type?
        r":\s*\w+!\s*(?:[,=\{\n]|$)",  # : Type!
        r"let\s+\w+:\s*\w+\?",  # let variable: Type?
        r"var\s+\w+:\s*\w+\?",  # var variable: Type?
        r"let\s+\w+:\s*\w+!",  # let variable: Type!
        r"var\s+\w+:\s*\w+!",  # var variable: Type!
    ]
    optional_count = 0
    for pattern in optional_type_patterns:
        optional_count += len(re.findall(pattern, content))
    metrics.optional_types = optional_count

    metrics.force_unwraps = len(re.findall(r"!(?:\.|,|\s|\))", content))
    metrics.optional_chaining = len(re.findall(r"\?\.", content))
    metrics.nil_coalescing = len(re.findall(r"\?\?", content))
    metrics.guard_statements = len(re.findall(r"\bguard\s+", content))
    metrics.if_let_bindings = len(re.findall(r"\bif\s+let\s+", content))
    metrics.guard_let_bindings = len(re.findall(r"\bguard\s+let\s+", content))

    # Async/await metrics
    metrics.async_functions = len(
        re.findall(r"\basync\s+func\b|\bfunc\s+\w+[^{]*\basync\b", content)
    )
    metrics.await_calls = len(re.findall(r"\bawait\s+", content))

    # Task patterns - more comprehensive detection
    task_patterns = [
        r"\bTask\s*\{",  # Task { }
        r"\bTask\.detached\s*\{",  # Task.detached { }
        r"group\.addTask\s*\{",  # group.addTask { }
        r"\bwithTaskGroup\s*\(",  # withTaskGroup
        r"\bwithThrowingTaskGroup\s*\(",  # withThrowingTaskGroup
    ]
    task_count = 0
    for pattern in task_patterns:
        task_count += len(re.findall(pattern, content))
    metrics.task_count = task_count

    # Task groups specifically
    task_group_patterns = [
        r"\bwithTaskGroup\s*\(",
        r"\bwithThrowingTaskGroup\s*\(",
        r"group\.addTask\s*\{",
    ]
    task_groups = 0
    for pattern in task_group_patterns:
        task_groups += len(re.findall(pattern, content))
    metrics.task_groups = task_groups

    metrics.main_actor = len(re.findall(r"@MainActor\b", content))

    # Error handling
    metrics.do_blocks = len(re.findall(r"\bdo\s*\{", content))
    metrics.try_statements = len(re.findall(r"\btry[!?]?\s+", content))
    metrics.catch_blocks = len(re.findall(r"\bcatch\s+", content))
    metrics.throw_statements = len(re.findall(r"\bthrow\s+", content))
    metrics.defer_statements = len(re.findall(r"\bdefer\s*\{", content))

    # Closures and functional programming
    metrics.closure_count = len(re.findall(r"\{[^}]*(?:in\s+|\$0)[^}]*\}", content))
    metrics.trailing_closures = len(re.findall(r"\)\s*\{[^}]*(?:in\s+|\$0)", content))
    metrics.higher_order_functions = len(
        re.findall(r"\.(?:map|filter|reduce|flatMap|compactMap|forEach)\s*(?:\{|\()", content)
    )

    # Property wrappers (SwiftUI and others)
    metrics.state_wrappers = len(re.findall(r"@State\b", content))
    metrics.stateobject_wrappers = len(re.findall(r"@StateObject\b", content))
    metrics.observedobject_wrappers = len(re.findall(r"@ObservedObject\b", content))
    metrics.published_wrappers = len(re.findall(r"@Published\b", content))
    metrics.binding_wrappers = len(re.findall(r"@Binding\b", content))
    metrics.environment_wrappers = len(re.findall(r"@Environment(?:Object)?\b", content))

    # SwiftUI specific
    if self._is_swiftui_file(content):
        metrics.swiftui_views = len(re.findall(r":\s*(?:some\s+)?View\s*\{", content))
        metrics.view_body_count = len(
            re.findall(r"\bvar\s+body\s*:\s*some\s+View\s*\{", content)
        )
        metrics.view_modifiers = len(
            re.findall(
                r"\.(?:padding|frame|background|foregroundColor|font|cornerRadius|shadow|overlay|offset|opacity|scaleEffect|rotationEffect|animation|transition)\s*\(",
                content,
            )
        )
        metrics.geometryreader_usage = len(re.findall(r"\bGeometryReader\s*\{", content))
        metrics.foreach_usage = len(re.findall(r"\bForEach\s*(?:\(|<)", content))

    # UIKit specific
    if self._is_uikit_file(content):
        metrics.viewcontroller_count = len(re.findall(r":\s*UI\w*ViewController", content))
        metrics.view_lifecycle = len(
            re.findall(r"\boverride\s+func\s+(?:viewDid|viewWill)", content)
        )
        metrics.iboutlet_count = len(re.findall(r"@IBOutlet\b", content))
        metrics.ibaction_count = len(re.findall(r"@IBAction\b", content))
        metrics.delegation_count = len(re.findall(r"delegate\s*=\s*self", content))

    # Combine framework
    metrics.combine_publishers = len(
        re.findall(
            r"(?:Published|PassthroughSubject|CurrentValueSubject|AnyPublisher)", content
        )
    )
    metrics.combine_subscriptions = len(re.findall(r"\.sink\s*\{", content))

    # Combine operators
    combine_operator_patterns = [
        r"\.map\s*\{",
        r"\.filter\s*\{",
        r"\.flatMap\s*\{",
        r"\.debounce\s*\(",
        r"\.removeDuplicates\s*\(",
        r"\.delay\s*\(",
        r"\.throttle\s*\(",
        r"\.combineLatest\s*\(",
        r"\.merge\s*\(",
        r"\.zip\s*\(",
        r"\.retry\s*\(",
        r"\.catch\s*\{",
        r"\.replaceError\s*\(",
        r"\.switchToLatest\s*\(",
    ]
    combine_operators = 0
    for pattern in combine_operator_patterns:
        combine_operators += len(re.findall(pattern, content))
    metrics.combine_operators = combine_operators

    # Access control
    metrics.public_declarations = len(
        re.findall(r"\bpublic\s+(?:class|struct|enum|protocol|func|var|let)\b", content)
    )
    metrics.private_declarations = len(
        re.findall(r"\bprivate\s+(?:class|struct|enum|protocol|func|var|let)\b", content)
    )
    metrics.fileprivate_declarations = len(
        re.findall(r"\bfileprivate\s+(?:class|struct|enum|protocol|func|var|let)\b", content)
    )

    # Calculate maintainability index
    import math

    if metrics.code_lines > 0:
        # Adjusted for Swift
        optional_safety_factor = 1 - (metrics.force_unwraps * 0.02)
        async_factor = 1 - (metrics.await_calls * 0.001)
        guard_factor = 1 + (metrics.guard_statements * 0.005)
        protocol_factor = 1 + (metrics.protocol_count * 0.01)

        mi = (
            171
            - 5.2 * math.log(max(1, complexity))
            - 0.23 * complexity
            - 16.2 * math.log(metrics.code_lines)
            + 10 * optional_safety_factor
            + 5 * async_factor
            + 5 * guard_factor
            + 5 * protocol_factor
        )
        metrics.maintainability_index = max(0, min(100, mi))

    return metrics

Functions