Closed chandlerwall closed 5 months ago
I checked out SwiftLint's source to debug the issue a bit and found the cause: SwiftLintCore.SwiftVersion
does not compare string versions reliably, preventing version-specific workarounds from being applied.
For Swift 5.10, version-specific workarounds are not applied correctly. Specifically, LintableFilesVisitor.parallel
is assigned true
instead of false
when SwiftVersion.current < .fiveDotSix
returns an incorrect value.
I replaced SwiftVersion
with the following:
/// A value describing the version of the Swift compiler.
public struct SwiftVersion: RawRepresentable, Codable, Comparable, Sendable {
public typealias RawValue = String
public let rawValue: String
public init(rawValue: String) {
self.rawValue = rawValue
}
public static func < (lhs: SwiftVersion, rhs: SwiftVersion) -> Bool {
func versionComponents(from version: String) -> [Int] {
return version.components(separatedBy: ".").compactMap { Int($0) }
}
let lhsComponents = versionComponents(from: lhs.rawValue)
let rhsComponents = versionComponents(from: rhs.rawValue)
for (lhsComponent, rhsComponent) in zip(lhsComponents, rhsComponents) {
if lhsComponent < rhsComponent {
return true
} else if lhsComponent > rhsComponent {
return false
}
}
return lhsComponents.count < rhsComponents.count
}
}
Note: I used Claude to implement static func < (lhs:rhs:)
. I wanted to save time while troubleshooting. The implementation may or may not handle edge cases correctly. I only verified the implementation for my environment.
With the changes in place, I'm able to run swiftlint analyze
on a larger set of files. The run below was limited to 30 files. I also verified the result on a run with 350+ files.
Analyzing Swift files in current working directory
Collecting 'Modules/Sources/StyleGuide/_exported.swift' (1/30)
Collecting 'SomethingsWrong.swift' (2/30)
Collecting 'ToolbarMenuButton.swift' (3/30)
Collecting 'ShowInMusicMenuButton.swift' (4/30)
Collecting 'View+hidden.swift' (5/30)
Collecting 'View+foregroundStyle.swift' (6/30)
Collecting 'View+dimensionOverlay.swift' (7/30)
Collecting 'View+enabled.swift' (8/30)
Collecting 'View+firstTextCenterline.swift' (9/30)
Collecting 'HeaderTitle.swift' (10/30)
Collecting 'ExplicitTitle.swift' (11/30)
Collecting 'LabelStyle.swift' (12/30)
Collecting 'StyleGuide.swift' (13/30)
Collecting 'ActiveTrackIcon.swift' (14/30)
Collecting 'FontPreview.swift' (15/30)
Collecting 'CountsView.swift' (16/30)
Collecting 'NoSearchResults.swift' (17/30)
Collecting 'LibraryIcon.swift' (18/30)
Collecting 'PresentationState.swift' (19/30)
Collecting 'AlertPresentation.swift' (20/30)
Collecting 'ConfirmationDialogPresentation.swift' (21/30)
Collecting 'Symbol.swift' (22/30)
Collecting 'SearchControllerProxy.swift' (23/30)
Collecting 'EnvironmentAction.swift' (24/30)
Collecting 'Resolvable.swift' (25/30)
Collecting 'SearchableUIHostingController.swift' (26/30)
Collecting 'SearchScope.swift' (27/30)
Collecting 'RelativeTimeframe.swift' (28/30)
Collecting 'SimilarityResult.swift' (29/30)
Collecting 'Counts.swift' (30/30)
Analyzing 'Modules/Sources/StyleGuide/_exported.swift' (1/30)
Analyzing 'SomethingsWrong.swift' (2/30)
Analyzing 'ToolbarMenuButton.swift' (3/30)
Analyzing 'ShowInMusicMenuButton.swift' (4/30)
Analyzing 'View+hidden.swift' (5/30)
Analyzing 'View+foregroundStyle.swift' (6/30)
Analyzing 'View+dimensionOverlay.swift' (7/30)
Analyzing 'View+enabled.swift' (8/30)
Analyzing 'View+firstTextCenterline.swift' (9/30)
Analyzing 'HeaderTitle.swift' (10/30)
Analyzing 'ExplicitTitle.swift' (11/30)
Analyzing 'LabelStyle.swift' (12/30)
Analyzing 'StyleGuide.swift' (13/30)
Analyzing 'ActiveTrackIcon.swift' (14/30)
Analyzing 'FontPreview.swift' (15/30)
Analyzing 'CountsView.swift' (16/30)
Analyzing 'NoSearchResults.swift' (17/30)
Analyzing 'LibraryIcon.swift' (18/30)
Analyzing 'PresentationState.swift' (19/30)
Analyzing 'AlertPresentation.swift' (20/30)
Analyzing 'ConfirmationDialogPresentation.swift' (21/30)
Analyzing 'Symbol.swift' (22/30)
Analyzing 'SearchControllerProxy.swift' (23/30)
Analyzing 'EnvironmentAction.swift' (24/30)
Analyzing 'Resolvable.swift' (25/30)
Analyzing 'SearchableUIHostingController.swift' (26/30)
Analyzing 'SearchScope.swift' (27/30)
Analyzing 'RelativeTimeframe.swift' (28/30)
Analyzing 'SimilarityResult.swift' (29/30)
Analyzing 'Counts.swift' (30/30)
Done analyzing! Found 0 violations, 0 serious in 30 files.
Can the stop of analysis be associated with a specific file maybe?
Can the stop of analysis be associated with a specific file maybe?
I started my troubleshooting by adjusting included
and excluded
to find a problematic file. I started with a small number of files and gradually included more files until the issue occurred. I thought I found the problematic file. I added more files and noticed the issue again. I tested different combinations and realized I could move "problematic" files from excluded
to included
without triggering the issue. As long as I keep the file count very low, the command finished. As soon as I added an extra file, the command chokes.
Forget my previous question. You were obviously a little faster with the detailed report of your investigation. I didn't notice it while crafting my message.
Your reasoning makes a lot of sense. Looks like SwiftVersion
wasn't developed with version components >9 in mind or the implementors didn't expect such high numbers.
Would you like to open a PR to fix the comparison algorithm?
Yes, I will prepare a PR with a fix for the comparison algorithm. Appreciate the quick responses!
I'm seeing the exact same thing. For me it stops after 14 files, no matter what file that is.
New Issue Checklist
Describe the bug
After upgrading to Xcode 15.3 and Swift 5.10,
swiftlint analyze
appears to stop collecting files. For my environment, the console output stops updating after collecting 12 files. If I adjustincluded
orexcluded
to 12 or fewer files, I can reliably avoid the issue.Complete output when running SwiftLint, including the stack trace and command used
Environment
SwiftLint version (run
swiftlint version
to be sure)?Installation method used (Homebrew, CocoaPods, building from source, etc)?
Paste your configuration file:
Are you using nested configurations?
Which Xcode version are you using (check
xcodebuild -version
)?Do you have a sample that shows the issue? Run
echo "[string here]" | swiftlint lint --no-cache --use-stdin --enable-all-rules
to quickly test if your example is really demonstrating the issue. If your example is more complex, you can useswiftlint lint --path [file here] --no-cache --enable-all-rules
.