Skip to content

Fix crash on imports with attributes on their own line - #366

Merged
sidepelican merged 1 commit into
uber:masterfrom
bielikb:fix/attributed-import-crash
Nov 14, 2026
Merged

sidepelican merged 1 commit into
uber:masterfrom
bielikb:fix/attributed-import-crash

Conversation

@bielikb

@bielikb bielikb commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Problem

mockolo traps (SIGTRAP, exit 133, Fatal error: Range requires lowerBound <= upperBound) when a source file has an import whose attribute is on its own line:

@diagnose(UnusedImportAccess, as: ignored)
import Foundation
/// @mockable
public protocol P { func f() }

The same happens for @preconcurrency on its own line, or an attribute wrapped in #if. The last case is now common: swift-openapi-generator 1.14+ starts every generated file with

#if compiler(>=6.4)
@diagnose(UnusedImportAccess, as: ignored)
#endif
@_spi(Generated) public import OpenAPIRuntime

so running mockolo over any target with OpenAPI-generated code crashes (reproduced with 2.6.1, 2.7.0 and current master).

Root cause

Import(line:) parsed node.trimmedDescription as text and sliced it between the first and last newline. With a newline between the attribute and import, the end index lands before the import keyword and the moduleName range is invalid. Single-line attributes didn't crash, but they made the modifier unparsable, so @_spi(X) public import Y lost its access level.

Fix

Build Import from ImportDeclSyntax instead of from its text: module path (plus import kind, e.g. struct Foundation.URL), @testable from the attributes, access level from the modifiers. Other attributes are still dropped, as before. One small behavior change: the access level is now kept when an import also has an attribute (@_spi(X) public import Y → public import Y, previously import Y), consistent with how plain public import Y is handled.

Tests

Added to ACLImportTests:

  • testAttributedImports: single-line and own-line attributes (@_spi, @preconcurrency, @_implementationOnly, @testable, @diagnose), including inside an #if import block.
  • testOpenAPIGeneratorImportHeader: the swift-openapi-generator header above, plus @preconcurrency public import struct Foundation.URL under #if os(Linux).

Both crash the test process without the fix. Full suite passes locally (Xcode 27.0 / Swift 6.4).

🤖 Generated with Claude Code

Fixes #367

`Import(line:)` parsed the import's source text and sliced it between the
first and last newline. When an attribute sits on its own line (e.g.
`@diagnose(...)` or `@preconcurrency` above `import X`, or a `#if`-wrapped
attribute as emitted by swift-openapi-generator 1.14+), the end index lands
before the `import ` keyword and the range construction traps.

Build `Import` from `ImportDeclSyntax` instead: module path (plus import kind,
e.g. `struct Foundation.URL`), `@testable` from the attributes, and the access
level from the modifiers. Other attributes are dropped as before; the access
level is now kept when an import also has an attribute
(`@_spi(X) public import Y` -> `public import Y`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sidepelican sidepelican left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good way. Thank you.

@sidepelican
sidepelican merged commit a9335fd into uber:master Nov 14, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash (SIGTRAP, exit 133) on imports with an attribute on its own line

2 participants