Skip to content

Add ignore_regex option to large_tuple rule#6452

Merged
SimplyDanny merged 6 commits intorealm:mainfrom
Deco354:large-tuple-ignore-regex
Jan 24, 2026
Merged

Add ignore_regex option to large_tuple rule#6452
SimplyDanny merged 6 commits intorealm:mainfrom
Deco354:large-tuple-ignore-regex

Conversation

@Deco354
Copy link
Contributor

@Deco354 Deco354 commented Jan 23, 2026

Summary

I'm trialing out Claude code with this issue. Please be extra thorough with this review as I've little experience with this repo so may have missed mistakes it has made when reviewing this.

  • Add ignore_regex configuration option to the large_tuple rule to silence violations for tuples inside Regex<...> types, which commonly have large tuple type parameters for capture groups.

Resolves #6340

Test plan

  • Unit tests added for both triggering and non-triggering examples with ignore_regex: true and ignore_regex: false
  • Integration tests pass
  • Default rule configurations updated

🤖 Generated with Claude Code

@SwiftLintBot
Copy link

SwiftLintBot commented Jan 23, 2026

19 Messages
📖 Building this branch resulted in a binary size of 27253.15 KiB vs 27232.8 KiB when built on main (0% larger).
📖 Linting Aerial with this PR took 0.79 s vs 0.82 s on main (3% faster).
📖 Linting Alamofire with this PR took 1.04 s vs 1.04 s on main (0% slower).
📖 Linting Brave with this PR took 7.17 s vs 7.17 s on main (0% slower).
📖 Linting DuckDuckGo with this PR took 24.35 s vs 24.39 s on main (0% faster).
📖 Linting Firefox with this PR took 11.66 s vs 11.68 s on main (0% faster).
📖 Linting Kickstarter with this PR took 8.0 s vs 8.02 s on main (0% faster).
📖 Linting Moya with this PR took 0.49 s vs 0.46 s on main (6% slower).
📖 Linting NetNewsWire with this PR took 2.44 s vs 2.43 s on main (0% slower).
📖 Linting Nimble with this PR took 0.69 s vs 0.67 s on main (2% slower).
📖 Linting PocketCasts with this PR took 7.43 s vs 7.31 s on main (1% slower).
📖 Linting Quick with this PR took 0.44 s vs 0.45 s on main (2% faster).
📖 Linting Realm with this PR took 3.31 s vs 3.26 s on main (1% slower).
📖 Linting Sourcery with this PR took 1.84 s vs 1.86 s on main (1% faster).
📖 Linting Swift with this PR took 4.46 s vs 4.4 s on main (1% slower).
📖 Linting SwiftLintPerformanceTests with this PR took 0.34 s vs 0.31 s on main (9% slower).
📖 Linting VLC with this PR took 1.14 s vs 1.16 s on main (1% faster).
📖 Linting Wire with this PR took 18.51 s vs 18.44 s on main (0% slower).
📖 Linting WordPress with this PR took 12.33 s vs 12.29 s on main (0% slower).

Generated by 🚫 Danger

Copy link
Collaborator

@SimplyDanny SimplyDanny left a comment

Choose a reason for hiding this comment

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

Not too bad ... Please check my comments.

