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

Adds invalid swiftlint command rule #4546

Conversation

mildm8nnered
Copy link
Collaborator

@mildm8nnered mildm8nnered commented Nov 13, 2022

Rule-based approach to #4543

Adds an invalid_swiftlint_command rule to detect malformed swiftlint commands. Bungled enable's in particular, after a valid disable can lead to stretches of code going unintentionally un-linted.

nonTriggeringExamples:

// swiftlint:disable unused_import
// swiftlint:enable unused_import
// swiftlint:disable:next unused_import
// swiftlint:disable:previous unused_import
// swiftlint:disable:this unused_import

triggeringExamples:

// swiftlint:
// swiftlint: 
// swiftlint::
// swiftlint:: 
// swiftlint:disable
// swiftlint:dissable unused_import
// swiftlint:enaaaable unused_import
// swiftlint:disable:nxt unused_import
// swiftlint:enable:prevus unused_import
// swiftlint:enable:ths unused_import
// swiftlint:enable
// swiftlint:enable:
// swiftlint:enable: 
// swiftlint:disable: unused_import

Command Parsing

This PR also slightly changes the parsing of commands. Previously cases like

// swiftlint:disable: unused_import
// swiftlint:disable:nxt unused_import
// swiftlint:enable:prevus unused_import
// swiftlint:enable:ths unused_import

Would have been parsed, incorrectly, as

// swiftlint:disable unused_import
// swiftlint:disable unused_import
// swiftlint:enable unused_import
// swiftlint:enable unused_import

These cases will now be ignored, and will be warned about by this rule.

@SwiftLintBot
Copy link

SwiftLintBot commented Nov 13, 2022

1 Warning
⚠️ This PR introduced a violation in WordPress: /WordPress/UITestsFoundation/Screens/ReaderScreen.swift:15:53: warning: Invalid SwiftLint Command Violation: swiftlint command does not have a valid action or modifier (invalid_swiftlint_command)
18 Messages
📖 Linting Aerial with this PR took 1.03s vs 1.03s on main (0% slower)
📖 Linting Alamofire with this PR took 1.34s vs 1.35s on main (0% faster)
📖 Linting Brave with this PR took 7.2s vs 7.17s on main (0% slower)
📖 Linting DuckDuckGo with this PR took 3.02s vs 3.01s on main (0% slower)
📖 Linting Firefox with this PR took 9.15s vs 9.09s on main (0% slower)
📖 Linting Kickstarter with this PR took 10.0s vs 10.05s on main (0% faster)
📖 Linting Moya with this PR took 0.54s vs 0.53s on main (1% slower)
📖 Linting NetNewsWire with this PR took 2.99s vs 2.98s on main (0% slower)
📖 Linting Nimble with this PR took 0.58s vs 0.58s on main (0% slower)
📖 Linting PocketCasts with this PR took 7.03s vs 7.0s on main (0% slower)
📖 Linting Quick with this PR took 0.22s vs 0.22s on main (0% slower)
📖 Linting Realm with this PR took 11.29s vs 11.32s on main (0% faster)
📖 Linting SourceKitten with this PR took 0.43s vs 0.43s on main (0% slower)
📖 Linting Sourcery with this PR took 2.19s vs 2.16s on main (1% slower)
📖 Linting Swift with this PR took 4.44s vs 4.41s on main (0% slower)
📖 Linting VLC with this PR took 1.32s vs 1.32s on main (0% slower)
📖 Linting Wire with this PR took 8.2s vs 8.15s on main (0% slower)
📖 Linting WordPress with this PR took 10.91s vs 10.88s on main (0% slower)

Generated by 🚫 Danger

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-invalid-swiftlint-directives-rule branch 2 times, most recently from 6f63adc to 8fd470f Compare January 29, 2023 13:16
@mildm8nnered
Copy link
Collaborator Author

So I managed to work out make sourcery to get the new rule into PrimaryRuleList, but I'm failing the generated tests because of the nature of the rule, it needs to be validated with

    func testExamples() {
        verifyRule(InvalidSwiftLintCommandRule.description, skipCommentTests: true, skipDisableCommandTests: true)
    }

as I've done in InvalidSwiftLintCommandRuleTests, but there doesn't seem to be any way to pass these parameters into the generated tests, or to exclude that rule from the generated tests.

Not sure what the best way is to go from here ...

@SimplyDanny
Copy link
Collaborator

Not sure what the best way is to go from here ...

See for example ExpiringTodoRule. You can pass the options to skip certain tests to every example or an array of examples.

@mildm8nnered
Copy link
Collaborator Author

So I guess I could special case this rule in .sourcery/GeneratedTests.stencil, something like

@_spi(TestHelper)
@testable import SwiftLintFramework
import SwiftLintTestHelpers
import XCTest

// swiftlint:disable file_length single_test_class type_name

{% for rule in types.structs %}
{% if rule.name|hasSuffix:"Rule" and rule.name != "InvalidSwiftLintCommandRule" %}
class {{ rule.name }}GeneratedTests: XCTestCase {
    func testWithDefaultConfiguration() {
        verifyRule({{ rule.name }}.description)
    }
}
{% if not forloop.last %}

{% endif %}
{% endif %}
{% endfor %}

and rely on the handwritten test.

Or I could further edit the stencil to generate the appropriate code for this case. That doesn't feel very graceful. I will also face a similar problem for #4684, so ideally any mechanism here would be easily extensible.

@mildm8nnered mildm8nnered marked this pull request as ready for review January 29, 2023 23:55
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-invalid-swiftlint-directives-rule branch from 3c1d2f3 to 9fed2a9 Compare February 11, 2023 11:18
@mildm8nnered mildm8nnered force-pushed the mildm8nnered-invalid-swiftlint-directives-rule branch 2 times, most recently from 2a8191e to 5656430 Compare February 26, 2023 17:05
@mildm8nnered
Copy link
Collaborator Author

See also my comment at https://github.com/realm/SwiftLint/issues/3769#issuecomment-1445466113 - it looks like all kinds of odd strings, like // hjkhjkkswiftlint:disable all will be treated as valid, which seems off.

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.

Sorry to miss your last comment. Apart from some smaller findings, it looks good to me now.

I like that the rule itself is very easy now. Good work!

@@ -27,6 +30,8 @@ public struct Command: Equatable {
case this
/// The command should only apply to the line following its definition.
case next
/// The modifier string was invalid
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: In documentation, prefered style is a period at the end of sentences/descriptions.

@@ -8,13 +8,16 @@ public struct Command: Equatable {
case enable
/// The rule(s) associated with this command should be disabled by the SwiftLint engine.
case disable
/// The action string was invalid
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here: Prefer a period at the end.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There should be a rule for that :-)

@mildm8nnered mildm8nnered force-pushed the mildm8nnered-invalid-swiftlint-directives-rule branch from 5656430 to f3abe43 Compare February 28, 2023 21:47
@SimplyDanny SimplyDanny merged commit 1c3c62e into realm:main Mar 4, 2023
@SimplyDanny
Copy link
Collaborator

Merged. 😊 Thanks for all the work @mildm8nnered!

@mildm8nnered mildm8nnered deleted the mildm8nnered-invalid-swiftlint-directives-rule branch April 17, 2023 23:31
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