mirror of
https://github.com/nicklockwood/SwiftFormat.git
synced 2026-06-16 10:34:34 +00:00
92 lines
3.2 KiB
Swift
92 lines
3.2 KiB
Swift
//
|
|
// RedundantPublic.swift
|
|
// SwiftFormat
|
|
//
|
|
// Created by Cal Stephens on 5/30/2025.
|
|
// Copyright © 2025 Nick Lockwood. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
public extension FormatRule {
|
|
static let redundantPublic = FormatRule(
|
|
help: "Remove redundant public access control from declarations in internal or private types."
|
|
) { formatter in
|
|
let declarations = formatter.parseDeclarations()
|
|
|
|
// Find all internally declared types in the file
|
|
var internalTypes = Set<String>()
|
|
declarations.forEachRecursiveDeclaration { declaration in
|
|
if let typeDecl = declaration.asTypeDeclaration,
|
|
typeDecl.keyword != "extension" && typeDecl.keyword != "protocol",
|
|
let typeName = declaration.fullyQualifiedName,
|
|
declaration.visibility() == .internal || declaration.visibility() == nil
|
|
{
|
|
// Inside public extensions, types with no access control modifier are public.
|
|
// This case is handled by the extensionAccessControl rule.
|
|
let insidePublicExtension = declaration.parentDeclarations.contains(where: {
|
|
$0.keyword == "extension" && $0.visibility() == .public
|
|
})
|
|
|
|
if !insidePublicExtension {
|
|
internalTypes.insert(typeName)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process all declarations recursively
|
|
declarations.forEachRecursiveDeclaration { declaration in
|
|
guard declaration.visibility() == .public,
|
|
let parentType = declaration.parentType
|
|
else { return }
|
|
|
|
// Inside public extensions, types with no access control modifier are public.
|
|
// This case is handled by the extensionAccessControl rule.
|
|
let insidePublicExtension = declaration.parentDeclarations.contains(where: {
|
|
$0.keyword == "extension" && $0.visibility() == .public
|
|
})
|
|
|
|
if insidePublicExtension {
|
|
return
|
|
}
|
|
|
|
if declaration.hasModifier("@_spi") {
|
|
return
|
|
}
|
|
|
|
switch parentType.keyword {
|
|
case "extension":
|
|
// Inside an extension where the extended type is internal, any `public` modifier has no effect.
|
|
// We can only handle this case if the extension and type are defined in the same file.
|
|
if let extendedTypeName = parentType.name,
|
|
internalTypes.contains(extendedTypeName)
|
|
{
|
|
declaration.removeVisibility(.public)
|
|
}
|
|
|
|
// Inside an internal or private type, any `public` modifier has no effect
|
|
default:
|
|
if (parentType.visibility() ?? .internal) <= .internal {
|
|
declaration.removeVisibility(.public)
|
|
}
|
|
}
|
|
}
|
|
} examples: {
|
|
"""
|
|
```diff
|
|
struct Foo {
|
|
- public let bar: Bar
|
|
+ let bar: Bar
|
|
- public func baz() {}
|
|
+ func baz() {}
|
|
}
|
|
|
|
extension Foo {
|
|
- public func quux() {}
|
|
+ func quux() {}
|
|
}
|
|
```
|
|
"""
|
|
}
|
|
}
|