Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix superfluous disable command for custom_rules #5670

Conversation

mildm8nnered
Copy link
Collaborator

@mildm8nnered mildm8nnered commented Jul 13, 2024

So this is a kind of scary PR - addresses #4754 - The superfluous_disable_command rule should work for individual custom_rules.

#4755 attempted to address this, but had issues, and was reverted in #5336

This PR is based on @marcelofabri 's work in #4755 with a few additional fixes.

A fair few times I thought I had this cracked, only to find a big hole. I think it's right now, but this PR definitely deserves additional scrutiny.

Consider the example below:

custom_rules:
  forbidden:
    regex: 'FORBIDDEN'
    message: "This is forbidden"
    severity: warning

The following code should trigger a superfluous_disable_command violation:

let FORBIDDEN = 1
// swiftlint:disable:next forbidden
let ALLOWED = 2

Today this would produce:

% swiftlint --config t.config t.swift --quiet
/Some/Path/To/t.swift:1:5: warning: forbidden Violation: This is forbidden (forbidden)

and after this PR is applied, we get:

% swiftlint.debug --config t.config t.swift --quiet
/Some/Path/To/t.swift:1:5: warning: forbidden Violation: This is forbidden (forbidden)
/Some/Path/To/t.swift:3:1: warning: Superfluous Disable Command Violation: SwiftLint rule 'forbidden' did not trigger a violation in the disabled region; remove the disable command (superfluous_disable_command)

It is currently also possible to disable all custom rules with:

// swiftlint:disable:next custom_rules
let FORBIDDEN = 1

That behaviour is still supported.

@SwiftLintBot
Copy link

SwiftLintBot commented Jul 13, 2024

17 Messages
📖 Linting Aerial with this PR took 0.95s vs 0.93s on main (2% slower)
📖 Linting Alamofire with this PR took 1.27s vs 1.28s on main (0% faster)
📖 Linting Brave with this PR took 7.46s vs 7.44s on main (0% slower)
📖 Linting DuckDuckGo with this PR took 4.87s vs 4.89s on main (0% faster)
📖 Linting Firefox with this PR took 10.94s vs 10.97s on main (0% faster)
📖 Linting Kickstarter with this PR took 10.05s vs 10.08s on main (0% faster)
📖 Linting Moya with this PR took 0.52s vs 0.53s on main (1% faster)
📖 Linting NetNewsWire with this PR took 2.55s vs 2.55s on main (0% slower)
📖 Linting Nimble with this PR took 0.76s vs 0.76s on main (0% slower)
📖 Linting PocketCasts with this PR took 8.57s vs 8.7s on main (1% faster)
📖 Linting Quick with this PR took 0.43s vs 0.43s on main (0% slower)
📖 Linting Realm with this PR took 4.68s vs 4.69s on main (0% faster)
📖 Linting Sourcery with this PR took 2.34s vs 2.34s on main (0% slower)
📖 Linting Swift with this PR took 4.57s vs 4.57s on main (0% slower)
📖 Linting VLC with this PR took 1.25s vs 1.25s on main (0% slower)
📖 Linting Wire with this PR took 18.23s vs 18.25s on main (0% faster)
📖 Linting WordPress with this PR took 11.82s vs 11.79s on main (0% slower)

Generated by 🚫 Danger

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 3 times, most recently from 8c02874 to 15da439 Compare July 18, 2024 01:55
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 3 times, most recently from 1cae064 to 44af4af Compare July 27, 2024 15:05
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 2 times, most recently from 1d55b97 to d37875b Compare July 28, 2024 18:06
@mildm8nnered mildm8nnered changed the title Fix superfluous disable command for custom rule again Fix superfluous disable command for custom_rules Jul 28, 2024
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 2 times, most recently from 776cd9d to 88051e0 Compare August 1, 2024 23:22
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 3 times, most recently from cb3a854 to 11e4322 Compare August 9, 2024 21:39
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 2 times, most recently from 4e95358 to 36d4ca6 Compare August 20, 2024 16:22
@mildm8nnered mildm8nnered marked this pull request as ready for review August 22, 2024 07:42
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch 2 times, most recently from cf7183c to 0cdf41e Compare August 24, 2024 10:40
@@ -46,7 +46,10 @@ public struct Region: Equatable {
///
/// - returns: True if the specified rule is disabled in this region.
public func isRuleDisabled(_ rule: some Rule) -> Bool {
areRulesDisabled(ruleIDs: type(of: rule).description.allIdentifiers)
if let rule = rule as? CustomRules {
return areRulesDisabled(ruleIDs: rule.customRuleIdentifiers + [type(of: rule).description.identifier])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this mean a custom rule custom_1 will be disabled if custom_2 is actually named in the disable command? rule.customRuleIdentifiers are all custom identifiers defined, aren't they?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So this specific function will return true in that case, yes, but the actual identifiers will be checked afterwards, here in the construction of identifiersWithRegions

    func superfluousDisableCommandViolations(regions: [Region],
                                             superfluousDisableCommandRule: SuperfluousDisableCommandRule?,
                                             allViolations: [StyleViolation]) -> [StyleViolation] {
        guard regions.isNotEmpty, let superfluousDisableCommandRule else {
            return []
        }

        let regionsDisablingSuperfluousDisableRule = regions.filter { region in
            region.isRuleDisabled(superfluousDisableCommandRule)
        }

        let identifiersWithRegions: [(String, [Region])] = {

The proof of the pudding 🤞 is (slightly expanded for clarity):

    func testUnviolatedSpecificCustomRulesTriggersSuperfluousDisableCommand() throws {
        let customRules =         [
            "forbidden": [
                "regex": "FORBIDDEN",
            ],
            "forbidden2": [
                "regex": "FORBIDDEN2",
            ],
        ]

        let example = Example("""
                              // swiftlint:disable:next forbidden forbidden2
                              let FORBIDDEN = 1
                              """)

        let violations = try self.violations(forExample: example, customRules: customRules)
        XCTAssertEqual(violations.count, 1)
        XCTAssertTrue(violations[0].isSuperfluousDisableCommandViolation(for: "forbidden2"))
    }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm wondering if a naming change might make this clearer, but I don't have a good candidate ...

Source/SwiftLintCore/Rules/CustomRules.swift Outdated Show resolved Hide resolved
Source/SwiftLintCore/Rules/CustomRules.swift Show resolved Hide resolved
Source/SwiftLintCore/Models/Linter.swift Outdated Show resolved Hide resolved
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch from 0cdf41e to 94488d7 Compare August 25, 2024 12:26
@SimplyDanny
Copy link
Collaborator

SimplyDanny commented Aug 31, 2024

I still have my concerns with the special handling of custom rules and some improvement ideas in my backlog.

Do you mind if I push some changes to your branch later?

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch from ea19066 to db114fb Compare August 31, 2024 13:05
@mildm8nnered
Copy link
Collaborator Author

I still have my concerns with the special handling of custom rules and some improvement ideas in my backlog.

Do you mind if I push some changes to your branch later?

Yes, I think there are still some oddities outside of superfluous_disable

Feel free to add more changes!

@SimplyDanny
Copy link
Collaborator

I managed to avoid explicit type checks at a few places. There are more in other (untouched) code, though, that we should get rid of in the long run.

Please check if my changes make sense to you, @mildm8nnered.

}

let customRulesIDs: [String] = {
guard let customRules = self as? CustomRules else {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps we could get rid of this by letting Self.description.allIdentifiers contain the custom IDs in case of custom rules.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I couldn't see an easy way to customize allIdentifiers, as the RuleDescription currently can't see the configuration :-(

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, also what I struggled with. We'd need to move allIdentifiers into Rule, but this has other disadvantages. So let's not bother with that in this PR. I think it's good as it is. The special handling of custom rules is a broader topic we may address in follow-ups.

@mildm8nnered
Copy link
Collaborator Author

I managed to avoid explicit type checks at a few places. There are more in other (untouched) code, though, that we should get rid of in the long run.

Please check if my changes make sense to you, @mildm8nnered.

So it may take me a while to digest those, but straight away it looks a lot shorter and cleaner.

One change request - I think you should add yourself to the authors in the changelog.

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch from 7abd386 to 17eb866 Compare September 7, 2024 19:33
@mildm8nnered
Copy link
Collaborator Author

I managed to avoid explicit type checks at a few places. There are more in other (untouched) code, though, that we should get rid of in the long run.
Please check if my changes make sense to you, @mildm8nnered.

So it may take me a while to digest those, but straight away it looks a lot shorter and cleaner.

One change request - I think you should add yourself to the authors in the changelog.

I think your changes look great @SimplyDanny. Am I ok to hit merge on this? Hopefully we'll do better than #4755 🤞

@SimplyDanny SimplyDanny merged commit 06e4e3c into realm:main Sep 7, 2024
13 checks passed
@SimplyDanny
Copy link
Collaborator

Am I ok to hit merge on this?

Oh, I misread this as a statement. Just merged it. 🫣

Hopefully we'll do better than #4755 🤞

People will let us know ... 😅

@mildm8nnered mildm8nnered deleted the mildm8nnered-fix-superfluous-disable-command-for-custom-rule-again branch September 8, 2024 11:06
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.

3 participants