Compare commits

...

152 Commits
0.51.0 ... 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
605 changed files with 6388 additions and 4310 deletions

View File

@ -5,6 +5,9 @@ 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 \

View File

@ -1 +1 @@
6.1.1
6.2.0

View File

@ -11,11 +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
- bundle exec danger --verbose
- label: "TSan Tests"
commands:
- echo "+++ Test"
- bazel test --test_output=streamed --build_tests_only --features=tsan --test_timeout=1000 //Tests/...
- bazel test --test_output=errors --build_tests_only --features=tsan --test_timeout=1000 //Tests/...
- label: "Sourcery"
commands:
- echo "+++ Run Sourcery"
- make --always-make sourcery
- echo "+++ Diff Files"
- git diff --quiet HEAD

View File

@ -9,7 +9,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3

View File

@ -1,30 +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: macos-12
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Update SwiftSyntax
id: update-swift-syntax
run: ./tools/update-swift-syntax.sh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create PR
if: steps.update-swift-syntax.outputs.needs_update == '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_tag }}...${{ steps.update-swift-syntax.outputs.new_tag }}
commit-message: Update SwiftSyntax
delete-branch: true
branch: update-swift-syntax
branch-suffix: timestamp

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,8 +1,5 @@
/// The rule list containing all available rules built into SwiftLint.
let builtInRules: [Rule.Type] = [
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 %}]
/// The rule list containing all available rules built into SwiftLint as well as native custom rules.
public let primaryRuleList = RuleList(rules: builtInRules + extraRules())

View File

@ -1,14 +1,14 @@
@testable import SwiftLintBuiltInRules
@_spi(TestHelper)
@testable import SwiftLintFramework
@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

@ -35,15 +35,20 @@ disabled_rules:
- 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
@ -60,16 +65,24 @@ 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: ^\s+identifier:\s*("\w+_rule"|"\S*[^a-z_]\S*")
@ -92,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

72
BUILD
View File