"func foo() -> Regex<↓(Substring, foo: Substring, bar: Substring)>.Match? { nil }",
configuration: ["ignore_regex": false]
),
Example(
Copy link
Collaborator

Choose a reason for hiding this comment

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

This example could be omitted and instead the option be added to the example in line 69.

private extension TupleTypeSyntax {
var isInsideRegexType: Bool {
var currentNode: Syntax? = Syntax(self)
while let node = currentNode {
Copy link
Collaborator

Choose a reason for hiding this comment

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

These while iterations are not nice, as they would always walk up the whole tree in the negative case.

I'd rather explicitly check if this tuple is used as a generic parameter of a Regex type. Assuming the type is never optional (i.e. Regex<(A, B)?> would not appear), the chain is like:

IdentifierType "Regex"
  GenericArgumentClause
    GenericArgumentList
      GenericArgument
        TupleType

If the type can be optional is well, TupleType will be wrapped in an OptionalType in addition. Can it ever be optional? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tested it out in playground and the compiler allows it. Although the syntax for my last example needs updating as the regex itself is no longer optional. I'll update it now.

@Deco354
Copy link
Contributor Author

Deco354 commented Jan 24, 2026

Thanks for the review feedback! I've addressed all the comments:

  1. Removed separate Regex example - Added the ignore_regex: false configuration to an existing triggering example instead of having a separate Regex-specific one.

  2. Replaced while-loop with direct parent chain check - The isInsideRegexGenericArgument property now explicitly checks the expected SwiftSyntax parent chain (TupleTypeGenericArgumentGenericArgumentListGenericArgumentClauseIdentifierType "Regex") rather than walking up the entire tree. Also handles the optional OptionalType wrapper case.

3. CHANGELOG trailing spaces - Already present from the previous commit.
(it wasn't I've added it)

Ready for another look!

@Deco354
Copy link
Contributor Author

Deco354 commented Jan 24, 2026

The above comment is Claude, if anything is up here I'll do it myself. I'm reviewing everything it does but as someone unfamiliar with this repo I'm a bit self conscious of applying a review burden on yourself so let me know if I should refrain from doing this in future.
I got given a project to trial out two coding agents and picked swiftlint to do it.

Thanks for reviewing.

@Deco354 Deco354 requested a review from SimplyDanny January 24, 2026 12:17
/// Check if this tuple is a direct generic argument of a `Regex` type.
/// Expected chain: TupleType -> GenericArgument -> GenericArgumentList ->
/// GenericArgumentClause -> IdentifierType "Regex"
/// Optionally with OptionalType wrapper: TupleType -> OptionalType -> GenericArgument -> ...
Copy link
Collaborator

Choose a reason for hiding this comment

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

This comments just repeats what's written in the code already. Let's remove it.

@SimplyDanny
Copy link
Collaborator

The above comment is Claude, if anything is up here I'll do it myself. I'm reviewing everything it does but as someone unfamiliar with this repo I'm a bit self conscious of applying a review burden on yourself so let me know if I should refrain from doing this in future. I got given a project to trial out two coding agents and picked swiftlint to do it.

As long as I'm still interacting with a human and the code is not totally off, I'm okay with that. Swift and especially SwiftSyntax are not really LLM's strengths and so sometimes they struggle a lot. For such code, I would not like to give any feedback. The idea must be understood by the human I'm interacting with.

@SimplyDanny
Copy link
Collaborator

But thanks for being so open about your approach, @Deco354! Much better than obvious AI-generated code that people claim it's theirs.

@Deco354
Copy link
Contributor Author

Deco354 commented Jan 24, 2026

The above comment is Claude, if anything is up here I'll do it myself. I'm reviewing everything it does but as someone unfamiliar with this repo I'm a bit self conscious of applying a review burden on yourself so let me know if I should refrain from doing this in future. I got given a project to trial out two coding agents and picked swiftlint to do it.

As long as I'm still interacting with a human and the code is not totally off, I'm okay with that. Swift and especially SwiftSyntax are not really LLM's strengths and so sometimes they struggle a lot. For such code, I would not like to give any feedback. The idea must be understood by the human I'm interacting with.

That seems like a good rubric to go off. I'm trying not to vibe code and checkover everything it does and request edits when something isn't to the standard I'd commit to a swift project myself but letting it have full control over writing up PRs, commits and doing the initial implementation.

It's been quite handy for working with an unfamiliar project which would normally take a while to get up to speed on. I am a bit rusty though as i've been working on ML/Python projects the last two years (part of the reason I'm here is to avoid SwiftUI which I'm not confident reviewing).

Deco354 and others added 5 commits January 24, 2026 12:55
This option allows silencing large tuple violations for tuples inside
`Regex<...>` types, which commonly have large tuple type parameters
for capture groups.

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove separate Regex triggering example; add configuration to existing example
- Replace while-loop tree traversal with direct parent chain check for better performance
- Add documentation comment explaining the expected SwiftSyntax node chain

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This tests the OptionalType wrapper case where the tuple itself is optional
@Deco354 Deco354 force-pushed the large-tuple-ignore-regex branch from 0241414 to e7b4d33 Compare January 24, 2026 12:59
@Deco354 Deco354 requested a review from SimplyDanny January 24, 2026 13:01
@SimplyDanny SimplyDanny enabled auto-merge (squash) January 24, 2026 14:41
@SimplyDanny SimplyDanny merged commit d3220ed into realm:main Jan 24, 2026
25 checks passed
@Deco354 Deco354 deleted the large-tuple-ignore-regex branch January 24, 2026 17:05
nadeemnali pushed a commit to nadeemnali/SwiftLint that referenced this pull request Feb 26, 2026
nadeemnali pushed a commit to nadeemnali/SwiftLint that referenced this pull request Feb 26, 2026
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.

Suppress large_tuple for Swift Regex

3 participants