Compare commits

...

299 Commits
0.50.1 ... main

Author SHA1 Message Date
Danny Mösch 3ec9bc85bc Inline variables 2023-06-18 12:01:28 +02:00
Danny Mösch f5ea2492dc Merge allowed symbols with alphanumerics where possible 2023-06-18 12:01:28 +02:00
Danny Mösch b89e43a799
Make sure case check can be disabled by new `off` option value (#5064) 2023-06-17 22:27:57 +02:00
Danny Mösch c8cd311615 Collapse conditional statements into single expression 2023-06-13 23:24:48 +02:00
Danny Mösch ba42a6aa36 Extract examples 2023-06-13 23:24:48 +02:00
Danny Mösch 83ab977a1b Introduce visitor that tracks declared variables while traversing the AST 2023-06-13 23:24:48 +02:00
Danny Mösch f12b8d66d3
Do not trigger `prefer_self_in_static_references` rule on collection types (#5055) 2023-06-12 16:40:45 -04:00
JP Simard e29de7a99f
Update Bazel dependencies (#5060)
* rules_apple: 2.2.0 -> 2.3.0
* rules_swift: 1.7.1 -> 1.8.0
* rules_xcodeproj: 1.5.1 -> 1.7.0
2023-06-12 15:58:41 -04:00
JP Simard d32bf2b879
Update CryptoSwift (#5059)
Diff: https://github.com/krzyzanowskim/CryptoSwift/compare/1.7.1...1.7.2
2023-06-12 19:23:33 +00:00
JP Simard e5cf99088b
Update SwiftSyntax to 509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a (#5058)
Diff: https://github.com/apple/swift-syntax/compare/509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-05-02-a...509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a
2023-06-12 15:22:17 -04:00
JP Simard 7462187191
Add 5.9 to Swift version tests (#5057)
This gets all tests passing with Xcode 15 beta 1.
2023-06-12 18:39:18 +00:00
Danny Mösch 23326fc433
Specify default options in configurations only (#5056) 2023-06-11 10:44:06 -07:00
woxtu 156f6aabc8
Fix false positives in `sorted_first_last` rule when `first`/`last` have a predicate (#5038) 2023-06-11 17:22:06 +02:00
woxtu 43190834c5
Fix `legacy_random` examples (#5047) 2023-06-10 23:53:45 +02:00
woxtu f1d5a55658
Fix typo (#5044) 2023-06-10 23:50:49 +02:00
woxtu c735e6320f
Add Swift version 5.8.1 (#5050) 2023-06-05 16:52:35 +00:00
woxtu 2f9997e2cc
Fix typos (#5033) 2023-05-25 23:58:29 +02:00
woxtu 8f3eea06d3
Fix include path for custom `rule_id` rule (#5031) 2023-05-24 00:36:00 +02:00
woxtu a53a1f052b
Fix links to rules directory (#5029) 2023-05-22 21:37:48 +02:00
Danny Mösch 704c9ae116
Move ViolationsSyntaxVisitor into its own file (#5028) 2023-05-22 07:35:46 -04:00
Martin Redington 521df18fdb
Fix false alarms in `redundant_objc_attribute` rule (#4742) 2023-05-20 21:45:27 +02:00
Danny Mösch a2ba0a0626
Omit "Rule" in configuration names (#5024) 2023-05-20 04:39:04 -04:00
Hilton Campbell 1094a3b70e
Add `grouping` option to the `sorted_imports` rule (#4935) 2023-05-19 15:49:07 -04:00
Haocen Jiang 754127924f
Update replacement for CGRectIntersection (#5023) 2023-05-19 15:17:14 -04:00
Danny Mösch 3f039f26d5
Connect configs with their referencing rules to have some context in error logging (#5017)
With the binding of configurations to their associated rule types
"unknown configuration" errors can be made more specific mentioning
also the rule's identifier in the printed message.
2023-05-19 20:58:24 +02:00
Danny Mösch 671589b1d4
Let configuration names match rule names (#5021) 2023-05-18 12:04:39 -04:00
Danny Mösch d938b2d3c3
Specify default options in configurations only (#5020) 2023-05-18 17:21:30 +02:00
Danny Mösch 7fd22e0d6e
Use `SeverityBasedRuleConfiguration` where possible (#5019) 2023-05-18 16:04:20 +02:00
JP Simard 07740506b5
Automate adding a new changelog section after releasing (#5016) 2023-05-17 10:36:31 -04:00
kid cherish 26d06bcebb
[Update] Add Code Line in README_KR.md (#5015) 2023-05-17 07:05:37 +02:00
Danny Mösch fe312a06fe
Rely on pre-defined issues and allow to print them directly to the console (#5013)
Advantages of having typical errors at a common place:
* Error message styling can be harmonized
* Existing messages can be reused
* Overview of prefixes ('error: ', 'warning: ')
* Manage how to print them to the console
2023-05-16 20:15:14 +02:00
Danny Mösch d73970e9d7
Remove error wrapper (#5008) 2023-05-16 18:22:25 +02:00
Danny Mösch c0ea9d1925
Do not trigger `prefer_self_in_static_references` rule on `typealias` in classes (#5012) 2023-05-15 14:07:21 -04:00
Danny Mösch 405113f793
Open ConfigurationError up to be used more broadly (#5005) 2023-05-14 20:00:46 +02:00
Danny Mösch f4987071f0
Extract configuration into its own file (#5007) 2023-05-14 13:05:36 -04:00
Danny Mösch 306dec0fcc
Disable `no_fallthrough_only` in favor of simultaneously active `fallthrough` (#5006)
Avoids two violation when using `fallthrough`.
2023-05-14 15:55:02 +00:00
Danny Mösch 4d4a330d46
Silence `xct_specific_matcher` rule on types and tuples used in "one argument asserts" (#4997) 2023-05-13 22:04:35 +02:00
JP Simard 1e73835e83
Remove dead code (#5004)
Identified with the upcoming improved dead code detection.
2023-05-12 14:20:31 -04:00
JP Simard 866001db2f
Add new changelog section 2023-05-12 11:05:45 -04:00
JP Simard 34f5ffa7f7
release 0.52.2 2023-05-12 11:02:03 -04:00
JP Simard 1b1b19a902
Fix some `unhandled_throwing_task` false positives (#5001)
Fixes some of the cases reported in
https://github.com/realm/SwiftLint/issues/4987
2023-05-12 10:35:59 -04:00
JP Simard 15a18fd4e8
Merge `make release` with `make publish` (#5003)
To simplify the release process.
2023-05-12 09:58:06 -04:00
JP Simard 5802fd99b1
Parallelize TSan tests on CI (#5002) 2023-05-12 09:54:27 -04:00
JP Simard e7bf813f15
Make `unhandled_throwing_task` rule opt-in (#5000)
Because since it was included in a release a few days ago, we've had
several reports of false positives and so flipping to opt-in is
appropriate so users can determine for themselves if they should enable
the rule.
2023-05-12 09:46:07 -04:00
Danny Mösch 3cf9585b2e
Exclude `self.x = x` from being reported in the `redundant_self_in_closure` rule (#4996) 2023-05-11 23:26:39 +02:00
JP Simard 8827fca693
Automate GitHub Release Creation (#4995)
* Add `tools/generate-release-notes.sh` script
* Add `tools/create-github-release.sh` script
* Update `Releasing.md`
2023-05-11 14:01:29 -04:00
Marcelo Fabri 9f7c57b719
Make id and isVirtual public in SwiftLintFile (#4994) 2023-05-11 13:33:48 -04:00
JP Simard 73acbaf6d5
Add new changelog section 2023-05-11 11:26:23 -04:00
JP Simard 5616d858bc
release 0.52.1 2023-05-11 11:13:58 -04:00
JP Simard 6cdb0aa689
Update `make publish`
To use the CocoaPods version from bundler and to remove the stale
workaround.
2023-05-11 11:03:28 -04:00
JP Simard 7483e61615
Fix Bazel release tarball for compiling on macOS (#4992)
Fixes #4985
2023-05-11 10:59:02 -04:00
Kyle Bashour 87e230ce87
Fix false positive when result is accessed (#4986) 2023-05-10 20:36:00 -04:00
JP Simard 7f3b93147a
Update Gemfile.lock (#4983)
This happened automatically when I ran `bundle install` locally.
2023-05-10 17:23:50 -04:00
JP Simard 7501d44b69
Add new changelog section 2023-05-10 16:46:19 -04:00
Danny Mösch 0ffe0c5911 Extract tests for NameConfiguration 2023-05-10 22:20:30 +02:00
Danny Mösch c99a4286b8 Let `validates_start_with_lowercase` option in name configurations expect a severity 2023-05-10 22:20:30 +02:00
Danny Mösch 8d5700afca Remove deprecation warning in `identifier_name` rule
It was introduced 6 years ago.
2023-05-10 22:20:30 +02:00
Danny Mösch 1fa8e484c4 Add expiring TODO comments on deprecation warnings 2023-05-10 21:44:20 +02:00
Danny Mösch 9e15e37255 Disable `todo` in favor of `expiring_todo` 2023-05-10 21:44:20 +02:00
JP Simard 97259e24d0
release 0.52.0 2023-05-10 15:15:09 -04:00
JP Simard eb6d50a04c
Update SwiftSyntax to 509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-04-25-b (#4982) 2023-05-10 15:02:58 -04:00
Danny Mösch 9c1678968f
Remove deprecation warnings introduced > 2 years ago (#4972) 2023-05-10 14:05:28 -04:00
JP Simard fa32fbc4f0
Minor edits to `unhandled_throwing_task` changelog entry
And rule description.
2023-05-10 14:04:42 -04:00
Kyle Bashour 8822d40687
Add `unhandled_throwing_task` rule (#4958)
This rule will check Task's that are not explicitly annotated with success and
failure types for unhandled try expressions. These trys will silently fail if an
error is thrown.

See this forum thread for more details:
https://forums.swift.org/t/task-initializer-with-throwing-closure-swallows-error/56066
2023-05-10 14:03:01 -04:00
JP Simard c0cf1bf5c9
Add changelog entry for module split 2023-05-10 13:23:32 -04:00
JP Simard 444653bfd5
Update bazel version to 6.2.0 (#4981) 2023-05-10 16:25:34 +00:00
Danny Mösch 9138213121
Mark change as breaking (#4969) 2023-05-06 20:46:43 +00:00
Danny Mösch 6fd5f98d38 Add examples for weak variables to `implicitly_unwrapped_optional` rule 2023-05-06 22:46:25 +02:00
Danny Mösch bc18ff14e3 Add violation markers 2023-05-06 22:46:25 +02:00
Andyy Hope 5e15039554
Move `excludedPaths` out of iteration loop to speed up lint times (#4955) 2023-05-06 16:43:33 -04:00
Danny Mösch 7756793356
Add new option to `attributes` rule to influence it for attributes with arguments (#4855) 2023-05-05 16:12:01 -04:00
Danny Mösch f0138ea1df
Add example to proof that shorthand optional bindings work with `unused_declaration` rule (#4857) 2023-05-05 15:22:59 -04:00
Danny Mösch 6a2e973de3
Add new `redundant_self_in_closure` rule (#4911) 2023-05-05 21:14:14 +02:00
JP Simard e86c06c390
[SwiftLintCore] Make `focused()` public (#4959)
So it can be used from SwiftLintBuiltInRules.

I missed this when splitting the SwiftLintFramework module.
2023-05-04 15:07:37 +00:00
JP Simard 6b094dd711
[SwiftSyntax] Update to latest 509.0.0 tag (#4920)
* [bazel] Remove custom SwiftSyntax BUILD file

Something similar to this has been merged upstream instead now. This
also renames the repo name to SwiftSyntax in preparation for it being in
the BCR

* [SwiftSyntax] Update to latest 509.0.0 tag

https://github.com/apple/swift-syntax/releases/tag/509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-04-25-b
2023-05-03 11:34:26 -04:00
Simon Støvring 9054ec0658
Add test verifying that the `file_header` rule can require an empty file header (#4928) 2023-05-01 18:47:37 +02:00
Chris White 71b89e66de
Prepend `warning: ` to error messages (#4927) 2023-05-01 18:26:25 +02:00
JP Simard a7bc9e20c7
Move built-in rules to new SwiftLintBuiltInRules module (#4950) 2023-04-27 11:16:01 -04:00
JP Simard eaf34d7204
Move extra rules into its own module (#4949)
This will decouple building extra rules from built-in rules so that
making changes in one of those modules doesn't rebuild the other.
2023-04-27 10:37:30 -04:00
JP Simard 86d60400c1 Move core SwiftLint functionality to new SwiftLintCore module
Over the years, SwiftLintFramework had become a fairly massive monolith,
containing over 400 source files with both core infrastructure and
rules.

Architecturally, the rules should rely on the core infrastructure but
not the other way around. There are two exceptions to this:
`custom_rules` and `superfluous_disable_command` which need special
integration with the linter infrastructure.

Now the time has come to formalize this architecture and one way to do
that is to move the core SwiftLint functionality out of
SwiftLintFramework and into a new SwiftLintCore module that the rules
can depend on.

Beyond enforcing architectural patterns, this also has the advantage of
speeding up incremental compilation by skipping rebuilding the core
functionality when iterating on rules.

Because the core functionality is always useful when building rules, I'm
opting to import SwiftLintCore in SwiftLintFramework as `@_exported` so
that it's implicitly available to all files in SwiftLintFramework
without needing to import it directly.

In a follow-up I'll also split the built-in rules and the extra rules
into their own modules. More modularization is possible from there, but
not planned.

The bulk of this PR just moves files from `Source/SwiftLintFramework/*`
to `Source/SwiftLintCore/*`. There are some other changes that can't be
split up into their own PRs:

* Change jazzy to document the SwiftLintCore module instead of
  SwiftLintFramework.
* Change imports in unit tests to reflect where code was moved to.
* Update `sourcery` make rule to reflect where code was moved to.
* Create a new `coreRules` array and register those rules with the
  registry. This allows the `custom_rules` and
  `superfluous_disable_command` rule implementations to remain internal
  to the SwiftLintCore module, preventing more implementation details
  from leaking across architectural layers.
* Move `RuleRegistry.registerAllRulesOnce()` out of the type declaration
  and up one level so it can access rules defined downstream from
  SwiftLintCore.
2023-04-26 21:10:19 -04:00
JP Simard 740572f049 Move `Version.swift` to SwiftLintCore 2023-04-26 21:10:19 -04:00
JP Simard 3541ef4d02 Import SwiftLintCore in generated tests
In preparation for it containing the `superfluous_disable_command` rule.
2023-04-26 21:10:19 -04:00
JP Simard 39a05f2c35 Re-export SwiftLintCore import in SwiftLintFramework
Because the core functionality is always useful when building rules, I'm
opting to import SwiftLintCore in SwiftLintFramework as `@_exported` so
that it's implicitly available to all files in SwiftLintFramework
without needing to import it directly.
2023-04-26 21:10:19 -04:00
JP Simard 711d92e26f Add empty SwiftLintCore module
Source files will be added to it in a follow-up commit.
2023-04-26 21:10:19 -04:00
JP Simard d8dfc3c937
Update rules_xcodeproj to 1.5.1 (#4948)
Lots of performance optimizations in this release

https://github.com/MobileNativeFoundation/rules_xcodeproj/releases/tag/1.5.1
2023-04-26 21:06:17 -04:00
JP Simard 3a2bb15ca3
Make some SwiftLintFramework declarations public (#4945)
* Make some SwiftLintFramework declarations public

If built-in rules depend on them.

This will allow separating the rules from the core infrastructure in
separate modules in an upcoming PR.

It also helps formalize the API contract for what should be accessible
to rule implementations.

* Exclude extensions from jazzy
2023-04-26 16:37:25 -04:00
JP Simard a7e3909c6a
Improve StyleViolation reason formatting validation (#4946)
So it checks violations for all rules in the registry, not just the
built-in rules.
2023-04-26 18:54:44 +00:00
JP Simard 72c2a5488d
Re-order `CustomRules.swift` (#4944)
For consistency with other files in this project, which usually have
private extensions at the bottom of the file.
2023-04-26 18:37:40 +00:00
JP Simard ea56405983
Rename `Request.cursorInfo()` to `cursorInfoWithoutSymbolGraph()` (#4943)
To avoid conflicting with the `cursorInfo` declared in
SourceKittenFramework.
2023-04-26 18:28:24 +00:00
JP Simard 9c414932d8
Add more documentation comments (#4942)
In preparation for these declarations to become public.
2023-04-26 14:18:13 -04:00
JP Simard 8a21549ca9
Change `Reachability` to an enum (#4941)
Since it's already acting as a namespace, might as well make it so it
can't be instantiated and can't have instance properties.
2023-04-26 13:55:17 -04:00
JP Simard 4abcf5f0dd
Remove `SwiftLintFramework` dependency from GeneratedTests target (#4940)
Since it's available transitively from SwiftLintTestHelpers.
2023-04-26 16:37:23 +00:00
JP Simard b2a4c9fcb9
Mark `RulesFilter` as `final class` (#4939)
Since it's not designed to be subclassed.
2023-04-26 16:26:22 +00:00
JP Simard 603fff9a82
Make `Correction` and `CorrectableRule` declarations public (#4937)
The CLI target shouldn't be importing SwiftLintFramework with
`@_spi(TestHelper)`. If the CLI target needs to access something in
SwiftLintFramework, that declaration should be `public`.
2023-04-26 12:17:10 -04:00
JP Simard 2544dc79d3
Move `CustomRuleTimer` to its own file (#4938)
And add docs.
2023-04-26 15:56:04 +00:00
Kris Kline ea6b3b4d64
Update minimum OS versions for Xcode 14.3 (#4934)
* iOS - 11.0
* MacOS - 10.13
* tvOS - 11.0
* WatchOS - 7.0
2023-04-25 19:51:36 +00:00
Benny Wong 172b8b8a94
Remove `else else` typo (#4933) 2023-04-25 18:03:25 +00:00
JP Simard 4c04cdafa7 Introduce SwiftLintTestCase
To consistently set up rules before tests
2023-04-25 12:28:50 -04:00
JP Simard 165172e0fa Introduce a "rule registry" concept
This will allow for registering rules that aren't compiled as part of
SwiftLintFramework.

Specifically this will allow us to split the built-in and extra rules
into separate modules, leading to faster incremental compilation when
working on rules since the rest of the framework won't need to be
rebuilt on every compilation.
2023-04-25 12:28:50 -04:00
JP Simard 3f52acd0a2
Make `UnitTestRuleConfiguration` internal (#4931) 2023-04-25 13:28:28 +00:00
JP Simard e14a73438f
Remove SourceKitten from OSSCheck (#4930)
It looks like there's some non-determinism in how we lint it that was
recently introduced, maybe it's due to some SwiftSyntax update, not
sure.
2023-04-25 09:27:24 -04:00
JP Simard 817de197d5
Clean up `MARK` comments 2023-04-24 15:13:44 -04:00
JP Simard 214a749ace
Extend the custom rules section in the README (#4926)
To link to a video tutorial and example project for creating custom
rules written in Swift and to outline some of the advantages to using
these over regex custom rules.
2023-04-24 17:04:56 +00:00
JP Simard fd4f9afb08
Remove AppCode section in README.md (#4925)
> AppCode is no longer available as a commercial product as of
> December 14, 2022.

From https://blog.jetbrains.com/appcode/2022/12/appcode-2022-3-release-and-end-of-sales-and-support/
2023-04-24 12:44:49 -04:00
Danny Mösch c241935635
Introduce basic Stack type (#4922) 2023-04-23 09:12:35 +00:00
JP Simard 46ff727a13
Update Bazel version to 6.1.2 (#4918) 2023-04-21 17:00:53 -04:00
JP Simard dc89109622
Apply suggested bazel flags (#4917) 2023-04-21 16:51:14 -04:00
JP Simard 9c2525139a
Update CryptoSwift to 1.7.1 (#4916)
To fix Swift 5.8 warnings
2023-04-21 14:15:44 +00:00
JP Simard d601917e40
Apply minor changelog edits 2023-04-21 09:25:11 -04:00
YoungBin Lee 498b4c8fbe
Correct organization name in README files (#4913)
Rename 'Ray Wenderlich' to 'Kodeco'.
2023-04-21 05:16:13 +00:00
Danny Mösch 69fadb6918
Remove no-op initializers from structs (#4912) 2023-04-20 11:59:37 +02:00
JP Simard f866ec32b1
Add link to video tutorial demonstrating how to write a rule (#4910)
https://vimeo.com/819268038
2023-04-19 17:16:27 -04:00
JP Simard 6d51459323
Update Ruby Gems (#4909)
* danger: 8.6.1 -> 9.2.0
* cocoapods: 1.11.3 -> 1.12.1
* jazzy: 0.14.2 -> 0.14.3
2023-04-19 10:23:21 -04:00
JP Simard 21dc766c93
Exclude new `XCTSpecificMatcherRule` examples from documentation (#4907) 2023-04-18 21:45:51 +00:00
JP Simard 0f802f766a
[CI] Remove `update_swift_syntax.yml` (#4906)
We now manually update SwiftSyntax as needed.
2023-04-18 21:35:43 +00:00
JP Simard fbbccf9db8
Allow configuring `xct_specific_matcher` with matchers (#4905)
So that either `one-argument-asserts` or `two-argument-asserts` or both
can be enabled.

The following configuration effectively reverts back to the rule
behavior prior to https://github.com/realm/SwiftLint/pull/3858:

```yaml
xct_specific_matcher:
  matchers:
    - two-argument-asserts
```
2023-04-18 20:50:58 +00:00
JP Simard 8b72eb0406
Mark `bazel_skylib` as `dev_dependency = True` (#4904)
So folks who integrate SwiftLint with Bazel don't need to match this
exact version.
2023-04-18 18:50:56 +00:00
JP Simard c22d60fac0
Update `UnusedImportRuleExamples` for Swift 5.8 (#4903) 2023-04-18 17:58:40 +00:00
Keith Smiley 1892c846b0
Workaround dyld warning about SwiftSyntax classes (#4901)
This uses a recent but unannounced (also read as private) feature of
dyld where it ignores duplicate Objective-C classes when they're in a
special format in the binary. c8a445f88f/dyld/PrebuiltLoader.cpp (L1660-L1662)

I think this is generally safe because hopefully people aren't actually
using the SwiftSyntax classes through the Objective-C runtime, but if
they are we'd still probably prefer to silence the noise and accept the
UB.

Fixes https://github.com/realm/SwiftLint/issues/4782
2023-04-17 19:55:33 -04:00
Andrew Montgomery 41290a23d3
Remove checks for setUp/tearDown from `overridden_super_call` rule (#4875) 2023-04-17 20:18:41 +00:00
Frad LEE 5814ec1a1a
Add architecture detection to Xcode script configuration (#4873) 2023-04-17 18:48:06 +00:00
JP Simard f9b0e9f0af
Update CryptoSwift to 1.7.0 (#4899) 2023-04-17 10:37:40 +00:00
Keith Smiley 3ef44cf742
Switch to SwiftPM conditional dependencies API (#4003)
This API allows us to mostly remove `#if` conditionals which enables
cross compilation from macOS -> Linux. It also removes the thrashing of
Package.resolved if you compile in a docker image.
2023-04-16 20:19:25 +02:00
Danny Mösch 5aed7ce95c
Check first argument label in `reduce_boolean` rule (#4895) 2023-04-16 09:58:27 +02:00
Martin Redington 97fd216455
Skip unit tests in `no_magic_numbers` rule (#4897) 2023-04-16 09:07:54 +02:00
Danny Mösch f127ba14dd
Ignore block comments in `let_var_whitespace` rule (#4889) 2023-04-16 00:10:03 +02:00
JP Simard 74b82daba0
[CI] Use rbenv to manage Ruby (#4893)
And pin the Ruby version to 2.7.5. rbenv was installed on all CI
machines using Homebrew, with Ruby 2.7.5 installed and set as the
global version. The `pre-command` script was also updated on all agents
to add rbenv binaries to the path and run `rbenv init`.

Remove rules_ruby integration and just use rbenv and ruby directly.
2023-04-14 16:23:05 +00:00
JP Simard 8c617d7412
[CI] Update Azure Pipelines to run with Swift 5.8 (#4890)
Linux only because Azure Pipelines doesn't have any
images with macOS 13 or Xcode 14.3 yet.
2023-04-14 14:27:03 +00:00
JP Simard a4f4680442
Update copyright year for html docs 2023-04-14 10:18:47 -04:00
JP Simard 62b2914271
Update rules_ruby (#4891)
Just to stay up to date.
2023-04-14 10:11:50 -04:00
JP Simard 1b0f37c6f6
Pin Sourcery version to 2.0.2 (#4888)
By adding a `tools/sourcery` script that downloads and runs Sourcery via
Bazel.

Previously, unrelated changes might include modifications to the
generated comment headers because contributors' local versions of
Sourcery would be used, which we don't control.

Also move the CI job to Buildkite where the bazel server is usually
already warmed up and running.
2023-04-13 20:09:26 +00:00
JP Simard 5226725689
Fix extra space before member access 2023-04-13 15:12:37 -04:00
JP Simard e361e14c90
Move changelog entry to the latest section 2023-04-13 15:04:13 -04:00
JP Simard 70a56a1420
Update SwiftSyntax to 04-10 snapshot (#4887)
https://github.com/apple/swift-syntax/releases/tag/509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-10-a
2023-04-13 14:04:43 -04:00
Gabriel Féron 409f117da9
Use Ubuntu 20.04 to release Linux binaries (#4882)
* Use Ubuntu 20.04 to release Linux binaries

Using the latest version of Ubuntu leads to incompatibilities with `glibc` versions from LTS versions.

* Use Ubuntu 20.04 for Azure pipelines
2023-04-13 13:25:43 -04:00
JP Simard 7fe7bb28d9
Update rules_xcodeproj to 1.4.0 (#4885)
https://github.com/MobileNativeFoundation/rules_xcodeproj/releases/tag/1.4.0
2023-04-13 15:25:17 +00:00
Danny Mösch bb11e6a0a7 Extract examples to separate file 2023-04-04 20:10:59 +02:00
Danny Mösch eee97a7b2b Trigger `prefer_self_in_static_references` rule on types 2023-04-04 20:10:59 +02:00
Danny Mösch cf1e2e27dc Use `is` instead of `as` for simple type checks 2023-04-04 20:10:59 +02:00
Sven Münnich a2facce70c
Fix false positives related to multiline strings in `indentation_width` rule (#4862) 2023-04-04 19:27:16 +02:00
Danny Mösch bd444fcd77
Fix `lower_acl_than_parent` rule rewriter by preserving leading whitespace (#4861) 2023-04-03 20:26:46 +00:00
Danny Mösch ee849bcb10
Remove unused imports (#4856) 2023-04-03 19:26:59 +02:00
Danny Mösch 6d4bc78cb4
Add new `superfluous_else` rule (#4696) 2023-04-02 12:32:40 +02:00
Danny Mösch 16e2bb0f18
Extend `xct_specific_matcher` rule to check for boolean asserts on (un)equal comparisons (#3858) 2023-04-02 12:30:21 +02:00
Kim de Vos b0cbb440c3
Add new `sorted_enum_cases` rule (#4845) 2023-04-02 11:33:20 +02:00
Danny Mösch 58a07eb452
Update SwiftSyntax (#4852) 2023-03-31 23:12:31 +02:00
Danny Mösch 82491e6f84
Add Swift version 5.8 (#4851) 2023-03-31 22:44:25 +02:00
Danny Mösch 3d15419adb
Fix warnings in Swift 5.8/Xcode 14.3 (#4850) 2023-03-31 22:13:20 +02:00
Martin Redington 6a09af169e
Fix crash when parsing apple/swift (#4828) 2023-03-31 20:59:47 +02:00
Martin Redington 7dad240ea7
Add a `reporters` subcommand (#4836) 2023-03-31 08:09:01 +02:00
Martin Redington ca43d2359b
Fix unit test configuration (#4847) 2023-03-30 22:46:31 +02:00
JP Simard da27f1c7fd
Add empty changelog section 2023-03-27 12:11:36 -04:00
JP Simard eb85125a5f
release 0.51.0 2023-03-27 11:44:47 -04:00
JP Simard 62b9c2de7a
Don't run `make clean` automatically on `build`
Since when releasing, many steps depend on the `build`, so we don't want
to clean mid-way through releasing.

Explicitly run `make clean` at the start of `make release`.
2023-03-27 11:22:00 -04:00
JP Simard aeee6325af
Update bazel dependencies (#4842)
* Update bazel from 6.0.0 to 6.1.1
* Update rules_apple from 2.0.0 to 2.2.0
* Update rules_swift from 1.5.1 to 1.7.1
* Update rules_xcodeproj from 1.1.0 to 1.3.3
2023-03-27 14:36:44 +00:00
Martin Redington 5a91b1e392
Fixed display of optin and correctable (#4841)
Co-authored-by: Martin Redington <mildm8nnered@gmail.com>
2023-03-27 07:48:51 +02:00
JP Simard efc5afd5d5
Apply small formatting fixes (#4840)
* Trim excess trailing and vertical whitespace
* Move `SwiftyTextTable` dependency into `frameworkDependencies`
* Adjust wording in README around analyzer rules in the `opt_in_rules`
  section, since analyzer rules can only go in the `analyzer_rules`
  section.
2023-03-26 16:09:43 -04:00
Martin Redington f2d15355be
Add a `summary` table reporter (#4820) 2023-03-25 08:28:42 +01:00
Martin Redington a840058cf5
Add default.profraw to .gitignore and delete obsolete instructions (#4835)
Co-authored-by: Martin Redington <mildm8nnered@gmail.com>
2023-03-25 08:21:22 +01:00
dependabot[bot] 358bdc89a5
Bump activesupport from 6.1.7.1 to 6.1.7.3 (#4824)
Bumps [activesupport](https://github.com/rails/rails) from 6.1.7.1 to 6.1.7.3.
- [Release notes](https://github.com/rails/rails/releases)
- [Changelog](https://github.com/rails/rails/blob/v7.0.4.3/activesupport/CHANGELOG.md)
- [Commits](https://github.com/rails/rails/compare/v6.1.7.1...v6.1.7.3)

---
updated-dependencies:
- dependency-name: activesupport
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-24 15:27:01 -04:00
강수진 a81a532091
Fix SwiftLint rule count in Korean README (#4832) 2023-03-22 20:08:28 +01:00
Martin Redington 6983c813c8
Fix rewriter of `trailing_semicolon` rule wrongly removing trailing comments (#4818) 2023-03-13 22:23:35 +00:00
Danny Mösch fb89ab2fb5 Stop triggering `unused_capture_list` on variables referenced in optional bindings 2023-03-12 14:38:10 +01:00
Danny Mösch 7ac128c83d Enable `direct_return` rule in the repository 2023-03-12 14:36:07 +01:00
Danny Mösch 06578e5d91 Get rid of some more disabled commands 2023-03-12 00:03:02 +01:00
Danny Mösch 1940e0e2d2 Make custom rule `rule_id` more specific 2023-03-12 00:03:02 +01:00
Danny Mösch bd77cbcf6e
Add example verifying that `trailing_semicolon` works with trailing comments (#4808) 2023-03-11 13:29:38 +00:00
Danny Mösch 1bf2f25e40
Get rid of some disabled commands (#4807) 2023-03-11 08:20:47 -05:00
Danny Mösch 7d7bee5eee
Disable deprecated rules (#4806) 2023-03-11 12:48:04 +00:00
Martin Redington 31510b662e
Use `all` optin rules facility for SwiftLint's own `.swiftlint.yml` (#4800) 2023-03-11 11:59:05 +01:00
Martin Redington 0bd8a7aba6
Add new `blanket_disable_command` rule (#4731) 2023-03-07 21:43:53 +01:00
Keith Smiley 084ad9dfd4
Remove unused _SwiftSyntaxMacros library (#4802)
This one was actually renamed to not have the underscore but it's not
used so we might as well drop it.
2023-03-07 17:54:46 +00:00
Martin Redington 228d53787b
Stop`superfluous_disable_command` from firing when disabled (#4791) 2023-03-05 19:21:35 +01:00
1in1 4fee8e6a0c
Add new `duplicate_conditions` rule (#4771) 2023-03-05 11:05:23 +01:00
Danny Mösch 4f9a608cf4
Remove duplicate line (#4797) 2023-03-04 13:12:59 +00:00
Martin Redington 1c3c62e422
Add new `invalid_swiftlint_command` rule (#4546) 2023-03-04 13:53:27 +01:00
Martin Redington d6e3bbb64d
Add "all" pseudo-rule which enables all opt-in rules (#4544) 2023-03-04 13:49:00 +01:00
Danny Mösch 128f37a6b8
Fix whitespace issue in rewriter of `redundant_optional_initialization` rule (#4795) 2023-03-04 11:47:24 +00:00
Tony Arnold cfd9a26e33
Ensure that configuration exclusion rules are respected by the build plugin (#4757)
We always pass all of the Swift source files in the target to the tool, so we need to ensure that any exclusion rules in the configuration are respected.
2023-03-02 22:26:49 +01:00
David Davies-Payne a71f588637
Add instructions for disabling Xcode package validation (#4751) 2023-02-28 19:40:23 +00:00
Martin Redington d73d87ac97
Add `include_multiline_strings` option to `indentation_width` rule (#4785) 2023-02-26 11:52:29 +01:00
Martin Redington 04791929a7
Improve `identifier_name` documentation (#4784) 2023-02-25 20:02:02 +01:00
Danny Mösch c9b1b961f5
Fix some issues in `direct_return` rule (#4783) 2023-02-25 02:48:31 -05:00
Danny Mösch 613e916c39
Use parameter names in description (#4781) 2023-02-24 15:55:39 +00:00
JP Simard e2f3f3ad45
Include `MODULE.bazel` in bazel release archive (#4779)
So it can be used with bzlmod.
2023-02-22 12:29:26 -05:00
JP Simard 5c94a43352
Update SourceKitten for Bazel without bzlmod (#4778)
Missed this in #4776.
2023-02-20 22:32:58 +00:00
JP Simard 183c0aa784
Set `--platform linux/amd64` in `make zip_linux_release`
So it works on other architectures (e.g. Apple Silicon)
2023-02-20 17:00:48 -05:00
JP Simard ed6793f8f1
Fix changelog whitespace formatting 2023-02-20 16:38:40 -05:00
JP Simard 1790ad56dd
Update SourceKitten & Yams (#4776) 2023-02-20 15:50:14 -05:00
JP Simard 2f0e537f9b
Update SwiftSyntax to latest development snapshot (#4759)
* Merge `spacedBinaryOperator` and `unspacedBinaryOperator`

* New contextual keyword enums

* Update for removed `UnavailabilityConditionSyntax`

* Handle how attributes are now defined

This partially reverts commit 325d0ee1e4.

* Handle removal of `TokenListSyntax`

* Update `Package.swift`

* Extract some SwiftSyntax helpers

* Update to `0.50900.0-swift-DEVELOPMENT-SNAPSHOT-2023-02-06-a`

* Skip attributes with keypath arguments in `attributes` rule

To preserve the rule's existing behavior.

* Limit unowned_variable_capture violations to capture lists

* Add changelog entries
2023-02-20 10:51:31 -05:00
Danny Mösch 393318d903
Add new `direct_return` opt-in rule (#4717) 2023-02-19 13:09:41 +01:00
Danny Mösch f3e5557de9
Stop triggering `strict_fileprivate` rule on protocol implementations (#4705) 2023-02-18 13:23:26 +01:00
Mathias Schreck 352ffdfc57
Fix void_return rule to support async and async throws functions (#4772) 2023-02-17 21:39:32 +01:00
Thi Doãn 6a9e6776a9
Update BUILD file for SwiftSyntax (#4768) 2023-02-16 13:25:16 -05:00
Danny Mösch ec38c244fd
Refactor rule list documentation (#4763) 2023-02-13 21:22:10 +01:00
Vasiliy Kattouf ad29864d7f
Add markdown local links to listed rules (#4762) 2023-02-12 23:22:09 +01:00
Marcelo Fabri b9e5cfb202
Fix correction on `lower_acl_than_parent` rule (#4761)
Fixes #4753
2023-02-09 01:47:33 -08:00
Michael S 9c216baf20
Add new `relative-path` reporter (#4739) 2023-02-07 23:23:00 +01:00
Marcelo Fabri 7eb479d546
Rewrite MultilineArgumentsRule using SwiftSyntax (#4750)
* Rewrite MultilineArgumentsRule using SwiftSyntax

* Add examples and changelog

Fixes #3399, #3605
2023-02-07 02:55:21 -08:00
Danny Mösch aafc574e90
Allow to pass a rule identifier to the `swiftlint docs` command (#4710) 2023-02-07 00:01:52 +01:00
Danny Mösch 5af4291b53
Let Emoji reporter print rule identifier (#4708) 2023-02-06 16:28:07 -05:00
Danny Mösch d3ebfc5567
Let `number_separator` rule trigger on misplaced separators (#4685) 2023-02-06 16:22:31 -05:00
Marcelo Fabri 60d0dd8a05
Update SwiftSyntaxRule.swift (#4749) 2023-02-06 14:16:18 -05:00
Marcelo Fabri 0163ffd328
Cache folded syntax tree (#4744) 2023-02-06 10:39:36 -08:00
JP Simard eb5712582f
Update rules_xcodeproj to 1.0.1 (#4748)
https://www.buildbuddy.io/blog/introducing-rules_xcodeproj-1-0
2023-02-06 18:08:11 +00:00
JP Simard 6ea0397620
Replace `if_let_shadowing` with `shorthand_optional_binding` (#4747)
In `.swiftlint.yml`
2023-02-06 16:12:08 +00:00
Marcelo Fabri aba0f63704
Speed up class_delegate_protocol rule (#4743) 2023-02-05 18:45:24 -08:00
Martin Redington 993f34a96c
Document `allow_zero_lintable_files` and move the `analyzer_rules` section up (#4741)
Co-authored-by: Martin Redington <mildm8nnered@gmail.com>
2023-02-04 13:43:41 +01:00
Christian Clauss eaacd9873e
Show how pre-commit can apply fixes and fail on errors (#4740) 2023-02-04 13:39:25 +01:00
Roman Stetsenko 843198d241
Use prebuildCommand for SwiftLint plugin (#4680) 2023-02-02 19:25:25 +01:00
Danny Mösch 325d0ee1e4
Consider custom attributes in `attributes` rule (#4616) 2023-01-31 22:34:11 +01:00
Danny Mösch 5eed8fe91b
Enable `if_let_shadowing` rule and fix all violations (#4247) 2023-01-31 22:31:38 +01:00
Jim Puls 60610cef84
Update Package.resolved (#4736) 2023-01-31 13:41:26 -05:00
JP Simard ca09bc5a22
Update rules_xcodeproj & Yams (#4735)
* rules_xcodeproj: https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/1.0.0rc1
* Yams: https://github.com/jpsim/Yams/releases/tag/5.0.4
2023-01-31 16:51:16 +00:00
Danny Mösch 0796236031
Use text blocks in reporters if reasonable (#4733) 2023-01-30 16:38:07 -05:00
Patrick 651b00eb70
Updated JUnit reporter (#4725) 2023-01-30 20:48:29 +01:00
Danny Mösch 500f143c7d
Remove unused code (#4729) 2023-01-28 19:50:22 +01:00
JP Simard 81f1dbfd1b
[CI] Stop running "Analyze" job (#4728)
it's extremely time-consuming, taking 25 minutes lately, and we'll
hopefully have a better solution soon with the upcoming improvements
to dead code detection, taking less than 1 second to run.

```
(1/4) Collecting units and records (0.25s)
(2/4) Collecting protocol conformances (0.26s)
(3/4) Collecting declarations and references (0.04s)
(4/4) Calculating unused declarations (0.05s)
Source/SwiftLintFramework/Extensions/Configuration+IndentationStyle.swift:16:18: error: Unused declaration named 'init(_:)'
Source/SwiftLintFramework/Models/LinterCache.swift:53:13: error: Unused declaration named 'init(cache:location:fileManager:swiftVersion:)'
Source/SwiftLintFramework/Models/SwiftVersion.swift:25:16: error: Unused declaration named 'fiveDotTwo'
Source/SwiftLintFramework/Models/SwiftVersion.swift:27:16: error: Unused declaration named 'fiveDotThree'
Source/SwiftLintFramework/Models/SwiftVersion.swift:31:16: error: Unused declaration named 'fiveDotFive'
Source/SwiftLintFramework/Rules/Lint/CompilerProtocolInitRule.swift:85:5: error: Unused declaration named 'init(protocolName:types:arguments:)'
Found 6 unused declarations (0.61s)
```
2023-01-27 19:51:13 -05:00
JP Simard 0750d5d465
Extract `EnumDeclSyntax.supportsRawValues` helper (#4727)
I'll want to use this elsewhere shortly.

Also adds `CGFloat` to the raw value types since we were missing that
one.
2023-01-27 16:46:54 -05:00
JP Simard 84c6d200b6
Clean up unused initializers (#4726)
Found with the upcoming improve dead code detection.
2023-01-27 16:31:56 -05:00
JP Simard 9ac13f078a
Update rules_xcodeproj to 0.12.3 (#4724)
https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/0.12.3
2023-01-26 21:24:21 -05:00
JP Simard c84124d8bc
Enable all tests when using rules_xcodeproj (#4723)
* Revert "Skip tests requiring runfiles support when testing with rules_xcodeproj (#4694)"

This reverts commit 040096a641.

* Enable all tests when using rules_xcodeproj

Turns out we don't need runfiles support
(https://github.com/buildbuddy-io/rules_xcodeproj/issues/828) since the
tests run outside the sandbox in Xcode, so we can get the path to these
files from the `BUILD_WORKSPACE_DIRECTORY` environment variable that
`bazel test` sets.
2023-01-26 21:18:05 -05:00
JP Simard 3907772163
Revert "[OSSCheck] Cache git repos (#4699)" (#4718)
This reverts commit fbd9f16955.
2023-01-23 17:05:15 +00:00
dependabot[bot] d98fd5386a
Bump activesupport from 6.1.6.1 to 6.1.7.1 (#4716)
Bumps [activesupport](https://github.com/rails/rails) from 6.1.6.1 to 6.1.7.1.
- [Release notes](https://github.com/rails/rails/releases)
- [Changelog](https://github.com/rails/rails/blob/v7.0.4.1/activesupport/CHANGELOG.md)
- [Commits](https://github.com/rails/rails/compare/v6.1.6.1...v6.1.7.1)

---
updated-dependencies:
- dependency-name: activesupport
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-21 09:18:21 +01:00
JP Simard 36c24c822c
Add "fixed releaser" to BCR config
So that the publish-to-bcr GitHub app uses my personal fork of
bazel-central-registry as documented in
https://github.com/bazel-contrib/publish-to-bcr/blob/main/templates/README.md#optional-configyml
2023-01-19 21:41:20 -05:00
Keith Smiley e1fdf17d1b
Add bazel BCR config (#4713) 2023-01-19 21:17:21 -05:00
Keith Smiley 23e4db3e5f
Add support for bzlmod (#4704) 2023-01-19 17:04:21 -05:00
JP Simard b4641e7e60
Update rules_xcodeproj to 0.12.2 (#4709)
https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/0.12.2
2023-01-19 15:36:47 -05:00
Danny Mösch 341db66f3c
Support Swift version 5.7.3 (#4711) 2023-01-19 15:35:41 -05:00
JP Simard c9791783ba
Update rules_xcodeproj to 0.12.0 (#4703)
This is the first release to fix running unit tests since 0.10.1.

It should include some performance improvements and bug fixes that will
benefit us.

https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/0.12.0
2023-01-18 16:14:55 +00:00
JP Simard dc228d57ac
Update dependencies (#4702) 2023-01-17 12:59:32 -05:00
JP Simard fbd9f16955
[OSSCheck] Cache git repos (#4699)
By maintaining persistent clones of the repos which are incrementally
synced instead of cloned from scratch on every run.
2023-01-17 12:07:48 -05:00
JP Simard d120f41181
[CI] Remove 'TSan Runs' job (#4701)
This frequently crashes and I don't think it's due to a real TSan race.

E.g. https://buildkite.com/swiftlint/swiftlint/builds/4912#0185c098-a803-4525-8df1-827d1c97ed01

```
swiftlint(373,0x1ecdd3a80) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
Linting Swift files in current working directory
1 of 538 [                              ] ETA: 0s (13129 files/s)
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
ThreadSanitizer:DEADLYSIGNAL
==373==ERROR: ThreadSanitizer: SEGV on unknown address 0x000000000008 (pc 0x000102cbe380 bp 0x00016f50ee00 sp 0x00016f50edc0 T30753687)
==373==The signal is caused by a UNKNOWN memory access.
==373==Hint: address points to the zero page.
    #0 __tsan::ThreadClock::release(__tsan::DenseSlabAllocCache*, __tsan::SyncClock*) <null>:46801128 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2a380)
    #1 __tsan::Release(__tsan::ThreadState*, unsigned long, unsigned long) <null>:46801128 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x7456c)
    #2 swift::runJobInEstablishedExecutorContext(swift::Job*) <null>:46801128 (libswift_Concurrency.dylib:arm64e+0x40588)
    #3 swift_job_runImpl(swift::Job*, swift::ExecutorRef) <null>:46801128 (libswift_Concurrency.dylib:arm64e+0x41404)
    #4 _dispatch_root_queue_drain <null>:46801128 (libdispatch.dylib:arm64e+0x15f90)
    #5 _dispatch_worker_thread2 <null>:46801128 (libdispatch.dylib:arm64e+0x167bc)
    #6 _pthread_wqthread <null>:46801128 (libsystem_pthread.dylib:arm64e+0x30c0)
    #7 start_wqthread <null>:46801128 (libsystem_pthread.dylib:arm64e+0x1e1c)

==373==Register values:
 x[0] = 0x0000000102a53458   x[1] = 0x0000000000000538   x[2] = 0x0000000000000000   x[3] = 0x0000000000000000
 x[4] = 0x0000000000000001   x[5] = 0x0000000000000000   x[6] = 0x0095000004220122   x[7] = 0x0000000000000001
 x[8] = 0x0000000000000008   x[9] = 0x0000000000000000  x[10] = 0x0000000000000000  x[11] = 0x0000000000000000
x[12] = 0x0000000000000020  x[13] = 0x0000000110904040  x[14] = 0x0000000000000000  x[15] = 0x0000000106251910
x[16] = 0x0000000104190960  x[17] = 0x0000000000200018  x[18] = 0x0000000000000000  x[19] = 0x000000010f5d3488
x[20] = 0x0000000109ca03f0  x[21] = 0x0000000102a53458  x[22] = 0x0000000109ca03f0  x[23] = 0x0000000109cc0078
x[24] = 0x00040c0000fd77c4  x[25] = 0x0000010000000000  x[26] = 0x00000002287898f8  x[27] = 0x0000000000000000
x[28] = 0x000000016f50f0e0     fp = 0x000000016f50ee00     lr = 0x0000000102cbe360     sp = 0x000000016f50edc0
ThreadSanitizer can not provide additional info.
SUMMARY: ThreadSanitizer: SEGV (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2a380) in __tsan::ThreadClock::release(__tsan::DenseSlabAllocCache*, __tsan::SyncClock*)+0x174
==373==ABORTING
```
2023-01-17 11:42:46 -05:00
JP Simard db6aea5d07
Disable remote cache for the "TSan Runs" CI job (#4700)
I suspect it might be the reason why it occasionally crashes.
2023-01-17 11:24:48 -05:00
JP Simard 876d8fc872
Remove `.swp` file that snuck in (#4697)
https://github.com/realm/SwiftLint/pull/4657
2023-01-17 08:23:53 -05:00
JP Simard 45c5f06754
Move changelog sections to the latest section (#4698)
These were introduced after 0.50.3 was released.
2023-01-17 13:16:12 +00:00
JP Simard 040096a641
Skip tests requiring runfiles support when testing with rules_xcodeproj (#4694)
rules_xcodeproj doesn't support runfiles yet:
https://github.com/buildbuddy-io/rules_xcodeproj/issues/828
2023-01-16 13:09:56 -05:00
JP Simard f91a2d5310
Revert rules_xcodeproj to 0.10.1 (#4693)
It looks like later versions can't run tests because of
https://github.com/buildbuddy-io/rules_xcodeproj/issues/1586.
2023-01-16 17:14:31 +00:00
Danny Mösch f8f2317bdb
Extract common plugin execution code to method (#4690) 2023-01-14 12:35:53 +01:00
Danny Mösch 82249f5ed4
Include recently added option into rule/cache description (#4688) 2023-01-13 17:37:29 -05:00
Danny Mösch 78c9ad6f33
Rephrase rule description (#4686)
"Can't" sounds too hard. The Swift compiler allows multiple enum cases with the same name. It's rather a recommendation.
2023-01-12 18:06:04 +01:00
Danny Mösch 693e504258
Use basic NSRegularExpression type with caching (#4683) 2023-01-11 20:28:16 +01:00
Danny Mösch b66dd13e2f
Ensure negative literals in initializers don't trigger `no_magic_numbers` (#4679) 2023-01-11 00:09:53 +01:00
kyounh12 5ec6112ba1
Interpret strings in `excluded` option of `*_name` rules as regex (#4655) 2023-01-10 23:29:04 +01:00
Danny Mösch 74dbd52add Fix/improve some rule descriptions 2023-01-10 22:29:13 +01:00
Danny Mösch cc44c989b7 Check every used internal violation reason for a pending period 2023-01-10 22:29:13 +01:00
Danny Mösch e64e82d80d Get rid of periods finishing rule descriptions 2023-01-10 22:29:13 +01:00
dependabot[bot] ea8b17dd9c
Bump git from 1.12.0 to 1.13.0 (#4678)
Bumps [git](https://github.com/ruby-git/ruby-git) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/ruby-git/ruby-git/releases)
- [Changelog](https://github.com/ruby-git/ruby-git/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ruby-git/ruby-git/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: git
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 17:29:07 -05:00
Danny Mösch 672e19651f Use configuration raw name expected when reading the configuration 2023-01-08 15:05:43 +01:00
Danny Mösch 67eb330f1c Add key to severity configuration as a hint for the correct YAML syntax 2023-01-08 15:05:43 +01:00
JP Simard e6d4ad653c
Pin SwiftSyntax to a tagged version (#4674)
Specifically this tag:
https://github.com/apple/swift-syntax/releases/tag/0.50800.0-SNAPSHOT-2022-12-29-a

This should make SwiftPM happier about the stability of the pinned
version.

Also switch the CI job to run on macOS to avoid adding Linux-only deps
to the `Package.resolved` file (e.g. CryptoSwift).
2023-01-06 13:10:59 -05:00
JP Simard 100b3eec2a
Update Docker CI job to use `actions/checkout@v3` (#4675) 2023-01-06 18:04:50 +00:00
github-actions[bot] bcfc2c4b6c
Update SwiftSyntax (#4673)
* Exclude `Documentation.docc` when building SwiftSyntax
* Remove references to `.stringInterpolationAnchor`

Co-authored-by: JP Simard <jp@jpsim.com>
2023-01-06 11:12:17 -05:00
Ethan Wong 68dc0f58d2
List Analyzer rules in an independent section in the rule directory (#4664) 2023-01-03 07:18:25 +01:00
Danny Mösch d6ff2a7f37
Rewrite `explicit_type_interface` rule with SwiftSyntax fixing a false-positive (#4638) 2023-01-01 23:23:50 +01:00
Danny Mösch 64d9619a8a
Report violations in all `<scope>_length` rules when error < warning threshold (#4647) 2023-01-01 23:15:36 +01:00
github-actions[bot] 470d471e51
Update SwiftSyntax (#4659)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-12-26 09:37:51 -05:00
Danny Mösch 5ff40867b3
Apply consistent capitalization to rule names (#3938) 2022-12-26 09:32:36 +01:00
Martin Redington 58611e6718
Ignore compiler directives in `opening_brace` rule (#4658) 2022-12-25 18:46:16 +01:00
Danny Mösch c740da48d5
Deprecate `inert_defer` rule in favor of the Swift compiler warning (#4618) 2022-12-23 04:07:41 -05:00
Jimmy Arts eda0d92f44
Make forceExclude work with directly specified files (#4609) 2022-12-22 21:15:08 +01:00
Benedek Kozma d76daf5f62
Deprecate `unused_capture_list` rule in favor of the Swift compiler warning (#4656) 2022-12-22 10:33:44 -05:00
JP Simard 1a39194f65
Update rules_xcodeproj to 0.11.0 (#4653)
https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/0.11.0
2022-12-21 18:07:55 -05:00
JP Simard 0e53e19cb1
[CI] Increase timeout for `analyze` CI job to 60 minutes (#4654)
I recently moved CI machines over to use Xcode 14.2 and it's possible
that running SwiftLint analyzer rules now take longer.
2022-12-21 17:37:44 -05:00
JP Simard 3cba460f9a
Update rules_apple to 2.0.0 (#4652)
https://github.com/bazelbuild/rules_apple/releases/tag/2.0.0
2022-12-21 16:08:44 -05:00
Julio Carrettoni d3928cb8e8
Update docker_test to swift 5.7 (#4625) 2022-12-19 19:12:44 -03:00
JP Simard a6c3cec8c9
Update to Bazel 6.0.0 (#4651)
https://www.buildbuddy.io/blog/whats-new-in-bazel-6-0/
2022-12-19 15:12:53 -05:00
Marcelo Fabri 7bd8362dae
Fix false positive on `private_subject` (#4646)
Fixes #4643
2022-12-19 13:31:34 -03:00
JP Simard e1cddb710d
Remove remote bazel cache steps from CI instructions (#4650)
Moved over to BuildBuddy.
2022-12-19 11:02:04 -05:00
github-actions[bot] 4a6387da67
Update SwiftSyntax (#4649)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-12-19 09:22:53 -05:00
Danny Mösch 83ee9a89dd
Add Swift version 5.7.2 (#4648) 2022-12-17 04:18:21 -05:00
David Steinacher 540003e2a1
Add support for new Quick APIs `aroundEach` and `justBeforeEach` (#4627) 2022-12-15 23:29:02 +01:00
Julio Carrettoni 3745704c03
Add rule for single space after period on comments (#4624) 2022-12-15 23:27:33 +01:00
github-actions[bot] 33fa42becb
Update SwiftSyntax (#4644)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-12-14 11:17:34 -05:00
github-actions[bot] 25c3fb161d
Update SwiftSyntax (#4639)
* `ObjcKeyPathExprSyntax` -> `MacroExpansionExprSyntax`
* Fix `#selector()` and add a regression test

Co-authored-by: JP Simard <jp@jpsim.com>
2022-12-14 10:52:47 -05:00
JP Simard 53ee4a955d
Fix `make release`
`make package` has a dependency on `make clean` so this was removing
the bazel release artifacts.
2022-12-09 14:42:20 -05:00
JP Simard 40fb3796cb
Add empty changelog section 2022-12-09 14:41:42 -05:00
JP Simard a876e860ee
release 0.50.3 2022-12-09 14:12:02 -05:00
JP Simard 4c406459bd
Set first changelog entry header to `Main` again 2022-12-09 14:10:55 -05:00
JP Simard 4ddeb22b6d
Fix `Package.swift` 2022-12-09 14:08:08 -05:00
JP Simard ff06e0ed00
release 0.50.2 2022-12-09 13:49:24 -05:00
github-actions[bot] 6734a64554
Update SwiftSyntax (#4636)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-12-09 13:25:09 -05:00
JP Simard 73a64d674c
Fix rewrite issue with `comma` rule (#4635) 2022-12-09 12:56:50 -05:00
github-actions[bot] 7f8eb9de77
Update SwiftSyntax (#4629)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-12-07 17:44:23 -05:00
Danny Mösch 609418f702
Skip `defer` statements in `#if` block if it is not itself the last statement (#4617) 2022-12-06 02:22:03 -05:00
Danny Mösch 4adabd8e4b
Print a warning for Analyzer rules misplaced in the configuration (#4620) 2022-12-05 18:03:54 -05:00
Danny Mösch 93d0d8fa7f
Fix configuration parsing error in `unused_declaration` rule (#4619) 2022-12-05 23:11:19 +01:00
JP Simard 4dfef014ab
Build with `--swiftcopt=-warnings-as-errors` when using Bazel (#4622) 2022-12-05 11:33:02 -05:00
JP Simard 95d56e4130
Use `raw` in SwiftSyntaxBuilder string interpolation (#4623)
Fixing build warnings to account for
https://github.com/apple/swift-syntax/pull/1090.
2022-12-05 11:26:04 -05:00
JP Simard 7f9dd69c62
Move changelog entries to correct sections 2022-12-05 10:33:29 -05:00
github-actions[bot] ac44fe23b6
Update SwiftSyntax (#4621)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-12-05 08:40:45 -05:00
Marcelo Fabri 60128ab196
Don’t trigger shorthand_operator inside operator declaration (#4613)
Fixes #4611
2022-12-02 02:00:44 -05:00
Martin Redington 7a8b2d1dab
Add `test_parent_class` option to more test rules (#4262) 2022-12-01 18:56:13 +01:00
Ryan Aveo 92304cdd98
Fix building tests in Xcode (#4607)
Co-authored-by: JP Simard <jp@jpsim.com>
2022-11-30 10:33:33 -05:00
Tony Arnold ab143685a4
Use a binary target for the build tool plugin (#4603)
* Use a binary target for the build tool plugin

* Merge `push_version` and `release` make commands

Instead of running `make push_version "0.2.0: Tumble Dry"` and then
`make release`, now run `make release "0.2.0: Tumble Dry"`, which will
build the release artifacts and update/push the new version to GitHub.

This allows the artifacts to use the new version, update the artifact
bundle checksum in the package manifest, then tag the release.

The Releasing.md instructions were updated to reflect this new workflow.

* Add `SwiftLintSourcePlugin` source plugin for SwiftPM

* Add changelog entry

* Remove SwiftLintSourcePlugin for now

* Build from Source on Linux

* Use a lower-level method of checking if a file is accessible

This shouldn’t trigger sandbox violations, I hope…

* Prevent an infinite recursion of the filesystem root

* Remove unnecessary logging

* Quieten the output so that Xcode only prints violations

* Break up comment to avoid line length warning

* Fix capitalization of Glibc import

Co-authored-by: JP Simard <jp@jpsim.com>
2022-11-29 18:10:47 -05:00
github-actions[bot] 9cb1069090
Update SwiftSyntax (#4605)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-11-29 15:30:56 -05:00
JP Simard e405d3d583
Fix `update-swift-syntax.sh` script (#4604) 2022-11-29 15:07:37 -05:00
Steffen Matthischke 97ba82d740
Fix empty_enum_arguments false positive when called expression is an identifier (#4600) 2022-11-28 17:20:34 -05:00
JP Simard d8d5e5bb43
Add empty changelog section 2022-11-28 09:20:39 -05:00
653 changed files with 11137 additions and 6779 deletions

1
.bazelignore Normal file
View File

@ -0,0 +1 @@
.build

View File

@ -1,8 +1,14 @@
common --enable_bzlmod
try-import %workspace%/ci.bazelrc
try-import %workspace%/user.bazelrc
build --macos_minimum_os=12.0 --host_macos_minimum_os=12.0
build --disk_cache=~/.bazel_cache
build --experimental_remote_cache_compression
build --experimental_remote_build_event_upload=minimal
build --nolegacy_important_outputs
build --swiftcopt=-warnings-as-errors
build:release \
--compilation_mode=opt \

View File

@ -1 +1 @@
5.3.2
6.2.0

3
.bcr/config.yml Normal file
View File

@ -0,0 +1,3 @@
fixedReleaser:
login: jpsim
email: jp@jpsim.com

View File

@ -0,0 +1,15 @@
{
"homepage": "https://github.com/realm/SwiftLint",
"maintainers": [
{
"email": "jp@jpsim.com",
"github": "jpsim",
"name": "JP Simard"
}
],
"repository": [
"github:realm/SwiftLint"
],
"versions": [],
"yanked_versions": {}
}

24
.bcr/presubmit.yml Normal file
View File

@ -0,0 +1,24 @@
shell_commands: &shell_commands
- "echo --- Downloading and extracting Swift $SWIFT_VERSION to $SWIFT_HOME"
- "mkdir $SWIFT_HOME"
- "curl https://download.swift.org/swift-${SWIFT_VERSION}-release/ubuntu2004/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu20.04.tar.gz | tar xvz --strip-components=1 -C $SWIFT_HOME"
tasks:
verify_targets_linux:
name: Verify targets (Linux)
platform: ubuntu2004
environment:
CC: "clang"
SWIFT_VERSION: "5.7.2"
SWIFT_HOME: "$HOME/swift-$SWIFT_VERSION"
PATH: "$PATH:$SWIFT_HOME/usr/bin"
shell_commands: *shell_commands
build_flags:
- "--action_env=PATH"
build_targets:
- '@SwiftLint//:swiftlint'
verify_targets_macos:
name: Verify targets (macOS)
platform: macos
build_targets:
- '@SwiftLint//:swiftlint'

View File

@ -0,0 +1,5 @@
{
"url": "https://github.com/realm/SwiftLint/releases/download/{TAG}/bazel.tar.gz",
"integrity": "",
"strip_prefix": ""
}

View File

@ -11,23 +11,19 @@ steps:
- swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES
- label: "Danger"
commands:
- echo "--- Build Danger"
- bazel build //tools:danger
- echo "--- Install Bundler"
- gem install bundler
- echo "--- Bundle Install"
- bundle install
- echo "+++ Run Danger"
- ./bazel-bin/tools/danger --verbose
- label: "Analyze"
commands:
- echo "+++ Analyze"
- bazel test -c opt --test_output=streamed --test_timeout=1800 --spawn_strategy=local analyze
- bundle exec danger --verbose
- label: "TSan Tests"
commands:
- echo "+++ Test"
- bazel test --test_output=streamed --build_tests_only --features=tsan --test_timeout=1000 //Tests/...
- label: "TSan Runs"
- bazel test --test_output=errors --build_tests_only --features=tsan --test_timeout=1000 //Tests/...
- label: "Sourcery"
commands:
- echo "--- Build"
- bazel build --config=release --features=tsan swiftlint
- echo "+++ Pre-cache SwiftLint Run"
- ./bazel-bin/swiftlint --progress --lenient
- echo "+++ Post-cache SwiftLint Run"
- ./bazel-bin/swiftlint --progress --lenient
- echo "+++ Run Sourcery"
- make --always-make sourcery
- echo "+++ Diff Files"
- git diff --quiet HEAD

View File

@ -9,10 +9,10 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Extract DOCKER_TAG using tag name
if: startsWith(github.ref, 'refs/tags/')

View File

@ -1,36 +0,0 @@
name: update_swift_syntax
on:
workflow_dispatch:
schedule:
# Mondays at 1pm UTC (9am EDT)
- cron: "0 13 * * 1"
jobs:
update_swift_syntax:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v2
- name: Update SwiftSyntax
id: update-swift-syntax
run: ./tools/update-swift-syntax.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check for changes
id: state
run: |
if ! git diff-index --quiet HEAD --; then
echo "dirty=true" >> $GITHUB_OUTPUT
fi
- name: Create PR
if: steps.state.outputs.dirty == 'true'
uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27
with:
title: Update SwiftSyntax
body: |
Diff: https://github.com/apple/swift-syntax/compare/${{ steps.update-swift-syntax.outputs.old_commit }}...${{ steps.update-swift-syntax.outputs.new_commit }}
commit-message: Update SwiftSyntax
delete-branch: true
branch: update-swift-syntax
branch-suffix: timestamp

2
.gitignore vendored
View File

@ -1,6 +1,5 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
@ -22,6 +21,7 @@ xcuserdata
*.moved-aside
*.xcuserstate
*.xcscmblueprint
default.profraw
## Obj-C/Swift specific
*.hmap

View File

@ -1,4 +1,4 @@
module: SwiftLintFramework
module: SwiftLintCore
author: JP Simard, SwiftLint Contributors
author_url: https://jpsim.com
root_url: https://realm.github.io/SwiftLint/
@ -7,13 +7,14 @@ github_file_prefix: https://github.com/realm/SwiftLint/tree/main
swift_build_tool: spm
theme: fullwidth
clean: true
copyright: '© 2022 [JP Simard](https://jpsim.com) under MIT.'
copyright: '© 2023 [JP Simard](https://jpsim.com) under MIT.'
documentation: rule_docs/*.md
hide_unlisted_documentation: true
custom_categories_unlisted_prefix: ''
exclude:
- Source/SwiftLintFramework/Rules/**/*.swift
# TODO: Document extensions
- Source/SwiftLintCore/Extensions/*.swift
custom_categories:
- name: Rules
children:

View File

@ -1,4 +1,5 @@
/// The rule list containing all available rules built into SwiftLint.
public let primaryRuleList = RuleList(rules: [
public let builtInRules: [Rule.Type] = [
{% for rule in types.structs where rule.name|hasSuffix:"Rule" or rule.name|hasSuffix:"Rules" %} {{ rule.name }}.self{% if not forloop.last %},{% endif %}
{% endfor %}] + extraRules())
{% endfor %}]

View File

@ -1,12 +1,14 @@
@testable import SwiftLintFramework
@testable import SwiftLintBuiltInRules
@_spi(TestHelper)
@testable import SwiftLintCore
import SwiftLintTestHelpers
import XCTest
// swiftlint:disable:next blanket_disable_command
// swiftlint:disable file_length single_test_class type_name
{% for rule in types.structs %}
{% if rule.name|hasSuffix:"Rule" %}
class {{ rule.name }}GeneratedTests: XCTestCase {
class {{ rule.name }}GeneratedTests: SwiftLintTestCase {
func testWithDefaultConfiguration() {
verifyRule({{ rule.name }}.description)
}

View File

@ -0,0 +1,7 @@
/// The reporters list containing all the reporters built into SwiftLint.
public let reportersList: [Reporter.Type] = [
{% for reporter in types.structs where reporter.name|hasSuffix:"Reporter" %}
{{ reporter.name }}.self{% if not forloop.last %},{% endif %}
{% endfor %}
]

View File

@ -8,75 +8,55 @@ analyzer_rules:
- unused_declaration
- unused_import
opt_in_rules:
- array_init
- attributes
- closure_end_indentation
- closure_spacing
- collection_alignment
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- discouraged_none_name
- discouraged_object_literal
- empty_collection_literal
- empty_count
- empty_string
- empty_xctest_method
- enum_case_associated_values_count
- explicit_init
- extension_access_modifier
- fallthrough
- fatal_error_message
- file_header
- file_name
- first_where
- flatmap_over_map_reduce
- identical_operands
- joined_default_parameter
- last_where
- legacy_multiple
- literal_expression_end_indentation
- local_doc_comment
- lower_acl_than_parent
- modifier_order
- nimble_operator
- nslocalizedstring_key
- number_separator
- object_literal
- operator_usage_whitespace
- overridden_super_call
- override_in_extension
- pattern_matching_keywords
- prefer_self_type_over_type_of_self
- private_action
- private_outlet
- prohibited_interface_builder
- prohibited_super_call
- quick_discouraged_call
- quick_discouraged_focused_test
- quick_discouraged_pending_test
- reduce_into
- redundant_nil_coalescing
- redundant_type_annotation
- return_value_from_void_function
- single_test_class
- sorted_first_last
- sorted_imports
- static_operator
- strong_iboutlet
- test_case_accessibility
- toggle_bool
- unavailable_function
- unneeded_parentheses_in_closure_argument
- unowned_variable_capture
- untyped_error_in_catch
- vertical_parameter_alignment_on_call
- vertical_whitespace_closing_braces
- vertical_whitespace_opening_braces
- xct_specific_matcher
- yoda_condition
- all
disabled_rules:
- anonymous_argument_in_multiline_closure
- anyobject_protocol
- closure_body_length
- conditional_returns_on_newline
- convenience_type
- discouraged_optional_collection
- explicit_acl
- explicit_enum_raw_value
- explicit_top_level_acl
- explicit_type_interface
- file_types_order
- force_unwrapping
- function_default_parameter_at_end
- implicit_return
- implicitly_unwrapped_optional
- indentation_width
- inert_defer
- missing_docs
- multiline_arguments
- multiline_arguments_brackets
- multiline_function_chains
- multiline_literal_brackets
- multiline_parameters
- multiline_parameters_brackets
- no_extension_access_modifier
- no_fallthrough_only
- no_grouping_extension
- no_magic_numbers
- prefer_nimble
- prefer_self_in_static_references
- prefixed_toplevel_constant
- redundant_self_in_closure
- required_deinit
- self_binding
- sorted_enum_cases
- strict_fileprivate
- superfluous_else
- switch_case_on_newline
- todo
- trailing_closure
- type_contents_order
- unused_capture_list
- vertical_whitespace_between_cases
attributes:
always_on_line_above:
- "@OptionGroup"
identifier_name:
excluded:
- id
@ -85,19 +65,27 @@ number_separator:
minimum_length: 5
file_name:
excluded:
- SwiftSyntax+SwiftLint.swift
- Exports.swift
- GeneratedTests.swift
- SwiftSyntax+SwiftLint.swift
- TestHelpers.swift
balanced_xctest_lifecycle: &unit_test_configuration
test_parent_classes:
- SwiftLintTestCase
- XCTestCase
empty_xctest_method: *unit_test_configuration
single_test_class: *unit_test_configuration
function_body_length: 60
type_body_length: 400
custom_rules:
rule_id:
included: Source/SwiftLintFramework/Rules/.+/\w+\.swift
included: Source/SwiftLintBuiltInRules/Rules/.+/\w+\.swift
name: Rule ID
message: Rule IDs must be all lowercase, snake case and not end with `rule`
regex: identifier:\s*("\w+_rule"|"\S*[^a-z_]\S*")
regex: ^\s+identifier:\s*("\w+_rule"|"\S*[^a-z_]\S*")
severity: error
fatal_error:
name: Fatal Error
@ -117,3 +105,4 @@ custom_rules:
unused_import:
always_keep_imports:
- SwiftSyntaxBuilder # we can't detect uses of string interpolation of swift syntax nodes
- SwiftLintFramework # now that this is a wrapper around other modules, don't treat as unused

76
BUILD
View File

@ -5,29 +5,68 @@ load(
"swift_library",
)
load(
"@com_github_buildbuddy_io_rules_xcodeproj//xcodeproj:defs.bzl",
"@rules_xcodeproj//xcodeproj:defs.bzl",
"xcode_schemes",
"xcodeproj",
)
# Targets
swift_library(
name = "SwiftLintCore",
srcs = glob(["Source/SwiftLintCore/**/*.swift"]),
module_name = "SwiftLintCore",
visibility = ["//visibility:public"],
deps = [
"@SwiftSyntax//:SwiftIDEUtils_opt",
"@SwiftSyntax//:SwiftOperators_opt",
"@SwiftSyntax//:SwiftParserDiagnostics_opt",
"@SwiftSyntax//:SwiftSyntaxBuilder_opt",
"@SwiftSyntax//:SwiftSyntax_opt",
"@com_github_jpsim_sourcekitten//:SourceKittenFramework",
"@sourcekitten_com_github_jpsim_yams//:Yams",
"@swiftlint_com_github_scottrhoyt_swifty_text_table//:SwiftyTextTable",
] + select({
"@platforms//os:linux": ["@com_github_krzyzanowskim_cryptoswift//:CryptoSwift"],
"//conditions:default": [":DyldWarningWorkaround"],
}),
)
swift_library(
name = "SwiftLintBuiltInRules",
srcs = glob(["Source/SwiftLintBuiltInRules/**/*.swift"]),
module_name = "SwiftLintBuiltInRules",
visibility = ["//visibility:public"],
deps = [
":SwiftLintCore",
],
)
swift_library(
name = "SwiftLintExtraRules",
srcs = [
"Source/SwiftLintExtraRules/Exports.swift",
"@swiftlint_extra_rules//:extra_rules",
],
module_name = "SwiftLintExtraRules",
visibility = ["//visibility:public"],
deps = [
":SwiftLintCore",
],
)
swift_library(
name = "SwiftLintFramework",
srcs = glob(
["Source/SwiftLintFramework/**/*.swift"],
exclude = ["Source/SwiftLintFramework/Rules/ExcludedFromBazel/ExtraRules.swift"],
) + ["@swiftlint_extra_rules//:extra_rules"],
),
module_name = "SwiftLintFramework",
visibility = ["//visibility:public"],
deps = [
"@com_github_jpsim_sourcekitten//:SourceKittenFramework",
"@com_github_apple_swift_syntax//:optlibs",
"@sourcekitten_com_github_jpsim_yams//:Yams",
] + select({
"@platforms//os:linux": ["@com_github_krzyzanowskim_cryptoswift//:CryptoSwift"],
"//conditions:default": [],
}),
":SwiftLintBuiltInRules",
":SwiftLintCore",
":SwiftLintExtraRules",
],
)
swift_library(
@ -63,6 +102,21 @@ apple_universal_binary(
visibility = ["//visibility:public"],
)
filegroup(
name = "DyldWarningWorkaroundSources",
srcs = [
"Source/DyldWarningWorkaround/DyldWarningWorkaround.c",
"Source/DyldWarningWorkaround/include/objc_dupclass.h",
],
)
cc_library(
name = "DyldWarningWorkaround",
srcs = ["//:DyldWarningWorkaroundSources"],
includes = ["Source/DyldWarningWorkaround/include"],
alwayslink = True,
)
# Linting
filegroup(
@ -81,6 +135,8 @@ filegroup(
srcs = [
"BUILD",
"LICENSE",
"MODULE.bazel",
"//:DyldWarningWorkaroundSources",
"//:LintInputs",
"//Tests:BUILD",
"//bazel:release_files",

View File

@ -1,3 +1,497 @@
## Main
#### Breaking
* None.
#### Experimental
* None.
#### Enhancements
* Mention a rule's identifier in the console message that is printed when the
rule's associated configuration entry contains invalid values.
[SimplyDanny](https://github.com/SimplyDanny)
* Silence `xct_specific_matcher` rule on "one argument asserts" if there are
potential types or tuples involved in the comparison as types and tuples do
not conform to `Equatable`.
[SimplyDanny](https://github.com/SimplyDanny)
[#4990](https://github.com/realm/SwiftLint/issues/4990)
* Add `grouping` option to the `sorted_imports` rule allowing
to sort groups of imports defined by their preceding attributes
(e.g. `@testable`, `@_exported`, ...).
[hiltonc](https://github.com/hiltonc)
* Do not trigger `redundant_self_in_closure` rule when another idenfier `x` in
scope shadows the field accessed by `self.x` to avoid semantical changes.
[SimplyDanny](https://github.com/SimplyDanny)
[#5010](https://github.com/realm/SwiftLint/issues/5010)
#### Bug Fixes
* The option `validates_start_with_lowercase` can now be disabled by setting it
to `off`.
[SimplyDanny](https://github.com/SimplyDanny)
[#5036](https://github.com/realm/SwiftLint/issues/5036)
* Do not trigger `prefer_self_in_static_references` rule on `typealias`
declarations in classes.
[SimplyDanny](https://github.com/SimplyDanny)
[#5009](https://github.com/realm/SwiftLint/issues/5009)
* Do not trigger `prefer_self_in_static_references` rule on collection types in
classes, but on initializers like `[C]()` in all types.
[SimplyDanny](https://github.com/SimplyDanny)
[#5042](https://github.com/realm/SwiftLint/issues/5042)
* Fix false positives on `redundant_objc_attribute` rule for enums
and private members.
[Martin Redington](https://github.com/mildm8nnered)
[#4633](https://github.com/realm/SwiftLint/issues/4633)
* Fix autocorrect for `CGIntersectionRect` in `legacy_cggeometry_functions`
rule.
[Haoocen](https://github.com/Haoocen)
[#5023](https://github.com/realm/SwiftLint/pull/5023)
* Fix false positives on `sorted_first_last` rule when `first`/`last` have
a predicate.
[woxtu](https://github.com/woxtu)
[#3023](https://github.com/realm/SwiftLint/issues/3023)
## 0.52.2: Crisper Clearer Pleats
#### Breaking
* None.
#### Experimental
* None.
#### Enhancements
* Exclude simple assignments of the form `self.x = x` from being reported by
the `redundant_self_in_closure` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4988](https://github.com/realm/SwiftLint/issues/4988)
#### Bug Fixes
* Make `unhandled_throwing_task` opt-in instead of enabled by default. The rule
is still prone to false positives at this point, so this makes enabling the
rule a conscious decision by end-users.
[JP Simard](https://github.com/jpsim)
[#4987](https://github.com/realm/SwiftLint/issues/4987)
* Fix `unhandled_throwing_task` false positives when the `Task` is returned or
where the throwing code is handled in a `Result` initializer.
[JP Simard](https://github.com/jpsim)
[#4987](https://github.com/realm/SwiftLint/issues/4987)
## 0.52.1: Crisp Clear Pleats
#### Breaking
* None.
#### Experimental
* None.
#### Enhancements
* None.
#### Bug Fixes
* Let the `validates_start_with_lowercase` option in name configurations
expect a severity (warning or error). Not setting it disables the check.
Boolean values are now deprecated. A `true` value enables the check as an
error for the time being to keep the previous behavior.
[SimplyDanny](https://github.com/SimplyDanny)
[#2180](https://github.com/realm/SwiftLint/issues/2180)
* Fixed a false positive in `unhandled_throwing_task`.
[kylebshr](https://github.com/kylebshr)
[#4984](https://github.com/realm/SwiftLint/issues/4984)
* Fix Bazel release tarball for compiling on macOS.
[JP Simard](https://github.com/jpsim)
[#4985](https://github.com/realm/SwiftLint/issues/4985)
## 0.52.0: Crisp Clear Pleats
#### Breaking
* The `attributes` rule now expects attributes with arguments to be placed
on their own line above the declaration they are supposed to influence.
This applies to attributes with any kinds of arguments including single
key path arguments which were previously handled in a different way. This
behavior can be turned off by setting `attributes_with_arguments_always_on_line_above`
to `false.
[SimplyDanny](https://github.com/SimplyDanny)
[#4843](https://github.com/realm/SwiftLint/issues/4843)
* The internal module structure for SwiftLint has changed to split the
monolithic `SwiftLintFramework` into new `SwiftLintCore` for core linter
infrastructure, `SwiftLintBuiltInRules` for built-in rules and
`SwiftLintExtraRules` to add your own native rules to SwiftLint.
[JP Simard](https://github.com/jpsim)
#### Experimental
* None.
#### Enhancements
* Add new `superfluous_else` rule that triggers on `if`-statements when an
attached `else`-block can be removed, because all branches of the previous
`if`-block(s) would certainly exit the current scope already.
[SimplyDanny](https://github.com/SimplyDanny)
* Add `sorted_enum_cases` rule which warns when enum cases are not sorted.
[kimdv](https://github.com/kimdv)
* Add new `redundant_self_in_closure` rule that triggers in closures on
explicitly used `self` when it's actually not needed due to:
* Strongly captured `self` (`{ [self] in ... }`)
* Closure used in a struct declaration (`self` can always be omitted)
* Anonymous closures that are directly called (`{ ... }()`) as they are
definitly not escaping
* Weakly captured `self` with explicit unwrapping
[SimplyDanny](https://github.com/SimplyDanny)
[#59](https://github.com/realm/SwiftLint/issues/59)
* Extend `xct_specific_matcher` rule to check for boolean asserts on (un)equal
comparisons. The rule can be configured with the matchers that should trigger
rule violations. By default, all matchers trigger, but that can be limited to
just `one-argument-asserts` or `two-argument-asserts`.
[SimplyDanny](https://github.com/SimplyDanny)
[JP Simard](https://github.com/jpsim)
[#3726](https://github.com/realm/SwiftLint/issues/3726)
* Trigger `prefer_self_in_static_references` rule on more type references.
[SimplyDanny](https://github.com/SimplyDanny)
* Adds a new `reporters` command, to improve discoverability of reporters.
[Martin Redington](https://github.com/mildm8nnered)
[#4819](https://github.com/realm/SwiftLint/issues/4819)
* Adds `test_parent_classes` option to the `no_magic_numbers` rule.
Violations within test classes will now be ignored by default.
[Martin Redington](https://github.com/mildm8nnered)
[#4896](https://github.com/realm/SwiftLint/issues/4896)
* Stop enforcing calls to super from the override functions `setUp()`,
`tearDown()`, `setUpWithError()`, and `tearDownWithError()` in `XCTestCase`
subclasses.
[AndrewDMontgomery](https://github.com/andrewdmontgomery)
[#4875](https://github.com/realm/SwiftLint/pull/4875)
* Prepend `warning: ` to error messages so that they show in Xcode.
[whiteio](https://github.com/whiteio)
[#4923](https://github.com/realm/SwiftLint/issues/4923)
* The `attributes` rule received a new boolean option
`attributes_with_arguments_always_on_line_above` which is `true` by default.
Setting it to `false` ensures that attributes with arguments like
`@Persisted(primaryKey: true)` don't violate the rule if they are on the same
line with the variable declaration.
[SimplyDanny](https://github.com/SimplyDanny)
[#4843](https://github.com/realm/SwiftLint/issues/4843)
* Add new `unhandled_throwing_task` rule that triggers when a Task with an
implicit error type has unhandled trys or errors thrown inside its body.
This results in errors being silently discarded, which may be unexpected.
See this forum thread for more details: https://forums.swift.org/t/56066
[kylebshr](https://github.com/kylebshr)
#### Bug Fixes
* Fix `lower_acl_than_parent` rule rewriter by preserving leading whitespace.
[SimplyDanny](https://github.com/SimplyDanny)
[#4860](https://github.com/realm/SwiftLint/issues/4860)
* Ignore block comments in `let_var_whitespace` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4871](https://github.com/realm/SwiftLint/issues/4871)
* Fix false positives in `indentation_width` rule.
[Sven Münnich](https://github.com/svenmuennich)
* Do not trigger `reduce_boolean` on `reduce` methods with a first named
argument that is different from `into`.
[SimplyDanny](https://github.com/SimplyDanny)
[#4894](https://github.com/realm/SwiftLint/issues/4894)
* Work around dyld warning about duplicate SwiftSyntax classes.
[keith](https://github.com/keith)
[#4782](https://github.com/realm/SwiftLint/issues/4782)
* Improve lint times of SwiftLintPlugin by moving the
`excludedPaths(fileManager:)` operation out of the linting iterations.
[andyyhope](https://github.com/andyyhope)
[#4844](https://github.com/realm/SwiftLint/issues/4844)
## 0.51.0: bzllint
#### Breaking
* Deprecate the `unused_capture_list` rule in favor of the Swift compiler
warning. At the same time, make it an opt-in rule.
[Cyberbeni](https://github.com/Cyberbeni)
[#4656](https://github.com/realm/SwiftLint/issues/4656)
* Deprecate the `inert_defer` rule in favor of the Swift compiler warning.
At the same time, make it an opt-in rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4615](https://github.com/realm/SwiftLint/issues/4615)
* Interpret strings in `excluded` option of `identifier_name`,
`type_name` and `generic_type_name` rules as regular expression. Existing
configurations should remain working without notice as long as they don't
contain characters that must be escaped in regular expression.
[Moly](https://github.com/kyounh12)
[#4655](https://github.com/realm/SwiftLint/pull/4655)
#### Experimental
* None.
#### Enhancements
* Add `duplicate_conditions` rule which warns when a condition is duplicated
in separate branches of the same branching statement (if-else, or switch).
[1in1](https://github.com/1in1)
[#4666](https://github.com/realm/SwiftLint/issues/4666)
* Add local links to rule descriptions to every rule listed
in `Rule Directory.md`.
[kattouf](https://github.com/kattouf)
* Make forceExclude work with directly specified files.
[jimmya](https://github.com/jimmya)
[#4609](https://github.com/realm/SwiftLint/issues/4609)
* Adds `all` pseudo-rule for `opt_in_rules` - enables all opt in rules
that are not listed in `disabled_rules`
[Martin Redington](https://github.com/mildm8nnered)
[#4540](https://github.com/realm/SwiftLint/issues/4540)
* Separate analyzer rules as an independent section in the rule directory of
the reference.
[Ethan Wong](https://github.com/GetToSet)
[#4664](https://github.com/realm/SwiftLint/pull/4664)
* Add rule identifier to output of Emoji reporter.
[SimplyDanny](https://github.com/SimplyDanny)
[#4707](https://github.com/realm/SwiftLint/issues/4707)
* Add new `direct_return` rule that triggers on `return` statements returning
variables that have been declared in the statement before only.
[SimplyDanny](https://github.com/SimplyDanny)
* Add `period_spacing` opt-in rule that checks periods are not followed
by 2 or more spaces in comments.
[Julioacarrettoni](https://github.com/Julioacarrettoni)
[#4624](https://github.com/realm/SwiftLint/pull/4624)
* Allow to pass a rule identifier to the `swiftlint docs` command to open its
specific documentation website, e.g. `swiftlint docs for_where`.
[SimplyDanny](https://github.com/SimplyDanny)
[#4707](https://github.com/realm/SwiftLint/issues/4707)
* Allow new Quick APIs `aroundEach` and `justBeforeEach` for
`quick_discouraged_call`.
[David Steinacher](https://github.com/stonko1994)
[#4626](https://github.com/realm/SwiftLint/issues/4626)
* Add `relative-path` reporter to generate reports with relative file paths.
[Roya1v](https://github.com/roya1v)
[#4660](https://github.com/realm/SwiftLint/issues/4660)
* Let `number_separator` rule trigger on misplaced separators, e.g. `10_00`.
[SimplyDanny](https://github.com/SimplyDanny)
[#4637](https://github.com/realm/SwiftLint/issues/4637)
* Rewrite `multiline_arguments` rule using SwiftSyntax, ignoring trailing
closures.
[Marcelo Fabri](https://github.com/marcelofabri)
[#3399](https://github.com/realm/SwiftLint/issues/3399)
[#3605](https://github.com/realm/SwiftLint/issues/3605)
* Speed up linting by up to 6% updating to use a newer version of
`SwiftSyntax`.
[JP Simard](https://github.com/jpsim)
* Catch more valid `legacy_multiple` violations.
[JP Simard](https://github.com/jpsim)
* Catch more valid `no_magic_numbers` violations.
[JP Simard](https://github.com/jpsim)
* Add `blanket_disable_command` rule that checks whether
rules are re-enabled after being disabled.
[Martin Redington](https://github.com/mildm8nnered)
[#4731](https://github.com/realm/SwiftLint/pull/4731)
* Add `invalid_swiftlint_command` rule that validates
`// swiftlint:enable` and `disable` commands.
[Martin Redington](https://github.com/mildm8nnered)
[#4546](https://github.com/realm/SwiftLint/pull/4546)
* Improve `identifier_name` documentation.
[Martin Redington](https://github.com/mildm8nnered)
[#4767](https://github.com/realm/SwiftLint/issues/4767)
* Adds `include_multiline_strings` option to `indentation_width` rule.
[Martin Redington](https://github.com/mildm8nnered)
[#4248](https://github.com/realm/SwiftLint/issues/4248)
* Adds a new `summary` reporter, that displays the number of violations
of each rule in a text table.
[Martin Redington](https://github.com/mildm8nnered)
#### Bug Fixes
* Report violations in all `<scope>_length` rules when the error threshold is
smaller than the warning threshold.
[SimplyDanny](https://github.com/SimplyDanny)
[#4645](https://github.com/realm/SwiftLint/issues/4645)
* Consider custom attributes in `attributes` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4599](https://github.com/realm/SwiftLint/issues/4599)
* Fix whitespaces issue in auto-fix of `redundant_optional_initialization`
rule when multiple variable declaration are involved.
[SimplyDanny](https://github.com/SimplyDanny)
[#4794](https://github.com/realm/SwiftLint/issues/4794)
* Stop triggering `strict_fileprivate` rule on symbols implementing a protocol
in the same file.
[SimplyDanny](https://github.com/SimplyDanny)
[#4692](https://github.com/realm/SwiftLint/issues/4692)
* Fix false positives on `private_subject` rule when using
subjects inside functions.
[Marcelo Fabri](https://github.com/marcelofabri)
[#4643](https://github.com/realm/SwiftLint/issues/4643)
* Fix for compiler directives masking subsequent `opening_brace`
violations.
[Martin Redington](https://github.com/mildm8nnered)
[#3712](https://github.com/realm/SwiftLint/issues/3712)
* Rewrite `explicit_type_interface` rule with SwiftSyntax fixing a
false-positive in if-case-let statements.
[SimplyDanny](https://github.com/SimplyDanny)
[#4548](https://github.com/realm/SwiftLint/issues/4548)
* Stop triggering `unused_capture_list` on captured variable that is only
referenced by a shorthand optional binding (`if let capturedVar { ... }`).
[SimplyDanny](https://github.com/SimplyDanny)
[#4804](https://github.com/realm/SwiftLint/issues/4804)
* Ensure that negative literals in initializers do not trigger
`no_magic_numbers` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4677](https://github.com/realm/SwiftLint/issues/4677)
* Fix caching of `indentation_width` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4121](https://github.com/realm/SwiftLint/issues/4121)
* Updated JUnit reporter to output error count and warning count.
[patricks](https://github.com/patricks)
[#4725](https://github.com/realm/SwiftLint/pull/4725)
* Fix correction on `lower_acl_than_parent` rule for `open` declarations.
[Marcelo Fabri](https://github.com/marcelofabri)
[#4753](https://github.com/realm/SwiftLint/issues/4753)
* Fix `void_return` rule to support async and async throws functions.
[Mathias Schreck](https://github.com/lo1tuma)
[#4772](https://github.com/realm/SwiftLint/issues/4772)
* Fix false positives in `attributes` rule when using property wrappers
with keypath arguments.
[JP Simard](https://github.com/jpsim)
* Fix for `superfluous_disable_command` not being completely disabled
by `disable` commands.
[Martin Redington](https://github.com/mildm8nnered)
[#4788](https://github.com/realm/SwiftLint/issues/4788)
* Fixed correction for `trailing_comma` rule wrongly removing trailing
comments.
[Martin Redington](https://github.com/mildm8nnered)
[#4814](https://github.com/realm/SwiftLint/issues/4814)
## 0.50.3: Bundle of Towels
#### Breaking
* None.
#### Experimental
* None.
#### Enhancements
* The `SwiftLintPlugin` SwiftPM plugin now uses a prebuilt binary on
macOS.
[Tony Arnold](https://github.com/tonyarnold)
[JP Simard](https://github.com/jpsim)
[#4558](https://github.com/realm/SwiftLint/issues/4558)
* Don't trigger `shorthand_operator` violations inside a shorthand
operator function declaration.
[Marcelo Fabri](https://github.com/marcelofabri)
[#4611](https://github.com/realm/SwiftLint/issues/4611)
* The `balanced_xctest_lifecycle`, `single_test_class`,
`empty_xctest_method` and `test_case_accessibility` rules will now be
applied to subclasses of `QuickSpec`, as well as `XCTestCase`, by
default.
[Martin Redington](https://github.com/mildm8nnered)
* Add `test_parent_classes` option to `balanced_xctest_lifecycle`,
`single_test_class` and `empty_xctest_method` rules.
[Martin Redington](https://github.com/mildm8nnered)
[#4200](https://github.com/realm/SwiftLint/issues/4200)
* Show warnings in the console for Analyzer rules that are listed in the
`opt_in_rules` configuration section.
[SimplyDanny](https://github.com/SimplyDanny)
[#4612](https://github.com/realm/SwiftLint/issues/4612)
#### Bug Fixes
* Fix configuration parsing error in `unused_declaration` rule.
[SimplyDanny](https://github.com/SimplyDanny)
[#4612](https://github.com/realm/SwiftLint/issues/4612)
* Skip `defer` statements being last in an `#if` block if the `#if`
statement is not itself the last statement in a block.
[SimplyDanny](https://github.com/SimplyDanny)
[#4615](https://github.com/realm/SwiftLint/issues/4615)
* Fix false positives in `empty_enum_arguments` when the called
expression is an identifier or an init call.
[Steffen Matthischke](https://github.com/heeaad)
[#4597](https://github.com/realm/SwiftLint/issues/4597)
* Fix correction issue in `comma` when there was too much whitespace
following the comma.
[JP Simard](https://github.com/jpsim)
## 0.50.1: Artisanal Clothes Pegs Fixup Edition
#### Breaking

View File

@ -1,3 +1,9 @@
## Tutorial
If you'd like to write a SwiftLint rule but aren't sure how to start,
please watch and follow along with
[this video tutorial](https://vimeo.com/819268038).
## Pull Requests
All changes, no matter how trivial, must be done via pull request. Commits
@ -58,7 +64,7 @@ $ make docker_test
## Rules
New rules should be added in the `Source/SwiftLintFramework/Rules` directory.
New rules should be added in the `Source/SwiftLintBuiltInRules/Rules` directory.
Rules should conform to either the `Rule` or `ASTRule` protocols.
@ -98,11 +104,11 @@ configuration object via the `configuration` property:
* If none of the provided `RuleConfiguration`s are applicable, you can create one
specifically for your rule.
See [`ForceCastRule`](https://github.com/realm/SwiftLint/blob/main/Source/SwiftLintFramework/Rules/Idiomatic/ForceCastRule.swift)
See [`ForceCastRule`](https://github.com/realm/SwiftLint/blob/main/Source/SwiftLintBuiltInRules/Rules/Idiomatic/ForceCastRule.swift)
for a rule that allows severity configuration,
[`FileLengthRule`](https://github.com/realm/SwiftLint/blob/main/Source/SwiftLintFramework/Rules/Metrics/FileLengthRule.swift)
[`FileLengthRule`](https://github.com/realm/SwiftLint/blob/main/Source/SwiftLintBuiltInRules/Rules/Metrics/FileLengthRule.swift)
for a rule that has multiple severity levels,
[`IdentifierNameRule`](https://github.com/realm/SwiftLint/blob/main/Source/SwiftLintFramework/Rules/Style/IdentifierNameRule.swift)
[`IdentifierNameRule`](https://github.com/realm/SwiftLint/blob/main/Source/SwiftLintBuiltInRules/Rules/Style/IdentifierNameRule.swift)
for a rule that allows name evaluation configuration:
``` yaml
@ -174,10 +180,5 @@ To bring up a new Buildkite worker from MacStadium:
`brew install aria2 bazelisk htop buildkite/buildkite/buildkite-agent robotsandpencils/made/xcodes`
1. Install latest Xcode version: `xcodes update && xcodes install 14.0.0`
1. Add `DANGER_GITHUB_API_TOKEN` and `HOME` to `/opt/homebrew/etc/buildkite-agent/hooks/environment`
1. Add `echo "build --remote_cache=grpc://<creds>@swiftlint-ci.jpsim.com:9092" > ci.bazelrc`
to `/opt/homebrew/etc/buildkite-agent/hooks/pre-command`, replacing `<creds>` with the
bazel-remote credentials
1. Configure and launch buildkite agent: `brew info buildkite-agent` /
https://buildkite.com/organizations/swiftlint/agents#setup-macos
1. On the `swiftlint-ci.jpsim.com` machine only:
`docker run -d -u 1000:1000 -v /tmp/swiftlint-bazel-remote-cache:/data -v ~/Desktop/bazel-remote.htpasswd:/etc/bazel-remote/htpasswd -p 9090:8080 -p 9092:9092 buchgr/bazel-remote-cache --htpasswd_file=/etc/bazel-remote/htpasswd --max_size=5`

View File

@ -16,7 +16,7 @@ has_app_changes = !modified_files.grep(/Source/).empty?
has_test_changes = !modified_files.grep(/Tests/).empty?
has_danger_changes = !modified_files.grep(/Dangerfile|tools\/oss-check|Gemfile/).empty?
has_package_changes = !modified_files.grep(/Package\.swift/).empty?
has_bazel_changes = !modified_files.grep(/\.bazelrc|\.bazelversion|WORKSPACE|bazel\/|BUILD/).empty?
has_bazel_changes = !modified_files.grep(/\.bazelrc|\.bazelversion|WORKSPACE|bazel\/|BUILD|MODULE\.bazel/).empty?
# Add a CHANGELOG entry for app changes
if !modified_files.include?('CHANGELOG.md') && has_app_changes

View File

@ -1,15 +1,14 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.5)
CFPropertyList (3.0.6)
rexml
activesupport (6.1.6.1)
activesupport (7.0.4.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
@ -20,15 +19,15 @@ GEM
cork
nap
open4 (~> 1.3)
cocoapods (1.11.3)
cocoapods (1.12.1)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.11.3)
cocoapods-core (= 1.12.1)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.4.0, < 2.0)
cocoapods-downloader (>= 1.6.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.4.0, < 2.0)
cocoapods-trunk (>= 1.6.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
@ -36,10 +35,10 @@ GEM
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 1.0, < 3.0)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.11.3)
activesupport (>= 5.0, < 7)
cocoapods-core (1.12.1)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
@ -58,61 +57,42 @@ GEM
netrc (~> 0.11)
cocoapods-try (1.2.0)
colored2 (3.1.2)
concurrent-ruby (1.1.10)
concurrent-ruby (1.2.2)
cork (0.3.0)
colored2 (~> 3.1)
danger (8.6.1)
danger (9.2.0)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
cork (~> 0.1)
faraday (>= 0.9.0, < 2.0)
faraday (>= 0.9.0, < 3.0)
faraday-http-cache (~> 2.0)
git (~> 1.7)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
octokit (~> 4.7)
octokit (~> 5.0)
terminal-table (>= 1, < 4)
escape (0.0.4)
ethon (0.15.0)
ethon (0.16.0)
ffi (>= 1.15.0)
faraday (1.10.2)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
faraday-httpclient (~> 1.0)
faraday-multipart (~> 1.0)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.0)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
faraday-retry (~> 1.0)
faraday (2.7.4)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-http-cache (2.4.1)
faraday (>= 0.8)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
faraday-retry (1.0.3)
faraday-net_http (3.0.2)
ffi (1.15.5)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
git (1.12.0)
git (1.18.0)
addressable (~> 2.8)
rchardet (~> 1.8)
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jazzy (0.14.2)
jazzy (0.14.3)
cocoapods (~> 1.5)
mustache (~> 1.1)
open4 (~> 1.3)
@ -122,27 +102,26 @@ GEM
sassc (~> 2.1)
sqlite3 (~> 1.3)
xcinvoke (~> 0.3.0)
json (2.6.2)
json (2.6.3)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liferaft (0.0.6)
minitest (5.16.3)
minitest (5.18.0)
molinillo (0.8.0)
multipart-post (2.2.3)
mustache (1.1.1)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
no_proxy_fix (0.1.2)
octokit (4.25.1)
octokit (5.6.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
open4 (1.3.4)
public_suffix (4.0.7)
rchardet (1.8.0)
redcarpet (3.5.1)
redcarpet (3.6.0)
rexml (3.2.5)
rouge (3.30.0)
ruby-macho (2.5.1)
@ -152,14 +131,14 @@ GEM
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
sqlite3 (1.4.4)
sqlite3 (1.6.2-arm64-darwin)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (2.0.5)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.2.0)
unicode-display_width (2.4.2)
xcinvoke (0.3.0)
liferaft (~> 0.0.6)
xcodeproj (1.22.0)
@ -169,11 +148,10 @@ GEM
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
zeitwerk (2.6.0)
PLATFORMS
arm64-darwin-21
ruby
arm64-darwin-22
DEPENDENCIES
cocoapods
@ -181,4 +159,4 @@ DEPENDENCIES
jazzy
BUNDLED WITH
2.3.8
2.4.12

27
MODULE.bazel Normal file
View File

@ -0,0 +1,27 @@
module(
name = "swiftlint",
version = "0.52.2",
compatibility_level = 1,
repo_name = "SwiftLint",
)
bazel_dep(name = "bazel_skylib", version = "1.4.1", dev_dependency = True)
bazel_dep(name = "platforms", version = "0.0.6")
bazel_dep(name = "rules_apple", version = "2.3.0", repo_name = "build_bazel_rules_apple")
bazel_dep(name = "rules_swift", version = "1.8.0", repo_name = "build_bazel_rules_swift")
bazel_dep(name = "rules_xcodeproj", version = "1.7.0")
bazel_dep(name = "sourcekitten", version = "0.34.1", repo_name = "com_github_jpsim_sourcekitten")
bazel_dep(name = "swift_argument_parser", version = "1.2.1", repo_name = "sourcekitten_com_github_apple_swift_argument_parser")
bazel_dep(name = "yams", version = "5.0.5", repo_name = "sourcekitten_com_github_jpsim_yams")
swiftlint_repos = use_extension("//bazel:repos.bzl", "swiftlint_repos_bzlmod")
use_repo(
swiftlint_repos,
"SwiftSyntax",
"com_github_johnsundell_collectionconcurrencykit",
"com_github_krzyzanowskim_cryptoswift",
"swiftlint_com_github_scottrhoyt_swifty_text_table",
)
extra_rules = use_extension("//bazel:extensions.bzl", "extra_rules")
use_repo(extra_rules, "swiftlint_extra_rules")

View File

@ -30,14 +30,18 @@ VERSION_STRING=$(shell ./tools/get-version)
all: build
sourcery: Source/SwiftLintFramework/Models/PrimaryRuleList.swift Tests/GeneratedTests/GeneratedTests.swift
sourcery: Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift Source/SwiftLintCore/Models/ReportersList.swift Tests/GeneratedTests/GeneratedTests.swift
Source/SwiftLintFramework/Models/PrimaryRuleList.swift: Source/SwiftLintFramework/Rules/**/*.swift .sourcery/PrimaryRuleList.stencil
sourcery --sources Source/SwiftLintFramework/Rules --templates .sourcery/PrimaryRuleList.stencil --output .sourcery
mv .sourcery/PrimaryRuleList.generated.swift Source/SwiftLintFramework/Models/PrimaryRuleList.swift
Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift: Source/SwiftLintBuiltInRules/Rules/**/*.swift .sourcery/BuiltInRules.stencil
./tools/sourcery --sources Source/SwiftLintBuiltInRules/Rules --templates .sourcery/BuiltInRules.stencil --output .sourcery
mv .sourcery/BuiltInRules.generated.swift Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift
Tests/GeneratedTests/GeneratedTests.swift: Source/SwiftLintFramework/Rules/**/*.swift .sourcery/GeneratedTests.stencil
sourcery --sources Source/SwiftLintFramework/Rules --templates .sourcery/GeneratedTests.stencil --output .sourcery
Source/SwiftLintCore/Models/ReportersList.swift: Source/SwiftLintCore/Reporters/*.swift .sourcery/ReportersList.stencil
./tools/sourcery --sources Source/SwiftLintCore/Reporters --templates .sourcery/ReportersList.stencil --output .sourcery
mv .sourcery/ReportersList.generated.swift Source/SwiftLintCore/Models/ReportersList.swift
Tests/GeneratedTests/GeneratedTests.swift: Source/SwiftLint*/Rules/**/*.swift .sourcery/GeneratedTests.stencil
./tools/sourcery --sources Source/SwiftLintCore/Rules --sources Source/SwiftLintBuiltInRules/Rules --templates .sourcery/GeneratedTests.stencil --output .sourcery
mv .sourcery/GeneratedTests.generated.swift Tests/GeneratedTests/GeneratedTests.swift
test: clean_xcode
@ -65,7 +69,7 @@ clean:
clean_xcode:
$(BUILD_TOOL) $(XCODEFLAGS) -configuration Test clean
build: clean
build:
mkdir -p "$(SWIFTLINT_EXECUTABLE_PARENT)"
bazel build --config release universal_swiftlint
$(eval SWIFTLINT_BINARY := $(shell bazel cquery --config release --output=files universal_swiftlint))
@ -113,10 +117,11 @@ zip_linux: docker_image
zip_linux_release:
$(eval TMP_FOLDER := $(shell mktemp -d))
docker run "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(TMP_FOLDER)/swiftlint"
docker run --platform linux/amd64 "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(TMP_FOLDER)/swiftlint"
chmod +x "$(TMP_FOLDER)/swiftlint"
cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)"
(cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip"
gh release upload "$(VERSION_STRING)" swiftlint_linux.zip
package: build
$(eval PACKAGE_ROOT := $(shell mktemp -d))
@ -132,13 +137,11 @@ bazel_release:
bazel build :release
mv bazel-bin/bazel.tar.gz bazel-bin/bazel.tar.gz.sha256 .
release: clean bazel_release package portable_zip spm_artifactbundle_macos zip_linux_release
docker_image:
docker build --platform linux/amd64 --force-rm --tag swiftlint .
docker_test:
docker run -v `pwd`:`pwd` -w `pwd` --name swiftlint --rm swift:5.6-focal swift test --parallel
docker run -v `pwd`:`pwd` -w `pwd` --name swiftlint --rm swift:5.7-focal swift test --parallel
docker_htop:
docker run --platform linux/amd64 -it --rm --pid=container:swiftlint terencewestphal/htop || reset
@ -149,8 +152,8 @@ display_compilation_time:
publish:
brew update && brew bump-formula-pr --tag=$(shell git describe --tags) --revision=$(shell git rev-parse HEAD) swiftlint
# Workaround for https://github.com/CocoaPods/CocoaPods/issues/11185
arch -arch x86_64 pod trunk push SwiftLint.podspec
bundle install
bundle exec pod trunk push SwiftLint.podspec
docs:
swift run swiftlint generate-docs
@ -160,18 +163,30 @@ docs:
get_version:
@echo "$(VERSION_STRING)"
push_version:
release:
ifneq ($(strip $(shell git status --untracked-files=no --porcelain 2>/dev/null)),)
$(error git state is not clean)
endif
$(eval NEW_VERSION_AND_NAME := $(filter-out $@,$(MAKECMDGOALS)))
$(eval NEW_VERSION := $(shell echo $(NEW_VERSION_AND_NAME) | sed 's/:.*//' ))
@sed -i '' 's/## Main/## $(NEW_VERSION_AND_NAME)/g' CHANGELOG.md
@sed 's/__VERSION__/$(NEW_VERSION)/g' tools/Version.swift.template > Source/SwiftLintFramework/Models/Version.swift
@sed 's/__VERSION__/$(NEW_VERSION)/g' tools/Version.swift.template > Source/SwiftLintCore/Models/Version.swift
@sed -e '3s/.*/ version = "$(NEW_VERSION)",/' -i '' MODULE.bazel
make clean
make package
make bazel_release
make portable_zip
make spm_artifactbundle_macos
./tools/update-artifact-bundle.sh "$(NEW_VERSION)"
git commit -a -m "release $(NEW_VERSION)"
git tag -a $(NEW_VERSION) -m "$(NEW_VERSION_AND_NAME)"
git push origin HEAD
git push origin $(NEW_VERSION)
./tools/create-github-release.sh "$(NEW_VERSION)"
make publish
./tools/add-new-changelog-section.sh
git commit -a -m "Add new changelog section"
git push origin HEAD
%:
@:

View File

@ -9,13 +9,22 @@
"version" : "0.2.0"
}
},
{
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "32f641cf24fc7abc1c591a2025e9f2f572648b0f",
"version" : "1.7.2"
}
},
{
"identity" : "sourcekitten",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "fc12c0f182c5cf80781dd933b17a82eb98bd7c61",
"version" : "0.33.1"
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
"version" : "0.34.1"
}
},
{
@ -23,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "fddd1c00396eed152c45a46bea9f47b98e59301d",
"version" : "1.2.0"
"revision" : "4ad606ba5d7673ea60679a61ff867cc1ff8c8e86",
"version" : "1.2.1"
}
},
{
@ -32,7 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "a82041008d2c678a97407fbd0ce420d3ab047538"
"revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5",
"version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a"
}
},
{
@ -58,8 +68,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "01835dc202670b5bb90d07f3eae41867e9ed29f6",
"version" : "5.0.1"
"revision" : "f47ba4838c30dbd59998a4e4c87ab620ff959e8a",
"version" : "5.0.5"
}
}
],

View File

@ -1,23 +1,6 @@
// swift-tools-version:5.7
import PackageDescription
#if os(macOS)
private let addCryptoSwift = false
#else
private let addCryptoSwift = true
#endif
let frameworkDependencies: [Target.Dependency] = [
.product(name: "IDEUtils", package: "swift-syntax"),
.product(name: "SourceKittenFramework", package: "SourceKitten"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftOperators", package: "swift-syntax"),
"Yams",
]
+ (addCryptoSwift ? ["CryptoSwift"] : [])
let package = Package(
name: "SwiftLint",
platforms: [.macOS(.v12)],
@ -27,19 +10,21 @@ let package = Package(
.plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.0")),
.package(url: "https://github.com/apple/swift-syntax.git", revision: "a82041008d2c678a97407fbd0ce420d3ab047538"),
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.33.1")),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1"),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.1")),
.package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a"),
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.34.1")),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.5"),
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
.package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit.git", from: "0.2.0")
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.6.0"))] : []),
.package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit.git", from: "0.2.0"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.7.2"))
],
targets: [
.plugin(
name: "SwiftLintPlugin",
capability: .buildTool(),
dependencies: [
.target(name: "swiftlint")
.target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])),
.target(name: "swiftlint", condition: .when(platforms: [.linux]))
]
),
.executableTarget(
@ -58,14 +43,43 @@ let package = Package(
]
),
.target(
name: "SwiftLintFramework",
dependencies: frameworkDependencies
name: "SwiftLintCore",
dependencies: [
.product(name: "CryptoSwift", package: "CryptoSwift", condition: .when(platforms: [.linux])),
.target(name: "DyldWarningWorkaround", condition: .when(platforms: [.macOS])),
.product(name: "SourceKittenFramework", package: "SourceKitten"),
.product(name: "SwiftIDEUtils", package: "swift-syntax"),
.product(name: "SwiftOperators", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "SwiftyTextTable", package: "SwiftyTextTable"),
.product(name: "Yams", package: "Yams"),
]
),
.testTarget(
.target(
name: "SwiftLintBuiltInRules",
dependencies: ["SwiftLintCore"]
),
.target(
name: "SwiftLintExtraRules",
dependencies: ["SwiftLintCore"]
),
.target(
name: "SwiftLintFramework",
dependencies: [
"SwiftLintBuiltInRules",
"SwiftLintCore",
"SwiftLintExtraRules"
]
),
.target(name: "DyldWarningWorkaround"),
.target(
name: "SwiftLintTestHelpers",
dependencies: [
"SwiftLintFramework"
]
],
path: "Tests/SwiftLintTestHelpers"
),
.testTarget(
name: "SwiftLintFrameworkTests",
@ -98,5 +112,10 @@ let package = Package(
"SwiftLintTestHelpers"
]
),
.binaryTarget(
name: "SwiftLintBinary",
url: "https://github.com/realm/SwiftLint/releases/download/0.52.2/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "89651e1c87fb62faf076ef785a5b1af7f43570b2b74c6773526e0d5114e0578e"
)
]
)

View File

@ -1,16 +1,42 @@
import Foundation
import PackagePlugin
#if os(Linux)
import Glibc
#else
import Darwin
#endif
extension Path {
/// Scans the receiver, then all of its parents looking for a configuration file with the name ".swiftlint.yml".
///
/// - returns: Path to the configuration file, or nil if one cannot be found.
func firstConfigurationFileInParentDirectories() -> Path? {
let defaultConfigurationFileName = ".swiftlint.yml"
let proposedDirectory = sequence(first: self, next: { $0.removingLastComponent() }).first { path in
let proposedDirectory = sequence(
first: self,
next: { path in
guard path.stem.count > 1 else {
// Check we're not at the root of this filesystem, as `removingLastComponent()`
// will continually return the root from itself.
return nil
}
return path.removingLastComponent()
}
).first { path in
let potentialConfigurationFile = path.appending(subpath: defaultConfigurationFileName)
return FileManager.default.isReadableFile(atPath: potentialConfigurationFile.string)
return potentialConfigurationFile.isAccessible()
}
return proposedDirectory?.appending(subpath: defaultConfigurationFileName)
}
/// Safe way to check if the file is accessible from within the current process sandbox.
private func isAccessible() -> Bool {
let result = string.withCString { pointer in
access(pointer, R_OK)
}
return result == 0
}
}

View File

@ -3,45 +3,55 @@ import PackagePlugin
@main
struct SwiftLintPlugin: BuildToolPlugin {
func createBuildCommands(
context: PackagePlugin.PluginContext,
target: PackagePlugin.Target
) async throws -> [PackagePlugin.Command] {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
guard let sourceTarget = target as? SourceModuleTarget else {
return []
}
return createBuildCommands(
inputFiles: sourceTarget.sourceFiles(withSuffix: "swift").map(\.path),
packageDirectory: context.package.directory,
workingDirectory: context.pluginWorkDirectory,
tool: try context.tool(named: "swiftlint")
)
}
let inputFilePaths = sourceTarget.sourceFiles(withSuffix: "swift")
.map(\.path)
guard inputFilePaths.isEmpty == false else {
private func createBuildCommands(
inputFiles: [Path],
packageDirectory: Path,
workingDirectory: Path,
tool: PluginContext.Tool
) -> [Command] {
if inputFiles.isEmpty {
// Don't lint anything if there are no Swift source files in this target
return []
}
let swiftlint = try context.tool(named: "swiftlint")
var arguments: [String] = [
var arguments = [
"lint",
"--cache-path", "\(context.pluginWorkDirectory)"
"--quiet",
// We always pass all of the Swift source files in the target to the tool,
// so we need to ensure that any exclusion rules in the configuration are
// respected.
"--force-exclude",
"--cache-path", "\(workingDirectory)"
]
// Manually look for configuration files, to avoid issues when the plugin does not execute our tool from the
// package source directory.
if let configuration = context.package.directory.firstConfigurationFileInParentDirectories() {
arguments.append(contentsOf: [
"--config", "\(configuration.string)"
])
if let configuration = packageDirectory.firstConfigurationFileInParentDirectories() {
arguments.append(contentsOf: ["--config", "\(configuration.string)"])
}
arguments += inputFiles.map(\.string)
arguments += inputFilePaths.map(\.string)
// We are not producing output files and this is needed only to not include cache files into bundle
let outputFilesDirectory = workingDirectory.appending("Output")
return [
.buildCommand(
.prebuildCommand(
displayName: "SwiftLint",
executable: swiftlint.path,
executable: tool.path,
arguments: arguments,
inputFiles: inputFilePaths,
outputFiles: [context.pluginWorkDirectory]
outputFilesDirectory: outputFilesDirectory
)
]
}
@ -51,44 +61,16 @@ struct SwiftLintPlugin: BuildToolPlugin {
import XcodeProjectPlugin
extension SwiftLintPlugin: XcodeBuildToolPlugin {
func createBuildCommands(
context: XcodePluginContext,
target: XcodeTarget
) throws -> [Command] {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
let inputFilePaths = target.inputFiles
.filter { $0.type == .source && $0.path.extension == "swift" }
.map(\.path)
guard inputFilePaths.isEmpty == false else {
// Don't lint anything if there are no Swift source files in this target
return []
}
let swiftlint = try context.tool(named: "swiftlint")
var arguments: [String] = [
"lint",
"--cache-path", "\(context.pluginWorkDirectory)"
]
// Xcode build tool plugins don't seem to run from the project source directory, so our auto-discovery of
// configuration files doesn't work. We approximate it here.
if let configuration = context.xcodeProject.directory.firstConfigurationFileInParentDirectories() {
arguments.append(contentsOf: [
"--config", "\(configuration.string)"
])
}
arguments += inputFilePaths.map(\.string)
return [
.buildCommand(
displayName: "SwiftLint",
executable: swiftlint.path,
arguments: arguments,
inputFiles: inputFilePaths,
outputFiles: [context.pluginWorkDirectory]
)
]
return createBuildCommands(
inputFiles: inputFilePaths,
packageDirectory: context.xcodeProject.directory,
workingDirectory: context.pluginWorkDirectory,
tool: try context.tool(named: "swiftlint")
)
}
}
#endif

View File

@ -1,6 +1,6 @@
# SwiftLint
A tool to enforce Swift style and conventions, loosely based on the now archived [GitHub Swift Style Guide](https://github.com/github/swift-style-guide). SwiftLint enforces the style guide rules that are generally accepted by the Swift community. These rules are well described in popular style guides like [Ray Wenderlich's Swift Style Guide](https://github.com/raywenderlich/swift-style-guide).
A tool to enforce Swift style and conventions, loosely based on the now archived [GitHub Swift Style Guide](https://github.com/github/swift-style-guide). SwiftLint enforces the style guide rules that are generally accepted by the Swift community. These rules are well described in popular style guides like [Kodeco's Swift Style Guide](https://github.com/kodecocodes/swift-style-guide).
SwiftLint hooks into [Clang](http://clang.llvm.org) and
[SourceKit](http://www.jpsim.com/uncovering-sourcekit) to use the
@ -64,13 +64,19 @@ You can also build and install from source by cloning this project and running
### Using Bazel
Put this in your `WORKSPACE`:
Put this in your `MODULE.bazel`:
```bzl
bazel_dep(name = "swiftlint", version = "0.50.4", repo_name = "SwiftLint")
```
Or put this in your `WORKSPACE`:
<details>
<summary>WORKSPACE</summary>
```python
```bzl
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
@ -152,7 +158,10 @@ folder by default. To instruct Xcode where to find SwiftLint, you can either add
`/opt/homebrew/bin` to the `PATH` environment variable in your build phase
```bash
export PATH="$PATH:/opt/homebrew/bin"
if [[ "$(uname -m)" == arm64 ]]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if which swiftlint > /dev/null; then
swiftlint
else
@ -194,7 +203,7 @@ there is currently no way to pass any additional options to the SwiftLint execut
#### Xcode
You can integrate SwiftLint as a Xcode Build Tool Plug-in if you're working
You can integrate SwiftLint as an Xcode Build Tool Plug-in if you're working
with a project in Xcode.
Add SwiftLint as a package dependency to your project without linking any of the
@ -206,6 +215,15 @@ Select `SwiftLintPlugin` from the list and add it to the project.
![](assets/select-swiftlint-plugin.png)
For unattended use (e.g. on CI), you can disable the package validation dialog by
* individually passing `-skipPackagePluginValidation` to `xcodebuild` or
* globally setting `defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES`
for that user.
_Note: This implicitly trusts all Xcode package plugins and bypasses Xcode's package validation
dialogs, which has security implications._
#### Swift Package
You can integrate SwiftLint as a Swift Package Manager Plug-in if you're working with
@ -221,14 +239,6 @@ Add SwiftLint to a target using the `plugins` parameter.
),
```
### AppCode
To integrate SwiftLint with AppCode, install
[this plugin](https://plugins.jetbrains.com/plugin/9175) and configure
SwiftLint's installed path in the plugin's preferences.
The `fix` action is available via `⌥⏎`.
### Visual Studio Code
To integrate SwiftLint with [vscode](https://code.visualstudio.com), install the
@ -298,6 +308,7 @@ SUBCOMMANDS:
docs Open SwiftLint documentation website in the default web browser
generate-docs Generates markdown documentation for all rules
lint (default) Print lint warnings and errors
reporters Display the list of reporters and their identifiers
rules Display the list of rules and their identifiers
version Display the current version of SwiftLint
@ -365,12 +376,21 @@ Once [installed](https://pre-commit.com/#install), add this to the
```yaml
repos:
- repo: https://github.com/realm/SwiftLint
rev: 0.44.0
rev: 0.50.3
hooks:
- id: swiftlint
```
Adjust `rev` to the SwiftLint version of your choice.
Adjust `rev` to the SwiftLint version of your choice. `pre-commit autoupdate` can be used to update to the current version.
SwiftLint can be configured using `entry` to apply fixes and fail on errors:
```yaml
- repo: https://github.com/realm/SwiftLint
rev: 0.50.3
hooks:
- id: swiftlint
entry: swiftlint --fix --strict
```
## Rules
@ -381,7 +401,7 @@ continues to contribute more over time.
You can find an updated list of rules and more information about them
[here](https://realm.github.io/SwiftLint/rule-directory.html).
You can also check [Source/SwiftLintFramework/Rules](https://github.com/realm/SwiftLint/tree/main/Source/SwiftLintFramework/Rules)
You can also check [Source/SwiftLintBuiltInRules/Rules](https://github.com/realm/SwiftLint/tree/main/Source/SwiftLintBuiltInRules/Rules)
directory to see their implementation.
### Opt-In Rules
@ -459,7 +479,9 @@ run SwiftLint from. The following parameters can be configured:
Rule inclusion:
* `disabled_rules`: Disable rules from the default enabled set.
* `opt_in_rules`: Enable rules that are not part of the default set.
* `opt_in_rules`: Enable rules that are not part of the default set. The
special `all` identifier will enable all opt in linter rules, except the ones
listed in `disabled_rules`.
* `only_rules`: Only the rules specified in this list will be enabled.
Cannot be specified alongside `disabled_rules` or `opt_in_rules`.
* `analyzer_rules`: This is an entirely separate list of rules that are only
@ -481,6 +503,9 @@ opt_in_rules: # some rules are turned off by default, so you need to opt-in
# - empty_parameters
# - vertical_whitespace
analyzer_rules: # Rules run by `swiftlint analyze`
- explicit_self
included: # paths to include during linting. `--path` is ignored if present.
- Source
excluded: # paths to ignore during linting. Takes precedence over `included`.
@ -489,8 +514,9 @@ excluded: # paths to ignore during linting. Takes precedence over `included`.
- Source/ExcludedFolder
- Source/ExcludedFile.swift
- Source/*/ExcludedFile.swift # Exclude files with a wildcard
analyzer_rules: # Rules run by `swiftlint analyze`
- explicit_self
# If true, SwiftLint will not fail if no lintable files are found.
allow_zero_lintable_files: false
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
@ -524,13 +550,29 @@ identifier_name:
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging)
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging, summary)
```
You can also use environment variables in your configuration file,
by using `${SOME_VARIABLE}` in a string.
#### Defining Custom Rules
### Defining Custom Rules
In addition to the rules that the main SwiftLint project ships with, SwiftLint
can also run two types of custom rules that you can define yourself in your own
projects:
#### 1. Swift Custom Rules
These rules are written the same way as the Swift-based rules that ship with
SwiftLint so they're fast, accurate, can leverage SwiftSyntax, can be unit
tested, and more.
Using these requires building SwiftLint with Bazel as described in
[this video](https://vimeo.com/820572803) or its associated code in
[github.com/jpsim/swiftlint-bazel-example](https://github.com/jpsim/swiftlint-bazel-example).
#### 2. Regex Custom Rules
You can define custom regex-based rules in your configuration file using the
following syntax:
@ -595,6 +637,9 @@ which match to `keyword` and `identifier` in the above list.
If using custom rules in combination with `only_rules`, make sure to add
`custom_rules` as an item under `only_rules`.
Unlike Swift custom rules, you can use official SwiftLint builds
(e.g. from Homebrew) to run regex custom rules.
### Auto-correct
SwiftLint can automatically correct certain violations. Files on disk are

View File

@ -1,6 +1,6 @@
# SwiftLint
SwiftLint 是一个用于强制检查 Swift 代码风格和规定的一个工具,基本上以 [Ray Wenderlich's Swift 代码风格指南](https://github.com/raywenderlich/swift-style-guide)为基础。
SwiftLint 是一个用于强制检查 Swift 代码风格和规定的一个工具,基本上以 [Kodeco's Swift 代码风格指南](https://github.com/kodecocodes/swift-style-guide)为基础。
SwiftLint Hook 了 [Clang](http://clang.llvm.org) 和 [SourceKit](http://www.jpsim.com/uncovering-sourcekit) 从而能够使用 [AST](http://clang.llvm.org/docs/IntroductionToTheClangAST.html) 来表示源代码文件的更多精确结果。
@ -167,7 +167,7 @@ SwiftLint 已经包含了超过 75 条规则,并且我们希望 Swift 社区
你可以在 [Rule Directory](https://realm.github.io/SwiftLint/rule-directory.html) 找到规则的更新列表和更多信息。
你也可以检视 [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules) 目录来查看它们的实现。
你也可以检视 [Source/SwiftLintBuiltInRules/Rules](Source/SwiftLintBuiltInRules/Rules) 目录来查看它们的实现。
`opt_in_rules` 默认是关闭的(即,你需要在你的配置文件中明确地打开它们)。

View File

@ -1,6 +1,6 @@
# SwiftLint
SwiftLint는 스위프트 스타일 및 컨벤션을 강제하기 위한 도구로, [Ray Wenderlich 스위프트 스타일 가이드](https://github.com/raywenderlich/swift-style-guide)에 대략적인 기반을 두고 있습니다.
SwiftLint는 스위프트 스타일 및 컨벤션을 강제하기 위한 도구로, [Kodeco 스위프트 스타일 가이드](https://github.com/kodecocodes/swift-style-guide)에 대략적인 기반을 두고 있습니다.
SwiftLint는 좀 더 정확한 결과를 위해 [Clang](http://clang.llvm.org)과 [SourceKit](http://www.jpsim.com/uncovering-sourcekit)에 연결하여 소스 파일의 [AST](http://clang.llvm.org/docs/IntroductionToTheClangAST.html) 표현을 사용합니다.
@ -75,7 +75,10 @@ fi
그 이유는, 애플 실리콘 기반 맥에서 Homebrew는 기본적으로 바이너리들을 `/opt/homebrew/bin`에 저장하기 때문입니다. SwiftLint가 어디 있는지 찾는 것을 Xcode에 알려주기 위해, build phase에서 `/opt/homebrew/bin``PATH` 환경 변수에 동시에 추가하여야 합니다.
```bash
export PATH="$PATH:/opt/homebrew/bin"
if [[ "$(uname -m)" == arm64 ]]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if which swiftlint > /dev/null; then
swiftlint
else
@ -180,9 +183,9 @@ $ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint autocorrect
## 룰
SwiftLint에는 75개가 넘는 룰들이 있고, 스위프트 커뮤니티(바로 여러분들!)는 이를 지속적으로 발전시켜 가고 있습니다. [풀 리퀘스트](CONTRIBUTING.md)는 언제나 환영입니다.
SwiftLint에는 200개가 넘는 룰들이 있고, 스위프트 커뮤니티(바로 여러분들!)는 이를 지속적으로 발전시켜 가고 있습니다. [풀 리퀘스트](CONTRIBUTING.md)는 언제나 환영입니다.
현재 구현된 룰 전체를 확인하려면 [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules)를 살펴보세요.
현재 구현된 룰 전체를 확인하려면 [Source/SwiftLintBuiltInRules/Rules](Source/SwiftLintBuiltInRules/Rules)를 살펴보세요.
`opt_in_rules`는 기본적으로 비활성화되어 있습니다. (즉, 설정 파일에서 명시적으로 해당 룰을 활성화해야 합니다.)

View File

@ -7,19 +7,8 @@ For SwiftLint contributors, follow these steps to cut a release:
* FabricSoftenerRule
* Top Loading
* Fresh Out Of The Dryer
1. Push new version: `make push_version "0.2.0: Tumble Dry"`
1. Make sure you have the latest stable Xcode version installed and
`xcode-select`ed.
1. Create the pkg installer, framework zip, portable zip,
macos artifactbundle zip, and Linux zip:
`make release`
1. Create a GitHub release: https://github.com/realm/SwiftLint/releases/new
* Specify the tag you just pushed from the dropdown.
* Set the release title to the new version number & release name.
* Add the changelog section to the release description text box.
* Upload the bazel tarball & SHA-256 signature, pkg installer,
framework zip, portable zip, macos artifactbundle zip, and Linux zip
you just built to the GitHub release binaries.
* Click "Publish release".
1. Publish to Homebrew and CocoaPods trunk: `make publish`
`xcode-select`ed
1. Release new version: `make release "0.2.0: Tumble Dry"`
1. Wait for the Docker CI job to finish then run: `make zip_linux_release`
1. Celebrate. :tada:

View File

@ -0,0 +1,15 @@
#ifdef __APPLE__
#include "objc_dupclass.h"
OBJC_DUPCLASS(_TtC11SwiftSyntax11SyntaxArena);
OBJC_DUPCLASS(_TtC11SwiftSyntax13SyntaxVisitor);
OBJC_DUPCLASS(_TtC11SwiftSyntax14SyntaxRewriter);
OBJC_DUPCLASS(_TtC11SwiftSyntax16BumpPtrAllocator);
OBJC_DUPCLASS(_TtC11SwiftSyntax16SyntaxAnyVisitor);
OBJC_DUPCLASS(_TtC11SwiftSyntax18ParsingSyntaxArena);
OBJC_DUPCLASS(_TtC11SwiftSyntax23SourceLocationConverter);
OBJC_DUPCLASS(_TtC11SwiftSyntax26IncrementalParseTransition);
OBJC_DUPCLASS(_TtC11SwiftSyntax35IncrementalParseReusedNodeCollector);
#endif // __APPLE__

View File

@ -0,0 +1,19 @@
// https://github.com/keith/objc_dupclass
#include <stdint.h>
// TODO: This isn't entirely accurate, but I'm not sure how to more accurately determine
#if (defined(__arm64__) || defined(DUPCLASS_FORCE_DATA_CONST)) && !defined(DUPCLASS_FORCE_DATA)
#define SECTION "__DATA_CONST"
#else
#define SECTION "__DATA"
#endif
// Struct layout from https://github.com/apple-oss-distributions/objc4/blob/8701d5672d3fd3cd817aeb84db1077aafe1a1604/runtime/objc-abi.h#L175-L183
#define OBJC_DUPCLASS(kclass) \
__attribute__((used)) __attribute__((visibility("hidden"))) \
static struct { uint32_t version; uint32_t flags; const char name[64]; } \
const __duplicate_class_##kclass = { 0, 0, #kclass }; \
\
__attribute__((used)) __attribute__((visibility("hidden"))) \
__attribute__((section (SECTION",__objc_dupclass"))) \
const void* __set___objc_dupclass_sym___duplicate_class_##kclass = &__duplicate_class_##kclass

View File

@ -0,0 +1 @@
@_exported import SwiftLintCore

View File

@ -66,7 +66,7 @@ extension SourceKittenDictionary {
/// arguments appears in the view's substructure.
func hasModifier(anyOf modifiers: [SwiftUIModifier], in file: SwiftLintFile) -> Bool {
// SwiftUI ViewModifiers are treated as `call` expressions, and we make sure we can get the expression's name.
guard expressionKind == .call, let name = name else {
guard expressionKind == .call, let name else {
return false
}
@ -169,7 +169,7 @@ extension SourceKittenDictionary {
/// Helper to get the value of an argument.
func getArgumentValue(in file: SwiftLintFile) -> String? {
guard expressionKind == .argument, let bodyByteRange = bodyByteRange else {
guard expressionKind == .argument, let bodyByteRange else {
return nil
}
@ -178,7 +178,7 @@ extension SourceKittenDictionary {
/// Helper to get the value of a single unnamed argument to a function call.
func getSingleUnnamedArgumentValue(in file: SwiftLintFile) -> String? {
guard expressionKind == .call, let bodyByteRange = bodyByteRange else {
guard expressionKind == .call, let bodyByteRange else {
return nil
}

View File

@ -62,7 +62,7 @@ enum LegacyFunctionRuleHelper {
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
let trimmedArguments = node.argumentList.map { $0.trimmed() }
let trimmedArguments = node.argumentList.map { $0.trimmingTrailingComma() }
let rewriteStrategy = legacyFunctions[funcName]
let expr: ExprSyntax
@ -70,20 +70,20 @@ enum LegacyFunctionRuleHelper {
case .equal:
expr = "\(trimmedArguments[0]) == \(trimmedArguments[1])"
case let .property(name: propertyName):
expr = "\(trimmedArguments[0]).\(propertyName)"
expr = "\(trimmedArguments[0]).\(raw: propertyName)"
case let .function(name: functionName, argumentLabels: argumentLabels, reversed: reversed):
let arguments = reversed ? trimmedArguments.reversed() : trimmedArguments
let params = zip(argumentLabels, arguments.dropFirst())
.map { $0.isEmpty ? "\($1)" : "\($0): \($1)" }
.joined(separator: ", ")
expr = "\(arguments[0]).\(functionName)(\(params))"
expr = "\(arguments[0]).\(raw: functionName)(\(raw: params))"
case .none:
return super.visit(node)
}
return expr
.withLeadingTrivia(node.leadingTrivia ?? .zero)
.withTrailingTrivia(node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
}
}
@ -103,10 +103,7 @@ private extension FunctionCallExprSyntax {
}
private extension TupleExprElementSyntax {
func trimmed() -> TupleExprElementSyntax {
self
.withoutTrivia()
.withTrailingComma(nil)
.withoutTrivia()
func trimmingTrailingComma() -> TupleExprElementSyntax {
self.trimmed.with(\.trailingComma, nil).trimmed
}
}

View File

@ -1,7 +1,8 @@
// Generated using Sourcery 1.9.0 https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
/// The rule list containing all available rules built into SwiftLint.
public let primaryRuleList = RuleList(rules: [
public let builtInRules: [Rule.Type] = [
AccessibilityLabelForImageRule.self,
AccessibilityTraitForButtonRule.self,
AnonymousArgumentInMultilineClosureRule.self,
@ -9,6 +10,7 @@ public let primaryRuleList = RuleList(rules: [
ArrayInitRule.self,
AttributesRule.self,
BalancedXCTestLifecycleRule.self,
BlanketDisableCommandRule.self,
BlockBasedKVORule.self,
CaptureVariableRule.self,
ClassDelegateProtocolRule.self,
@ -31,9 +33,9 @@ public let primaryRuleList = RuleList(rules: [
ContainsOverRangeNilComparisonRule.self,
ControlStatementRule.self,
ConvenienceTypeRule.self,
CustomRules.self,
CyclomaticComplexityRule.self,
DeploymentTargetRule.self,
DirectReturnRule.self,
DiscardedNotificationCenterObserverRule.self,
DiscouragedAssertRule.self,
DiscouragedDirectInitRule.self,
@ -41,6 +43,7 @@ public let primaryRuleList = RuleList(rules: [
DiscouragedObjectLiteralRule.self,
DiscouragedOptionalBooleanRule.self,
DiscouragedOptionalCollectionRule.self,
DuplicateConditionsRule.self,
DuplicateEnumCasesRule.self,
DuplicateImportsRule.self,
DuplicatedKeyInDictionaryLiteralRule.self,
@ -87,6 +90,7 @@ public let primaryRuleList = RuleList(rules: [
InclusiveLanguageRule.self,
IndentationWidthRule.self,
InertDeferRule.self,
InvalidSwiftLintCommandRule.self,
IsDisjointRule.self,
JoinedDefaultParameterRule.self,
LargeTupleRule.self,
@ -102,7 +106,7 @@ public let primaryRuleList = RuleList(rules: [
LegacyRandomRule.self,
LetVarWhitespaceRule.self,
LineLengthRule.self,
LiteralExpressionEndIdentationRule.self,
LiteralExpressionEndIndentationRule.self,
LocalDocCommentRule.self,
LowerACLThanParentRule.self,
MarkRule.self,
@ -137,6 +141,7 @@ public let primaryRuleList = RuleList(rules: [
OverriddenSuperCallRule.self,
OverrideInExtensionRule.self,
PatternMatchingKeywordsRule.self,
PeriodSpacingRule.self,
PreferNimbleRule.self,
PreferSelfInStaticReferencesRule.self,
PreferSelfTypeOverTypeOfSelfRule.self,
@ -160,6 +165,7 @@ public let primaryRuleList = RuleList(rules: [
RedundantNilCoalescingRule.self,
RedundantObjcAttributeRule.self,
RedundantOptionalInitializationRule.self,
RedundantSelfInClosureRule.self,
RedundantSetAccessControlRule.self,
RedundantStringEnumValueRule.self,
RedundantTypeAnnotationRule.self,
@ -173,13 +179,14 @@ public let primaryRuleList = RuleList(rules: [
ShorthandOperatorRule.self,
ShorthandOptionalBindingRule.self,
SingleTestClassRule.self,
SortedEnumCasesRule.self,
SortedFirstLastRule.self,
SortedImportsRule.self,
StatementPositionRule.self,
StaticOperatorRule.self,
StrictFilePrivateRule.self,
StrongIBOutletRule.self,
SuperfluousDisableCommandRule.self,
SuperfluousElseRule.self,
SwitchCaseAlignmentRule.self,
SwitchCaseOnNewlineRule.self,
SyntacticSugarRule.self,
@ -197,6 +204,7 @@ public let primaryRuleList = RuleList(rules: [
TypesafeArrayInitRule.self,
UnavailableConditionRule.self,
UnavailableFunctionRule.self,
UnhandledThrowingTaskRule.self,
UnneededBreakInSwitchRule.self,
UnneededParenthesesInClosureArgumentRule.self,
UnownedVariableCaptureRule.self,
@ -222,4 +230,4 @@ public let primaryRuleList = RuleList(rules: [
XCTFailMessageRule.self,
XCTSpecificMatcherRule.self,
YodaConditionRule.self
] + extraRules())
]

View File

@ -23,7 +23,7 @@ enum ImportUsage {
case .unused:
return nil
case .missing(let module):
return "Missing import for referenced module '\(module)'."
return "Missing import for referenced module '\(module)'"
}
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct AnonymousArgumentInMultilineClosureRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "anonymous_argument_in_multiline_closure",
@ -50,12 +48,7 @@ private extension AnonymousArgumentInMultilineClosureRule {
override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind {
let startLocation = locationConverter.location(for: node.leftBrace.positionAfterSkippingLeadingTrivia)
let endLocation = locationConverter.location(for: node.rightBrace.endPositionBeforeTrailingTrivia)
guard let startLine = startLocation.line, let endLine = endLocation.line, startLine != endLine else {
return .skipChildren
}
return .visitChildren
return startLocation.line == endLocation.line ? .skipChildren : .visitChildren
}
override func visitPost(_ node: IdentifierExprSyntax) {

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct BlockBasedKVORule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "block_based_kvo",
name: "Block Based KVO",
description: "Prefer the new block based KVO API with keypaths when using Swift 3.2 or later.",
description: "Prefer the new block based KVO API with keypaths when using Swift 3.2 or later",
kind: .idiomatic,
nonTriggeringExamples: [
Example(#"""
@ -47,13 +45,13 @@ private extension BlockBasedKVORule {
case let parameterList = node.signature.input.parameterList,
parameterList.count == 4,
node.identifier.text == "observeValue",
parameterList.compactMap(\.firstName?.text) == ["forKeyPath", "of", "change", "context"]
parameterList.map(\.firstName.text) == ["forKeyPath", "of", "change", "context"]
else {
return
}
let types = parameterList
.compactMap { $0.type?.withoutTrivia().description.replacingOccurrences(of: " ", with: "") }
.map { $0.type.trimmedDescription.replacingOccurrences(of: " ", with: "") }
let firstTypes = ["String?", "Any?", "[NSKeyValueChangeKey:Any]?", "UnsafeMutableRawPointer?"]
let secondTypes = ["String?", "Any?", "Dictionary<NSKeyValueChangeKey,Any>?", "UnsafeMutableRawPointer?"]
if types == firstTypes || types == secondTypes {

View File

@ -1,15 +1,13 @@
import SwiftSyntax
struct ConvenienceTypeRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "convenience_type",
name: "Convenience Type",
description: "Types used for hosting only static members should be implemented as a caseless enum " +
"to avoid instantiation.",
"to avoid instantiation",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
@ -127,13 +125,21 @@ private extension ConvenienceTypeRule {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: StructDeclSyntax) {
if hasViolation(inheritance: node.inheritanceClause, attributes: node.attributes, members: node.members) {
if hasViolation(
inheritance: node.inheritanceClause,
attributes: node.attributes,
members: node.memberBlock
) {
violations.append(node.structKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: ClassDeclSyntax) {
if hasViolation(inheritance: node.inheritanceClause, attributes: node.attributes, members: node.members) {
if hasViolation(
inheritance: node.inheritanceClause,
attributes: node.attributes,
members: node.memberBlock
) {
violations.append(node.classKeyword.positionAfterSkippingLeadingTrivia)
}
}
@ -198,15 +204,11 @@ private extension TypeInheritanceClauseSyntax? {
private extension AttributeListSyntax? {
var containsObjcMembers: Bool {
self?.contains { elem in
elem.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("objcMembers")
} ?? false
contains(attributeNamed: "objcMembers")
}
var containsObjc: Bool {
self?.contains { elem in
elem.as(AttributeSyntax.self)?.attributeName.tokenKind == .contextualKeyword("objc")
} ?? false
contains(attributeNamed: "objc")
}
}
@ -218,12 +220,12 @@ private extension AttributeListSyntax? {
return attrs.contains { elem in
guard let attr = elem.as(AttributeSyntax.self),
let arguments = attr.argument?.as(AvailabilitySpecListSyntax.self) else {
let arguments = attr.argument?.as(AvailabilitySpecListSyntax.self) else {
return false
}
return attr.attributeName.tokenKind == .contextualKeyword("available") && arguments.contains { arg in
arg.entry.as(TokenSyntax.self)?.tokenKind == .contextualKeyword("unavailable")
return attr.attributeNameText == "available" && arguments.contains { arg in
arg.entry.as(TokenSyntax.self)?.tokenKind.isUnavailableKeyword == true
}
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct DiscouragedAssertRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
// MARK: - Properties
var configuration = SeverityConfiguration(.warning)
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "discouraged_assert",
@ -25,12 +23,6 @@ struct DiscouragedAssertRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderR
]
)
// MARK: - Life cycle
init() {}
// MARK: - Public
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
@ -39,11 +31,11 @@ struct DiscouragedAssertRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderR
private extension DiscouragedAssertRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.withoutTrivia().text == "assert",
guard node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.text == "assert",
let firstArg = node.argumentList.first,
firstArg.label == nil,
let boolExpr = firstArg.expression.as(BooleanLiteralExprSyntax.self),
boolExpr.booleanLiteral.tokenKind == .falseKeyword else {
boolExpr.booleanLiteral.tokenKind == .keyword(.false) else {
return
}

View File

@ -1,14 +1,13 @@
import SwiftSyntax
struct DiscouragedNoneNameRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "discouraged_none_name",
name: "Discouraged None Name",
description: "Discourages name cases/static members `none`, which can conflict with `Optional<T>.none`.",
description: "Enum cases and static members named `none` are discouraged as they can conflict with " +
"`Optional<T>.none`.",
kind: .idiomatic,
nonTriggeringExamples: [
// Should not trigger unless exactly matches "none"
@ -206,7 +205,7 @@ private extension DiscouragedNoneNameRule {
}
}()
guard let type = type else {
guard let type else {
return
}
@ -224,9 +223,9 @@ private extension DiscouragedNoneNameRule {
}
private func reason(type: String) -> String {
let reason = "Avoid naming \(type) `none` as the compiler can think you mean `Optional<T>.none`."
let recommendation = "Consider using an Optional value instead."
return "\(reason) \(recommendation)"
let reason = "Avoid naming \(type) `none` as the compiler can think you mean `Optional<T>.none`"
let recommendation = "consider using an Optional value instead"
return "\(reason); \(recommendation)"
}
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct DiscouragedObjectLiteralRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = ObjectLiteralConfiguration()
init() {}
var configuration = DiscouragedObjectLiteralConfiguration()
static let description = RuleDescription(
identifier: "discouraged_object_literal",
name: "Discouraged Object Literal",
description: "Prefer initializers over object literals.",
description: "Prefer initializers over object literals",
kind: .idiomatic,
nonTriggeringExamples: [
Example("let image = UIImage(named: aVariable)"),
@ -31,9 +29,9 @@ struct DiscouragedObjectLiteralRule: SwiftSyntaxRule, OptInRule, ConfigurationPr
private extension DiscouragedObjectLiteralRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: ObjectLiteralConfiguration
private let configuration: ConfigurationType
init(configuration: ObjectLiteralConfiguration) {
init(configuration: ConfigurationType) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct DiscouragedOptionalBooleanRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "discouraged_optional_boolean",
name: "Discouraged Optional Boolean",
description: "Prefer non-optional booleans over optional booleans.",
description: "Prefer non-optional booleans over optional booleans",
kind: .idiomatic,
nonTriggeringExamples: DiscouragedOptionalBooleanRuleExamples.nonTriggeringExamples,
triggeringExamples: DiscouragedOptionalBooleanRuleExamples.triggeringExamples

View File

@ -1,14 +1,12 @@
import SourceKittenFramework
struct DiscouragedOptionalCollectionRule: ASTRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "discouraged_optional_collection",
name: "Discouraged Optional Collection",
description: "Prefer empty collection over optional collection.",
description: "Prefer empty collection over optional collection",
kind: .idiomatic,
nonTriggeringExamples: DiscouragedOptionalCollectionExamples.nonTriggeringExamples,
triggeringExamples: DiscouragedOptionalCollectionExamples.triggeringExamples
@ -17,7 +15,7 @@ struct DiscouragedOptionalCollectionRule: ASTRule, OptInRule, ConfigurationProvi
func validate(file: SwiftLintFile,
kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) -> [StyleViolation] {
let offsets = variableViolations(file: file, kind: kind, dictionary: dictionary) +
let offsets = variableViolations(kind: kind, dictionary: dictionary) +
functionViolations(file: file, kind: kind, dictionary: dictionary)
return offsets.map {
@ -29,9 +27,7 @@ struct DiscouragedOptionalCollectionRule: ASTRule, OptInRule, ConfigurationProvi
// MARK: - Private
private func variableViolations(file: SwiftLintFile,
kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) -> [ByteCount] {
private func variableViolations(kind: SwiftDeclarationKind, dictionary: SourceKittenDictionary) -> [ByteCount] {
guard
SwiftDeclarationKind.variableKinds.contains(kind),
let offset = dictionary.offset,

View File

@ -2,7 +2,7 @@ import Foundation
import SourceKittenFramework
struct DuplicateImportsRule: ConfigurationProviderRule, CorrectableRule {
var configuration = SeverityConfiguration(.warning)
var configuration = SeverityConfiguration<Self>(.warning)
// List of all possible import kinds
static let importKinds = [
@ -11,12 +11,10 @@ struct DuplicateImportsRule: ConfigurationProviderRule, CorrectableRule {
"var", "func"
]
init() {}
static let description = RuleDescription(
identifier: "duplicate_imports",
name: "Duplicate Imports",
description: "Imports should be unique.",
description: "Imports should be unique",
kind: .idiomatic,
nonTriggeringExamples: DuplicateImportsRuleExamples.nonTriggeringExamples,
triggeringExamples: DuplicateImportsRuleExamples.triggeringExamples,
@ -194,7 +192,7 @@ private extension Line {
/// For "import A.B.C" returns slices [["A", "B", "C"], ["A", "B"], ["A"]]
var importSlices: [ImportSlice] {
guard let importIdentifier = importIdentifier else { return [] }
guard let importIdentifier else { return [] }
let importedSubpathParts = importIdentifier.split(separator: ".").map { String($0) }
guard !importedSubpathParts.isEmpty else { return [] }

View File

@ -4,14 +4,12 @@ import SourceKittenFramework
private typealias SourceKittenElement = SourceKittenDictionary
struct ExplicitACLRule: OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_acl",
name: "Explicit ACL",
description: "All declarations should specify Access Control Level keywords explicitly.",
description: "All declarations should specify Access Control Level keywords explicitly",
kind: .idiomatic,
nonTriggeringExamples: [
Example("internal enum A {}\n"),
@ -188,7 +186,7 @@ private extension SwiftDeclarationKind {
.functionMethodInstance, .functionMethodStatic, .functionOperator, .functionOperatorInfix,
.functionOperatorPostfix, .functionOperatorPrefix, .functionSubscript, .protocol, .opaqueType:
return true
case .class, .enum, .extension, .extensionClass, .extensionEnum,
case .actor, .class, .enum, .extension, .extensionClass, .extensionEnum,
.extensionProtocol, .extensionStruct, .struct:
return false
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ExplicitEnumRawValueRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_enum_raw_value",
name: "Explicit Enum Raw Value",
description: "Enums should be explicitly assigned their raw values.",
description: "Enums should be explicitly assigned their raw values",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
@ -89,17 +87,14 @@ private extension ExplicitEnumRawValueRule {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: EnumCaseElementSyntax) {
if node.rawValue == nil,
let enclosingEnum = Syntax(node).enclosingEnum(),
let inheritance = enclosingEnum.inheritanceClause,
inheritance.supportsRawValue {
if node.rawValue == nil, node.enclosingEnum()?.supportsRawValues == true {
violations.append(node.identifier.positionAfterSkippingLeadingTrivia)
}
}
}
}
private extension Syntax {
private extension SyntaxProtocol {
func enclosingEnum() -> EnumDeclSyntax? {
if let node = self.as(EnumDeclSyntax.self) {
return node
@ -108,23 +103,3 @@ private extension Syntax {
return parent?.enclosingEnum()
}
}
private extension TypeInheritanceClauseSyntax {
var supportsRawValue: Bool {
// Check if it's an enum which supports raw values
let implicitRawValueSet: Set<String> = [
"Int", "Int8", "Int16", "Int32", "Int64",
"UInt", "UInt8", "UInt16", "UInt32", "UInt64",
"Double", "Float", "Float80", "Decimal", "NSNumber",
"NSDecimalNumber", "NSInteger", "String"
]
return inheritedTypeCollection.contains { element in
guard let identifier = element.typeName.as(SimpleTypeIdentifierSyntax.self)?.name.text else {
return false
}
return implicitRawValueSet.contains(identifier)
}
}
}

View File

@ -2,14 +2,12 @@ import SwiftSyntax
import SwiftSyntaxBuilder
struct ExplicitInitRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_init",
name: "Explicit Init",
description: "Explicitly calling .init() should be avoided.",
description: "Explicitly calling .init() should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
@ -218,14 +216,15 @@ private extension ExplicitInitRule {
}
correctionPositions.append(violationPosition)
return super.visit(node.withCalledExpression("\(calledBase.withoutTrivia())"))
let newNode = node.with(\.calledExpression, calledBase.trimmed)
return super.visit(newNode)
}
}
}
private extension MemberAccessExprSyntax {
var explicitInitPosition: AbsolutePosition? {
if let base = base, base.isTypeReferenceLike, name.text == "init" {
if let base, base.isTypeReferenceLike, name.text == "init" {
return base.endPositionBeforeTrailingTrivia
} else {
return nil

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ExplicitTopLevelACLRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_top_level_acl",
name: "Explicit Top Level ACL",
description: "Top-level declarations should specify Access Control Level keywords explicitly.",
description: "Top-level declarations should specify Access Control Level keywords explicitly",
kind: .idiomatic,
nonTriggeringExamples: [
Example("internal enum A {}\n"),
@ -83,7 +81,7 @@ private extension ExplicitTopLevelACLRule {
override func visitPost(_ node: VariableDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.letOrVarKeyword.positionAfterSkippingLeadingTrivia)
violations.append(node.bindingKeyword.positionAfterSkippingLeadingTrivia)
}
}
@ -96,7 +94,7 @@ private extension ExplicitTopLevelACLRule {
}
private func hasViolation(modifiers: ModifierListSyntax?) -> Bool {
guard let modifiers = modifiers else {
guard let modifiers else {
return true
}
@ -108,11 +106,11 @@ private extension ExplicitTopLevelACLRule {
private extension DeclModifierSyntax {
var isACLModifier: Bool {
let aclModifiers: Set<TokenKind> = [
.privateKeyword,
.fileprivateKeyword,
.internalKeyword,
.publicKeyword,
.contextualKeyword("open")
.keyword(.private),
.keyword(.fileprivate),
.keyword(.internal),
.keyword(.public),
.keyword(.open)
]
return detail == nil && aclModifiers.contains(name.tokenKind)

View File

@ -0,0 +1,142 @@
import SwiftSyntax
struct ExplicitTypeInterfaceRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = ExplicitTypeInterfaceConfiguration()
static let description = RuleDescription(
identifier: "explicit_type_interface",
name: "Explicit Type Interface",
description: "Properties should have a type interface",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
class Foo {
var myVar: Int? = 0
}
"""),
Example("""
class Foo {
let myVar: Int? = 0, s: String = ""
}
"""),
Example("""
class Foo {
static var myVar: Int? = 0
}
"""),
Example("""
class Foo {
class var myVar: Int? = 0
}
"""),
Example("""
func f() {
if case .failure(let error) = errorCompletion {}
}
""", excludeFromDocumentation: true)
],
triggeringExamples: [
Example("""
class Foo {
var myVar = 0
}
"""),
Example("""
class Foo {
let mylet = 0
}
"""),
Example("""
class Foo {
static var myStaticVar = 0
}
"""),
Example("""
class Foo {
class var myClassVar = 0
}
"""),
Example("""
class Foo {
let myVar = Int(0), s = ""
}
"""),
Example("""
class Foo {
let myVar = Set<Int>(0)
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private class Visitor: ViolationsSyntaxVisitor {
let configuration: ExplicitTypeInterfaceConfiguration
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
init(configuration: ExplicitTypeInterfaceConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: VariableDeclSyntax) {
if node.modifiers.isClass {
if configuration.allowedKinds.contains(.class) {
checkViolation(node)
}
} else if node.modifiers.isStatic {
if configuration.allowedKinds.contains(.static) {
checkViolation(node)
}
} else if node.parent?.is(MemberDeclListItemSyntax.self) == true {
if configuration.allowedKinds.contains(.instance) {
checkViolation(node)
}
} else if node.parent?.is(CodeBlockItemSyntax.self) == true {
if configuration.allowedKinds.contains(.local) {
checkViolation(node)
}
}
}
private func checkViolation(_ node: VariableDeclSyntax) {
for binding in node.bindings {
if configuration.allowRedundancy, let initializer = binding.initializer,
initializer.isTypeConstructor || initializer.isTypeReference {
continue
}
if binding.typeAnnotation == nil {
violations.append(binding.positionAfterSkippingLeadingTrivia)
}
}
}
}
private extension InitializerClauseSyntax {
var isTypeConstructor: Bool {
if value.as(FunctionCallExprSyntax.self)?.callsPotentialType == true {
return true
}
if let tryExpr = value.as(TryExprSyntax.self),
tryExpr.expression.as(FunctionCallExprSyntax.self)?.callsPotentialType == true {
return true
}
return false
}
var isTypeReference: Bool {
value.as(MemberAccessExprSyntax.self)?.name.tokenKind == .keyword(.self)
}
}
private extension FunctionCallExprSyntax {
var callsPotentialType: Bool {
let name = calledExpression.debugDescription
return name.first?.isUppercase == true || (name.first == "[" && name.last == "]")
}
}

View File

@ -2,9 +2,7 @@ import Foundation
import SourceKittenFramework
struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "extension_access_modifier",
@ -157,9 +155,7 @@ struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, OptInRul
// attributeBuiltin (`final` for example) tokens between them
let length = typeOffset - previousInternalByteRange.location
let range = ByteRange(location: previousInternalByteRange.location, length: length)
let internalBelongsToType = Set(file.syntaxMap.kinds(inByteRange: range)) == [.attributeBuiltin]
return internalBelongsToType
return Set(file.syntaxMap.kinds(inByteRange: range)) == [.attributeBuiltin]
}
return violationOffsets.map {

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct FallthroughRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "fallthrough",
name: "Fallthrough",
description: "Fallthrough should be avoided.",
description: "Fallthrough should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct FatalErrorMessageRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "fatal_error_message",
name: "Fatal Error Message",
description: "A fatalError call should have a message.",
description: "A fatalError call should have a message",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
@ -45,7 +43,7 @@ private extension FatalErrorMessageRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard let expression = node.calledExpression.as(IdentifierExprSyntax.self),
expression.identifier.withoutTrivia().text == "fatalError",
expression.identifier.text == "fatalError",
node.argumentList.isEmptyOrEmptyString else {
return
}

View File

@ -2,17 +2,12 @@ import Foundation
import SourceKittenFramework
struct FileNameNoSpaceRule: ConfigurationProviderRule, OptInRule, SourceKitFreeRule {
var configuration = FileNameNoSpaceConfiguration(
severity: .warning,
excluded: []
)
init() {}
var configuration = FileNameNoSpaceConfiguration()
static let description = RuleDescription(
identifier: "file_name_no_space",
name: "File Name No Space",
description: "File name should not contain any whitespace.",
name: "File Name no Space",
description: "File name should not contain any whitespace",
kind: .idiomatic
)
@ -25,7 +20,7 @@ struct FileNameNoSpaceRule: ConfigurationProviderRule, OptInRule, SourceKitFreeR
}
return [StyleViolation(ruleDescription: Self.description,
severity: configuration.severity.severity,
severity: configuration.severity,
location: Location(file: filePath, line: 1))]
}
}

View File

@ -1,20 +1,12 @@
import SwiftSyntax
struct FileNameRule: ConfigurationProviderRule, OptInRule, SourceKitFreeRule {
var configuration = FileNameConfiguration(
severity: .warning,
excluded: ["main.swift", "LinuxMain.swift"],
prefixPattern: "",
suffixPattern: "\\+.*",
nestedTypeSeparator: "."
)
init() {}
var configuration = FileNameConfiguration()
static let description = RuleDescription(
identifier: "file_name",
name: "File Name",
description: "File name should match a type or extension declared in the file (if any).",
description: "File name should match a type or extension declared in the file (if any)",
kind: .idiomatic
)
@ -54,7 +46,7 @@ struct FileNameRule: ConfigurationProviderRule, OptInRule, SourceKitFreeRule {
}
return [StyleViolation(ruleDescription: Self.description,
severity: configuration.severity.severity,
severity: configuration.severity,
location: Location(file: filePath, line: 1))]
}
}
@ -87,6 +79,6 @@ private class TypeNameCollectingVisitor: SyntaxVisitor {
}
override func visitPost(_ node: ExtensionDeclSyntax) {
names.insert(node.extendedType.withoutTrivia().description)
names.insert(node.extendedType.trimmedDescription)
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ForWhereRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = ForWhereRuleConfiguration()
init() {}
var configuration = ForWhereConfiguration()
static let description = RuleDescription(
identifier: "for_where",
name: "For Where",
description: "`where` clauses are preferred over a single `if` inside a `for`.",
name: "Prefer For-Where",
description: "`where` clauses are preferred over a single `if` inside a `for`",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
@ -134,26 +132,26 @@ private extension ForWhereRule {
override func visitPost(_ node: ForInStmtSyntax) {
guard node.whereClause == nil,
case let statements = node.body.statements,
let ifStatement = statements.onlyElement?.item.as(IfStmtSyntax.self),
ifStatement.elseBody == nil,
!ifStatement.containsOptionalBinding,
!ifStatement.containsPatternCondition,
let condition = ifStatement.conditions.onlyElement,
let onlyExprStmt = node.body.statements.onlyElement?.item.as(ExpressionStmtSyntax.self),
let ifExpr = onlyExprStmt.expression.as(IfExprSyntax.self),
ifExpr.elseBody == nil,
!ifExpr.containsOptionalBinding,
!ifExpr.containsPatternCondition,
let condition = ifExpr.conditions.onlyElement,
!condition.containsMultipleConditions else {
return
}
if allowForAsFilter, ifStatement.containsReturnStatement {
if allowForAsFilter, ifExpr.containsReturnStatement {
return
}
violations.append(ifStatement.positionAfterSkippingLeadingTrivia)
violations.append(ifExpr.positionAfterSkippingLeadingTrivia)
}
}
}
private extension IfStmtSyntax {
private extension IfExprSyntax {
var containsOptionalBinding: Bool {
conditions.contains { element in
element.condition.is(OptionalBindingConditionSyntax.self)

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ForceCastRule: ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.error)
init() {}
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
identifier: "force_cast",
name: "Force Cast",
description: "Force casts should be avoided.",
description: "Force casts should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("NSNumber() as? Int\n")

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ForceTryRule: ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.error)
init() {}
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
identifier: "force_try",
name: "Force Try",
description: "Force tries should be avoided.",
description: "Force tries should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ForceUnwrappingRule: OptInRule, SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "force_unwrapping",
name: "Force Unwrapping",
description: "Force unwrapping should be avoided.",
description: "Force unwrapping should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("if let url = NSURL(string: query)"),

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct FunctionDefaultParameterAtEndRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "function_default_parameter_at_end",
name: "Function Default Parameter at End",
description: "Prefer to locate parameters with defaults toward the end of the parameter list.",
description: "Prefer to locate parameters with defaults toward the end of the parameter list",
kind: .idiomatic,
nonTriggeringExamples: [
Example("func foo(baz: String, bar: Int = 0) {}"),
@ -104,20 +102,20 @@ private extension FunctionSignatureSyntax {
private extension FunctionParameterSyntax {
var isClosure: Bool {
if isEscaping || type?.as(FunctionTypeSyntax.self) != nil {
if isEscaping || type.is(FunctionTypeSyntax.self) {
return true
}
if let optionalType = type?.as(OptionalTypeSyntax.self),
if let optionalType = type.as(OptionalTypeSyntax.self),
let tuple = optionalType.wrappedType.as(TupleTypeSyntax.self) {
return tuple.elements.onlyElement?.type.as(FunctionTypeSyntax.self) != nil
}
if let tuple = type?.as(TupleTypeSyntax.self) {
if let tuple = type.as(TupleTypeSyntax.self) {
return tuple.elements.onlyElement?.type.as(FunctionTypeSyntax.self) != nil
}
if let attrType = type?.as(AttributedTypeSyntax.self) {
if let attrType = type.as(AttributedTypeSyntax.self) {
return attrType.baseType.is(FunctionTypeSyntax.self)
}
@ -125,12 +123,10 @@ private extension FunctionParameterSyntax {
}
var isEscaping: Bool {
guard let attrType = type?.as(AttributedTypeSyntax.self) else {
guard let attrType = type.as(AttributedTypeSyntax.self) else {
return false
}
return attrType.attributes?.contains { attr in
attr.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("escaping")
} ?? false
return attrType.attributes.contains(attributeNamed: "escaping")
}
}

View File

@ -2,12 +2,10 @@ import Foundation
import SwiftSyntax
struct GenericTypeNameRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = NameConfiguration(minLengthWarning: 1,
minLengthError: 0,
maxLengthWarning: 20,
maxLengthError: 1000)
init() {}
var configuration = NameConfiguration<Self>(minLengthWarning: 1,
minLengthError: 0,
maxLengthWarning: 20,
maxLengthError: 1000)
static let description = RuleDescription(
identifier: "generic_type_name",
@ -57,40 +55,39 @@ struct GenericTypeNameRule: SwiftSyntaxRule, ConfigurationProviderRule {
private extension GenericTypeNameRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: NameConfiguration
private let configuration: ConfigurationType
init(configuration: NameConfiguration) {
init(configuration: ConfigurationType) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: GenericParameterSyntax) {
let name = node.name.text
guard !configuration.excluded.contains(name) else {
return
}
guard !name.isEmpty, !configuration.shouldExclude(name: name) else { return }
let allowedSymbols = configuration.allowedSymbols.union(.alphanumerics)
if !allowedSymbols.isSuperset(of: CharacterSet(charactersIn: name)) {
if !configuration.allowedSymbolsAndAlphanumerics.isSuperset(of: CharacterSet(charactersIn: name)) {
violations.append(
ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,
reason: "Generic type name should only contain alphanumeric characters: '\(name)'",
reason: """
Generic type name '\(name)' should only contain alphanumeric and other allowed characters
""",
severity: .error
)
)
} else if configuration.validatesStartWithLowercase &&
} else if let caseCheckSeverity = configuration.validatesStartWithLowercase.severity,
!String(name[name.startIndex]).isUppercase() {
violations.append(
ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,
reason: "Generic type name should start with an uppercase character: '\(name)'",
severity: .error
reason: "Generic type name '\(name)' should start with an uppercase character",
severity: caseCheckSeverity
)
)
} else if let severity = configuration.severity(forLength: name.count) {
let reason = "Generic type name should be between \(configuration.minLengthThreshold) and " +
"\(configuration.maxLengthThreshold) characters long: '\(name)'"
let reason = "Generic type name '\(name)' should be between \(configuration.minLengthThreshold) and " +
"\(configuration.maxLengthThreshold) characters long"
violations.append(
ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,

View File

@ -1,17 +1,12 @@
import SwiftSyntax
struct ImplicitlyUnwrappedOptionalRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = ImplicitlyUnwrappedOptionalConfiguration(
mode: .allExceptIBOutlets,
severityConfiguration: SeverityConfiguration(.warning)
)
init() {}
var configuration = ImplicitlyUnwrappedOptionalConfiguration()
static let description = RuleDescription(
identifier: "implicitly_unwrapped_optional",
name: "Implicitly Unwrapped Optional",
description: "Implicitly unwrapped optionals should be avoided when possible.",
description: "Implicitly unwrapped optionals should be avoided when possible",
kind: .idiomatic,
nonTriggeringExamples: [
Example("@IBOutlet private var label: UILabel!"),
@ -19,19 +14,30 @@ struct ImplicitlyUnwrappedOptionalRule: SwiftSyntaxRule, ConfigurationProviderRu
Example("@IBOutlet var label: [UILabel!]"),
Example("if !boolean {}"),
Example("let int: Int? = 42"),
Example("let int: Int? = nil")
Example("let int: Int? = nil"),
Example("""
class MyClass {
@IBOutlet
weak var bar: SomeObject!
}
""", configuration: ["mode": "all_except_iboutlets"], excludeFromDocumentation: true)
],
triggeringExamples: [
Example("let label: UILabel!"),
Example("let IBOutlet: UILabel!"),
Example("let labels: [UILabel!]"),
Example("var ints: [Int!] = [42, nil, 42]"),
Example("let label: IBOutlet!"),
Example("let int: Int! = 42"),
Example("let int: Int! = nil"),
Example("var int: Int! = 42"),
Example("let collection: AnyCollection<Int!>"),
Example("func foo(int: Int!) {}")
Example("let label: ↓UILabel!"),
Example("let IBOutlet: ↓UILabel!"),
Example("let labels: [↓UILabel!]"),
Example("var ints: [↓Int!] = [42, nil, 42]"),
Example("let label: ↓IBOutlet!"),
Example("let int: ↓Int! = 42"),
Example("let int: ↓Int! = nil"),
Example("var int: ↓Int! = 42"),
Example("let collection: AnyCollection<↓Int!>"),
Example("func foo(int: ↓Int!) {}"),
Example("""
class MyClass {
weak var bar: SomeObject!
}
""")
]
)
@ -42,9 +48,9 @@ struct ImplicitlyUnwrappedOptionalRule: SwiftSyntaxRule, ConfigurationProviderRu
private extension ImplicitlyUnwrappedOptionalRule {
final class Visitor: ViolationsSyntaxVisitor {
private let mode: ImplicitlyUnwrappedOptionalModeConfiguration
private let mode: ConfigurationType.ImplicitlyUnwrappedOptionalModeConfiguration
init(mode: ImplicitlyUnwrappedOptionalModeConfiguration) {
init(mode: ConfigurationType.ImplicitlyUnwrappedOptionalModeConfiguration) {
self.mode = mode
super.init(viewMode: .sourceAccurate)
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct IsDisjointRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "is_disjoint",
name: "Is Disjoint",
description: "Prefer using `Set.isDisjoint(with:)` over `Set.intersection(_:).isEmpty`.",
description: "Prefer using `Set.isDisjoint(with:)` over `Set.intersection(_:).isEmpty`",
kind: .idiomatic,
nonTriggeringExamples: [
Example("_ = Set(syntaxKinds).isDisjoint(with: commentAndStringKindsSet)"),

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct JoinedDefaultParameterRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "joined_default_parameter",
name: "Joined Default Parameter",
description: "Discouraged explicit usage of the default separator.",
description: "Discouraged explicit usage of the default separator",
kind: .idiomatic,
nonTriggeringExamples: [
Example("let foo = bar.joined()"),
@ -76,7 +74,7 @@ private extension JoinedDefaultParameterRule {
}
correctionPositions.append(violationPosition)
let newNode = node.withArgumentList(nil)
let newNode = node.with(\.argumentList, [])
return super.visit(newNode)
}
}

View File

@ -1,7 +1,5 @@
struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_cggeometry_functions",
@ -70,7 +68,7 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule, ConfigurationP
Example("↓CGRectInset(rect, 5.0, -7.0)\n"): Example("rect.insetBy(dx: 5.0, dy: -7.0)\n"),
Example("↓CGRectOffset(rect, -2, 8.3)\n"): Example("rect.offsetBy(dx: -2, dy: 8.3)\n"),
Example("↓CGRectUnion(rect1, rect2)\n"): Example("rect1.union(rect2)\n"),
Example("↓CGRectIntersection( rect1 ,rect2)\n"): Example("rect1.intersect(rect2)\n"),
Example("↓CGRectIntersection( rect1 ,rect2)\n"): Example("rect1.intersection(rect2)\n"),
Example("↓CGRectContainsRect( rect1,rect2 )\n"): Example("rect1.contains(rect2)\n"),
Example("↓CGRectContainsPoint(rect ,point)\n"): Example("rect.contains(point)\n"),
Example("↓CGRectIntersectsRect( rect1,rect2 )\n"): Example("rect1.intersects(rect2)\n"),
@ -99,7 +97,7 @@ struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule, ConfigurationP
"CGRectContainsRect": .function(name: "contains", argumentLabels: [""]),
"CGRectContainsPoint": .function(name: "contains", argumentLabels: [""]),
"CGRectIntersectsRect": .function(name: "intersects", argumentLabels: [""]),
"CGRectIntersection": .function(name: "intersect", argumentLabels: [""])
"CGRectIntersection": .function(name: "intersection", argumentLabels: [""])
]
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {

View File

@ -2,14 +2,12 @@ import SwiftSyntax
import SwiftSyntaxBuilder
struct LegacyConstantRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_constant",
name: "Legacy Constant",
description: "Struct-scoped constants are preferred over legacy global constants.",
description: "Struct-scoped constants are preferred over legacy global constants",
kind: .idiomatic,
nonTriggeringExamples: LegacyConstantRuleExamples.nonTriggeringExamples,
triggeringExamples: LegacyConstantRuleExamples.triggeringExamples,
@ -62,9 +60,9 @@ private extension LegacyConstantRule {
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return ("\(correction)" as ExprSyntax)
.withLeadingTrivia(node.leadingTrivia ?? .zero)
.withTrailingTrivia(node.trailingTrivia ?? .zero)
return ("\(raw: correction)" as ExprSyntax)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
@ -77,9 +75,9 @@ private extension LegacyConstantRule {
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return ("\(calledExpression.identifier.text).pi" as ExprSyntax)
.withLeadingTrivia(node.leadingTrivia ?? .zero)
.withTrailingTrivia(node.trailingTrivia ?? .zero)
return ("\(raw: calledExpression.identifier.text).pi" as ExprSyntax)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct LegacyConstructorRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_constructor",
name: "Legacy Constructor",
description: "Swift constructors are preferred over legacy convenience functions.",
description: "Swift constructors are preferred over legacy convenience functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("CGPoint(x: 10, y: 10)"),
@ -140,7 +138,7 @@ private extension LegacyConstructorRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let identifierExpr = node.calledExpression.as(IdentifierExprSyntax.self),
constructorsToCorrectedNames[identifierExpr.identifier.withoutTrivia().text] != nil {
constructorsToCorrectedNames[identifierExpr.identifier.text] != nil {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
@ -158,7 +156,7 @@ private extension LegacyConstructorRule {
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
guard let identifierExpr = node.calledExpression.as(IdentifierExprSyntax.self),
case let identifier = identifierExpr.identifier.withoutTrivia().text,
case let identifier = identifierExpr.identifier.text,
let correctedName = constructorsToCorrectedNames[identifier],
let args = constructorsToArguments[identifier],
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
@ -167,12 +165,13 @@ private extension LegacyConstructorRule {
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
let arguments = TupleExprElementListSyntax(node.argumentList.map { elem in
let arguments = TupleExprElementListSyntax(node.argumentList.enumerated().map { index, elem in
elem
.withLabel(.identifier(args[elem.indexInParent]))
.withColon(.colonToken(trailingTrivia: .space))
.with(\.label, .identifier(args[index]))
.with(\.colon, .colonToken(trailingTrivia: .space))
})
let newExpression = identifierExpr.withIdentifier(
let newExpression = identifierExpr.with(
\.identifier,
.identifier(
correctedName,
leadingTrivia: identifierExpr.identifier.leadingTrivia,
@ -180,8 +179,8 @@ private extension LegacyConstructorRule {
)
)
let newNode = node
.withCalledExpression(ExprSyntax(newExpression))
.withArgumentList(arguments)
.with(\.calledExpression, ExprSyntax(newExpression))
.with(\.argumentList, arguments)
return super.visit(newNode)
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct LegacyHashingRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_hashing",
@ -85,7 +83,7 @@ extension LegacyHashingRule {
override func visitPost(_ node: VariableDeclSyntax) {
guard
node.parent?.is(MemberDeclListItemSyntax.self) == true,
node.letOrVarKeyword.tokenKind == .varKeyword,
node.bindingKeyword.tokenKind == .keyword(.var),
let binding = node.bindings.onlyElement,
let identifier = binding.pattern.as(IdentifierPatternSyntax.self),
identifier.identifier.text == "hashValue",
@ -95,7 +93,7 @@ extension LegacyHashingRule {
return
}
violations.append(node.letOrVarKeyword.positionAfterSkippingLeadingTrivia)
violations.append(node.bindingKeyword.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct LegacyMultipleRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_multiple",
name: "Legacy Multiple",
description: "Prefer using the `isMultiple(of:)` function instead of using the remainder operator (`%`).",
description: "Prefer using the `isMultiple(of:)` function instead of using the remainder operator (`%`)",
kind: .idiomatic,
nonTriggeringExamples: [
Example("cell.contentView.backgroundColor = indexPath.row.isMultiple(of: 2) ? .gray : .white"),
@ -39,8 +37,8 @@ struct LegacyMultipleRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule
]
)
func preprocess(syntaxTree: SourceFileSyntax) -> SourceFileSyntax? {
syntaxTree.folded()
func preprocess(file: SwiftLintFile) -> SourceFileSyntax? {
file.foldedSyntaxTree
}
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
@ -52,7 +50,7 @@ private extension LegacyMultipleRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: InfixOperatorExprSyntax) {
guard let operatorNode = node.operatorOperand.as(BinaryOperatorExprSyntax.self),
operatorNode.operatorToken.tokenKind == .spacedBinaryOperator("%"),
operatorNode.operatorToken.tokenKind == .binaryOperator("%"),
let parent = node.parent?.as(InfixOperatorExprSyntax.self),
let parentOperatorNode = parent.operatorOperand.as(BinaryOperatorExprSyntax.self),
parentOperatorNode.isEqualityOrInequalityOperator else {
@ -80,8 +78,7 @@ private extension LegacyMultipleRule {
private extension BinaryOperatorExprSyntax {
var isEqualityOrInequalityOperator: Bool {
operatorToken.tokenKind == .spacedBinaryOperator("==") ||
operatorToken.tokenKind == .unspacedBinaryOperator("==") ||
operatorToken.tokenKind == .spacedBinaryOperator("!=")
operatorToken.tokenKind == .binaryOperator("==") ||
operatorToken.tokenKind == .binaryOperator("!=")
}
}

View File

@ -1,7 +1,5 @@
struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_nsgeometry_functions",

View File

@ -29,9 +29,7 @@ private let legacyObjcTypes = [
]
struct LegacyObjcTypeRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_objc_type",

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct LegacyRandomRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "legacy_random",
name: "Legacy Random",
description: "Prefer using `type.random(in:)` over legacy functions.",
description: "Prefer using `type.random(in:)` over legacy functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("Int.random(in: 0..<10)\n"),
@ -16,9 +14,9 @@ struct LegacyRandomRule: SwiftSyntaxRule, ConfigurationProviderRule {
Example("Float.random(in: 0 ..< 1)\n")
],
triggeringExamples: [
Example("↓arc4random(10)\n"),
Example("↓arc4random()\n"),
Example("↓arc4random_uniform(83)\n"),
Example("↓drand48(52)\n")
Example("↓drand48()\n")
]
)
@ -36,7 +34,7 @@ private extension LegacyRandomRule {
]
override func visitPost(_ node: FunctionCallExprSyntax) {
if let function = node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.withoutTrivia().text,
if let function = node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.text,
Self.legacyRandomFunctions.contains(function) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}

View File

@ -2,14 +2,12 @@ import Foundation
import SourceKittenFramework
struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, CorrectableRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "nimble_operator",
name: "Nimble Operator",
description: "Prefer Nimble operator overloads over free matcher functions.",
description: "Prefer Nimble operator overloads over free matcher functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("expect(seagull.squawk) != \"Hi!\"\n"),
@ -114,12 +112,10 @@ struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, CorrectableRule
return false
}
let containsCall = file.structureDictionary.structures(forByteOffset: byteRange.upperBound - 1)
return file.structureDictionary.structures(forByteOffset: byteRange.upperBound - 1)
.contains(where: { dict -> Bool in
return dict.expressionKind == .call && (dict.name ?? "").starts(with: "expect")
})
return containsCall
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct NoExtensionAccessModifierRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.error)
init() {}
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
identifier: "no_extension_access_modifier",

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct NoFallthroughOnlyRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "no_fallthrough_only",
name: "No Fallthrough Only",
description: "Fallthroughs can only be used if the `case` contains at least one other statement.",
name: "No Fallthrough only",
description: "Fallthroughs can only be used if the `case` contains at least one other statement",
kind: .idiomatic,
nonTriggeringExamples: NoFallthroughOnlyRuleExamples.nonTriggeringExamples,
triggeringExamples: NoFallthroughOnlyRuleExamples.triggeringExamples

View File

@ -1,14 +1,12 @@
import SourceKittenFramework
struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "no_grouping_extension",
name: "No Grouping Extension",
description: "Extensions shouldn't be used to group code within the same source file.",
description: "Extensions shouldn't be used to group code within the same source file",
kind: .idiomatic,
nonTriggeringExamples: [
Example("protocol Food {}\nextension Food {}\n"),

View File

@ -0,0 +1,129 @@
import SwiftSyntax
struct NoMagicNumbersRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = NoMagicNumbersConfiguration()
static let description = RuleDescription(
identifier: "no_magic_numbers",
name: "No Magic Numbers",
description: "Magic numbers should be replaced by named constants",
kind: .idiomatic,
nonTriggeringExamples: [
Example("var foo = 123"),
Example("static let bar: Double = 0.123"),
Example("let a = b + 1.0"),
Example("array[0] + array[1] "),
Example("let foo = 1_000.000_01"),
Example("// array[1337]"),
Example("baz(\"9999\")"),
Example("""
func foo() {
let x: Int = 2
let y = 3
let vector = [x, y, -1]
}
"""),
Example("""
class A {
var foo: Double = 132
static let bar: Double = 0.98
}
"""),
Example("""
@available(iOS 13, *)
func version() {
if #available(iOS 13, OSX 10.10, *) {
return
}
}
"""),
Example("""
enum Example: Int {
case positive = 2
case negative = -2
}
"""),
Example("""
class FooTests: XCTestCase {
let array: [Int] = []
let bar = array[42]
}
"""),
Example("""
class FooTests: XCTestCase {
class Bar {
let array: [Int] = []
let bar = array[42]
}
}
""")
],
triggeringExamples: [
Example("foo(↓321)"),
Example("bar(↓1_000.005_01)"),
Example("array[↓42]"),
Example("let box = array[↓12 + ↓14]"),
Example("let a = b + ↓2.0"),
Example("Color.primary.opacity(isAnimate ? ↓0.1 : ↓1.5)")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate, testParentClasses: configuration.testParentClasses)
}
}
private extension NoMagicNumbersRule {
final class Visitor: ViolationsSyntaxVisitor {
private let testParentClasses: Set<String>
init(viewMode: SyntaxTreeViewMode, testParentClasses: Set<String>) {
self.testParentClasses = testParentClasses
super.init(viewMode: viewMode)
}
override func visitPost(_ node: FloatLiteralExprSyntax) {
if node.isMemberOfATestClass(testParentClasses) == false, node.floatingDigits.isMagicNumber {
violations.append(node.floatingDigits.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: IntegerLiteralExprSyntax) {
if node.isMemberOfATestClass(testParentClasses) == false, node.digits.isMagicNumber {
violations.append(node.digits.positionAfterSkippingLeadingTrivia)
}
}
}
}
private extension TokenSyntax {
var isMagicNumber: Bool {
guard let number = Double(text.replacingOccurrences(of: "_", with: "")) else {
return false
}
if [0, 1].contains(number) {
return false
}
guard let grandparent = parent?.parent else {
return true
}
return !grandparent.is(InitializerClauseSyntax.self)
&& grandparent.as(PrefixOperatorExprSyntax.self)?.parent?.is(InitializerClauseSyntax.self) != true
}
}
private extension ExprSyntaxProtocol {
func isMemberOfATestClass(_ testParentClasses: Set<String>) -> Bool {
var parent = parent
while parent != nil {
if
let classDecl = parent?.as(ClassDeclSyntax.self),
classDecl.isXCTestCase(testParentClasses)
{
return true
}
parent = parent?.parent
}
return false
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ObjectLiteralRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = ObjectLiteralConfiguration()
init() {}
var configuration = ObjectLiteralConfiguration<Self>()
static let description = RuleDescription(
identifier: "object_literal",
name: "Object Literal",
description: "Prefer object literals over image and color inits.",
description: "Prefer object literals over image and color inits",
kind: .idiomatic,
nonTriggeringExamples: [
Example("let image = #imageLiteral(resourceName: \"image.jpg\")"),
@ -54,7 +52,7 @@ private extension ObjectLiteralRule {
return
}
let name = node.calledExpression.withoutTrivia().description
let name = node.calledExpression.trimmedDescription
if validateImageLiteral, isImageNamedInit(node: node, name: name) {
violations.append(node.positionAfterSkippingLeadingTrivia)
} else if validateColorLiteral, isColorInit(node: node, name: name) {

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct PatternMatchingKeywordsRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "pattern_matching_keywords",
name: "Pattern Matching Keywords",
description: "Combine multiple pattern matching bindings by moving keywords out of tuples.",
description: "Combine multiple pattern matching bindings by moving keywords out of tuples",
kind: .idiomatic,
nonTriggeringExamples: [
Example("default"),
@ -57,12 +55,12 @@ private extension PatternMatchingKeywordsRule {
}
guard list.count > 1,
let firstLetOrVar = list.first?.letOrVarKeyword.tokenKind else {
let firstLetOrVar = list.first?.bindingKeyword.tokenKind else {
return
}
let hasViolation = list.allSatisfy { elem in
elem.letOrVarKeyword.tokenKind == firstLetOrVar
elem.bindingKeyword.tokenKind == firstLetOrVar
}
guard hasViolation else {
@ -70,7 +68,7 @@ private extension PatternMatchingKeywordsRule {
}
violations.append(contentsOf: list.compactMap { elem in
return elem.letOrVarKeyword.positionAfterSkippingLeadingTrivia
return elem.bindingKeyword.positionAfterSkippingLeadingTrivia
})
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct PreferNimbleRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "prefer_nimble",
name: "Prefer Nimble",
description: "Prefer Nimble matchers over XCTAssert functions.",
description: "Prefer Nimble matchers over XCTAssert functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("expect(foo) == 1"),

View File

@ -1,7 +1,7 @@
import SwiftSyntax
struct PreferZeroOverExplicitInitRule: SwiftSyntaxCorrectableRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "prefer_zero_over_explicit_init",
@ -34,8 +34,6 @@ struct PreferZeroOverExplicitInitRule: SwiftSyntaxCorrectableRule, OptInRule, Co
]
)
init() {}
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
@ -76,11 +74,12 @@ private extension PreferZeroOverExplicitInitRule {
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
let newNode: MemberAccessExprSyntax = "\(name).zero"
let newNode = MemberAccessExprSyntax(name: "zero")
.with(\.base, "\(raw: name)")
return super.visit(
newNode
.withLeadingTrivia(node.leadingTrivia ?? .zero)
.withTrailingTrivia(node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
)
}
}

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct PrivateOverFilePrivateRule: ConfigurationProviderRule, SwiftSyntaxCorrectableRule {
var configuration = PrivateOverFilePrivateRuleConfiguration()
init() {}
var configuration = PrivateOverFilePrivateConfiguration()
static let description = RuleDescription(
identifier: "private_over_fileprivate",
name: "Private over fileprivate",
description: "Prefer `private` over `fileprivate` declarations.",
name: "Private over Fileprivate",
description: "Prefer `private` over `fileprivate` declarations",
kind: .idiomatic,
nonTriggeringExamples: [
Example("extension String {}"),
@ -150,108 +148,123 @@ private extension PrivateOverFilePrivateRule {
// don't call super in any of the `visit` methods to avoid digging into the children
override func visit(_ node: ExtensionDeclSyntax) -> DeclSyntax {
guard validateExtensions, let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: ClassDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: StructDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: EnumDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: ProtocolDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: FunctionDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: VariableDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
override func visit(_ node: TypealiasDeclSyntax) -> DeclSyntax {
guard let modifier = node.modifiers.fileprivateModifier,
let modifierIndex = node.modifiers.fileprivateModifierIndex,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return DeclSyntax(node)
}
correctionPositions.append(modifier.positionAfterSkippingLeadingTrivia)
let newNode = node.withModifiers(node.modifiers?.replacing(fileprivateModifier: modifier))
let newNode = node.with(\.modifiers, node.modifiers?.replacing(fileprivateModifierIndex: modifierIndex))
return DeclSyntax(newNode)
}
}
}
private extension ModifierListSyntax? {
var fileprivateModifierIndex: ModifierListSyntax.Index? {
self?.firstIndex(where: { $0.name.tokenKind == .keyword(.fileprivate) })
}
var fileprivateModifier: DeclModifierSyntax? {
self?.first { $0.name.tokenKind == .fileprivateKeyword }
fileprivateModifierIndex.flatMap { self?[$0] }
}
}
private extension ModifierListSyntax {
func replacing(fileprivateModifier: DeclModifierSyntax) -> ModifierListSyntax? {
replacing(
childAt: fileprivateModifier.indexInParent,
with: fileprivateModifier.withName(
.privateKeyword(
leadingTrivia: fileprivateModifier.leadingTrivia ?? .zero,
trailingTrivia: fileprivateModifier.trailingTrivia ?? .zero
func replacing(fileprivateModifierIndex: ModifierListSyntax.Index) -> ModifierListSyntax? {
let fileprivateModifier = self[fileprivateModifierIndex]
return replacing(
childAt: self.distance(from: self.startIndex, to: fileprivateModifierIndex),
with: fileprivateModifier.with(
\.name,
.keyword(
.private,
leadingTrivia: fileprivateModifier.leadingTrivia,
trailingTrivia: fileprivateModifier.trailingTrivia
)
)
)

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct RedundantNilCoalescingRule: OptInRule, SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_nil_coalescing",
@ -38,7 +36,8 @@ struct RedundantNilCoalescingRule: OptInRule, SwiftSyntaxCorrectableRule, Config
private extension RedundantNilCoalescingRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: TokenSyntax) {
if node.tokenKind.isNilCoalescingOperator && node.nextToken?.tokenKind == .nilKeyword {
if node.tokenKind.isNilCoalescingOperator,
node.nextToken(viewMode: .sourceAccurate)?.tokenKind == .keyword(.nil) {
violations.append(node.position)
}
}
@ -66,7 +65,7 @@ private extension RedundantNilCoalescingRule {
return super.visit(node)
}
let newNode = node.removingLast().removingLast().withoutTrailingTrivia()
let newNode = node.removingLast().removingLast().with(\.trailingTrivia, [])
correctionPositions.append(newNode.endPosition)
return super.visit(newNode)
}
@ -75,6 +74,6 @@ private extension RedundantNilCoalescingRule {
private extension TokenKind {
var isNilCoalescingOperator: Bool {
self == .spacedBinaryOperator("??") || self == .unspacedBinaryOperator("??")
self == .binaryOperator("??")
}
}

View File

@ -6,14 +6,12 @@ private let attributeNamesImplyingObjc: Set<String> = [
]
struct RedundantObjcAttributeRule: SwiftSyntaxRule, SubstitutionCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_objc_attribute",
name: "Redundant @objc Attribute",
description: "Objective-C attribute (@objc) is redundant in declaration.",
description: "Objective-C attribute (@objc) is redundant in declaration",
kind: .idiomatic,
nonTriggeringExamples: RedundantObjcAttributeRuleExamples.nonTriggeringExamples,
triggeringExamples: RedundantObjcAttributeRuleExamples.triggeringExamples,
@ -42,22 +40,15 @@ struct RedundantObjcAttributeRule: SwiftSyntaxRule, SubstitutionCorrectableRule,
}
private extension AttributeListSyntax {
var hasObjCMembers: Bool {
contains { $0.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("objcMembers") }
}
var objCAttribute: AttributeSyntax? {
lazy
.compactMap { $0.as(AttributeSyntax.self) }
.first { attribute in
attribute.attributeName.tokenKind == .contextualKeyword("objc") &&
attribute.argument == nil
}
.first { $0.attributeNameText == "objc" && $0.argument == nil }
}
var hasAttributeImplyingObjC: Bool {
contains { element in
guard case let .identifier(attributeName) = element.as(AttributeSyntax.self)?.attributeName.tokenKind else {
guard let attributeName = element.as(AttributeSyntax.self)?.attributeNameText else {
return false
}
@ -77,6 +68,15 @@ private extension Syntax {
return false
}
}
var functionOrVariableModifiers: ModifierListSyntax? {
if let functionDecl = self.as(FunctionDeclSyntax.self) {
return functionDecl.modifiers
} else if let variableDecl = self.as(VariableDeclSyntax.self) {
return variableDecl.modifiers
}
return nil
}
}
private extension AttributeListSyntax {
@ -87,10 +87,12 @@ private extension AttributeListSyntax {
if hasAttributeImplyingObjC, parent?.is(ExtensionDeclSyntax.self) != true {
return objcAttribute
} else if parent?.is(EnumDeclSyntax.self) == true {
return nil
} else if parent?.isFunctionOrStoredProperty == true,
let parentClassDecl = parent?.parent?.parent?.parent?.parent?.as(ClassDeclSyntax.self),
parentClassDecl.attributes?.hasObjCMembers == true {
return objcAttribute
parentClassDecl.attributes.contains(attributeNamed: "objcMembers") {
return parent?.functionOrVariableModifiers.isPrivateOrFileprivate == true ? nil : objcAttribute
} else if let parentExtensionDecl = parent?.parent?.parent?.parent?.parent?.as(ExtensionDeclSyntax.self),
parentExtensionDecl.attributes?.objCAttribute != nil {
return objcAttribute

View File

@ -13,7 +13,7 @@ struct RedundantObjcAttributeRuleExamples {
class Foo {
var bar: Any?
@objc
class Bar {
class Bar: NSObject {
@objc
var foo: Any?
}
@ -59,14 +59,15 @@ struct RedundantObjcAttributeRuleExamples {
Example("""
@objcMembers
class Foo {
@objc
class Bar: NSObject {
@objc var foo: Any
@objc var foo: Any?
}
}
"""),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objc class Bar {}
}
"""),
@ -75,6 +76,59 @@ struct RedundantObjcAttributeRuleExamples {
@objc(addElementsObject:)
@NSManaged public func addToElements(_ value: BlockEditorSettingElement)
}
"""),
Example("""
@objcMembers
public class Foo: NSObject {
@objc
private func handler(_ notification: Notification) {
}
func registerForNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(handler(_:)), name: nil, object: nil)
}
}
"""),
Example("""
class Foo: NSObject { }
@objc extension Foo {
@objc enum Bar: Int {
case bar
}
var bar: Bar { .bar }
}
"""),
Example("""
class Foo: NSObject { }
@objc extension Foo {
@objc private enum Baz: Int {
case baz
}
private var baz: Baz { .baz }
}
"""),
Example("""
@objcMembers
internal class Foo: NSObject {
@objc
private var baz: Int = 1
var x: Any? {
value(forKey: "baz")
}
}
"""),
Example("""
@objcMembers
class Foo: NSObject {
@objc enum Bar: Int {
case bar
}
}
""")
]
@ -90,13 +144,13 @@ struct RedundantObjcAttributeRuleExamples {
Example("↓@objc @IBDesignable class Foo {}"),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objc var bar: Any?
}
"""),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objc var bar: Any?
@objc var foo: Any?
@objc
@ -126,7 +180,7 @@ struct RedundantObjcAttributeRuleExamples {
"""),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objcMembers
class Bar: NSObject {
@objc var foo: Any
@ -160,23 +214,23 @@ struct RedundantObjcAttributeRuleExamples {
Example("↓@objc @IBDesignable class Foo {}"): Example("@IBDesignable class Foo {}"),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objc var bar: Any?
}
"""):
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
var bar: Any?
}
"""),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objc var bar: Any?
@objc var foo: Any?
@objc
class Bar {
class Bar: NSObject {
@objc
var foo2: Any?
}
@ -184,11 +238,11 @@ struct RedundantObjcAttributeRuleExamples {
"""):
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
var bar: Any?
var foo: Any?
@objc
class Bar {
class Bar: NSObject {
@objc
var foo2: Any?
}
@ -230,7 +284,7 @@ struct RedundantObjcAttributeRuleExamples {
"""),
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objcMembers
class Bar: NSObject {
@objc var foo: Any
@ -239,7 +293,7 @@ struct RedundantObjcAttributeRuleExamples {
"""):
Example("""
@objcMembers
class Foo {
class Foo: NSObject {
@objcMembers
class Bar: NSObject {
var foo: Any

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct RedundantOptionalInitializationRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_optional_initialization",
name: "Redundant Optional Initialization",
description: "Initializing an optional variable with nil is redundant.",
description: "Initializing an optional variable with nil is redundant",
kind: .idiomatic,
nonTriggeringExamples: [
Example("var myVar: Int?\n"),
@ -96,12 +94,12 @@ struct RedundantOptionalInitializationRule: SwiftSyntaxCorrectableRule, Configur
"""),
Example("""
func foo() {
var myVar: String? = nil
var myVar: String? = nil, b: Int
}
"""):
Example("""
func foo() {
var myVar: String?
var myVar: String?, b: Int
}
""")
]
@ -121,7 +119,7 @@ struct RedundantOptionalInitializationRule: SwiftSyntaxCorrectableRule, Configur
private extension RedundantOptionalInitializationRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: VariableDeclSyntax) {
guard node.letOrVarKeyword.tokenKind == .varKeyword,
guard node.bindingKeyword.tokenKind == .keyword(.var),
!node.modifiers.containsLazy else {
return
}
@ -141,7 +139,7 @@ private extension RedundantOptionalInitializationRule {
}
override func visit(_ node: VariableDeclSyntax) -> DeclSyntax {
guard node.letOrVarKeyword.tokenKind == .varKeyword,
guard node.bindingKeyword.tokenKind == .keyword(.var),
!node.modifiers.containsLazy else {
return super.visit(node)
}
@ -165,24 +163,24 @@ private extension RedundantOptionalInitializationRule {
guard violatingBindings.contains(binding) else {
return binding
}
let newBinding = binding.withInitializer(nil)
if newBinding.accessor == nil {
return newBinding.withTrailingTrivia(binding.initializer?.trailingTrivia ?? .zero)
} else {
let newBinding = binding.with(\.initializer, nil)
if newBinding.accessor != nil {
return newBinding
}
if binding.trailingComma != nil {
return newBinding.with(\.typeAnnotation, binding.typeAnnotation?.with(\.trailingTrivia, Trivia()))
}
return newBinding.with(\.trailingTrivia, binding.initializer?.trailingTrivia ?? Trivia())
})
return super.visit(node.withBindings(newBindings))
return super.visit(node.with(\.bindings, newBindings))
}
}
}
private extension PatternBindingSyntax {
var violationPosition: AbsolutePosition? {
guard let initializer = initializer,
guard let initializer,
let type = typeAnnotation,
initializer.isInitializingToNil,
type.isOptionalType else {

View File

@ -1,15 +1,13 @@
import SwiftSyntax
struct RedundantSetAccessControlRule: ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_set_access_control",
name: "Redundant Set Access Control Rule",
name: "Redundant Access Control for Setter",
description: "Property setter access level shouldn't be explicit if " +
"it's the same as the variable access level.",
"it's the same as the variable access level",
kind: .idiomatic,
nonTriggeringExamples: [
Example("private(set) public var foo: Int"),
@ -82,11 +80,11 @@ private extension RedundantSetAccessControlRule {
return
}
if setAccessor.name.tokenKind == .fileprivateKeyword,
if setAccessor.name.tokenKind == .keyword(.fileprivate),
modifiers.getAccessor == nil,
let closestDeclModifiers = node.closestDecl()?.modifiers {
let closestDeclIsFilePrivate = closestDeclModifiers.contains {
$0.name.tokenKind == .fileprivateKeyword
$0.name.tokenKind == .keyword(.fileprivate)
}
if closestDeclIsFilePrivate {
@ -95,12 +93,12 @@ private extension RedundantSetAccessControlRule {
}
}
if setAccessor.name.tokenKind == .internalKeyword,
if setAccessor.name.tokenKind == .keyword(.internal),
modifiers.getAccessor == nil,
let closesDecl = node.closestDecl(),
let closestDeclModifiers = closesDecl.modifiers {
let closestDeclIsInternal = closestDeclModifiers.isEmpty || closestDeclModifiers.contains {
$0.name.tokenKind == .internalKeyword
$0.name.tokenKind == .keyword(.internal)
}
if closestDeclIsInternal {
@ -144,7 +142,7 @@ private extension DeclSyntax {
private extension ModifierListSyntax {
var setAccessor: DeclModifierSyntax? {
first { $0.detail?.detail.tokenKind == .contextualKeyword("set") }
first { $0.detail?.detail.tokenKind == .identifier("set") }
}
var getAccessor: DeclModifierSyntax? {

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct RedundantStringEnumValueRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_string_enum_value",
name: "Redundant String Enum Value",
description: "String enum values can be omitted when they are equal to the enumcase name.",
description: "String enum values can be omitted when they are equal to the enumcase name",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
@ -73,7 +71,7 @@ private extension RedundantStringEnumValueRule {
return
}
let enumsWithExplicitValues = node.members.members
let enumsWithExplicitValues = node.memberBlock.members
.flatMap { member -> EnumCaseElementListSyntax in
guard let enumCaseDecl = member.decl.as(EnumCaseDeclSyntax.self) else {
return EnumCaseElementListSyntax([])
@ -103,7 +101,7 @@ private extension RedundantStringEnumValueRule {
private extension EnumDeclSyntax {
var isStringEnum: Bool {
guard let inheritanceClause = inheritanceClause else {
guard let inheritanceClause else {
return false
}

View File

@ -2,7 +2,7 @@ import Foundation
import SourceKittenFramework
struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_type_annotation",
@ -110,7 +110,7 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule, Conf
}
func violationRanges(in file: SwiftLintFile) -> [NSRange] {
let violatingRanges = file
return file
.match(pattern: expressionPattern)
.filter {
$0.1 == [.keyword, .identifier, .typeidentifier, .identifier] ||
@ -122,8 +122,6 @@ struct RedundantTypeAnnotationRule: OptInRule, SubstitutionCorrectableRule, Conf
file.match(pattern: typeAnnotationPattern,
excludingSyntaxKinds: SyntaxKind.commentAndStringKinds, range: $0.0).first
}
return violatingRanges
}
private func isFalsePositive(file: SwiftLintFile, range: NSRange) -> Bool {

View File

@ -2,14 +2,12 @@ import Foundation
import SourceKittenFramework
struct RedundantVoidReturnRule: ConfigurationProviderRule, SubstitutionCorrectableASTRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_void_return",
name: "Redundant Void Return",
description: "Returning Void in a function declaration is redundant.",
description: "Returning Void in a function declaration is redundant",
kind: .idiomatic,
nonTriggeringExamples: [
Example("func foo() {}\n"),

View File

@ -1,14 +1,12 @@
import SwiftSyntax
struct ReturnValueFromVoidFunctionRule: ConfigurationProviderRule, OptInRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "return_value_from_void_function",
name: "Return Value from Void Function",
description: "Returning values from Void functions should be avoided.",
description: "Returning values from Void functions should be avoided",
kind: .idiomatic,
minSwiftVersion: .fiveDotOne,
nonTriggeringExamples: ReturnValueFromVoidFunctionRuleExamples.nonTriggeringExamples,

Some files were not shown because too many files have changed in this diff Show More