@ -13,24 +13,62 @@ load(
# Targets
swift_library(
name = "SwiftLintFramework",
srcs = glob(
["Source/SwiftLintFramework/**/*.swift"],
exclude = ["Source/SwiftLintFramework/Rules/ExcludedFromBazel/ExtraRules.swift"],
) + ["@swiftlint_extra_rules//:extra_rules"],
module_name = "SwiftLintFramework",
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",
"@com_github_apple_swift_syntax//:optlibs",
"@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": [],
"//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"],
),
module_name = "SwiftLintFramework",
visibility = ["//visibility:public"],
deps = [
":SwiftLintBuiltInRules",
":SwiftLintCore",
":SwiftLintExtraRules",
],
)
swift_library(
name = "swiftlint.library",
srcs = glob(["Source/swiftlint/**/*.swift"]),
@ -64,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(
@ -80,9 +133,10 @@ filegroup(
filegroup(
name = "release_files",
srcs = [
"MODULE.bazel",
"BUILD",
"LICENSE",
"MODULE.bazel",
"//:DyldWarningWorkaroundSources",
"//:LintInputs",
"//Tests:BUILD",
"//bazel:release_files",

View File

@ -1,3 +1,243 @@
## 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
@ -11,6 +251,13 @@
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
@ -45,11 +292,6 @@
[SimplyDanny](https://github.com/SimplyDanny)
[#4707](https://github.com/realm/SwiftLint/issues/4707)
* Interpret strings in `excluded` option of `identifier_name`,
`type_name` and `generic_type_name` rules as regex.
[Moly](https://github.com/kyounh12)
[#4655](https://github.com/realm/SwiftLint/pull/4655)
* 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)

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

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.7.3)
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)
@ -61,58 +60,39 @@ GEM
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.13.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,7 +102,7 @@ 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)
@ -130,19 +110,18 @@ GEM
liferaft (0.0.6)
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.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.7)
PLATFORMS
arm64-darwin-21
ruby
arm64-darwin-22
DEPENDENCIES
cocoapods
@ -181,4 +159,4 @@ DEPENDENCIES
jazzy
BUNDLED WITH
2.3.8
2.4.12

View File

@ -1,14 +1,15 @@
module(
name = "swiftlint",
version = "0.51.0",
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.2.0", repo_name = "build_bazel_rules_apple")
bazel_dep(name = "rules_swift", version = "1.7.1", repo_name = "build_bazel_rules_swift")
bazel_dep(name = "rules_xcodeproj", version = "1.3.3")
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")
@ -16,7 +17,7 @@ bazel_dep(name = "yams", version = "5.0.5", repo_name = "sourcekitten_com_github
swiftlint_repos = use_extension("//bazel:repos.bzl", "swiftlint_repos_bzlmod")
use_repo(
swiftlint_repos,
"com_github_apple_swift_syntax",
"SwiftSyntax",
"com_github_johnsundell_collectionconcurrencykit",
"com_github_krzyzanowskim_cryptoswift",
"swiftlint_com_github_scottrhoyt_swifty_text_table",

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
@ -117,6 +121,7 @@ zip_linux_release:
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))
@ -147,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
@ -165,7 +170,7 @@ 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
@ -177,6 +182,11 @@ endif
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,6 +9,15 @@
"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",
@ -32,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "013a48e2312e57b7b355db25bd3ea75282ebf274",
"version" : "0.50900.0-swift-DEVELOPMENT-SNAPSHOT-2023-02-06-a"
"revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5",
"version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a"
}
},
{

View File

@ -1,26 +1,6 @@
// swift-tools-version:5.7
import PackageDescription
#if os(macOS)
private let addCryptoSwift = false
private let binaryPlugin = true
#else
private let addCryptoSwift = true
private let binaryPlugin = false
#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"),
"SwiftyTextTable",
"Yams",
]
+ (addCryptoSwift ? ["CryptoSwift"] : [])
let package = Package(
name: "SwiftLint",
platforms: [.macOS(.v12)],
@ -31,18 +11,20 @@ let package = Package(
],
dependencies: [
.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: "0.50900.0-swift-DEVELOPMENT-SNAPSHOT-2023-02-06-a"),
.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: binaryPlugin ? "SwiftLintBinary" : "swiftlint")
.target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])),
.target(name: "swiftlint", condition: .when(platforms: [.linux]))
]
),
.executableTarget(
@ -61,9 +43,37 @@ 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"),
]
),
.target(
name: "SwiftLintBuiltInRules",
dependencies: ["SwiftLintCore"]
),
.target(
name: "SwiftLintExtraRules",
dependencies: ["SwiftLintCore"]
),
.target(
name: "SwiftLintFramework",
dependencies: [
"SwiftLintBuiltInRules",
"SwiftLintCore",
"SwiftLintExtraRules"
]
),
.target(name: "DyldWarningWorkaround"),
.target(
name: "SwiftLintTestHelpers",
dependencies: [
@ -104,8 +114,8 @@ let package = Package(
),
.binaryTarget(
name: "SwiftLintBinary",
url: "https://github.com/realm/SwiftLint/releases/download/0.51.0/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "9fbfdf1c2a248469cfbe17a158c5fbf96ac1b606fbcfef4b800993e7accf43ae"
url: "https://github.com/realm/SwiftLint/releases/download/0.52.2/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "89651e1c87fb62faf076ef785a5b1af7f43570b2b74c6773526e0d5114e0578e"
)
]
)

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
@ -158,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
@ -236,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
@ -313,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
@ -405,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
@ -554,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:
@ -625,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
@ -182,7 +185,7 @@ $ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint autocorrect
SwiftLint에는 200개가 넘는 룰들이 있고, 스위프트 커뮤니티(바로 여러분들!)는 이를 지속적으로 발전시켜 가고 있습니다. [풀 리퀘스트](CONTRIBUTING.md)는 언제나 환영입니다.
현재 구현된 룰 전체를 확인하려면 [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules)를 살펴보세요.
현재 구현된 룰 전체를 확인하려면 [Source/SwiftLintBuiltInRules/Rules](Source/SwiftLintBuiltInRules/Rules)를 살펴보세요.
`opt_in_rules`는 기본적으로 비활성화되어 있습니다. (즉, 설정 파일에서 명시적으로 해당 룰을 활성화해야 합니다.)

View File

@ -8,16 +8,7 @@ For SwiftLint contributors, follow these steps to cut a release:
* Top Loading
* Fresh Out Of The Dryer
1. Make sure you have the latest stable Xcode version installed and
`xcode-select`ed.
`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. 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,
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`
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

