Compare commits

...

1398 Commits

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

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

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

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

* [SwiftSyntax] Update to latest 509.0.0 tag

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

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

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

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

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

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

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

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

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

If built-in rules depend on them.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* New contextual keyword enums

* Update for removed `UnavailabilityConditionSyntax`

* Handle how attributes are now defined

This partially reverts commit 325d0ee1e4.

* Handle removal of `TokenListSyntax`

* Update `Package.swift`

* Extract some SwiftSyntax helpers

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

* Skip attributes with keypath arguments in `attributes` rule

To preserve the rule's existing behavior.

* Limit unowned_variable_capture violations to capture lists

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

* Add examples and changelog

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

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

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

This reverts commit 040096a641.

* Enable all tests when using rules_xcodeproj

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

* Merge `push_version` and `release` make commands

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

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

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

* Add `SwiftLintSourcePlugin` source plugin for SwiftPM

* Add changelog entry

* Remove SwiftLintSourcePlugin for now

* Build from Source on Linux

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

This shouldn’t trigger sandbox violations, I hope…

* Prevent an infinite recursion of the filesystem root

* Remove unnecessary logging

* Quieten the output so that Xcode only prints violations

* Break up comment to avoid line length warning

* Fix capitalization of Glibc import

Co-authored-by: JP Simard <jp@jpsim.com>
2022-11-29 18:10:47 -05:00
github-actions[bot] 9cb1069090
Update SwiftSyntax (#4605)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-11-29 15:30:56 -05:00
JP Simard e405d3d583
Fix `update-swift-syntax.sh` script (#4604) 2022-11-29 15:07:37 -05:00
Steffen Matthischke 97ba82d740
Fix empty_enum_arguments false positive when called expression is an identifier (#4600) 2022-11-28 17:20:34 -05:00
JP Simard d8d5e5bb43
Add empty changelog section 2022-11-28 09:20:39 -05:00
JP Simard 28a4aa2195
release 0.50.1 2022-11-25 11:38:16 -05:00
JP Simard 28e2a1b022
Fix configuration description for some vertical whitespace rules (#4594)
Before: `N/A`
After: `warning, only_enforce_before_trivial_lines: false`
2022-11-25 11:18:41 -05:00
JP Simard c1c5e5f722
Add test cases for https://github.com/realm/SwiftLint/issues/4565 (#4593) 2022-11-25 11:12:48 -05:00
JP Simard 60ad710b7f
Fix `type_name` regression when using backticks (#4592)
Fixes https://github.com/realm/SwiftLint/issues/4571
2022-11-25 10:57:05 -05:00
JP Simard 5a7d3ade02
Lint Plugins directory (#4591) 2022-11-25 15:51:09 +00:00
JP Simard 12c8bb369e
Fix false positives in `unused_closure_parameter` when using backticks (#4590)
Fixes https://github.com/realm/SwiftLint/issues/4588
2022-11-25 07:29:31 -05:00
Tony Arnold f088bbde15
Only lint Swift source files within the provided target (#4406)
* Only lint Swift source files within the provided target

* Restore plugin display name to “SwiftLint”

* Xcode targets don’t always conform to the SourceModuleTarget

Use a “baser” way to get at the Swift sources of the current target

* Use the cache path as the outputFiles

This prevents the warning we’re seeing in Xcode on every build, but shouldn’t interfere with the re-run logic

* Look for configuration files manually in the project directory and parents

* Check if the file is readable, not just that it exists

* Move the Path helper into a separate file

* Fix a wayward apostrophe

Signed-off-by: Tony Arnold <tony@thecocoabots.com>

* Add an entry to the CHANGELOG

Signed-off-by: Tony Arnold <tony@thecocoabots.com>

Signed-off-by: Tony Arnold <tony@thecocoabots.com>
2022-11-24 18:38:41 -05:00
JP Simard e9c1128b86
Move SwiftPM CI job to Buildkite (#4589)
We have 6 CI machines now and these should run faster on bare metal
machines with lots of stuff already cached, like starting with an
existing git repo.
2022-11-24 17:58:09 +00:00
JP Simard 4ccf9eebb4
Fix line count calculation for multiline string literals (#4587)
Fixes https://github.com/realm/SwiftLint/issues/4585

Update body length rule thresholds for SwiftLint
2022-11-24 16:40:51 +00:00
JP Simard f6de471b5f
Fix false positives in `closure_spacing` (#4584)
Fixes https://github.com/realm/SwiftLint/issues/4582
2022-11-24 10:30:40 -05:00
JP Simard 0f68a0a0cb
Fix `update-swift-syntax.sh` (#4586)
I forgot to update this in https://github.com/realm/SwiftLint/pull/4570
2022-11-24 10:26:51 -05:00
JP Simard ac21584224
Fix `minimum_fraction_length` handling in `number_separator` (#4583)
Fixes https://github.com/realm/SwiftLint/issues/4576

Before it would apply the `minimum_length` parameter to the
`minimal_fractional_length` setting if the latter wasn't set.
2022-11-24 14:19:20 +00:00
Steffen Matthischke 907c80f84c
Fix lower_acl_than_parent false positives when the nominal parent is an extension (#4575) 2022-11-24 08:08:23 -05:00
JP Simard fd502b4526
Add new `local_doc_comment` rule (#4581)
Moving the validation of doc comments in local scopes out of
`orphaned_doc_comment` and into a new opt-in `local_doc_comment` rule.

Addresses https://github.com/realm/SwiftLint/issues/4573.
2022-11-23 17:50:18 -05:00
JP Simard a6c4ea9614
Makefile: use bazel in more places (#4580)
Previously, it took a very long time to run `make release` since it had
to clean build everything.

With bazel, I'm more confident in incremental builds being solid, so it
now just takes a few seconds if there's anything cached, which is often
the case.
2022-11-23 21:41:28 +00:00
JP Simard 571ad33ceb
Add `universal_swiftlint` universal macOS binary (#4579)
With architectures for x86_64 and arm64 for portable distribution.
2022-11-23 11:33:38 -05:00
JP Simard 6af9175386
Update swift-argument-parser to 1.2.0 (#4572) 2022-11-21 15:33:00 +00:00
JP Simard fe4ec3521e
Update `Package.swift` to `swift-tools-version:5.7` (#4570)
We already require Swift 5.7 as of SwiftLint 0.50.0.
2022-11-21 15:14:25 +00:00
JP Simard 1dbde3d9c3
Update SourceKitten to 0.33.1 (#4569)
To make SwiftPM happy about the package being set to a stable release.
2022-11-21 09:52:23 -05:00
github-actions[bot] cc49e82348
Update SwiftSyntax (#4567)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-11-21 09:15:01 -05:00
JP Simard 4408250920
Fix building with `swift build -c release` (#4563)
Which previously tried to build the SwiftLintTestHelpers module,
which is a test-only module.

This should fix building with precommit and Mint, both of which assume
you can build the CLI targets in a Swift package with the
`swift build -c release` command.
2022-11-20 20:59:39 +00:00
JP Simard 85e59c706a
Disable `prefer_self_in_static_references` in SwiftLint (#4557)
I find this rule to not help readability for this project at least,
where `Version(value: "0.50.0")` is a lot more descriptive than
`Self(value: "0.50.0")`.
2022-11-19 09:23:55 -05:00
JP Simard cdd891a4a2
release 0.50.0 2022-11-18 14:43:44 -05:00
JP Simard e5b1944ae6
Reorder changelog entries 2022-11-18 14:43:21 -05:00
github-actions[bot] cd291b043a
Update SwiftSyntax (#4556) 2022-11-18 14:41:07 -05:00
JP Simard 8cdbb50cbf
Update rules_xcodeproj 2022-11-16 16:22:25 -05:00
JP Simard ba8899714d
Reduce visibility of custom rules (#4553) 2022-11-16 16:14:50 -05:00
JP Simard 4f652a68e7
Move XCTestHelpers to TestCaseAccessibilityRule.swift (#4552)
it's only used in that file
2022-11-16 14:31:00 -05:00
JP Simard 953ee620f7
Refactor ExecutableInfo (#4551)
To improve how it renders in jazzy-generated docs.
2022-11-16 14:07:39 -05:00
JP Simard 18f9a0e3a6
Write some docs for internal APIs (#4550)
These should be useful when writing rules, but also may become public
API in the future.
2022-11-16 13:58:55 -05:00
JP Simard 0362cd07b8
Fix jazzy CodeClimateReporter capitalization (#4549) 2022-11-16 13:16:05 -05:00
github-actions[bot] 9d2ec3dc8d
Update SwiftSyntax (#4547)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-11-13 19:35:15 -05:00
JP Simard 04d1184904
Remove structure cache (#4541) 2022-11-10 14:53:16 -05:00
JP Simard 4bd7da32ea
Reduce visibility of rules to be `internal` (#4533)
There's no reason to expose these publicly and this will make it nicer
to move to a new module outside of the core SwiftLint functionality.
2022-11-09 11:01:26 -05:00
JP Simard 901f05cd4f
Update rules_apple to 1.1.3 (#4537) 2022-11-09 10:59:52 -05:00
JP Simard ca0813c605
Update Bazel to 5.3.2 (#4536)
Latest stable release: https://github.com/bazelbuild/bazel/releases/tag/5.3.2
Run OSSCheck if `.bazelversion` changes
2022-11-09 10:47:55 -05:00
github-actions[bot] ac7833aaf4
Update SwiftSyntax (#4535)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-11-08 23:01:13 -05:00
github-actions[bot] 5fceb213d9
Update SwiftSyntax (#4529)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-11-08 10:24:02 -05:00
JP Simard 2928dab4ec
Fix running update-swift-syntax.sh locally 2022-11-08 10:05:45 -05:00
JP Simard 0c828e35fb
Improve automated Swift Syntax update PR messages 2022-11-08 09:52:20 -05:00
Danny Mösch 3864ecc12f
Fix indentation in error message (#4528) 2022-11-07 14:47:14 -05:00
github-actions[bot] fe141cd3b6
Update SwiftSyntax (#4527)
Diff: e1f771ea8a...4fa6e6b0ff
2022-11-07 10:42:36 -05:00
Marcelo Fabri eaf7db1250
Rewrite `object_literal` rule with SwiftSyntax (#4525) 2022-11-06 20:42:00 -08:00
Marcelo Fabri 6c7e2107ae
Rewrite `nslocalizedstring_key` with SwiftSyntax (#4523) 2022-11-06 19:12:53 -08:00
Danny Mösch 1edef5ebdc
Trigger `prefer_self_in_static_references` rule on constructor calls (#4519) 2022-11-06 14:55:28 +01:00
Danny Mösch 7e8a3ae2ac
Introduce `onlyElement` property on `Collection` (#4518) 2022-11-06 07:37:44 -05:00
Marcelo Fabri 45ac3dcdff
Rewrite `required_enum_case` with SwiftSyntax (#4521) 2022-11-06 01:26:11 -08:00
Marcelo Fabri 1c675bc993
Rewrite `balanced_xctest_lifecycle` with SwiftSyntax (#4520) 2022-11-06 00:05:32 -07:00
Marcelo Fabri fc0c0c7f5b
Rewrite `pattern_matching_keywords` with SwiftSyntax (#4490) 2022-11-05 23:16:59 -07:00
Marcelo Fabri 22522254df
Validate shorthand option binding in `self_binding` rule (#4514)
* Validate shorthand option binding in `self_binding` rule

* Fix CHANGELOG
2022-11-05 21:32:09 -07:00
Danny Mösch 9a706ba371
Trigger `prefer_self_in_static_references` rule in computed property blocks (#4517) 2022-11-06 00:19:48 +01:00
Danny Mösch d4ea19e434
Trigger `prefer_self_in_static_references` rule on key paths (#4516) 2022-11-05 13:39:27 +01:00
Danny Mösch eb3d502ad7
Rephrase rule description letting it no longer refer to classes only (#4515) 2022-11-05 07:13:24 -04:00
Danny Mösch 65874dc40f
Rewrite `prefer_self_in_static_references` with SwiftSyntax (#4504) 2022-11-05 11:46:33 +01:00
JP Simard 759408fdb5
Update SwiftSyntax (#4506)
This update pulls in https://github.com/apple/swift-syntax/pull/1050,
which fixes a memory leak, reducing memory usage by up to 3x and
improves lint times by 20%-50% in my tests.
2022-11-04 06:05:38 -04:00
Craig Siemens ec5124d939
Rewrite `multiline_arguments_brackets` with SwiftSyntax (#4512)
Fix false-positives when a function call has a single line closure.
2022-11-03 21:57:27 -04:00
JP Simard 05e06d1945
Allow passing a commit to `update-swift-syntax.sh` (#4509)
E.g.

```console
$ ./tools/update-swift-syntax.sh e19c5f2909127ce4537d6f8981919aba4645ce4e
```
2022-11-03 16:05:09 -04:00
John Szumski 6fcdd8077f
Adds NSError to the list of types in discouraged_direct_init. (#4508) 2022-11-03 13:52:30 -04:00
Danny Mösch 32152646f3
Use `Self` in constructor calls (#4505) 2022-11-02 22:50:22 +00:00
JP Simard e97119efec
Migrate `orphaned_doc_comment` to use SwiftSyntax classifications (#4461) 2022-11-02 15:55:47 +00:00
JP Simard fce8283843
Fix & clean up Dockerfile (#4502)
We no longer need `_InternalSwiftSyntaxParser`, but we do need
`libswiftCore.so`.

Fixes https://github.com/realm/SwiftLint/issues/4501

Add a more useful validation test at the end of the Dockerfile.
In addition to running `swiftlint version`, also actually run the linter
which will exercise the SourceKit codepaths.
2022-11-02 10:28:55 -04:00
JP Simard f1f6a3c4a0
Add `ByteSourceRange.toSourceKittenByteRange()` helper (#4500)
This will be useful for other rules too.
2022-11-01 14:13:29 -04:00
César Pinto Castillo c56e19a0c2
Fix SwiftLint support on Xcode Cloud (#4485)
Fixes #4484 by checking the process environment for all the expected
environment variables set by Xcode Cloud.
2022-11-01 13:00:50 -04:00
JP Simard 3800ad32bf
Sort list of rules migrated to SwiftSyntax in changelog (#4499) 2022-10-31 13:07:53 -04:00
JP Simard 79e3c8bd4a
Add special handling for https://github.com/apple/swift/issues/61817 (#4498) 2022-10-31 09:58:36 -04:00
github-actions[bot] 6ad4a704f5
Update SwiftSyntax (#4497) 2022-10-31 09:49:40 -04:00
Marcelo Fabri 20bfe264f5
Rewrite `overridden_super_call` and `prohibited_super_call` with SwiftSyntax (#4493)
* Rewrite `overridden_super_call` with SwiftSyntax

* Rewrite `prohibited_super_call` too
2022-10-30 20:28:25 -07:00
Marcelo Fabri 697eaa73dd
Rewrite `private_subject` rule with SwiftSyntax (#4495) 2022-10-30 18:41:57 -07:00
Marcelo Fabri 5144cccb57
Revert "[OSSCheck] Cache repos (#4456) (#4477)" (#4494)
This reverts commit 6b5352feac.
2022-10-30 17:46:53 -07:00
Marcelo Fabri 98e9c2f1f4
Fix SwiftVersionTests when using Xcode 14.2 (#4492) 2022-10-30 19:50:49 -04:00
Henry 63c043664d
Add new `no_magic_numbers` rule (#4265) 2022-10-30 15:28:20 +01:00
JP Simard a18436d4d6
Rewrite `optional_enum_case_matching` with SwiftSyntax (#4488) 2022-10-28 19:30:33 +00:00
JP Simard a5c44605af
Update to rules_xcodeproj 0.10.0 (#4486)
Mostly has optimizations: https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/0.10.0
2022-10-28 14:17:03 -04:00
JP Simard b7f621c239
Make `update-swift-syntax.sh` script portable (#4487) 2022-10-28 14:16:48 -04:00
JP Simard d551cb8c16
Update SwiftSyntax (#4480)
Moves syntax classifications to a new IDEUtils module.
2022-10-28 09:23:06 -04:00
JP Simard 1b59a3f168
Cache location converters (#4481)
This is 2%-12% faster according to OSSCheck
2022-10-26 12:37:16 -04:00
JP Simard 6b5352feac
[OSSCheck] Cache repos (#4456) (#4477)
This should speed up OSSCheck runs considerably.

In my local testing, cloning repos goes from 77s to 29s on a 100 Mbps
connection.
2022-10-26 10:58:23 -04:00
JP Simard 9a305dd2e6
Update CI setup instructions (#4479) 2022-10-26 10:25:06 -04:00
github-actions[bot] 7738f0c0a5
Update SwiftSyntax (#4476)
Co-authored-by: jpsim <jpsim@users.noreply.github.com>
2022-10-24 17:10:17 -04:00
JP Simard 374130bb56
Update SwiftSyntax on a weekly scheduled CI job (#4475) 2022-10-24 16:37:29 -04:00
Marcelo Fabri d37465ad37
Rewrite `vertical_parameter_alignment` with SwiftSyntax (#4466)
* Rewrite `vertical_parameter_alignment` rule with SwiftSyntax

* Validate inits
2022-10-24 12:56:48 -07:00
Marcelo Fabri 50c85ef5c1
Rewrite `explicit_top_level_acl` with SwiftSyntax (#4450) 2022-10-24 11:31:12 -07:00
Marcelo Fabri fa6db3cca7
Rewrite `collection_alignment` rule with SwiftSyntax (#4472) 2022-10-24 10:51:31 -07:00
JP Simard 96925d480e
Revert "[OSSCheck] Cache repos (#4456)" (#4473)
This reverts commit f0f46a45eb.

This might need more error handling / recovery:
https://github.com/realm/SwiftLint/pull/4456#issuecomment-1288792588
2022-10-24 06:26:52 -04:00
Marcelo Fabri 31ea58381c
Add example for #3558 (#4471)
Fixes #3558
2022-10-24 06:14:30 -04:00
Marcelo Fabri 95838aa230
Add example for #2008 (#4470)
Fixes #2008
2022-10-24 05:32:56 -04:00
Marcelo Fabri f8d505a225
Add example for #3945 (#4469)
Fixes #3945
2022-10-24 09:23:37 +00:00
Marcelo Fabri 7a8de1c966
Add example for #2782 (#4468)
Fixes #2782
2022-10-24 09:22:31 +00:00
Marcelo Fabri 7a3d0d55a0
Add example for #3022 (#4467)
Fixes #3022
2022-10-24 08:56:23 +00:00
Marcelo Fabri 1c6b6c67e0
Rewrite `duplicated_key_in_dictionary_literal` with SwiftSyntax (#4396) 2022-10-23 23:11:17 -07:00
Marcelo Fabri 87bebb6744
Rewrite `test_case_accessibility` with SwiftSyntax (#4446) 2022-10-23 17:39:45 -07:00
Marcelo Fabri 7f5b189c1f
Rewrite `override_in_extension` with SwiftSyntax (#4463) 2022-10-23 17:38:40 -07:00
Marcelo Fabri c1f2b615e2
Rewrite `redundant_optional_initialization` with SwiftSyntax (#4409) 2022-10-23 20:30:29 -04:00
Marcelo Fabri 5d1906456b
Rewrite `xct_specific_matcher` with SwiftSyntax (#4462) 2022-10-23 19:17:29 -04:00
Marcelo Fabri 53752f58ad
Rewrite `redundant_set_access_control` with SwiftSyntax (#4395) 2022-10-23 15:30:01 -07:00
Marcelo Fabri c98ffcc940
Rewrite `convenience_type` rule with SwiftSyntax (#4452) 2022-10-23 15:28:55 -07:00
Marcelo Fabri 351c8be2e0
Rewrite `return_arrow_whitespace` with SwiftSyntax (#4413) 2022-10-23 15:06:14 -07:00
JP Simard cb79584c7d
Migrate `comment_spacing` to use SwiftSyntax classifications (#4460) 2022-10-23 17:39:38 -04:00
Marcelo Fabri def404259f
Add more repos to oss-check (#4453) 2022-10-23 14:21:02 -07:00
JP Simard de7996f5c7
Rewrite `discarded_notification_center_observer` with SwiftSyntax (#4459) 2022-10-23 20:35:09 +00:00
JP Simard b4f45aa55e
Move TSan Runs CI job to Buildkite (#4457)
Now that we have more Buildkite machines, these should be faster than
running on Azure Pipelines.

Also remove the `//bazel:xcode_config` configurations since they should
no longer be in use.
2022-10-23 13:05:28 -04:00
JP Simard f0f46a45eb
[OSSCheck] Cache repos (#4456)
This should speed up OSSCheck runs considerably.

In my local testing, cloning repos goes from 77s to 29s on a 100 Mbps
connection.
2022-10-23 12:20:11 -04:00
JP Simard 1ee5154687
Update SwiftSyntax to `fa7ff05` (#4455)
There's a new SwiftParserDiagnostics module and the rewriter visit
function signatures changed.
2022-10-23 11:56:22 -04:00
JP Simard 401d0f7929
Update SwiftSyntax to `60c7037` (#4454)
This has changes to how comments are associated to nodes.

See https://github.com/apple/swift-syntax/pull/985
2022-10-23 11:15:27 -04:00
Marcelo Fabri 25a04e8eeb
Migrate `inclusive_language` rule to SwiftSyntax (#4390) 2022-10-23 14:00:40 +00:00
Marcelo Fabri 0bd9e4e65f
Rewrite `unused_optional_binding` with SwiftSyntax (#4449) 2022-10-23 06:13:54 -07:00
Marcelo Fabri 60054da0f7
Rewrite `prefer_self_type_over_type_of_self` with SwiftSyntax (#4451) 2022-10-23 06:06:16 -07:00
Marcelo Fabri 35fcf55198
Rewrite `reduce_into` rule with SwiftSyntax (#4447) 2022-10-23 07:58:48 -04:00
Marcelo Fabri cee4af098f
Migrate `prefer_zero_over_explicit_init` to SwiftSyntax (#4448) 2022-10-23 04:53:00 -07:00
Marcelo Fabri 9c8708bc01
Extract common SwiftSyntax extensions (#4445) 2022-10-23 00:54:18 -07:00
Marcelo Fabri 7b1099a33d
Rewrite `prefixed_toplevel_constant` with SwiftSyntax (#4425) 2022-10-21 13:11:40 -07:00
JP Simard 359699cea7
Report memory usage when `--benchmark` is specified (#4442)
With the memory increase related to
https://github.com/apple/swift-syntax/issues/921,
I wanted a way to quickly know how much memory was being used by
SwiftLint.

Here's how much memory it took to lint SwiftLint itself at various
versions in the last few weeks:

* 0.49.1: 223 MB
* 0.50.0-rc.1: 356 MB
* 0.50.0-rc.2: 444 MB
* main (458916174): 464 MB

```console
$ swiftlint --progress --benchmark
Linting Swift files in current working directory
529 of 529 [==============================] ETA: 0s (121 files/s)
Done linting! Found 0 violations, 0 serious in 529 files.
Memory used: 464 MB
$ swiftlint --progress --benchmark
Linting Swift files in current working directory
529 of 529 [==============================] ETA: 0s (16220 files/s)
Done linting! Found 0 violations, 0 serious in 529 files.
Memory used: 55.8 MB
```
2022-10-21 19:04:43 +00:00
JP Simard 4589161742
Rewrite `redundant_objc_attribute` with SwiftSyntax (#4441) 2022-10-21 18:28:21 +00:00
JP Simard 5af8e3dd68
Rewrite `lower_acl_than_parent` with SwiftSyntax (#4432)
And fix violations in SwiftLint.
2022-10-21 09:31:10 -04:00
Marcelo Fabri 1fb04902c0
Rewrite `multiline_parameters` rule with SwiftSyntax (#4438) 2022-10-21 09:08:27 +00:00
Marcelo Fabri 0dfc7a85b5
Rewrite `required_deinit` rule with SwiftSyntax (#4439) 2022-10-21 08:33:54 +00:00
Marcelo Fabri a4fbec355c
Validate protocols in `type_name` rule (#4433)
Fixes #4430
2022-10-21 00:11:18 -07:00
Marcelo Fabri 8f3a23e1a9
[oss-check] Add Pocket-Casts (#4436) 2022-10-20 19:04:43 -07:00
Marcelo Fabri ead4ca9b56
Revert "Add Automattic/pocket-casts-ios to oss-check (#4434)" (#4435)
This reverts commit 2d76e43068.
2022-10-20 18:54:10 -07:00
Marcelo Fabri 9f4b2c37ba
Rewrite `for_where`, adding `allow_for_as_filter` config (#4154) 2022-10-20 18:47:31 -07:00
Marcelo Fabri f509998ec1
Rewrite `empty_count` with SwiftSyntax (#4426) 2022-10-20 16:52:30 -07:00
Marcelo Fabri 2d76e43068
Add Automattic/pocket-casts-ios to oss-check (#4434) 2022-10-20 16:51:44 -07:00
JP Simard e84430f222
Update SwiftSyntax (#4431) 2022-10-20 13:16:00 -04:00
Marcelo Fabri 469a3aa87a
Rewrite `type_name` rule with SwiftSyntax (#4428) 2022-10-20 09:22:39 -07:00
Marcelo Fabri 59ad84f6e9
Add ns_number_init_as_function_reference rule (#4414) 2022-10-20 09:15:17 -07:00
Marcelo Fabri fd722892e5
Rewrite `notification_center_detachment` with SwiftSyntax (#4422) 2022-10-20 09:14:51 -07:00
Marcelo Fabri c46fd55711
Migrate `file_name` rule to SwiftSyntax (#4423) 2022-10-20 09:14:08 -07:00
Marcelo Fabri 2929e35183
Rewrite `single_test_class` rule with SwiftSyntax (#4424) 2022-10-20 09:13:23 -07:00
Marcelo Fabri 533917dced
Rewrite `raw_value_for_camel_cased_codable_enum` with SwiftSyntax (#4427) 2022-10-20 08:23:32 -07:00
JP Simard 25c9d34f5a
Update SwiftSyntax (#4429) 2022-10-20 09:21:14 -04:00
Marcelo Fabri d11dc2b321
Add changelog for https://github.com/realm/SwiftLint/pull/4421 2022-10-19 23:24:16 -07:00
Marcelo Fabri 62c8985a3e
Make `Quick*` rules more permissive (#4421)
Fixes #4420
2022-10-19 16:08:35 -07:00
JP Simard 230688848e
Update CI docs (#4419)
To reflect the need to install `bazelisk`.
2022-10-19 14:14:47 +00:00
JP Simard eb8971a933
Update CI docs (#4418)
Needs the `HOME` environment variable to bet set with some machines.
2022-10-19 09:10:36 -04:00
JP Simard 016831d471
Update CI machine setup instructions (#4416) 2022-10-19 07:49:18 -04:00
Marcelo Fabri 93b016bca3
Migrate `unavailable_function` to SwiftSyntax (#4387) 2022-10-18 20:19:27 -07:00
Marcelo Fabri bf716d7089
Rewrite `unused_capture_list` with SwiftSyntax (#4412) 2022-10-18 20:16:39 -07:00
Marcelo Fabri d3274565a1
Migrate `compiler_protocol_init` rule to SwiftSyntax (#4392) 2022-10-18 20:14:00 -07:00
Marcelo Fabri 04d7ce05ca
Rewrite `joined_default_parameter` with SwiftSyntax (#4411) 2022-10-18 20:12:56 -07:00
Marcelo Fabri bda8487ed2
Rewrite `prefer_nimble` rule with SwiftSyntax (#4410) 2022-10-18 01:42:08 -07:00
Danny Mösch a8bc9e9b42
Let more rules rely on SwiftSyntaxRule's defaults (#4401) 2022-10-18 02:23:39 -04:00
Marcelo Fabri 286e59a0e6
Fix false positive in `nsobject_prefer_isequal` rule (#4408)
Fixes #4404
2022-10-17 22:26:37 -07:00
Marcelo Fabri db910946dc
Simplift `DiscouragedNoneNameRule` implementation (#4407) 2022-10-18 04:43:40 +00:00
JP Simard 1837ae59cb
Rewrite `legacy_objc_type` with SwiftSyntax (#4372) 2022-10-17 17:29:09 -04:00
Marcelo Fabri 03848ce583
Make `DiscouragedNoneNameRule` opt-in again (#4403)
I mistakenly made it enable by default when rewriting it
2022-10-17 17:01:42 -04:00
JP Simard e9f2248072
Remove dead code in `DiscouragedDirectInitRule.swift` (#4402) 2022-10-17 18:25:02 +00:00
Marcelo Fabri 9a9629c1e8
Rewrite `discouraged_direct_init` with SwiftSyntax (#4397) 2022-10-17 10:47:46 -07:00
JP Simard 1b86aa7eeb
Simplify `SwitchCaseAlignmentRule` (#4399)
By using `ReasonedRuleViolation`, `SwiftSyntaxRule` and `makeVisitor()`.
2022-10-17 10:59:07 -04:00
JP Simard 8ec6e0eefc
Update SwiftSyntax (#4398)
https://github.com/apple/swift-syntax/pull/938 was impacting some
corrections in Lyft's codebase.
2022-10-17 09:42:02 -04:00
Marcelo Fabri 937228d1ba
Add `function_parameter_count` to CHANGELOG 2022-10-17 00:44:43 -07:00
Marcelo Fabri 0504d2c3f9
Migrate `function_parameter_count` to SwiftSyntax (#4394) 2022-10-17 00:44:17 -07:00
Marcelo Fabri 07be57027a
Add more rewritten rules to CHANGELOG 2022-10-16 23:55:42 -07:00
Marcelo Fabri 844b7c02dd
Rewrite `trailing_comma` rule with SwiftSyntax (#4385) 2022-10-16 23:36:11 -07:00
Marcelo Fabri b4ec2d360d
Rewrite `unused_control_flow_label` with SwiftSyntax (#4339) 2022-10-16 22:58:01 -07:00
Marcelo Fabri 89c227ecaa
Migrate `weak_delegate` rule to SwiftSyntax (#4389)
* Migrate `weak_delegate` rule to SwiftSyntax

* Remove unused declarations
2022-10-16 22:57:42 -07:00
Marcelo Fabri 6f4b75b0f6
Migrate `legacy_constructor` to SwiftSyntax (#4386) 2022-10-16 22:56:25 -07:00
Marcelo Fabri 4522005ab4
Migrate `implicitly_unwrapped_optional` to SwiftSyntax (#4278)
* Migrate `implicitly_unwrapped_optional` to SwiftSyntax

* Update Source/SwiftLintFramework/Rules/RuleConfigurations/ImplicitlyUnwrappedOptionalConfiguration.swift

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>

* Fix after rebase

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>
2022-10-16 22:55:32 -07:00
Marcelo Fabri 56a23448c3
Migrate `unused_enumerated` to SwiftSyntax (#4391) 2022-10-16 22:34:26 -07:00
Marcelo Fabri bb1de21059
Convert `enum_case_associated_values_count` to SwiftSyntax (#4393) 2022-10-16 22:34:12 -07:00
Marcelo Fabri 89c24cd52d
Rewrite `fatal_error_message` rule with SwiftSyntax (#4230) 2022-10-16 20:52:09 -04:00
Danny Mösch 0fbd03cf2b
Require visitors to exist (#4383) 2022-10-16 18:40:12 +02:00
Marcelo Fabri 8b96aa0585
Make UnavailableConditionRule conform to SwiftSyntaxRule (#4388) 2022-10-16 07:49:36 -07:00
Marcelo Fabri 7ff3094821
Support .focused() in keys for corrections (#4384) 2022-10-16 07:50:10 -04:00
Danny Mösch f8e5339c69
Introduce `ReasonedRuleViolation` type to associate a reason with a violation position (#4379) 2022-10-16 12:53:38 +02:00
Marcelo Fabri 9959f971f9
Add way to preprocess syntaxTree in SwiftSyntaxRule (#4381)
* Add way to preprocess syntaxTree in SwiftSyntaxRule

* Update Source/SwiftLintFramework/Protocols/SwiftSyntaxRule.swift

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>

* Update Source/SwiftLintFramework/Protocols/SwiftSyntaxRule.swift

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>

Co-authored-by: Danny Mösch <danny.moesch@icloud.com>
2022-10-16 01:40:02 -07:00
Danny Mösch dcf03f5987
Fix compilation errors (#4380) 2022-10-15 22:49:16 -04:00
Marcelo Fabri 860b027005
Migrate `private_over_fileprivate` to SwiftSyntax (#4376) 2022-10-15 14:49:16 -07:00
Marcelo Fabri 4aa9588454
Rewrite `function_default_parameter_at_end` with SwiftSyntax (#4320)
* Rewrite `function_default_parameter_at_end` with SwiftSyntax

* Fix oss-check issues

* Handle optional closures

* Handle other closure types

* Fix violation

* Handle @autoclosure
2022-10-15 14:48:59 -07:00
Marcelo Fabri 37bf2c9168
Rewrite `discouraged_none_name` with SwiftSyntax (#4377)
* Rewrite `discouraged_none_name` with SwiftSyntax

* Handle `none`
2022-10-15 14:48:38 -07:00
Danny Mösch bd8c9e5bcb
Provide syntax visitor base class allowing for convenient skipping of declaration nodes (#4310) 2022-10-15 19:03:49 +02:00
Marcelo Fabri 510cb39b11
Rewrite `quick_discouraged_pending_test` with SwiftSyntax (#4378) 2022-10-15 04:21:38 -07:00
Marcelo Fabri c9ef157c29
Rewrite `conditional_returns_on_newline` with SwiftSyntax (#4340)
* Rewrite `conditional_returns_on_newline` with SwiftSyntax

* Keep original behavior

* PR feedback
2022-10-15 02:25:56 -07:00
Marcelo Fabri e74e11533c
Rewrite `valid_ibinspectable` rule with SwiftSyntax (#4322)
* Rewrite `valid_ibinspectable` rule with SwiftSyntax

* Fix false positives
2022-10-14 20:32:03 -07:00
Danny Mösch a7ff8a8d76
Rename `if_let_shadowing` rule to `shorthand_optional_binding` (#4334) 2022-10-14 21:47:37 +00:00
JP Simard 7585aef910
Rewrite `reduce_boolean` with SwiftSyntax (#4375) 2022-10-14 07:03:30 -04:00
JP Simard f04e28cbf8
Rewrite `switch_case_alignment` with SwiftSyntax (#4373) 2022-10-14 10:06:54 +00:00
JP Simard 39bb05f7d1
Rewrite "body length" rules with SwiftSyntax (#4370)
- `closure_body_length`
- `function_body_length`
- `type_body_length`
2022-10-14 03:50:39 -04:00
JP Simard 7624059caa
Rewrite `unused_closure_parameter` with SwiftSyntax (#4371) 2022-10-14 03:35:51 -04:00
JP Simard fa6bf50a22
Rethink body line count calculation (#4369)
A long-standing limitation with SourceKit's "editor open" request is
that we weren't able to get certain tokens, such as braces, brackets and
parentheses.

This meant that this code block would be counted as two lines:

```swift
print(
  "hi"
)
```

because the trailing `)` would be treated as a whitespace line.

This meant that our "body length" family of rules that measure the
effective line count of declarations like functions, types or closures
would often significantly under-count the number of content lines in a
body.

Now with SwiftSyntax, we can get all tokens, including the ones
SourceKit was previously ignoring, so we can get much more accurate line
counts when ignoring whitespace and comments.

In addition, we weren't very thorough in how we measured body length.

As an exercise, how many lines long would you say the body of this
function is?

```swift
func hello() {
  print("hello")
}
```

Does the body span one line or three lines?

I propose that we consistently ignore the left and right brace lines
when calculating the body line count of these scopes so that we measure
body line counts like this:

```swift
// 1 line
{ print("foo") }
// 1 line
{
}
// 1 line
{
  print("foo")
}
// 2 lines
{
  let sum = 1 + 2
  print(sum)
}
```

Now with those changes in place, in order to keep the default
configuration thresholds to similar levels as before, we need to adjust
them slightly. Here's what I'm suggesting:

|Rule|Before|After|
|-|-|-|
|closure_body_length|20/100|30/100|
|function_body_length|40/100|50/100|
|type_body_length|200/350|250/350|

This is a pretty significant breaking change and I suspect we'll hear
from users who are surprised that some of their declarations now exceed
the rule limits, but I believe this new approach to calculating body
lines is more correct and intuitive compared to what we've had until
now.

OSSCheck is also going to report a bazillion changes with this, which is
expected given the scope of this change.
2022-10-14 03:16:26 -04:00
JP Simard 5c3d4c1dab
Rewrite `legacy_hashing` with SwiftSyntax (#4367) 2022-10-13 16:27:54 +00:00
JP Simard 02b5a034d2
Rewrite `is_disjoint` with SwiftSyntax (#4368) 2022-10-13 12:22:57 -04:00
JP Simard 48fde2321f
Rewrite `contains_over_first_not_nil` & `last_where` with SwiftSyntax (#4366)
Replace `MemberAccessExprSyntax.functionCallBase` with
`ExprSyntax.asFunctionCall` so we can use it in more places.

Move `TokenKind.isEqualityComparison` into `SwiftSyntax+SwiftLint.swift`
2022-10-13 15:59:30 +00:00
JP Simard 8d29b21ecb
Rewrite `sorted_first_last` & `first_where` with SwiftSyntax (#4365)
Add a `functionCallBase` helper.
2022-10-13 15:30:22 +00:00
JP Simard 3bae16bee5
Rewrite `contains_over_filter_is_empty` with SwiftSyntax (#4364) 2022-10-13 10:45:40 -04:00
JP Simard 33f6ee1f36
Update SwiftSyntax (#4363)
Noteworthy:

* https://github.com/apple/swift-syntax/pull/912
* https://github.com/apple/swift-syntax/pull/932
2022-10-13 10:28:00 -04:00
JP Simard de0b91cd5a
Print violations in realtime if progress with an output file (#4362) 2022-10-13 06:23:24 +00:00
JP Simard 4e3c750086
Rewrite `attributes` with SwiftSyntax (#4359)
Not 100% the same as it previously was, but I think all the changes
reported by OSSCheck are improvements or neutral.
2022-10-13 00:40:24 -04:00
JP Simard 2f300502c0
Fix changelog formatting (#4361) 2022-10-13 00:36:25 -04:00
Danny Mösch 9db88947b9
Fix bugs when auto-correcting content given via stdin (#4212)
Fixes #4211.
Fixes #4234.
Fixes #4347.
2022-10-13 00:34:48 -04:00
Marcelo Fabri 99436906cd
Rewrite `self_in_property_initialization` with SwiftSyntax (#4343) 2022-10-12 20:58:57 -07:00
JP Simard 7653b2d635
Update link to video presentation in readme (#4360)
This link has had a broken video resource for years.

The video was just re-published.
2022-10-12 22:49:45 -04:00
Danny Mösch b4e01ba1b4
Disregard whitespace differences in `identical_operands` rule (#4331) 2022-10-12 23:38:00 +02:00
JP Simard b9653e3e1b
Replace `swift run` with `swift build --product` (#4357) 2022-10-12 15:51:10 -04:00
JP Simard 9aaeff67d0
Add `SyntaxProtocol.isContainedIn(regions:locationConverter:)` helper (#4356) 2022-10-12 19:50:32 +00:00
JP Simard 1a7f03bbc5
Rewrite `redundant_discardable_let` with SwiftSyntax (#4355) 2022-10-12 15:27:03 -04:00
JP Simard b849234572
Remove `Configuration.FileGraph.Vertix.configurationString` property (#4354)
It's unused and for large configuration files this uses unnecessary
memory.
2022-10-12 17:16:27 +00:00
JP Simard 0282bf1923
Remove optionality in getting syntax tree and source location converter (#4353)
Parsing does not throw errors.
See https://github.com/apple/swift-syntax/pull/912.
2022-10-12 12:50:17 -04:00
JP Simard 4b04e528af
Revert "Run TSan job on Azure Pipelines with Bazel (#4130)" (#4350)
This reverts commit 848ec452c3.

This appears to be slower most of the time.
2022-10-12 14:26:45 +00:00
JP Simard 602070164b
Reduce memory usage (#4349)
When linting SwiftLint, this brings memory usage down by around 20%,
going from 372MB to 297MB.

This is achieved by removing the unused `RebuildQueue` and by clearing
cached data associated with files after processing them.

Depends on https://github.com/jpsim/SourceKitten/pull/749.
2022-10-12 09:39:36 -04:00
JP Simard 87e9757af2
Update SwiftSyntax (#4346)
I think there might have been changes impacting the `static_operator`
rule, so I want to look more into those here.

Remove workaround for https://github.com/apple/swift-syntax/issues/888
2022-10-11 21:12:29 -04:00
Marcelo Fabri 81ee297908
Rewrite `unused_setter_value` rule with SwiftSyntax (#4342) 2022-10-11 13:08:40 -07:00
JP Simard 016c7b6abd
[Bazel] Fix CryptoSwift compiler warnings (#4345)
Pulls in https://github.com/krzyzanowskim/CryptoSwift/pull/989
2022-10-11 14:22:22 -04:00
Marcelo Fabri 6998d8af23
Migrate `shorthand_operator` rule to SwiftSyntax (#4336)
* Migrate `shorthand_operator` rule to SwiftSyntax

* Remove unneeded imports
2022-10-10 21:28:55 -07:00
Marcelo Fabri 4da2ff1118
Rewrite `operator_whitespace` rule with SwiftSyntax (#4335) 2022-10-10 14:12:03 -07:00
Marcelo Fabri 05d98b84cf
Rewrite `quick_discouraged_focused_test` with SwiftSyntax (#4338) 2022-10-10 14:11:37 -07:00
Marcelo Fabri ec05864880
Rewrite `nslocalizedstring_require_bundle` with SwiftSyntax (#4337) 2022-10-10 14:11:28 -07:00
Marcelo Fabri b938a4e07d
Convert `number_separator` rule to SwiftSyntax (#4333) 2022-10-09 21:03:57 -07:00
Marcelo Fabri ca7510a394
Migrate `static_operator` rule to SwiftSyntax (#4271)
* Migrate `static_operator` rule to SwiftSyntax

* PR feedback
2022-10-08 01:49:15 -07:00
Marcelo Fabri 04bd091810
Migrate `legacy_multiple` rule to SwiftSyntax (#4317) 2022-10-07 23:49:14 -07:00
Danny Mösch 82e916db15
Extend SyntaxProtocol to avoid wrapping (#4332) 2022-10-07 19:41:08 -04:00
Danny Mösch 957208c44b
Make `nsobject_prefer_isequal` rule work for nested classes (#4329) 2022-10-08 00:21:16 +02:00
JP Simard fe6a930bd4
Use os_unfair_lock instead of NSLock on Darwin (#4330) 2022-10-07 20:42:22 +00:00
Marcelo Fabri 8bcf8713e9
Convert `discouraged_assert` rule to SwiftSyntax (#4316) 2022-10-07 13:40:23 -07:00
Marcelo Fabri d913c8e63b
Rewrite `legacy_random` rule with SwiftSyntax (#4318) 2022-10-07 13:35:13 -07:00
Marcelo Fabri b01e1504a1
Rewrite `prohibited_interface_builder` with SwiftSyntax (#4321) 2022-10-07 13:33:49 -07:00
JP Simard 3ac518ce69
Only build `swiftlint` target in Makefile (#4327)
Otherwise this tries to build the SwiftLintTestHelpers module in release
mode, which fails.

Also, to build the actual executable CLI, we can't just
`swift build --target=swiftlint` because that doesn't produce a CLI,
just the object file for the binary. So we have to `swift run`.
2022-10-07 16:50:56 +00:00
JP Simard 0c06b7f65f
Fix jpsim GitHub URL in changelog 2022-10-07 12:14:21 -04:00
JP Simard 1a76a882ca
Ignore incorrect keypath parser diagnostics (#4325)
Works around https://github.com/apple/swift-syntax/issues/888
2022-10-07 10:33:13 -04:00
JP Simard f34169575c
Update rules_apple to 1.1.2 (#4324)
https://github.com/bazelbuild/rules_apple/releases/tag/1.1.2
2022-10-07 10:22:23 -04:00
JP Simard 9c53c94736
Update rules_xcodeproj to 0.9 (#4323)
https://github.com/buildbuddy-io/rules_xcodeproj/releases/tag/0.9.0
2022-10-07 10:14:46 -04:00
Marcelo Fabri 515587fb9f
Convert `strict_fileprivate` rule to SwiftSyntax (#4319) 2022-10-07 02:11:32 -07:00
Marcelo Fabri f174a55c94
Migrate `explicit_enum_raw_value` rule to SwiftSyntax (#4281)
* Migrate `explicit_enum_raw_value` rule to SwiftSyntax

* Handle nested enums
2022-10-07 00:56:15 -07:00
Marcelo Fabri c0a4dd1be7
Rewrite IdenticalOperandsRule with SwiftSyntax (#3894)
* Rewrite IdenticalOperandsRule with SwiftSyntax

* Use folding algorithm from swift-format

* Add workaround for debug builds

* Update implementation after rebasing

* Use SwiftOperators

* Remove focused
2022-10-07 00:55:41 -07:00
JP Simard 1533e72fd4
Specify `@SwiftLint` workspace in opt_wrapper.bzl load (#4314) 2022-10-06 16:59:24 -04:00
JP Simard 549c71a27c
Introduce LegacyFunctionRuleHelper (#4312) 2022-10-06 16:48:51 -04:00
Keith Smiley 367389a489
[bazel] For SwiftSyntax to compile with optimizations (#4311)
This avoids potential stack overflows and slowness when just working on
SwiftLint itself with bazel. These compiles take a lot longer but as
long as you're not updating swift-syntax that should be a 1 time penalty
2022-10-06 15:54:41 -04:00
JP Simard ef248f6529
Remove Signal from OSSCheck (#4313)
It's misbehaving for some reason. It'd be good if anyone wanted to look
into that.
2022-10-06 15:40:18 -04:00
JP Simard a6c90dd942
Rewrite `legacy_cggeometry_functions` with SwiftSyntax (#4309) 2022-10-06 15:16:49 -04:00
Danny Mösch 2a95f1bde9
Add tests for `fileprivate` to `private_outlet` rule (#4308) 2022-10-06 19:13:25 +02:00
JP Simard 5ba9d60f8d
Rewrite `legacy_nsgeometry_functions` with SwiftSyntax (#4307) 2022-10-06 12:46:27 -04:00
Danny Mösch 8345545865
Make `private_unit_test` rule correctable (#4293) 2022-10-06 18:03:03 +02:00
JP Simard d6fd754679
Rewrite `contains_over_range_nil_comparison` with SwiftSyntax (#4225)
Use SwiftOperators.
2022-10-06 01:18:31 -04:00
JP Simard a8d3813cc7
Fix Dockerfile to account for new test modules (#4306) 2022-10-06 00:36:04 -04:00
JP Simard 5ae1d98596
Create new GeneratedTests and IntegrationTests test targets (#4304)
* Move generated rule tests to a dedicated GeneratedTests target
* Move integration tests to a dedicated IntegrationTests target

This will improve bazel cacheability by having fewer tests depend on all
lint inputs, which are only needed by the integration tests.
2022-10-06 00:10:04 -04:00
JP Simard d3fd234883
Fix Dockerfile to account for SwiftLintTestHelpers (#4305) 2022-10-05 23:53:14 -04:00
JP Simard 503f8c506b
Move ExtraRulesTests to its own target & directory (#4300)
Also create a SwiftLintTestHelpers test target.
2022-10-05 23:36:46 -04:00
JP Simard 8470b65ae9
Simplify analyze bazel test (#4303)
By removing SourceAndTestFiles since those files should all be covered
by LintInputs.
2022-10-05 23:25:54 -04:00
JP Simard 4552facb7e
[LegacyConstantRule] Remove unused patterns (#4302)
We now just need these patterns for the mapping of legacy to new.
2022-10-05 22:42:09 -04:00
JP Simard c29e1673dd
Rewrite `legacy_constant` with SwiftSyntax (#4299) 2022-10-05 21:55:48 -04:00
JP Simard cfabd8ec99
Organize `Tests/BUILD` with comments (#4301) 2022-10-05 21:40:12 -04:00
JP Simard 91d4a42687
Loosen correction location assertions (#4297)
With SwiftSyntax rewriters, the visitors get called with the new nodes
after previous mutations have been applied, so it's not straightforward
to translate those back into the original source positions.

So only check the first locations.
2022-10-05 20:51:46 -04:00
JP Simard 7af26f0f77
[CI] Increase TSan test timeout to 1,000 seconds (~16 minutes) (#4298)
We're starting to hit this timeout.
2022-10-05 20:45:07 -04:00
Marcelo Fabri c087e79437
[oss-check] Add DuckDuckGo and Signal (#4275) 2022-10-05 19:00:37 -04:00
JP Simard 54ec0c9b28
Rewrite `trailing_semicolon` with SwiftSyntax (#4296) 2022-10-05 18:46:14 -04:00
JP Simard 3834e52ac4
Rewrite `empty_parameters` with SwiftSyntax (#4295) 2022-10-05 18:26:57 -04:00
JP Simard 5d9a72b2a5
Make `allow_private_set` allow `fileprivate(set)` too (#4294)
As was previously the case.
2022-10-05 17:32:28 -04:00
Danny Mösch af222a5754
Ignore static methods in `private_unit_test` rule (#4292)
Static methods cannot be tests.
2022-10-05 21:00:06 +00:00
JP Simard 54ccc39e72
Update SwiftSyntax (#4290)
Just staying up to date here.

There's no need to frequently update, but given that we just updated to
trunk, I wanted to make sure we can update without issues.
2022-10-05 16:28:56 -04:00
JP Simard 8b578ebf36
Update changelog entry for rules rewritten using SwiftSyntax (#4291) 2022-10-05 16:11:04 -04:00
JP Simard 2eb764d0c9
Update Dockerfile for plugin support (#4289) 2022-10-05 15:34:55 -04:00
JP Simard 13c45a5c15
Add resolved issues to plugin changelog entry (#4288) 2022-10-05 15:31:11 -04:00
Johannes Ebeling 3fd1573c57
Make SwiftLint available as a build tool plugin (#4176)
*  (spm) add build tool plugin definition for swiftlint
* 📝 (changelog) add changelog item for the plugin
* 🐛 (cache) define cache path explicitly to avoid issues during build without issues
* 🎨 minor code cleanup
* 📝 document usage with Xcode as well as Swift packages
2022-10-05 15:28:19 -04:00
JP Simard 6d75645f67
[CI] Disable xcodebuild tests (#4287)
This is failing very often now due to FB11648454.

Given that we run these tests on macOS via SwiftPM and Bazel as well,
I'm satisfied with the amount of coverage we have on our tests without
this.
2022-10-05 15:26:14 -04:00
Danny Mösch 8eec5e6997
Rewrite `private_unit_test` with SwiftSyntax (#4285) 2022-10-05 21:15:25 +02:00
JP Simard 44382ea397
Avoid making SourceKit requests to get parser diagnostics (#4286)
By using SwiftSyntax instead, we avoid the overhead of a SourceKit
request, which has a significant impact if none of the rules being
corrected use SourceKit.
2022-10-05 15:38:11 +00:00
JP Simard 41b8834a13
Rewrite `private_outlet` with SwiftSyntax (#4228) 2022-10-05 11:29:01 -04:00
Marcelo Fabri a40cc70478
Migrate `no_extension_access_modifier` to SwiftSyntax (#4270)
* Migrate `no_extension_access_modifier` to SwiftSyntax

* PR feedback
2022-10-05 00:56:42 -04:00
Marcelo Fabri 1cbf3caae1
Migrate `anonymous_argument_in_multiline_closure` to SwiftSyntax (#4279) 2022-10-04 20:57:22 -07:00
JP Simard 0f9705901b
Add column for SourceKit usage to `rules` command (#4284) 2022-10-04 18:52:03 +00:00
Vasiliy Kattouf 129a55fb74
Add ability to filter rules for `generate-docs` subcommand (#4195)
Added rules filtering options, like in the `rules` subcommand.

<img width="880" alt="generate-docs--help" src="https://user-images.githubusercontent.com/7829589/189372666-2f5aba62-57a1-49dc-9155-c60f9e085984.png">

To achieve reuse with `rules` subcommand:
- extracted filtering logic into `RulesFilter` (and write tests)
- extracted filtering command line parameters into `RulesFilterOptions: ParsableArguments`
2022-10-04 18:45:52 +00:00
Marcelo Fabri c70510c3ea
Migrate `strong_iboutlet` to SwiftSyntax (#4277) 2022-10-04 10:03:33 -07:00
JP Simard 6bfecb8fcc
Rewrite `nsobject_prefer_isequal` with SwiftSyntax (#4283) 2022-10-04 16:34:24 +00:00
JP Simard db20dbb4a3
Replace mutating for-in with `reduce(into:)` (#4282) 2022-10-04 11:47:27 -04:00
JP Simard 46649c8662
Rewrite `explicit_init` with SwiftSyntax (#4223) 2022-10-04 11:20:00 -04:00
JP Simard 1662a38922
Rewrite `ibinspectable_in_extension` with SwiftSyntax (#4227) 2022-10-04 09:28:46 -04:00
JP Simard 18ab68859c
Rewrite `contains_over_filter_count` with SwiftSyntax (#4226) 2022-10-04 09:14:27 -04:00
Danny Mösch ab3f070222
Introduce `SeverityBasedRuleConfiguration` to avoid custom `makeViolation`s (#4274) 2022-10-04 07:39:07 +02:00
Marcelo Fabri e3f1b56129
Convert `duplicate_enum_cases` rule to SwiftSyntax (#4263) 2022-10-03 13:20:43 -07:00
Marcelo Fabri 26ca731cf0
Migrate `deployment_target` rule to SwiftSyntax (#4268) 2022-10-03 10:18:56 -07:00
Marcelo Fabri 8926596da0
Migrate `closure_parameter_position` to SwiftSyntax (#4264) 2022-10-03 10:18:43 -07:00
Marcelo Fabri 647819eedc
Migrate `switch_case_on_newline` to SwiftSyntax (#4269) 2022-10-03 09:28:29 -07:00
Marcelo Fabri f37ea8acc4
Migrate `no_fallthrough_only` rule to SwiftSyntax (#4266) 2022-10-03 09:28:14 -07:00
Marcelo Fabri ac91f7bfa0
Migrate `private_action` rule to SwiftSyntax (#4267) 2022-10-03 09:27:29 -07:00
Marcelo Fabri 462f741065
Rewrite `redundant_string_enum_value` with SwiftSyntax (#4243) 2022-10-02 17:29:55 -07:00
Marcelo Fabri 268415893d
Rewrite protocol_property_accessors_order with SwiftSyntax (#4237)
* Rewrite protocol_property_accessors_order with SwiftSyntax

* PR feedback
2022-10-02 17:29:04 -07:00
JP Simard 2388e49190
Use SwiftSyntax's new SwiftParser (#4216) 2022-10-01 15:05:36 -04:00
JP Simard b2caef7202
Generate Swift Syntax Dashboard in documentation (#4260)
This is a useful overview of where the migration effort stands and what
rules can be migrated next.
2022-10-01 11:29:10 -04:00
Danny Mösch 2efd538d37
Explain where to get syntax kinds for custom rules from (#4246) 2022-09-30 20:23:05 +02:00
Benjamin Kramer 0fe3404494
Add configuration `only_enforce_before_trivial_lines` to `vertical_whitespace_closing_braces` rule (#3941)
Vertical whitespace may be important for readability when the line
with the closing brace is not a trivial one (e.g. `} else if ... {`).
The configuration allows not enforcing the rule in such cases.
2022-09-29 20:26:51 +02:00
Danny Mösch da75cdca40
Remove instructions for Atom editor (#4255)
Atom editor will be sunset at the end of the year.
2022-09-29 06:49:35 +02:00
JP Simard 86f6023d13
Update CryptoSwift to 1.6.0 release (#4258) 2022-09-28 23:37:54 -04:00
JP Simard afb46dc76d
Remove anyobject_protocol from configuration (#4257)
It's been deprecated and the compiler catches these now.
2022-09-28 23:23:06 -04:00
Marcelo Fabri a40488feaf
Rewrite `inert_defer` rule with SwiftSyntax (#4242) 2022-09-28 19:57:00 -07:00
JP Simard d2c638b5e4
[bazel] Enable WMO in `release` configuration (#4252)
Enabling WMO can make SwiftLint up to 90% faster in my testing, and
matches what SwiftPM does when building with `swift buid -c release`.
2022-09-27 21:56:17 -04:00
JP Simard 86a176d4c6
[bazel] Fix release config (#4253) 2022-09-27 21:39:29 -04:00
JP Simard 73def99b49
[bazel] Define a `release` configuration (#4251)
This will be used to put release configurations, like WMO.
2022-09-27 21:34:27 -04:00
JP Simard fd7afedfcf
Update SwiftSyntax & internal parser for Swift 5.7 (#4203)
Require Swift 5.7 to compile
2022-09-26 14:11:39 +00:00
Danny Mösch c6eec8072c
Move method (#4238) 2022-09-25 12:31:24 -04:00
Marcelo Fabri a4c46f624d
Rewrite `no_space_in_method_call` with SwiftSyntax (#4236) 2022-09-25 02:55:00 -07:00
Marcelo Fabri 734eceada0
Rewrite empty_parentheses_with_trailing_closure with SwiftSyntax (#4235) 2022-09-25 02:54:29 -07:00
JP Simard 4fb5ebe19b
Docker: Update to Swift 5.7 & Ubuntu Jammy (#4241)
And apply workaround for https://github.com/apple/swift/issues/59961 to
all commands.
2022-09-24 15:09:41 -04:00
JP Simard bb309de9df
Pin Swift Docker image to 5.6.3-focal (#4240) 2022-09-24 13:56:41 -04:00
Danny Mösch 7be6f866fe
Add new `if_let_shadowing` rule (#4206) 2022-09-22 19:27:45 +02:00
Martin Redington 0db26db975
Add `test_parent_classes` option to `test_case_accessibility` rule (#4214) 2022-09-21 18:29:32 +02:00
Marcelo Fabri f8a4276aba
Rewrite `generic_type_name` rule with SwiftSyntax (#4229) 2022-09-21 08:29:52 -07:00
Danny Mösch 95ffaed655
Filter out compiler argument not understood by SourceKit in Xcode 14 (#4210) 2022-09-20 23:24:40 +02:00
JP Simard 7b1de2f9cd
Rewrite `dynamic_inline` with SwiftSyntax (#4218) 2022-09-20 20:07:24 +00:00
JP Simard 49665a9ec7
Rewrite `fallthrough` with SwiftSyntax (#4224) 2022-09-20 15:56:57 -04:00
Danny Mösch 0ea26edd4f
Skip autocorrecting usage of `NSIntersectionRect` (#4213) 2022-09-20 07:09:05 +02:00
Danny Mösch 2efa085dd4
Make `willMove` a lifecycle method in `type_contents_order` rule (#4201) 2022-09-19 23:27:15 +02:00
dahlborn f3d367f667
Add `LibraryContentProvider` to `file_types_order` rule (#4209) 2022-09-19 22:15:41 +02:00
JP Simard 345a904055
Rewrite `empty_enum_arguments` with SwiftSyntax (#4221) 2022-09-19 20:12:21 +00:00
JP Simard 0808f2508b
Fix typo in example (#4222) 2022-09-19 15:51:21 -04:00
JP Simard 8d500d1a63
Rewrite `empty_collection_literal` with SwiftSyntax (#4220) 2022-09-19 12:39:35 +02:00
JP Simard 992cc9afe3
Rewrite `discouraged_object_literal` with SwiftSyntax (#4219) 2022-09-19 10:24:22 +00:00
Danny Mösch 49ace1729f
Add Swift 5.6.3 to version test (#4207) 2022-09-14 23:20:51 +02:00
Danny Mösch 38e71f7a10
Enhance docs for `type_name` rule (#4197) 2022-09-10 10:54:13 -04:00
tillhainbach a9ec894caf
Add exceptions to `weak_delegate` rule (#3599) 2022-09-10 10:07:43 -04:00
Chris Brakebill 9db303e3a3
Respect 'validates_start_with_lowercase' for function names in `identifier_name` rule (#4188) 2022-09-09 23:36:55 +02:00
JP Simard 4b1bb38fc3
Include the configured `bind_identifier` in `self_binding` violation (#4196)
As suggested in https://github.com/realm/SwiftLint/pull/4146#issuecomment-1241793057
2022-09-09 16:08:26 +00:00
Marcelo Fabri 623bc8ea73
Add multiple_closures_with_trailing_closure to changelog 2022-09-08 19:34:37 +02:00
Marcelo Fabri baf5647e2b
Rewrite `multiple_closures_with_trailing_closure` with SwiftSyntax (#4193) 2022-09-08 19:34:06 +02:00
JP Simard ea574bd640
Update changelog to reflect rules rewritten with SwiftSyntax (#4191) 2022-09-08 05:50:58 +00:00
JP Simard 837f46479f
Rewrite `toggle_bool` with SwiftSyntax (#4190) 2022-09-08 05:27:44 +00:00
JP Simard c6f3d0a6af
Rewrite `xctfail_message` with SwiftSyntax (#4189) 2022-09-08 00:03:44 -04:00
JP Simard 8c5d3cbfc8
Use Xcode 14 RC1 on CI (#4186)
https://twitter.com/XcodeReleases/status/1567607977900929024
2022-09-07 22:58:15 -04:00
Danny Mösch 311a724c3c
Get rid of optional return value (#4187) 2022-09-07 18:18:34 -04:00
Danny Mösch 6b393b1b53
Re-delegate to ArrayInitRule (#4185) 2022-09-07 21:14:45 +00:00
JP Simard 4234664671
Rewrite `anyobject_protocol` with SwiftSyntax & deprecate (#4170) 2022-09-07 19:40:34 +00:00
JP Simard 8cd025112d
Rewrite `block_based_kvo` with SwiftSyntax (#4171) 2022-09-07 15:16:22 -04:00
JP Simard efbe4d9f0f
Rewrite `discouraged_optional_boolean` with SwiftSyntax (#4179) 2022-09-07 15:15:38 -04:00
JP Simard 4a239a695e
Rewrite `array_init` rule with SwiftSyntax (#4175) 2022-09-07 15:15:10 -04:00
JP Simard bc7792ecd6
Rewrite `empty_string` with SwiftSyntax (#4177) 2022-09-07 13:59:15 -04:00
JP Simard 958cc20a9f
Rewrite `redundant_nil_coalescing` with SwiftSyntax (#4182) 2022-09-07 13:29:06 -04:00
JP Simard 117ef7f0e2
Rewrite `flatmap_over_map_reduce` with SwiftSyntax (#4178) 2022-09-07 13:23:51 -04:00
JP Simard 0d03221281
Rewrite `class_delegate_protocol` with SwiftSyntax (#4172) 2022-09-07 12:20:47 -04:00
JP Simard 80c8e5d37a
Rewrite `closing_brace` with SwiftSyntax (#4173) 2022-09-07 12:20:26 -04:00
JP Simard 9060d3f8e8
Rewrite `force_try` with SwiftSyntax (#4181) 2022-09-07 11:18:01 -04:00
JP Simard eb30be3826
Add `SourceKitFreeRule` conformance to `FileNameNoSpaceRule` (#4180) 2022-09-07 10:36:57 -04:00
JP Simard 2a8d536857
Remove delegation of TypesafeArrayInitRule to ArrayInitRule (#4174)
In preparation for rewriting `ArrayInitRule` with SwiftSyntax.
2022-09-07 01:34:58 -04:00
Ryan Cole c34955ca64
Add `accessibility_trait_for_button` rule (#3989) 2022-09-06 21:44:09 +00:00
Danny Mösch e459c4ae9b
Exclude `weak_delegate` rule from autocorrection (#4153) 2022-09-06 22:56:51 +02:00
Marcelo Fabri 75a6d14788
Update CHANGELOG.md 2022-09-06 09:25:55 -07:00
Marcelo Fabri e2900c4a7e
Rewrite `untyped_error_in_catch` with SwiftSyntax (#4163) 2022-09-06 09:25:06 -07:00
Marcelo Fabri dd94d4ec53
Rewrite `computed_accessors_order` with SwiftSyntax (#4165) 2022-09-06 09:24:54 -07:00
Marcelo Fabri 1e7e0d6301
Remove references to ImplicitlyUnwrappedOptional type (#4166) 2022-09-06 09:01:22 -07:00
JP Simard 4b8a68072b
Call `super.visit` in `SyntaxRewriter` overrides (#4167)
As discussed in https://github.com/realm/SwiftLint/pull/4159#discussion_r962841482
2022-09-06 13:52:40 +00:00
JP Simard 26465f21ce
Add methods from SE-0348 to `UnusedDeclarationRule` (#4168)
https://github.com/apple/swift-evolution/blob/main/proposals/0348-buildpartialblock.md
2022-09-06 09:45:34 -04:00
Marcelo Fabri b29c07e07e
Update CHANGELOG.md 2022-09-05 20:33:01 -07:00
Marcelo Fabri 622d48bd0a
Convert `unneeded_break_in_switch` to SwiftSyntax (#4164) 2022-09-05 20:32:29 -07:00
Marcelo Fabri b9e6a9aed8
Rewrite unneeded_parentheses_in_closure_argument with SwiftSyntax (#4159) 2022-09-05 06:12:33 -04:00
Marcelo Fabri 6c0413077c
Rewrite unowned_variable_capture with SwiftSyntax (#4161) 2022-09-05 05:38:29 -04:00
Marcelo Fabri 772e5f5806
Delegate Location init for AbsolutePosition to existing one (#4162) 2022-09-05 01:47:25 -04:00
Marcelo Fabri c7c4e0a1f3
Rewrite `implicit_getter` rule with SwiftSyntax (#4160)
* Rewrite `implicit_getter` rule with SwiftSyntax

* Handle different reason messages

* Add changelog + implicit return
2022-09-05 01:28:25 -04:00
Marcelo Fabri ca2d3a874f
Rewrite `large_tuple` rule with SwiftSyntax (#4156)
* Rewrite `large_tuple` rule with SwiftSyntax

* Add changelog, remove import

* Update Source/SwiftLintFramework/Rules/Metrics/LargeTupleRule.swift

Co-authored-by: JP Simard <jp@jpsim.com>

Co-authored-by: JP Simard <jp@jpsim.com>
2022-09-05 01:10:59 -04:00
Marcelo Fabri 79347a1728
Rewrite ForceUnwrappingRule using SwiftSyntax (#4155) 2022-09-04 02:08:26 -07:00
Marcelo Fabri c1650e6918
Add `excludes_trivial_init` for `missing_docs (#4152)
Fixes #4107
2022-09-03 22:11:57 -07:00
JP Simard c26c40d31f
Set `.bazelversion`
To avoid this issue: https://github.com/bazelbuild/bazelisk/issues/220
2022-09-02 10:46:17 -04:00
JP Simard 93158a609e
Update rules_xcodeproj to 0.7.1 2022-09-02 10:39:59 -04:00
JP Simard a3b70a0ffb
Update rules_apple/rules_swift to 1.1.1 (#4150)
https://github.com/bazelbuild/rules_apple/releases/tag/1.1.1
https://github.com/bazelbuild/rules_swift/releases/tag/1.1.1
2022-09-02 14:34:58 +00:00
JP Simard e381a7d684
Update bazel version in readme 2022-09-02 10:10:09 -04:00
JP Simard abad253310
Add empty changelog section 2022-09-01 12:43:37 -04:00
JP Simard 57dc1c9532
release 0.49.1 2022-09-01 12:32:19 -04:00
JP Simard d72877a34f
Move changelog entry 2022-09-01 12:29:13 -04:00
JP Simard ea41b9fd09
Rename default branch from `master` to `main` (#4116) 2022-09-01 07:09:46 -04:00
JP Simard e0f23fa8e9
Add `--progress` flag to lint and analyze commands (#4147)
Inspired by https://github.com/jkandzi/Progress.swift

```
4948 of 29100 [=====                         ] ETA: 44s (540 files/s)
```

Demo:

[![asciicast](https://asciinema.org/a/517985.svg)](https://asciinema.org/a/517985)
2022-08-31 18:26:17 -04:00
JP Simard 4bc6588f38
Add `--output` option to lint and analyze commands (#4148)
To write to a file instead of to stdout.

Addresses https://github.com/realm/SwiftLint/issues/4048
2022-08-31 17:34:37 -04:00
JP Simard d14cf598fd
Add SwiftSyntaxBuilder to SwiftLintFramework Bazel deps (#4149)
Even though we don't use this ourselves yet, it's useful to expose this
so that users with custom rules can access it.
2022-08-31 11:31:37 -04:00
JP Simard 9979c4fd27
Add new `self_binding` opt-in rule (#4146)
To enforce that `self` identifiers are consistently re-bound to a common
identifier name.

Configure `bind_identifier` to the name you want to use.

Defaults to `self`.

Addresses https://github.com/realm/SwiftLint/issues/2495
2022-08-30 16:37:19 -04:00
JP Simard f032c82b59
Fix link in comments (#4145) 2022-08-29 14:29:20 -04:00
JP Simard c8a66e7070
Add changelog entry for https://github.com/realm/SwiftLint/pull/4143 (#4144) 2022-08-29 12:59:23 -04:00
Martin Hosna f32bc1f337
RedundantDiscardableLetRule should not produce warning when used with async (#4143)
handle situation with async let _ = ....
let can not be removed from "async let _ = ..." because removing it produces invalid swift syntax

Co-authored-by: Martin Hosna <mhosna@samepage.io>
2022-08-29 12:56:35 -04:00
JP Simard fc3b143973
Rename `script` directory to `tools` (#4141)
And move the Danger bazel config there
2022-08-29 01:16:20 -04:00
JP Simard 4119c27857
Fix typo 2022-08-29 00:33:51 -04:00
JP Simard a9e5a644bb
Remove rbenv/ruby setup from CONTRIBUTING.md (#4140)
It's no longer needed as of https://github.com/realm/SwiftLint/pull/4138
2022-08-28 23:54:47 -04:00
JP Simard 501142d3e7
Update gems (#4139) 2022-08-29 03:29:37 +00:00
JP Simard ea6ca3e8dd
[CI] Use `ci.bazelrc` in Azure Pipelines 2022-08-28 23:00:17 -04:00
JP Simard 0fd9a112b4
[CI] Run Danger with Bazel (#4138)
It'd be nice to avoid needing to maintain rbenv on CI
2022-08-28 22:58:39 -04:00
JP Simard eb14f5283c
Speed up Analyze CI job (#4136)
By merging `write_swiftpm_yaml` into analyze test
2022-08-28 22:35:42 -04:00
JP Simard cd9bd5f9fd
Make duplicate_imports rule documentation deterministic (#4137) 2022-08-28 18:27:12 -04:00
Danny Mösch 9875ab904b
Print autocorrected STDIN input to STDOUT (#4132) 2022-08-28 23:17:20 +02:00
JP Simard 7412205b6c
[CI] Use Xcode 13.4.1 on Azure Pipelines (#4134) 2022-08-28 14:42:57 -04:00
JP Simard 8dbc0e4cbf
Update Azure Pipelines to use 'ubuntu-latest' for Linux jobs 2022-08-28 14:20:11 -04:00
JP Simard ccac242f3a
Update CI setup instructions again 2022-08-28 14:15:28 -04:00
JP Simard dcb5bf438d
Support `user.bazelrc`
So devs can put extra bazel flags in there
2022-08-28 14:09:22 -04:00
JP Simard fdcdcf76d1
Use bazel remote cache on Buildkite (#4133) 2022-08-28 14:07:10 -04:00
JP Simard 05461c8525
Update `CONTRIBUTING.md` with new CI steps for Bazel remote cache 2022-08-28 12:37:02 -04:00
JP Simard 848ec452c3
Run TSan job on Azure Pipelines with Bazel (#4130) 2022-08-28 10:51:58 -04:00
Danny Mösch bf9bf83143
Migrate EmptyXCTestMethodRule to SwiftSyntax fixing some false-positives (#4129) 2022-08-27 03:02:05 -04:00
JP Simard d9ec625601
Add empty changelog section 2022-08-26 11:08:56 -04:00
JP Simard ef36201e6b
release 0.49.0 2022-08-26 10:48:09 -04:00
JP Simard 5a30991fa4
Add SwiftSyntax rule helpers (#4126)
This cuts down on the boilerplate involved in writing SwiftSyntax-based
rules. May not be significant right now since most rules are still built
with SourceKit, but as we migrate more rules moving forward, this should
make it easier for rule authors to write rules that behave performantly
and correctly.
2022-08-26 14:46:32 +00:00
JP Simard aebded15ba
Fix changelog formatting 2022-08-26 10:16:16 -04:00
Ben Davis 7dfadc205a
Add new configuration to `operator_usage_whitespace` rule to specify no-space operators (#4112) 2022-08-25 17:59:27 +02:00
JP Simard 9cfd3dc978
Update CI to use Xcode 14 beta 6 (#4125)
Only used for the TSan CI job right now, which was previously using
Xcode 14 beta 5.

https://twitter.com/XcodeReleases/status/1562130365191315457
2022-08-23 15:31:25 -04:00
JP Simard c73f68683a
Update rules_apple to 1.1.0 (#4124)
https://github.com/bazelbuild/rules_apple/releases/tag/1.1.0
2022-08-23 15:17:38 -04:00
JP Simard cf764e7b90
Fix hang after linting or analyzing on Linux (#4123)
Fixes https://github.com/realm/SwiftLint/issues/4117
2022-08-23 13:45:10 -04:00
JP Simard 83bf37e642
Add `SwiftLintFile.isTestFile` (#4122) 2022-08-23 12:04:30 -04:00
JP Simard 7259c02ee5
Teach `--compile-commands` to parse SwiftPM yaml files (#4119)
And move analyze CI job to Bazel

Which will benefit from caching previous results,
so if we make a PR that doesn't impact the analysis
results (i.e. changelog or docs) we might be able to
skip running this at all.
2022-08-23 11:01:13 -04:00
JP Simard 68983d7da2
Enable Bazel disk cache (#4120)
Set to `~/.bazel_cache`. https://bazel.build/remote/caching#disk-cache
2022-08-23 07:58:31 -04:00
JP Simard 2960ae6a7a
Test with thread sanitizer in Buildkite using Bazel (#4115)
This will allow for the test to be skipped if it's already cached,
speeding up CI runs.
2022-08-22 19:21:54 -04:00
JP Simard 69f3a3b4b7
Refactor bazel release rule
Moving the signature file generation from the Makefile to the bazel rule
2022-08-22 12:26:22 -04:00
Danny Mösch f3e2c0b7bb
Replace manual backtracking by location information from the captured group (#4111) 2022-08-19 20:14:19 +02:00
JP Simard e8f738b39c
Automate producing release tarballs for Bazel (#4113) 2022-08-19 17:26:21 +00:00
Danny Mösch 6dc2ef937e
Add trigger markers to examples (#4110) 2022-08-18 22:15:11 +00:00
JP Simard 0e3f3de17f
Set CHANGELOG header back to 'Master'
And update bazel ref in readme to point to `0.49.0-rc.2`.
2022-08-18 16:35:21 -04:00
JP Simard dd55f59207
release 0.49.0-rc.2 2022-08-18 13:31:47 -04:00
JP Simard c1de2ef087
Fix changelog formatting 2022-08-18 13:27:35 -04:00
Kotaro Suto 78949c1b99
Fix broken correction for `explicit_init` rule (#4109) 2022-08-18 17:17:52 +00:00
chrisjf 1ef15f3bb7
Update documentation for multiline_arguments_brackets and multiline_literal_brackets (#4098)
- added two triggering examples that are a common style, to make it immediately obvious that they trigger the rules
- also fixed a spelling mistake throughout the examples for the multiline_literal_brackets rule ("Gryffindor" is now correctly spelt)
2022-08-18 09:53:52 +02:00
Kotaro Suto 3aa249b8a1
Fix first_where false negative (#4105) 2022-08-17 00:06:32 +00:00
JP Simard c2be5b18b4
Only check `sourcekitdFailed` for SourceKit-based rules (#4104)
And only warn once if it's disabled.

This check is expensive and as more rules move away from SourceKit to
SwiftSyntax, it's increasingly common for rules to not use SourceKit at
all.

In addition, SourceKit crashes used to be a lot more common but I
haven't seen one myself in quite a while.
2022-08-16 16:46:55 +00:00
JP Simard f6fc4727b6
Skip OSSCheck if binary hasn't changed (#4103) 2022-08-16 16:07:36 +00:00
JP Simard 73c88c3af0
Add `version --verbose` command (#4102)
Prints out something like this on macOS:

```
Version: 0.49.0-rc.1
Build ID: B43931F3-D096-3704-B41C-FC40673A3F96
```

This can be used to determine if two `swiftlint` executables are
identical.
2022-08-16 14:12:44 +00:00
JP Simard ac23f2e89a
Log time spent in each custom rule (#4100) 2022-08-15 22:03:06 -04:00
JP Simard 781034bd78
Revert "Clear bazel caches" (#4099)
This reverts commit fe43d6ecd4.
2022-08-15 21:39:38 -04:00
JP Simard 13703c4466
Update SourceKitFreeRules (#4097)
None of these rules use SourceKit
2022-08-16 00:56:03 +00:00
JP Simard 0a3ebdbd37
[Bazel] Define minimum OS versions (#4096)
This helps when building with Xcode 14.
2022-08-15 16:34:50 -04:00
JP Simard 408ba29951
Integrate with rules_xcodeproj (#4095) 2022-08-15 16:22:47 -04:00
JP Simard 3037946bbc
Migrate ClosureSpacingRule to SwiftSyntax (#4092)
Fixes #4090. Continued from #4091.
2022-08-15 18:27:43 +00:00
sarastro-nl d1a1485af6
enable glob for includePaths (#4093) 2022-08-15 13:54:49 +00:00
Danny Mösch ef515ac45e
Fix false positive in `yoda_condition` rule basing it on SwiftSyntax (#4089) 2022-08-14 16:30:09 -04:00
JP Simard 15970311e1
Update CHANGELOG header to say "Master" again 2022-08-12 11:08:49 -04:00
JP Simard 35df4ba6a1
Update bazel ref in readme 2022-08-12 11:07:05 -04:00
JP Simard 6f03036591
release 0.49.0-rc.1 2022-08-12 09:49:13 -04:00
JP Simard dec9ecbf0b
Add note in changelog about upcoming default branch rename (#4088) 2022-08-12 09:46:11 -04:00
JP Simard 5e1eaea148
Improve Buildkite grouping (#4086)
Reference: https://buildkite.com/docs/pipelines/managing-log-output
2022-08-12 00:02:13 -04:00
JP Simard 21ba7c8280
Update SourceKitten to 0.33.0 (#4085)
https://github.com/jpsim/SourceKitten/releases/tag/0.33.0
2022-08-11 21:04:32 +00:00
JP Simard a163638214
Clean up .swiftlint.yml
By removing references to deleted files
2022-08-11 14:48:43 -04:00
Danny Mösch 9eb6dd016c
Let Sourcery always run independent of changed files (#4084) 2022-08-11 16:28:17 +00:00
Timofey Solonin 557c5b5948
Make `duplicate_imports` rule correctable (#4014)
Also fix reporting of redundant violations when more than one duplicate is present.
2022-08-11 18:19:26 +02:00
Danny Mösch c1b74cd752
Rename test classes (#4083) 2022-08-11 07:33:11 +02:00
Danny Mösch a02d4a76cb
Remove references to ManuallyTestedExamplesRule protocol (#4082)
Follow-up of d730e0b3fa.
2022-08-10 21:42:10 +00:00
JP Simard dd4aefd23a
Danger: Clarify that changelog entries are for user-facing changes only 2022-08-10 17:30:47 -04:00
JP Simard 73f4c3e991
Clarify that changelog entries are for user-facing changes only 2022-08-10 17:29:45 -04:00
Danny Mösch d730e0b3fa
Let all example verification tests be generated by Sourcery (#4076) 2022-08-10 22:49:28 +02:00
Danny Mösch 828f36958f
Introduce option to ignore indentation of compiler directives in `indentation_width` rule (#4066) 2022-08-10 21:52:32 +02:00
JP Simard adec1c76ee
Show Bazel test errors on CI 2022-08-10 15:03:44 -04:00
JP Simard 8f620ccd0b
Bump SourceKitten bazel ref (#4080)
To avoid a compiler warning when building with Xcode 14 beta 5
2022-08-10 14:30:41 -04:00
JP Simard 481da28f1e
Remove internal changelog entries 2022-08-10 13:36:58 -04:00
Sara Tavares f8e1b178d6
chore(typo): fix typo on test (#4078) 2022-08-10 13:36:03 -04:00
Sara Tavares 436a6f3484
chore(typo): fix typo on func (#4077) 2022-08-10 13:35:42 -04:00
Danny Mösch 449190d324
Verify examples in rules by default and enforce explicit exclusion (#4065)
A rule must conform to ManuallyTestedExamplesRule to skip generation of a test for its examples.
2022-08-09 22:32:09 +02:00
JP Simard 1ac0419eb6
Fix failing Swift 5.7 test (#4075)
Seems like `CGPoint` moved from the `CoreGraphics` module to the
`CoreFoundation` module.
2022-08-09 16:44:05 +00:00
JP Simard a97718f4c6
Replace incrementer dispatch queue with an actor (#4073)
To support this, we first must use an async entrypoint to the CLI, which
we do by changing the lint and analyze commands to conform to
`AsyncParsableCommand`.

The in order to map over the closures with suspension points, we pull in
CollectionConcurrencyKit as a new dependency.

This change does not touch SwiftLintFramework, only the CLI target.
2022-08-09 13:06:08 +00:00
JP Simard ec8ba17388
Use `@main` attribute (#4072)
This will allow us to have an async entrypoint and use structured
concurrency features in the future.
2022-08-09 03:48:12 +00:00
JP Simard 2b00164081
Remove uses of `Result` in CLI target (#4071)
Which will make it easier to adopt some structured concurrency features
in the future.
2022-08-08 23:04:20 -04:00
JP Simard f39323160c
Remove availability check (#4070)
Since SwiftLint now requires macOS 12 or higher to run.
2022-08-09 02:28:32 +00:00
JP Simard 235264bb7e
Stop building Docker images for Swift 5.5 (#4068)
Follow-up to https://github.com/realm/SwiftLint/pull/4037
2022-08-07 22:03:45 -04:00
JP Simard cc7c400e81
Run bazel tests in sandbox on CI
By setting `IN_PROCESS_SOURCEKIT=1` as `--test_env`
2022-08-07 22:00:10 -04:00
JP Simard 8b8b3d0738
Run all tests with Bazel (#4067)
Other than the one test case that uses paths with spaces in them which
Bazel doesn't support.
2022-08-07 16:56:45 -04:00
JP Simard 0ded5859a1
Rewrite ColonRule with SwiftSyntax (#4063)
Making it about 7x faster, finding some previously missed cases.
2022-08-04 17:23:52 -04:00
Danny Mösch cdb87e3869
Verify all examples provided in rule descriptions (#4061) 2022-08-04 23:06:37 +02:00
JP Simard c50b42c183
Rewrite CommaRule with SwiftSyntax (#4062)
Making it about 10x faster, finding some previously missed cases and
fixing some previously wrong corrections.

This pulls in the `Collection.windows(ofCount:)` function from Swift
Algorithms.
2022-08-04 04:29:38 +00:00
JP Simard ee655a920c
Fix changelog entry placement 2022-08-03 23:14:37 -04:00
Or Eliyahu 19eda14df1
Fix false positives in duplicated_key_in_dictionary_literal rule (#4057) 2022-07-31 21:07:15 +02:00
Danny Mösch 54a8435479
Use specific failure messages in extended tests (#4058) 2022-07-31 14:45:47 +02:00
JP Simard 1dab8181b8
Fix bazel extra rules tests on Linux (#4056) 2022-07-29 19:34:54 +00:00
JP Simard 8b90623b38
[Bazel] Set up tests (#4055)
Run with `bazel test --spawn_strategy=standalone //Tests/...`

Consumers who define rules via `swiftlint_extra_rules` can run tests for
their custom rules too:

```
./bazelw test \
  --spawn_strategy=standalone \
  @SwiftLint//Tests:ExtraRulesTests
```
2022-07-28 19:14:03 +00:00
JP Simard b70c92c34c
Fix `PrimaryRuleList.stencil` (#4053) 2022-07-28 13:23:02 -04:00
JP Simard 340fce43c8
Update bazel ref in readme (#4052) 2022-07-28 13:19:19 -04:00
JP Simard 6c5f53ef66
Add micro-optimization to commands cache (#4050)
Speeds up overall lint time by ~2% for Lyft's iOS monorepo.
2022-07-28 15:44:34 +00:00
JP Simard 949ab6289a
[Bazel] Update SourceKitten 2022-07-27 11:04:45 -04:00
Steve Madsen 4d8abec16e
Make comma_inheritance rule opt-in (#4047) 2022-07-27 17:01:11 +02:00
Danny Mösch 68d88ded61
Check in build that Sourcery generated files are up-to-date (#4035) 2022-07-26 20:50:05 +02:00
JP Simard 9e485266be
Run OSSCheck when bazel files change (#4046) 2022-07-26 14:49:02 -04:00
Marcelo Fabri 3a64518119
Fix false positive in self_in_property_initialization (#4044)
* Fix false positive in self_in_property_initialization

Fixes #4041

* Update CHANGELOG.md

Co-authored-by: JP Simard <jp@jpsim.com>

Co-authored-by: JP Simard <jp@jpsim.com>
2022-07-26 11:41:09 -07:00
JP Simard 29cd97e59c
Bump SourceKitten (#4045) 2022-07-26 14:30:02 -04:00
JP Simard c0f9f2175b
Add support for native custom rules (#4039)
This change makes it possible to add native custom rules when building
SwiftLint via Bazel (possible as of
https://github.com/realm/SwiftLint/pull/4038).

First, add a local bazel repository where custom rules will be defined
to your project's `WORKSPACE`:

```python
local_repository(
    name = "swiftlint_extra_rules",
    path = "swiftlint_extra_rules",
)
```

Then in the extra rules directory, add an empty `WORKSPACE` and a
`BUILD` file with the following contents:

```python
filegroup(
    name = "extra_rules",
    srcs = glob(["*.swift"]),
    visibility = ["//visibility:public"],
)
```

To add a rule (for example, `MyPrivateRule`) add the following two
files:

```swift
// ExtraRules.swift
func extraRules() -> [Rule.Type] {
    [
        MyPrivateRule.self,
    ]
}
```

```swift
// MyPrivateRule.swift
import SourceKittenFramework
import SwiftSyntax

struct MyPrivateRule: ConfigurationProviderRule {
    var configuration = SeverityConfiguration(.error)

    init() {}

    static let description = RuleDescription(
        identifier: "my_private_rule",
        name: "My Private Rule",
        description: "This is my private rule.",
        kind: .idiomatic
    )

    func validate(file: SwiftLintFile) -> [StyleViolation] {
        // Perform validation here...
    }
}
```

Then you can reference the rule in your configuration or source files as
though they were built in to the official SwiftLint repo.

This means that you have access to SwiftLintFramework's internal API.
We make no guarantees as to the stability of these internal APIs,
although if you end up using something that gets removed please reach
out and we'll make a best effort to maintain some level of support.

This PR also improves the linter cache on macOS to make it correctly
invalidate previous results when custom native rules are edited. This
even works when doing local development of SwiftLint, where previous it
was necessary to use `--no-cache` when working on SwiftLint, now the
cache should always work.

Co-authored-by: Keith Smiley <keithbsmiley@gmail.com>
2022-07-26 13:56:22 -04:00
JP Simard 7155af1981
[CI] Move `oss-check` to use Bazel (#4043)
Which should improve the CI times thanks to Bazel's improved build
caching.
2022-07-26 12:10:06 -04:00
JP Simard ffc6379828
Fix rendering issue in readme
GitHub doesn't render this as a code block, it renders the backticks.
2022-07-26 09:56:13 -04:00
JP Simard fe652e8c8a
Update Makefile to drop support for Swift 5.5 2022-07-26 09:45:16 -04:00
JP Simard 8ee7485c8a
Fix changelog 2022-07-26 08:05:29 -04:00
JP Simard 24735ef4d3
Add support for building with Bazel (#4038) 2022-07-26 07:09:02 -04:00
JP Simard 05ac3c9d75
Require macOS 12 & Swift 5.6 (#4037)
This will unblock using Swift Concurrency features and updating to the
latest versions of Swift Argument Parser.

This won't drop support for linting projects with an older toolchain /
Xcode selected, as long as SwiftLint was _built_ with 5.6+ and is
_running_ on macOS 12+. So the main breaking change for end users here
is requiring macOS 12 to run.

However, the upside to using Swift Concurrency features is worth the
breaking change in my opinion. Also being able to stay on recent Swift
Argument Parser releases.
2022-07-26 03:55:36 -04:00
JP Simard 09837b7bab
Add empty changelog section 2022-07-26 03:53:03 -04:00
JP Simard 22fb9eb9e5
release 0.48.0 2022-07-26 03:34:06 -04:00
JP Simard 617f83c81d
Add note about dropping support for Swift 5.5 / macOS 11 2022-07-26 03:30:35 -04:00
JP Simard f81972e98c
Apply minor stylistic edits to `OperatorUsageWhitespaceRule` 2022-07-26 03:23:35 -04:00
JP Simard c53dc0ce17
Move changelog entry to correct section 2022-07-26 03:10:41 -04:00
Danny Mösch 1c7b8b7dcb
Run Sourcery enabling automatic test for ModifierOrderRule (#4034) 2022-07-24 14:11:09 -04:00
Danny Mösch 4aa38957c3
Enable auto-test for rule (#4033) 2022-07-24 08:24:11 -04:00
Craig Siemens c5aa8065d1
Update `nimble_operator` to suggest the (in)equal operator instead of `beNil()` (#4025) 2022-07-14 13:44:29 -04:00
DCherish c95670edd2
Fix Korean README (#4020) 2022-07-11 08:08:13 +02:00
DCherish 69dc18135a
Update Korean README (#4018) 2022-07-09 17:51:03 +02:00
Danny Mösch a51be7bcce
Refactor deployment target configuration to avoid duplications (#4017) 2022-07-06 17:07:15 -04:00
Ruby 37f95d996e
fix typo in README (#4016) 2022-07-06 15:32:09 +02:00
Taha Bebek e34f49695b
Support extension targets in `deployment_target` rule (#4011) 2022-07-05 22:41:56 +02:00
Koki Hirokawa 25ed3d2d26
Support `UIEdgeInsets` type in `prefer_zero_over_explicit_init` rule (#4008) 2022-06-29 21:28:47 +02:00
Marcelo Fabri 45a03dec20
Add back `void_function_in_ternary` rule (#3956) 2022-06-27 09:41:52 -07:00
Marcelo Fabri a19ffddf66
Support arrays for `included` & `excluded` in custom rules (#4006)
* Support arrays for `included` & `excluded` in custom rules

* Extract shouldValidate(filePath:) and add tests
2022-06-27 00:29:26 -07:00
Danny Mösch 1faea36a22
Do not trigger unavailable_condition rule if other #(un)available checks are involved (#4002) 2022-06-24 22:58:02 +02:00
Danny Mösch a20a75d422
Fix various shortcomings in relative path computation (#4005) 2022-06-24 02:25:37 -04:00
Danny Mösch 04972a39da
Look for call expressions which are not wrapped into an argument (#3977)
This makes the added test cases work in Xcode 13.2 where the wrapping does not happen.
The call expression is the first substructure in the dictionary, while in Xcode 13.3
it's an argument containing the call expression.
2022-06-19 13:39:07 -04:00
Danny Mösch 634406a30a
Fix violation message in untyped_error_in_catch rule (#4001)
It was just "warning". Now it is the description of the rule (default).
2022-06-19 13:09:33 -04:00
Danny Mösch 0d070a8c8c
Update result builder methods in unused_declaration rule fixing some false-positives (#4000) 2022-06-19 11:59:23 +02:00
Marcelo Fabri 71db511003
Remove Alcatraz from README
This hasn't been properly supported for years. Fixes https://github.com/realm/SwiftLint/issues/3782
2022-06-15 10:18:54 -07:00
Danny Mösch 86e765c418
Deprecate the `--path` option in favor of the positional `paths` argument (#3952)
There is no real benefit for this option. Files and folders to lint/analyze
can be passed to `swiftlint` as last arguments. There cannot be multiple
`--path` arguments. If there is more than one only the last path is considered.
2022-06-14 23:10:28 +02:00
Liam 64f656cb46
Update README.md (#3995) 2022-06-14 21:17:07 +02:00
Danny Mösch 323a249f70
Make `for_where` independent of order in structure dictionary (#3979) 2022-06-14 13:55:12 -04:00
Marcelo Fabri 4382ef49b9
Use URL(fileURLWithPath:isDirectory) to avoid file system call (#3976) 2022-05-26 21:54:23 +02:00
Jaehong Kang 809dcc6bdc
Prevent crash for private types named `_` in `type_name` rule (#3972) 2022-05-10 19:15:44 +02:00
Danny Mösch ca9217d5e1
Ignore array types if their associated `Index` is accessed (#3970) 2022-05-07 19:11:53 -04:00
Marcelo Fabri f880b66cbf
Rewrite `operator_usage_whitespace` with SwiftSyntax (#3962) 2022-05-06 16:48:57 -07:00
Dennis Hong ea6cc50890
Fix Korean grammar errors (#3967) 2022-05-02 07:22:15 +02:00
Marcelo Fabri ebc77391bc
Add workaround to avoid stack overflow in debug (#3963) 2022-05-01 14:57:28 -07:00
Danny Mösch bc7917be04
Use explicit link command (#3966) 2022-05-01 12:32:14 -04:00
JP Simard 3a4afce623
[CI] Update to Xcode 13.3.1 (#3961)
* [CI] Update to Xcode 13.3.1

* Update jazzy
2022-04-27 11:31:01 -04:00
Danny Mösch a27c7da7e2
Allow custom attributes on lines directly before let/var declarations (#3943) 2022-04-26 22:00:44 +02:00
JP Simard 113b2985de
Add empty changelog section 2022-04-25 12:40:04 -04:00
JP Simard e497f1f5b1
release 0.47.1 2022-04-25 11:31:09 -04:00
JP Simard 11dff81247
Remove extra trailing space in changelog 2022-04-25 11:24:56 -04:00
JP Simard f0d6c54574
[CONTRIBUTING] Add note to install bundler on CI machines 2022-04-25 11:21:15 -04:00
Ryan Cole 43c84146db
Add accessibility_label_for_image rule (#3862)
Warns if a SwiftUI Image does not have an accessibility label and is not hidden from accessibility. When this is the case, the image's accessibility label defaults to the name of the image file causing a poor UX.
2022-04-18 10:40:51 +02:00
Marcelo Fabri 5f44d3f306
Add comma_inheritance_rule rule (#3954)
Fixes #3950
2022-04-17 04:47:02 -07:00
Marcelo Fabri 1752587b7b
Add unavailable_condition rule (#3953)
Fixes #3897
2022-04-17 03:30:53 -07:00
Marcelo Fabri a786e310a3
Add back return_value_from_void_function rule (#3882) 2022-04-16 16:53:11 -07:00
Danny Mösch 291b500269
Analyze all files listed in the command even if the `--path` option is used (#3951) 2022-04-15 10:36:29 -04:00
coffmark 564c6ddb55
Lint all files listed in the command even if the `--path` option is used (#3923) 2022-04-13 15:13:08 -04:00
Danny Mösch 870a7be2f4
Revert "Enable `typesafe_array_init` rule in repository" (#3948)
This reverts commit 42a2932883.

See #3942 for the reasons behind the revert.
2022-04-12 15:28:07 -04:00
JP Simard bdb548e1c0
Add a few more possible future Swift versions (#3946)
So tests don't fail on whatever the next Swift releases are.
2022-04-12 11:59:34 -04:00
coffmark 23fe6f4a39
[Test] fix Swift5.6.1 version (#3944) 2022-04-12 11:23:51 -04:00
Chris Hale 9beef23175
Throw error on bad expiring todo date format (#3626) 2022-04-11 21:20:05 +02:00
Danny Mösch 42a2932883
Enable `typesafe_array_init` rule in repository (#3942) 2022-04-10 11:42:58 -04:00
dependabot[bot] 5d7394be0e
Bump cocoapods-downloader from 1.4.0 to 1.6.3 (#3937)
Bumps [cocoapods-downloader](https://github.com/CocoaPods/cocoapods-downloader) from 1.4.0 to 1.6.3.
- [Release notes](https://github.com/CocoaPods/cocoapods-downloader/releases)
- [Changelog](https://github.com/CocoaPods/cocoapods-downloader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/CocoaPods/cocoapods-downloader/compare/1.4.0...1.6.3)

---
updated-dependencies:
- dependency-name: cocoapods-downloader
  dependency-type: indirect
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-05 20:41:14 -04:00
Marcelo Fabri 0fbf010ea4
Only skip autocorrect on files with errors (#3933)
* Only skip autocorrect on files with errors

* Use other kind of warning so tests succeed on Linux

* Update CHANGELOG.md

Co-authored-by: JP Simard <jp@jpsim.com>

Co-authored-by: JP Simard <jp@jpsim.com>
2022-04-05 10:59:50 -07:00
JP Simard cb5fa0425d
Move Analyze CI job to Buildkite (#3919)
We now have two Buildkite agents thanks to a newly added M1 Mac mini
from MacStadium. Running the analyze job should be considerably faster
than the VMs that run on Azure Pipelines, although still slower than
if we were to run them with Xcode 13.2.1 because of the performance
regressions described in https://github.com/realm/SwiftLint/issues/3920.
2022-04-05 12:05:38 -04:00
JP Simard 5897598ba8
[CONTRIBUTING] Add CI section 2022-04-05 11:28:49 -04:00
JP Simard e92a3aeae9
fixup! fixup! Add `--in-process-sourcekit` command line flag 2022-03-31 12:49:12 -04:00
JP Simard 4c14678d77
fixup! Add `--in-process-sourcekit` command line flag 2022-03-31 11:42:42 -04:00
Juozas Valančius a28516d5e8
Create `.artifactbundle` during release 2022-03-31 09:52:22 -04:00
Juozas Valančius 62cc0f1a32
Add `--in-process-sourcekit` command line flag 2022-03-31 09:46:21 -04:00
JP Simard 89ebac11d5
Fix analyzer rules with Xcode 13.3 (#3921)
* Fix analyzer rules with Xcode 13.3

Looks like starting with Xcode 13.3 / Swift 5.6, cursor info requests
started canceling in-flight requests, so we need to pass
`key.cancel_on_subsequent_request: false` to bypass that.

Analyzer rules on Swift 5.6 are extremely slow, however. Not really
usable right now.

* Run analyzer rules one file at a time

* Add changelog entry
2022-03-28 11:58:34 -04:00
Danny Moesch fa2a0bab6c
Move StringView.byteOffset into generally accessible extension (#3917) 2022-03-25 07:27:50 +01:00
JP Simard a773c3ec21
Apply minor changes to the syntactic sugar rewrite (#3915)
* Improve docstrings for `StringView+SwiftSyntax.swift`
* Move changelog entry to correct section & reword
* Change parameter type from `Int` to `ByteCount`
* Move AbsolutePosition / ByteCount conversion to internal API
* Only warn once if syntax tree cannot be parsed
* Move Syntactic Sugar examples to a dedicated file
* Change SyntacticSugarRuleVisitor from SyntaxAnyVisitor to SyntaxVisitor
* Add `SugaredType` enum to help with the implement `SyntacticSugarRule`
2022-03-24 10:27:05 -04:00
JP Simard 9ace4bbb73
Don't pass `--path` to bundle install (#3918)
> [DEPRECATED] The `--path` flag is deprecated because it relies on
> being remembered across bundler invocations, which bundler will no
> longer do in future versions. Instead please use
> `bundle config set path 'vendor/bundle'`, and stop using this flag
2022-03-24 10:12:32 -04:00
Danny Moesch a801bbc83b
Add new type-safe ArrayInitRule (#3914)
The idea of this new Analyzer rule is to filter the calls of `map` before they are passed on to the classic ArrayInitRule which does the detailed checking of the lambda function block. The rule makes sure that only the `map` function is considered that is defined by the `Sequence` protocol.
2022-03-23 22:29:50 +01:00
JP Simard 83a86870bb
Fix false positives in `unused_closure_parameter` (#3916)
When using parameters with backticks.
2022-03-23 16:57:23 -04:00
Paul Taykalo d756541204
Rewrite SyntacticSugarRule using SwiftSyntax (#3866)
Rewrite SyntacticSugarRule with SwiftSyntax
2022-03-23 18:30:43 +02:00
JP Simard 206ff10e6e
Add empty changelog section 2022-03-23 11:34:40 -04:00
JP Simard e5791ec16c
release 0.47.0 2022-03-23 10:58:54 -04:00
Paul Taykalo 1616023b63
Add ability to run only one(focused) example (#3911)
* Add ability to focus on a specific test example

* Update CHANGELOG.md

Co-authored-by: JP Simard <jp@jpsim.com>

* Update CONTRIBUTING.md

Co-authored-by: JP Simard <jp@jpsim.com>

Co-authored-by: JP Simard <jp@jpsim.com>
2022-03-22 19:21:25 +02:00
JP Simard 702b36a781
Revert strip on Docker 2022-03-18 21:01:50 -04:00
JP Simard e06da98b6b
fixup! fixup! Strip binary when building for release 2022-03-18 20:54:07 -04:00
JP Simard a59be8092d
fixup! Strip binary when building for release 2022-03-18 20:44:53 -04:00
JP Simard 91b58c6cbe
Strip binary when building for release
Shaves ~32% off the binary size.

Brings the universal fat binary on macOS from 86MB to 58MB.
2022-03-18 20:43:55 -04:00
Danny Moesch 12cda68ce2
Fix some typos and improve wording/style (#3910) 2022-03-18 17:42:25 -04:00
JP Simard 24bf129268
Run OSSCheck when Package.swift changes (#3909) 2022-03-18 17:13:21 -04:00
JP Simard a256fa2c8c
Bump SwiftSyntax to latest release (#3907)
Fixes https://github.com/realm/SwiftLint/issues/3906

Going from 0.50600.0 to 0.50600.1
2022-03-18 11:59:35 -04:00
JP Simard 21bb280068
Build additional Docker image with Swift 5.5 (#3904)
* Build additional Docker image with Swift 5.5
* Build `swiftlint_linux_swift_5_5.zip`
2022-03-17 17:27:05 -04:00
JP Simard c44a3f4ff9
Add a changelog entry for `IN_PROCESS_SOURCEKIT` 2022-03-17 15:06:24 -04:00
JP Simard 402fe69f59
Add changelog entry for `IN_PROCESS_SOURCEKIT` 2022-03-17 15:05:11 -04:00
JP Simard 87d21e44e6
Edit wording in build phase Homebrew instructions 2022-03-17 13:31:04 -04:00
Michael Henry a129163053
Update applesilicon x brew fix Instruction (#3903) 2022-03-17 13:22:09 -04:00
JP Simard de3569cb3b
Update SwiftSyntax to 0.50600.0 (#3901)
Uses SwiftSyntax 5.5 on Linux when building with Swift 5.5. We use the 5.6 version of
SwiftSyntax when building with Swift 5.5 and 5.6 on macOS because we statically link
`lib_InternalSwiftSyntaxParser` thanks to
https://github.com/keith/StaticInternalSwiftSyntaxParser/releases/tag/5.6.

This keeps SwiftLint binaries portable across machines on macOS, regardless of
_where_ or even _if_ `lib_InternalSwiftSyntaxParser` is installed.

* Run TSan CI job with `--configuration release` to avoid stack overflows
* Add Swift 5.6 CI job
* Fix linker settings
2022-03-17 13:19:48 -04:00
JP Simard ca2712aaee
Make linux zip from GitHub's remote Docker image
Locally I had trouble building the image on both my previous Intel MacBook Pro
and my new M1 Max MacBook Pro.
2022-03-16 11:05:09 -04:00
Marcelo Fabri 0e5d838765
Support #unavailable in deployment_target rule (#3898)
Fixes #3896
2022-03-16 10:41:04 -04:00
JP Simard 84bc2174af
Bump dependencies (#3900)
SourceKitten: 0.31.1 to 0.32.0
SWXMLHash: 5.0.2 to 6.0.0

Also prevent swift-argument-parser from being updated to 1.1.0 which is
incompatible with our macOS version support.
2022-03-15 17:17:42 -04:00
Marcelo Fabri db2721f78e
Require Swift 5.0 in runtime (#3886)
* Require Swift 5.0 in runtime

* Fix violation

* Enable legacy_rule by default

* Update changelog

* Fix changelog after rebase

* More cleanup
2022-03-11 14:01:27 -08:00
JP Simard c664c4f9e6
Move Buildkite pipeline config to repo (#3893)
These were previously defined in Buildkite itself.
2022-03-11 16:27:17 -05:00
JP Simard 1abc50304c
Use alternate implementation of glob with globstar support (#3892)
Adapted from https://gist.github.com/efirestone/ce01ae109e08772647eb061b3bb387c3

The implementation from Pathos seems buggy.

Fixes https://github.com/realm/SwiftLint/issues/3891
2022-03-11 13:24:39 -05:00
Fumito Nakazawa 2ae22d06a2
Support recursive globs (#3843)
ref: https://github.com/realm/SwiftLint/issues/3789

## Overview
Support glob recursive by using [Pathos](https://github.com/dduan/Pathos)
- Introduce Pathos
- Replace glob logic
- Fix some test cases
2022-03-10 21:56:43 -05:00
JP Simard 92e199649d
Fix make package command (#3890) 2022-03-10 20:00:49 -05:00
JP Simard 3273cef42b
Prevent empty files from triggering rule violations (#3885)
There are many valid cases to have an empty Swift source files, and these
shouldn't trigger violations.
2022-03-09 16:09:11 -05:00
JP Simard eeba297f33
[Docs] Remove "experimental" label for analyzer rules (#3884)
These have been fairly stable for over two years at this point.
2022-03-09 14:45:09 -05:00
Marcelo Fabri b619154905
Automatically enforce min Swift version for all rules (#3881)
* Automatically enforce min Swift version for all rules

* Fix violations
2022-03-09 11:44:56 -08:00
tobias 811ca32c6d
`class_delegate_protocol`: Add line break separator for protocol inheritance
clause to match format style with curly brackets on new line
2022-03-09 14:37:47 -05:00
JP Simard 0691a2e7e4
release 0.46.5 2022-03-08 16:35:33 -05:00
JP Simard ebaa6d2182
Add workaround for https://github.com/CocoaPods/CocoaPods/issues/11185 2022-03-08 16:33:17 -05:00
JP Simard 0f3de846d8
push to HEAD in `make push_version` 2022-03-08 16:18:20 -05:00
Danny Moesch 6fa8ff6070
Exclude examples with complex language constructs from the rule documentation (#3880) 2022-03-08 16:04:51 -05:00
Marcelo Fabri f9b9c35c1f
Fix regression in `trailing_closure` rule with Swift 5.6 (#3879)
Fixes #3848
2022-03-08 12:52:07 -08:00
JP Simard 2ae6a55ba4
Fix regression in `unused_import` rule when using Swift 5.6 (#3878)
Fixes https://github.com/realm/SwiftLint/issues/3849
2022-03-08 13:15:39 -05:00
JP Simard 28dd673c48
Use SwiftSyntax visitor to parse commands (#3872)
* Cache SwiftSyntax syntax trees
* Use SwiftSyntax visitor to parse commands
* Update changelog entry
* Cache commands
2022-03-08 12:33:06 -05:00
Keith Smiley 0830eca24c
Add -I to _InternalSwiftSyntaxParser on Linux (#3873)
Since `_InternalSwiftSyntaxParser` isn't in the search paths when building with the `-static-stdlib` flag, we have to manually pass an include path so the swift compiler discovers it. Unfortunately we cannot just pass `-I/usr/lib/swift` because that results in duplicate library errors since the libraries we're linking statically also live there as shared libraries. This first symlinks the module definition to the root of the checkout and uses `.` for the `-I`. Any temporary path could be used instead.
2022-03-08 08:49:24 -08:00
Marcelo Fabri 678c3483ed
Fix regression in `last_where` rule with Swift 5.6 (#3874)
Fixes #3847
2022-03-08 07:53:56 -05:00
Marcelo Fabri 3f24998be5
Fix `closure_parameter_position` rule with Swift 5.6 (#3871)
Fixes #3845
2022-03-07 13:23:31 -08:00
Marcelo Fabri f19555f707
Fix `empty_parentheses_with_trailing_closure` with Swift 5.6 (#3870)
Fixes #3846
2022-03-07 13:39:57 -05:00
JP Simard a43e52aa91
Integrate Swift Syntax in the `force_cast` rule (#3867)
We've tried adding Swift Syntax support to SwiftLint in the past but had to turn it off in https://github.com/realm/SwiftLint/pull/3107 due to distribution and portability issues.

With https://github.com/keith/StaticInternalSwiftSyntaxParser it should be possible to avoid those issues by statically linking the internal Swift syntax parser so it's available no matter where users have Xcode installed on their computer.

By removing all calls to SourceKit (collecting comment commands + checking the current Swift version), there's a really significant performance improvement.

| Framework | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| SourceKit | 517.8 ± 8.3 | 505.5 | 531.1 | 6.59 ± 0.43 |
| SwiftSyntax | 78.6 ± 5.0 | 72.6 | 92.1 | 1.00 |

In practice, the SourceKit overhead will continue being there for as long as any rule being run is still looking up the SwiftLint syntax map though.
2022-03-07 12:51:24 -05:00
JP Simard be1f8596e4
Require Swift 5.5 to build SwiftLint (#3869)
* Disable Swift 5.4 CI jobs
* Remove SwiftLintFramework podspec
  I couldn't find a single use in GitHub's search: https://github.com/search?q=SwiftLintFramework+filename%3APodfile+language%3ARuby+language%3ARuby&type=Code
  Just not worth maintaining anymore.
* Change package swift tools version to 5.5
* Update docker_test to use Swift 5.5 image
* Clean up old Swift versions in SwiftVersionTests
  Even though these older Swift versions should still be supported, these tests
  can't be built against those versions so they're useless.
* Run docker commands with `--platform linux/amd64`
* Remove LinuxMain
  It looks like tests are discovered dynamically on Linux as of recent
  SwiftPM versions.
2022-03-07 12:15:03 -05:00
JP Simard d84be10e66
Add emmpty changelog section 2022-03-07 11:22:38 -05:00
JP Simard f3712b2b93
release 0.46.4 2022-03-07 11:15:27 -05:00
JP Simard ee7eee32b5
release 0.46.3 2022-03-07 11:15:03 -05:00
Marcelo Fabri ff4249856e
Fix false positive in `EmptyEnumArgumentsRule` with Swift 5.6 (#3868)
Fixes #3850
2022-03-07 11:10:15 -05:00
JP Simard 02675a9c09
Fix typo in doc comment: delimeter -> delimiter 2022-03-07 09:27:28 -05:00
Goran Blažič 7b7754ad3b
Ignore MARK in multiline comment (#3844)
Fixes #1749 and #3841
2022-03-04 11:33:12 -05:00
JP Simard 7f9f41aa36
Fix changelog entry position 2022-03-03 12:53:16 -05:00
JP Simard 54a24638a2
Print minimum_fraction_length in description even when unset 2022-03-03 12:49:11 -05:00
Danny Moesch d77d23cbeb
Add option to exclude examples from the rule documentation (#3834)
The option can be used if an example has mainly been added as another test case, but is not suitable
as a user example. User examples should be easy to understand. They should clearly show where and
why a rule is applied and where not. Complex examples with rarely used language constructs or
pathological use cases which are indeed important to test but not helpful for understanding can be
hidden from the documentation with this option.
2022-03-02 10:55:42 -05:00
Danny Moesch 0e7b588d50
Ignore meta class types in `prefer_self_in_static_references` rule (#3832) 2022-03-02 10:52:12 -05:00
JP Simard e6c92f5958
Add empty changelog section 2022-02-22 16:29:32 -05:00
JP Simard 9c81e1a93a
release 0.46.3 2022-02-22 15:29:40 -05:00
JP Simard 932e8f4996
Fix changelog formatting 2022-02-22 15:26:22 -05:00
Takuhiro Muta 867fc1a34c
Update CryptoSwift to 1.4.3 (#3861) 2022-02-19 12:48:11 -05:00
HA Pors 8d0aeb995d
Generate fingerprint with relativefile (#3860)
* Change fingerprint generation to use relativeFile instead of location in order to support CI/CD on multiple machines.

* Created copy of location with relativeFile instead of file to generate fingerprint.

Co-authored-by: Henk Pors <hpors@anwb.nl>
2022-02-17 08:29:16 -08:00
JP Simard 51d97a2037
Add 5.5.3 to `testDetectSwiftVersion()` 2022-02-15 09:24:40 -05:00
Natan Rolnik fe905f8ae9
Fix default rules section in documentation (#3857)
While browsing the rules documentation, I noticed **many** rules were both in the Default Rules and in the Opt In Rules section.

After looking into it, the docs of the `drop(while predicate: (Element) throws -> Bool` function states:

A closure that takes an element of the sequence as its argument and returns true if the element should be skipped or false if it should be included. **Once the predicate returns false it will not be called again.**

This caused the `defaultRuleDocumentations` array to contain almost all `ruleDocumentation`.
2022-02-15 06:23:05 -08:00
Greg c09b6fe3ad
fix typo (#3837) 2022-02-02 15:31:06 -05:00
JP Simard 1864d77f37
Fix testDetectSwiftVersion() test when running with Swift 5.6 2022-01-30 13:35:13 -05:00
Danny Moesch f9be00421e
Rename values for "Enabled by default" property (#3833) 2022-01-29 13:35:09 -05:00
JP Simard 2f2a4ad680
[ClosureEndIndentationRule] Fix crash with Swift 5.6 (#3831)
Fixes https://github.com/realm/SwiftLint/issues/3830
2022-01-27 17:36:31 -05:00
JP Simard f8909b5c0f
Add empty changelog section 2022-01-27 09:46:32 -05:00
JP Simard b4a54f32df
release 0.46.2 2022-01-27 09:16:25 -05:00
JP Simard 23b5c2b0ec
Fix changelog formatting 2022-01-27 09:04:43 -05:00
Steven 09f6f1bc83
Fix `class_delegate_protocol` false positives when using `where` clause (#3829) 2022-01-27 06:03:53 -08:00
JP Simard b107180cf5
[CI] Fix codecov integration (#3828)
This has been broken since we removed the Xcode project in #3414 over a
year ago.
2022-01-25 15:13:14 -08:00
JP Simard d65a708f29
Add Swift 5.5 / Xcode 13.2.1 CI jobs (#3827)
And lint the SwiftLint podspec in addition to the SwiftLintFramework one
2022-01-25 14:33:59 -08:00
JP Simard 068f6037fe
[CI] Move back to Azure Pipelines (#3826)
Yesterday I started moving SwiftLint's CI jobs from Azure Pipelines to
GitHub Actions, which has nicer integrations with GitHub's web UI and
feels nicer & more lightweight overall.

However, GitHub Actions has a serious limitation compared to Azure
Pipelines, which is that it only has 5x macOS job concurrency vs Azure's
10x ([see Twitter](https://twitter.com/simjp/status/1326592600393068546)).
This leads to significant queuing when merging PRs or pushing to PRs in
a short span, which is the main way I work on SwiftLint when catching up
on PR/issue backlog every few months.

A quick timing check showed that a PR using Azure Pipelines (#3825) took
26m 47s vs GitHub Actions (#3824) took 32m 31s. These PRs were opened at
a time when no other CI jobs were running, so even though Azure
Pipelines already took 6 minutes less to run than GitHub Actions, that
difference would be even larger if there had been other PRs triggering
CI jobs at the same time.

So I think the best move for the project for the time being is to stay
with Azure Pipelines for its CI. If GitHub ever increases its macOS
concurrency to match Azure Pipelines's 10x we can explore this again.
2022-01-25 13:56:58 -08:00
JP Simard c5ea00c2d7
Fix CI badges 2022-01-24 23:41:58 -05:00
JP Simard 4525e9999b
Move remaining CI jobs to GitHub Actions (#3822)
Analyze, TSan, Xcode & Docs
2022-01-24 20:29:33 -08:00
JP Simard 006bb2a85e
Sort implicit return configuration description (#3823)
To make the output deterministic
2022-01-24 17:13:12 -08:00
JP Simard 83560fffa7
Move SwiftLint Analyze CI job to GitHub Actions (#3820) 2022-01-24 16:25:39 -08:00
JP Simard 0c731e72da
Bump Xcode version used by jazzy CI job (#3821) 2022-01-24 16:00:22 -08:00
JP Simard 2bd54cf3ce
Move CocoaPods CI jobs to GitHub Actions (#3819) 2022-01-24 15:24:42 -08:00
JP Simard 4c3bb24a04
Move SwiftPM CI jobs to GitHub Actions (#3818) 2022-01-24 14:59:14 -08:00
JP Simard db3422b69a
Move changelog entry from breaking to bug fixes 2022-01-24 13:31:49 -05:00
JP Simard 6ce4766517
Fix pkg installer (#3817) 2022-01-24 18:26:52 +00:00
Danny Moesch a94d120839
Ignore `prefer_self_in_static_references` rule in extensions generally (#3813) 2022-01-24 09:57:57 -08:00
Danny Moesch 0f55447956
Use pre-defined set of extension kinds (#3814) 2022-01-24 09:55:01 -08:00
JP Simard b91b56c14d
Add empty changelog section 2022-01-21 17:11:56 -05:00
JP Simard 61c5351978
release 0.46.1 2022-01-21 16:59:57 -05:00
JP Simard 31872aaa3f
Re-add 'weak_delegate' rule as opt-in
After feedback from users: https://github.com/realm/SwiftLint/pull/3809#issuecomment-1018859093
2022-01-21 16:57:13 -05:00
JP Simard 17779cbfd4
release 0.46.0 2022-01-21 15:57:48 -05:00
JP Simard 73e6cef0c2
Add changelog entry for Docker 2022-01-21 15:52:31 -05:00
Danny Moesch d99be668c5
Ignore more locations of static references not using 'Self' in classes (#3771)
Static references with `Self` are not allowed to define

* default values of properties,
* annotation parameter values and
* default method parameter values

in classes.
2022-01-21 12:43:12 -08:00
JP Simard 3d1821d3c0
Revert "Publish a multi-platform Docker image"
This reverts commits 76dae19b1c &
11e86babc7.
2022-01-21 15:38:21 -05:00
JP Simard 76dae19b1c
fixup! Publish a multi-platform Docker image 2022-01-21 15:36:14 -05:00
JP Simard 11e86babc7
Publish a multi-platform Docker image 2022-01-21 15:33:00 -05:00
JP Simard fb7755adf5
Minor edits to changelog entries 2022-01-21 14:55:01 -05:00
JP Simard e3f232ec28
Fix `convenience_type` false positives when using actors (#3812)
Fixes https://github.com/realm/SwiftLint/issues/3761.
2022-01-21 19:54:59 +00:00
JP Simard d534a30a78
Fix OSSCheck (#3810)
Maybe can fix cases like these: https://github.com/realm/SwiftLint/pull/3803#issuecomment-1008461939
2022-01-21 18:09:59 +00:00
JP Simard 341ec2a907
Remove 'weak_delegate' rule (#3809)
This was very prone to false positives and not worth keeping.

The identifier will stick around for a release to ease the migration.
2022-01-21 17:56:59 +00:00
Sergei aff3536bb8
Fix the regex for expiring-todos. (#3803)
- Make "middle part" `.*` not so greedy with `?`.
- Use `(?!` negative look-ahead to improve matching.
- Added corresponding unit tests.

Co-authored-by: Sergei Shirokov <sshirokov@malwarebytes.com>
2022-01-21 17:42:17 +00:00
Francisco Javier Trujillo Mata c52d4cde8d
Add usage of Docker into the Readme (#3808) 2022-01-21 08:28:19 -08:00
Ikko Ashimine 640efba68d
Fix typo: implict -> implicit 2022-01-21 11:05:21 -05:00
Andrés Cecilia Luque af59581b66
Fix specifying the cachePath from command line (#3797) 2022-01-21 08:01:48 -08:00
Ikko Ashimine 3d7775de11
Fix typo in CommentSpacingRule.swift (#3795)
charcter -> character
2022-01-21 07:47:14 -08:00
Ethan Wong 5fd8ef38c1
Fix malformed doc for rule "InclusiveLanguage". 2022-01-21 10:45:15 -05:00
Ethan Wong bb37a253e2
Add rule identifiers in 'Rule Directory' documentation page. 2022-01-21 10:43:09 -05:00
JP Simard f38083998d
Update docker.yml 2022-01-21 07:39:47 -08:00
Francisco Javier Trujillo Mata a2ada88fd1
Upload Docker Image in to Github Container (#3791) 2022-01-21 07:38:47 -08:00
Paul Williamson 9e37d0fa44
Prevent false triggering of `unused_closure_parameter` when using list bindings (#3799) 2022-01-21 07:35:12 -08:00
Sam Soffes 09d912ca37
Update README.md (#3778)
Since Homebrew installs to a path that isn't in Xcode's path by default, we need to add to the path to support the default location Homebrew installs SwiftLint on Apple Silicon.

From https://stackoverflow.com/a/66003612/118631
2022-01-21 07:02:14 -08:00
grosem c90c329f12
Allow unused_setter_value for overrides (#3653)
Fixes #2585
2022-01-20 22:53:18 +00:00
Ezequiel França 2408839be3
Updating Readme to replace autocorrect by fix (#3779) 2021-12-16 14:08:29 +00:00
JP Simard 027bdcdc95
Fix crash when parsing multi-line attributes with the `attributes` rule (#3776)
Fixes #3761
2021-12-06 16:08:53 +00:00
JP Simard 559685823e
Add empty changelog section 2021-11-29 17:04:02 -05:00
JP Simard 95349376fd
release 0.45.1 2021-11-29 16:47:21 -05:00
JP Simard 4f82adf018
Move changelog entry 2021-11-29 16:44:30 -05:00
iressler 3da6502bac
Fix false positive in legacy_objc_type when a non-legacy Objective-C type name begins with a legacy Objective-C type name. (#3752) 2021-11-29 12:36:27 -08:00
Hannes Ljungberg ed79195cf5
Add support for pre-commit (#3714) 2021-11-29 11:09:43 -08:00
Danny Mösch 050473a0e1
Add optional prefer_self_in_static_references rule (#3732) 2021-11-29 18:42:53 +00:00
Kaitlin Mahar 5429ff642c
Fix false positives with async closures for large_tuple rule (#3754) 2021-11-29 18:06:15 +00:00
Benny Wong 210874f4d8
Documentation: Separate out default rules vs opt in rules in rule list (#3758) 2021-11-29 17:50:14 +00:00
Ikko Ashimine d97bf0951e
Fix typo in StrictFilePrivateRule.swift (#3737)
occurences -> occurrences
2021-11-29 09:47:17 -08:00
Bas Broek 119f9d7f91
Expand README url (#3755)
From https://realm.github.io/SwiftLint/index.html, this would route to `https://realm.github.io/SwiftLint/Source/SwiftLintFramework/Rules`, which does not exist. Explicitly link to GitHub.
2021-11-29 09:21:50 -08:00
JP Simard 2544d7b945
[unused_import] Fix SwiftShims being considered a used import (#3766) 2021-11-29 17:07:38 +00:00
JP Simard 5a98458d94
Add more Swift versions to testDetectSwiftVersion() 2021-11-01 11:39:34 -04:00
JP Simard 292642a815
Add empty changelog section 2021-10-18 12:16:41 -04:00
JP Simard 99465e659f
release 0.45.0 2021-10-18 11:57:37 -04:00
JP Simard 8c3b51ea75
Fix up changelog 2021-10-18 11:54:41 -04:00
Paul Taykalo b519753fd6
Speedup analyzer rules (#3747) 2021-10-18 08:40:15 -07:00
Paul Taykalo 13e1bf709d
Update linux version on CI to Ubuntu 18.04 (#3742) 2021-10-15 08:40:40 -07:00
Paul Taykalo 945efde5f5
Prevent multiple recalculations of capture groups ranges (#3745) 2021-10-15 02:38:18 +03:00
Paul Taykalo a87aee1771
Colon rule should ignore cases when comment is in function argument (#3740) 2021-10-14 16:05:11 +03:00
Marcelo Fabri 383e5b5bc2
Handle `get async` and `get throws` in `implicit_getter` (#3743)
Fixes #3684
2021-10-12 10:32:34 -07:00
uhooi b621fb128f
Bump Swift Argument Parser and SourceKitten (#3733) 2021-10-05 22:00:14 -04:00
Artem Garmash 67114bb729
Exclude `id` from `identifier_name` by default (#3730) 2021-10-04 21:13:40 +00:00
Paul Taykalo 6b8c4442b0
Speed up "computed accessors order" rule (#3727) 2021-10-01 03:07:57 +03:00
Naruki Chigira e4ff164f64
Fix redundant_optional_initialization autocorrect (#3717)
* Fix autocorrect for redundant_optional_initialization in case observer's brace exists.
2021-09-30 23:15:53 +00:00
Marcelo Fabri b63a60df14
Fix false positive in unneeded_break_in_switch (#3725)
Fixes #3724
2021-09-29 12:00:08 -07:00
Marcelo Fabri 4052c43f16 Make rule more generic and rename it 2021-09-29 10:28:39 -07:00
Marcelo Fabri cfa3dff7fe Fix unrelated test 2021-09-29 10:28:39 -07:00
Marcelo Fabri 2674d367f9 Fix violation 2021-09-29 10:28:39 -07:00
Marcelo Fabri eb3a405930 Remove unused function 2021-09-29 10:28:39 -07:00
Marcelo Fabri 68bfc13941 Add add_target_in_variable_declaration_closure rule 2021-09-29 10:28:39 -07:00
Ben Fox 00799cc782
Fixes MissingDocRuleConfiguration (#3713)
* add configuration for missing_docs

* fix MissingDocsRuleConfiguration

* add to changelog

* fix up Config default values and update tests

* use XCTAssertTrue and XCTAssertFalse

* fix line length violation

* finish up unit tests

* rever Package.resolved
2021-09-13 15:23:55 -04:00
Atsuto Yamashita db229aa221
fix typo in ExplicitTopLevelACLRule.swift (#3716) 2021-09-12 19:45:32 -04:00
Atsuto Yamashita 67ba092912
fix a typo of changelog.md (#3715) 2021-09-12 06:46:01 -04:00
JP Simard 4d3217f959
Run CI with Xcode 13 & Swift 5.5 (#3711)
Currently Xcode 13 beta 5, will switch to GM when available.
2021-09-10 09:24:39 -07:00
JP Simard 888619912f
Run CI with Xcode 12.5.1 & Swift 5.4 (#3710)
And require Swift 5.4 or Xcode 12.5 or later to build SwiftLint.
2021-09-10 08:32:02 -07:00
JP Simard f9be1e1ac3
Add empty changelog section 2021-09-10 07:18:51 -04:00
JP Simard e820e750b0
release 0.44.0 2021-09-09 17:59:13 -04:00
Gonzalo RH 9c9e3f54ab
Updated README to mach swift-argument-parser's array parsing strategy. (#3698) 2021-09-09 14:15:21 -07:00
JP Simard 986d98c475
Fix tests on Swift 5.5 / Xcode 13 (#3709) 2021-09-09 21:11:22 +00:00
JP Simard e6301c0d66
Fix changelog formatting 2021-09-09 16:12:09 -04:00
Wolfgang Lutz 7420248c0f
Make Analyzer instructions more clear (#3708)
Instructions originally posted by @timothycosta in https://github.com/realm/SwiftLint/issues/3634#issuecomment-845611219
2021-09-09 12:42:20 -04:00
Ben Fox 1f44d56357
add configuration for missing_docs (#3701)
* `excludes_extensions` defaults to `true` to skip reporting violations
  for extensions with missing documentation comments.
* `excludes_inherited_types` defaults to `true` to skip reporting
  violations for inherited declarations, like subclass overrides.
2021-09-01 21:42:47 +00:00
Adam Wolf 6953fe268e
Fix improper handling of `\ ` in Xcode build logs 2021-09-01 17:08:29 -04:00
Kane Cheshire 55b62cccb3 Updated file name to match type 2021-08-24 00:19:35 -07:00
Kane Cheshire 4a293632c2 Named rule correctly for Sourcery to work properly 2021-08-24 00:19:35 -07:00
Marcelo Fabri b1307de785
Update CHANGELOG.md 2021-08-16 02:24:22 -07:00
Marcelo Fabri 50b6992852 Fix issues with explicit_type_interface on Swift 5.4
Fixes #3615
2021-08-16 02:23:28 -07:00
Marcelo Fabri cc79edd4af Fix issues in ImplicitReturnRule 2021-08-16 02:23:28 -07:00
Marcelo Fabri 9e3f0a8ff8 Fix some rules when using Swift 5.4 2021-08-16 02:23:28 -07:00
Marcelo Fabri 1401d56195
#3664, but for CN 2021-08-16 02:18:32 -07:00
Marcelo Fabri 01b9488c16
#3664, but for KR 2021-08-16 02:18:13 -07:00
Adam Wolf 83e1bee22b
Fix misleading env variable example in README (#3664) 2021-08-16 02:17:30 -07:00
iressler 9aff1e0a8e
This change addresses a false negative case in the RedundantOptionalInitializationRule. (#3671) 2021-08-16 02:01:17 -07:00
dependabot[bot] bc2563175c
Bump addressable from 2.7.0 to 2.8.0 (#3675)
Bumps [addressable](https://github.com/sporkmonger/addressable) from 2.7.0 to 2.8.0.
- [Release notes](https://github.com/sporkmonger/addressable/releases)
- [Changelog](https://github.com/sporkmonger/addressable/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sporkmonger/addressable/compare/addressable-2.7.0...addressable-2.8.0)

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

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-20 06:35:11 -07:00
Ikko Ashimine 81eb0d9b1f
Fix typo in ClosureSpacingRule.swift (#3669)
occurences -> occurrences
2021-07-06 10:41:59 -07:00
Marcelo Fabri 9939c536d5
Add anonymous_argument_in_multiline_closure opt-in rule (#3659)
* Add anonymous_argument_in_multiline_closure opt-in rule

* Restrict match to the closure

* Fixes
2021-06-17 17:03:19 -07:00
Steven Grosmark 300bf77967
Improve `file_length` warnings when excluding comments (#3654)
* Improve `file_length` warnings when excluding comments

* Update changelog

* Update Source/SwiftLintFramework/Rules/Metrics/FileLengthRule.swift

Co-authored-by: Yegor Chsherbatykh <ego1309@yandex.ru>

Co-authored-by: Steven Grosmark <steven.grosmark@ww.com>
Co-authored-by: Yegor Chsherbatykh <ego1309@yandex.ru>
2021-06-17 11:11:17 -07:00
Marcelo Fabri 147f43c1bf
Update CHANGELOG.md 2021-05-24 12:06:26 -07:00
Kane Cheshire 6367ff20c8 Updated triggering examples to indicate where the violation should occur 2021-05-24 12:05:29 -07:00
Kane Cheshire 50169fb556 Removed unused import causing CI to fail 2021-05-24 12:05:29 -07:00
Kane Cheshire 92f76057cf Updated CHANGELOG.md 2021-05-24 12:05:29 -07:00
Kane Cheshire 9c5d3b3c6f Tidy up 2021-05-24 12:05:29 -07:00
Kane Cheshire 3536a86ba1 Added more non-triggering examples 2021-05-24 12:05:29 -07:00
Kane Cheshire 881bd244da Updated swiftlint.yml 2021-05-24 12:05:29 -07:00
Kane Cheshire 91b125b001 Ran sourcery + tidied up 2021-05-24 12:05:29 -07:00
Kane Cheshire d6223893ed Moved description back 2021-05-24 12:05:29 -07:00
Kane Cheshire d7aeea39d9 Adding examples/tests 2021-05-24 12:05:29 -07:00
Kane Cheshire 0dd96d249e Uses correct enumcase instead of enum 2021-05-24 12:05:29 -07:00
Kane Cheshire 538764278b Adding new DisallowNoneCase rule 2021-05-24 12:05:29 -07:00
Marcelo Fabri c1d1390f8f
Update CHANGELOG.md 2021-05-21 14:34:50 -07:00
p-x9 050a10bbd9 Add Test 2021-05-21 14:33:16 -07:00
p-x9 80ca9a7e37 Fix Space appending process when multi byte offsets. 2021-05-21 14:33:16 -07:00
p-x9 7ea514b77a Fixed error in character limit per line. 2021-05-21 14:33:16 -07:00
p-x9 f0c707f477 Fix indents 2021-05-21 14:33:16 -07:00
p-x9 fa06f10c04 Update CHANGELOG 2021-05-21 14:33:16 -07:00
p-x9 04a41bdb2f Fix Autocorrect on no space between the tuple and "in" in unneeded_parentheses_in_closure_argument 2021-05-21 14:33:16 -07:00
Seth Friedman 14ab9fe775
Fix CHANGELOG bad merge from colon violation fix (#3639)
The PR for this change was really old, so when it was merged in it was put under 0.43.1.
In actuality, it's a master change.
2021-05-21 04:15:42 +00:00
raduciobanu002 07c8e52fc8
"Colon Spacing" rule name update (#3583)
* * Changed rule name from "Colon" to "Colon Spacing"
* Updated tests

* Update CHANGELOG.md

Co-authored-by: Seth Friedman <sethfri@gmail.com>
2021-05-20 23:46:54 -04:00
Roger Oba 242151776f
Update number of rules. (#3630) 2021-05-13 10:48:53 -07:00
Steven 625cd180ae
Fix `type_contents_order` initializer detection (#3622) 2021-05-10 09:56:21 -04:00
Dan Loman dd672b4b0c
[bug fix] expiring todo regex (#3597)
* Add failing tests

* Fix regex to allow non-zero-padded dates

* Update changelog

* Update CHANGELOG.md
2021-05-02 17:12:52 -04:00
Valentin Knabel ebb51ed6f7
Add vscode extension to README.md (#3568) 2021-05-02 16:12:15 -04:00
Marcelo Fabri 4e3c87e2f3
Fix false positive in `empty_enum_arguments` (#3616)
Fixes #3562
2021-04-28 20:25:05 -07:00
Marcelo Fabri a10158c475
Add duplicated_key_in_dictionary_literal rule (#3613) 2021-04-28 17:25:08 -07:00
Dylan Maryk 5a3844401b
Fix missing comma in description (#3588) 2021-04-27 22:51:37 -07:00
Iulian Onofrei d712e77bab
Add contributing screenshot with better example arguments (#3604)
Add a screenshot that shows the `--no-cache` argument, because this is
what should be used in most cases, since the cache is enabled by
default, so the debugger won't stop in the implementation of a rule on a
subsequent run.

Also update the second screenshot from the same macOS version (Big Sur)
for consistency.
2021-04-27 22:48:12 -07:00
Keith Smiley 7976b74615
Add test functions with parameters to TestCaseAccessibilityRule (#3612)
If a function starts with `test` but takes some parameters, it is not
actually a test.
2021-04-26 20:04:04 +00:00
JP Simard deb7ffb355
Update ruby gems for Apple Silicon support 2021-04-25 08:42:21 -04:00
dependabot[bot] 86b6392aa2
Bump kramdown from 2.3.0 to 2.3.1 (#3585)
Bumps [kramdown](https://github.com/gettalong/kramdown) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/gettalong/kramdown/releases)
- [Changelog](https://github.com/gettalong/kramdown/blob/master/doc/news.page)
- [Commits](https://github.com/gettalong/kramdown/commits)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-03-29 14:10:37 -07:00
JP Simard 4039eff984
Release 0.43.1 2021-03-15 13:13:51 -04:00
JP Simard 60ec029e1b
Re-add --format flag to reformat Swift files using SourceKit (#3573)
Missed during the migration from Commandant to swift-argument-parser in
https://github.com/realm/SwiftLint/pull/3465.

Fixes https://github.com/realm/SwiftLint/issues/3571.
2021-03-15 11:15:09 -04:00
Stephen Williams c1b77f8e0a
Rename the “File Line Length” rule to just “File Length” 2021-03-08 09:29:51 -05:00
JP Simard 058869f446
Require Swift 5.3 or higher to build (#3553)
* Require Swift 5.3 or higher to build

* Remove Swift Version Support tables from readmes

These weren't exactly accurate because SwiftLint should still work with
older Swift versions long after we update the minimum version of Swift
needed to _build_ the tool. So I doubt this table was very helpful to
anyone.
2021-03-04 18:07:04 +00:00
JP Simard ca559c70df
Add empty changelog section 2021-03-03 16:14:58 -05:00
JP Simard da2ca76953
release 0.43.0 2021-03-03 16:01:42 -05:00
JP Simard e47fb60c7a
Regenerate Sourcery output 2021-03-03 15:41:50 -05:00
JP Simard 92061e84b5
Merge pull request #3550 from realm/fix-oss-check-noise
Fix OSSCheck noise
2021-03-03 15:10:40 -05:00
JP Simard aa32742abf
Revert OSSCheck changes for faster debugging 2021-03-03 14:43:37 -05:00
JP Simard 027f130e8c
fixup! Fix OSSCheck noise 2021-03-03 11:36:09 -05:00
JP Simard 8b145d4ba4
Merge pull request #3549 from realm/fix-parsing-xcode-logs-for-analyzer-rules-for-target-names-with-spaces
Fix parsing xcode logs for analyzer rules for target names with spaces
2021-03-03 11:35:02 -05:00
JP Simard 7f7fc03a8f
Fix OSSCheck noise
Try a few things:

1. Sort InclusiveLanguageRule terms since they're a Set and don't have
  deteministic ordering (will definitely help)
2. Fetch remote at the beginning of the script (likely to help)
3. Only fetch remote once (likely to help)
4. Sort branch & master output before diffing (unlikely to help)
5. Change diff filter from `d` to `AMRCU` (no idea if it will help)
2021-03-03 11:19:41 -05:00
JP Simard eec4c58e1f
Fix parsing xcode logs for analyzer rules for target names with spaces 2021-03-03 10:36:22 -05:00
László Kustra 87d4accb39
Add "Capture non-constant variable" rule 2021-03-02 16:11:33 -05:00
JP Simard fa1154c9a8
Merge pull request #3547 from realm/file-false-negatives-in-unused_declaration
File false negatives in unused_declaration
2021-03-02 12:05:02 -05:00
JP Simard 0a0fb1e71b
File false negatives in unused_declaration
When a declaration refers to an Objective-C type but doesn't have an
explicit `@objc` attribute.

It would have the string `@objc` embedded in its USR. So add a space so
we only trigger this condition when there's an explicit `@objc`
attribute in the declaration source code.

The triggering example added here didn't trigger before this change.
2021-03-02 11:36:06 -05:00
Otavio Cordeiro fd97e2259c
Merge pull request #3495 from otaviocc/oc/xctests_setup_teardown
Add opt-in rule balanced_xctest_lifecycle
2021-03-01 02:40:46 +01:00
Otavio Cordeiro 24122e1325
Rename Rule to BalancedXCTestLifecycleRule 2021-03-01 01:29:16 +01:00
Otavio Cordeiro a6a5e633d0
Add support to unbalanced teardown methods 2021-03-01 01:18:30 +01:00
Otavio Cordeiro 7c1b5ff757
Update CHANGELOG after git rebase 2021-02-28 23:49:27 +01:00
Otavio Cordeiro a4820f49c2
Update CHANGELOG after git rebase 2021-02-28 23:48:06 +01:00
Otavio Cordeiro 3fbc482a2e
Add MARKs
to trigger a new build.
2021-02-28 23:48:06 +01:00
Otavio Cordeiro cdd877c289
Add examples for static setUp and tearDown 2021-02-28 23:48:06 +01:00
Otavio Cordeiro bd4dcd5b23
Add required_xctest_tearddown opt-in rule 2021-02-28 23:48:05 +01:00
JP Simard 9d02cec17f
Merge pull request #3543 from realm/feature/fix-changelog-typo
Fix typo in changelog
2021-02-26 17:22:08 -05:00
Frederick Pietschmann 3d0c87738c Fix typo in changelog 2021-02-26 23:09:54 +01:00
JP Simard 43083f6537
Merge pull request #3542 from realm/relative-config
Fix issue that prevented the inclusion of a configuration file from a parent folder
2021-02-26 13:00:46 -05:00
JP Simard fed8644e01
Remove duplicate disable commands 2021-02-26 12:09:40 -05:00
JP Simard 2009b00366
Add entry to breaking section of changelog 2021-02-26 11:58:14 -05:00
JP Simard 3e04acd97d
Revert "Revert "Fix issue that prevented the inclusion of a configuration file from a parent folder (#3491)""
This reverts commit b66f7c7992.
2021-02-26 11:44:10 -05:00
JP Simard 9182eda98c
Disable file & type body length rules in ConfigurationTests 2021-02-26 10:37:47 -05:00
JP Simard 8c29a89888
Fix changelog spacing 2021-02-25 17:21:29 -05:00
JP Simard 706abfe9e3
Tweak the auto-correction result console output for clarity (#3522)
A colleague was confused by the output of `swiftlint autocorrect`, she
couldn't understand why SwiftLint told her it corrected thousands of
files when she only touched one.

The "Done correcting \(files.count) ..." output made her think that a
change was made on each of the `files`, when really they had only been
inspected.

A good solution would be to adopt a similar approach as the `lint`
command does.

Not being familiar with the codebase, I though a good first step could
have been to tweak the message a bit, making it clearer that the count
printed to the console is the inspected files.
2021-02-25 17:20:58 -05:00
JP Simard 5b1d737683
Merge pull request #3538 from realm/feature/fix-custom-rules-merging
Multiple fixes for custom rules
2021-02-25 16:14:50 -05:00
JP Simard 4e2a569aac
Add SWIFTLINT_LOG_MODULE_USAGE environment variable for UnusedImportRule (#3539)
That's because it can currently be difficult to know why a module is
referenced in a file.

To use, run SwiftLint with the environment variable set to the module
whose references you want to log to `stderr`:

    SWIFTLINT_LOG_MODULE_USAGE=MyModule swiftlint analyze ...
2021-02-25 15:25:31 -05:00
JP Simard 8b6167c7f2
Add changelog entry 2021-02-25 14:54:51 -05:00
JP Simard 721b077608
Add SWIFTLINT_LOG_MODULE_USAGE environment variable for UnusedImportRule
That's because it can currently be difficult to know why a module is
referenced in a file.

To use, run SwiftLint with the environment variable set to the module
whose references you want to log to `stderr`:

    SWIFTLINT_LOG_MODULE_USAGE=MyModule swiftlint analyze ...
2021-02-25 14:53:07 -05:00
JP Simard b66f7c7992
Revert "Fix issue that prevented the inclusion of a configuration file from a parent folder (#3491)"
This reverts commit 2f6fd1e95f.
2021-02-25 14:49:10 -05:00
Frederick Pietschmann 235f598ac7 Fix custom rules bug when using only_rules mode 2021-02-25 19:22:57 +01:00
Frederick Pietschmann 0dfb04b25a Add 2 new tests for custom rules when in only_rules mode 2021-02-25 19:22:57 +01:00
Frederick Pietschmann 520d224719 Revert "Revert "Merge pull request #3473 from realm/feature/3472-fix-custom-rules-merging" (#3503)"
This reverts commit 6a38b15657.
2021-02-25 19:22:57 +01:00
JP Simard 8326624491
Make discarded_notification_center_observer opt-in (#3537)
It's very common for this rule to produce false positives, and there's
no easy way to address them.

See these issues:
  * https://github.com/realm/SwiftLint/issues/1398
  * https://github.com/realm/SwiftLint/issues/3498
2021-02-25 09:06:00 -08:00
JP Simard 62d558eb53
Fix changelog whitespace 2021-02-24 17:31:53 -05:00
JP Simard 21cf0b77db
Fix changelog entry location 2021-02-24 17:30:04 -05:00
Artem Garmash 4266ea9d60
Add Bool violation reporting in `redundant_type_annotation` (#3438)
* Add Bool violation detection

* Update Changelog

* Fix issues found by the rule
2021-02-24 14:29:08 -08:00
Bradley Walters 5eb00b79cc
Update CodeClimateReporter to produce relative paths (#3499)
GitLab and the CodeClimate spec both expect these paths to be relative.

https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#implementing-a-custom-tool
690633cb2a/spec/analyzers/SPEC.md (locations)
2021-02-24 14:16:18 -08:00
JP Simard 559470a245
Integrate OS Signposts to help profile SwiftLint performance (#3535)
* Integrate OS Signposts to help profile SwiftLint performance

* Split LintOrAnalyzeCommand.lintOrAnalyze(_:) into two functions

Using a builder reference type to share common mutable state.
2021-02-24 10:03:53 -08:00
Frederick Pietschmann 2f6fd1e95f
Fix issue that prevented the inclusion of a configuration file from a parent folder (#3491)
* Add (currently failing) test for #3485

* [#3485] Add missing rootDir adjustment for included / excluded paths

* Add changelog entry

* Adjust tests for relative included / excluded paths
2021-02-23 18:19:19 -05:00
Thomas Goyne 8f216b8398
Support Swift Playground control comments in the comment spacing rule
Swift Playgrounds use `//:` to mark prose sections and `//:#` for embedded
content like images and localized prose, so those shouldn't violate the
space-after-comment rule.
2021-02-23 17:33:20 -05:00
leogdion 3643fea111
adding platform specification to Swift package (#3482) 2021-02-23 13:29:55 -08:00
JP Simard 402e76b33d
Add a few more possible upcoming versions to testDetectSwiftVersion
To give us more lead time before we need to update this again.
2021-02-23 16:27:27 -05:00
JP Simard eca9ea4bb8
Adding Legacy ObjC Type Rule #2758 (#3531) 2021-02-23 12:08:01 -08:00
Christian Mitteldorf 4e75099e16
Link to Ray Wenderlich’s Swift Style guide (#3250)
GitHub has archived their current style guide.
The style guide from Wenderlich closely follows the existing rules, and is still being maintained.
2021-02-23 12:07:07 -08:00
JP Simard cfd67b9534
Make strong-iboutlet rule correctable (#3530)
* Make strong-iboutlet rule correctable

* fixup! Make strong-iboutlet rule correctable

Co-authored-by: Max Haertwig <dev@maxhaertwig.com>
2021-02-23 11:37:23 -08:00
JP Simard 08fbd043c0
Remove stale probot config (#3529)
I believe this will completely remove the bot.

Rationale: https://github.com/realm/SwiftLint/pull/3385#issuecomment-784411782

> I've changed my mind on this. I believe this is solving the wrong
> problem. It can be very disappointing for users when their issues /
> PRs remain ignored by maintainers for a long time, but I think it's
> worse when issues / PRs are automatically closed, and I don't think it
> actually helps with the health of the project, or make maintainer's
> lives easier.
>
> I can't guarantee anything, but I am working on a plan to improve the
> maintainership of SwiftLint moving forward, and hopefully that can be
> more impactful when it comes to responsiveness to community issues and
> PRs, and I believe that's a better way to triage issues and PRs.
2021-02-23 10:49:14 -08:00
JP Simard 6b51c3ebc5
[UnusedDeclarationRule] Fix false positives with result builders (#3528) 2021-02-23 07:59:37 -08:00
JP Simard 60242fd599
[UnusedDeclarationRule] Allow configuration related USRs to skip (#3525)
For example you might have custom source tooling that does something
with types conforming to a procotol even if that type is never
explicitly referenced by other code.
2021-02-17 12:25:23 -08:00
Gio Lodi ff1ca8fd5a
Update changelog with entry for #3522 2021-02-17 12:19:52 +11:00
Gio Lodi 8248178213
Tweak the auto-correction result console output for clarity
A colleague was confused by the output of `swiftlint autocorrect`, she
couldn't understand why SwiftLint told her it corrected thousands of
files when she only touched one.

The "Done correcting \(files.count) ..." output made her think that a
change was made on each of the `files`, when really they had only been
inspected.

A good solution would be to adopt a similar approach as the `lint`
command does.

Not being familiar with the codebase, I though a good first step could
have been to tweak the message a bit, making it clearer that the count
printed to the console is the inspected files.
2021-02-16 20:41:04 +11:00
Otavio Cordeiro 46777539ad
Add opt-in rule private_passthrough_subject (#3504) 2021-02-08 10:43:27 -08:00
Colton Schlosser 01a0f82e99
Improve parallelMap implementation by removing iteration for force unwrapping every element (#3517) 2021-02-08 06:37:20 -05:00
Otavio Cordeiro 7ea9b733ff
Allow multi-line parameters rule to always break lines (#3494) 2021-02-02 13:27:29 -08:00
DwayneCoussement f66c51b9f2
Update tests to support Swift 5.3.3 (#3509) 2021-02-02 07:18:31 -08:00
JP Simard bbf1ad4a18
[ExplicitSelfRule] Fix violation location and misplaced corrections (#3507) 2021-01-29 10:59:28 -08:00
Otavio Cordeiro 59eb887cfa
Add opt-in rule discouraged_assert (#3506)
Co-authored-by: Keith Smiley <keithbsmiley@gmail.com>
2021-01-29 09:30:57 -08:00
JP Simard 6a38b15657
Revert "Merge pull request #3473 from realm/feature/3472-fix-custom-rules-merging" (#3503)
This reverts commit 537e53f6b3, reversing
changes made to ba49f7d309.
2021-01-22 10:31:05 -08:00
JP Simard 6de5771899
[Analyze] Support compile commands with relative paths (#3501)
* [Analyze] Support compile commands with relative paths

* Add changelog entry

And made small formatting edits to other recent entries.
2021-01-22 09:44:30 -08:00
Frederick Pietschmann 537e53f6b3
Merge pull request #3473 from realm/feature/3472-fix-custom-rules-merging
Multiple Fixes for custom rules
2021-01-15 11:53:17 +01:00
Frederick Pietschmann 22d25da7fc Add newline at end of yml test file 2021-01-15 00:14:50 +01:00
Frederick Pietschmann 2d17045b11 [#3477] Fix bug that prevented the reconfiguration of a custom rule in a child config 2021-01-14 23:35:21 +01:00
Frederick Pietschmann a39e72ef13 Fix changelog 2021-01-14 23:35:21 +01:00
Frederick Pietschmann 56e4f175ac Fix if statement formatting 2021-01-14 23:35:21 +01:00
Frederick Pietschmann 5bffc77af6 Fix custom_rules merging when a configuration is based on only_rules 2021-01-14 23:35:21 +01:00
Frederick Pietschmann e3e169b4b9 Add changelog entry 2021-01-14 23:35:21 +01:00
Frederick Pietschmann 256288ab88 Separate custom rules merging & filtering to avoid misleading warnings 2021-01-14 23:35:21 +01:00
dependabot[bot] ba49f7d309
Bump redcarpet from 3.5.0 to 3.5.1 (#3487)
Bumps [redcarpet](https://github.com/vmg/redcarpet) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/vmg/redcarpet/releases)
- [Changelog](https://github.com/vmg/redcarpet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vmg/redcarpet/compare/v3.5.0...v3.5.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-11 12:21:59 -08:00
Marcelo Fabri d10b80d49f
Merge pull request #3474 from realm/feature/swift-532
Add 5.3.2 to testDetectSwiftVersion()
2020-12-20 23:31:51 -08:00
Frederick Pietschmann 0a0e3f50eb Add 5.3.2 to testDetectSwiftVersion() 2020-12-20 15:56:14 +01:00
Frederick Pietschmann 81b12739df
Merge pull request #3467 from advantis/bugfix/file-name-options
Fix typos in configuration options for file_name rule
2020-12-20 15:46:53 +01:00
Yurii Kotov dacfdcef40
Add changelog entry 2020-12-17 16:55:03 +02:00
Yurii Kotov 6dba929b4f
Fix typos in configuration options for file_name rule 2020-12-16 19:56:50 +02:00
JP Simard 5134545093
Make `--strict` mutually exclusive with `--lenient` 2020-12-14 15:54:08 -05:00
JP Simard 7351648590
Fix paths argument handling 2020-12-14 15:53:50 -05:00
JP Simard 6bad2eccdf
Remove unused imports 2020-12-14 15:53:49 -05:00
JP Simard 4a94f6a894
Add changelog entry 2020-12-14 15:53:49 -05:00
JP Simard fa55508668
Migrate from Commandant to swift-argument-parser 2020-12-14 15:51:04 -05:00
JP Simard 82b00bf4b5
Rename command files 2020-12-14 15:51:04 -05:00
JP Simard e7f4a8fd67
Update SourceKittenFramework to 0.31.0 2020-12-14 15:51:04 -05:00
JP Simard 2436f669fe
Add empty changelog section 2020-12-14 15:49:31 -05:00
JP Simard d53fc2664d
release 0.42.0 2020-12-14 15:26:56 -05:00
JP Simard 40cf2ddef2
Fix false positives on unused_declaration for outlets with accessors (#3462)
* Fix false positives on unused_declaration for outlets with accessors

* Also willSet/didSet

* fixup! Fix false positives on unused_declaration for outlets with accessors
2020-12-11 10:03:20 -08:00
JP Simard ab6aeed5b1
Replace non_private_xctest_member with test_case_accessibility (#3464)
in `.swiftlint.yml`.
2020-12-11 09:05:02 -08:00
JP Simard 9c672c774c
Update Yams 2020-12-11 11:20:00 -05:00
JP Simard ebca5238a7
Fix false positives on unused_declaration for outlets with accessors 2020-12-11 10:07:22 -05:00
JP Simard f8bc10aaaa
Merge pull request #3460 from realm/dont-log-a-warning-if-no-configuration-files-were-explicitly-specified
Don't log a warning if no configuration files were explicitly specified
2020-12-11 10:02:41 -05:00
JP Simard 01b1001a81
fixup! Don't log a warning if no configuration files were explicitly specified 2020-12-11 10:02:16 -05:00
JP Simard cb3eed544c
Add FileGraphInitializationResult to make error handling more explicit 2020-12-11 09:27:51 -05:00
JP Simard 12cea6b9c7
fixup! Don't log a warning if no configuration files were explicitly specified 2020-12-10 09:39:49 -05:00
JP Simard ab700a3262
Re-add warning message if the config file was implicit and misconfigured
Thanks fredpi!
2020-12-10 09:37:09 -05:00
JP Simard d75b9c45df
Remove unused error case 2020-12-09 17:18:21 -05:00
JP Simard 35d75809c9
Fix typo 2020-12-09 17:16:50 -05:00
JP Simard 2b50902d1a
Revert most changes, just don't log a warning 2020-12-09 17:14:04 -05:00
JP Simard d010569f1d
Extract out error string generation 2020-12-09 16:26:10 -05:00
Keith Smiley 800030ad11
Remove NonPrivateXCTestMembersRule (#3459)
* Remove NonPrivateXCTestMembersRule

I accidentally implemented this rule twice. So TestCaseAccessibilityRule
did the same thing but with a bit more behavior. This change deletes
NonPrivateXCTestMembersRule but also ports over the autocorrection from
it to TestCaseAccessibilityRule.
2020-12-09 13:16:40 -08:00
JP Simard 82e5870a16
Don't log a warning if no configuration files were explicitly specified
And none was found at the default location of `.swiftlint.yml`.
2020-12-09 16:16:04 -05:00
JP Simard 71449e76b7
Merge pull request #3455 from realm/add-dockerfile
Add Dockerfile
2020-12-09 09:14:19 -05:00
Keith Smiley 22ee449971
Fix @IBInspectable unused declarations with get/set (#3458) 2020-12-07 11:07:16 -08:00
JP Simard c521e54e7e
Merge pull request #3457 from jrturton/weak-delegate-exception-for-@UIApplicationDelegateAdaptor
Add exception for UIApplicationDelegateAdaptor
2020-12-04 16:46:12 -05:00
richard.turton 4357eed219 Updated changelog 2020-12-04 17:08:51 +00:00
richard.turton 103cf7504a Fixed whitespace violations 2020-12-04 17:01:47 +00:00
richard.turton 62298de662 Add exception for UIApplicationDelegateAdaptor 2020-12-04 16:45:51 +00:00
Norio Nomura a84aee23df
[Makefile] Update zip_linux target to depending Dockerfile
Hiding dependencies required at build time in the Dockerfile
2020-12-05 00:25:42 +09:00
Norio Nomura 4e61c8436c
[Docker] Add Dockerfile
Provides:
- a runtime environment on ubuntu that does not include the Swift toolchain.
- supportintg `docker build https://github.com/realm/SwiftLint.git`
- add `libcurl4-openssl-dev` as build time dependency that introduced by #3058
2020-12-05 00:22:54 +09:00
Keith Smiley 03f13e5bb7
Remove @IBOutlet and @IBInspectable from UnusedDeclarationRule (#3432)
The original implementation wasn't tested so it regressed.

https://github.com/realm/SwiftLint/pull/3184
2020-12-03 11:00:53 -08:00
JP Simard 0c5136d725
Merge pull request #3451 from realm/fix-paths-log
Fix logging linting the current working directory
2020-12-01 15:12:09 -05:00
JP Simard f926cfaabd
fixup! fixup! Fix logging linting the current working directory 2020-12-01 14:47:25 -05:00
JP Simard 0019c61de7
fixup! Fix logging linting the current working directory 2020-12-01 14:46:46 -05:00
JP Simard b73673ab01
Fix logging linting the current working directory
Fixes log messages saying `Linting files at path ''` that should have
said `Linting files in current working directory`.
2020-12-01 14:34:16 -05:00
JP Simard 231ef2b5db
Indent changelog entry 2020-11-23 16:52:17 -05:00
JP Simard be21dc3b4b
Add scrip/get-version script
Previous way wasn't working and this way we edit one less file when
pushing new versions.
2020-11-23 11:15:52 -05:00
JP Simard f0f0086aca
Merge pull request #3443 from realm/remove-info.plist-files
Remove Info.plist files
2020-11-23 10:47:36 -05:00
Frederick Pietschmann b8f5b6a30e
Merge pull request #3058 from realm/feature/remote-child-parent-configs
Add remote, parent & child configuration features
2020-11-22 10:55:16 +01:00
Frederick Pietschmann 26aae94f1b Drop unneeded import statement 2020-11-21 00:58:24 +01:00
Frederick Pietschmann 28cb43afa9 Fix test resources access on Linux 2020-11-21 00:35:34 +01:00
Frederick Pietschmann 715a8db2db Adjust file naming in child / parent config tests 2020-11-21 00:20:40 +01:00
Frederick Pietschmann 495d742f65 Fix issues originating from new set semantics 2020-11-21 00:05:42 +01:00
Frederick Pietschmann 4c5a3f0577 Add remote, parent & child configuration features 2020-11-20 23:08:37 +01:00
JP Simard 69250c9cd5
Merge pull request #3442 from realm/fix-deprecation-compiler-warnings-on-linux-for-showdocscommand.swift
Fix deprecation compiler warnings on Linux for ShowDocsCommand.swift
2020-11-20 15:26:44 -05:00
JP Simard f45f381320
fixup! Remove Info.plist files 2020-11-20 15:25:50 -05:00
JP Simard e143a18e5c
Remove Info.plist files
These are no longer needed now that we removed the Xcode project.
2020-11-20 15:01:09 -05:00
JP Simard 8bf8ca482a
Fix deprecation compiler warnings on Linux for ShowDocsCommand.swift 2020-11-20 15:00:54 -05:00
Dalton Claybrook ba5e6d2e1c
Fix false positives in inclusive_language rule (#3439)
* Add support for allowed terms in inclusive language rule

* Update changelog

* Move changelog entry to Enhancements section

Co-authored-by: JP Simard <jp@jpsim.com>
2020-11-20 14:12:24 -05:00
JP Simard cd9cf682e7
Merge pull request #3441 from realm/fix-how-test-failures-are-rendered
Fix how test failures are rendered
2020-11-20 11:55:02 -05:00
JP Simard 36263cd0b9
Merge pull request #3431 from realm/ks/add-support-for-testing-examples-with-configuration
Add support for testing Examples with configuration
2020-11-20 11:53:25 -05:00
JP Simard 5a077d9f3f
Fix how test failures are rendered 2020-11-20 11:19:27 -05:00
JP Simard 42373a94b6
Remove example failing test
This is hard to fix, and already covered by the corrections.
2020-11-20 11:18:07 -05:00
JP Simard 5f057d5ebf
Merge pull request #3437 from realm/build-universal-binary
[Makefile] Build `swiftlint` as a universal binary on macOS
2020-11-19 07:14:50 -05:00
Norio Nomura 88d77a3211
[Makefile] Build `swiftlint` as a universal binary on macOS
SwiftPM 5.3 uses the `XCBuild.framework` to generate universal binaries when it receives multiple `--arch` options.
In that case, `--show-bin-path` returns `.build/apple/Products/Release`.
2020-11-19 18:48:11 +09:00
JP Simard b484d439b8
Merge pull request #3434 from realm/static-stdlib-zip-linux
Use `-static-stdlib` on building Linux binary for release artifacts
2020-11-18 08:51:43 -05:00
Norio Nomura 97052faf18
Use `-static-stdlib` on building Linux binary for release artifacts
This change prevents `swiftlint` from having links to shared libraries belonging to `/usr/lib/swift`.
```
$ docker run -v$PWD:$PWD -w$PWD --rm swift sh -c 'ldd $(swift build -c release --show-bin-path)/swiftlint'
	linux-vdso.so.1 (0x00007ffee8bb8000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f75e750b000)
	libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f75e7308000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f75e7104000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f75e6d66000)
	libxml2.so.2 => /usr/lib/x86_64-linux-gnu/libxml2.so.2 (0x00007f75e69a5000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f75e661c000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f75e6404000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f75e6013000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f75ea7bf000)
	libicuuc.so.60 => /usr/lib/x86_64-linux-gnu/libicuuc.so.60 (0x00007f75e5c5b000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f75e5a3e000)
	liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f75e5818000)
	libicudata.so.60 => /usr/lib/x86_64-linux-gnu/libicudata.so.60 (0x00007f75e3c6f000)
```
I confirmed that `swiftlint` produced by `make zip_linux` works with following docker images:
- swift:5.3.1-xenial
- swift:5.3.1-bionic
- swift:5.3.1-focal
- swift:5.3.1-centos8
- swift:5.3.1-amazonlinux2
- norionomura/swift:5.3.1
- norionomura/swift:5.3.0
- norionomura/swift:5.2.5
- norionomura/swift:5.1.5
- norionomura/swift:5.0.3
2020-11-18 21:39:31 +09:00
Keith Smiley e50e34a60a Add another 2020-11-16 15:54:23 -08:00
Keith Smiley b7ec75b68b Add support for testing Examples with configuration
This was extracting from another change that no longer needed it. It
should be helpful for anyone testing custom configuration with their
non-analyzer rules.

I added a random example of something that wasn't previously tested as
an example.
2020-11-16 15:37:15 -08:00
Keith Smiley 866102c3fc
Add XCTestCase examples to unused declaration rule (#3192) 2020-11-16 15:32:51 -08:00
Keith Smiley 3151e6c45f
Add NonPrivateXCTestMembersRule (#3248)
Co-authored-by: JP Simard <jp@jpsim.com>
2020-11-16 09:50:56 -08:00
JP Simard 07f559549a
Rename OverridenSuperCallConfiguration to fix typo (#3426)
* BREAKING CHANGE: As `OverridenSuperCallConfiguration` is a
publicly-exposed struct, this rename should be considered breaking.

* Fix consoleDescription for OverriddenSuperCallConfiguration
2020-11-11 13:37:12 -05:00
Jan-Otto Kröpke 874cacbd1f
Add codeclimate reporter (#3425) 2020-11-11 10:29:00 -08:00
Bryan Ricker 999bfbdefa Fix consoleDescription for OverriddenSuperCallConfiguration 2020-11-10 20:40:41 -08:00
Bryan Ricker 8a0eb67561 chore: rename OverridenSuperCallConfiguration to OverriddenSuperCallConfiguration
BREAKING CHANGE: As `OverridenSuperCallConfiguration` is a
publicly-exposed struct, this rename should be considered breaking.
2020-11-10 20:40:41 -08:00
Noah Gilmore 2e26e9cd93
Merge pull request #3416 from noahsark769/noahsark769/comment-spacing-rule-updated
Add CommentSpacingRule (#3233)
2020-11-10 17:08:40 -08:00
Noah Gilmore 6d4487c517 Fix a few test which failed due to comment_spacing being a default rule 2020-11-10 16:08:25 -08:00
JP Simard bf2790df54
Enable CommentSpacingRule by default
And fix violations in SwiftLint
2020-11-10 12:50:39 -05:00
JP Simard 869fe868b3
Apply minor refactorings
1. Add some comments
2. Name variables when used in multiline closures
3. Change violation range length from 1 to 0, which simplifies the
   substitution
4. Tweak indentation
2020-11-10 12:42:40 -05:00
JP Simard 30db88dde3
Add double trailing space to changelog entry 2020-11-10 12:28:28 -05:00
Noah Gilmore 5185afc4a4 Update Changelog 2020-11-09 21:57:01 -08:00
Noah Gilmore 5108233ac5 Further PR comments 2020-11-09 21:54:14 -08:00
Noah Gilmore 6bd38e8607 Update Source/SwiftLintFramework/Rules/Lint/CommentSpacingRule.swift
Co-authored-by: JP Simard <jp@jpsim.com>
2020-11-09 21:54:14 -08:00
Noah Gilmore 442eac2556 Update Source/SwiftLintFramework/Rules/Lint/CommentSpacingRule.swift
Co-authored-by: JP Simard <jp@jpsim.com>
2020-11-09 21:54:14 -08:00
Noah Gilmore 3508ef8e1e Add changelog entry 2020-11-09 21:54:14 -08:00
Noah Gilmore 1a104e4dc4 Add comments 2020-11-09 21:54:14 -08:00
Noah Gilmore dd5c0d3599 Add CommentSpacingRule (#3233) 2020-11-09 21:54:14 -08:00
JP Simard eb0c1b271f
Fix changelog entry 2020-11-09 17:44:50 -05:00
JP Simard d9b5df2d72
Merge pull request #3254 from realm/ks/add-always_keep_imports-to-unusedimportrule
Add 'always_keep_imports' to UnusedImportRule
2020-11-09 17:43:20 -05:00
JP Simard ddfba6ea5d
Fix duplicate changelog entry 2020-11-09 13:16:29 -05:00
JP Simard d319ad1c8b
Merge pull request #1645 from Skoti/feature/distinguish_types_and_statements_nesting
Separating level counting for types and functions in `nesting` rule.
2020-11-09 12:56:17 -05:00
JP Simard 6c370caa77
Fix indentation 2020-11-09 12:06:45 -05:00
JP Simard 46ed5e2ece
Add print statement for deprecation
To indicate that `statement_level` has been renamed to `function_level`.
2020-11-09 12:06:45 -05:00
JP Simard aa02a8aec0
Apply small refactorings 2020-11-09 12:06:44 -05:00
JP Simard 0788cd237c
Format changelog entries 2020-11-09 12:06:34 -05:00
Skoti b9841595a5
Separated nesting level counting for types and functions in `nesting` rule (fixes #1151). Enhanced `nesting` rule to search for nested types and functions within closures and statements. Enhanced `nesting` rule to allow for one nested type within a function even if breaking a maximum type level nesting (fixes #1151). 2020-11-09 12:06:34 -05:00
JP Simard 474cb2bd29
Reword changelog entry 2020-11-09 12:05:15 -05:00
JP Simard 5e23fbdd3e
Merge pull request #3418 from agarmash/unavailable_function_never
Rule Modification: Don't trigger `unavailable_function` for a function that returns `Never`
2020-11-09 12:03:46 -05:00
Artem Garmash d1d42a9a35 Fix tests 2020-11-09 17:17:38 +03:00
Artem Garmash 7b1175511e Update changelog 2020-11-09 12:28:50 +03:00
Artem Garmash b679b8d75c Add check for return type Never 2020-11-09 12:18:42 +03:00
JP Simard fced10f61b
Remove Xcode project & drop Carthage support (#3414)
* Remove Xcode project & Drop Carthage Support

Xcode has supported Swift Package Manager projects natively since Xcode
11, which has been out for over a year, where you can use Xcode by
having it open the `Package.swift` manifest rather than a `.xcodeproj`
or `.xcworkspace`.

I've been primarily developing SwiftLint in Xcode using this approach
for over a year, and despite a few nitpicks I have, it's been a joy to
use.

So I'd like to completely remove the Xcode project along with things
that support it:

* `SwiftLint.xcworkspace`/`SwiftLint.xcodeproj`: Neither of these are
  needed if we use `xed .` or `xed Package.swift` to develop SwiftLint
  in Xcode.
* `Cartfile`/`Cartfile.private`/`Cartfile.resolved`/`.gitmodules`/`Carthage/`:
  These were used to manage dependencies as git submodules for use in
  the Xcode workspace, but that's no longer necessary if Xcode delegates
  to SwiftPM to manage dependencies for us.
* Some scripts can be simplified, cleaned up or even completely removed.

* **Reduce duplication:** Rather than update dependencies or files in
  multiples places, there will only be the package manifest and the
  Podfile
* **Reduce merge conflicts:** This hasn't been too bad, but it's
  occasionally a pain when trying to land old PRs
* **Reduce development overhead:** No need to manually make sure that
  files in the Xcode project are sorted alphabetically
* **Reduce clone time:** No need to run
  `git submodules update --init --recursive` anymore

I think this breaks Carthage users that pull in SwiftLintFramework as a
dependency in a Cartfile.

However I can't find any references to [`SwiftLintFramework` in any
`Cartfile` files on GitHub](https://github.com/search?q=swiftlintframework+filename%3ACartfile&type=Code&ref=advsearch&l=&l=)
so this doesn't appear to be worth continuing to maintain.

Resolves https://github.com/realm/SwiftLint/issues/3412
2020-11-08 14:42:41 -05:00
JP Simard f365dfd1d0
Duplicate Array+SwiftLint.swift rather than symlink 2020-11-08 14:06:09 -05:00
JP Simard 76708d88f7
Remove Xcode project & Drop Carthage Support
Xcode has supported Swift Package Manager projects natively since Xcode
11, which has been out for over a year, where you can use Xcode by
having it open the `Package.swift` manifest rather than a `.xcodeproj`
or `.xcworkspace`.

I've been primarily developing SwiftLint in Xcode using this approach
for over a year, and despite a few nitpicks I have, it's been a joy to
use.

So I'd like to completely remove the Xcode project along with things
that support it:

* `SwiftLint.xcworkspace`/`SwiftLint.xcodeproj`: Neither of these are
  needed if we use `xed .` or `xed Package.swift` to develop SwiftLint
  in Xcode.
* `Cartfile`/`Cartfile.private`/`Cartfile.resolved`/`.gitmodules`/`Carthage/`:
  These were used to manage dependencies as git submodules for use in
  the Xcode workspace, but that's no longer necessary if Xcode delegates
  to SwiftPM to manage dependencies for us.
* Some scripts can be simplified, cleaned up or even completely removed.

* **Reduce duplication:** Rather than update dependencies or files in
  multiples places, there will only be the package manifest and the
  Podfile
* **Reduce merge conflicts:** This hasn't been too bad, but it's
  occasionally a pain when trying to land old PRs
* **Reduce development overhead:** No need to manually make sure that
  files in the Xcode project are sorted alphabetically
* **Reduce clone time:** No need to run
  `git submodules update --init --recursive` anymore

I think this breaks Carthage users that pull in SwiftLintFramework as a
dependency in a Cartfile.

However I can't find any references to [`SwiftLintFramework` in any
`Cartfile` files on GitHub](https://github.com/search?q=swiftlintframework+filename%3ACartfile&type=Code&ref=advsearch&l=&l=)
so this doesn't appear to be worth continuing to maintain.

Resolves https://github.com/realm/SwiftLint/issues/3412
2020-11-08 13:32:07 -05:00
JP Simard b2b95cf403
Require Swift 5.2 or higher to build (#3413)
Swift 5.2 has been officially released for over 7 months now, there's no
reason to keep supporting earlier versions when _building_ SwiftLint.

However, SwiftLint still supports _linting_ back up to Swift 3.0.
2020-11-08 13:31:29 -05:00
JP Simard 2950826bb1
Add helpful comment 2020-11-08 12:55:57 -05:00
JP Simard 2d94feee86
Add deployment targets to iOS/macOS/watchos/tvos 2020-11-08 12:39:21 -05:00
JP Simard 45f7aaa961
Update CryptoSwift to 1.3.2 2020-11-08 12:30:59 -05:00
JP Simard f2c9a55811
Add empty changelog section 2020-11-08 12:30:50 -05:00
JP Simard d91c2179bb
release 0.41.0 2020-11-08 12:07:40 -05:00
JP Simard 41c99048bf
Format changelog 2020-11-08 10:11:14 -05:00
Paul Taykalo ba58d571d8
Add option that allows skipping aligned constants (#3391) 2020-11-08 10:07:24 -05:00
Christian Mitteldorf 67165f7c64
Improve documentation for running SwiftLint as Xcode build phase 2020-11-08 09:11:02 -05:00
Marcelo Fabri 0e29701aba
Merge pull request #3410 from realm/mf-bugfix-3398
Fix false positive in `toggle_bool` rule
2020-11-08 05:23:57 -08:00
Marcelo Fabri f2e12c3db5
Merge pull request #3409 from realm/mf-1082
Validate closures outside of function calls in unused_closure_parameter
2020-11-08 05:19:50 -08:00
Marcelo Fabri 551cf2da3c Fix false positive in `toggle_bool` rule 2020-11-08 04:57:59 -08:00
Marcelo Fabri 7ccda8eb23 Validate closures outside of function calls in unused_closure_parameter
Fixes #1082
2020-11-08 04:47:35 -08:00
Marcelo Fabri 1172ab5730
Merge pull request #3408 from realm/mf-prefer_nimble
Add prefer_nimble opt-in rule
2020-11-08 04:39:45 -08:00
Marcelo Fabri c8596a647a Add prefer_nimble opt-in rule
Fixes #3293
2020-11-08 00:09:51 -08:00
Seth Friedman 6d77deb359
Use working directory as root path instead of trying to calculate it (#3384)
We currently try to derive the root path by using the path passed in. However, this doesn't allow us to actually get the root, just the containing directory of the path passed in. We also don't currently have a heuristic to use for deriving the root path for multiple paths passed in.

The fix (which fixes #3383) is to remove our root path calculation and just use the current working directory as the root instead.
2020-11-07 23:51:44 -05:00
Paul Taykalo 1b3e9945af
Fix inconsistency in `operator_usage_whitespace` rule (#3388)
This Fixes case when the right part of the expression is an array or a string
Previously, strings and comments tokens were ignored.
In the current implementation, matching done first and then those are filtered if the operator is within the string token
2020-11-07 23:16:44 -05:00
Seth Friedman e316bd693d
Fix finding the nested config when a single file path is passed (#3379)
This was previously attempted in #3342, but produced a bug in the case where `--config` is used to specify a config from outside of the source tree. The `--config` argument wasn't always being used as an override, and was being merged with the config in the source tree. This has now been addressed and reverts the revert done in #3362. 

Fixes #3341
2020-11-07 23:07:03 -05:00
JP Simard 6c5a850c25
Exempt rule requests from being closed as stale 2020-11-07 22:12:26 -05:00
Dalton Claybrook d305e03905
Add `inclusive_language` rule (#3243)
Current events have renewed the conversation in our community about the roles of terminology with racist connotations in our software. Many companies and developers are now taking appropriate steps to remove this terminology from their codebases and products. (e.g. [GitHub](https://twitter.com/natfriedman/status/1271253144442253312)) This small rule prevents the use of declarations that contain any of the terms: whitelist, blacklist, master, and slave. It may be appropriate to add more terms to this list now or in the future.
2020-11-07 22:03:08 -05:00
Seth Friedman 812e9dd950
Add stale probot config (#3385) 2020-11-07 20:18:53 -05:00
JP Simard 0465d3984a
Fix changelog entry location 2020-11-07 20:13:30 -05:00
Zev Eisenberg 87bf6c6a6b
Fix convenience type false positives (#3062) 2020-11-07 20:12:09 -05:00
Iulian Onofrei bed8591e65
Fix incorrect regex patterns in README files (#3393) 2020-11-07 20:08:27 -05:00
JP Simard 390e9a2423
Remove UnneededNotificationCenterRemovalRule (#3407)
See https://github.com/realm/SwiftLint/issues/3338 for detailed
motivation.
2020-11-07 18:59:33 -05:00
Paul Taykalo 693ee2cae9
Add Isnot Empty extension in the Swift Framework (#3387) 2020-11-07 18:42:55 -05:00
Dalton Claybrook 580314d21e
'nslocalizedstring_key' now validates the comment argument in addition to the key argument (#3373) 2020-11-07 18:10:30 -05:00
JP Simard c8d8d913b9
Fix incorrect violation message for line length violations (#3406) 2020-11-07 18:01:04 -05:00
Quinn Taylor 865b59f0c8
Fix some missed cases in rule `unavailable_function`. (realm#3374) (#3375) 2020-11-07 17:36:26 -05:00
JP Simard 35ad3f941c
Add 5.3.1 to testDetectSwiftVersion() 2020-11-07 16:58:12 -05:00
JP Simard 2dcce6b184
[AttributesRule] Fix parameterized attributes (#3405)
Some attributes are parameterized, such as `@objc(name)`. Previously
these reported `attributes` violations because their contents weren't
included in the configuration, which would just have `@objc`.
2020-11-07 16:57:57 -05:00
Zsolt Kovács ac2c5e4054
Allow opening brace on newline in case of multiline function (#3068) 2020-11-07 16:02:17 -05:00
Cihat Gündüz 81942449d3
Adjust --strict to treat warnings as errors instead of only altering exit code (#3372) 2020-11-07 15:47:38 -05:00
JP Simard b005920cc5
Improve compilation times (#3404)
By speeding up a handful of the longest expressions to compile.
2020-11-07 12:16:25 -08:00
Mikhail Monakov fc0092dc8c
Add excluding by prefix option (#3345)
As we discussed here https://github.com/realm/SwiftLint/pull/3325 sometimes current excluding algorithm maybe slower than excluding paths by absolute prefix. So I added option for such cases.

Based on what I've checked it works faster for next scenarios:
- the number of input files is relatively small (e.g. when using `use-script-input-files`) and excluded directories contain relatively big number of lintable files
- the number of excluded directories relatively small (e.g. Pods + ThirdParty) and globs not used
2020-11-07 10:54:06 -08:00
JP Simard d628c41665
[IdentifierNameRule] Allow "allowed symbols" as first character (#3403)
This means that if `allowed_symbols` contains `_`, you can now write
identifiers like `let _myLet`.

Fixes https://github.com/realm/SwiftLint/issues/3306
2020-11-07 09:54:04 -08:00
Keith Smiley 05344f5fed
Fix DuplicateImportsRule's support for import attributes (#3402)
* Fix DuplicateImportsRule's support for import attributes

* update changelog

* Fix changelog
2020-11-05 10:45:01 -08:00
Keith Smiley 51084adf82
Remove @IBOutlet and @IBInspectable from UnusedDeclarationRule (#3184) 2020-11-05 08:21:54 -08:00
Sam e6df1d32e1
Use indentation_width severity configuration (#3397)
* Use the severity from the configuration

It was previously using a hardcoded value, that of the default configuration.

* Update CHANGELOG.md

* Correctly format CHANGELOG addition
2020-10-31 11:50:43 +02:00
Iulian Onofrei 1950abb3b7
Fix incomplete example (#3396) 2020-10-28 12:45:00 -07:00
mknabbe 5308e0d167
Improve CONTRIBUTING.md (#3394)
* Improve "Working Directory" instructions in CONTRIBUTING.md (#1280)

The instruction wasn't clear to me and it took me some time to figure out what to insert into the "Working Directory" option.

Co-Authored-By: oonoo <2565796+oonoo@users.noreply.github.com>

* Improve "Arguments Passed On Launch" instructions in CONTRIBUTING.md (#1280)

I wasn't sure which arguments could be passed to SwiftLint. I referenced the Command Line paragraph in the README, it already lists the available arguments.

Co-Authored-By: oonoo <2565796+oonoo@users.noreply.github.com>

* Add more details to "Submodules" in CONTRIBUTING.md (#1280)

The reason to checkout git submodules wasn't mentioned. I added the use cases for submodules, as Swift Package Manager doesn't make use of the git submodules.

* Format "Using Xcode" in CONTRIBUTING.md (#1280)

Limit line length to 80 characters in "Using Xcode" section of CONTRIBUTING.md.

* Document changes in CHANGELOG.md (#1280)

* Add missing word

Co-authored-by: oonoo <2565796+oonoo@users.noreply.github.com>
Co-authored-by: JP Simard <jp@jpsim.com>
2020-10-27 10:33:08 -07:00
hank121314 9afc3bbfd9
[Fix] `UnusedCaptureListRule`: unowned self in @escaping closures (#3392)
* [Fix] `UnusedCaptureListRule`: should also handle unowned self
* [Docs] `CHANGELOG.md`: update.
2020-10-24 21:10:18 +03:00
Paul Taykalo 662db7be39
Fix correct .zero autocorrection (#3386) 2020-10-19 14:27:47 -07:00
Keith Smiley 5d6e25ae5f
Add TestCaseAccessibilityRule (#3376)
Co-authored-by: JP Simard <jp@jpsim.com>
2020-10-12 08:59:45 -07:00
Sven Münnich da408b5901
Fix some false positives in rule `explicit_self` (#3368) 2020-09-25 09:23:03 -07:00
JP Simard 15c25abc47
Update SourceKitten to 0.30.1 (#3367) 2020-09-23 08:34:46 -07:00
JP Simard 2731f994d8
Fix issues with analyzer rules, Xcode 12 & SwiftUI (#3366)
We weren't properly handling some new Xcode 12 compiler logs.

We also were marking declarations used by SwiftUI as unused
(`@main` and preview providers).
2020-09-23 07:15:54 -07:00
JP Simard 1ff293888b
Add empty changelog section 2020-09-22 17:43:48 -04:00
JP Simard 4f8b7a5f48
release 0.40.3 2020-09-22 17:22:18 -04:00
Frederick Kellison-Linn 64b309e19e
Fix false positives for 'multiple_closures_with_trailing_closure' (#3353) 2020-09-22 14:18:50 -07:00
JP Simard 494796b526
[UnusedDeclarationRule] Work around SR-11985 (#3363) 2020-09-22 10:00:16 -07:00
JP Simard a67b0f26e7
Revert "Fix finding the nested config when a single file path is passed (#3342)" (#3362)
This reverts commit ea06b79e0d.
2020-09-22 08:30:52 -07:00
JP Simard 774267c436
[CONTRIBUTING] Add building & running tips (#3360)
* [CONTRIBUTING] Add building & running tips

* fixup! [CONTRIBUTING] Add building & running tips
2020-09-22 10:44:11 -04:00
Seth Friedman ea06b79e0d
Fix finding the nested config when a single file path is passed (#3342)
Fixes #3341

When SwiftLint searches for nested configurations and only one file has been passed in via the `paths` argument, SwiftLint returns early after inadvertently comparing the containing directory of the file-to-be-linted to itself. This happens because `rootDirectory` is calculated from `rootPath`, which is set to the file being linted in this scenario.
2020-09-22 07:24:52 -07:00
Seth Friedman 7db31658cb
Include Linux zip in list of GitHub release binaries (#3350)
* Include Linux zip in list of GitHub release binaries

This matches what has been included in recent releases.

* Fix one more Linux zip reference

* Use all 1s for the numbered list in Releasing.md

Markdown renders the numbered list correctly, and this way one can easily reorder the steps
or add new steps without needing to renumber everything.
2020-09-22 07:01:55 -07:00
JP Simard f71394a372
[UnusedDeclarationRule] Add more tests (#3359) 2020-09-21 12:10:46 -07:00
JP Simard 59d6c2ef52
Test CI with official Swift 5.3 release (#3356) 2020-09-20 11:16:10 -04:00
JP Simard 0ecf9a945b
Don't mark `@NSApplicationMain` or `@UIApplicationMain` classes as unused (#3355) 2020-09-20 07:16:26 -07:00
hank121314 5e537fa821
[Fix] `UnusedCaptureListRule`: implicit self in @escaping closures (#3352)
## Summary

This pr fixes: #3267 .

Since Swift 5.3 is released. It support implicit self in @escaping closures([SE-0269](https://github.com/apple/swift-evolution/blob/master/proposals/0269-implicit-self-explicit-capture.md))

I think we should exclude self keyword from capture list rule.

## Test Plan

I have already add some test in example.

Thanks you so much for your code review!
2020-09-18 07:26:49 -07:00
JP Simard 6d2e8cfc06
Skip correcting files with parser diagnostics (#3349)
* Skip correcting files with parser diagnostics

Also fix many rule examples with parser diagnostics.

* Sourcery

* Link to issue in changelog entry
2020-09-17 18:14:00 -04:00
JP Simard 9b93b3efb8
[SwiftLintFile] Remove lock in favor of UUID (#3347)
We were using this lock to guarantee a new ID for every file, but we can
get that benefit by using values that are guaranteed to be unique
without the need for locks, such as a UUID.
2020-09-17 07:35:05 -07:00
JP Simard ea311bab23
[UnusedDeclarationRule] Speed up and detect more dead code (#3340)
By using SourceKit's `index` request to index the entire source file,
we can avoid having to make `cursor-info` requests for every candidate
token in the file, which scales linearly with the number of candiate
tokens.

For the Yams project, this approach improved the total SwiftLint run
time by 4.6x: 7.9 down from 36.8s.

The SourceKit index response doesn't have everything we need to identify
declarations, so we still need to make some `cursor-info` requests,
mostly to detect overrides: protocol conformances and parent class
overrides.

This approach ends up finding more unused declarations because the index
contains more declared USRs than can be found by calling `cursor-info`
on candidate tokens in a file.

---

Remove unused declaration in ArrayInitRule

---

Update package versions
2020-09-15 10:33:27 -07:00
JP Simard d9ce579b38
Add empty changelog section 2020-09-10 22:41:13 -04:00
JP Simard 9ab72060b6
release 0.40.2 2020-09-10 22:25:10 -04:00
JP Simard 7009463876
Format changelog 2020-09-10 21:15:07 -04:00
Ryan Demo 51544bb4cc
Add `excluded_match_kinds` custom rule config parameter (#3336)
This allows custom rules to define an `excluded_match_kinds` array instead of listing out all but one or a few of the `SyntaxKind`s in `match_kinds`. Rules that include both `match_kinds` and `excluded_match_kinds` will be invalid, since there's not an obvious way to resolve the two without an arbitrary priority between them.
2020-09-10 21:08:41 -04:00
JP Simard 4083f16885
Merge pull request #3331 from lightsprint09/patch-1
Use correct term for associated values
2020-09-03 07:37:34 -07:00
JP Simard 89981cc984
Merge pull request #3330 from realm/add-linux-binary-to-release-artifacts
Add Linux binary to release artifacts
2020-09-03 06:18:16 -07:00
Lukas Schmidt 96c8918982
Update CHANGELOG.md 2020-09-03 12:23:34 +02:00
Lukas Schmidt 8945038087
Use correct term for associated values
See https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html for reference
2020-09-03 11:26:57 +02:00
JP Simard d0d9ad575f
Add Linux binary to release artifacts
There are a lot of libraries dynamically linked, so it's unlikely to
work in most places other than the same Docker image used to build the
binary (latest official Swift Docker image).

It might still be useful if you can guarantee that you'll use this from
that image.

    ldd .build/release/swiftlint
      linux-vdso.so.1 (0x00007fff38db5000)
      libswiftCore.so => /usr/lib/swift/linux/libswiftCore.so (0x00007f11503cd000)
      libFoundation.so => /usr/lib/swift/linux/libFoundation.so (0x00007f114fba6000)
      libswiftGlibc.so => /usr/lib/swift/linux/libswiftGlibc.so (0x00007f1151264000)
      libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f114f987000)
      libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f114f784000)
      libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f114f580000)
      libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f114f1e2000)
      libswiftDispatch.so => /usr/lib/swift/linux/libswiftDispatch.so (0x00007f115122b000)
      libdispatch.so => /usr/lib/swift/linux/libdispatch.so (0x00007f114ef82000)
      libBlocksRuntime.so => /usr/lib/swift/linux/libBlocksRuntime.so (0x00007f114ed7f000)
      libFoundationXML.so => /usr/lib/swift/linux/libFoundationXML.so (0x00007f11511d2000)
      libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f114e98e000)
      libicui18nswift.so.65 => /usr/lib/swift/linux/libicui18nswift.so.65 (0x00007f114e463000)
      libicuucswift.so.65 => /usr/lib/swift/linux/libicuucswift.so.65 (0x00007f114e062000)
      libicudataswift.so.65 => /usr/lib/swift/linux/libicudataswift.so.65 (0x00007f114c3b3000)
      libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f114c02a000)
      libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f114be12000)
      /lib64/ld-linux-x86-64.so.2 (0x00007f1151053000)
      librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f114bc0a000)
      libxml2.so.2 => /usr/lib/x86_64-linux-gnu/libxml2.so.2 (0x00007f114b849000)
      libicuuc.so.60 => /usr/lib/x86_64-linux-gnu/libicuuc.so.60 (0x00007f114b491000)
      libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f114b274000)
      liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007f114b04e000)
      libicudata.so.60 => /usr/lib/x86_64-linux-gnu/libicudata.so.60 (0x00007f11494a5000)
2020-09-02 15:33:46 -04:00
JP Simard 2ea422b52a
Add empty changelog section 2020-08-27 11:52:50 -04:00
JP Simard 1a1db6c706
release 0.40.1 2020-08-27 11:33:45 -04:00
JP Simard ff0e9f46c0
Merge pull request #3319 from realm/update-sourcekitten-and-yams
Update SourceKitten and Yams
2020-08-24 20:56:15 -07:00
JP Simard 81e8501dd5
Update SourceKitten and Yams 2020-08-24 22:27:13 -04:00
JP Simard e677737fe6
Merge pull request #3313 from realm/ks/add-support-for-params-files-for-file-path-arguments
Add support for params files for file path arguments
2020-08-21 08:13:06 -07:00
Keith Smiley eb841988f9 Add empty args 2020-08-20 11:32:05 -07:00
Keith Smiley 32579f457a Add support for params files for file path arguments
This allows you to pass `@path/to/file` which will be read line by line
for the list of files to lint / analyze. This is useful if you want to
pass a massive list of files which will either exceed arg max, or
break most unix tools if you use script input files + env vars.
2020-08-20 11:20:09 -07:00
JP Simard e90d2e2005
Merge pull request #3309 from ZevEisenberg/patch-1
Explain why two trailing spaces are needed
2020-08-18 10:57:32 -07:00
Zev Eisenberg 5a1693c6aa
Less forceful language. 2020-08-18 11:32:23 -04:00
Zev Eisenberg 93527bc9b8
Explain why two trailing spaces are needed. 2020-08-18 11:23:26 -04:00
JP Simard af2837e3e5
Merge pull request #3298 from cfiken/fix-swift-version
Fixed .swift-version with Swift 5.1
2020-08-13 07:46:40 -07:00
JP Simard c3b5bc186e
Merge branch 'master' into fix-swift-version 2020-08-13 07:46:08 -07:00
JP Simard 7feb50f0df
Merge pull request #3299 from cfiken/fix_swift_version_test
Update test `testDetectSwiftVersion` for Swift 5.2.5
2020-08-13 07:44:50 -07:00
cfiken 1b95821205 Fix: testDetectSwiftVersion for Swift 5.2.5 2020-08-13 12:48:33 +09:00
cfiken 776b7d74e2 Fix: CHANGELOG 2020-08-13 12:33:14 +09:00
cfiken 2418534ce5 Fix: .swift-version with Swift 5.1 2020-08-13 12:16:28 +09:00
Marcelo Fabri 0e8ad1d169
Update CHANGELOG.md 2020-08-10 09:43:13 -07:00
Marcelo Fabri da66a81710 release 0.40.0 2020-08-10 08:23:58 -07:00
Marcelo Fabri 83f52704f4
Merge pull request #3292 from realm/marcelo/unneeded_notification_center_removal
Add `unneeded_notification_center_removal` rule
2020-08-10 08:17:29 -07:00
Marcelo Fabri 5e1c13be52 Add `unneeded_notification_center_removal` rule
Fixes #2755
2020-08-10 07:46:51 -07:00
Marcelo Fabri 6a8f413bd7
Merge pull request #3291 from realm/marcelo/codecov
Setup codecov
2020-08-10 02:11:41 -07:00
Marcelo Fabri 6cf3534db9 Setup codecov 2020-08-10 01:41:32 -07:00
Marcelo Fabri 5ae6a32944
Merge pull request #3289 from realm/dependabot/bundler/kramdown-2.3.0
Bump kramdown from 2.1.0 to 2.3.0
2020-08-08 16:38:13 -07:00
dependabot[bot] bf834b6ff4
Bump kramdown from 2.1.0 to 2.3.0
Bumps [kramdown](https://github.com/gettalong/kramdown) from 2.1.0 to 2.3.0.
- [Release notes](https://github.com/gettalong/kramdown/releases)
- [Changelog](https://github.com/gettalong/kramdown/blob/master/doc/news.page)
- [Commits](https://github.com/gettalong/kramdown/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2020-08-07 23:28:37 +00:00
Marcelo Fabri 1dbe1f23f0
Merge pull request #3153 from realm/mf-bugfix-3150
Fix false positives in extension_access_modifier with Swift 5.2
2020-08-05 22:14:41 -07:00
Marcelo Fabri 4756ce6b69 Ignore local vars and params 2020-08-05 21:46:33 -07:00
Marcelo Fabri bb372c2146 Fix false positives in extension_access_modifier with Swift 5.2 2020-08-05 21:36:09 -07:00
Marcelo Fabri a61ae0e656
Update CHANGELOG.md 2020-08-05 21:30:19 -07:00
Marcelo Fabri 124ed9564b
Merge pull request #3047 from 417-72KI/feature/open-browser-for-docs
Add `swiftlint show-docs` command to easily open online docs.
2020-08-05 21:08:09 -07:00
Marcelo Fabri 20092640fe
Merge pull request #3137 from AdrianBinDC/add-access-control-level-tests
Add tests for AccessControlLevel
2020-08-05 20:39:26 -07:00
Marcelo Fabri e6d9f72cad Rename command 2020-08-05 20:37:49 -07:00
417-72KI 6c0f8365b3 Remove backquotes and "Framework" from the sentence 2020-08-05 20:34:33 -07:00
417-72KI d0328b3990 Update CHANGELOG 2020-08-05 20:34:33 -07:00
417-72KI 3d05146c3a Add file to pbxproj 2020-08-05 20:34:33 -07:00
417-72KI 6e237f77b8 Fix URL 2020-08-05 20:34:33 -07:00
417-72KI 623e69e623 Add `show-docs` command 2020-08-05 20:34:33 -07:00
Marcelo Fabri 6dbc0523fa Rename file 2020-08-05 20:13:53 -07:00
Marcelo Fabri 2b7230709d Move tests 2020-08-05 20:13:03 -07:00
Adrian Bolinger c156af86bc Add tests for AccessControlLevel
- add assertions for `description`
- add assertions to test 'priority'
2020-08-05 20:10:51 -07:00
Marcelo Fabri a5dbe93023
Merge pull request #3191 from MortyMerr/feature/preferZeroRule
Add prefer_zero_over_explicit_init rule
2020-08-05 15:49:22 -07:00
Marcelo Fabri 2bb7e842b5
Merge pull request #3287 from realm/marcelo/maybe-fix-jazzy
Fix Jazzy
2020-08-05 15:23:14 -07:00
Marcelo Fabri aae9730ee1 Fix Jazzy
Don’t try to create ~/.ssh if it already exists
2020-08-05 15:22:25 -07:00
Marcelo Fabri 244f41c2dd Improve CHANGELOG 2020-08-05 15:12:22 -07:00
Marcelo Fabri 30c7add095 Change to .idiomatic 2020-08-05 15:11:41 -07:00
antonnazarov 09a0a216d1 Change types on string representation 2020-08-05 15:05:02 -07:00
antonnazarov 63bd8ce7a5 Add PreferZeroOverExplicitInitRule 2020-08-05 15:05:02 -07:00
Marcelo Fabri 89523a92a9
Merge pull request #3122 from lordzsolt/if-guard-case
Extend empty_enum_arguments rule to support `if case` and `guard case`
2020-08-05 14:51:55 -07:00
Marcelo Fabri c9d96ff5c7
Merge pull request #3284 from janakmshah/master
Include IndexSet in compiler_protocol_init
2020-08-05 14:42:43 -07:00
Janak Shah 733db8496b
Update CHANGELOG.md 2020-08-05 13:18:17 +01:00
Janak Shah 6b3e4e64a0
Include IndexSet in byArrayLiteral collection 2020-08-05 13:03:46 +01:00
Zsolt Kovacs f3802a3a75 Update CHANGELOG.md 2020-08-05 03:49:49 -07:00
Zsolt Kovacs b33b86acd9 Extend empty_enum_arguments rule to support `if case` and `guard case` 2020-08-05 03:48:42 -07:00
Marcelo Fabri 0cabed81d7
Merge pull request #3283 from realm/marcelo/bugfix-3214
Use atexit on Linux
2020-08-05 03:47:33 -07:00
Marcelo Fabri 2d67213741
Merge pull request #3282 from realm/marcelo/self-and-is-multiple
Enable legacy_multiple and prefer_self_type_over_type_of_self in our codebase
2020-08-05 03:46:50 -07:00
Marcelo Fabri caedfcb62b Use atexit on Linux
Fixes #3214
2020-08-05 01:40:38 -07:00
Marcelo Fabri 8638d23aec
Merge pull request #3281 from realm/marcelo/bugfix-3225
Trigger closure_parameter_position in free closures and capture lists
2020-08-05 01:12:22 -07:00
Marcelo Fabri f8ef7d649c Enable legacy_multiple and prefer_self_type_over_type_of_self in our codebase 2020-08-05 01:11:17 -07:00
Marcelo Fabri 5a817b0139
Update CHANGELOG.md 2020-08-05 01:03:18 -07:00
Marcelo Fabri a05a87e7f2
Merge pull request #3258 from SimplyDanny/bugfix-3034
Fix #3034: Allow opening brace directly after another opening brace
2020-08-05 01:02:00 -07:00
Marcelo Fabri 6ec5806a93 Trigger closure_parameter_position in free closures and capture lists 2020-08-05 00:42:27 -07:00
Marcelo Fabri ed37784cd6
Merge pull request #3280 from realm/marcelo/bugfix-3259
Fix false positive in no_space_in_method_call with multiple trailing closures
2020-08-04 23:56:35 -07:00
Marcelo Fabri b1a776116e Add CHANGELOG entry 2020-08-04 23:46:27 -07:00
Marcelo Fabri d36743b58a Fix false positive in no_space_in_method_call with multiple trailing closures
Fixes #3259
2020-08-04 21:20:54 -07:00
Marcelo Fabri 5ad5bf2dae
Merge pull request #3276 from realm/marcelo/bugfix-3186
Fix false negative in `explicit_acl` rule with Swift 5.2+
2020-08-04 20:53:42 -07:00
Marcelo Fabri b541d253c6 Ignore .varParameter 2020-08-04 20:25:16 -07:00
Marcelo Fabri 1279523798 Ignore varLocal 2020-08-04 16:22:11 -07:00
Marcelo Fabri 934a208df7 Fix CHANGELOG 2020-08-04 15:53:20 -07:00
Marcelo Fabri 0a592a34c9 Fix rule 2020-08-04 15:53:11 -07:00
Keith Smiley cf94d5d8ea
Add IBInspectableInExtensionRule (#3174) 2020-08-04 14:15:40 -07:00
Marcelo Fabri 9e5557fbc5
Merge pull request #3160 from realm/mf-computed_accessors_order
Add computed_accessors_order rule
2020-08-04 05:04:45 -07:00
Marcelo Fabri 6d2360a2f4
Merge pull request #3273 from realm/marcelo/update-linux-main
Update LinuxMain to add missing test
2020-08-04 05:03:58 -07:00
Marcelo Fabri 2d7702fc25 Fix false positive in `explicit_acl` rule with Swift 5.2+
Fixes #3186
2020-08-04 04:24:52 -07:00
Marcelo Fabri a4a0481a50
Merge pull request #3275 from realm/marcelo/rename-blacklist
Remove a usage of “blacklist”
2020-08-04 04:01:08 -07:00
Marcelo Fabri 28bec96b3e Remove a usage of “blacklist” 2020-08-04 04:00:36 -07:00
Marcelo Fabri 20b86147d9
Merge pull request #3236 from realm/cg_improve-whitelist-docs
Improve visibility of whitelist_rules option
2020-08-04 03:53:07 -07:00
Marcelo Fabri dc1b60742e
Update CHANGELOG.md 2020-08-04 03:36:01 -07:00
Marcelo Fabri b64d02c829
Merge pull request #3175 from teameh/false-positive-raw_value_for_camel_cased_codable_enum
Fix false positive uppercase enum case in raw_value_for_camel_cased_codable_enum
2020-08-04 03:35:36 -07:00
Tieme van Veen 5f8f9a5a3d Fix false positive UPPERCASE raw_value_for_camel_cased_codable_enum 2020-08-04 03:34:28 -07:00
Marcelo Fabri e238587588
Update CHANGELOG.md 2020-08-04 03:24:56 -07:00
Marcelo Fabri 0219584605 Update LinuxMain to add missing test 2020-08-04 03:24:15 -07:00
Marcelo Fabri 240e25232f Add computed_accessors_order rule
Fixes #3158
2020-08-04 03:23:36 -07:00
Marcelo Fabri a23d4e1c34
Update CHANGELOG.md 2020-08-04 03:20:48 -07:00
Marcelo Fabri 5242d6b442
Merge pull request #3272 from realm/marcelo/bugfix-3253
Fix false positive on switch_case_on_newline with Swift 5.3
2020-08-04 03:18:33 -07:00
Marcelo Fabri 063cd3e56c Fix false positive on switch_case_on_newline with Swift 5.3
Fixes #3253
2020-08-04 03:17:23 -07:00
Marcelo Fabri 990c2808ef
Merge pull request #3271 from realm/marcelo/run-xcode-12
Run tests on Xcode 12 as well
2020-08-04 03:16:07 -07:00
Marcelo Fabri a2de4a0585
Merge pull request #3223 from liamnichols/ln/reporters-in-readme
Update README files to include complete list of reporters
2020-08-04 03:15:36 -07:00
Marcelo Fabri a718ffae35
Merge pull request #3193 from yusukegoto/duplicate_imports_configuration
Fix severity level configuration for duplicate_imports
2020-08-04 03:01:06 -07:00
Marcelo Fabri d09a1411c9
Merge branch 'master' into duplicate_imports_configuration 2020-08-04 03:00:38 -07:00
Marcelo Fabri 1f5ee4d9fd Run tests on Xcode 12 as well 2020-08-04 02:45:42 -07:00
Danny Moesch d08ea47920 Fix #3034: Allow opening brace directly after another opening brace or `in`
This special case occurs in functions implicitly returning closures.
2020-07-26 12:38:46 +02:00
JP Simard 0dd3dac82c
Merge pull request #3262 from changm4n/master
Typo fix in README_KR
2020-07-14 08:49:05 -04:00
changmin lee e367a11175 Correct typo in README_KR.md 2020-07-14 18:57:56 +09:00
Keith Smiley 46b99892d2 fix lint 2020-06-30 14:03:12 -07:00
Keith Smiley 660920a5f8 Add 'always_keep_imports' to UnusedImportRule
Sometimes we hit issues with SourceKit that cause this rule to produce
false positives of some imports. While we would prefer to fix all of
these cases whenever possible, this gives us a temporary escape hatch to
tell the rule never to remove imports of specific modules until the
fixes land in SwiftLint or Swift itself.

Currently this is for us to opt out of https://bugs.swift.org/browse/SR-13120
2020-06-30 10:00:33 -07:00
JP Simard 075312af6e
Fix Linux Swift 5.2 Azure Pipeline (#3247)
* Update Makefile with Swift 5.2.4 image
* Add support for Xcode 11.5 and Swift 5.2.4
2020-06-18 13:32:26 -07:00
Frederick Pietschmann eaff622233 Add support for Xcode 11.5 and Swift 5.2.4 2020-06-18 14:52:20 -05:00
Ilias Karim a91c987552 Update Makefile with Swift 5.2.4 image 2020-06-18 14:51:45 -05:00
Cihat Gündüz 11b13da9ad Improve visibility of whitelist_rules option
Related to https://github.com/realm/SwiftLint/issues/1451 and https://github.com/realm/SwiftLint/issues/1118
2020-06-11 17:24:14 +02:00
Liam Nichols d1b1393748
Update README files to include complete list of reporters 2020-06-05 14:06:46 +01:00
Noah Gilmore bda1cd56e0
#3167: Fixes false positives for multiline_parameters_brackets and multiline_arguments_brackets (#3171)
* Issue #3167: Fixes false positives for multiline_parameters_brackets and multiline_arguments_brackets

* Add changelog entry

* Fix trailing comma in MultilineParametersBracketsRule nontriggering examples

* Remove header comments from ExtendedStringTests.swift

Co-authored-by: Paul Taykalo <ptaykalo@macpaw.com>
2020-05-29 11:59:02 +03:00
Mateusz Matrejek 8ed7c31161
Fix false positive in with Swift 5.2 (#3112) (#3206) 2020-05-27 22:13:46 +03:00
Tieda 9f05692d12
Typo fix in README_CN (#3215)
`XCode` -> `Xcode`
2020-05-24 14:09:45 -07:00
Yusuke Goto 7da113e932 Fix severity level configuration for duplicate_imports 2020-05-12 17:27:33 +09:00
Keith Smiley e3ba417303
Fix UnusedImportRule breaking transitive imports (#3198) 2020-05-06 15:39:32 -07:00
JP Simard 345933ebb1
Run CI on Linux Swift 5.2 (#3199)
* Run CI on Linux Swift 5.2

* fixup! Run CI on Linux Swift 5.2

* Move SwiftVersion tests to its own file
2020-05-06 14:16:17 -07:00
JP Simard 52cd6ebe06
Fix `@available` attribute to work around SR-12500
https://bugs.swift.org/browse/SR-12500
2020-05-06 13:33:10 -07:00
Keith Smiley bf3da85d8d
Improve compile commands error handling (#3188)
* Improve compile commands error handling

Previously when a compile commands file was invalid, it could be hard to
figure out what about it was wrong. This adds some more granular error
handling which hopefully helps provide valid files here.

* fix desc

* Fixups

* Update changelog

* Make what broke clear

* Reword changelog entry

Co-authored-by: JP Simard <jp@jpsim.com>
2020-04-28 09:20:07 -07:00
Cihat Gündüz 5a22b94ec6
Add new file_content_type for PreviewProvider subclasses (#3063)
Fixes #2860.

Co-authored-by: Paul Taykalo <tt.kilew@gmail.com>
2020-04-24 13:21:24 +03:00
JP Simard 889dc49bb6
Remove support for compiling with 5.0.x (#3180)
* Remove support for compiling with 5.0.x

* fixup! Remove support for compiling with 5.0.x
2020-04-14 08:46:23 -07:00
Alexander Chapliuk ef4a37ee1e
JUnit reporter for GitLab artifact:report:junit (#3177)
* Add JUnit reporter for GitLab artifact:report:junit

* Added CHANGELOG entry

Co-authored-by: Alexander Chapliuk <2318002+krin-san@users.noreply.github.com>
2020-04-12 17:14:52 +03:00
JP Simard 1e1807b88b
Add empty changelog section 2020-04-03 20:52:26 -07:00
JP Simard b1c72069ca
release 0.39.2 2020-04-03 20:22:50 -07:00
JP Simard bc4b7d2962
Update CI to run jobs with Xcode 11.0 to 11.4 (#3168)
* Update CI to run jobs with Xcode 11.0 to 11.4

In the process, remove CI jobs running with Swift 5.0.x and indicate
in the changelog that the next release will be the last one to support
building with Swift 5.0.x.

* fixup! Update CI to run jobs with Xcode 11.0 to 11.4

* fixup! Update CI to run jobs with Xcode 11.0 to 11.4

* fixup! Update CI to run jobs with Xcode 11.0 to 11.4

* fixup! Update CI to run jobs with Xcode 11.0 to 11.4

* Disable Swift 5.2 tests on Linux due to SR-12500

* Update ruby gems

Mostly to get jazzy 0.13.2 with Swift 5.2 bug fixes.
2020-04-03 18:06:22 -07:00
JP Simard da3e1a793b
Fix false positives in valid_ibinspectable rule when using Swift 5.2 (#3155)
* Fix false positives in valid_ibinspectable rule when using Swift 5.2

when defining inspectable properties in class extensions with computed
properties.

The following was triggering:

```swift
extension Foo {
  @IBInspectable var color: UIColor {
    set {
      self.bar.textColor = newValue
    }

    get {
      return self.bar.textColor
    }
  }
}
```

Fix by checking to see if an instance property has `set` keywords in its
body when running with Swift 5.2 or later.

* fixup! Fix false positives in valid_ibinspectable rule when using Swift 5.2
2020-03-27 10:04:04 -07:00
JP Simard 85d3425210
Fix attributes rule false positive with Swift 5.2 (#3154)
The following was triggering:

```swift
func printBoolOrTrue(_ expression: @autoclosure () throws -> Bool?) rethrows {
  try print(expression() ?? true)
}
```

Fix by adding the `rethrows` attribute kind to the rule's blacklist.
2020-03-27 09:33:12 -07:00
Marcelo Fabri e6ecd6b8ce
Fix CHANGELOG link 2020-03-26 19:31:38 -07:00
Marcelo Fabri 0bbbcb0a56
Fix false positives in redundant_objc_attribute with Swift 5.2 (#3152) 2020-03-26 19:23:48 -07:00
Marcelo Fabri 39ee6fe34e
Fix false positives on implicit_getter with Swift 5.2+ (#3151)
Fixes #3149
2020-03-26 18:53:36 -07:00
JP Simard c201ae43e6
Simplify regex (#3145)
* Simplify regex

`\w` already includes `_`

* Fix test
2020-03-18 16:23:52 -07:00
Ryoya Ito 302f377a4b
fix links about configuration rules (#3142) 2020-03-13 08:34:43 -07:00
JP Simard d10ccacb45
Add unused_import config options to require imports for each module used (#3123)
For example, if `CGFloat` is used in a file where only `UIKit` is imported but not `CoreGraphics`, this will be a violation even if the file previously compiled.

This is because Swift allows referencing some declarations that are only transitively imported.

Enabling the `require_explicit_imports` configuration option will require that the module of every declaration referenced in a source file be explicitly imported.

This will add significant noise to the imports list, but has a few advantages:

1. It will be easier to understand all the dependencies explicitly referenced in a source file.
2. Correcting the `unused_import` rule will no longer introduce compilation errors in files that compiled prior to the correction.

If missing imports are added to a file when correcting it, the `sorted_imports` rule will be automatically run on that file.

If you with to allow some imports to be implicitly importable transitively, you may specify the `allowed_transitive_imports` configuration:

```yaml
unused_import:
  require_explicit_imports: true
  allowed_transitive_imports:
    - module: Foundation
      allowed_transitive_imports:
        - CoreFoundation
        - Darwin
        - ObjectiveC
```
2020-02-22 14:39:07 -08:00
JP Simard 8beb7144f0
Add empty changelog section 2020-02-11 14:11:39 -08:00
JP Simard 8f22943ca1
release 0.39.1 2020-02-11 13:43:28 -08:00
JP Simard b744cf08f1
Temporarily remove all SwiftSyntax rules and support (#3107)
The new rules introduced in 0.39.0 that depend on SwiftSyntax have been temporarily removed as we work out release packaging issues.

* `prohibited_nan_comparison`
* `return_value_from_void_function`
* `tuple_pattern`
* `void_function_in_ternary`

See https://github.com/realm/SwiftLint/issues/3105 for details.
2020-02-11 13:40:04 -08:00
JP Simard 05a8a854f5
Fix unused_import rule reported locations and corrections (#3106)
When multiple `@testable` imports are involved.

Because we use the `.dotMatchesLineSeparators` regular expression option, the dot was matching across lines when the intention was for it to just match `\w_` characters.
2020-02-11 11:23:27 -08:00
Marcelo Fabri 5a4c3f143d release 0.39.0 2020-02-10 22:19:59 -08:00
927 changed files with 48024 additions and 29583 deletions

1
.bazelignore Normal file
View File

@ -0,0 +1 @@
.build

15
.bazelrc Normal file
View File

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

1
.bazelversion Normal file
View File

@ -0,0 +1 @@
6.2.0

3
.bcr/config.yml Normal file
View File

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

View File

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

24
.bcr/presubmit.yml Normal file
View File

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

View File

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

29
.buildkite/pipeline.yml Normal file
View File

@ -0,0 +1,29 @@
steps:
- label: "Bazel"
commands:
- echo "+++ Build"
- bazel build :swiftlint
- echo "+++ Test"
- bazel test --test_output=errors //Tests/...
- label: "SwiftPM"
commands:
- echo "+++ Test"
- swift test --parallel -Xswiftc -DDISABLE_FOCUSED_EXAMPLES
- label: "Danger"
commands:
- echo "--- Install Bundler"
- gem install bundler
- echo "--- Bundle Install"
- bundle install
- echo "+++ Run Danger"
- bundle exec danger --verbose
- label: "TSan Tests"
commands:
- echo "+++ Test"
- 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

5
.dockerignore Normal file
View File

@ -0,0 +1,5 @@
*
!Plugins
!Source
!Tests
!Package.*

46
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,46 @@
name: docker
on:
push:
branches:
- main
tags:
- '*'
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Extract DOCKER_TAG using tag name
if: startsWith(github.ref, 'refs/tags/')
run: |
echo "DOCKER_TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
- name: Use default DOCKER_TAG
if: startsWith(github.ref, 'refs/tags/') != true
run: |
echo "DOCKER_TAG=latest" >> $GITHUB_ENV
- name: Set lowercase repository name
run: |
echo "REPOSITORY_LC=${REPOSITORY,,}" >>${GITHUB_ENV}
env:
REPOSITORY: '${{ github.repository }}'
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Github registry
uses: docker/login-action@v1
with:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
- uses: docker/build-push-action@v2
with:
push: true
tags: ghcr.io/${{ env.REPOSITORY_LC }}:${{ env.DOCKER_TAG }}

20
.gitignore vendored
View File

@ -1,6 +1,5 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
@ -22,6 +21,7 @@ xcuserdata
*.moved-aside
*.xcuserstate
*.xcscmblueprint
default.profraw
## Obj-C/Swift specific
*.hmap
@ -35,22 +35,19 @@ xcuserdata
#
#Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# SwiftLint
SwiftLint.xcodeproj
SwiftLint.pkg
SwiftLintFramework.framework.zip
*.zip
benchmark_*
portable_swiftlint.zip
osscheck/
docs/
rule_docs/
bazel.tar.gz
bazel.tar.gz.sha256
ci.bazelrc
user.bazelrc
# Swift Package Manager
#
@ -65,3 +62,6 @@ Packages/
# Bundler
.bundle/
bundle/
# Bazel
bazel-*

21
.gitmodules vendored
View File

@ -1,21 +0,0 @@
[submodule "Carthage/Checkouts/SWXMLHash"]
path = Carthage/Checkouts/SWXMLHash
url = https://github.com/drmohundro/SWXMLHash.git
[submodule "Carthage/Checkouts/xcconfigs"]
path = Carthage/Checkouts/xcconfigs
url = https://github.com/jspahrsummers/xcconfigs.git
[submodule "Carthage/Checkouts/Commandant"]
path = Carthage/Checkouts/Commandant
url = https://github.com/Carthage/Commandant.git
[submodule "Carthage/Checkouts/SourceKitten"]
path = Carthage/Checkouts/SourceKitten
url = https://github.com/jpsim/SourceKitten.git
[submodule "Carthage/Checkouts/SwiftyTextTable"]
path = Carthage/Checkouts/SwiftyTextTable
url = https://github.com/scottrhoyt/SwiftyTextTable.git
[submodule "Carthage/Checkouts/Yams"]
path = Carthage/Checkouts/Yams
url = https://github.com/jpsim/Yams.git
[submodule "SwiftSyntax"]
path = SwiftSyntax
url = https://github.com/apple/swift-syntax.git

View File

@ -1,19 +1,20 @@
module: SwiftLintFramework
module: SwiftLintCore
author: JP Simard, SwiftLint Contributors
author_url: https://jpsim.com
root_url: https://realm.github.io/SwiftLint/
github_url: https://github.com/realm/SwiftLint
github_file_prefix: https://github.com/realm/SwiftLint/tree/master
github_file_prefix: https://github.com/realm/SwiftLint/tree/main
swift_build_tool: spm
theme: fullwidth
clean: true
copyright: '© 2020 [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:
@ -22,6 +23,7 @@ custom_categories:
children:
- CSVReporter
- CheckstyleReporter
- CodeClimateReporter
- EmojiReporter
- GitHubActionsLoggingReporter
- HTMLReporter

6
.pre-commit-hooks.yaml Normal file
View File

@ -0,0 +1,6 @@
- id: swiftlint
name: SwiftLint
description: "Check Swift files for issues with SwiftLint"
entry: "swiftlint --quiet"
language: swift
types: [swift]

View File

@ -1,14 +0,0 @@
import SwiftLintFramework
import XCTest
// swiftlint:disable file_length single_test_class type_name
{% for rule in types.structs|based:"AutomaticTestableRule" %}
class {{ rule.name }}Tests: XCTestCase {
func testWithDefaultConfiguration() {
verifyRule({{ rule.name }}.description)
}
}
{% if not forloop.last %}
{% endif %}{% endfor %}

View File

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

View File

@ -0,0 +1,20 @@
@testable import SwiftLintBuiltInRules
@_spi(TestHelper)
@testable import SwiftLintCore
import SwiftLintTestHelpers
// 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: SwiftLintTestCase {
func testWithDefaultConfiguration() {
verifyRule({{ rule.name }}.description)
}
}
{% if not forloop.last %}
{% endif %}
{% endif %}
{% endfor %}

View File

@ -1,16 +0,0 @@
@testable import SwiftLintFrameworkTests
import XCTest
// swiftlint:disable line_length file_length
{% for type in types.classes|based:"XCTestCase" %}
extension {{ type.name }} {
static var allTests: [(String, ({{ type.name }}) -> () throws -> Void)] = [
{% for method in type.methods where method.parameters.count == 0 and method.shortName|hasPrefix:"test" and method|!annotated:"skipTestOnLinux" %} ("{{ method.shortName }}", {{ method.shortName }}){% if not forloop.last %},{% endif %}
{% endfor %}]
}
{% endfor %}
XCTMain([
{% for type in types.classes|based:"XCTestCase" %} testCase({{ type.name }}.allTests){% if not forloop.last %},{% endif %}
{% endfor %}])

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

@ -1 +0,0 @@
5.0

View File

@ -1,4 +1,5 @@
included:
- Plugins
- Source
- Tests
excluded:
@ -7,95 +8,84 @@ analyzer_rules:
- unused_declaration
- unused_import
opt_in_rules:
- all
disabled_rules:
- anonymous_argument_in_multiline_closure
- anyobject_protocol
- array_init
- attributes
- closure_end_indentation
- closure_spacing
- collection_alignment
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- discouraged_object_literal
- empty_collection_literal
- empty_count
- empty_string
- empty_xctest_method
- enum_case_associated_values_count
- explicit_init
- extension_access_modifier
- fallthrough
- fatal_error_message
- file_header
- file_name
- first_where
- flatmap_over_map_reduce
- identical_operands
- joined_default_parameter
- legacy_random
- let_var_whitespace
- last_where
- literal_expression_end_indentation
- lower_acl_than_parent
- modifier_order
- nimble_operator
- nslocalizedstring_key
- number_separator
- object_literal
- operator_usage_whitespace
- overridden_super_call
- override_in_extension
- pattern_matching_keywords
- private_action
- private_outlet
- prohibited_interface_builder
- prohibited_nan_comparison
- prohibited_super_call
- quick_discouraged_call
- quick_discouraged_focused_test
- quick_discouraged_pending_test
- reduce_into
- redundant_nil_coalescing
- redundant_type_annotation
- return_value_from_void_function
- single_test_class
- sorted_first_last
- sorted_imports
- static_operator
- strong_iboutlet
- toggle_bool
- tuple_pattern
- unavailable_function
- unneeded_parentheses_in_closure_argument
- unowned_variable_capture
- untyped_error_in_catch
- vertical_parameter_alignment_on_call
- vertical_whitespace_closing_braces
- vertical_whitespace_opening_braces
- void_function_in_ternary
- xct_specific_matcher
- yoda_condition
- closure_body_length
- conditional_returns_on_newline
- convenience_type
- discouraged_optional_collection
- explicit_acl
- explicit_enum_raw_value
- explicit_top_level_acl
- explicit_type_interface
- file_types_order
- force_unwrapping
- function_default_parameter_at_end
- implicit_return
- implicitly_unwrapped_optional
- indentation_width
- inert_defer
- missing_docs
- multiline_arguments
- multiline_arguments_brackets
- multiline_function_chains
- multiline_literal_brackets
- multiline_parameters
- multiline_parameters_brackets
- no_extension_access_modifier
- no_fallthrough_only
- no_grouping_extension
- no_magic_numbers
- prefer_nimble
- prefer_self_in_static_references
- prefixed_toplevel_constant
- redundant_self_in_closure
- required_deinit
- self_binding
- sorted_enum_cases
- strict_fileprivate
- superfluous_else
- switch_case_on_newline
- todo
- trailing_closure
- type_contents_order
- unused_capture_list
- vertical_whitespace_between_cases
attributes:
always_on_line_above:
- "@OptionGroup"
identifier_name:
excluded:
- id
large_tuple: 3
number_separator:
minimum_length: 5
file_name:
excluded:
- main.swift
- LinuxMain.swift
- Exports.swift
- GeneratedTests.swift
- SwiftSyntax+SwiftLint.swift
- TestHelpers.swift
- shim.swift
- AutomaticRuleTests.generated.swift
balanced_xctest_lifecycle: &unit_test_configuration
test_parent_classes:
- SwiftLintTestCase
- XCTestCase
empty_xctest_method: *unit_test_configuration
single_test_class: *unit_test_configuration
function_body_length: 60
type_body_length: 400
custom_rules:
rule_id:
included: Source/SwiftLintFramework/Rules/.+/\w+\.swift
included: Source/SwiftLintBuiltInRules/Rules/.+/\w+\.swift
name: Rule ID
message: Rule IDs must be all lowercase, snake case and not end with `rule`
regex: identifier:\s*("\w+_rule"|"\S*[^a-z_]\S*")
regex: ^\s+identifier:\s*("\w+_rule"|"\S*[^a-z_]\S*")
severity: error
fatal_error:
name: Fatal Error
@ -111,3 +101,8 @@ custom_rules:
message: Rule Test Function mustn't end with `rule`
regex: func\s*test\w+(r|R)ule\(\)
severity: error
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

211
BUILD Normal file
View File

@ -0,0 +1,211 @@
load("@build_bazel_rules_apple//apple:apple.bzl", "apple_universal_binary")
load(
"@build_bazel_rules_swift//swift:swift.bzl",
"swift_binary",
"swift_library",
)
load(
"@rules_xcodeproj//xcodeproj:defs.bzl",
"xcode_schemes",
"xcodeproj",
)
# Targets
swift_library(
name = "SwiftLintCore",
srcs = glob(["Source/SwiftLintCore/**/*.swift"]),
module_name = "SwiftLintCore",
visibility = ["//visibility:public"],
deps = [
"@SwiftSyntax//:SwiftIDEUtils_opt",
"@SwiftSyntax//:SwiftOperators_opt",
"@SwiftSyntax//:SwiftParserDiagnostics_opt",
"@SwiftSyntax//:SwiftSyntaxBuilder_opt",
"@SwiftSyntax//:SwiftSyntax_opt",
"@com_github_jpsim_sourcekitten//:SourceKittenFramework",
"@sourcekitten_com_github_jpsim_yams//:Yams",
"@swiftlint_com_github_scottrhoyt_swifty_text_table//:SwiftyTextTable",
] + select({
"@platforms//os:linux": ["@com_github_krzyzanowskim_cryptoswift//:CryptoSwift"],
"//conditions:default": [":DyldWarningWorkaround"],
}),
)
swift_library(
name = "SwiftLintBuiltInRules",
srcs = glob(["Source/SwiftLintBuiltInRules/**/*.swift"]),
module_name = "SwiftLintBuiltInRules",
visibility = ["//visibility:public"],
deps = [
":SwiftLintCore",
],
)
swift_library(
name = "SwiftLintExtraRules",
srcs = [
"Source/SwiftLintExtraRules/Exports.swift",
"@swiftlint_extra_rules//:extra_rules",
],
module_name = "SwiftLintExtraRules",
visibility = ["//visibility:public"],
deps = [
":SwiftLintCore",
],
)
swift_library(
name = "SwiftLintFramework",
srcs = glob(
["Source/SwiftLintFramework/**/*.swift"],
),
module_name = "SwiftLintFramework",
visibility = ["//visibility:public"],
deps = [
":SwiftLintBuiltInRules",
":SwiftLintCore",
":SwiftLintExtraRules",
],
)
swift_library(
name = "swiftlint.library",
srcs = glob(["Source/swiftlint/**/*.swift"]),
module_name = "swiftlint",
visibility = ["//visibility:public"],
deps = [
":SwiftLintFramework",
"@com_github_johnsundell_collectionconcurrencykit//:CollectionConcurrencyKit",
"@sourcekitten_com_github_apple_swift_argument_parser//:ArgumentParser",
"@swiftlint_com_github_scottrhoyt_swifty_text_table//:SwiftyTextTable",
],
)
swift_binary(
name = "swiftlint",
visibility = ["//visibility:public"],
deps = [
":swiftlint.library",
],
)
apple_universal_binary(
name = "universal_swiftlint",
binary = ":swiftlint",
forced_cpus = [
"x86_64",
"arm64",
],
minimum_os_version = "12.0",
platform_type = "macos",
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(
name = "LintInputs",
srcs = glob(["Source/**/*.swift"]) + [
".swiftlint.yml",
"//Tests:SwiftLintFrameworkTestsData",
],
visibility = ["//Tests:__subpackages__"],
)
# Release
filegroup(
name = "release_files",
srcs = [
"BUILD",
"LICENSE",
"MODULE.bazel",
"//:DyldWarningWorkaroundSources",
"//:LintInputs",
"//Tests:BUILD",
"//bazel:release_files",
],
)
# TODO: Use rules_pkg
genrule(
name = "release",
srcs = [":release_files"],
outs = [
"bazel.tar.gz",
"bazel.tar.gz.sha256",
],
cmd = """\
set -euo pipefail
outs=($(OUTS))
COPYFILE_DISABLE=1 tar czvfh "$${outs[0]}" \
--exclude ^bazel-out/ \
--exclude ^external/ \
*
shasum -a 256 "$${outs[0]}" > "$${outs[1]}"
""",
)
# Xcode Integration
xcodeproj(
name = "xcodeproj",
project_name = "SwiftLint",
schemes = [
xcode_schemes.scheme(
name = "SwiftLint",
launch_action = xcode_schemes.launch_action(
"swiftlint",
args = [
"--progress",
],
),
test_action = xcode_schemes.test_action([
"//Tests:CLITests",
"//Tests:SwiftLintFrameworkTests",
"//Tests:GeneratedTests",
"//Tests:IntegrationTests",
"//Tests:ExtraRulesTests",
]),
),
],
top_level_targets = [
"//:swiftlint",
"//Tests:CLITests",
"//Tests:SwiftLintFrameworkTests",
"//Tests:GeneratedTests",
"//Tests:IntegrationTests",
"//Tests:ExtraRulesTests",
],
)
# Analyze
sh_test(
name = "analyze",
srcs = ["//tools:test-analyze.sh"],
data = [
"Package.resolved",
"Package.swift",
":LintInputs",
":swiftlint",
],
)

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,47 @@
## 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
should never be made directly on the `master` branch. Prefer rebasing over
merging `master` into your PR branch to update it and resolve conflicts.
should never be made directly on the `main` branch. Prefer rebasing over
merging `main` into your PR branch to update it and resolve conflicts.
_If you have commit access to SwiftLint and believe your change to be trivial
and not worth waiting for review, you may open a pull request and merge
immediately, but this should be the exception, not the norm._
### Submodules
### Building And Running Locally
This SwiftLint repository uses submodules for its dependencies.
This means that if you decide to fork this repository to contribute to SwiftLint,
don't forget to checkout the submodules as well when cloning, by running
`git submodule update --init --recursive` after cloning.
#### Using Xcode
See more info [in the README](https://github.com/realm/SwiftLint#installation).
1. `git clone https://github.com/realm/SwiftLint.git`
1. `cd SwiftLint`
1. `xed .`
1. Select the "swiftlint" scheme
1. `cmd-opt-r` open the scheme options
1. Set the "Arguments Passed On Launch" you want in the "Arguments" tab. See
available arguments [in the README](https://github.com/realm/SwiftLint#command-line).
1. Set the "Working Directory" in the "Options" tab to the path where you would like
to execute SwiftLint. A folder that contains swift source files.
1. Hit "Run"
|Arguments|Options|
|-|-|
|![image](https://user-images.githubusercontent.com/5748627/115156411-d38c8780-a08c-11eb-9de4-939606c81574.png)|![image](https://user-images.githubusercontent.com/5748627/115156276-287bce00-a08c-11eb-9e1d-35684a665228.png)|
Then you can use the full power of Xcode/LLDB/Instruments to develop and debug your changes to SwiftLint.
#### Using the command line
1. `git clone https://github.com/realm/SwiftLint.git`
1. `cd SwiftLint`
1. `swift build [-c release]`
1. Use the produced `swiftlint` binary from the command line, either by running `swift run [-c release] [swiftlint] [arguments]` or by invoking the binary directly at `.build/[release|debug]/swiftlint`
1. [Optional] Attach LLDB: `lldb -- .build/[release|debug]/swiftlint [arguments]`
### Code Generation
@ -31,14 +57,14 @@ with Swift Package Manager on Linux. When contributing code changes, please
ensure that all three supported build methods continue to work and pass tests.
```shell
$ script/cibuild
$ xcodebuild -scheme swiftlint test
$ swift test
$ 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.
@ -52,6 +78,19 @@ over time. This way adding a unit test for your new Rule is just a matter of
adding a test case in `RulesTests.swift` which simply calls
`verifyRule(YourNewRule.description)`.
For debugging purposes examples can be marked as `focused`. If there are any
focused examples found, then only those will be run when running tests for that rule.
```
nonTriggeringExamples: [
Example("let x: [Int]"),
Example("let x: [Int: String]").focused() // only this one will be run in tests
],
triggeringExamples: [
Example("let x: ↓Array<String>"),
Example("let x: ↓Dictionary<Int, String>")
]
```
### `ConfigurationProviderRule`
If your rule supports user-configurable options via `.swiftlint.yml`, you can
@ -65,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/master/Source/SwiftLintFramework/Rules/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/master/Source/SwiftLintFramework/Rules/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/master/Source/SwiftLintFramework/Rules/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
@ -106,16 +145,40 @@ If your rule is configurable, but does not fit the pattern of
All changes should be made via pull requests on GitHub.
When issuing a pull request, please add a summary of your changes to
the `CHANGELOG.md` file.
When issuing a pull request with user-facing changes, please add a
summary of your changes to the `CHANGELOG.md` file.
We follow the same syntax as CocoaPods' CHANGELOG.md:
1. One Markdown unnumbered list item describing the change.
2. 2 trailing spaces on the last line describing the change.
2. 2 trailing spaces on the last line describing the change (so that Markdown renders each change [on its own line](https://daringfireball.net/projects/markdown/syntax#p)).
3. A list of Markdown hyperlinks to the contributors to the change. One entry
per line. Usually just one.
4. A list of Markdown hyperlinks to the issues the change addresses. One entry
per line. Usually just one. If there was no issue tracking this change,
you may instead link to the change's pull request.
5. All CHANGELOG.md content is hard-wrapped at 80 characters.
## CI
SwiftLint uses Azure Pipelines for most of its CI jobs, primarily because
they're the only CI provider to have a free tier with 10x concurrency on macOS.
Some CI jobs run in GitHub Actions (e.g. Docker).
Some CI jobs run on Buildkite using Mac Minis from MacStadium. These are jobs
that benefit from being run on the latest Xcode & macOS versions on bare metal.
### Buildkite Setup
To bring up a new Buildkite worker from MacStadium:
1. Change account password
1. Update macOS to the latest version
1. Install Homebrew: https://brew.sh
1. Install Buildkite agent and other tools via Homebrew:
`brew install aria2 bazelisk htop buildkite/buildkite/buildkite-agent robotsandpencils/made/xcodes`
1. Install latest Xcode version: `xcodes update && xcodes install 14.0.0`
1. Add `DANGER_GITHUB_API_TOKEN` and `HOME` to `/opt/homebrew/etc/buildkite-agent/hooks/environment`
1. Configure and launch buildkite agent: `brew info buildkite-agent` /
https://buildkite.com/organizations/swiftlint/agents#setup-macos

View File

@ -1,2 +0,0 @@
github "jpsim/SourceKitten" ~> 0.29.0
github "scottrhoyt/SwiftyTextTable" ~> 0.9.0

View File

@ -1,3 +0,0 @@
github "Carthage/Commandant" ~> 0.17.0
github "jpsim/Yams" ~> 2.0.0
github "jspahrsummers/xcconfigs" ~> 0.12.0

View File

@ -1,6 +0,0 @@
github "Carthage/Commandant" "0.17.0"
github "drmohundro/SWXMLHash" "5.0.1"
github "jpsim/SourceKitten" "0.29.0"
github "jpsim/Yams" "2.0.0"
github "jspahrsummers/xcconfigs" "0.12"
github "scottrhoyt/SwiftyTextTable" "0.9.0"

@ -1 +0,0 @@
Subproject commit ab68611013dec67413628ac87c1f29e8427bc8e4

@ -1 +0,0 @@
Subproject commit a4931e5c3bafbedeb1601d3bb76bbe835c6d475a

@ -1 +0,0 @@
Subproject commit 77a4dbbb477a8110eb8765e3c44c70fb4929098f

@ -1 +0,0 @@
Subproject commit c6df6cf533d120716bff38f8ff9885e1ce2a4ac3

@ -1 +0,0 @@
Subproject commit c947a306d2e80ecb2c0859047b35c73b8e1ca27f

@ -1 +0,0 @@
Subproject commit bb795558a76e5daf3688500055bbcfe243bffa8d

View File

@ -14,11 +14,13 @@ modified_files = git.modified_files + git.added_files
# including in a CHANGELOG for example
has_app_changes = !modified_files.grep(/Source/).empty?
has_test_changes = !modified_files.grep(/Tests/).empty?
has_danger_changes = !modified_files.grep(/Dangerfile|script\/oss-check|Gemfile/).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|MODULE\.bazel/).empty?
# Add a CHANGELOG entry for app changes
if !modified_files.include?('CHANGELOG.md') && has_app_changes
warn("Please include a CHANGELOG entry to credit yourself! \nYou can find it at [CHANGELOG.md](https://github.com/realm/SwiftLint/blob/master/CHANGELOG.md).")
warn("If this is a user-facing change, please include a CHANGELOG entry to credit yourself! \nYou can find it at [CHANGELOG.md](https://github.com/realm/SwiftLint/blob/main/CHANGELOG.md).")
markdown <<-MARKDOWN
Here's an example of your CHANGELOG entry:
```markdown
@ -30,7 +32,7 @@ Here's an example of your CHANGELOG entry:
MARKDOWN
end
return unless has_app_changes || has_danger_changes
return unless has_app_changes || has_danger_changes || has_package_changes || has_bazel_changes
# Non-trivial amounts of app changes without tests
if git.lines_of_code > 50 && has_app_changes && !has_test_changes
@ -49,7 +51,8 @@ end
file = Tempfile.new('violations')
Open3.popen3("script/oss-check -v 2> #{file.path}") do |_, stdout, _, _|
force_flag = has_danger_changes ? "--force" : ""
Open3.popen3("tools/oss-check -v #{force_flag} 2> #{file.path}") do |_, stdout, _, _|
while char = stdout.getc
print char
end

39
Dockerfile Normal file
View File

@ -0,0 +1,39 @@
# Explicitly specify `jammy` to keep the Swift & Ubuntu images in sync.
ARG BUILDER_IMAGE=swift:jammy
ARG RUNTIME_IMAGE=ubuntu:jammy
# builder image
FROM ${BUILDER_IMAGE} AS builder
RUN apt-get update && apt-get install -y \
libcurl4-openssl-dev \
libxml2-dev \
&& rm -r /var/lib/apt/lists/*
WORKDIR /workdir/
COPY Plugins Plugins/
COPY Source Source/
COPY Tests Tests/
COPY Package.* ./
RUN swift package update
ARG SWIFT_FLAGS="-c release -Xswiftc -static-stdlib -Xlinker -lCFURLSessionInterface -Xlinker -lCFXMLInterface -Xlinker -lcurl -Xlinker -lxml2 -Xswiftc -I. -Xlinker -fuse-ld=lld -Xlinker -L/usr/lib/swift/linux"
RUN swift build $SWIFT_FLAGS --product swiftlint
RUN mkdir -p /executables
RUN install -v `swift build $SWIFT_FLAGS --show-bin-path`/swiftlint /executables
# runtime image
FROM ${RUNTIME_IMAGE}
LABEL org.opencontainers.image.source https://github.com/realm/SwiftLint
RUN apt-get update && apt-get install -y \
libcurl4 \
libxml2 \
&& rm -r /var/lib/apt/lists/*
COPY --from=builder /usr/lib/libsourcekitdInProc.so /usr/lib
COPY --from=builder /usr/lib/swift/linux/libBlocksRuntime.so /usr/lib
COPY --from=builder /usr/lib/swift/linux/libdispatch.so /usr/lib
COPY --from=builder /usr/lib/swift/linux/libswiftCore.so /usr/lib
COPY --from=builder /executables/* /usr/bin
RUN swiftlint version
RUN echo "_ = 0" | swiftlint --use-stdin
CMD ["swiftlint"]

View File

@ -1,141 +1,157 @@
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.2)
activesupport (4.2.11.1)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
algoliasearch (1.27.1)
CFPropertyList (3.0.6)
rexml
activesupport (7.0.4.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
claide (1.0.3)
claide (1.1.0)
claide-plugins (0.9.2)
cork
nap
open4 (~> 1.3)
cocoapods (1.8.4)
activesupport (>= 4.0.2, < 5)
cocoapods (1.12.1)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.8.4)
cocoapods-core (= 1.12.1)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.2.2, < 2.0)
cocoapods-downloader (>= 1.6.0, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-stats (>= 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)
fourflusher (>= 2.3.0, < 3.0)
gh_inspector (~> 1.0)
molinillo (~> 0.6.6)
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (~> 1.4)
xcodeproj (>= 1.11.1, < 2.0)
cocoapods-core (1.8.4)
activesupport (>= 4.0.2, < 6)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.12.1)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
cocoapods-deintegrate (1.0.4)
cocoapods-downloader (1.3.0)
netrc (~> 0.11)
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.6.3)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.0)
cocoapods-stats (1.1.0)
cocoapods-trunk (1.4.1)
cocoapods-search (1.0.1)
cocoapods-trunk (1.6.0)
nap (>= 0.8, < 2.0)
netrc (~> 0.11)
cocoapods-try (1.1.0)
cocoapods-try (1.2.0)
colored2 (3.1.2)
concurrent-ruby (1.1.5)
concurrent-ruby (1.2.2)
cork (0.3.0)
colored2 (~> 3.1)
danger (6.1.0)
danger (9.2.0)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
cork (~> 0.1)
faraday (~> 0.9)
faraday (>= 0.9.0, < 3.0)
faraday-http-cache (~> 2.0)
git (~> 1.5)
kramdown (~> 2.0)
git (~> 1.7)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
octokit (~> 4.7)
terminal-table (~> 1)
octokit (~> 5.0)
terminal-table (>= 1, < 4)
escape (0.0.4)
faraday (0.17.3)
multipart-post (>= 1.2, < 3)
faraday-http-cache (2.0.0)
faraday (~> 0.8)
ffi (1.11.3)
ethon (0.16.0)
ffi (>= 1.15.0)
faraday (2.7.4)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-http-cache (2.4.1)
faraday (>= 0.8)
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.5.0)
git (1.18.0)
addressable (~> 2.8)
rchardet (~> 1.8)
httpclient (2.8.3)
i18n (0.9.5)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
jazzy (0.13.1)
jazzy (0.14.3)
cocoapods (~> 1.5)
mustache (~> 1.1)
open4
open4 (~> 1.3)
redcarpet (~> 3.4)
rexml (~> 3.2)
rouge (>= 2.0.6, < 4.0)
sassc (~> 2.1)
sqlite3 (~> 1.3)
xcinvoke (~> 0.3.0)
json (2.3.0)
kramdown (2.1.0)
json (2.6.3)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liferaft (0.0.6)
minitest (5.13.0)
molinillo (0.6.6)
multipart-post (2.1.1)
minitest (5.18.0)
molinillo (0.8.0)
mustache (1.1.1)
nanaimo (0.2.6)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
no_proxy_fix (0.1.2)
octokit (4.15.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
octokit (5.6.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
open4 (1.3.4)
public_suffix (4.0.3)
redcarpet (3.5.0)
rouge (3.14.0)
ruby-macho (1.4.0)
sassc (2.2.1)
public_suffix (4.0.7)
rchardet (1.8.0)
redcarpet (3.6.0)
rexml (3.2.5)
rouge (3.30.0)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
sassc (2.4.0)
ffi (~> 1.9)
sawyer (0.8.2)
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (> 0.8, < 2.0)
sqlite3 (1.4.2)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
thread_safe (0.3.6)
tzinfo (1.2.6)
thread_safe (~> 0.1)
unicode-display_width (1.6.0)
faraday (>= 0.17.3, < 3)
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.4.2)
xcinvoke (0.3.0)
liferaft (~> 0.0.6)
xcodeproj (1.14.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.2.6)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
PLATFORMS
ruby
arm64-darwin-21
arm64-darwin-22
DEPENDENCIES
cocoapods
@ -143,4 +159,4 @@ DEPENDENCIES
jazzy
BUNDLED WITH
2.0.2
2.4.12

27
MODULE.bazel Normal file
View File

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

133
Makefile
View File

@ -2,21 +2,16 @@ TEMPORARY_FOLDER?=/tmp/SwiftLint.dst
PREFIX?=/usr/local
BUILD_TOOL?=xcodebuild
XCODEFLAGS=-workspace 'SwiftLint.xcworkspace' \
-scheme 'swiftlint' \
XCODEFLAGS=-scheme 'swiftlint' \
DSTROOT=$(TEMPORARY_FOLDER) \
OTHER_LDFLAGS=-Wl,-headerpad_max_install_names
SWIFT_BUILD_FLAGS=--configuration release
UNAME=$(shell uname)
ifeq ($(UNAME), Darwin)
USE_SWIFT_STATIC_STDLIB:=$(shell test -d $$(dirname $$(xcrun --find swift))/../lib/swift_static/macosx && echo yes)
ifeq ($(USE_SWIFT_STATIC_STDLIB), yes)
SWIFT_BUILD_FLAGS+= -Xswiftc -static-stdlib
endif
endif
SWIFT_BUILD_FLAGS=--configuration release -Xlinker -dead_strip
SWIFTLINT_EXECUTABLE=$(shell swift build $(SWIFT_BUILD_FLAGS) --show-bin-path)/swiftlint
SWIFTLINT_EXECUTABLE_PARENT=.build/universal
SWIFTLINT_EXECUTABLE=$(SWIFTLINT_EXECUTABLE_PARENT)/swiftlint
ARTIFACT_BUNDLE_PATH=$(TEMPORARY_FOLDER)/SwiftLintBinary.artifactbundle
TSAN_LIB=$(subst bin/swift,lib/swift/clang/lib/darwin/libclang_rt.tsan_osx_dynamic.dylib,$(shell xcrun --find swift))
TSAN_SWIFT_BUILD_FLAGS=-Xswiftc -sanitize=thread
@ -29,41 +24,35 @@ LICENSE_PATH="$(shell pwd)/LICENSE"
OUTPUT_PACKAGE=SwiftLint.pkg
SWIFTLINT_PLIST=Source/swiftlint/Supporting Files/Info.plist
SWIFTLINTFRAMEWORK_PLIST=Source/SwiftLintFramework/Supporting Files/Info.plist
VERSION_STRING=$(shell ./tools/get-version)
VERSION_STRING=$(shell /usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "$(SWIFTLINT_PLIST)")
.PHONY: all bootstrap clean build install package test uninstall docs
.PHONY: all clean build install package test uninstall docs
all: build
sourcery: Source/SwiftLintFramework/Models/MasterRuleList.swift Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift Tests/LinuxMain.swift
sourcery: Source/SwiftLintBuiltInRules/Models/BuiltInRules.swift Source/SwiftLintCore/Models/ReportersList.swift Tests/GeneratedTests/GeneratedTests.swift
Tests/LinuxMain.swift: Tests/*/*.swift .sourcery/LinuxMain.stencil
sourcery --sources Tests --exclude-sources Tests/SwiftLintFrameworkTests/Resources --templates .sourcery/LinuxMain.stencil --output .sourcery --force-parse generated
mv .sourcery/LinuxMain.generated.swift Tests/LinuxMain.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
Source/SwiftLintFramework/Models/MasterRuleList.swift: Source/SwiftLintFramework/Rules/**/*.swift .sourcery/MasterRuleList.stencil
sourcery --sources Source/SwiftLintFramework/Rules --templates .sourcery/MasterRuleList.stencil --output .sourcery
mv .sourcery/MasterRuleList.generated.swift Source/SwiftLintFramework/Models/MasterRuleList.swift
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/SwiftLintFrameworkTests/AutomaticRuleTests.generated.swift: Source/SwiftLintFramework/Rules/**/*.swift .sourcery/AutomaticRuleTests.stencil
sourcery --sources Source/SwiftLintFramework/Rules --templates .sourcery/AutomaticRuleTests.stencil --output .sourcery
mv .sourcery/AutomaticRuleTests.generated.swift Tests/SwiftLintFrameworkTests/AutomaticRuleTests.generated.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
bootstrap:
script/bootstrap
test: clean_xcode bootstrap
test: clean_xcode
$(BUILD_TOOL) $(XCODEFLAGS) test
test_tsan:
swift build --build-tests $(TSAN_SWIFT_BUILD_FLAGS)
DYLD_INSERT_LIBRARIES=$(TSAN_LIB) $(TSAN_XCTEST) $(TSAN_TEST_BUNDLE)
write_xcodebuild_log: bootstrap
xcodebuild -workspace SwiftLint.xcworkspace -scheme swiftlint clean build-for-testing > xcodebuild.log
write_xcodebuild_log:
xcodebuild -scheme swiftlint clean build-for-testing -destination "platform=macOS" > xcodebuild.log
analyze: write_xcodebuild_log
swift run -c release swiftlint analyze --strict --compiler-log-path xcodebuild.log
@ -74,14 +63,19 @@ analyze_autocorrect: write_xcodebuild_log
clean:
rm -f "$(OUTPUT_PACKAGE)"
rm -rf "$(TEMPORARY_FOLDER)"
rm -f "./portable_swiftlint.zip"
rm -f "./*.zip" "bazel.tar.gz" "bazel.tar.gz.sha256"
swift package clean
clean_xcode:
$(BUILD_TOOL) $(XCODEFLAGS) -configuration Test clean
build:
swift build $(SWIFT_BUILD_FLAGS)
mkdir -p "$(SWIFTLINT_EXECUTABLE_PARENT)"
bazel build --config release universal_swiftlint
$(eval SWIFTLINT_BINARY := $(shell bazel cquery --config release --output=files universal_swiftlint))
mv "$(SWIFTLINT_BINARY)" "$(SWIFTLINT_EXECUTABLE)"
chmod +w "$(SWIFTLINT_EXECUTABLE)"
strip -rSTX "$(SWIFTLINT_EXECUTABLE)"
build_with_disable_sandbox:
swift build --disable-sandbox $(SWIFT_BUILD_FLAGS)
@ -107,25 +101,50 @@ portable_zip: installables
cp -f "$(LICENSE_PATH)" "$(TEMPORARY_FOLDER)"
(cd "$(TEMPORARY_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./portable_swiftlint.zip"
package: installables
spm_artifactbundle_macos: installables
mkdir -p "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin"
sed 's/__VERSION__/$(VERSION_STRING)/g' tools/info-macos.json.template > "$(ARTIFACT_BUNDLE_PATH)/info.json"
cp -f "$(SWIFTLINT_EXECUTABLE)" "$(ARTIFACT_BUNDLE_PATH)/swiftlint-$(VERSION_STRING)-macos/bin"
cp -f "$(LICENSE_PATH)" "$(ARTIFACT_BUNDLE_PATH)"
(cd "$(TEMPORARY_FOLDER)"; zip -yr - "SwiftLintBinary.artifactbundle") > "./SwiftLintBinary-macos.artifactbundle.zip"
zip_linux: docker_image
$(eval TMP_FOLDER := $(shell mktemp -d))
docker run swiftlint cat /usr/bin/swiftlint > "$(TMP_FOLDER)/swiftlint"
chmod +x "$(TMP_FOLDER)/swiftlint"
cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)"
(cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip"
zip_linux_release:
$(eval TMP_FOLDER := $(shell mktemp -d))
docker run --platform linux/amd64 "ghcr.io/realm/swiftlint:$(VERSION_STRING)" cat /usr/bin/swiftlint > "$(TMP_FOLDER)/swiftlint"
chmod +x "$(TMP_FOLDER)/swiftlint"
cp -f "$(LICENSE_PATH)" "$(TMP_FOLDER)"
(cd "$(TMP_FOLDER)"; zip -yr - "swiftlint" "LICENSE") > "./swiftlint_linux.zip"
gh release upload "$(VERSION_STRING)" swiftlint_linux.zip
package: build
$(eval PACKAGE_ROOT := $(shell mktemp -d))
cp "$(SWIFTLINT_EXECUTABLE)" "$(PACKAGE_ROOT)"
pkgbuild \
--identifier "io.realm.swiftlint" \
--install-location "/" \
--root "$(TEMPORARY_FOLDER)" \
--install-location "/usr/local/bin" \
--root "$(PACKAGE_ROOT)" \
--version "$(VERSION_STRING)" \
"$(OUTPUT_PACKAGE)"
archive:
carthage build --no-skip-current --platform mac
carthage archive SwiftLintFramework
bazel_release:
bazel build :release
mv bazel-bin/bazel.tar.gz bazel-bin/bazel.tar.gz.sha256 .
release: package archive portable_zip
docker_image:
docker build --platform linux/amd64 --force-rm --tag swiftlint .
docker_test:
docker run -v `pwd`:`pwd` -w `pwd` --name swiftlint --rm norionomura/swift:51 swift test --parallel
docker run -v `pwd`:`pwd` -w `pwd` --name swiftlint --rm swift:5.7-focal swift test --parallel
docker_htop:
docker run -it --rm --pid=container:swiftlint terencewestphal/htop || reset
docker run --platform linux/amd64 -it --rm --pid=container:swiftlint terencewestphal/htop || reset
# https://irace.me/swift-profiling
display_compilation_time:
@ -133,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
pod trunk push SwiftLintFramework.podspec
pod trunk push SwiftLint.podspec
bundle install
bundle exec pod trunk push SwiftLint.podspec
docs:
swift run swiftlint generate-docs
@ -142,22 +161,32 @@ docs:
bundle exec jazzy
get_version:
@echo $(VERSION_STRING)
@echo "$(VERSION_STRING)"
push_version:
release:
ifneq ($(strip $(shell git status --untracked-files=no --porcelain 2>/dev/null)),)
$(error git state is not clean)
endif
$(eval NEW_VERSION_AND_NAME := $(filter-out $@,$(MAKECMDGOALS)))
$(eval NEW_VERSION := $(shell echo $(NEW_VERSION_AND_NAME) | sed 's/:.*//' ))
@sed -i '' 's/## Master/## $(NEW_VERSION_AND_NAME)/g' CHANGELOG.md
@sed 's/__VERSION__/$(NEW_VERSION)/g' script/Version.swift.template > Source/SwiftLintFramework/Models/Version.swift
@/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $(NEW_VERSION)" "$(SWIFTLINTFRAMEWORK_PLIST)"
@/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $(NEW_VERSION)" "$(SWIFTLINT_PLIST)"
@sed -i '' 's/## Main/## $(NEW_VERSION_AND_NAME)/g' CHANGELOG.md
@sed 's/__VERSION__/$(NEW_VERSION)/g' tools/Version.swift.template > Source/SwiftLintCore/Models/Version.swift
@sed -e '3s/.*/ version = "$(NEW_VERSION)",/' -i '' MODULE.bazel
make clean
make package
make bazel_release
make portable_zip
make spm_artifactbundle_macos
./tools/update-artifact-bundle.sh "$(NEW_VERSION)"
git commit -a -m "release $(NEW_VERSION)"
git tag -a $(NEW_VERSION) -m "$(NEW_VERSION_AND_NAME)"
git push origin master
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

@ -1,97 +1,77 @@
{
"object": {
"pins": [
"pins" : [
{
"package": "Commandant",
"repositoryURL": "https://github.com/Carthage/Commandant.git",
"state": {
"branch": null,
"revision": "ab68611013dec67413628ac87c1f29e8427bc8e4",
"version": "0.17.0"
"identity" : "collectionconcurrencykit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git",
"state" : {
"revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95",
"version" : "0.2.0"
}
},
{
"package": "CwlCatchException",
"repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git",
"state": {
"branch": null,
"revision": "7cd2f8cacc4d22f21bc0b2309c3b18acf7957b66",
"version": "1.2.0"
"identity" : "cryptoswift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/krzyzanowskim/CryptoSwift.git",
"state" : {
"revision" : "32f641cf24fc7abc1c591a2025e9f2f572648b0f",
"version" : "1.7.2"
}
},
{
"package": "CwlPreconditionTesting",
"repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git",
"state": {
"branch": null,
"revision": "c228db5d2ad1b01ebc84435e823e6cca4e3db98b",
"version": "1.2.0"
"identity" : "sourcekitten",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/SourceKitten.git",
"state" : {
"revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56",
"version" : "0.34.1"
}
},
{
"package": "Nimble",
"repositoryURL": "https://github.com/Quick/Nimble.git",
"state": {
"branch": null,
"revision": "b02b00b30b6353632aa4a5fb6124f8147f7140c0",
"version": "8.0.5"
"identity" : "swift-argument-parser",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-argument-parser.git",
"state" : {
"revision" : "4ad606ba5d7673ea60679a61ff867cc1ff8c8e86",
"version" : "1.2.1"
}
},
{
"package": "Quick",
"repositoryURL": "https://github.com/Quick/Quick.git",
"state": {
"branch": null,
"revision": "33682c2f6230c60614861dfc61df267e11a1602f",
"version": "2.2.0"
"identity" : "swift-syntax",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "165fc6d22394c1168ff76ab5d951245971ef07e5",
"version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a"
}
},
{
"package": "SourceKitten",
"repositoryURL": "https://github.com/jpsim/SourceKitten.git",
"state": {
"branch": null,
"revision": "77a4dbbb477a8110eb8765e3c44c70fb4929098f",
"version": "0.29.0"
"identity" : "swiftytexttable",
"kind" : "remoteSourceControl",
"location" : "https://github.com/scottrhoyt/SwiftyTextTable.git",
"state" : {
"revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
"version" : "0.9.0"
}
},
{
"package": "SwiftSyntax",
"repositoryURL": "https://github.com/apple/swift-syntax.git",
"state": {
"branch": null,
"revision": "3e3eb191fcdbecc6031522660c4ed6ce25282c25",
"version": "0.50100.0"
"identity" : "swxmlhash",
"kind" : "remoteSourceControl",
"location" : "https://github.com/drmohundro/SWXMLHash.git",
"state" : {
"revision" : "4d0f62f561458cbe1f732171e625f03195151b60",
"version" : "7.0.1"
}
},
{
"package": "SwiftyTextTable",
"repositoryURL": "https://github.com/scottrhoyt/SwiftyTextTable.git",
"state": {
"branch": null,
"revision": "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3",
"version": "0.9.0"
}
},
{
"package": "SWXMLHash",
"repositoryURL": "https://github.com/drmohundro/SWXMLHash.git",
"state": {
"branch": null,
"revision": "a4931e5c3bafbedeb1601d3bb76bbe835c6d475a",
"version": "5.0.1"
}
},
{
"package": "Yams",
"repositoryURL": "https://github.com/jpsim/Yams.git",
"state": {
"branch": null,
"revision": "c947a306d2e80ecb2c0859047b35c73b8e1ca27f",
"version": "2.0.0"
"identity" : "yams",
"kind" : "remoteSourceControl",
"location" : "https://github.com/jpsim/Yams.git",
"state" : {
"revision" : "f47ba4838c30dbd59998a4e4c87ab620ff959e8a",
"version" : "5.0.5"
}
}
]
},
"version": 1
],
"version" : 2
}

View File

@ -1,59 +1,121 @@
// swift-tools-version:5.0
// swift-tools-version:5.7
import PackageDescription
#if canImport(CommonCrypto)
private let addCryptoSwift = false
#else
private let addCryptoSwift = true
#endif
#if compiler(>=5.1.0)
private let addSwiftSyntax = true
#else
private let addSwiftSyntax = false
#endif
let package = Package(
name: "SwiftLint",
platforms: [
.macOS(.v10_12)
],
platforms: [.macOS(.v12)],
products: [
.executable(name: "swiftlint", targets: ["swiftlint"]),
.library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"])
.library(name: "SwiftLintFramework", targets: ["SwiftLintFramework"]),
.plugin(name: "SwiftLintPlugin", targets: ["SwiftLintPlugin"])
],
dependencies: [
.package(url: "https://github.com/Carthage/Commandant.git", .upToNextMinor(from: "0.17.0")),
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.29.0")),
.package(url: "https://github.com/jpsim/Yams.git", from: "2.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.2.1")),
.package(url: "https://github.com/apple/swift-syntax.git", exact: "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-06-05-a"),
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.34.1")),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.5"),
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
] + (addCryptoSwift ? [.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))] : []) +
(addSwiftSyntax ? [.package(url: "https://github.com/apple/swift-syntax.git", .exact("0.50100.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: [
.target(
.plugin(
name: "SwiftLintPlugin",
capability: .buildTool(),
dependencies: [
.target(name: "SwiftLintBinary", condition: .when(platforms: [.macOS])),
.target(name: "swiftlint", condition: .when(platforms: [.linux]))
]
),
.executableTarget(
name: "swiftlint",
dependencies: [
"Commandant",
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"CollectionConcurrencyKit",
"SwiftLintFramework",
"SwiftyTextTable",
]
),
.testTarget(
name: "CLITests",
dependencies: [
"swiftlint"
]
),
.target(
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: [
"SourceKittenFramework",
"Yams",
] + (addCryptoSwift ? ["CryptoSwift"] : []) +
(addSwiftSyntax ? ["SwiftSyntax"] : [])
"SwiftLintBuiltInRules",
"SwiftLintCore",
"SwiftLintExtraRules"
]
),
.target(name: "DyldWarningWorkaround"),
.target(
name: "SwiftLintTestHelpers",
dependencies: [
"SwiftLintFramework"
],
path: "Tests/SwiftLintTestHelpers"
),
.testTarget(
name: "SwiftLintFrameworkTests",
dependencies: [
"SwiftLintFramework"
"SwiftLintFramework",
"SwiftLintTestHelpers"
],
exclude: [
"Resources",
]
),
.testTarget(
name: "GeneratedTests",
dependencies: [
"SwiftLintFramework",
"SwiftLintTestHelpers"
]
),
.testTarget(
name: "IntegrationTests",
dependencies: [
"SwiftLintFramework",
"SwiftLintTestHelpers"
]
),
.testTarget(
name: "ExtraRulesTests",
dependencies: [
"SwiftLintFramework",
"SwiftLintTestHelpers"
]
),
.binaryTarget(
name: "SwiftLintBinary",
url: "https://github.com/realm/SwiftLint/releases/download/0.52.2/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "89651e1c87fb62faf076ef785a5b1af7f43570b2b74c6773526e0d5114e0578e"
)
]
)

View File

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

View File

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

528
README.md
View File

@ -1,15 +1,14 @@
# SwiftLint
A tool to enforce Swift style and conventions, loosely based on
[GitHub's Swift Style Guide](https://github.com/github/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
[AST](http://clang.llvm.org/docs/IntroductionToTheClangAST.html) representation
of your source files for more accurate results.
[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=master)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=master)
[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=master)](https://codecov.io/github/realm/SwiftLint?branch=master)
[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=main)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=main)
[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=main)](https://codecov.io/github/realm/SwiftLint?branch=main)
![](assets/screenshot.png)
@ -17,7 +16,7 @@ This project adheres to the [Contributor Covenant Code of Conduct](https://realm
By participating, you are expected to uphold this code. Please report
unacceptable behavior to [info@realm.io](mailto:info@realm.io).
> Language Switch: [中文](https://github.com/realm/SwiftLint/blob/master/README_CN.md), [한국어](https://github.com/realm/SwiftLint/blob/master/README_KR.md).
> Language Switch: [中文](https://github.com/realm/SwiftLint/blob/main/README_CN.md), [한국어](https://github.com/realm/SwiftLint/blob/main/README_KR.md).
## Installation
@ -42,7 +41,7 @@ in your Script Build Phases.
This is the recommended way to install a specific version of SwiftLint since it supports
installing a pinned version rather than simply the latest (which is the case with Homebrew).
Note that this will add the SwiftLint binaries, its dependencies' binaries and the Swift binary
Note that this will add the SwiftLint binaries, its dependencies' binaries, and the Swift binary
library distribution to the `Pods/` directory, so checking in this directory to SCM such as
git is discouraged.
@ -58,22 +57,77 @@ You can also install SwiftLint by downloading `SwiftLint.pkg` from the
[latest GitHub release](https://github.com/realm/SwiftLint/releases/latest) and
running it.
### Compiling from source:
### Installing from source:
You can also build from source by cloning this project and running
`script/bootstrap; make install` (Xcode 11.0 or later).
You can also build and install from source by cloning this project and running
`make install` (Xcode 13.3 or later).
### Known Installation Issues On MacOS Before 10.14.4
### Using Bazel
Starting with [SwiftLint 0.32.0](https://github.com/realm/SwiftLint/releases/tag/0.32.0), if you get
an error similar to `dyld: Symbol not found: _$s11SubSequenceSlTl` when running SwiftLint,
you'll need to install the [Swift 5 Runtime Support for Command Line Tools](https://support.apple.com/kb/DL1998).
Put this in your `MODULE.bazel`:
Alternatively, you can:
```bzl
bazel_dep(name = "swiftlint", version = "0.50.4", repo_name = "SwiftLint")
```
* Update to macOS 10.14.4 or later
* Install Xcode 10.2 or later at `/Applications/Xcode.app`
* Rebuild SwiftLint from source using Xcode 10.2 or later
Or put this in your `WORKSPACE`:
<details>
<summary>WORKSPACE</summary>
```bzl
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "build_bazel_rules_apple",
sha256 = "f94e6dddf74739ef5cb30f000e13a2a613f6ebfa5e63588305a71fce8a8a9911",
url = "https://github.com/bazelbuild/rules_apple/releases/download/1.1.3/rules_apple.1.1.3.tar.gz",
)
load(
"@build_bazel_rules_apple//apple:repositories.bzl",
"apple_rules_dependencies",
)
apple_rules_dependencies()
load(
"@build_bazel_rules_swift//swift:repositories.bzl",
"swift_rules_dependencies",
)
swift_rules_dependencies()
load(
"@build_bazel_rules_swift//swift:extras.bzl",
"swift_rules_extra_dependencies",
)
swift_rules_extra_dependencies()
http_archive(
name = "SwiftLint",
sha256 = "7c454ff4abeeecdd9513f6293238a6d9f803b587eb93de147f9aa1be0d8337c4",
url = "https://github.com/realm/SwiftLint/releases/download/0.49.1/bazel.tar.gz",
)
load("@SwiftLint//bazel:repos.bzl", "swiftlint_repos")
swiftlint_repos()
load("@SwiftLint//bazel:deps.bzl", "swiftlint_deps")
swiftlint_deps()
```
</details>
Then you can run SwiftLint in the current directory with this command:
```console
bazel run -c opt @SwiftLint//:swiftlint
```
## Usage
@ -82,49 +136,113 @@ Alternatively, you can:
To get a high-level overview of recommended ways to integrate SwiftLint into your project,
we encourage you to watch this presentation or read the transcript:
[![Presentation](assets/presentation.svg)](https://academy.realm.io/posts/slug-jp-simard-swiftlint/)
[![Presentation](assets/presentation.svg)](https://youtu.be/9Z1nTMTejqU)
### Xcode
Integrate SwiftLint into an Xcode scheme to get warnings and errors displayed
in the IDE. Just add a new "Run Script Phase" with:
Integrate SwiftLint into your Xcode project to get warnings and errors displayed
in the issue navigator.
To do this select the project in the file navigator, then select the primary app
target, and go to Build Phases. Click the + and select "New Run Script Phase".
Insert the following as the script:
![](assets/runscript.png)
If you installed SwiftLint via Homebrew on Apple Silicon, you might experience this warning:
> warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint
That is because Homebrew on Apple Silicon installs the binaries into the `/opt/homebrew/bin`
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
if which swiftlint >/dev/null; then
if [[ "$(uname -m)" == arm64 ]]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if which swiftlint > /dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
```
![](assets/runscript.png)
or you can create a symbolic link in `/usr/local/bin` pointing to the actual binary:
Alternatively, if you've installed SwiftLint via CocoaPods the script should look like this:
```bash
ln -s /opt/homebrew/bin/swiftlint /usr/local/bin/swiftlint
```
You might want to move your SwiftLint phase directly before the 'Compile Sources'
step to detect errors quickly before compiling. However, SwiftLint is designed
to run on valid Swift code that cleanly completes the compiler's parsing stage.
So running SwiftLint before 'Compile Sources' might yield some incorrect
results.
If you wish to fix violations as well, your script could run
`swiftlint --fix && swiftlint` instead of just `swiftlint`. This will mean
that all correctable violations are fixed while ensuring warnings show up in
your project for remaining violations.
If you've installed SwiftLint via CocoaPods the script should look like this:
```bash
"${PODS_ROOT}/SwiftLint/swiftlint"
```
#### Format on Save Xcode Plugin
### Plug-in Support
To run `swiftlint autocorrect` on save in Xcode, install the
[SwiftLintXcode](https://github.com/ypresto/SwiftLintXcode) plugin from Alcatraz.
SwiftLint can be used as a build tool plug-in for both Xcode projects as well as
Swift packages.
This plugin will not work with Xcode 8 or later without disabling SIP.
This is not recommended.
> Due to limitations with Swift Package Manager Plug-ins this is only
recommended for projects that have a SwiftLint configuration in their root directory as
there is currently no way to pass any additional options to the SwiftLint executable.
### AppCode
#### Xcode
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 `autocorrect` action is available via `⌥⏎`.
You can integrate SwiftLint as an Xcode Build Tool Plug-in if you're working
with a project in Xcode.
### Atom
Add SwiftLint as a package dependency to your project without linking any of the
products.
To integrate SwiftLint with [Atom](https://atom.io/), install the
[`linter-swiftlint`](https://atom.io/packages/linter-swiftlint) package from
APM.
Select the target you want to add linting to and open the `Build Phases` inspector.
Open `Run Build Tool Plug-ins` and select the `+` button.
Select `SwiftLintPlugin` from the list and add it to the project.
![](assets/select-swiftlint-plugin.png)
For unattended use (e.g. on CI), you can disable the package validation dialog by
* individually passing `-skipPackagePluginValidation` to `xcodebuild` or
* globally setting `defaults write com.apple.dt.Xcode IDESkipPackagePluginFingerprintValidatation -bool YES`
for that user.
_Note: This implicitly trusts all Xcode package plugins and bypasses Xcode's package validation
dialogs, which has security implications._
#### Swift Package
You can integrate SwiftLint as a Swift Package Manager Plug-in if you're working with
a Swift Package with a `Package.swift` manifest.
Add SwiftLint as a package dependency to your `Package.swift` file.
Add SwiftLint to a target using the `plugins` parameter.
```swift
.target(
...
plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")]
),
```
### Visual Studio Code
To integrate SwiftLint with [vscode](https://code.visualstudio.com), install the
[`vscode-swiftlint`](https://marketplace.visualstudio.com/items?itemName=vknabel.vscode-swiftlint) extension from the marketplace.
### fastlane
@ -148,32 +266,65 @@ swiftlint(
)
```
### Docker
`swiftlint` is also available as a [Docker](https://www.docker.com/) image using `Ubuntu`.
So just the first time you need to pull the docker image using the next command:
```bash
docker pull ghcr.io/realm/swiftlint:latest
```
Then following times, you just run `swiftlint` inside of the docker like:
```bash
docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest
```
This will execute `swiftlint` in the folder where you are right now (`pwd`), showing an output like:
```bash
$ docker run -it -v `pwd`:`pwd` -w `pwd` ghcr.io/realm/swiftlint:latest
Linting Swift files in current working directory
Linting 'RuleDocumentation.swift' (1/490)
...
Linting 'YamlSwiftLintTests.swift' (490/490)
Done linting! Found 0 violations, 0 serious in 490 files.
```
Here you have more documentation about the usage of [Docker Images](https://docs.docker.com/).
### Command Line
```
$ swiftlint help
Available commands:
OVERVIEW: A tool to enforce Swift style and conventions.
analyze [Experimental] Run analysis rules
autocorrect Automatically correct warnings and errors
USAGE: swiftlint <subcommand>
OPTIONS:
--version Show the version.
-h, --help Show help information.
SUBCOMMANDS:
analyze Run analysis rules
docs Open SwiftLint documentation website in the default web browser
generate-docs Generates markdown documentation for all rules
help Display general or command-specific help
lint Print lint warnings and errors (default command)
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
See 'swiftlint help <subcommand>' for detailed help.
```
Run `swiftlint` in the directory containing the Swift files to lint. Directories
will be searched recursively.
To specify a list of files when using `lint`, `autocorrect` or `analyze`
To specify a list of files when using `lint` or `analyze`
(like the list of files modified by Xcode specified by the
[`ExtraBuildPhase`](https://github.com/norio-nomura/ExtraBuildPhase) Xcode
plugin, or modified files in the working tree based on `git ls-files -m`), you
can do so by passing the option `--use-script-input-files` and setting the
following instance variables: `SCRIPT_INPUT_FILE_COUNT` and
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`...`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT}`.
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`...`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}`.
These are same environment variables set for input files to
[custom Xcode script phases](http://indiestack.com/2014/12/speeding-up-custom-script-phases/).
@ -209,36 +360,48 @@ You may also set the `TOOLCHAINS` environment variable to the reverse-DNS
notation that identifies a Swift toolchain version:
```shell
$ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint autocorrect
$ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint --fix
```
On Linux, SourceKit is expected to be located in
`/usr/lib/libsourcekitdInProc.so` or specified by the `LINUX_SOURCEKIT_LIB_PATH`
environment variable.
### Swift Version Support
### pre-commit
Here's a reference of which SwiftLint version to use for a given Swift version.
SwiftLint can be run as a [pre-commit](https://pre-commit.com/) hook.
Once [installed](https://pre-commit.com/#install), add this to the
`.pre-commit-config.yaml` in the root of your repository:
| Swift version | Last supported SwiftLint release |
|:----------------|:---------------------------------|
| Swift 1.x | SwiftLint 0.1.2 |
| Swift 2.x | SwiftLint 0.18.1 |
| Swift 3.x | SwiftLint 0.25.1 |
| Swift 4.0-4.1.x | SwiftLint 0.28.2 |
| Swift 4.2.x | SwiftLint 0.35.0 |
| Swift 5.x | Latest |
```yaml
repos:
- repo: https://github.com/realm/SwiftLint
rev: 0.50.3
hooks:
- id: swiftlint
```
Adjust `rev` to the SwiftLint version of your choice. `pre-commit autoupdate` can be used to update to the current version.
SwiftLint can be configured using `entry` to apply fixes and fail on errors:
```yaml
- repo: https://github.com/realm/SwiftLint
rev: 0.50.3
hooks:
- id: swiftlint
entry: swiftlint --fix --strict
```
## Rules
Over 75 rules are included in SwiftLint and the Swift community (that's you!)
Over 200 rules are included in SwiftLint and the Swift community (that's you!)
continues to contribute more over time.
[Pull requests](CONTRIBUTING.md) are encouraged.
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](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
@ -316,23 +479,33 @@ run SwiftLint from. The following parameters can be configured:
Rule inclusion:
* `disabled_rules`: Disable rules from the default enabled set.
* `opt_in_rules`: Enable rules not from the default set.
* `whitelist_rules`: Acts as a whitelist, only the rules specified in this list
will be enabled. Can not be specified alongside `disabled_rules` or
`opt_in_rules`.
* `opt_in_rules`: Enable rules that are not part of the default set. The
special `all` identifier will enable all opt in linter rules, except the ones
listed in `disabled_rules`.
* `only_rules`: Only the rules specified in this list will be enabled.
Cannot be specified alongside `disabled_rules` or `opt_in_rules`.
* `analyzer_rules`: This is an entirely separate list of rules that are only
run by the `analyze` command. All analyzer rules are opt-in, so this is the
only configurable rule list (there is no disabled/whitelist equivalent).
only configurable rule list, there are no equivalents for `disabled_rules`
`only_rules`.
```yaml
disabled_rules: # rule identifiers to exclude from running
# By default, SwiftLint uses a set of sensible default rules you can adjust:
disabled_rules: # rule identifiers turned on by default to exclude from running
- colon
- comma
- control_statement
opt_in_rules: # some rules are only opt-in
- empty_count
# Find all the available rules by running:
# swiftlint rules
opt_in_rules: # some rules are turned off by default, so you need to opt-in
- empty_count # Find all the available rules by running: `swiftlint rules`
# Alternatively, specify all rules explicitly by uncommenting this option:
# only_rules: # delete `disabled_rules` & `opt_in_rules` if using this
# - empty_parameters
# - vertical_whitespace
analyzer_rules: # Rules run by `swiftlint analyze`
- explicit_self
included: # paths to include during linting. `--path` is ignored if present.
- Source
excluded: # paths to ignore during linting. Takes precedence over `included`.
@ -341,8 +514,9 @@ excluded: # paths to ignore during linting. Takes precedence over `included`.
- Source/ExcludedFolder
- Source/ExcludedFile.swift
- Source/*/ExcludedFile.swift # Exclude files with a wildcard
analyzer_rules: # Rules run by `swiftlint analyze` (experimental)
- explicit_self
# If true, SwiftLint will not fail if no lintable files are found.
allow_zero_lintable_files: false
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
@ -376,13 +550,29 @@ identifier_name:
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown)
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:
@ -390,10 +580,12 @@ following syntax:
```yaml
custom_rules:
pirates_beat_ninjas: # rule identifier
included: ".*\\.swift" # regex that defines paths to include during linting. optional.
excluded: ".*Test\\.swift" # regex that defines paths to exclude during linting. optional
included:
- ".*\\.swift" # regex that defines paths to include during linting. optional.
excluded:
- ".*Test\\.swift" # regex that defines paths to exclude during linting. optional
name: "Pirates Beat Ninjas" # rule name. optional.
regex: "([n,N]inja)" # matching pattern
regex: "([nN]inja)" # matching pattern
capture_group: 0 # number of regex capture group to highlight the rule violation at. optional.
match_kinds: # SyntaxKinds to match. optional.
- comment
@ -401,7 +593,7 @@ custom_rules:
message: "Pirates are better than ninjas." # violation message. optional.
severity: error # violation severity. optional.
no_hiding_in_strings:
regex: "([n,N]inja)"
regex: "([nN]inja)"
match_kinds: string
```
@ -413,39 +605,40 @@ You can filter the matches by providing one or more `match_kinds`, which will
reject matches that include syntax kinds that are not present in this list. Here
are all the possible syntax kinds:
* argument
* attribute.builtin
* attribute.id
* buildconfig.id
* buildconfig.keyword
* comment
* comment.mark
* comment.url
* doccomment
* doccomment.field
* identifier
* keyword
* number
* objectliteral
* parameter
* placeholder
* string
* string_interpolation_anchor
* typeidentifier
* `argument`
* `attribute.builtin`
* `attribute.id`
* `buildconfig.id`
* `buildconfig.keyword`
* `comment`
* `comment.mark`
* `comment.url`
* `doccomment`
* `doccomment.field`
* `identifier`
* `keyword`
* `number`
* `objectliteral`
* `parameter`
* `placeholder`
* `string`
* `string_interpolation_anchor`
* `typeidentifier`
If using custom rules alongside a whitelist, make sure to add `custom_rules` as an item under `whitelist_rules`.
All syntax kinds used in a snippet of Swift code can be extracted asking
[SourceKitten](https://github.com/jpsim/SourceKitten). For example,
`sourcekitten syntax --text "struct S {}"` delivers
#### Nested Configurations
* `source.lang.swift.syntaxtype.keyword` for the `struct` keyword and
* `source.lang.swift.syntaxtype.identifier` for its name `S`
SwiftLint supports nesting configuration files for more granular control over
the linting process.
which match to `keyword` and `identifier` in the above list.
* Include additional `.swiftlint.yml` files where necessary in your directory
structure.
* Each file will be linted using the configuration file that is in its
directory or at the deepest level of its parent directories. Otherwise the
root configuration will be used.
* `included` is ignored for nested configurations.
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
@ -453,27 +646,136 @@ SwiftLint can automatically correct certain violations. Files on disk are
overwritten with a corrected version.
Please make sure to have backups of these files before running
`swiftlint autocorrect`, otherwise important data may be lost.
`swiftlint --fix`, otherwise important data may be lost.
Standard linting is disabled while correcting because of the high likelihood of
violations (or their offsets) being incorrect after modifying a file while
applying corrections.
### Analyze (experimental)
### Analyze
The _experimental_ `swiftlint analyze` command can lint Swift files using the
The `swiftlint analyze` command can lint Swift files using the
full type-checked AST. The compiler log path containing the clean `swiftc` build
command invocation (incremental builds will fail) must be passed to `analyze`
via the `--compiler-log-path` flag.
e.g. `--compiler-log-path /path/to/xcodebuild.log`
This can be obtained by running
`xcodebuild -workspace {WORKSPACE}.xcworkspace -scheme {SCHEME} > xcodebuild.log`
with a clean `DerivedData` folder.
This can be obtained by
This command and related code in SwiftLint is subject to substantial changes at
any time while this feature is marked as experimental. Analyzer rules also tend
to be considerably slower than lint rules.
1. Cleaning DerivedData (incremental builds won't work with analyze)
2. Running `xcodebuild -workspace {WORKSPACE}.xcworkspace -scheme {SCHEME} > xcodebuild.log`
3. Running `swiftlint analyze --compiler-log-path xcodebuild.log`
Analyzer rules tend to be considerably slower than lint rules.
## Using Multiple Configuration Files
SwiftLint offers a variety of ways to include multiple configuration files.
Multiple configuration files get merged into one single configuration that is then applied
just as a single configuration file would get applied.
There are quite a lot of use cases where using multiple configuration files could be helpful:
For instance, one could use a team-wide shared SwiftLint configuration while allowing overrides
in each project via a child configuration file.
Team-Wide Configuration:
```yaml
disabled_rules:
- force_cast
```
Project-Specific Configuration:
```yaml
opt_in_rules:
- force_cast
```
### Child / Parent Configs (Locally)
You can specify a `child_config` and / or a `parent_config` reference within a configuration file.
These references should be local paths relative to the folder of the configuration file they are specified in.
This even works recursively, as long as there are no cycles and no ambiguities.
**A child config is treated as a refinement and therefore has a higher priority**,
while a parent config is considered a base with lower priority in case of conflicts.
Here's an example, assuming you have the following file structure:
```
ProjectRoot
|_ .swiftlint.yml
|_ .swiftlint_refinement.yml
|_ Base
|_ .swiftlint_base.yml
```
To include both the refinement and the base file, your `.swiftlint.yml` should look like this:
```yaml
child_config: .swiftlint_refinement.yml
parent_config: Base/.swiftlint_base.yml
```
When merging parent and child configs, `included` and `excluded` configurations
are processed carefully to account for differences in the directory location
of the containing configuration files.
### Child / Parent Configs (Remote)
Just as you can provide local `child_config` / `parent_config` references, instead of
referencing local paths, you can just put urls that lead to configuration files.
In order for SwiftLint to detect these remote references, they must start with `http://` or `https://`.
The referenced remote configuration files may even recursively reference other
remote configuration files, but aren't allowed to include local references.
Using a remote reference, your `.swiftlint.yml` could look like this:
```yaml
parent_config: https://myteamserver.com/our-base-swiftlint-config.yml
```
Every time you run SwiftLint and have an Internet connection, SwiftLint tries to get a new version of
every remote configuration that is referenced. If this request times out, a cached version is
used if available. If there is no cached version available, SwiftLint fails but no worries, a cached version
should be there once SwiftLint has run successfully at least once.
If needed, the timeouts for the remote configuration fetching can be specified manually via the
configuration file(s) using the `remote_timeout` / `remote_timeout_if_cached` specifiers.
These values default to 2 / 1 second(s).
### Command Line
Instead of just providing one configuration file when running SwiftLint via the command line,
you can also pass a hierarchy, where the first configuration is treated as a parent,
while the last one is treated as the highest-priority child.
A simple example including just two configuration files looks like this:
`swiftlint --config .swiftlint.yml --config .swiftlint_child.yml`
### Nested Configurations
In addition to a main configuration (the `.swiftlint.yml` file in the root folder),
you can put other configuration files named `.swiftlint.yml` into the directory structure
that then get merged as a child config, but only with an effect for those files
that are within the same directory as the config or in a deeper directory where
there isn't another configuration file. In other words: Nested configurations don't work
recursively there's a maximum number of one nested configuration per file
that may be applied in addition to the main configuration.
`.swiftlint.yml` files are only considered as a nested configuration if they have not been
used to build the main configuration already (e. g. by having been referenced via something
like `child_config: Folder/.swiftlint.yml`). Also, `parent_config` / `child_config`
specifications of nested configurations are getting ignored because there's no sense to that.
If one (or more) SwiftLint file(s) are explicitly specified via the `--config` parameter,
that configuration will be treated as an override, no matter whether there exist
other `.swiftlint.yml` files somewhere within the directory. **So if you want to use
nested configurations, you can't use the `--config` parameter.**
## License

View File

@ -1,11 +1,11 @@
# SwiftLint
SwiftLint 是一个用于强制检查 Swift 代码风格和规定的一个工具,基本上以 [GitHub's Swift 代码风格指南](https://github.com/github/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) 来表示源代码文件的更多精确结果。
[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=master)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=master)
[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=master)](https://codecov.io/github/realm/SwiftLint?branch=master)
[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=main)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=main)
[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=main)](https://codecov.io/github/realm/SwiftLint?branch=main)
![](assets/screenshot.png)
@ -45,7 +45,7 @@ $ mint install realm/SwiftLint
### 编译源代码:
你也可以通过 Clone SwiftLint 的 Git 仓库到本地然后执行 `git submodule update --init --recursive; make install` (Xcode 10.2+) 编译源代码的方式来安装。
你也可以通过 Clone SwiftLint 的 Git 仓库到本地然后执行 `make install` (Xcode 12.5+) 编译源代码的方式来安装。
## 用法
@ -77,7 +77,7 @@ fi
#### 格式化保存 Xcode 插件
在 XCode 中保存时执行 `swiftlint autocorrect`,需要从 Alcatraz 安装 [SwiftLintXcode](https://github.com/ypresto/SwiftLintXcode) 插件。
在 Xcode 中保存时执行 `swiftlint autocorrect`,需要从 Alcatraz 安装 [SwiftLintXcode](https://github.com/ypresto/SwiftLintXcode) 插件。
⚠ ️如果没有禁用 SIP 的话,这个插件在 Xcode 8 或者更新版本的 Xcode 上将不会工作。不推荐此操作。
@ -127,7 +127,7 @@ Available commands:
在包含有需要执行代码分析的 Swift 源码文件的目录下执行 `swiftlint` 命令,会对目录进行递归查找。
当使用 `lint` 或者 `autocorrect` 命令时,你可以通过添加 `--use-script-input-files` 选项并且设置以下实例变量:`SCRIPT_INPUT_FILE_COUNT` 和
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`... `SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT}` 的方式来指定一个文件列表(就像被 Xcode 特别是 [`ExtraBuildPhase`](https://github.com/norio-nomura/ExtraBuildPhase) Xcode 插件修改的文件组成的列表,或者类似 Git 工作树中 `git ls-files -m` 命令显示的被修改的文件列表)。
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`... `SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}` 的方式来指定一个文件列表(就像被 Xcode 特别是 [`ExtraBuildPhase`](https://github.com/norio-nomura/ExtraBuildPhase) Xcode 插件修改的文件组成的列表,或者类似 Git 工作树中 `git ls-files -m` 命令显示的被修改的文件列表)。
也有类似的用来设置输入文件的环境变量以 [自定义 Xcode script phases](http://indiestack.com/2014/12/speeding-up-custom-script-phases/) 。
@ -161,26 +161,13 @@ $ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint autocorrect
在 Linux 上SourceKit 默认需要位于 `/usr/lib/libsourcekitdInProc.so` 或者通过 `LINUX_SOURCEKIT_LIB_PATH` 环境变量进行指定。
### Swift Version Support
这里有一份 SwiftLint 版本和对应该 Swift 版本的对照表作为参考。
| Swift 版本 | 最后一个 SwiftLint 支持版本 |
|:----------------|:----------------------------|
| Swift 1.x | SwiftLint 0.1.2 |
| Swift 2.x | SwiftLint 0.18.1 |
| Swift 3.x | SwiftLint 0.25.1 |
| Swift 4.0-4.1.x | SwiftLint 0.28.2 |
| Swift 4.2.x | SwiftLint 0.35.0 |
| Swift 5.x | 最新的 |
## 规则
SwiftLint 已经包含了超过 75 条规则,并且我们希望 Swift 社区(就是你!)会在以后有更多的贡献,我们鼓励提交 [Pull Requests](CONTRIBUTING.md)。
你可以在 [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` 默认是关闭的(即,你需要在你的配置文件中明确地打开它们)。
@ -232,7 +219,7 @@ let noWarning3 = NSNumber() as! Int
* `disabled_rules`: 关闭某些默认开启的规则。
* `opt_in_rules`: 一些规则是可选的。
* `whitelist_rules`: 不可以和 `disabled_rules` 或者 `opt_in_rules` 并列。类似一个白名单,只有在这个列表中的规则才是开启的。
* `only_rules`: 不可以和 `disabled_rules` 或者 `opt_in_rules` 并列。类似一个白名单,只有在这个列表中的规则才是开启的。
```yaml
disabled_rules: # 执行时排除掉的规则
@ -283,7 +270,7 @@ identifier_name:
- id
- URL
- GlobalAPIKey
reporter: "xcode" # 报告类型 (xcode, json, csv, checkstyle, junit, html, emoji)
reporter: "xcode" # 报告类型 (xcode, json, csv, checkstyle, codeclimate, junit, html, emoji, sonarqube, markdown, github-actions-logging)
```
#### 定义自定义规则
@ -294,14 +281,14 @@ reporter: "xcode" # 报告类型 (xcode, json, csv, checkstyle, junit, html, emo
custom_rules:
pirates_beat_ninjas: # 规则标识符
name: "Pirates Beat Ninjas" # 规则名称,可选
regex: "([n,N]inja)" # 匹配的模式
regex: "([nN]inja)" # 匹配的模式
match_kinds: # 需要匹配的语法类型,可选
- comment
- identifier
message: "Pirates are better than ninjas." # 提示信息,可选
severity: error # 提示的级别,可选
no_hiding_in_strings:
regex: "([n,N]inja)"
regex: "([nN]inja)"
match_kinds: string
```

View File

@ -1,11 +1,11 @@
# SwiftLint
SwiftLint는 스위프트 스타일 및 컨벤션을 강제하기 위한 도구로, [GitHub 스위프트 스타일 가이드](https://github.com/github/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) 표현을 사용합니다.
[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=master)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=master)
[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=master)](https://codecov.io/github/realm/SwiftLint?branch=master)
[![Build Status](https://dev.azure.com/jpsim/SwiftLint/_apis/build/status/realm.SwiftLint?branchName=main)](https://dev.azure.com/jpsim/SwiftLint/_build/latest?definitionId=4?branchName=main)
[![codecov.io](https://codecov.io/github/realm/SwiftLint/coverage.svg?branch=main)](https://codecov.io/github/realm/SwiftLint?branch=main)
![](assets/screenshot.png)
@ -27,11 +27,11 @@ Podfile에 아래 라인을 추가하기만 하면 됩니다.
pod 'SwiftLint'
```
이를 실행하면 다음번 `pod install` 실행시 SwiftLint 바이너리 및 `Pods/`에 있는 디펜던시들을 다운로드하고, Script Build Phases에서 `${PODS_ROOT}/SwiftLint/swiftlint` 명령을 사용할 수 있게 됩니다.
이를 실행하면 다음번 `pod install` 실행 시 SwiftLint 바이너리 및 `Pods/`에 있는 디펜던시들을 다운로드하고, Script Build Phases에서 `${PODS_ROOT}/SwiftLint/swiftlint` 명령을 사용할 수 있게 됩니다.
CocoaPods를 사용하면 최신 버전 외에도 SwiftLint의 특정 버전을 설치할 수 있기 때문에 이 방법을 권장합니다. (Homebrew는 최신 버전만 설치 가능)
이렇게 했을때 SwiftLint 바이너리 및 그에 종속된 바이너리들과 스위프트 바이너리까지 `Pods/` 디렉토리에 추가되기 때문에, git 등의 SCM에 이런 디렉토리들을 체크인하는 것은 권장하지 않습니다.
이렇게 했을 때 SwiftLint 바이너리 및 그에 종속된 바이너리들과 스위프트 바이너리까지 `Pods/` 디렉터리에 추가되기 때문에, git 등의 SCM에 이런 디렉터리들을 체크인하는 것은 권장하지 않습니다.
### [Mint](https://github.com/yonaskolb/mint)를 사용하는 경우:
```
@ -44,7 +44,7 @@ $ mint install realm/SwiftLint
### 소스를 직접 컴파일하는 경우:
본 프로젝트를 클론해서 빌드할 수도 있습니다. `git submodule update --init --recursive; make install` 명령을 사용합니다. (Xcode 10.2 이후 버전)
본 프로젝트를 클론해서 빌드할 수도 있습니다. `make install` 명령을 사용합니다. (Xcode 12.5 이후 버전)
## 사용 방법
@ -56,7 +56,7 @@ $ mint install realm/SwiftLint
### Xcode
SwiftLint를 Xcode 스킴에 통합하여 IDE 상에 경고나 에러를 표시할 수 있습니다. "Run Script Phase"를 새로 만들고 아래 스크립트를 추가하기만 하면 됩니다.
SwiftLint를 Xcode 프로젝트에 통합하여 IDE 상에 경고나 에러를 표시할 수 있습니다. 프로젝트의 파일 내비게이터에서 타겟 앱을 선택 후 "Build Phases" 탭으로 이동합니다. + 버튼을 클릭한 후 "Run Script Phase"를 선택합니다. 그 후 아래 스크립트를 추가하기만 하면 됩니다.
```bash
if which swiftlint >/dev/null; then
@ -68,6 +68,34 @@ fi
![](assets/runscript.png)
만약, 애플 실리콘 환경에서 Homebrew를 통해 SwiftLint를 설치했다면, 아마도 다음과 같은 경고를 겪었을 것입니다.
> warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint
그 이유는, 애플 실리콘 기반 맥에서 Homebrew는 기본적으로 바이너리들을 `/opt/homebrew/bin`에 저장하기 때문입니다. SwiftLint가 어디 있는지 찾는 것을 Xcode에 알려주기 위해, build phase에서 `/opt/homebrew/bin``PATH` 환경 변수에 동시에 추가하여야 합니다.
```bash
if [[ "$(uname -m)" == arm64 ]]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if which swiftlint > /dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
```
혹은 아래와 같이 `/usr/local/bin`에 심볼릭 링크를 생성하여 실제 바이너리가 있는 곳으로 포인팅할 수 있습니다. :
```bash
ln -s /opt/homebrew/bin/swiftlint /usr/local/bin/swiftlint
```
당신은 SwiftLint phase를 'Compile Sources' 단계 직전으로 옮겨 컴파일 전에 에러를 빠르게 찾고 싶어 할 것입니다. 하지만, SwiftLint는 컴파일러의 구문 분석 단계를 완벽히 수행하는 유효한 Swift 코드를 실행하기 위해 설계되었습니다. 따라서, 'Compile Sources' 전에 SwiftLint를 실행하면 일부 부정확한 오류가 발생할 수도 있습니다.
만약 당신은 위반 사항(violations)을 동시에 수정하는 것을 원한다면, 스크립트에 `swiftlint` 대신 `swiftlint --fix && swiftlint`을 적어야 합니다. 이는 프로젝트의 수정 가능한 모든 위반 사항들이 수정되고 나머지 위반 사항에 대한 경고가 표시된다는 것을 의미합니다.
CocoaPods를 사용해서 설치한 경우는 아래 스크립트를 대신 사용합니다.
```bash
@ -95,7 +123,7 @@ fastlane 과정에서 SwiftLint를 사용하려면 [공식적인 fastlane 액션
```ruby
swiftlint(
mode: :lint, # SwiftLint 모드: :lint (디폴트) 아니면 :autocorrect
 executable: "Pods/SwiftLint/swiftlint", # SwiftLint 바이너리 경로 (선택 가능). CocoaPods를 사용해서 설치한 경우는 이 션이 중요합니다
 executable: "Pods/SwiftLint/swiftlint", # SwiftLint 바이너리 경로 (선택 가능). CocoaPods를 사용해서 설치한 경우는 이 션이 중요합니다
 output_file: "swiftlint.result.json", # 결과 파일의 경로 (선택 가능)
 reporter: "json", # 보고 유형 (선택 가능)
 config_file: ".swiftlint-ci.yml",     # 설정 파일의 경로 (선택 가능)
@ -116,16 +144,16 @@ Available commands:
version Display the current version of SwiftLint
```
스위프트 파일이 있는 디렉토리에서 `swiftlint`를 실행합니다. 디렉토리는 재귀적으로 탐색됩니다.
스위프트 파일이 있는 디렉터리에서 `swiftlint`를 실행합니다. 디렉터리는 재귀적으로 탐색됩니다.
`lint``autocorrect`를 사용할 때 여러 파일(예를 들면, [`ExtraBuildPhase`](https://github.com/norio-nomura/ExtraBuildPhase) 플러그인에 의해 Xcode가 변경한 파일들 혹은 `git ls-files -m` 명령으로 인해 작업 트리에서 변경된 파일들)을 지정하려면 `--use-script-input-files` 옵션을 넘기고 다음 인스턴스 변수들을 설정하면 됩니다. `SCRIPT_INPUT_FILE_COUNT` and
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`...`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT}`
`SCRIPT_INPUT_FILE_0`, `SCRIPT_INPUT_FILE_1`...`SCRIPT_INPUT_FILE_{SCRIPT_INPUT_FILE_COUNT - 1}`
이는 [Xcode의 커스텀 스크립트 단계](http://indiestack.com/2014/12/speeding-up-custom-script-phases/)에 입력 파일로 환경 변수를 지정하는 것과 동일합니다.
### 스위프트 여러 버전에 대한 대응
SwiftLint는 SourceKit에 연결되어 있으므로 스위프트 언어가 변화하더라도 이상없이 동작할 수 있습니다.
SwiftLint는 SourceKit에 연결되어 있으므로 스위프트 언어가 변화하더라도 이상 없이 동작할 수 있습니다.
이는 전체 스위프트 컴파일러가 포함되지 않아도 되므로 SwiftLint가 간결하게 유지될 수 있습니다. SwiftLint는 데스크탑에 이미 설치되어 있는 공식 스위프트 컴파일러와 통신하기만 하면 됩니다.
@ -143,7 +171,7 @@ SwiftLint가 어느 스위프트 툴체인을 사용할지 결정하는 순서
* `~/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`
* `~/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`
`sourcekitd.framework`은 위에서 선택된 경로의 `usr/lib/` 하위 디렉리에 존재해야 합니다.
`sourcekitd.framework`은 위에서 선택된 경로의 `usr/lib/` 하위 디렉리에 존재해야 합니다.
`TOOLCHAINS` 환경 변수에 스위프트 툴체인 버전을 식별할 수 있는 값을 리버스 DNS 형식으로 지정할 수도 있습니다.
@ -155,9 +183,9 @@ $ TOOLCHAINS=com.apple.dt.toolchain.Swift_2_3 swiftlint autocorrect
## 룰
SwiftLint에는 75개가 넘는 룰들이 있고, 스위프트 커뮤니티(바로 여러분들!)는 이를 지속적으로 발전시켜 가고 있습니다. [풀 리퀘스트](CONTRIBUTING.md)는 언제나 환영입니다.
SwiftLint에는 200개가 넘는 룰들이 있고, 스위프트 커뮤니티(바로 여러분들!)는 이를 지속적으로 발전시켜 가고 있습니다. [풀 리퀘스트](CONTRIBUTING.md)는 언제나 환영입니다.
현재 구현된 룰 전체를 확인하려면 [Source/SwiftLintFramework/Rules](Source/SwiftLintFramework/Rules)를 살펴보세요.
현재 구현된 룰 전체를 확인하려면 [Source/SwiftLintBuiltInRules/Rules](Source/SwiftLintBuiltInRules/Rules)를 살펴보세요.
`opt_in_rules`는 기본적으로 비활성화되어 있습니다. (즉, 설정 파일에서 명시적으로 해당 룰을 활성화해야 합니다.)
@ -169,11 +197,11 @@ SwiftLint에는 75개가 넘는 룰들이 있고, 스위프트 커뮤니티(바
### 코드에서 룰 비활성화하기
소스 파일에서 아래 형식의 주석을 사용하면 룰을 비활성화 할 수 있습니다.
소스 파일에서 아래 형식의 주석을 사용하면 룰을 비활성화할 수 있습니다.
`// swiftlint:disable <룰1> [<룰2> <룰3>...]`
비활성화 된 룰은 해당 파일의 마지막까지 적용되거나, 활성화 주석이 나타날 때까지 적용됩니다.
비활성화된 룰은 해당 파일의 마지막까지 적용되거나, 활성화 주석이 나타날 때까지 적용됩니다.
`// swiftlint:enable <룰1> [<룰2> <룰3>...]`
@ -203,13 +231,13 @@ let noWarning3 = NSNumber() as! Int
### 설정
SwiftLint가 실행될 디렉리에 `.swiftlint.yml` 파일을 추가해서 SwiftLint를 설정할 수 있습니다. 아래 파라미터들을 설정 가능합니다.
SwiftLint가 실행될 디렉리에 `.swiftlint.yml` 파일을 추가해서 SwiftLint를 설정할 수 있습니다. 아래 파라미터들을 설정 가능합니다.
룰 적용여부 설정:
* `disabled_rules`: 기본 활성화된 룰 중에 비활성화할 룰들을 지정합니다.
* `opt_in_rules`: 기본 룰이 아닌 룰들을 활성화합니다.
* `whitelist_rules`: 지정한 룰들만 활성화되도록 화이트리스트로 지정합니다. `disabled_rules``opt_in_rules`과는 같이 사용할 수 없습니다.
* `only_rules`: 지정한 룰들만 활성화되도록 화이트리스트로 지정합니다. `disabled_rules``opt_in_rules`과는 같이 사용할 수 없습니다.
```yaml
disabled_rules: # 실행에서 제외할 룰 식별자들
@ -258,7 +286,7 @@ identifier_name:
- id
- URL
- GlobalAPIKey
reporter: "xcode" # 보고 유형 (xcode, json, csv, checkstyle, junit, html, emoji, markdown)
reporter: "xcode" # 보고 유형 (xcode, json, csv, codeclimate, checkstyle, junit, html, emoji, sonarqube, markdown, github-actions-logging)
```
#### 커스텀 룰 정의
@ -268,16 +296,16 @@ reporter: "xcode" # 보고 유형 (xcode, json, csv, checkstyle, junit, html, em
```yaml
custom_rules:
pirates_beat_ninjas: # 룰 식별자
included: ".*.swift" # 린트 실행시 포함할 경로를 정의하는 정규표현식. 선택 가능.
included: ".*.swift" # 린트 실행 시 포함할 경로를 정의하는 정규표현식. 선택 가능.
name: "Pirates Beat Ninjas" # 룰 이름. 선택 가능.
regex: "([n,N]inja)" # 패턴 매칭
regex: "([nN]inja)" # 패턴 매칭
match_kinds: # 매칭할 SyntaxKinds. 선택 가능.
- comment
- identifier
message: "Pirates are better than ninjas." # 위반 메시지. 선택 가능.
severity: error # 위반 수준. 선택 가능.
no_hiding_in_strings:
regex: "([n,N]inja)"
regex: "([nN]inja)"
match_kinds: string
```
@ -285,7 +313,7 @@ custom_rules:
![](assets/custom-rule.png)
하나 이상의 `match_kinds`를 사용해서 매칭된 결과를 필터링 할 수 있습니다. 이 목록에 들어있지 않은 구문 유형이 포함된 결과는 매칭에서 제외됩니다. 사용 가능한 모든 구문 유형은 다음과 같습니다.
하나 이상의 `match_kinds`를 사용해서 매칭된 결과를 필터링할 수 있습니다. 이 목록에 들어있지 않은 구문 유형이 포함된 결과는 매칭에서 제외됩니다. 사용 가능한 모든 구문 유형은 다음과 같습니다.
* argument
* attribute.builtin
@ -311,13 +339,13 @@ custom_rules:
SwiftLint는 설정 파일을 중첩되게 구성해서 린트 과정을 더욱 세밀하게 제어할 수 있습니다.
* 디렉리 구조에서 필요한 곳이면 어디든지 `.swiftlint.yml` 파일을 추가할 수 있습니다.
* 각 파일은 자신의 디렉토리 내에 있는 설정 파일을 사용하거나, 계층구조 상 가장 가까운 부모 디렉토리에 있는 설정 파일을 사용해서 린트됩니다. 별도로 설정 파일이 존재하지 않으면 루트에 있는 설정 파일이 사용됩니다.
* 디렉리 구조에서 필요한 곳이면 어디든지 `.swiftlint.yml` 파일을 추가할 수 있습니다.
* 각 파일은 자신의 디렉터리 내에 있는 설정 파일을 사용하거나, 계층구조 상 가장 가까운 부모 디렉터리에 있는 설정 파일을 사용해서 린트됩니다. 별도로 설정 파일이 존재하지 않으면 루트에 있는 설정 파일이 사용됩니다.
* 중첩 구성에서 `excluded``included`는 무시됩니다.
### 자동 수정
SwiftLint는 일부 위반 사항들을 자동으로 수정할 수 있습니다. 디스크상의 파일들은 수정된 버전으로 덮어 쓰여지게 됩니다.
SwiftLint는 일부 위반 사항들을 자동으로 수정할 수 있습니다. 디스크 상의 파일들은 수정된 버전으로 덮어 쓰여지게 됩니다.
`swiftlint autocorrect`를 실행하기 전에 파일들을 백업해주세요. 그렇지 않으면 중요한 데이터가 유실될 수도 있습니다.

View File

@ -7,16 +7,8 @@ For SwiftLint contributors, follow these steps to cut a release:
* FabricSoftenerRule
* Top Loading
* Fresh Out Of The Dryer
2. Push new version: `make push_version "0.2.0: Tumble Dry"`
3. Make sure you have the latest stable Xcode version installed and
`xcode-select`ed.
4. Create the pkg installer, framework zip, and portable zip: `make release`
5. 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 pkg installer, framework zip, and portable zip you just built
to the GitHub release binaries.
* Click "Publish release".
6. Publish to Homebrew and CocoaPods trunk: `make publish`
7. Celebrate. :tada:
1. Make sure you have the latest stable Xcode version installed and
`xcode-select`ed
1. Release new version: `make release "0.2.0: Tumble Dry"`
1. Wait for the Docker CI job to finish then run: `make zip_linux_release`
1. Celebrate. :tada:

View File

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

View File

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

View File

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

View File

@ -0,0 +1,187 @@
import SourceKittenFramework
/// Struct to represent SwiftUI ViewModifiers for the purpose of finding modifiers in a substructure.
struct SwiftUIModifier {
/// Name of the modifier.
let name: String
/// List of arguments to check for in the modifier.
let arguments: [Argument]
struct Argument {
/// Name of the argument we want to find. For single unnamed arguments, use the empty string.
let name: String
/// Whether or not the argument is required. If the argument is present, value checks are enforced.
/// Allows for better handling of modifiers with default values for certain arguments where we want
/// to ensure that the default value is used.
let required: Bool
/// List of possible values for the argument. Typically should just be a list with a single element,
/// but allows for the flexibility of checking for multiple possible values. To only check for the presence
/// of the modifier and not enforce any certain values, pass an empty array. All values are parsed as
/// Strings; for other types (boolean, numeric, optional, etc) types you can check for "true", "5", "nil", etc.
let values: [String]
/// Success criteria used for matching values (prefix, suffix, substring, exact match, or none).
let matchType: MatchType
init(name: String, required: Bool = true, values: [String], matchType: MatchType = .exactMatch) {
self.name = name
self.required = required
self.values = values
self.matchType = matchType
}
}
enum MatchType {
case prefix, suffix, substring, exactMatch
/// Compares the parsed argument value to a target value for the given match type
/// and returns true is a match is found.
func matches(argumentValue: String, targetValue: String) -> Bool {
switch self {
case .prefix:
return argumentValue.hasPrefix(targetValue)
case .suffix:
return argumentValue.hasSuffix(targetValue)
case .substring:
return argumentValue.contains(targetValue)
case .exactMatch:
return argumentValue == targetValue
}
}
}
}
/// Extensions for recursively checking SwiftUI code for certain modifiers.
extension SourceKittenDictionary {
/// Call on a SwiftUI View to recursively check the substructure for a certain modifier with certain arguments.
/// - Parameters:
/// - modifiers: A list of `SwiftUIModifier` structs to check for in the view's substructure.
/// In most cases, this can just be a single modifier, but since some modifiers have
/// multiple versions, this enables checking for any modifier from the list.
/// - file: The SwiftLintFile object for the current file, used to extract argument values.
/// - Returns: A boolean value representing whether or not the given modifier with the specified
/// arguments appears in the view's substructure.
func hasModifier(anyOf modifiers: [SwiftUIModifier], in file: SwiftLintFile) -> Bool {
// SwiftUI ViewModifiers are treated as `call` expressions, and we make sure we can get the expression's name.
guard expressionKind == .call, let name else {
return false
}
// If any modifier from the list matches, return true.
for modifier in modifiers {
// Check for the given modifier name
guard name.hasSuffix(modifier.name) else {
continue
}
// Check arguments.
var matchesArgs = true
for argument in modifier.arguments {
var foundArg = false
var argValue: String?
// Check for single unnamed argument.
if argument.name.isEmpty {
foundArg = true
argValue = getSingleUnnamedArgumentValue(in: file)
} else if let parsedArgument = enclosedArguments.first(where: { $0.name == argument.name }) {
foundArg = true
argValue = parsedArgument.getArgumentValue(in: file)
}
// If argument is not required and we didn't find it, continue.
if !foundArg && !argument.required {
continue
}
// Otherwise, we must have found an argument with a non-nil value to continue.
guard foundArg, let argumentValue = argValue else {
matchesArgs = false
break
}
// Argument value can match any of the options given in the argument struct.
if argument.values.isEmpty || argument.values.contains(where: {
argument.matchType.matches(argumentValue: argumentValue, targetValue: $0)
}) {
// Found a match, continue to next argument.
continue
} else {
// Did not find a match, exit loop over arguments.
matchesArgs = false
break
}
}
// Return true if all arguments matched
if matchesArgs {
return true
}
}
// Recursively check substructure.
// SwiftUI literal Views with modifiers will have a SourceKittenDictionary structure like:
// Image("myImage").resizable().accessibility(hidden: true).frame
// --> Image("myImage").resizable().accessibility
// --> Image("myImage").resizable
// --> Image
return substructure.contains(where: { $0.hasModifier(anyOf: modifiers, in: file) })
}
// MARK: Sample use cases of `hasModifier` that are used in multiple rules
/// Whether or not the dictionary represents a SwiftUI View with an `accesibilityHidden(true)`
/// or `accessibility(hidden: true)` modifier.
func hasAccessibilityHiddenModifier(in file: SwiftLintFile) -> Bool {
return hasModifier(
anyOf: [
SwiftUIModifier(
name: "accessibilityHidden",
arguments: [.init(name: "", values: ["true"])]
),
SwiftUIModifier(
name: "accessibility",
arguments: [.init(name: "hidden", values: ["true"])]
)
],
in: file
)
}
/// Whether or not the dictionary represents a SwiftUI View with an `accessibilityElement()` or
/// `accessibilityElement(children: .ignore)` modifier (`.ignore` is the default parameter value).
func hasAccessibilityElementChildrenIgnoreModifier(in file: SwiftLintFile) -> Bool {
return hasModifier(
anyOf: [
SwiftUIModifier(
name: "accessibilityElement",
arguments: [.init(name: "children", required: false, values: [".ignore"], matchType: .suffix)]
)
],
in: file
)
}
// MARK: Helpers to extract argument values
/// Helper to get the value of an argument.
func getArgumentValue(in file: SwiftLintFile) -> String? {
guard expressionKind == .argument, let bodyByteRange else {
return nil
}
return file.stringView.substringWithByteRange(bodyByteRange)
}
/// Helper to get the value of a single unnamed argument to a function call.
func getSingleUnnamedArgumentValue(in file: SwiftLintFile) -> String? {
guard expressionKind == .call, let bodyByteRange else {
return nil
}
return file.stringView.substringWithByteRange(bodyByteRange)
}
}

View File

@ -0,0 +1,109 @@
import SwiftSyntax
import SwiftSyntaxBuilder
/// A helper to hold a visitor and rewriter that can lint and correct legacy NS/CG functions to a more modern syntax.
enum LegacyFunctionRuleHelper {
final class Visitor: ViolationsSyntaxVisitor {
private let legacyFunctions: [String: RewriteStrategy]
init(legacyFunctions: [String: RewriteStrategy]) {
self.legacyFunctions = legacyFunctions
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: FunctionCallExprSyntax) {
if node.isLegacyFunctionExpression(legacyFunctions: legacyFunctions) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
enum RewriteStrategy {
case equal
case property(name: String)
case function(name: String, argumentLabels: [String], reversed: Bool = false)
var expectedInitialArguments: Int {
switch self {
case .equal:
return 2
case .property:
return 1
case .function(name: _, argumentLabels: let argumentLabels, reversed: _):
return argumentLabels.count + 1
}
}
}
final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
private(set) var correctionPositions: [AbsolutePosition] = []
private let locationConverter: SourceLocationConverter
private let disabledRegions: [SourceRange]
private let legacyFunctions: [String: RewriteStrategy]
init(
legacyFunctions: [String: RewriteStrategy],
locationConverter: SourceLocationConverter,
disabledRegions: [SourceRange]
) {
self.legacyFunctions = legacyFunctions
self.locationConverter = locationConverter
self.disabledRegions = disabledRegions
}
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
guard
node.isLegacyFunctionExpression(legacyFunctions: legacyFunctions),
let funcName = node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.text,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter)
else {
return super.visit(node)
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
let trimmedArguments = node.argumentList.map { $0.trimmingTrailingComma() }
let rewriteStrategy = legacyFunctions[funcName]
let expr: ExprSyntax
switch rewriteStrategy {
case .equal:
expr = "\(trimmedArguments[0]) == \(trimmedArguments[1])"
case let .property(name: propertyName):
expr = "\(trimmedArguments[0]).\(raw: propertyName)"
case let .function(name: functionName, argumentLabels: argumentLabels, reversed: reversed):
let arguments = reversed ? trimmedArguments.reversed() : trimmedArguments
let params = zip(argumentLabels, arguments.dropFirst())
.map { $0.isEmpty ? "\($1)" : "\($0): \($1)" }
.joined(separator: ", ")
expr = "\(arguments[0]).\(raw: functionName)(\(raw: params))"
case .none:
return super.visit(node)
}
return expr
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
}
}
private extension FunctionCallExprSyntax {
func isLegacyFunctionExpression(legacyFunctions: [String: LegacyFunctionRuleHelper.RewriteStrategy]) -> Bool {
guard
let calledExpression = calledExpression.as(IdentifierExprSyntax.self),
let rewriteStrategy = legacyFunctions[calledExpression.identifier.text],
argumentList.count == rewriteStrategy.expectedInitialArguments
else {
return false
}
return true
}
}
private extension TupleExprElementSyntax {
func trimmingTrailingComma() -> TupleExprElementSyntax {
self.trimmed.with(\.trailingComma, nil).trimmed
}
}

View File

@ -1,12 +1,18 @@
// Generated using Sourcery 0.17.0 https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 2.0.2 https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT
/// The rule list containing all available rules built into SwiftLint.
public let masterRuleList = RuleList(rules: [
public let builtInRules: [Rule.Type] = [
AccessibilityLabelForImageRule.self,
AccessibilityTraitForButtonRule.self,
AnonymousArgumentInMultilineClosureRule.self,
AnyObjectProtocolRule.self,
ArrayInitRule.self,
AttributesRule.self,
BalancedXCTestLifecycleRule.self,
BlanketDisableCommandRule.self,
BlockBasedKVORule.self,
CaptureVariableRule.self,
ClassDelegateProtocolRule.self,
ClosingBraceRule.self,
ClosureBodyLengthRule.self,
@ -15,8 +21,11 @@ public let masterRuleList = RuleList(rules: [
ClosureSpacingRule.self,
CollectionAlignmentRule.self,
ColonRule.self,
CommaInheritanceRule.self,
CommaRule.self,
CommentSpacingRule.self,
CompilerProtocolInitRule.self,
ComputedAccessorsOrderRule.self,
ConditionalReturnsOnNewlineRule.self,
ContainsOverFilterCountRule.self,
ContainsOverFilterIsEmptyRule.self,
@ -24,16 +33,20 @@ public let masterRuleList = RuleList(rules: [
ContainsOverRangeNilComparisonRule.self,
ControlStatementRule.self,
ConvenienceTypeRule.self,
CustomRules.self,
CyclomaticComplexityRule.self,
DeploymentTargetRule.self,
DirectReturnRule.self,
DiscardedNotificationCenterObserverRule.self,
DiscouragedAssertRule.self,
DiscouragedDirectInitRule.self,
DiscouragedNoneNameRule.self,
DiscouragedObjectLiteralRule.self,
DiscouragedOptionalBooleanRule.self,
DiscouragedOptionalCollectionRule.self,
DuplicateConditionsRule.self,
DuplicateEnumCasesRule.self,
DuplicateImportsRule.self,
DuplicatedKeyInDictionaryLiteralRule.self,
DynamicInlineRule.self,
EmptyCollectionLiteralRule.self,
EmptyCountRule.self,
@ -68,13 +81,16 @@ public let masterRuleList = RuleList(rules: [
FunctionDefaultParameterAtEndRule.self,
FunctionParameterCountRule.self,
GenericTypeNameRule.self,
IBInspectableInExtensionRule.self,
IdenticalOperandsRule.self,
IdentifierNameRule.self,
ImplicitGetterRule.self,
ImplicitReturnRule.self,
ImplicitlyUnwrappedOptionalRule.self,
InclusiveLanguageRule.self,
IndentationWidthRule.self,
InertDeferRule.self,
InvalidSwiftLintCommandRule.self,
IsDisjointRule.self,
JoinedDefaultParameterRule.self,
LargeTupleRule.self,
@ -86,10 +102,12 @@ public let masterRuleList = RuleList(rules: [
LegacyHashingRule.self,
LegacyMultipleRule.self,
LegacyNSGeometryFunctionsRule.self,
LegacyObjcTypeRule.self,
LegacyRandomRule.self,
LetVarWhitespaceRule.self,
LineLengthRule.self,
LiteralExpressionEndIdentationRule.self,
LiteralExpressionEndIndentationRule.self,
LocalDocCommentRule.self,
LowerACLThanParentRule.self,
MarkRule.self,
MissingDocsRule.self,
@ -103,12 +121,14 @@ public let masterRuleList = RuleList(rules: [
MultipleClosuresWithTrailingClosureRule.self,
NSLocalizedStringKeyRule.self,
NSLocalizedStringRequireBundleRule.self,
NSNumberInitAsFunctionReferenceRule.self,
NSObjectPreferIsEqualRule.self,
NestingRule.self,
NimbleOperatorRule.self,
NoExtensionAccessModifierRule.self,
NoFallthroughOnlyRule.self,
NoGroupingExtensionRule.self,
NoMagicNumbersRule.self,
NoSpaceInMethodCallRule.self,
NotificationCenterDetachmentRule.self,
NumberSeparatorRule.self,
@ -121,12 +141,16 @@ public let masterRuleList = RuleList(rules: [
OverriddenSuperCallRule.self,
OverrideInExtensionRule.self,
PatternMatchingKeywordsRule.self,
PhohibitedNaNComparisonRule.self,
PeriodSpacingRule.self,
PreferNimbleRule.self,
PreferSelfInStaticReferencesRule.self,
PreferSelfTypeOverTypeOfSelfRule.self,
PreferZeroOverExplicitInitRule.self,
PrefixedTopLevelConstantRule.self,
PrivateActionRule.self,
PrivateOutletRule.self,
PrivateOverFilePrivateRule.self,
PrivateSubjectRule.self,
PrivateUnitTestRule.self,
ProhibitedInterfaceBuilderRule.self,
ProhibitedSuperRule.self,
@ -141,6 +165,7 @@ public let masterRuleList = RuleList(rules: [
RedundantNilCoalescingRule.self,
RedundantObjcAttributeRule.self,
RedundantOptionalInitializationRule.self,
RedundantSelfInClosureRule.self,
RedundantSetAccessControlRule.self,
RedundantStringEnumValueRule.self,
RedundantTypeAnnotationRule.self,
@ -149,18 +174,23 @@ public let masterRuleList = RuleList(rules: [
RequiredEnumCaseRule.self,
ReturnArrowWhitespaceRule.self,
ReturnValueFromVoidFunctionRule.self,
SelfBindingRule.self,
SelfInPropertyInitializationRule.self,
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,
TestCaseAccessibilityRule.self,
TodoRule.self,
ToggleBoolRule.self,
TrailingClosureRule.self,
@ -168,11 +198,13 @@ public let masterRuleList = RuleList(rules: [
TrailingNewlineRule.self,
TrailingSemicolonRule.self,
TrailingWhitespaceRule.self,
TuplePatternRule.self,
TypeBodyLengthRule.self,
TypeContentsOrderRule.self,
TypeNameRule.self,
TypesafeArrayInitRule.self,
UnavailableConditionRule.self,
UnavailableFunctionRule.self,
UnhandledThrowingTaskRule.self,
UnneededBreakInSwitchRule.self,
UnneededParenthesesInClosureArgumentRule.self,
UnownedVariableCaptureRule.self,
@ -198,4 +230,4 @@ public let masterRuleList = RuleList(rules: [
XCTFailMessageRule.self,
XCTSpecificMatcherRule.self,
YodaConditionRule.self
])
]

View File

@ -0,0 +1,29 @@
import Foundation
/// Represents unused or missing import statements.
enum ImportUsage {
/// The import is unused. Range is for the entire import statement.
case unused(module: String, range: NSRange)
/// The file is missing an explicit import of the `module`.
case missing(module: String)
/// The range where the violation for this import usage should be reported.
var violationRange: NSRange? {
switch self {
case .unused(_, let range):
return range
case .missing:
return nil
}
}
/// The reason why this import usage is a violation.
var violationReason: String? {
switch self {
case .unused:
return nil
case .missing(let module):
return "Missing import for referenced module '\(module)'"
}
}
}

View File

@ -0,0 +1,60 @@
import SwiftSyntax
struct AnonymousArgumentInMultilineClosureRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "anonymous_argument_in_multiline_closure",
name: "Anonymous Argument in Multiline Closure",
description: "Use named arguments in multiline closures",
kind: .idiomatic,
nonTriggeringExamples: [
Example("closure { $0 }"),
Example("closure { print($0) }"),
Example("""
closure { arg in
print(arg)
}
"""),
Example("""
closure { arg in
nestedClosure { $0 + arg }
}
""")
],
triggeringExamples: [
Example("""
closure {
print($0)
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(locationConverter: file.locationConverter)
}
}
private extension AnonymousArgumentInMultilineClosureRule {
final class Visitor: ViolationsSyntaxVisitor {
private let locationConverter: SourceLocationConverter
init(locationConverter: SourceLocationConverter) {
self.locationConverter = locationConverter
super.init(viewMode: .sourceAccurate)
}
override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind {
let startLocation = locationConverter.location(for: node.leftBrace.positionAfterSkippingLeadingTrivia)
let endLocation = locationConverter.location(for: node.rightBrace.endPositionBeforeTrailingTrivia)
return startLocation.line == endLocation.line ? .skipChildren : .visitChildren
}
override func visitPost(_ node: IdentifierExprSyntax) {
if case .dollarIdentifier = node.identifier.tokenKind {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
}

View File

@ -0,0 +1,62 @@
import SwiftSyntax
struct BlockBasedKVORule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "block_based_kvo",
name: "Block Based KVO",
description: "Prefer the new block based KVO API with keypaths when using Swift 3.2 or later",
kind: .idiomatic,
nonTriggeringExamples: [
Example(#"""
let observer = foo.observe(\.value, options: [.new]) { (foo, change) in
print(change.newValue)
}
"""#)
],
triggeringExamples: [
Example("""
class Foo: NSObject {
override func observeValue(forKeyPath keyPath: String?, of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {}
}
"""),
Example("""
class Foo: NSObject {
override func observeValue(forKeyPath keyPath: String?, of object: Any?,
change: Dictionary<NSKeyValueChangeKey, Any>?,
context: UnsafeMutableRawPointer?) {}
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension BlockBasedKVORule {
private final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionDeclSyntax) {
guard node.modifiers.containsOverride,
case let parameterList = node.signature.input.parameterList,
parameterList.count == 4,
node.identifier.text == "observeValue",
parameterList.map(\.firstName.text) == ["forKeyPath", "of", "change", "context"]
else {
return
}
let types = parameterList
.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 {
violations.append(node.funcKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
}

View File

@ -0,0 +1,232 @@
import SwiftSyntax
struct ConvenienceTypeRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "convenience_type",
name: "Convenience Type",
description: "Types used for hosting only static members should be implemented as a caseless enum " +
"to avoid instantiation",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
enum Math { // enum
public static let pi = 3.14
}
"""),
Example("""
// class with inheritance
class MathViewController: UIViewController {
public static let pi = 3.14
}
"""),
Example("""
@objc class Math: NSObject { // class visible to Obj-C
public static let pi = 3.14
}
"""),
Example("""
struct Math { // type with non-static declarations
public static let pi = 3.14
public let randomNumber = 2
}
"""),
Example("class DummyClass {}"),
Example("""
class Foo: NSObject { // class with Obj-C class property
class @objc let foo = 1
}
"""),
Example("""
class Foo: NSObject { // class with Obj-C static property
static @objc let foo = 1
}
"""),
Example("""
class Foo { // @objc class func can't exist on an enum
@objc class func foo() {}
}
"""),
Example("""
class Foo { // @objc static func can't exist on an enum
@objc static func foo() {}
}
"""),
Example("""
@objcMembers class Foo { // @objc static func can't exist on an enum
static func foo() {}
}
"""),
Example("""
final class Foo { // final class, but @objc class func can't exist on an enum
@objc class func foo() {}
}
"""),
Example("""
final class Foo { // final class, but @objc static func can't exist on an enum
@objc static func foo() {}
}
"""),
Example("""
@globalActor actor MyActor {
static let shared = MyActor()
}
""")
],
triggeringExamples: [
Example("""
struct Math {
public static let pi = 3.14
}
"""),
Example("""
struct Math {
public static let pi = 3.14
@available(*, unavailable) init() {}
}
"""),
Example("""
final class Foo { // final class can't be inherited
class let foo = 1
}
"""),
// Intentional false positives. Non-final classes could be
// subclassed, but we figure it is probably rare enough that it is
// more important to catch these cases, and manually disable the
// rule if needed.
Example("""
class Foo {
class let foo = 1
}
"""),
Example("""
class Foo {
final class let foo = 1
}
"""),
Example("""
class SomeClass {
static func foo() {}
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ConvenienceTypeRule {
final class Visitor: ViolationsSyntaxVisitor {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: StructDeclSyntax) {
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.memberBlock
) {
violations.append(node.classKeyword.positionAfterSkippingLeadingTrivia)
}
}
private func hasViolation(inheritance: TypeInheritanceClauseSyntax?,
attributes: AttributeListSyntax?,
members: MemberDeclBlockSyntax) -> Bool {
guard inheritance.isNilOrEmpty,
!attributes.containsObjcMembers,
!attributes.containsObjc,
!members.members.isEmpty else {
return false
}
return ConvenienceTypeCheckVisitor(viewMode: .sourceAccurate)
.walk(tree: members, handler: \.canBeConvenienceType)
}
}
}
private class ConvenienceTypeCheckVisitor: ViolationsSyntaxVisitor {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { .all }
private(set) var canBeConvenienceType = true
override func visitPost(_ node: VariableDeclSyntax) {
if node.isInstanceVariable {
canBeConvenienceType = false
} else if node.attributes.containsObjc {
canBeConvenienceType = false
}
}
override func visitPost(_ node: FunctionDeclSyntax) {
if node.modifiers.containsStaticOrClass {
if node.attributes.containsObjc {
canBeConvenienceType = false
}
} else {
canBeConvenienceType = false
}
}
override func visitPost(_ node: InitializerDeclSyntax) {
if !node.attributes.hasUnavailableAttribute {
canBeConvenienceType = false
}
}
override func visitPost(_ node: SubscriptDeclSyntax) {
if !node.modifiers.containsStaticOrClass {
canBeConvenienceType = false
}
}
}
private extension TypeInheritanceClauseSyntax? {
var isNilOrEmpty: Bool {
self?.inheritedTypeCollection.isEmpty ?? true
}
}
private extension AttributeListSyntax? {
var containsObjcMembers: Bool {
contains(attributeNamed: "objcMembers")
}
var containsObjc: Bool {
contains(attributeNamed: "objc")
}
}
private extension AttributeListSyntax? {
var hasUnavailableAttribute: Bool {
guard let attrs = self else {
return false
}
return attrs.contains { elem in
guard let attr = elem.as(AttributeSyntax.self),
let arguments = attr.argument?.as(AvailabilitySpecListSyntax.self) else {
return false
}
return attr.attributeNameText == "available" && arguments.contains { arg in
arg.entry.as(TokenSyntax.self)?.tokenKind.isUnavailableKeyword == true
}
}
}
}

View File

@ -0,0 +1,45 @@
import SwiftSyntax
struct DiscouragedAssertRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "discouraged_assert",
name: "Discouraged Assert",
description: "Prefer `assertionFailure()` and/or `preconditionFailure()` over `assert(false)`",
kind: .idiomatic,
nonTriggeringExamples: [
Example(#"assert(true)"#),
Example(#"assert(true, "foobar")"#),
Example(#"assert(true, "foobar", file: "toto", line: 42)"#),
Example(#"assert(false || true)"#),
Example(#"XCTAssert(false)"#)
],
triggeringExamples: [
Example(#"↓assert(false)"#),
Example(#"↓assert(false, "foobar")"#),
Example(#"↓assert(false, "foobar", file: "toto", line: 42)"#),
Example(#"↓assert( false , "foobar")"#)
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension DiscouragedAssertRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.text == "assert",
let firstArg = node.argumentList.first,
firstArg.label == nil,
let boolExpr = firstArg.expression.as(BooleanLiteralExprSyntax.self),
boolExpr.booleanLiteral.tokenKind == .keyword(.false) else {
return
}
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,237 @@
import SwiftSyntax
struct DiscouragedNoneNameRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "discouraged_none_name",
name: "Discouraged None Name",
description: "Enum cases and static members named `none` are discouraged as they can conflict with " +
"`Optional<T>.none`.",
kind: .idiomatic,
nonTriggeringExamples: [
// Should not trigger unless exactly matches "none"
Example("""
enum MyEnum {
case nOne
}
"""),
Example("""
enum MyEnum {
case _none
}
"""),
Example("""
enum MyEnum {
case none_
}
"""),
Example("""
enum MyEnum {
case none(Any)
}
"""),
Example("""
enum MyEnum {
case nonenone
}
"""),
Example("""
class MyClass {
class var nonenone: MyClass { MyClass() }
}
"""),
Example("""
class MyClass {
static var nonenone = MyClass()
}
"""),
Example("""
class MyClass {
static let nonenone = MyClass()
}
"""),
Example("""
struct MyStruct {
static var nonenone = MyStruct()
}
"""),
Example("""
struct MyStruct {
static let nonenone = MyStruct()
}
"""),
// Should not trigger if not an enum case or static/class member
Example("""
struct MyStruct {
let none = MyStruct()
}
"""),
Example("""
struct MyStruct {
var none = MyStruct()
}
"""),
Example("""
class MyClass {
let none = MyClass()
}
"""),
Example("""
class MyClass {
var none = MyClass()
}
""")
],
triggeringExamples: [
Example("""
enum MyEnum {
case none
}
"""),
Example("""
enum MyEnum {
case a, none
}
"""),
Example("""
enum MyEnum {
case none, b
}
"""),
Example("""
enum MyEnum {
case a, none, b
}
"""),
Example("""
enum MyEnum {
case a
case none
}
"""),
Example("""
enum MyEnum {
case none
case b
}
"""),
Example("""
enum MyEnum {
case a
case none
case b
}
"""),
Example("""
class MyClass {
static let none = MyClass()
}
"""),
Example("""
class MyClass {
static let none: MyClass = MyClass()
}
"""),
Example("""
class MyClass {
static var none: MyClass = MyClass()
}
"""),
Example("""
class MyClass {
class var none: MyClass { MyClass() }
}
"""),
Example("""
struct MyStruct {
static var none = MyStruct()
}
"""),
Example("""
struct MyStruct {
static var none: MyStruct = MyStruct()
}
"""),
Example("""
struct MyStruct {
static var none = MyStruct()
}
"""),
Example("""
struct MyStruct {
static var none: MyStruct = MyStruct()
}
"""),
Example("""
struct MyStruct {
static var a = MyStruct(), none = MyStruct()
}
"""),
Example("""
struct MyStruct {
static var none = MyStruct(), a = MyStruct()
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension DiscouragedNoneNameRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: EnumCaseElementSyntax) {
let emptyParams = node.associatedValue?.parameterList.isEmpty ?? true
if emptyParams, node.identifier.isNone {
violations.append(ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,
reason: reason(type: "`case`")
))
}
}
override func visitPost(_ node: VariableDeclSyntax) {
let type: String? = {
if node.modifiers.isClass {
return "`class` member"
} else if node.modifiers.isStatic {
return "`static` member"
} else {
return nil
}
}()
guard let type else {
return
}
for binding in node.bindings {
guard let pattern = binding.pattern.as(IdentifierPatternSyntax.self), pattern.identifier.isNone else {
continue
}
violations.append(ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,
reason: reason(type: type)
))
return
}
}
private func reason(type: String) -> String {
let reason = "Avoid naming \(type) `none` as the compiler can think you mean `Optional<T>.none`"
let recommendation = "consider using an Optional value instead"
return "\(reason); \(recommendation)"
}
}
}
private extension TokenSyntax {
var isNone: Bool {
tokenKind == .identifier("none") || tokenKind == .identifier("`none`")
}
}

View File

@ -0,0 +1,58 @@
import SwiftSyntax
struct DiscouragedObjectLiteralRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = DiscouragedObjectLiteralConfiguration()
static let description = RuleDescription(
identifier: "discouraged_object_literal",
name: "Discouraged Object Literal",
description: "Prefer initializers over object literals",
kind: .idiomatic,
nonTriggeringExamples: [
Example("let image = UIImage(named: aVariable)"),
Example("let image = UIImage(named: \"interpolated \\(variable)\")"),
Example("let color = UIColor(red: value, green: value, blue: value, alpha: 1)"),
Example("let image = NSImage(named: aVariable)"),
Example("let image = NSImage(named: \"interpolated \\(variable)\")"),
Example("let color = NSColor(red: value, green: value, blue: value, alpha: 1)")
],
triggeringExamples: [
Example("let image = ↓#imageLiteral(resourceName: \"image.jpg\")"),
Example("let color = ↓#colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension DiscouragedObjectLiteralRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: ConfigurationType
init(configuration: ConfigurationType) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: MacroExpansionExprSyntax) {
guard
case let .identifier(identifierText) = node.macro.tokenKind,
["colorLiteral", "imageLiteral"].contains(identifierText)
else {
return
}
if !configuration.imageLiteral && identifierText == "imageLiteral" {
return
}
if !configuration.colorLiteral && identifierText == "colorLiteral" {
return
}
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,49 @@
import SwiftSyntax
struct DiscouragedOptionalBooleanRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "discouraged_optional_boolean",
name: "Discouraged Optional Boolean",
description: "Prefer non-optional booleans over optional booleans",
kind: .idiomatic,
nonTriggeringExamples: DiscouragedOptionalBooleanRuleExamples.nonTriggeringExamples,
triggeringExamples: DiscouragedOptionalBooleanRuleExamples.triggeringExamples
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension DiscouragedOptionalBooleanRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: OptionalTypeSyntax) {
if node.wrappedType.as(SimpleTypeIdentifierSyntax.self)?.typeName == "Bool" {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: OptionalChainingExprSyntax) {
if node.expression.as(IdentifierExprSyntax.self)?.identifier.text == "Bool" {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: FunctionCallExprSyntax) {
guard
let calledExpression = node.calledExpression.as(MemberAccessExprSyntax.self),
let singleArgument = node.argumentList.onlyElement,
singleArgument.expression.is(BooleanLiteralExprSyntax.self),
let base = calledExpression.base?.as(IdentifierExprSyntax.self),
base.identifier.text == "Optional",
calledExpression.name.text == "some"
else {
return
}
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -154,7 +154,10 @@ internal struct DiscouragedOptionalBooleanRuleExamples {
wrapExample("enum", "func foo(input: [↓Bool?]) {}"),
wrapExample("enum", "static func foo(input: ↓Bool?) {}"),
wrapExample("enum", "static func foo(input: [String: ↓Bool?]) {}"),
wrapExample("enum", "static func foo(input: [↓Bool?]) {}")
wrapExample("enum", "static func foo(input: [↓Bool?]) {}"),
// Optional chaining
Example("_ = ↓Bool?.values()")
]
}

View File

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

View File

@ -0,0 +1,212 @@
import Foundation
import SourceKittenFramework
struct DuplicateImportsRule: ConfigurationProviderRule, CorrectableRule {
var configuration = SeverityConfiguration<Self>(.warning)
// List of all possible import kinds
static let importKinds = [
"typealias", "struct", "class",
"enum", "protocol", "let",
"var", "func"
]
static let description = RuleDescription(
identifier: "duplicate_imports",
name: "Duplicate Imports",
description: "Imports should be unique",
kind: .idiomatic,
nonTriggeringExamples: DuplicateImportsRuleExamples.nonTriggeringExamples,
triggeringExamples: DuplicateImportsRuleExamples.triggeringExamples,
corrections: DuplicateImportsRuleExamples.corrections
)
private func rangesInConditionalCompilation(file: SwiftLintFile) -> [ByteRange] {
let contents = file.stringView
let ranges = file.syntaxMap.tokens
.filter { $0.kind == .buildconfigKeyword }
.map { $0.range }
.filter { range in
return ["#if", "#endif"].contains(contents.substringWithByteRange(range))
}
// Make sure that each #if has corresponding #endif
guard ranges.count.isMultiple(of: 2) else { return [] }
return stride(from: 0, to: ranges.count, by: 2).reduce(into: []) { result, rangeIndex in
result.append(ranges[rangeIndex].union(with: ranges[rangeIndex + 1]))
}
}
private func buildImportLineSlicesByImportSubpath(
importLines: [Line]
) -> [ImportSubpath: [ImportLineSlice]] {
var importLineSlices = [ImportSubpath: [ImportLineSlice]]()
importLines.forEach { importLine in
importLine.importSlices.forEach { slice in
importLineSlices[slice.subpath, default: []].append(
ImportLineSlice(
slice: slice,
line: importLine
)
)
}
}
return importLineSlices
}
private func findDuplicateImports(
file: SwiftLintFile,
importLineSlicesGroupedBySubpath: [[ImportLineSlice]]
) -> [DuplicateImport] {
typealias ImportLocation = Int
var duplicateImportsByLocation = [ImportLocation: DuplicateImport]()
importLineSlicesGroupedBySubpath.forEach { linesImportingSubpath in
guard linesImportingSubpath.count > 1 else { return }
guard let primaryImportIndex = linesImportingSubpath.firstIndex(where: {
$0.slice.type == .complete
}) else { return }
linesImportingSubpath.enumerated().forEach { index, importedLine in
guard index != primaryImportIndex else { return }
let location = Location(
file: file,
characterOffset: importedLine.line.range.location
)
duplicateImportsByLocation[importedLine.line.range.location] = DuplicateImport(
location: location,
range: importedLine.line.range
)
}
}
return Array(duplicateImportsByLocation.values)
}
private struct DuplicateImport {
let location: Location
var range: NSRange
}
private func duplicateImports(file: SwiftLintFile) -> [DuplicateImport] {
let contents = file.stringView
let ignoredRanges = self.rangesInConditionalCompilation(file: file)
let importKinds = Self.importKinds.joined(separator: "|")
// Grammar of import declaration
// attributes(optional) import import-kind(optional) import-path
let regex = "^([a-zA-Z@_]+\\s)?import(\\s(\(importKinds)))?\\s+[a-zA-Z0-9._]+$"
let importRanges = file.match(pattern: regex)
.filter { $0.1.allSatisfy { [.keyword, .identifier, .attributeBuiltin].contains($0) } }
.compactMap { contents.NSRangeToByteRange(start: $0.0.location, length: $0.0.length) }
.filter { importRange -> Bool in
return !importRange.intersects(ignoredRanges)
}
let lines = file.lines
let importLines: [Line] = importRanges.compactMap { range in
guard let line = contents.lineAndCharacter(forByteOffset: range.location)?.line
else { return nil }
return lines[line - 1]
}
let importLineSlices = buildImportLineSlicesByImportSubpath(importLines: importLines)
let duplicateImports = findDuplicateImports(
file: file,
importLineSlicesGroupedBySubpath: Array(importLineSlices.values)
)
return duplicateImports.sorted(by: {
$0.range.lowerBound < $1.range.lowerBound
})
}
func validate(file: SwiftLintFile) -> [StyleViolation] {
return duplicateImports(file: file).map { duplicateImport in
StyleViolation(
ruleDescription: Self.description,
severity: configuration.severity,
location: duplicateImport.location
)
}
}
func correct(file: SwiftLintFile) -> [Correction] {
let duplicateImports = duplicateImports(file: file).reversed().filter {
file.ruleEnabled(violatingRange: $0.range, for: self) != nil
}
let violatingRanges = duplicateImports.map(\.range)
let correctedFileContents = violatingRanges.reduce(file.stringView.nsString) { contents, range in
contents.replacingCharacters(
in: range,
with: ""
).bridge()
}
file.write(correctedFileContents.bridge())
return duplicateImports.map { duplicateImport in
Correction(
ruleDescription: Self.description,
location: duplicateImport.location
)
}
}
}
private typealias ImportSubpath = ArraySlice<String>
private struct ImportSlice {
enum ImportSliceType {
/// For "import A.B.C" parent subpaths are ["A", "B"] and ["A"]
case parent
/// For "import A.B.C" complete subpath is ["A", "B", "C"]
case complete
}
let subpath: ImportSubpath
let type: ImportSliceType
}
private struct ImportLineSlice {
let slice: ImportSlice
let line: Line
}
private extension Line {
/// Returns name of the module being imported.
var importIdentifier: Substring? {
return self.content.split(separator: " ").last
}
/// For "import A.B.C" returns slices [["A", "B", "C"], ["A", "B"], ["A"]]
var importSlices: [ImportSlice] {
guard let importIdentifier else { return [] }
let importedSubpathParts = importIdentifier.split(separator: ".").map { String($0) }
guard !importedSubpathParts.isEmpty else { return [] }
return [
ImportSlice(
subpath: importedSubpathParts[0..<importedSubpathParts.count],
type: .complete
)
] + (1..<importedSubpathParts.count).map {
ImportSlice(
subpath: importedSubpathParts[0..<importedSubpathParts.count - $0],
type: .parent
)
}
}
}

View File

@ -0,0 +1,219 @@
internal struct DuplicateImportsRuleExamples {
static let nonTriggeringExamples = [
Example("""
import A
import B
import C
"""),
Example("""
import A.B
import A.C
"""),
Example("""
@_implementationOnly import A
@_implementationOnly import B
"""),
Example("""
@testable import A
@testable import B
"""),
Example("""
#if DEBUG
@testable import KsApi
#else
import KsApi
#endif
"""),
Example("""
import A // module
import B // module
"""),
Example("""
#if TEST
func test() {
}
""")
]
static let triggeringExamples = Array(corrections.keys.sorted())
static let corrections: [Example: Example] = {
var corrections = [
Example("""
import Foundation
import Dispatch
import Foundation
"""): Example(
"""
import Foundation
import Dispatch
"""),
Example("""
import Foundation
import Foundation.NSString
"""): Example("""
import Foundation
"""),
Example("""
import Foundation.NSString
import Foundation
"""): Example("""
import Foundation
"""),
Example("""
@_implementationOnly import A
@_implementationOnly import A
"""): Example("""
@_implementationOnly import A
"""),
Example("""
@testable import A
@testable import A
"""): Example("""
@testable import A
"""),
Example("""
import A.B.C
import A.B
"""): Example("""
import A.B
"""),
Example("""
import A.B
import A.B.C
"""): Example("""
import A.B
"""),
Example("""
import A
#if DEBUG
@testable import KsApi
#else
import KsApi
#endif
import A
"""): Example("""
import A
#if DEBUG
@testable import KsApi
#else
import KsApi
#endif
"""),
Example("""
import Foundation
import Foundation
import Foundation
"""): Example("""
import Foundation
"""),
Example("""
import A.B.C
import A.B
import A
""", excludeFromDocumentation: true): Example("""
import A
"""),
Example("""
import A.B.C
import A.B.C.D
import A.B.C.E
""", excludeFromDocumentation: true): Example("""
import A.B.C
"""),
Example("""
import A.B.C
import A
import A.B
""", excludeFromDocumentation: true): Example("""
import A
"""),
Example("""
import A.B
import A
import A.B.C
""", excludeFromDocumentation: true): Example("""
import A
"""),
Example("""
import A
import A.B.C
import A.B
""", excludeFromDocumentation: true): Example("""
import A
""")
]
DuplicateImportsRule.importKinds.map { importKind in
Example("""
import A
import \(importKind) A.Foo
""")
}.forEach {
corrections[$0] = Example(
"""
import A
""")
}
DuplicateImportsRule.importKinds.map { importKind in
Example("""
import A
import \(importKind) A.B.Foo
""", excludeFromDocumentation: true)
}.forEach {
corrections[$0] = Example(
"""
import A
""")
}
DuplicateImportsRule.importKinds.map { importKind in
Example("""
import A.B
import \(importKind) A.B.Foo
""", excludeFromDocumentation: true)
}.forEach {
corrections[$0] = Example(
"""
import A.B
""")
}
return corrections
}()
}

View File

@ -3,15 +3,13 @@ import SourceKittenFramework
private typealias SourceKittenElement = SourceKittenDictionary
public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
struct ExplicitACLRule: OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "explicit_acl",
name: "Explicit ACL",
description: "All declarations should specify Access Control Level keywords explicitly.",
description: "All declarations should specify Access Control Level keywords explicitly",
kind: .idiomatic,
nonTriggeringExamples: [
Example("internal enum A {}\n"),
@ -41,15 +39,50 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
"""),
Example("internal class A { deinit {} }"),
Example("extension A: Equatable {}"),
Example("extension A {}")
Example("extension A {}"),
Example("""
extension Foo {
internal func bar() {}
}
"""),
Example("""
internal enum Foo {
case bar
}
"""),
Example("""
extension Foo {
public var isValid: Bool {
let result = true
return result
}
}
"""),
Example("""
extension Foo {
private var isValid: Bool {
get {
return true
}
set(newValue) {
print(newValue)
}
}
}
""")
],
triggeringExamples: [
Example("enum A {}\n"),
Example("final class B {}\n"),
Example("internal struct C { let d = 5 }\n"),
Example("public struct C { let d = 5 }\n"),
Example("enum A {}\n"),
Example("final class B {}\n"),
Example("internal struct C { let d = 5 }\n"),
Example("public struct C { let d = 5 }\n"),
Example("func a() {}\n"),
Example("internal let a = 0\nfunc b() {}\n")
Example("internal let a = 0\n↓func b() {}\n"),
Example("""
extension Foo {
func bar() {}
}
""")
]
)
@ -62,16 +95,13 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
private func offsetOfElements(from elements: [SourceKittenElement], in file: SwiftLintFile,
thatAreNotInRanges ranges: [ByteRange]) -> [ByteCount] {
let extensionKinds: Set<SwiftDeclarationKind> = [.extension, .extensionClass, .extensionEnum,
.extensionProtocol, .extensionStruct]
return elements.compactMap { element in
guard let typeOffset = element.offset else {
return nil
}
guard let kind = element.declarationKind,
!extensionKinds.contains(kind) else {
!SwiftDeclarationKind.extensionKinds.contains(kind) else {
return nil
}
@ -90,10 +120,10 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
}
}
public func validate(file: SwiftLintFile) -> [StyleViolation] {
let implicitAndExplicitInternalElements = internalTypeElements(in: file.structureDictionary )
func validate(file: SwiftLintFile) -> [StyleViolation] {
let implicitAndExplicitInternalElements = internalTypeElements(in: file.structureDictionary)
guard !implicitAndExplicitInternalElements.isEmpty else {
guard implicitAndExplicitInternalElements.isNotEmpty else {
return []
}
@ -103,7 +133,7 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
thatAreNotInRanges: explicitInternalRanges)
return violations.map {
StyleViolation(ruleDescription: type(of: self).description,
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: $0))
}
@ -114,9 +144,10 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
return firstPartition.last
}
private func internalTypeElements(in element: SourceKittenElement) -> [SourceKittenElement] {
return element.substructure.flatMap { element -> [SourceKittenElement] in
guard let elementKind = element.declarationKind else {
private func internalTypeElements(in parent: SourceKittenElement) -> [SourceKittenElement] {
return parent.substructure.flatMap { element -> [SourceKittenElement] in
guard let elementKind = element.declarationKind,
elementKind != .varLocal, elementKind != .varParameter else {
return []
}
@ -129,7 +160,12 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
let internalTypeElementsInSubstructure = elementKind.childsAreExemptFromACL || isPrivate ? [] :
internalTypeElements(in: element)
if element.accessibility == .internal {
var isInExtension = false
if let kind = parent.declarationKind {
isInExtension = SwiftDeclarationKind.extensionKinds.contains(kind)
}
if element.accessibility == .internal || (element.accessibility == nil && isInExtension) {
return internalTypeElementsInSubstructure + [element]
}
@ -150,7 +186,7 @@ private extension SwiftDeclarationKind {
.functionMethodInstance, .functionMethodStatic, .functionOperator, .functionOperatorInfix,
.functionOperatorPostfix, .functionOperatorPrefix, .functionSubscript, .protocol, .opaqueType:
return true
case .class, .enum, .extension, .extensionClass, .extensionEnum,
case .actor, .class, .enum, .extension, .extensionClass, .extensionEnum,
.extensionProtocol, .extensionStruct, .struct:
return false
}

View File

@ -0,0 +1,105 @@
import SwiftSyntax
struct ExplicitEnumRawValueRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_enum_raw_value",
name: "Explicit Enum Raw Value",
description: "Enums should be explicitly assigned their raw values",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
enum Numbers {
case int(Int)
case short(Int16)
}
"""),
Example("""
enum Numbers: Int {
case one = 1
case two = 2
}
"""),
Example("""
enum Numbers: Double {
case one = 1.1
case two = 2.2
}
"""),
Example("""
enum Numbers: String {
case one = "one"
case two = "two"
}
"""),
Example("""
protocol Algebra {}
enum Numbers: Algebra {
case one
}
""")
],
triggeringExamples: [
Example("""
enum Numbers: Int {
case one = 10, two, three = 30
}
"""),
Example("""
enum Numbers: NSInteger {
case one
}
"""),
Example("""
enum Numbers: String {
case one
case two
}
"""),
Example("""
enum Numbers: String {
case one, two = "two"
}
"""),
Example("""
enum Numbers: Decimal {
case one, two
}
"""),
Example("""
enum Outer {
enum Numbers: Decimal {
case one, two
}
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ExplicitEnumRawValueRule {
final class Visitor: ViolationsSyntaxVisitor {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { [ProtocolDeclSyntax.self] }
override func visitPost(_ node: EnumCaseElementSyntax) {
if node.rawValue == nil, node.enclosingEnum()?.supportsRawValues == true {
violations.append(node.identifier.positionAfterSkippingLeadingTrivia)
}
}
}
}
private extension SyntaxProtocol {
func enclosingEnum() -> EnumDeclSyntax? {
if let node = self.as(EnumDeclSyntax.self) {
return node
}
return parent?.enclosingEnum()
}
}

View File

@ -0,0 +1,254 @@
import SwiftSyntax
import SwiftSyntaxBuilder
struct ExplicitInitRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_init",
name: "Explicit Init",
description: "Explicitly calling .init() should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
import Foundation
class C: NSObject {
override init() {
super.init()
}
}
"""), // super
Example("""
struct S {
let n: Int
}
extension S {
init() {
self.init(n: 1)
}
}
"""), // self
Example("""
[1].flatMap(String.init)
"""), // pass init as closure
Example("""
[String.self].map { $0.init(1) }
"""), // initialize from a metatype value
Example("""
[String.self].map { type in type.init(1) }
"""), // initialize from a metatype value
Example("""
Observable.zip(obs1, obs2, resultSelector: MyType.init).asMaybe()
"""),
Example("_ = GleanMetrics.Tabs.someType.init()"),
Example("""
Observable.zip(
obs1,
obs2,
resultSelector: MyType.init
).asMaybe()
""")
],
triggeringExamples: [
Example("""
[1].flatMap{String.init($0)}
"""),
Example("""
[String.self].map { Type in Type.init(1) }
"""), // Starting with capital letter assumes a type
Example("""
func foo() -> [String] {
return [1].flatMap { String.init($0) }
}
"""),
Example("_ = GleanMetrics.Tabs.GroupedTabExtra↓.init()"),
Example("_ = Set<KsApi.Category>↓.init()"),
Example("""
Observable.zip(
obs1,
obs2,
resultSelector: { MyType.init($0, $1) }
).asMaybe()
"""),
Example("""
let int = In🤓t
.init(1.0)
""", excludeFromDocumentation: true),
Example("""
let int = Int
.init(1.0)
""", excludeFromDocumentation: true),
Example("""
let int = Int
.init(1.0)
""", excludeFromDocumentation: true)
],
corrections: [
Example("""
[1].flatMap{String.init($0)}
"""):
Example("""
[1].flatMap{String($0)}
"""),
Example("""
func foo() -> [String] {
return [1].flatMap { String.init($0) }
}
"""):
Example("""
func foo() -> [String] {
return [1].flatMap { String($0) }
}
"""),
Example("""
class C {
#if true
func f() {
[1].flatMap{String.init($0)}
}
#endif
}
"""):
Example("""
class C {
#if true
func f() {
[1].flatMap{String($0)}
}
#endif
}
"""),
Example("""
let int = Int
.init(1.0)
"""):
Example("""
let int = Int(1.0)
"""),
Example("""
let int = Int
.init(1.0)
"""):
Example("""
let int = Int(1.0)
"""),
Example("""
let int = Int
.init(1.0)
"""):
Example("""
let int = Int(1.0)
"""),
Example("""
let int = Int
.init(1.0)
"""):
Example("""
let int = Int(1.0)
"""),
Example("_ = GleanMetrics.Tabs.GroupedTabExtra↓.init()"):
Example("_ = GleanMetrics.Tabs.GroupedTabExtra()"),
Example("_ = Set<KsApi.Category>↓.init()"):
Example("_ = Set<KsApi.Category>()")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
Rewriter(
locationConverter: file.locationConverter,
disabledRegions: disabledRegions(file: file)
)
}
}
private extension ExplicitInitRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard
let calledExpression = node.calledExpression.as(MemberAccessExprSyntax.self),
let violationPosition = calledExpression.explicitInitPosition
else {
return
}
violations.append(violationPosition)
}
}
final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
private(set) var correctionPositions: [AbsolutePosition] = []
let locationConverter: SourceLocationConverter
let disabledRegions: [SourceRange]
init(locationConverter: SourceLocationConverter, disabledRegions: [SourceRange]) {
self.locationConverter = locationConverter
self.disabledRegions = disabledRegions
}
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
guard
let calledExpression = node.calledExpression.as(MemberAccessExprSyntax.self),
let violationPosition = calledExpression.explicitInitPosition,
let calledBase = calledExpression.base,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter)
else {
return super.visit(node)
}
correctionPositions.append(violationPosition)
let newNode = node.with(\.calledExpression, calledBase.trimmed)
return super.visit(newNode)
}
}
}
private extension MemberAccessExprSyntax {
var explicitInitPosition: AbsolutePosition? {
if let base, base.isTypeReferenceLike, name.text == "init" {
return base.endPositionBeforeTrailingTrivia
} else {
return nil
}
}
}
private extension ExprSyntax {
/// `String` or `Nested.Type`.
var isTypeReferenceLike: Bool {
if let expr = self.as(IdentifierExprSyntax.self), expr.identifier.text.startsWithUppercase {
return true
} else if let expr = self.as(MemberAccessExprSyntax.self),
expr.description.split(separator: ".").allSatisfy(\.startsWithUppercase) {
return true
} else if let expr = self.as(SpecializeExprSyntax.self)?.expression.as(IdentifierExprSyntax.self),
expr.identifier.text.startsWithUppercase {
return true
} else {
return false
}
}
}
private extension StringProtocol {
var startsWithUppercase: Bool { first?.isUppercase == true }
}

View File

@ -0,0 +1,118 @@
import SwiftSyntax
struct ExplicitTopLevelACLRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "explicit_top_level_acl",
name: "Explicit Top Level ACL",
description: "Top-level declarations should specify Access Control Level keywords explicitly",
kind: .idiomatic,
nonTriggeringExamples: [
Example("internal enum A {}\n"),
Example("public final class B {}\n"),
Example("private struct C {}\n"),
Example("internal enum A {\n enum B {}\n}"),
Example("internal final class Foo {}"),
Example("internal\nclass Foo {}"),
Example("internal func a() {}\n"),
Example("extension A: Equatable {}"),
Example("extension A {}")
],
triggeringExamples: [
Example("↓enum A {}\n"),
Example("final ↓class B {}\n"),
Example("↓struct C {}\n"),
Example("↓func a() {}\n"),
Example("internal let a = 0\n↓func b() {}\n")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ExplicitTopLevelACLRule {
final class Visitor: ViolationsSyntaxVisitor {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: ClassDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.classKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: StructDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.structKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: EnumDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.enumKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: ProtocolDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.protocolKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: ActorDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.actorKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: TypealiasDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.typealiasKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: FunctionDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.funcKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: VariableDeclSyntax) {
if hasViolation(modifiers: node.modifiers) {
violations.append(node.bindingKeyword.positionAfterSkippingLeadingTrivia)
}
}
override func visit(_ node: CodeBlockSyntax) -> SyntaxVisitorContinueKind {
.skipChildren
}
override func visit(_ node: ClosureExprSyntax) -> SyntaxVisitorContinueKind {
.skipChildren
}
private func hasViolation(modifiers: ModifierListSyntax?) -> Bool {
guard let modifiers else {
return true
}
return !modifiers.contains(where: \.isACLModifier)
}
}
}
private extension DeclModifierSyntax {
var isACLModifier: Bool {
let aclModifiers: Set<TokenKind> = [
.keyword(.private),
.keyword(.fileprivate),
.keyword(.internal),
.keyword(.public),
.keyword(.open)
]
return detail == nil && aclModifiers.contains(name.tokenKind)
}
}

View File

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

View File

@ -1,12 +1,10 @@
import Foundation
import SourceKittenFramework
public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, OptInRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "extension_access_modifier",
name: "Extension Access Modifier",
description: "Prefer to use extension access modifiers",
@ -52,6 +50,12 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
open bar: Int { return 1 }
open baz: Int { return 1 }
}
"""),
Example("""
extension Foo {
func setup() {}
public func update() {}
}
""")
],
triggeringExamples: [
@ -72,11 +76,21 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
public func bar() {}
public func baz() {}
}
"""),
Example("""
extension Foo {
public var bar: Int {
let value = 1
return value
}
public var baz: Int { return 1 }
}
""")
]
)
public func validate(file: SwiftLintFile, kind: SwiftDeclarationKind,
func validate(file: SwiftLintFile, kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) -> [StyleViolation] {
guard kind == .extension, let offset = dictionary.offset,
dictionary.inheritedTypes.isEmpty
@ -86,14 +100,13 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
let declarations = dictionary.substructure
.compactMap { entry -> (acl: AccessControlLevel, offset: ByteCount)? in
guard entry.declarationKind != nil,
let acl = entry.accessibility,
let offset = entry.offset
else {
guard let kind = entry.declarationKind,
kind != .varLocal, kind != .varParameter,
let offset = entry.offset else {
return nil
}
return (acl: acl, offset: offset)
return (acl: entry.accessibility ?? .internal, offset: offset)
}
let declarationsACLs = declarations.map { $0.acl }.unique
@ -111,7 +124,7 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
}
return [
StyleViolation(ruleDescription: type(of: self).description,
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: offset))
]
@ -134,7 +147,7 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
let violationOffsets = declarationOffsets.filter { typeOffset in
// find the last ACL token before the type
guard let previousInternalByteRange = lastACLByteRange(before: typeOffset, in: allACLRanges) else {
// didn't find a candidate token, so the ACL is implict (not a violation)
// didn't find a candidate token, so the ACL is implicit (not a violation)
return false
}
@ -142,13 +155,11 @@ public struct ExtensionAccessModifierRule: ASTRule, ConfigurationProviderRule, O
// attributeBuiltin (`final` for example) tokens between them
let length = typeOffset - previousInternalByteRange.location
let range = ByteRange(location: previousInternalByteRange.location, length: length)
let internalBelongsToType = Set(file.syntaxMap.kinds(inByteRange: range)) == [.attributeBuiltin]
return internalBelongsToType
return Set(file.syntaxMap.kinds(inByteRange: range)) == [.attributeBuiltin]
}
return violationOffsets.map {
StyleViolation(ruleDescription: type(of: self).description,
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: $0))
}

View File

@ -0,0 +1,42 @@
import SwiftSyntax
struct FallthroughRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "fallthrough",
name: "Fallthrough",
description: "Fallthrough should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
switch foo {
case .bar, .bar2, .bar3:
something()
}
""")
],
triggeringExamples: [
Example("""
switch foo {
case .bar:
fallthrough
case .bar2:
something()
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension FallthroughRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FallthroughStmtSyntax) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,63 @@
import SwiftSyntax
struct FatalErrorMessageRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "fatal_error_message",
name: "Fatal Error Message",
description: "A fatalError call should have a message",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
func foo() {
fatalError("Foo")
}
"""),
Example("""
func foo() {
fatalError(x)
}
""")
],
triggeringExamples: [
Example("""
func foo() {
fatalError("")
}
"""),
Example("""
func foo() {
fatalError()
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension FatalErrorMessageRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard let expression = node.calledExpression.as(IdentifierExprSyntax.self),
expression.identifier.text == "fatalError",
node.argumentList.isEmptyOrEmptyString else {
return
}
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
private extension TupleExprElementListSyntax {
var isEmptyOrEmptyString: Bool {
if isEmpty {
return true
}
return count == 1 && first?.expression.as(StringLiteralExprSyntax.self)?.isEmptyString == true
}
}

View File

@ -1,22 +1,17 @@
import Foundation
import SourceKittenFramework
public struct FileNameNoSpaceRule: ConfigurationProviderRule, OptInRule {
public var configuration = FileNameNoSpaceConfiguration(
severity: .warning,
excluded: []
)
struct FileNameNoSpaceRule: ConfigurationProviderRule, OptInRule, SourceKitFreeRule {
var configuration = FileNameNoSpaceConfiguration()
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "file_name_no_space",
name: "File Name No Space",
description: "File name should not contain any whitespace.",
name: "File Name no Space",
description: "File name should not contain any whitespace",
kind: .idiomatic
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let filePath = file.path,
case let fileName = filePath.bridge().lastPathComponent,
!configuration.excluded.contains(fileName),
@ -24,8 +19,8 @@ public struct FileNameNoSpaceRule: ConfigurationProviderRule, OptInRule {
return []
}
return [StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity.severity,
return [StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: filePath, line: 1))]
}
}

View File

@ -0,0 +1,84 @@
import SwiftSyntax
struct FileNameRule: ConfigurationProviderRule, OptInRule, SourceKitFreeRule {
var configuration = FileNameConfiguration()
static let description = RuleDescription(
identifier: "file_name",
name: "File Name",
description: "File name should match a type or extension declared in the file (if any)",
kind: .idiomatic
)
func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let filePath = file.path,
case let fileName = filePath.bridge().lastPathComponent,
!configuration.excluded.contains(fileName) else {
return []
}
let prefixRegex = regex("\\A(?:\(configuration.prefixPattern))")
let suffixRegex = regex("(?:\(configuration.suffixPattern))\\z")
var typeInFileName = fileName.bridge().deletingPathExtension
// Process prefix
if let match = prefixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange),
let range = typeInFileName.nsrangeToIndexRange(match.range) {
typeInFileName.removeSubrange(range)
}
// Process suffix
if let match = suffixRegex.firstMatch(in: typeInFileName, options: [], range: typeInFileName.fullNSRange),
let range = typeInFileName.nsrangeToIndexRange(match.range) {
typeInFileName.removeSubrange(range)
}
// Process nested type separator
let allDeclaredTypeNames = TypeNameCollectingVisitor(viewMode: .sourceAccurate)
.walk(tree: file.syntaxTree, handler: \.names)
.map {
$0.replacingOccurrences(of: ".", with: configuration.nestedTypeSeparator)
}
guard allDeclaredTypeNames.isNotEmpty, !allDeclaredTypeNames.contains(typeInFileName) else {
return []
}
return [StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: filePath, line: 1))]
}
}
private class TypeNameCollectingVisitor: SyntaxVisitor {
private(set) var names: Set<String> = []
override func visitPost(_ node: ClassDeclSyntax) {
names.insert(node.identifier.text)
}
override func visitPost(_ node: ActorDeclSyntax) {
names.insert(node.identifier.text)
}
override func visitPost(_ node: StructDeclSyntax) {
names.insert(node.identifier.text)
}
override func visitPost(_ node: TypealiasDeclSyntax) {
names.insert(node.identifier.text)
}
override func visitPost(_ node: EnumDeclSyntax) {
names.insert(node.identifier.text)
}
override func visitPost(_ node: ProtocolDeclSyntax) {
names.insert(node.identifier.text)
}
override func visitPost(_ node: ExtensionDeclSyntax) {
names.insert(node.extendedType.trimmedDescription)
}
}

View File

@ -0,0 +1,189 @@
import SwiftSyntax
struct ForWhereRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = ForWhereConfiguration()
static let description = RuleDescription(
identifier: "for_where",
name: "Prefer For-Where",
description: "`where` clauses are preferred over a single `if` inside a `for`",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
for user in users where user.id == 1 { }
"""),
// if let
Example("""
for user in users {
if let id = user.id { }
}
"""),
// if var
Example("""
for user in users {
if var id = user.id { }
}
"""),
// if with else
Example("""
for user in users {
if user.id == 1 { } else { }
}
"""),
// if with else if
Example("""
for user in users {
if user.id == 1 {
} else if user.id == 2 { }
}
"""),
// if is not the only expression inside for
Example("""
for user in users {
if user.id == 1 { }
print(user)
}
"""),
// if a variable is used
Example("""
for user in users {
let id = user.id
if id == 1 { }
}
"""),
// if something is after if
Example("""
for user in users {
if user.id == 1 { }
return true
}
"""),
// condition with multiple clauses
Example("""
for user in users {
if user.id == 1 && user.age > 18 { }
}
"""),
Example("""
for user in users {
if user.id == 1, user.age > 18 { }
}
"""),
// if case
Example("""
for (index, value) in array.enumerated() {
if case .valueB(_) = value {
return index
}
}
"""),
Example("""
for user in users {
if user.id == 1 { return true }
}
""", configuration: ["allow_for_as_filter": true]),
Example("""
for user in users {
if user.id == 1 {
let derivedValue = calculateValue(from: user)
return derivedValue != 0
}
}
""", configuration: ["allow_for_as_filter": true])
],
triggeringExamples: [
Example("""
for user in users {
if user.id == 1 { return true }
}
"""),
Example("""
for subview in subviews {
if !(subview is UIStackView) {
subview.removeConstraints(subview.constraints)
subview.removeFromSuperview()
}
}
"""),
Example("""
for subview in subviews {
if !(subview is UIStackView) {
subview.removeConstraints(subview.constraints)
subview.removeFromSuperview()
}
}
""", configuration: ["allow_for_as_filter": true])
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(allowForAsFilter: configuration.allowForAsFilter)
}
}
private extension ForWhereRule {
final class Visitor: ViolationsSyntaxVisitor {
private let allowForAsFilter: Bool
init(allowForAsFilter: Bool) {
self.allowForAsFilter = allowForAsFilter
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: ForInStmtSyntax) {
guard node.whereClause == nil,
let onlyExprStmt = node.body.statements.onlyElement?.item.as(ExpressionStmtSyntax.self),
let ifExpr = onlyExprStmt.expression.as(IfExprSyntax.self),
ifExpr.elseBody == nil,
!ifExpr.containsOptionalBinding,
!ifExpr.containsPatternCondition,
let condition = ifExpr.conditions.onlyElement,
!condition.containsMultipleConditions else {
return
}
if allowForAsFilter, ifExpr.containsReturnStatement {
return
}
violations.append(ifExpr.positionAfterSkippingLeadingTrivia)
}
}
}
private extension IfExprSyntax {
var containsOptionalBinding: Bool {
conditions.contains { element in
element.condition.is(OptionalBindingConditionSyntax.self)
}
}
var containsPatternCondition: Bool {
conditions.contains { element in
element.condition.is(MatchingPatternConditionSyntax.self)
}
}
var containsReturnStatement: Bool {
body.statements.contains { element in
element.item.is(ReturnStmtSyntax.self)
}
}
}
private extension ConditionElementSyntax {
var containsMultipleConditions: Bool {
guard let condition = condition.as(SequenceExprSyntax.self) else {
return false
}
return condition.elements.contains { expr in
guard let binaryExpr = expr.as(BinaryOperatorExprSyntax.self) else {
return false
}
let operators: Set = ["&&", "||"]
return operators.contains(binaryExpr.operatorToken.text)
}
}
}

View File

@ -0,0 +1,34 @@
import SwiftSyntax
struct ForceCastRule: ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
identifier: "force_cast",
name: "Force Cast",
description: "Force casts should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("NSNumber() as? Int\n")
],
triggeringExamples: [ Example("NSNumber() ↓as! Int\n") ]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
ForceCastRuleVisitor(viewMode: .sourceAccurate)
}
}
private final class ForceCastRuleVisitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: AsExprSyntax) {
if node.questionOrExclamationMark?.tokenKind == .exclamationMark {
violations.append(node.asTok.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: UnresolvedAsExprSyntax) {
if node.questionOrExclamationMark?.tokenKind == .exclamationMark {
violations.append(node.asTok.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,40 @@
import SwiftSyntax
struct ForceTryRule: ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
identifier: "force_try",
name: "Force Try",
description: "Force tries should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
func a() throws {}
do {
try a()
} catch {}
""")
],
triggeringExamples: [
Example("""
func a() throws {}
try! a()
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension ForceTryRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: TryExprSyntax) {
if node.questionOrExclamationMark?.tokenKind == .exclamationMark {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
}

View File

@ -0,0 +1,77 @@
import SwiftSyntax
struct ForceUnwrappingRule: OptInRule, SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "force_unwrapping",
name: "Force Unwrapping",
description: "Force unwrapping should be avoided",
kind: .idiomatic,
nonTriggeringExamples: [
Example("if let url = NSURL(string: query)"),
Example("navigationController?.pushViewController(viewController, animated: true)"),
Example("let s as! Test"),
Example("try! canThrowErrors()"),
Example("let object: Any!"),
Example("@IBOutlet var constraints: [NSLayoutConstraint]!"),
Example("setEditing(!editing, animated: true)"),
Example("navigationController.setNavigationBarHidden(!navigationController." +
"navigationBarHidden, animated: true)"),
Example("if addedToPlaylist && (!self.selectedFilters.isEmpty || " +
"self.searchBar?.text?.isEmpty == false) {}"),
Example("print(\"\\(xVar)!\")"),
Example("var test = (!bar)"),
Example("var a: [Int]!"),
Example("private var myProperty: (Void -> Void)!"),
Example("func foo(_ options: [AnyHashable: Any]!) {"),
Example("func foo() -> [Int]!"),
Example("func foo() -> [AnyHashable: Any]!"),
Example("func foo() -> [Int]! { return [] }"),
Example("return self")
],
triggeringExamples: [
Example("let url = NSURL(string: query)↓!"),
Example("navigationController↓!.pushViewController(viewController, animated: true)"),
Example("let unwrapped = optional↓!"),
Example("return cell↓!"),
Example("let url = NSURL(string: \"http://www.google.com\")↓!"),
Example("""
let dict = ["Boooo": "👻"]
func bla() -> String {
return dict["Boooo"]!
}
"""),
Example("""
let dict = ["Boooo": "👻"]
func bla() -> String {
return dict["Boooo"]!.contains("B")
}
"""),
Example("let a = dict[\"abc\"]↓!.contains(\"B\")"),
Example("dict[\"abc\"]↓!.bar(\"B\")"),
Example("if dict[\"a\"]↓!↓!↓!↓! {}"),
Example("var foo: [Bool]! = dict[\"abc\"]↓!"),
Example("realm.objects(SwiftUTF8Object.self).filter(\"%K == %@\", \"柱нǢкƱаم👍\", utf8TestString).first↓!"),
Example("""
context("abc") {
var foo: [Bool]! = dict["abc"]!
}
"""),
Example("open var computed: String { return foo.bar↓! }"),
Example("return self↓!"),
Example("[1, 3, 5, 6].first { $0.isMultiple(of: 2) }↓!"),
Example("map[\"a\"]↓!↓!")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
ForceUnwrappingVisitor(viewMode: .sourceAccurate)
}
}
private final class ForceUnwrappingVisitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: ForcedValueExprSyntax) {
violations.append(node.exclamationMark.positionAfterSkippingLeadingTrivia)
}
}

View File

@ -0,0 +1,132 @@
import SwiftSyntax
struct FunctionDefaultParameterAtEndRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "function_default_parameter_at_end",
name: "Function Default Parameter at End",
description: "Prefer to locate parameters with defaults toward the end of the parameter list",
kind: .idiomatic,
nonTriggeringExamples: [
Example("func foo(baz: String, bar: Int = 0) {}"),
Example("func foo(x: String, y: Int = 0, z: CGFloat = 0) {}"),
Example("func foo(bar: String, baz: Int = 0, z: () -> Void) {}"),
Example("func foo(bar: String, z: () -> Void, baz: Int = 0) {}"),
Example("func foo(bar: Int = 0) {}"),
Example("func foo() {}"),
Example("""
class A: B {
override func foo(bar: Int = 0, baz: String) {}
"""),
Example("func foo(bar: Int = 0, completion: @escaping CompletionHandler) {}"),
Example("""
func foo(a: Int, b: CGFloat = 0) {
let block = { (error: Error?) in }
}
"""),
Example("""
func foo(a: String, b: String? = nil,
c: String? = nil, d: @escaping AlertActionHandler = { _ in }) {}
"""),
Example("override init?(for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}"),
Example("""
func handleNotification(_ userInfo: NSDictionary,
userInteraction: Bool = false,
completionHandler: ((UIBackgroundFetchResult) -> Void)?) {}
"""),
Example("""
func write(withoutNotifying tokens: [NotificationToken] = {}, _ block: (() throws -> Int)) {}
"""),
Example("""
func expect<T>(file: String = #file, _ expression: @autoclosure () -> (() throws -> T)) -> Expectation<T> {}
""", excludeFromDocumentation: true)
],
triggeringExamples: [
Example("↓func foo(bar: Int = 0, baz: String) {}"),
Example("private ↓func foo(bar: Int = 0, baz: String) {}"),
Example("public ↓init?(for date: Date = Date(), coordinate: CLLocationCoordinate2D) {}")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension FunctionDefaultParameterAtEndRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionDeclSyntax) {
guard !node.modifiers.containsOverride, node.signature.containsViolation else {
return
}
violations.append(node.funcKeyword.positionAfterSkippingLeadingTrivia)
}
override func visitPost(_ node: InitializerDeclSyntax) {
guard !node.modifiers.containsOverride, node.signature.containsViolation else {
return
}
violations.append(node.initKeyword.positionAfterSkippingLeadingTrivia)
}
}
}
private extension FunctionSignatureSyntax {
var containsViolation: Bool {
let params = input.parameterList.filter { param in
!param.isClosure
}
guard params.isNotEmpty else {
return false
}
let defaultParams = params.filter { param in
param.defaultArgument != nil
}
guard defaultParams.isNotEmpty else {
return false
}
let lastParameters = params.suffix(defaultParams.count)
let lastParametersWithDefaultValue = lastParameters.filter { param in
param.defaultArgument != nil
}
return lastParameters.count != lastParametersWithDefaultValue.count
}
}
private extension FunctionParameterSyntax {
var isClosure: Bool {
if isEscaping || type.is(FunctionTypeSyntax.self) {
return true
}
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) {
return tuple.elements.onlyElement?.type.as(FunctionTypeSyntax.self) != nil
}
if let attrType = type.as(AttributedTypeSyntax.self) {
return attrType.baseType.is(FunctionTypeSyntax.self)
}
return false
}
var isEscaping: Bool {
guard let attrType = type.as(AttributedTypeSyntax.self) else {
return false
}
return attrType.attributes.contains(attributeNamed: "escaping")
}
}

View File

@ -0,0 +1,101 @@
import Foundation
import SwiftSyntax
struct GenericTypeNameRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = NameConfiguration<Self>(minLengthWarning: 1,
minLengthError: 0,
maxLengthWarning: 20,
maxLengthError: 1000)
static let description = RuleDescription(
identifier: "generic_type_name",
name: "Generic Type Name",
description: "Generic type name should only contain alphanumeric characters, start with an " +
"uppercase character and span between 1 and 20 characters in length.",
kind: .idiomatic,
nonTriggeringExamples: [
Example("func foo<T>() {}\n"),
Example("func foo<T>() -> T {}\n"),
Example("func foo<T, U>(param: U) -> T {}\n"),
Example("func foo<T: Hashable, U: Rule>(param: U) -> T {}\n"),
Example("struct Foo<T> {}\n"),
Example("class Foo<T> {}\n"),
Example("enum Foo<T> {}\n"),
Example("func run(_ options: NoOptions<CommandantError<()>>) {}\n"),
Example("func foo(_ options: Set<type>) {}\n"),
Example("func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool\n"),
Example("func configureWith(data: Either<MessageThread, (project: Project, backing: Backing)>)\n"),
Example("typealias StringDictionary<T> = Dictionary<String, T>\n"),
Example("typealias BackwardTriple<T1, T2, T3> = (T3, T2, T1)\n"),
Example("typealias DictionaryOfStrings<T : Hashable> = Dictionary<T, String>\n")
],
triggeringExamples: [
Example("func foo<↓T_Foo>() {}\n"),
Example("func foo<T, ↓U_Foo>(param: U_Foo) -> T {}\n"),
Example("func foo<↓\(String(repeating: "T", count: 21))>() {}\n"),
Example("func foo<↓type>() {}\n"),
Example("typealias StringDictionary<↓T_Foo> = Dictionary<String, T_Foo>\n"),
Example("typealias BackwardTriple<T1, ↓T2_Bar, T3> = (T3, T2_Bar, T1)\n"),
Example("typealias DictionaryOfStrings<↓T_Foo: Hashable> = Dictionary<T_Foo, String>\n")
] + ["class", "struct", "enum"].flatMap { type -> [Example] in
return [
Example("\(type) Foo<↓T_Foo> {}\n"),
Example("\(type) Foo<T, ↓U_Foo> {}\n"),
Example("\(type) Foo<↓T_Foo, ↓U_Foo> {}\n"),
Example("\(type) Foo<↓\(String(repeating: "T", count: 21))> {}\n"),
Example("\(type) Foo<↓type> {}\n")
]
}
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(configuration: configuration)
}
}
private extension GenericTypeNameRule {
final class Visitor: ViolationsSyntaxVisitor {
private let configuration: ConfigurationType
init(configuration: ConfigurationType) {
self.configuration = configuration
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: GenericParameterSyntax) {
let name = node.name.text
guard !name.isEmpty, !configuration.shouldExclude(name: name) else { return }
if !configuration.allowedSymbolsAndAlphanumerics.isSuperset(of: CharacterSet(charactersIn: name)) {
violations.append(
ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,
reason: """
Generic type name '\(name)' should only contain alphanumeric and other allowed characters
""",
severity: .error
)
)
} 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: caseCheckSeverity
)
)
} else if let severity = configuration.severity(forLength: name.count) {
let reason = "Generic type name '\(name)' should be between \(configuration.minLengthThreshold) and " +
"\(configuration.maxLengthThreshold) characters long"
violations.append(
ReasonedRuleViolation(
position: node.positionAfterSkippingLeadingTrivia,
reason: reason,
severity: severity
)
)
}
}
}
}

View File

@ -0,0 +1,71 @@
import SwiftSyntax
struct ImplicitlyUnwrappedOptionalRule: SwiftSyntaxRule, ConfigurationProviderRule, OptInRule {
var configuration = ImplicitlyUnwrappedOptionalConfiguration()
static let description = RuleDescription(
identifier: "implicitly_unwrapped_optional",
name: "Implicitly Unwrapped Optional",
description: "Implicitly unwrapped optionals should be avoided when possible",
kind: .idiomatic,
nonTriggeringExamples: [
Example("@IBOutlet private var label: UILabel!"),
Example("@IBOutlet var label: UILabel!"),
Example("@IBOutlet var label: [UILabel!]"),
Example("if !boolean {}"),
Example("let int: Int? = 42"),
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("""
class MyClass {
weak var bar: SomeObject!
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(mode: configuration.mode)
}
}
private extension ImplicitlyUnwrappedOptionalRule {
final class Visitor: ViolationsSyntaxVisitor {
private let mode: ConfigurationType.ImplicitlyUnwrappedOptionalModeConfiguration
init(mode: ConfigurationType.ImplicitlyUnwrappedOptionalModeConfiguration) {
self.mode = mode
super.init(viewMode: .sourceAccurate)
}
override func visitPost(_ node: ImplicitlyUnwrappedOptionalTypeSyntax) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
override func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
switch mode {
case .all:
return .visitChildren
case .allExceptIBOutlets:
return node.isIBOutlet ? .skipChildren : .visitChildren
}
}
}
}

View File

@ -0,0 +1,43 @@
import SwiftSyntax
struct IsDisjointRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "is_disjoint",
name: "Is Disjoint",
description: "Prefer using `Set.isDisjoint(with:)` over `Set.intersection(_:).isEmpty`",
kind: .idiomatic,
nonTriggeringExamples: [
Example("_ = Set(syntaxKinds).isDisjoint(with: commentAndStringKindsSet)"),
Example("let isObjc = !objcAttributes.isDisjoint(with: dictionary.enclosedSwiftAttributes)"),
Example("_ = Set(syntaxKinds).intersection(commentAndStringKindsSet)"),
Example("_ = !objcAttributes.intersection(dictionary.enclosedSwiftAttributes)")
],
triggeringExamples: [
Example("_ = Set(syntaxKinds).↓intersection(commentAndStringKindsSet).isEmpty"),
Example("let isObjc = !objcAttributes.↓intersection(dictionary.enclosedSwiftAttributes).isEmpty")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension IsDisjointRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: MemberAccessExprSyntax) {
guard
node.name.text == "isEmpty",
let firstBase = node.base?.asFunctionCall,
let firstBaseCalledExpression = firstBase.calledExpression.as(MemberAccessExprSyntax.self),
firstBaseCalledExpression.name.text == "intersection"
else {
return
}
violations.append(firstBaseCalledExpression.name.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,96 @@
import SwiftSyntax
struct JoinedDefaultParameterRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule, OptInRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "joined_default_parameter",
name: "Joined Default Parameter",
description: "Discouraged explicit usage of the default separator",
kind: .idiomatic,
nonTriggeringExamples: [
Example("let foo = bar.joined()"),
Example("let foo = bar.joined(separator: \",\")"),
Example("let foo = bar.joined(separator: toto)")
],
triggeringExamples: [
Example("let foo = bar.joined(↓separator: \"\")"),
Example("""
let foo = bar.filter(toto)
.joined(separator: ""),
"""),
Example("""
func foo() -> String {
return ["1", "2"].joined(separator: "")
}
""")
],
corrections: [
Example("let foo = bar.joined(↓separator: \"\")"): Example("let foo = bar.joined()"),
Example("let foo = bar.filter(toto)\n.joined(↓separator: \"\")"):
Example("let foo = bar.filter(toto)\n.joined()"),
Example("func foo() -> String {\n return [\"1\", \"2\"].joined(↓separator: \"\")\n}"):
Example("func foo() -> String {\n return [\"1\", \"2\"].joined()\n}"),
Example("class C {\n#if true\nlet foo = bar.joined(↓separator: \"\")\n#endif\n}"):
Example("class C {\n#if true\nlet foo = bar.joined()\n#endif\n}")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
Rewriter(
locationConverter: file.locationConverter,
disabledRegions: disabledRegions(file: file)
)
}
}
private extension JoinedDefaultParameterRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let violationPosition = node.violationPosition {
violations.append(violationPosition)
}
}
}
final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
private(set) var correctionPositions: [AbsolutePosition] = []
private let locationConverter: SourceLocationConverter
private let disabledRegions: [SourceRange]
init(locationConverter: SourceLocationConverter, disabledRegions: [SourceRange]) {
self.locationConverter = locationConverter
self.disabledRegions = disabledRegions
}
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
guard let violationPosition = node.violationPosition,
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return super.visit(node)
}
correctionPositions.append(violationPosition)
let newNode = node.with(\.argumentList, [])
return super.visit(newNode)
}
}
}
private extension FunctionCallExprSyntax {
var violationPosition: AbsolutePosition? {
guard let argument = argumentList.first,
let memberExp = calledExpression.as(MemberAccessExprSyntax.self),
memberExp.name.text == "joined",
argument.label?.text == "separator",
let strLiteral = argument.expression.as(StringLiteralExprSyntax.self),
strLiteral.isEmptyString else {
return nil
}
return argument.positionAfterSkippingLeadingTrivia
}
}

View File

@ -1,12 +1,7 @@
import Foundation
import SourceKittenFramework
struct LegacyCGGeometryFunctionsRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
public struct LegacyCGGeometryFunctionsRule: CorrectableRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "legacy_cggeometry_functions",
name: "Legacy CGGeometry Functions",
description: "Struct extension properties and methods are preferred over legacy functions",
@ -73,7 +68,7 @@ public struct LegacyCGGeometryFunctionsRule: CorrectableRule, ConfigurationProvi
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"),
@ -82,49 +77,38 @@ public struct LegacyCGGeometryFunctionsRule: CorrectableRule, ConfigurationProvi
]
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
let functions = ["CGRectGetWidth", "CGRectGetHeight", "CGRectGetMinX", "CGRectGetMidX",
"CGRectGetMaxX", "CGRectGetMinY", "CGRectGetMidY", "CGRectGetMaxY",
"CGRectIsNull", "CGRectIsEmpty", "CGRectIsInfinite", "CGRectStandardize",
"CGRectIntegral", "CGRectInset", "CGRectOffset", "CGRectUnion",
"CGRectIntersection", "CGRectContainsRect", "CGRectContainsPoint",
"CGRectIntersectsRect"]
let pattern = "\\b(" + functions.joined(separator: "|") + ")\\b"
return file.match(pattern: pattern, with: [.identifier]).map {
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, characterOffset: $0.location))
}
}
public func correct(file: SwiftLintFile) -> [Correction] {
let varName = RegexHelpers.varNameGroup
let twoVars = RegexHelpers.twoVars
let twoVariableOrNumber = RegexHelpers.twoVariableOrNumber
let patterns: [String: String] = [
"CGRectGetWidth\\(\(varName)\\)": "$1.width",
"CGRectGetHeight\\(\(varName)\\)": "$1.height",
"CGRectGetMinX\\(\(varName)\\)": "$1.minX",
"CGRectGetMidX\\(\(varName)\\)": "$1.midX",
"CGRectGetMaxX\\(\(varName)\\)": "$1.maxX",
"CGRectGetMinY\\(\(varName)\\)": "$1.minY",
"CGRectGetMidY\\(\(varName)\\)": "$1.midY",
"CGRectGetMaxY\\(\(varName)\\)": "$1.maxY",
"CGRectIsNull\\(\(varName)\\)": "$1.isNull",
"CGRectIsEmpty\\(\(varName)\\)": "$1.isEmpty",
"CGRectIsInfinite\\(\(varName)\\)": "$1.isInfinite",
"CGRectStandardize\\(\(varName)\\)": "$1.standardized",
"CGRectIntegral\\(\(varName)\\)": "$1.integral",
"CGRectInset\\(\(varName),\(twoVariableOrNumber)\\)": "$1.insetBy(dx: $2, dy: $3)",
"CGRectOffset\\(\(varName),\(twoVariableOrNumber)\\)": "$1.offsetBy(dx: $2, dy: $3)",
"CGRectUnion\\(\(twoVars)\\)": "$1.union($2)",
"CGRectIntersection\\(\(twoVars)\\)": "$1.intersect($2)",
"CGRectContainsRect\\(\(twoVars)\\)": "$1.contains($2)",
"CGRectContainsPoint\\(\(twoVars)\\)": "$1.contains($2)",
"CGRectIntersectsRect\\(\(twoVars)\\)": "$1.intersects($2)"
private static let legacyFunctions: [String: LegacyFunctionRuleHelper.RewriteStrategy] = [
"CGRectGetWidth": .property(name: "width"),
"CGRectGetHeight": .property(name: "height"),
"CGRectGetMinX": .property(name: "minX"),
"CGRectGetMidX": .property(name: "midX"),
"CGRectGetMaxX": .property(name: "maxX"),
"CGRectGetMinY": .property(name: "minY"),
"CGRectGetMidY": .property(name: "midY"),
"CGRectGetMaxY": .property(name: "maxY"),
"CGRectIsNull": .property(name: "isNull"),
"CGRectIsEmpty": .property(name: "isEmpty"),
"CGRectIsInfinite": .property(name: "isInfinite"),
"CGRectStandardize": .property(name: "standardized"),
"CGRectIntegral": .property(name: "integral"),
"CGRectInset": .function(name: "insetBy", argumentLabels: ["dx", "dy"]),
"CGRectOffset": .function(name: "offsetBy", argumentLabels: ["dx", "dy"]),
"CGRectUnion": .function(name: "union", argumentLabels: [""]),
"CGRectContainsRect": .function(name: "contains", argumentLabels: [""]),
"CGRectContainsPoint": .function(name: "contains", argumentLabels: [""]),
"CGRectIntersectsRect": .function(name: "intersects", argumentLabels: [""]),
"CGRectIntersection": .function(name: "intersection", argumentLabels: [""])
]
return file.correct(legacyRule: self, patterns: patterns)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
LegacyFunctionRuleHelper.Visitor(legacyFunctions: Self.legacyFunctions)
}
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
LegacyFunctionRuleHelper.Rewriter(
legacyFunctions: Self.legacyFunctions,
locationConverter: file.locationConverter,
disabledRegions: disabledRegions(file: file)
)
}
}

View File

@ -0,0 +1,98 @@
import SwiftSyntax
import SwiftSyntaxBuilder
struct LegacyConstantRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_constant",
name: "Legacy Constant",
description: "Struct-scoped constants are preferred over legacy global constants",
kind: .idiomatic,
nonTriggeringExamples: LegacyConstantRuleExamples.nonTriggeringExamples,
triggeringExamples: LegacyConstantRuleExamples.triggeringExamples,
corrections: LegacyConstantRuleExamples.corrections
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
Rewriter(
locationConverter: file.locationConverter,
disabledRegions: disabledRegions(file: file)
)
}
}
private extension LegacyConstantRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: IdentifierExprSyntax) {
if LegacyConstantRuleExamples.patterns.keys.contains(node.identifier.text) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: FunctionCallExprSyntax) {
if node.isLegacyPiExpression {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
private(set) var correctionPositions: [AbsolutePosition] = []
let locationConverter: SourceLocationConverter
let disabledRegions: [SourceRange]
init(locationConverter: SourceLocationConverter, disabledRegions: [SourceRange]) {
self.locationConverter = locationConverter
self.disabledRegions = disabledRegions
}
override func visit(_ node: IdentifierExprSyntax) -> ExprSyntax {
guard
let correction = LegacyConstantRuleExamples.patterns[node.identifier.text],
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter)
else {
return super.visit(node)
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return ("\(raw: correction)" as ExprSyntax)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
guard
node.isLegacyPiExpression,
let calledExpression = node.calledExpression.as(IdentifierExprSyntax.self),
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter)
else {
return super.visit(node)
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
return ("\(raw: calledExpression.identifier.text).pi" as ExprSyntax)
.with(\.leadingTrivia, node.leadingTrivia)
.with(\.trailingTrivia, node.trailingTrivia)
}
}
}
private extension FunctionCallExprSyntax {
var isLegacyPiExpression: Bool {
guard
let calledExpression = calledExpression.as(IdentifierExprSyntax.self),
calledExpression.identifier.text == "CGFloat" || calledExpression.identifier.text == "Float",
let argument = argumentList.onlyElement?.expression.as(IdentifierExprSyntax.self),
argument.identifier.text == "M_PI"
else {
return false
}
return true
}
}

View File

@ -48,8 +48,6 @@ internal struct LegacyConstantRuleExamples {
"NSZeroPoint": "NSPoint.zero",
"NSZeroRect": "NSRect.zero",
"NSZeroSize": "NSSize.zero",
"CGRectNull": "CGRect.null",
"CGFloat\\(M_PI\\)": "CGFloat.pi",
"Float\\(M_PI\\)": "Float.pi"
"CGRectNull": "CGRect.null"
]
}

View File

@ -1,15 +1,12 @@
import Foundation
import SourceKittenFramework
import SwiftSyntax
public struct LegacyConstructorRule: ASTRule, CorrectableRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
struct LegacyConstructorRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "legacy_constructor",
name: "Legacy Constructor",
description: "Swift constructors are preferred over legacy convenience functions.",
description: "Swift constructors are preferred over legacy convenience functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("CGPoint(x: 10, y: 10)"),
@ -62,22 +59,22 @@ public struct LegacyConstructorRule: ASTRule, CorrectableRule, ConfigurationProv
Example("↓UIOffsetMake(horizontal, vertical)")
],
corrections: [
Example("↓CGPointMake(10, 10 )\n"): Example("CGPoint(x: 10, y: 10)\n"),
Example("↓CGPointMake(xPos, yPos )\n"): Example("CGPoint(x: xPos, y: yPos)\n"),
Example("↓CGPointMake(10, 10)\n"): Example("CGPoint(x: 10, y: 10)\n"),
Example("↓CGPointMake(xPos, yPos)\n"): Example("CGPoint(x: xPos, y: yPos)\n"),
Example("↓CGSizeMake(10, 10)\n"): Example("CGSize(width: 10, height: 10)\n"),
Example("↓CGSizeMake( aWidth, aHeight )\n"): Example("CGSize(width: aWidth, height: aHeight)\n"),
Example("↓CGSizeMake( aWidth, aHeight )\n"): Example("CGSize( width: aWidth, height: aHeight )\n"),
Example("↓CGRectMake(0, 0, 10, 10)\n"): Example("CGRect(x: 0, y: 0, width: 10, height: 10)\n"),
Example("↓CGRectMake(xPos, yPos , width, height)\n"):
Example("CGRect(x: xPos, y: yPos, width: width, height: height)\n"),
Example("CGRect(x: xPos, y: yPos , width: width, height: height)\n"),
Example("↓CGVectorMake(10, 10)\n"): Example("CGVector(dx: 10, dy: 10)\n"),
Example("↓CGVectorMake(deltaX, deltaY)\n"): Example("CGVector(dx: deltaX, dy: deltaY)\n"),
Example("↓NSMakePoint(10, 10 )\n"): Example("NSPoint(x: 10, y: 10)\n"),
Example("↓NSMakePoint(xPos, yPos )\n"): Example("NSPoint(x: xPos, y: yPos)\n"),
Example("↓NSMakePoint(10, 10 )\n"): Example("NSPoint(x: 10, y: 10 )\n"),
Example("↓NSMakePoint(xPos, yPos )\n"): Example("NSPoint(x: xPos, y: yPos )\n"),
Example("↓NSMakeSize(10, 10)\n"): Example("NSSize(width: 10, height: 10)\n"),
Example("↓NSMakeSize( aWidth, aHeight )\n"): Example("NSSize(width: aWidth, height: aHeight)\n"),
Example("↓NSMakeSize( aWidth, aHeight )\n"): Example("NSSize( width: aWidth, height: aHeight )\n"),
Example("↓NSMakeRect(0, 0, 10, 10)\n"): Example("NSRect(x: 0, y: 0, width: 10, height: 10)\n"),
Example("↓NSMakeRect(xPos, yPos , width, height)\n"):
Example("NSRect(x: xPos, y: yPos, width: width, height: height)\n"),
Example("NSRect(x: xPos, y: yPos , width: width, height: height)\n"),
Example("↓NSMakeRange(10, 1)\n"): Example("NSRange(location: 10, length: 1)\n"),
Example("↓NSMakeRange(loc, len)\n"): Example("NSRange(location: loc, length: len)\n"),
Example("↓CGVectorMake(10, 10)\n↓NSMakeRange(10, 1)\n"):
@ -125,99 +122,66 @@ public struct LegacyConstructorRule: ASTRule, CorrectableRule, ConfigurationProv
"NSEdgeInsetsMake": "NSEdgeInsets",
"UIOffsetMake": "UIOffset"]
public func validate(file: SwiftLintFile, kind: SwiftExpressionKind,
dictionary: SourceKittenDictionary) -> [StyleViolation] {
guard containsViolation(kind: kind, dictionary: dictionary),
let offset = dictionary.offset else {
return []
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
return [
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, byteOffset: offset))
]
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
Rewriter(
locationConverter: file.locationConverter,
disabledRegions: disabledRegions(file: file)
)
}
}
private func violations(in file: SwiftLintFile, kind: SwiftExpressionKind,
dictionary: SourceKittenDictionary) -> [SourceKittenDictionary] {
guard containsViolation(kind: kind, dictionary: dictionary) else {
return []
private extension LegacyConstructorRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
if let identifierExpr = node.calledExpression.as(IdentifierExprSyntax.self),
constructorsToCorrectedNames[identifierExpr.identifier.text] != nil {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
return [dictionary]
}
private func containsViolation(kind: SwiftExpressionKind,
dictionary: SourceKittenDictionary) -> Bool {
guard kind == .call,
let name = dictionary.name,
dictionary.offset != nil,
let expectedArguments = type(of: self).constructorsToArguments[name],
dictionary.enclosedArguments.count == expectedArguments.count else {
return false
}
return true
}
private func violations(in file: SwiftLintFile,
dictionary: SourceKittenDictionary) -> [SourceKittenDictionary] {
return dictionary.traverseDepthFirst { subDict in
guard let kind = subDict.expressionKind else { return nil }
return violations(in: file, kind: kind, dictionary: subDict)
}
}
private func violations(in file: SwiftLintFile) -> [SourceKittenDictionary] {
return violations(in: file, dictionary: file.structureDictionary).sorted { lhs, rhs in
(lhs.offset ?? 0) < (rhs.offset ?? 0)
}
final class Rewriter: SyntaxRewriter, ViolationsSyntaxRewriter {
private(set) var correctionPositions: [AbsolutePosition] = []
let locationConverter: SourceLocationConverter
let disabledRegions: [SourceRange]
init(locationConverter: SourceLocationConverter, disabledRegions: [SourceRange]) {
self.locationConverter = locationConverter
self.disabledRegions = disabledRegions
}
public func correct(file: SwiftLintFile) -> [Correction] {
let violatingDictionaries = violations(in: file)
var correctedContents = file.contents
var adjustedLocations = [Int]()
for dictionary in violatingDictionaries.reversed() {
guard let byteRange = dictionary.byteRange,
let range = file.stringView.byteRangeToNSRange(byteRange),
let name = dictionary.name,
let correctedName = type(of: self).constructorsToCorrectedNames[name],
file.ruleEnabled(violatingRanges: [range], for: self) == [range],
case let arguments = argumentsContents(file: file, arguments: dictionary.enclosedArguments),
let expectedArguments = type(of: self).constructorsToArguments[name],
arguments.count == expectedArguments.count else {
continue
override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
guard let identifierExpr = node.calledExpression.as(IdentifierExprSyntax.self),
case let identifier = identifierExpr.identifier.text,
let correctedName = constructorsToCorrectedNames[identifier],
let args = constructorsToArguments[identifier],
!node.isContainedIn(regions: disabledRegions, locationConverter: locationConverter) else {
return super.visit(node)
}
if let indexRange = correctedContents.nsrangeToIndexRange(range) {
let joinedArguments = zip(expectedArguments, arguments).map { "\($0): \($1)" }.joined(separator: ", ")
let replacement = correctedName + "(" + joinedArguments + ")"
correctedContents = correctedContents.replacingCharacters(in: indexRange, with: replacement)
adjustedLocations.insert(range.location, at: 0)
}
}
correctionPositions.append(node.positionAfterSkippingLeadingTrivia)
let corrections = adjustedLocations.map {
Correction(ruleDescription: type(of: self).description,
location: Location(file: file, characterOffset: $0))
}
file.write(correctedContents)
return corrections
}
private func argumentsContents(file: SwiftLintFile, arguments: [SourceKittenDictionary]) -> [String] {
let contents = file.stringView
return arguments.compactMap { argument -> String? in
guard argument.name == nil, let byteRange = argument.byteRange else {
return nil
}
return contents.substringWithByteRange(byteRange)
let arguments = TupleExprElementListSyntax(node.argumentList.enumerated().map { index, elem in
elem
.with(\.label, .identifier(args[index]))
.with(\.colon, .colonToken(trailingTrivia: .space))
})
let newExpression = identifierExpr.with(
\.identifier,
.identifier(
correctedName,
leadingTrivia: identifierExpr.identifier.leadingTrivia,
trailingTrivia: identifierExpr.identifier.trailingTrivia
)
)
let newNode = node
.with(\.calledExpression, ExprSyntax(newExpression))
.with(\.argumentList, arguments)
return super.visit(newNode)
}
}
}

View File

@ -1,16 +1,13 @@
import SourceKittenFramework
import SwiftSyntax
public struct LegacyHashingRule: ASTRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
struct LegacyHashingRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "legacy_hashing",
name: "Legacy Hashing",
description: "Prefer using the `hash(into:)` function instead of overriding `hashValue`",
kind: .idiomatic,
minSwiftVersion: .fourDotTwo,
nonTriggeringExamples: [
Example("""
struct Foo: Hashable {
@ -76,21 +73,27 @@ public struct LegacyHashingRule: ASTRule, ConfigurationProviderRule, AutomaticTe
]
)
// MARK: - ASTRule
public func validate(file: SwiftLintFile,
kind: SwiftDeclarationKind,
dictionary: SourceKittenDictionary) -> [StyleViolation] {
guard kind == .varInstance,
dictionary.setterAccessibility == nil,
dictionary.typeName == "Int",
dictionary.name == "hashValue",
let offset = dictionary.offset else {
return []
}
return [StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, byteOffset: offset))]
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
extension LegacyHashingRule {
private final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: VariableDeclSyntax) {
guard
node.parent?.is(MemberDeclListItemSyntax.self) == true,
node.bindingKeyword.tokenKind == .keyword(.var),
let binding = node.bindings.onlyElement,
let identifier = binding.pattern.as(IdentifierPatternSyntax.self),
identifier.identifier.text == "hashValue",
let returnType = binding.typeAnnotation?.type.as(SimpleTypeIdentifierSyntax.self),
returnType.name.text == "Int"
else {
return
}
violations.append(node.bindingKeyword.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,84 @@
import SwiftSyntax
struct LegacyMultipleRule: OptInRule, ConfigurationProviderRule, SwiftSyntaxRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_multiple",
name: "Legacy Multiple",
description: "Prefer using the `isMultiple(of:)` function instead of using the remainder operator (`%`)",
kind: .idiomatic,
nonTriggeringExamples: [
Example("cell.contentView.backgroundColor = indexPath.row.isMultiple(of: 2) ? .gray : .white"),
Example("guard count.isMultiple(of: 2) else { throw DecodingError.dataCorrupted(...) }"),
Example("sanityCheck(bytes > 0 && bytes.isMultiple(of: 4), \"capacity must be multiple of 4 bytes\")"),
Example("guard let i = reversedNumbers.firstIndex(where: { $0.isMultiple(of: 2) }) else { return }"),
Example("""
let constant = 56
let isMultiple = value.isMultiple(of: constant)
"""),
Example("""
let constant = 56
let secret = value % constant == 5
"""),
Example("let secretValue = (value % 3) + 2")
],
triggeringExamples: [
Example("cell.contentView.backgroundColor = indexPath.row ↓% 2 == 0 ? .gray : .white"),
Example("cell.contentView.backgroundColor = 0 == indexPath.row ↓% 2 ? .gray : .white"),
Example("cell.contentView.backgroundColor = indexPath.row ↓% 2 != 0 ? .gray : .white"),
Example("guard count ↓% 2 == 0 else { throw DecodingError.dataCorrupted(...) }"),
Example("sanityCheck(bytes > 0 && bytes ↓% 4 == 0, \"capacity must be multiple of 4 bytes\")"),
Example("guard let i = reversedNumbers.firstIndex(where: { $0 ↓% 2 == 0 }) else { return }"),
Example("""
let constant = 56
let isMultiple = value % constant == 0
""")
]
)
func preprocess(file: SwiftLintFile) -> SourceFileSyntax? {
file.foldedSyntaxTree
}
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension LegacyMultipleRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: InfixOperatorExprSyntax) {
guard let operatorNode = node.operatorOperand.as(BinaryOperatorExprSyntax.self),
operatorNode.operatorToken.tokenKind == .binaryOperator("%"),
let parent = node.parent?.as(InfixOperatorExprSyntax.self),
let parentOperatorNode = parent.operatorOperand.as(BinaryOperatorExprSyntax.self),
parentOperatorNode.isEqualityOrInequalityOperator else {
return
}
let isExprEqualTo0 = {
parent.leftOperand.as(InfixOperatorExprSyntax.self) == node &&
parent.rightOperand.as(IntegerLiteralExprSyntax.self)?.isZero == true
}
let is0EqualToExpr = {
parent.leftOperand.as(IntegerLiteralExprSyntax.self)?.isZero == true &&
parent.rightOperand.as(InfixOperatorExprSyntax.self) == node
}
guard isExprEqualTo0() || is0EqualToExpr() else {
return
}
violations.append(node.operatorOperand.positionAfterSkippingLeadingTrivia)
}
}
}
private extension BinaryOperatorExprSyntax {
var isEqualityOrInequalityOperator: Bool {
operatorToken.tokenKind == .binaryOperator("==") ||
operatorToken.tokenKind == .binaryOperator("!=")
}
}

View File

@ -1,12 +1,7 @@
import Foundation
import SourceKittenFramework
struct LegacyNSGeometryFunctionsRule: SwiftSyntaxCorrectableRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
public struct LegacyNSGeometryFunctionsRule: CorrectableRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "legacy_nsgeometry_functions",
name: "Legacy NSGeometry Functions",
description: "Struct extension properties and methods are preferred over legacy functions",
@ -25,7 +20,7 @@ public struct LegacyNSGeometryFunctionsRule: CorrectableRule, ConfigurationProvi
Example("rect.insetBy(dx: 5.0, dy: -7.0)"),
Example("rect.offsetBy(dx: 5.0, dy: -7.0)"),
Example("rect1.union(rect2)"),
Example("rect1.intersect(rect2)"),
Example("rect1.intersection(rect2)"),
// "rect.divide(atDistance: 10.2, fromEdge: edge)", No correction available for divide
Example("rect1.contains(rect2)"),
Example("rect.contains(point)"),
@ -72,59 +67,48 @@ public struct LegacyNSGeometryFunctionsRule: CorrectableRule, ConfigurationProvi
Example("↓NSInsetRect(rect, 5.0, -7.0)\n"): Example("rect.insetBy(dx: 5.0, dy: -7.0)\n"),
Example("↓NSOffsetRect(rect, -2, 8.3)\n"): Example("rect.offsetBy(dx: -2, dy: 8.3)\n"),
Example("↓NSUnionRect(rect1, rect2)\n"): Example("rect1.union(rect2)\n"),
Example("↓NSIntersectionRect( rect1 ,rect2)\n"): Example("rect1.intersect(rect2)\n"),
Example("↓NSContainsRect( rect1,rect2 )\n"): Example("rect1.contains(rect2)\n"),
Example("↓NSPointInRect(point ,rect)\n"): Example("rect.contains(point)\n"), // note order of arguments
Example("↓NSIntersectsRect( rect1,rect2 )\n"): Example("rect1.intersects(rect2)\n"),
Example("↓NSIntersectsRect(rect1, rect2 )\n↓NSWidth(rect )\n"):
Example("rect1.intersects(rect2)\nrect.width\n")
Example("rect1.intersects(rect2)\nrect.width\n"),
Example("↓NSIntersectionRect(rect1, rect2)"): Example("rect1.intersection(rect2)")
]
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
let functions = ["NSWidth", "NSHeight", "NSMinX", "NSMidX",
"NSMaxX", "NSMinY", "NSMidY", "NSMaxY",
"NSEqualRects", "NSEqualSizes", "NSEqualPoints", "NSEdgeInsetsEqual",
"NSIsEmptyRect", "NSIntegralRect", "NSInsetRect",
"NSOffsetRect", "NSUnionRect", "NSIntersectionRect",
"NSContainsRect", "NSPointInRect", "NSIntersectsRect"]
let pattern = "\\b(" + functions.joined(separator: "|") + ")\\b"
return file.match(pattern: pattern, with: [.identifier]).map {
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, characterOffset: $0.location))
}
}
public func correct(file: SwiftLintFile) -> [Correction] {
let varName = RegexHelpers.varNameGroup
let twoVars = RegexHelpers.twoVars
let twoVariableOrNumber = RegexHelpers.twoVariableOrNumber
let patterns: [String: String] = [
"NSWidth\\(\(varName)\\)": "$1.width",
"NSHeight\\(\(varName)\\)": "$1.height",
"NSMinX\\(\(varName)\\)": "$1.minX",
"NSMidX\\(\(varName)\\)": "$1.midX",
"NSMaxX\\(\(varName)\\)": "$1.maxX",
"NSMinY\\(\(varName)\\)": "$1.minY",
"NSMidY\\(\(varName)\\)": "$1.midY",
"NSMaxY\\(\(varName)\\)": "$1.maxY",
"NSEqualRects\\(\(twoVars)\\)": "$1 == $2",
"NSEqualSizes\\(\(twoVars)\\)": "$1 == $2",
"NSEqualPoints\\(\(twoVars)\\)": "$1 == $2",
"NSEdgeInsetsEqual\\(\(twoVars)\\)": "$1 == $2",
"NSIsEmptyRect\\(\(varName)\\)": "$1.isEmpty",
"NSIntegralRect\\(\(varName)\\)": "$1.integral",
"NSInsetRect\\(\(varName),\(twoVariableOrNumber)\\)": "$1.insetBy(dx: $2, dy: $3)",
"NSOffsetRect\\(\(varName),\(twoVariableOrNumber)\\)": "$1.offsetBy(dx: $2, dy: $3)",
"NSUnionRect\\(\(twoVars)\\)": "$1.union($2)",
"NSIntersectionRect\\(\(twoVars)\\)": "$1.intersect($2)",
"NSContainsRect\\(\(twoVars)\\)": "$1.contains($2)",
"NSPointInRect\\(\(twoVars)\\)": "$2.contains($1)", // note order of arguments
"NSIntersectsRect\\(\(twoVars)\\)": "$1.intersects($2)"
private static let legacyFunctions: [String: LegacyFunctionRuleHelper.RewriteStrategy] = [
"NSHeight": .property(name: "height"),
"NSIntegralRect": .property(name: "integral"),
"NSIsEmptyRect": .property(name: "isEmpty"),
"NSMaxX": .property(name: "maxX"),
"NSMaxY": .property(name: "maxY"),
"NSMidX": .property(name: "midX"),
"NSMidY": .property(name: "midY"),
"NSMinX": .property(name: "minX"),
"NSMinY": .property(name: "minY"),
"NSWidth": .property(name: "width"),
"NSEqualPoints": .equal,
"NSEqualSizes": .equal,
"NSEqualRects": .equal,
"NSEdgeInsetsEqual": .equal,
"NSInsetRect": .function(name: "insetBy", argumentLabels: ["dx", "dy"]),
"NSOffsetRect": .function(name: "offsetBy", argumentLabels: ["dx", "dy"]),
"NSUnionRect": .function(name: "union", argumentLabels: [""]),
"NSContainsRect": .function(name: "contains", argumentLabels: [""]),
"NSIntersectsRect": .function(name: "intersects", argumentLabels: [""]),
"NSIntersectionRect": .function(name: "intersection", argumentLabels: [""]),
"NSPointInRect": .function(name: "contains", argumentLabels: [""], reversed: true)
]
return file.correct(legacyRule: self, patterns: patterns)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
LegacyFunctionRuleHelper.Visitor(legacyFunctions: Self.legacyFunctions)
}
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? {
LegacyFunctionRuleHelper.Rewriter(
legacyFunctions: Self.legacyFunctions,
locationConverter: file.locationConverter,
disabledRegions: disabledRegions(file: file)
)
}
}

View File

@ -0,0 +1,98 @@
import SwiftSyntax
private let legacyObjcTypes = [
"NSAffineTransform",
"NSArray",
"NSCalendar",
"NSCharacterSet",
"NSData",
"NSDateComponents",
"NSDateInterval",
"NSDate",
"NSDecimalNumber",
"NSDictionary",
"NSIndexPath",
"NSIndexSet",
"NSLocale",
"NSMeasurement",
"NSNotification",
"NSNumber",
"NSPersonNameComponents",
"NSSet",
"NSString",
"NSTimeZone",
"NSURL",
"NSURLComponents",
"NSURLQueryItem",
"NSURLRequest",
"NSUUID"
]
struct LegacyObjcTypeRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "legacy_objc_type",
name: "Legacy Objective-C Reference Type",
description: "Prefer Swift value types to bridged Objective-C reference types",
kind: .idiomatic,
nonTriggeringExamples: [
Example("var array = Array<Int>()\n"),
Example("var calendar: Calendar? = nil"),
Example("var formatter: NSDataDetector"),
Example("var className: String = NSStringFromClass(MyClass.self)"),
Example("_ = URLRequest.CachePolicy.reloadIgnoringLocalCacheData"),
Example(#"_ = Notification.Name("com.apple.Music.playerInfo")"#)
],
triggeringExamples: [
Example("var array = ↓NSArray()"),
Example("var calendar: ↓NSCalendar? = nil"),
Example("_ = ↓NSURLRequest.CachePolicy.reloadIgnoringLocalCacheData"),
Example(#"_ = ↓NSNotification.Name("com.apple.Music.playerInfo")"#),
Example(#"""
let keyValuePair: (Int) -> (NSString, NSString) = {
let n = "\($0)" as NSString; return (n, n)
}
dictionary = [NSString: NSString](uniqueKeysWithValues:
(1...10_000).lazy.map(keyValuePair))
"""#),
Example("""
extension Foundation.Notification.Name {
static var reachabilityChanged: Foundation.NSNotification.Name {
return Foundation.Notification.Name("org.wordpress.reachability.changed")
}
}
""")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension LegacyObjcTypeRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: SimpleTypeIdentifierSyntax) {
if let typeName = node.typeName, legacyObjcTypes.contains(typeName) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: IdentifierExprSyntax) {
if legacyObjcTypes.contains(node.identifier.text) {
violations.append(node.identifier.positionAfterSkippingLeadingTrivia)
}
}
override func visitPost(_ node: MemberTypeIdentifierSyntax) {
guard node.baseType.as(SimpleTypeIdentifierSyntax.self)?.typeName == "Foundation",
legacyObjcTypes.contains(node.name.text)
else {
return
}
violations.append(node.name.positionAfterSkippingLeadingTrivia)
}
}
}

View File

@ -0,0 +1,43 @@
import SwiftSyntax
struct LegacyRandomRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static var description = RuleDescription(
identifier: "legacy_random",
name: "Legacy Random",
description: "Prefer using `type.random(in:)` over legacy functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("Int.random(in: 0..<10)\n"),
Example("Double.random(in: 8.6...111.34)\n"),
Example("Float.random(in: 0 ..< 1)\n")
],
triggeringExamples: [
Example("↓arc4random()\n"),
Example("↓arc4random_uniform(83)\n"),
Example("↓drand48()\n")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension LegacyRandomRule {
final class Visitor: ViolationsSyntaxVisitor {
private static let legacyRandomFunctions: Set<String> = [
"arc4random",
"arc4random_uniform",
"drand48"
]
override func visitPost(_ node: FunctionCallExprSyntax) {
if let function = node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.text,
Self.legacyRandomFunctions.contains(function) {
violations.append(node.positionAfterSkippingLeadingTrivia)
}
}
}
}

View File

@ -1,15 +1,13 @@
import Foundation
import SourceKittenFramework
public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, CorrectableRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, CorrectableRule {
var configuration = SeverityConfiguration<Self>(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "nimble_operator",
name: "Nimble Operator",
description: "Prefer Nimble operator overloads over free matcher functions.",
description: "Prefer Nimble operator overloads over free matcher functions",
kind: .idiomatic,
nonTriggeringExamples: [
Example("expect(seagull.squawk) != \"Hi!\"\n"),
@ -21,6 +19,8 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
Example("expect(x) === x"),
Example("expect(10) == 10"),
Example("expect(success) == true"),
Example("expect(value) == nil"),
Example("expect(value) != nil"),
Example("expect(object.asyncFunction()).toEventually(equal(1))\n"),
Example("expect(actual).to(haveCount(expected))\n"),
Example("""
@ -42,6 +42,8 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
Example("↓expect(x).to(beIdenticalTo(x))\n"),
Example("↓expect(success).to(beTrue())\n"),
Example("↓expect(success).to(beFalse())\n"),
Example("↓expect(value).to(beNil())\n"),
Example("↓expect(value).toNot(beNil())\n"),
Example("expect(10) > 2\n ↓expect(10).to(beGreaterThan(2))\n")
],
corrections: [
@ -60,6 +62,8 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
Example("↓expect(success).to(beFalse())\n"): Example("expect(success) == false\n"),
Example("↓expect(success).toNot(beFalse())\n"): Example("expect(success) != false\n"),
Example("↓expect(success).toNot(beTrue())\n"): Example("expect(success) != true\n"),
Example("↓expect(value).to(beNil())\n"): Example("expect(value) == nil\n"),
Example("↓expect(value).toNot(beNil())\n"): Example("expect(value) != nil\n"),
Example("expect(10) > 2\n ↓expect(10).to(beGreaterThan(2))\n"): Example("expect(10) > 2\n expect(10) > 2\n")
]
)
@ -88,19 +92,34 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
"beLessThan": (to: "<", toNot: nil, .withArguments),
"beLessThanOrEqualTo": (to: "<=", toNot: nil, .withArguments),
"beTrue": (to: "==", toNot: "!=", .nullary(analogueValue: "true")),
"beFalse": (to: "==", toNot: "!=", .nullary(analogueValue: "false"))
"beFalse": (to: "==", toNot: "!=", .nullary(analogueValue: "false")),
"beNil": (to: "==", toNot: "!=", .nullary(analogueValue: "nil"))
]
public func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) -> [StyleViolation] {
let matches = violationMatchesRanges(in: file)
return matches.map {
StyleViolation(ruleDescription: type(of: self).description,
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, characterOffset: $0.location))
}
}
private func violationMatchesRanges(in file: SwiftLintFile) -> [NSRange] {
let contents = file.stringView
return rawRegexResults(in: file).filter { range in
guard let byteRange = contents.NSRangeToByteRange(start: range.location, length: range.length) else {
return false
}
return file.structureDictionary.structures(forByteOffset: byteRange.upperBound - 1)
.contains(where: { dict -> Bool in
return dict.expressionKind == .call && (dict.name ?? "").starts(with: "expect")
})
}
}
private func rawRegexResults(in file: SwiftLintFile) -> [NSRange] {
let operandPattern = "(.(?!expect\\())+?"
let operatorsPattern = "(" + predicatesMapping.map { name, predicateDescription in
@ -112,34 +131,21 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
}.joined(separator: "|") + ")"
let pattern = "expect\\(\(operandPattern)\\)\\.to(Not)?\\(\(operatorsPattern)\\)"
let excludingKinds = SyntaxKind.commentKinds
return file.match(pattern: pattern)
.filter { _, kinds in
excludingKinds.isDisjoint(with: kinds) && kinds.first == .identifier
}.map { $0.0 }
.filter { range in
let contents = file.stringView
guard let byteRange = contents.NSRangeToByteRange(start: range.location, length: range.length) else {
return false
}
.map { $0.0 }
}
let containsCall = file.structureDictionary.structures(forByteOffset: byteRange.upperBound - 1)
.contains(where: { dict -> Bool in
return dict.expressionKind == .call && (dict.name ?? "").starts(with: "expect")
})
return containsCall
}
}
public func correct(file: SwiftLintFile) -> [Correction] {
func correct(file: SwiftLintFile) -> [Correction] {
let matches = violationMatchesRanges(in: file)
.filter { !file.ruleEnabled(violatingRanges: [$0], for: self).isEmpty }
guard !matches.isEmpty else { return [] }
.filter { file.ruleEnabled(violatingRanges: [$0], for: self).isNotEmpty }
guard matches.isNotEmpty else { return [] }
let description = type(of: self).description
let description = Self.description
var corrections: [Correction] = []
var contents = file.contents
@ -183,7 +189,7 @@ private extension String {
for case let (pattern, operatorString?) in [toPattern, toNotPattern] {
let expression = regex(pattern)
guard !expression.matches(in: self, options: [], range: range).isEmpty else {
guard expression.matches(in: self, options: [], range: range).isNotEmpty else {
continue
}

View File

@ -0,0 +1,39 @@
import SwiftSyntax
struct NoExtensionAccessModifierRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.error)
static let description = RuleDescription(
identifier: "no_extension_access_modifier",
name: "No Extension Access Modifier",
description: "Prefer not to use extension access modifiers",
kind: .idiomatic,
nonTriggeringExamples: [
Example("extension String {}"),
Example("\n\n extension String {}")
],
triggeringExamples: [
Example("↓private extension String {}"),
Example("↓public \n extension String {}"),
Example("↓open extension String {}"),
Example("↓internal extension String {}"),
Example("↓fileprivate extension String {}")
]
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension NoExtensionAccessModifierRule {
final class Visitor: ViolationsSyntaxVisitor {
override var skippableDeclarations: [DeclSyntaxProtocol.Type] { .all }
override func visitPost(_ node: ExtensionDeclSyntax) {
if let modifiers = node.modifiers, modifiers.isNotEmpty {
violations.append(modifiers.positionAfterSkippingLeadingTrivia)
}
}
}
}

View File

@ -0,0 +1,42 @@
import SwiftSyntax
struct NoFallthroughOnlyRule: SwiftSyntaxRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
static let description = RuleDescription(
identifier: "no_fallthrough_only",
name: "No Fallthrough only",
description: "Fallthroughs can only be used if the `case` contains at least one other statement",
kind: .idiomatic,
nonTriggeringExamples: NoFallthroughOnlyRuleExamples.nonTriggeringExamples,
triggeringExamples: NoFallthroughOnlyRuleExamples.triggeringExamples
)
func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor {
Visitor(viewMode: .sourceAccurate)
}
}
private extension NoFallthroughOnlyRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: SwitchCaseListSyntax) {
let cases = node.compactMap { $0.as(SwitchCaseSyntax.self) }
let localViolations = cases.enumerated()
.compactMap { index, element -> AbsolutePosition? in
if let fallthroughStmt = element.statements.onlyElement?.item.as(FallthroughStmtSyntax.self) {
if case let nextCaseIndex = cases.index(after: index),
nextCaseIndex < cases.endIndex,
case let nextCase = cases[nextCaseIndex],
nextCase.unknownAttr != nil {
return nil
}
return fallthroughStmt.positionAfterSkippingLeadingTrivia
}
return nil
}
violations.append(contentsOf: localViolations)
}
}
}

View File

@ -1,6 +1,5 @@
internal struct NoFallthroughOnlyRuleExamples {
static let nonTriggeringExamples: [Example] = {
let commonExamples = [
static let nonTriggeringExamples: [Example] = [
Example("""
switch myvar {
case 1:
@ -69,14 +68,7 @@ internal struct NoFallthroughOnlyRuleExamples {
case "abc":
let two = 2
}
""")
]
guard SwiftVersion.current >= .five else {
return commonExamples
}
return commonExamples + [
"""),
Example("""
switch enumInstance {
case .caseA:
@ -88,7 +80,6 @@ internal struct NoFallthroughOnlyRuleExamples {
}
""")
]
}()
static let triggeringExamples = [
Example("""

View File

@ -1,14 +1,12 @@
import SourceKittenFramework
public struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule {
var configuration = SeverityConfiguration<Self>(.warning)
public init() {}
public static let description = RuleDescription(
static let description = RuleDescription(
identifier: "no_grouping_extension",
name: "No Grouping Extension",
description: "Extensions shouldn't be used to group code within the same source file.",
description: "Extensions shouldn't be used to group code within the same source file",
kind: .idiomatic,
nonTriggeringExamples: [
Example("protocol Food {}\nextension Food {}\n"),
@ -23,7 +21,7 @@ public struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule, Aut
]
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
func validate(file: SwiftLintFile) -> [StyleViolation] {
let collector = NamespaceCollector(dictionary: file.structureDictionary)
let elements = collector.findAllElements(of: [.class, .enum, .struct, .extension])
@ -38,7 +36,7 @@ public struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule, Aut
return nil
}
return StyleViolation(ruleDescription: type(of: self).description,
return StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: element.offset))
}
@ -56,6 +54,6 @@ public struct NoGroupingExtensionRule: OptInRule, ConfigurationProviderRule, Aut
return false
}
return !file.match(pattern: "\\bwhere\\b", with: [.keyword], range: range).isEmpty
return file.match(pattern: "\\bwhere\\b", with: [.keyword], range: range).isNotEmpty
}
}

View File

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

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