-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
New Issue Checklist
- I've Updated SwiftLint to the latest version.
- I've searched for existing GitHub issues.
Bug Description
The accessibility_label_for_image rule incorrectly flags images within SwiftUI Label components as violations, even though Label automatically provides accessibility context through its text content.
In SwiftUI, when using Label with the expanded closure syntax, the text block provides the accessibility label for the entire component, including the icon. The image is decorative within this context and doesn't need a separate accessibility label.
Example that triggers false positive:
Label {
Text("Connected")
} icon: { // Violation here
Image(systemName: "checkmark.circle.fill")
}This is semantically equivalent to:
Label("Connected", systemImage: "checkmark.circle.fill") // No violationBoth produce identical accessibility behavior; VoiceOver reads "Connected" for the entire label. The rule should recognize that images within Label icon closures are inherently labeled.
Current behavior: Violation triggered
Expected behavior: No violation - the image has accessibility context from the Label's text
Environment
- SwiftLint version: 0.62.2
- Xcode version: Xcode 26.2; Build version 17C52
- Installation method: [SPM]
- Configuration file:
# From https://github.com/Lickability/swift-best-practices/blob/main/.swiftlint.yml
# You can reference documentation on rules here https://realm.github.io/SwiftLint/rule-directory.html
disabled_rules: # rule identifiers to exclude from running
- attributes
- closure_end_indentation
- cyclomatic_complexity
- discouraged_object_literal
- discouraged_optional_collection
- explicit_acl
- explicit_enum_raw_value
- explicit_top_level_acl
- explicit_type_interface
- extension_access_modifier
- file_length
- file_types_order
- function_body_length
- function_parameter_count
- generic_type_name
- identifier_name
- implicit_return
- large_tuple
- let_var_whitespace
- line_length
- literal_expression_end_indentation
- multiline_arguments
- multiline_arguments_brackets
- multiline_literal_brackets
- multiline_parameters_brackets
- nesting
- nimble_operator
- no_extension_access_modifier
- no_grouping_extension
- nslocalizedstring_require_bundle
- number_separator
- object_literal
- prefixed_toplevel_constant
- quick_discouraged_call
- quick_discouraged_focused_test
- quick_discouraged_pending_test
- raw_value_for_camel_cased_codable_enum
- reduce_into
- redundant_self_in_closure
- redundant_string_enum_value
- required_deinit
- sorted_enum_cases
- sorted_imports
- strict_fileprivate
- superfluous_else
- switch_case_on_newline
- todo
- trailing_closure
- trailing_whitespace
- type_body_length
- type_contents_order
- type_name
- unneeded_parentheses_in_closure_argument
- vertical_whitespace_between_cases
- vertical_whitespace_opening_braces
- xct_specific_matcher
opt_in_rules: # some rules are only opt-in
- accessibility_label_for_image
- accessibility_trait_for_button
- array_init
- block_based_kvo
- class_delegate_protocol
- closing_brace
- closure_parameter_position
- closure_spacing
- collection_alignment
- colon
- comma
- compiler_protocol_init
- conditional_returns_on_newline
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- control_statement
- convenience_type
- custom_todo
- direct_return
- discarded_notification_center_observer
- discouraged_direct_init
- discouraged_optional_boolean
- duplicate_enum_cases
- duplicate_imports
- dynamic_inline
- empty_collection_literal
- empty_count
- empty_enum_arguments
- empty_parameters
- empty_parentheses_with_trailing_closure
- empty_string
- empty_xctest_method
- explicit_init
- fallthrough
- fatal_error_message
- file_header
- first_where
- flatmap_over_map_reduce
- for_where
- force_cast
- force_try
- force_unwrapping
- function_name_whitespace
- identical_operands
- implicit_getter
- implicit_optional_initialization
- implicitly_unwrapped_optional
- is_disjoint
- joined_default_parameter
- last_where
- leading_whitespace
- legacy_cggeometry_functions
- legacy_constant
- legacy_constructor
- legacy_hashing
- legacy_multiple
- legacy_nsgeometry_functions
- local_doc_comment
- lower_acl_than_parent
- mark
- multiline_parameters
- multiple_closures_with_trailing_closure
- no_space_in_method_call
- non_overridable_class_declaration
- notification_center_detachment
- nslocalizedstring_key
- opening_brace
- operator_usage_whitespace
- overridden_super_call
- override_in_extension
- pattern_matching_keywords
- period_spacing
- prefer_self_in_static_references
- prefer_self_type_over_type_of_self
- prefer_zero_over_explicit_init
- private_action
- private_outlet
- private_over_fileprivate
- private_subject
- private_swiftui_state
- private_unit_test
- prohibited_super_call
- protocol_property_accessors_order
- reduce_boolean
- redundant_discardable_let
- redundant_nil_coalescing
- redundant_objc_attribute
- redundant_void_return
- required_enum_case
- return_arrow_whitespace
- return_value_from_void_function
- shorthand_operator
- single_test_class
- sorted_first_last
- statement_position
- superfluous_disable_command
- switch_case_alignment
- syntactic_sugar
- test_case_accessibility
- trailing_comma
- trailing_newline
- trailing_semicolon
- unavailable_function
- unneeded_break_in_switch
- unneeded_override
- unneeded_synthesized_initializer
- unused_closure_parameter
- unused_control_flow_label
- unused_enumerated
- unused_optional_binding
- unused_setter_value
- valid_ibinspectable
- vertical_parameter_alignment
- vertical_parameter_alignment_on_call
- vertical_whitespace
- vertical_whitespace_closing_braces
- void_return
- weak_delegate
- xctfail_message
- yoda_condition
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
file_header:
required_pattern: |
\/\/
\/\/ .*?
\/\/ .*?
\/\/
\/\/ Created by .*? on \d{1,2}\/\d{1,2}\/(\d{2}|\d{4})\.
\/\/ Copyright (©|\(c\)) \d{4} .*?\. All rights reserved\.
\/\/
custom_rules:
force_https:
name: "Force HTTPS over HTTP"
regex: "((?i)http(?!s))"
match_kinds: string
message: "HTTPS should be favored over HTTP"
severity: warning
custom_todo:
name: "TODO Violation"
regex: "(TODO).(?!.*(https&)).(?!.*issue)"
match_kinds: comment
message: "TODOs must include a link to the issue."
severity: warning