@ -82,8 +82,8 @@ enum LegacyFunctionRuleHelper {
}
return expr
.with(\.leadingTrivia, node.leadingTrivia ?? .zero)
.with(\.trailingTrivia, node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
}
}

View File

@ -1,8 +1,8 @@
// Generated using Sourcery 2.0.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.
let builtInRules: [Rule.Type] = [
public let builtInRules: [Rule.Type] = [
AccessibilityLabelForImageRule.self,
AccessibilityTraitForButtonRule.self,
AnonymousArgumentInMultilineClosureRule.self,
@ -33,7 +33,6 @@ let builtInRules: [Rule.Type] = [
ContainsOverRangeNilComparisonRule.self,
ControlStatementRule.self,
ConvenienceTypeRule.self,
CustomRules.self,
CyclomaticComplexityRule.self,
DeploymentTargetRule.self,
DirectReturnRule.self,
@ -107,7 +106,7 @@ let builtInRules: [Rule.Type] = [
LegacyRandomRule.self,
LetVarWhitespaceRule.self,
LineLengthRule.self,
LiteralExpressionEndIdentationRule.self,
LiteralExpressionEndIndentationRule.self,
LocalDocCommentRule.self,
LowerACLThanParentRule.self,
MarkRule.self,
@ -166,6 +165,7 @@ let builtInRules: [Rule.Type] = [
RedundantNilCoalescingRule.self,
RedundantObjcAttributeRule.self,
RedundantOptionalInitializationRule.self,
RedundantSelfInClosureRule.self,
RedundantSetAccessControlRule.self,
RedundantStringEnumValueRule.self,
RedundantTypeAnnotationRule.self,
@ -179,13 +179,14 @@ let builtInRules: [Rule.Type] = [
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,
@ -203,6 +204,7 @@ let builtInRules: [Rule.Type] = [
TypesafeArrayInitRule.self,
UnavailableConditionRule.self,
UnavailableFunctionRule.self,
UnhandledThrowingTaskRule.self,
UnneededBreakInSwitchRule.self,
UnneededParenthesesInClosureArgumentRule.self,
UnownedVariableCaptureRule.self,
@ -229,6 +231,3 @@ let builtInRules: [Rule.Type] = [
XCTSpecificMatcherRule.self,
YodaConditionRule.self
]
/// The rule list containing all available rules built into SwiftLint as well as native custom rules.
public let primaryRuleList = RuleList(rules: builtInRules + extraRules())

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,9 +1,7 @@
import SwiftSyntax
struct BlockBasedKVORule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "block_based_kvo",
@ -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?.trimmedDescription.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,9 +1,7 @@
import SwiftSyntax
struct ConvenienceTypeRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "convenience_type",
@ -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)
}
}

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)
}

View File

@ -1,9 +1,7 @@
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",

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct DiscouragedObjectLiteralRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = ObjectLiteralConfiguration()
init() {}
var configuration = DiscouragedObjectLiteralConfiguration()
static let description = RuleDescription(
identifier: "discouraged_object_literal",
@ -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,9 +1,7 @@
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",

View File

@ -1,9 +1,7 @@
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",

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,8 +11,6 @@ struct DuplicateImportsRule: ConfigurationProviderRule, CorrectableRule {
"var", "func"
]
init() {}
static let description = RuleDescription(
identifier: "duplicate_imports",
name: "Duplicate Imports",

View File

@ -4,9 +4,7 @@ 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",

View File

@ -1,9 +1,7 @@
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",

View File

@ -2,9 +2,7 @@ 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",

View File

@ -1,9 +1,7 @@
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",
@ -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)
}
}

View File

@ -3,8 +3,6 @@ import SwiftSyntax
struct ExplicitTypeInterfaceRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = ExplicitTypeInterfaceConfiguration()
init() {}
static let description = RuleDescription(
identifier: "explicit_type_interface",
name: "Explicit Type Interface",

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",

View File

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

View File

@ -1,9 +1,7 @@
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",

View File

@ -2,12 +2,7 @@ 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",
@ -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,15 +1,7 @@
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",
@ -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))]
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct ForWhereRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = ForWhereRuleConfiguration()
init() {}
var configuration = ForWhereConfiguration()
static let description = RuleDescription(
identifier: "for_where",

View File

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

View File

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

View File

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

View File

@ -1,9 +1,7 @@
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",
@ -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,7 +123,7 @@ private extension FunctionParameterSyntax {
}
var isEscaping: Bool {
guard let attrType = type?.as(AttributedTypeSyntax.self) else {
guard let attrType = type.as(AttributedTypeSyntax.self) else {
return false
}

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,33 +55,34 @@ 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.shouldExclude(name: 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 '\(name)' should only contain alphanumeric characters",
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 '\(name)' should start with an uppercase character",
severity: .error
severity: caseCheckSeverity
)
)
} else if let severity = configuration.severity(forLength: name.count) {

View File

@ -1,12 +1,7 @@
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",
@ -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,9 +1,7 @@
import SwiftSyntax
struct IsDisjointRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "is_disjoint",

View File

@ -1,9 +1,7 @@
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",

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,9 +2,7 @@ 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",
@ -63,8 +61,8 @@ private extension LegacyConstantRule {
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return ("\(raw: correction)" as ExprSyntax)
.with(\.leadingTrivia, node.leadingTrivia ?? .zero)
.with(\.trailingTrivia, node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
@ -78,8 +76,8 @@ private extension LegacyConstantRule {
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return ("\(raw: calledExpression.identifier.text).pi" as ExprSyntax)
.with(\.leadingTrivia, node.leadingTrivia ?? .zero)
.with(\.trailingTrivia, node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct LegacyConstructorRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_constructor",
@ -167,9 +165,9 @@ 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
.with(\.label, .identifier(args[elem.indexInParent]))
.with(\.label, .identifier(args[index]))
.with(\.colon, .colonToken(trailingTrivia: .space))
})
let newExpression = identifierExpr.with(

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 == .keyword(.var),
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,9 +1,7 @@
import SwiftSyntax
struct LegacyMultipleRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_multiple",

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,9 +1,7 @@
import SwiftSyntax
struct LegacyRandomRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "legacy_random",
@ -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")
]
)

View File

@ -2,9 +2,7 @@ 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",

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,9 +1,7 @@
import SwiftSyntax
struct NoFallthroughOnlyRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "no_fallthrough_only",

View File

@ -1,9 +1,7 @@
import SourceKittenFramework
struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "no_grouping_extension",

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct NoMagicNumbersRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
init() {}
var configuration = SeverityConfiguration(.warning)
var configuration = NoMagicNumbersConfiguration()
static let description = RuleDescription(
identifier: "no_magic_numbers",
@ -44,6 +42,20 @@ struct NoMagicNumbersRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule
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: [
@ -57,20 +69,27 @@ struct NoMagicNumbersRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
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.floatingDigits.isMagicNumber {
if node.isMemberOfATestClass(testParentClasses) == false, node.floatingDigits.isMagicNumber {
violations.append(node.floatingDigits.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: IntegerLiteralExprSyntax) {
if node.digits.isMagicNumber {
if node.isMemberOfATestClass(testParentClasses) == false, node.digits.isMagicNumber {
violations.append(node.digits.positionAfterSkippingLeadingTrivia)
}
}
@ -92,3 +111,19 @@ private extension TokenSyntax {
&& 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,9 +1,7 @@
import SwiftSyntax
struct ObjectLiteralRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = ObjectLiteralConfiguration()
init() {}
var configuration = ObjectLiteralConfiguration<Self>()
static let description = RuleDescription(
identifier: "object_literal",

View File

@ -1,9 +1,7 @@
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",
@ -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,9 +1,7 @@
import SwiftSyntax
struct PreferNimbleRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "prefer_nimble",

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)
}
@ -80,8 +78,8 @@ private extension PreferZeroOverExplicitInitRule {
.with(\.base, "\(raw: name)")
return super.visit(
newNode
.with(\.leadingTrivia, node.leadingTrivia ?? .zero)
.with(\.trailingTrivia, node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
)
}
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct PrivateOverFilePrivateRule: ConfigurationProviderRule, SwiftSyntaxCorrectableRule {
var configuration = PrivateOverFilePrivateRuleConfiguration()
init() {}
var configuration = PrivateOverFilePrivateConfiguration()
static let description = RuleDescription(
identifier: "private_over_fileprivate",
@ -150,110 +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.with(\.modifiers, 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.with(\.modifiers, 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.with(\.modifiers, 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.with(\.modifiers, 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.with(\.modifiers, 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.with(\.modifiers, 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.with(\.modifiers, 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.with(\.modifiers, 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 == .keyword(.fileprivate) }
fileprivateModifierIndex.flatMap { self?[$0] }
}
}
private extension ModifierListSyntax {
func replacing(fileprivateModifier: DeclModifierSyntax) -> ModifierListSyntax? {
replacing(
childAt: fileprivateModifier.indexInParent,
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 ?? .zero,
trailingTrivia: fileprivateModifier.trailingTrivia ?? .zero
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 == .keyword(.nil) {
if node.tokenKind.isNilCoalescingOperator,
node.nextToken(viewMode: .sourceAccurate)?.tokenKind == .keyword(.nil) {
violations.append(node.position)
}
}

View File

@ -6,9 +6,7 @@ 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",
@ -70,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 {
@ -80,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.contains(attributeNamed: "objcMembers") {
return objcAttribute
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,9 +1,7 @@
import SwiftSyntax
struct RedundantOptionalInitializationRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "redundant_optional_initialization",
@ -121,7 +119,7 @@ struct RedundantOptionalInitializationRule: SwiftSyntaxCorrectableRule, Configur
private extension RedundantOptionalInitializationRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: VariableDeclSyntax) {
guard node.letOrVarKeyword.tokenKind == .keyword(.var),
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 == .keyword(.var),
guard node.bindingKeyword.tokenKind == .keyword(.var),
!node.modifiers.containsLazy else {
return super.visit(node)
}
@ -170,9 +168,9 @@ private extension RedundantOptionalInitializationRule {
return newBinding
}
if binding.trailingComma != nil {
return newBinding.with(\.typeAnnotation, binding.typeAnnotation?.with(\.trailingTrivia, .zero))
return newBinding.with(\.typeAnnotation, binding.typeAnnotation?.with(\.trailingTrivia, Trivia()))
}
return newBinding.with(\.trailingTrivia, binding.initializer?.trailingTrivia ?? .zero)
return newBinding.with(\.trailingTrivia, binding.initializer?.trailingTrivia ?? Trivia())
})
return super.visit(node.with(\.bindings, newBindings))

View File

@ -1,9 +1,7 @@
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",
@ -144,7 +142,7 @@ private extension DeclSyntax {
private extension ModifierListSyntax {
var setAccessor: DeclModifierSyntax? {
first { $0.detail?.detail.tokenKind == .keyword(.set) }
first { $0.detail?.detail.tokenKind == .identifier("set") }
}
var getAccessor: DeclModifierSyntax? {

View File

@ -1,9 +1,7 @@
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",
@ -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([])

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",

View File

@ -2,9 +2,7 @@ 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",

View File

@ -1,9 +1,7 @@
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",

View File

@ -1,7 +1,7 @@
import SwiftSyntax
struct ShorthandOptionalBindingRule: OptInRule, SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "shorthand_optional_binding",
@ -79,8 +79,6 @@ struct ShorthandOptionalBindingRule: OptInRule, SwiftSyntaxCorrectableRule, Conf
deprecatedAliases: ["if_let_shadowing"]
)
init() {}
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
@ -96,7 +94,7 @@ struct ShorthandOptionalBindingRule: OptInRule, SwiftSyntaxCorrectableRule, Conf
private class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: OptionalBindingConditionSyntax) {
if node.isShadowingOptionalBinding {
violations.append(node.letOrVarKeyword.positionAfterSkippingLeadingTrivia)
violations.append(node.bindingKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
@ -122,7 +120,7 @@ private class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
let newNode = node
.with(\.initializer, nil)
.with(\.pattern, node.pattern.with(\.trailingTrivia, node.trailingTrivia ?? .zero))
.with(\.pattern, node.pattern.with(\.trailingTrivia, node.trailingTrivia))
return super.visit(newNode)
}
}

View File

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

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct StrictFilePrivateRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "strict_fileprivate",
@ -196,7 +194,7 @@ private extension StrictFilePrivateRule {
return
}
if let varDecl = grandparent.as(VariableDeclSyntax.self) {
let isSpecificForSetter = node.detail?.detail.tokenKind == .keyword(.set)
let isSpecificForSetter = node.detail?.detail.tokenKind == .identifier("set")
let firstImplementingProtocol = varDecl.bindings
.flatMap { binding in
let pattern = binding.pattern

View File

@ -3,9 +3,7 @@ import SourceKittenFramework
import SwiftSyntax
struct SyntacticSugarRule: CorrectableRule, ConfigurationProviderRule, SourceKitFreeRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "syntactic_sugar",
@ -334,7 +332,7 @@ extension SimpleTypeIdentifierSyntax: SyntaxWithGenericClause {
extension SpecializeExprSyntax: SyntaxWithGenericClause {
var typeName: String? {
expression.as(IdentifierExprSyntax.self)?.firstToken?.text ??
expression.as(IdentifierExprSyntax.self)?.firstToken(viewMode: .sourceAccurate)?.text ??
expression.as(MemberAccessExprSyntax.self)?.name.text
}
var genericArguments: GenericArgumentClauseSyntax? { genericArgumentClause }

View File

@ -2,9 +2,7 @@ import SwiftSyntax
import SwiftSyntaxBuilder
struct ToggleBoolRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "toggle_bool",
@ -79,8 +77,8 @@ private extension ToggleBoolRule {
)
.removingLast()
.removingLast()
.with(\.leadingTrivia, node.leadingTrivia ?? .zero)
.with(\.trailingTrivia, node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
return super.visit(newNode)
}

View File

@ -1,9 +1,7 @@
import SwiftSyntax
struct TrailingSemicolonRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration(.warning)
init() {}
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "trailing_semicolon",
@ -66,7 +64,7 @@ private extension TrailingSemicolonRule {
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return .unknown("").with(\.trailingTrivia, node.trailingTrivia ?? .zero)
return .unknown("").with(\.trailingTrivia, node.trailingTrivia)
}
}
}
@ -74,6 +72,9 @@ private extension TrailingSemicolonRule {
private extension TokenSyntax {
var isTrailingSemicolon: Bool {
tokenKind == .semicolon &&
(trailingTrivia.containsNewlines() || (nextToken?.leadingTrivia.containsNewlines() == true))
(
trailingTrivia.containsNewlines() ||
(nextToken(viewMode: .sourceAccurate)?.leadingTrivia.containsNewlines() == true)
)
}
}

View File

@ -2,9 +2,7 @@ import Foundation
import SwiftSyntax
struct TypeNameRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = TypeNameRuleConfiguration()
init() {}
var configuration = TypeNameConfiguration()
static let description = RuleDescription(
identifier: "type_name",
@ -26,9 +24,9 @@ struct TypeNameRule: SwiftSyntaxRule, ConfigurationProviderRule {
private extension TypeNameRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: TypeNameRuleConfiguration
private let configuration: TypeNameConfiguration
init(configuration: TypeNameRuleConfiguration) {
init(configuration: TypeNameConfiguration) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
@ -94,20 +92,18 @@ private extension TypeNameRule {
.strippingBackticks()
.strippingLeadingUnderscoreIfPrivate(modifiers: modifiers)
.strippingTrailingSwiftUIPreviewProvider(inheritedTypes: inheritedTypes)
let allowedSymbols = nameConfiguration.allowedSymbols.union(.alphanumerics)
if !allowedSymbols.isSuperset(of: CharacterSet(charactersIn: name)) {
if !nameConfiguration.allowedSymbolsAndAlphanumerics.isSuperset(of: CharacterSet(charactersIn: name)) {
return ReasonedRuleViolation(
position: identifier.positionAfterSkippingLeadingTrivia,
reason: "Type name '\(name)' should only contain alphanumeric characters",
reason: "Type name '\(name)' should only contain alphanumeric and other allowed characters",
severity: .error
)
} else if nameConfiguration.validatesStartWithLowercase &&
} else if let caseCheckSeverity = nameConfiguration.validatesStartWithLowercase.severity,
name.first?.isLowercase == true {
return ReasonedRuleViolation(
position: identifier.positionAfterSkippingLeadingTrivia,
reason: "Type name '\(name)' should start with an uppercase character",
severity: .error
severity: caseCheckSeverity
)
} else if let severity = nameConfiguration.severity(forLength: name.count) {
return ReasonedRuleViolation(

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