Skip to content

unused_import: require_explicit_imports: true requires explicit importing of "hidden" modules whose names begin with an underscore #6260

@rgoldberg

Description

@rgoldberg

New Issue Checklist

Bug Description

unused_import: require_explicit_imports: true requires explicit importing of "hidden" modules whose names begin with an underscore, e.g., _DarwinFoundation1, which seems to be available on Xcode 26 on macOS 26, but not on Xcode 16.4 on macOS 15.6.1.

I'm guessing that all modules whose names begin with an underscore are "hidden", and thus not guaranteed to be available in different toolchain versions.

Instead of requiring that they be imported, the rule should only require the lowest module whose name does not start with an underscore. e.g., if Darwin makes _DarwinFoundation1, _DarwinFoundation2, & _DarwinFoundation3 available, and no modules whose names don't start with an underscore are closer in the module tree than Darwin to the hidden modules, then require importing Darwin instead of those 3.

// This triggers a violation:
private import Darwin

func test() {
	floor(123 / 1000)
}

Unfortunately, I just noticed that the problem exists for other modules whose names don't start with an underscore.

Besides ignoring all modules whose name begins with an underscore, you should also be able to configure leaf modules without specifying exactly what modules they can transitively provide. I should be able to just say, e.g., that Darwin is a leaf module; if a module is transitively provided by Darwin, regardless of its name, do not require that it be explicitly imported.

Mention the command or other SwiftLint integration method that caused the issue. Include stack traces or command output.

$ swiftlint analyze --strict --quiet --reporter relative-path --compiler-log-path /path/to/Xcode.log

Environment

  • SwiftLint 0.61.0
  • Xcode 26.0.1 (17A400)
  • Installation Homebrew core
  • Configuration file:
---
excluded:
- .build/
- .idea/
- .swiftpm/
opt_in_rules:
- all
analyzer_rules:
- all
disabled_rules:
- contrasted_opening_brace
- explicit_acl
- explicit_enum_raw_value
- explicit_self
- explicit_top_level_acl
- explicit_type_interface
- file_header
- no_extension_access_modifier
- no_grouping_extension
- no_magic_numbers
- prefixed_toplevel_constant
- sorted_enum_cases
- strict_fileprivate
- vertical_whitespace_between_cases
- void_function_in_ternary
attributes:
  always_on_line_above: ['@MainActor', '@OptionGroup']
closure_body_length:
  warning: 35
cyclomatic_complexity:
  ignores_case_statements: true
  warning: 11
deployment_target:
  macOS_deployment_target: 10.15
  macOSApplicationExtension_deployment_target: 10.15
  iOS_deployment_target: 99
  iOSApplicationExtension_deployment_target: 99
  tvOS_deployment_target: 99
  tvOSApplicationExtension_deployment_target: 99
  watchOS_deployment_target: 99
  watchOSApplicationExtension_deployment_target: 99
explicit_init:
  include_bare_init: true
file_length:
  ignore_comment_only_lines: true
file_name:
  excluded: [Finder.swift, SpotlightInstalledApps.swift]
file_types_order:
  order:
  - main_type
  - supporting_type
  - extension
  - preview_provider
  - library_content_provider
function_body_length:
  warning: 75
indentation_width:
  indentation_width: 2
  include_multiline_strings: false
line_length:
  ignores_multiline_strings: true
multiline_arguments:
  first_argument_location: next_line
non_optional_string_data_conversion:
  include_variables: true
number_separator:
  minimum_length: 6
opening_brace:
  ignore_multiline_statement_conditions: true
operator_usage_whitespace:
  skip_aligned_constants: false
prefer_key_path:
  restrict_to_standard_functions: false
private_over_fileprivate:
  validate_extensions: true
redundant_type_annotation:
  consider_default_literal_types_redundant: true
trailing_comma:
  mandatory_comma: true
trailing_whitespace:
  ignores_comments: false
type_contents_order:
  order:
  - case
  - associated_type
  - type_alias
  - subtype
  - type_property
  - instance_property
  - ib_inspectable
  - ib_outlet
  - initializer
  - deinitializer
  - type_method
  - view_life_cycle_method
  - ib_action
  - other_method
  - subscript
unneeded_override:
  affect_initializers: true
unused_import:
  require_explicit_imports: true

Are you using nested configurations? No

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions