Skip to content

Commit 076fade

Browse files
committed
Fix false positives on explicit_acl and explicit_top_level_acl
Fixes #2705
1 parent a97487f commit 076fade

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@
7272
[Keith Smiley](https://github.com/keith)
7373
[#2703](https://github.com/realm/SwiftLint/issues/2703)
7474

75+
* Fix false positives on `explicit_acl` and `explicit_top_level_acl` rules when
76+
declaring extensions that add protocol conformances with Swift 5.
77+
[Marcelo Fabri](https://github.com/marcelofabri)
78+
[#2705](https://github.com/realm/SwiftLint/issues/2705)
79+
7580
## 0.31.0: Busy Laundromat
7681

7782
#### Breaking

Rules.md

+8
Original file line numberDiff line numberDiff line change
@@ -5763,6 +5763,10 @@ func b() {}
57635763

57645764
```
57655765

5766+
```swift
5767+
extension A: Equatable {}
5768+
```
5769+
57665770
</details>
57675771

57685772

@@ -6064,6 +6068,10 @@ func b() {}
60646068

60656069
```
60666070

6071+
```swift
6072+
extension A: Equatable {}
6073+
```
6074+
60676075
</details>
60686076

60696077

Source/SwiftLintFramework/Rules/Idiomatic/ExplicitACLRule.swift

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
4747
"internal struct C { let d = 5 }\n",
4848
"public struct C { let d = 5 }\n",
4949
"func a() {}\n",
50-
"internal let a = 0\nfunc b() {}\n"
50+
"internal let a = 0\nfunc b() {}\n",
51+
"extension A: Equatable {}"
5152
]
5253
)
5354

@@ -60,11 +61,20 @@ public struct ExplicitACLRule: OptInRule, ConfigurationProviderRule, AutomaticTe
6061

6162
private func offsetOfElements(from elements: [SourceKittenElement], in file: File,
6263
thatAreNotInRanges ranges: [NSRange]) -> [Int] {
64+
let extensionKinds: Set<SwiftDeclarationKind> = [.extension, .extensionClass, .extensionEnum,
65+
.extensionProtocol, .extensionStruct]
66+
6367
return elements.compactMap { element in
6468
guard let typeOffset = element.offset else {
6569
return nil
6670
}
6771

72+
guard let kind = element.kind.flatMap(SwiftDeclarationKind.init(rawValue:)),
73+
case let isConformanceExtension = extensionKinds.contains(kind) && !element.inheritedTypes.isEmpty,
74+
!isConformanceExtension else {
75+
return nil
76+
}
77+
6878
// find the last "internal" token before the type
6979
guard let previousInternalByteRange = lastInternalByteRange(before: typeOffset, in: ranges) else {
7080
return typeOffset

Source/SwiftLintFramework/Rules/Idiomatic/ExplicitTopLevelACLRule.swift

+12-1
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,24 @@ public struct ExplicitTopLevelACLRule: OptInRule, ConfigurationProviderRule, Aut
2525
"final class B {}\n",
2626
"struct C {}\n",
2727
"func a() {}\n",
28-
"internal let a = 0\nfunc b() {}\n"
28+
"internal let a = 0\nfunc b() {}\n",
29+
"extension A: Equatable {}"
2930
]
3031
)
3132

3233
public func validate(file: File) -> [StyleViolation] {
34+
let extensionKinds: Set<SwiftDeclarationKind> = [.extension, .extensionClass, .extensionEnum,
35+
.extensionProtocol, .extensionStruct]
36+
3337
// find all top-level types marked as internal (either explictly or implictly)
3438
let internalTypesOffsets = file.structure.dictionary.substructure.compactMap { element -> Int? in
39+
// ignore extensions that declare protocol conformance
40+
guard let kind = element.kind.flatMap(SwiftDeclarationKind.init(rawValue:)),
41+
case let isConformanceExtension = extensionKinds.contains(kind) && !element.inheritedTypes.isEmpty,
42+
!isConformanceExtension else {
43+
return nil
44+
}
45+
3546
if element.accessibility.flatMap(AccessControlLevel.init(identifier:)) == .internal {
3647
return element.offset
3748
}

0 commit comments

Comments
 (0)