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
This commit is contained in:
JP Simard 2023-04-26 16:37:25 -04:00 committed by GitHub
parent a7e3909c6a
commit 3a2bb15ca3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 204 additions and 199 deletions

View File

@ -13,6 +13,8 @@ documentation: rule_docs/*.md
hide_unlisted_documentation: true hide_unlisted_documentation: true
custom_categories_unlisted_prefix: '' custom_categories_unlisted_prefix: ''
exclude: exclude:
# TODO: Document extensions
- Source/SwiftLintFramework/Extensions/*.swift
- Source/SwiftLintFramework/Rules/**/*.swift - Source/SwiftLintFramework/Rules/**/*.swift
custom_categories: custom_categories:
- name: Rules - name: Rules

View File

@ -1,6 +1,6 @@
import Dispatch import Dispatch
extension Array where Element: Equatable { public extension Array where Element: Equatable {
/// The elements in this array, discarding duplicates after the first one. /// The elements in this array, discarding duplicates after the first one.
/// Order-preserving. /// Order-preserving.
var unique: [Element] { var unique: [Element] {
@ -12,7 +12,7 @@ extension Array where Element: Equatable {
} }
} }
extension Array where Element: Hashable { public extension Array where Element: Hashable {
/// Produces an array containing the passed `obj` value. /// Produces an array containing the passed `obj` value.
/// If `obj` is an array already, return it. /// If `obj` is an array already, return it.
/// If `obj` is a set, copy its elements to a new array. /// If `obj` is a set, copy its elements to a new array.
@ -33,7 +33,7 @@ extension Array where Element: Hashable {
} }
} }
extension Array { public extension Array {
/// Produces an array containing the passed `obj` value. /// Produces an array containing the passed `obj` value.
/// If `obj` is an array already, return it. /// If `obj` is an array already, return it.
/// If `obj` is a value of type `Element`, return a single-item array containing it. /// If `obj` is a value of type `Element`, return a single-item array containing it.
@ -67,8 +67,7 @@ extension Array {
/// ///
/// - returns: The elements failing the `belongsInSecondPartition` test, followed by the elements passing the /// - returns: The elements failing the `belongsInSecondPartition` test, followed by the elements passing the
/// `belongsInSecondPartition` test. /// `belongsInSecondPartition` test.
@_spi(TestHelper) func partitioned(by belongsInSecondPartition: (Element) throws -> Bool) rethrows ->
public func partitioned(by belongsInSecondPartition: (Element) throws -> Bool) rethrows ->
(first: ArraySlice<Element>, second: ArraySlice<Element>) { (first: ArraySlice<Element>, second: ArraySlice<Element>) {
var copy = self var copy = self
let pivot = try copy.partition(by: belongsInSecondPartition) let pivot = try copy.partition(by: belongsInSecondPartition)
@ -80,8 +79,7 @@ extension Array {
/// - parameter transform: The transformation to apply to each element. /// - parameter transform: The transformation to apply to each element.
/// ///
/// - returns: The result of applying `transform` on every element and flattening the results. /// - returns: The result of applying `transform` on every element and flattening the results.
@_spi(TestHelper) func parallelFlatMap<T>(transform: (Element) -> [T]) -> [T] {
public func parallelFlatMap<T>(transform: (Element) -> [T]) -> [T] {
return parallelMap(transform: transform).flatMap { $0 } return parallelMap(transform: transform).flatMap { $0 }
} }
@ -110,10 +108,9 @@ extension Array {
} }
} }
extension Collection { public extension Collection {
/// Whether this collection has one or more element. /// Whether this collection has one or more element.
@_spi(TestHelper) var isNotEmpty: Bool {
public var isNotEmpty: Bool {
return !isEmpty return !isEmpty
} }

View File

@ -1,7 +1,7 @@
import SourceKittenFramework import SourceKittenFramework
import SwiftSyntax import SwiftSyntax
extension ByteCount { public extension ByteCount {
/// Converts a SwiftSyntax `AbsolutePosition` to a SourceKitten `ByteCount`. /// Converts a SwiftSyntax `AbsolutePosition` to a SourceKitten `ByteCount`.
/// ///
/// - parameter position: The SwiftSyntax position to convert. /// - parameter position: The SwiftSyntax position to convert.

View File

@ -21,7 +21,7 @@ public struct SourceKittenDictionary {
/// Creates a SourceKitten dictionary given a `Dictionary<String, SourceKitRepresentable>` input. /// Creates a SourceKitten dictionary given a `Dictionary<String, SourceKitRepresentable>` input.
/// ///
/// - parameter value: The input dictionary/ /// - parameter value: The input dictionary/
init(_ value: [String: SourceKitRepresentable]) { public init(_ value: [String: SourceKitRepresentable]) {
self.value = value self.value = value
let substructure = value["key.substructure"] as? [SourceKitRepresentable] ?? [] let substructure = value["key.substructure"] as? [SourceKitRepresentable] ?? []
@ -37,123 +37,123 @@ public struct SourceKittenDictionary {
} }
/// Body length /// Body length
var bodyLength: ByteCount? { public var bodyLength: ByteCount? {
return (value["key.bodylength"] as? Int64).map(ByteCount.init) return (value["key.bodylength"] as? Int64).map(ByteCount.init)
} }
/// Body offset. /// Body offset.
var bodyOffset: ByteCount? { public var bodyOffset: ByteCount? {
return (value["key.bodyoffset"] as? Int64).map(ByteCount.init) return (value["key.bodyoffset"] as? Int64).map(ByteCount.init)
} }
/// Body byte range. /// Body byte range.
var bodyByteRange: ByteRange? { public var bodyByteRange: ByteRange? {
guard let offset = bodyOffset, let length = bodyLength else { return nil } guard let offset = bodyOffset, let length = bodyLength else { return nil }
return ByteRange(location: offset, length: length) return ByteRange(location: offset, length: length)
} }
/// Kind. /// Kind.
var kind: String? { public var kind: String? {
return value["key.kind"] as? String return value["key.kind"] as? String
} }
/// Length. /// Length.
var length: ByteCount? { public var length: ByteCount? {
return (value["key.length"] as? Int64).map(ByteCount.init) return (value["key.length"] as? Int64).map(ByteCount.init)
} }
/// Name. /// Name.
var name: String? { public var name: String? {
return value["key.name"] as? String return value["key.name"] as? String
} }
/// Name length. /// Name length.
var nameLength: ByteCount? { public var nameLength: ByteCount? {
return (value["key.namelength"] as? Int64).map(ByteCount.init) return (value["key.namelength"] as? Int64).map(ByteCount.init)
} }
/// Name offset. /// Name offset.
var nameOffset: ByteCount? { public var nameOffset: ByteCount? {
return (value["key.nameoffset"] as? Int64).map(ByteCount.init) return (value["key.nameoffset"] as? Int64).map(ByteCount.init)
} }
/// Byte range of name. /// Byte range of name.
var nameByteRange: ByteRange? { public var nameByteRange: ByteRange? {
guard let offset = nameOffset, let length = nameLength else { return nil } guard let offset = nameOffset, let length = nameLength else { return nil }
return ByteRange(location: offset, length: length) return ByteRange(location: offset, length: length)
} }
/// Offset. /// Offset.
var offset: ByteCount? { public var offset: ByteCount? {
return (value["key.offset"] as? Int64).map(ByteCount.init) return (value["key.offset"] as? Int64).map(ByteCount.init)
} }
/// Returns byte range starting from `offset` with `length` bytes /// Returns byte range starting from `offset` with `length` bytes
var byteRange: ByteRange? { public var byteRange: ByteRange? {
guard let offset, let length else { return nil } guard let offset, let length else { return nil }
return ByteRange(location: offset, length: length) return ByteRange(location: offset, length: length)
} }
/// Setter accessibility. /// Setter accessibility.
var setterAccessibility: String? { public var setterAccessibility: String? {
return value["key.setter_accessibility"] as? String return value["key.setter_accessibility"] as? String
} }
/// Type name. /// Type name.
var typeName: String? { public var typeName: String? {
return value["key.typename"] as? String return value["key.typename"] as? String
} }
/// Documentation length. /// Documentation length.
var docLength: ByteCount? { public var docLength: ByteCount? {
return (value["key.doclength"] as? Int64).flatMap(ByteCount.init) return (value["key.doclength"] as? Int64).flatMap(ByteCount.init)
} }
/// The attribute for this dictionary, as returned by SourceKit. /// The attribute for this dictionary, as returned by SourceKit.
var attribute: String? { public var attribute: String? {
return value["key.attribute"] as? String return value["key.attribute"] as? String
} }
/// Module name in `@import` expressions. /// Module name in `@import` expressions.
var moduleName: String? { public var moduleName: String? {
return value["key.modulename"] as? String return value["key.modulename"] as? String
} }
/// The line number for this declaration. /// The line number for this declaration.
var line: Int64? { public var line: Int64? {
return value["key.line"] as? Int64 return value["key.line"] as? Int64
} }
/// The column number for this declaration. /// The column number for this declaration.
var column: Int64? { public var column: Int64? {
return value["key.column"] as? Int64 return value["key.column"] as? Int64
} }
/// The `SwiftDeclarationAttributeKind` values associated with this dictionary. /// The `SwiftDeclarationAttributeKind` values associated with this dictionary.
var enclosedSwiftAttributes: [SwiftDeclarationAttributeKind] { public var enclosedSwiftAttributes: [SwiftDeclarationAttributeKind] {
return swiftAttributes.compactMap { $0.attribute } return swiftAttributes.compactMap { $0.attribute }
.compactMap(SwiftDeclarationAttributeKind.init(rawValue:)) .compactMap(SwiftDeclarationAttributeKind.init(rawValue:))
} }
/// The fully preserved SourceKitten dictionaries for all the attributes associated with this dictionary. /// The fully preserved SourceKitten dictionaries for all the attributes associated with this dictionary.
var swiftAttributes: [SourceKittenDictionary] { public var swiftAttributes: [SourceKittenDictionary] {
let array = value["key.attributes"] as? [SourceKitRepresentable] ?? [] let array = value["key.attributes"] as? [SourceKitRepresentable] ?? []
return array.compactMap { $0 as? [String: SourceKitRepresentable] } return array.compactMap { $0 as? [String: SourceKitRepresentable] }
.map(Self.init) .map(Self.init)
} }
var elements: [SourceKittenDictionary] { public var elements: [SourceKittenDictionary] {
let elements = value["key.elements"] as? [SourceKitRepresentable] ?? [] let elements = value["key.elements"] as? [SourceKitRepresentable] ?? []
return elements.compactMap { $0 as? [String: SourceKitRepresentable] } return elements.compactMap { $0 as? [String: SourceKitRepresentable] }
.map(Self.init) .map(Self.init)
} }
var entities: [SourceKittenDictionary] { public var entities: [SourceKittenDictionary] {
let entities = value["key.entities"] as? [SourceKitRepresentable] ?? [] let entities = value["key.entities"] as? [SourceKitRepresentable] ?? []
return entities.compactMap { $0 as? [String: SourceKitRepresentable] } return entities.compactMap { $0 as? [String: SourceKitRepresentable] }
.map(Self.init) .map(Self.init)
} }
var enclosedVarParameters: [SourceKittenDictionary] { public var enclosedVarParameters: [SourceKittenDictionary] {
return substructure.flatMap { subDict -> [SourceKittenDictionary] in return substructure.flatMap { subDict -> [SourceKittenDictionary] in
if subDict.declarationKind == .varParameter { if subDict.declarationKind == .varParameter {
return [subDict] return [subDict]
@ -166,7 +166,7 @@ public struct SourceKittenDictionary {
} }
} }
var enclosedArguments: [SourceKittenDictionary] { public var enclosedArguments: [SourceKittenDictionary] {
return substructure.flatMap { subDict -> [SourceKittenDictionary] in return substructure.flatMap { subDict -> [SourceKittenDictionary] in
guard subDict.expressionKind == .argument else { guard subDict.expressionKind == .argument else {
return [] return []
@ -176,7 +176,7 @@ public struct SourceKittenDictionary {
} }
} }
var inheritedTypes: [String] { public var inheritedTypes: [String] {
let array = value["key.inheritedtypes"] as? [SourceKitRepresentable] ?? [] let array = value["key.inheritedtypes"] as? [SourceKitRepresentable] ?? []
return array.compactMap { ($0 as? [String: String]).flatMap { $0["key.name"] } } return array.compactMap { ($0 as? [String: String]).flatMap { $0["key.name"] } }
} }
@ -189,7 +189,7 @@ extension SourceKittenDictionary {
/// - parameter traverseBlock: block that will be called for each substructure in the dictionary. /// - parameter traverseBlock: block that will be called for each substructure in the dictionary.
/// ///
/// - returns: The list of substructure dictionaries with updated values from the traverse block. /// - returns: The list of substructure dictionaries with updated values from the traverse block.
func traverseDepthFirst<T>(traverseBlock: (SourceKittenDictionary) -> [T]?) -> [T] { public func traverseDepthFirst<T>(traverseBlock: (SourceKittenDictionary) -> [T]?) -> [T] {
var result: [T] = [] var result: [T] = []
traverseDepthFirst(collectingValuesInto: &result, traverseBlock: traverseBlock) traverseDepthFirst(collectingValuesInto: &result, traverseBlock: traverseBlock)
return result return result
@ -212,7 +212,7 @@ extension SourceKittenDictionary {
/// - parameter traverseBlock: block that will be called for each entity in the dictionary. /// - parameter traverseBlock: block that will be called for each entity in the dictionary.
/// ///
/// - returns: The list of entity dictionaries with updated values from the traverse block. /// - returns: The list of entity dictionaries with updated values from the traverse block.
func traverseEntitiesDepthFirst<T>(traverseBlock: (SourceKittenDictionary) -> T?) -> [T] { public func traverseEntitiesDepthFirst<T>(traverseBlock: (SourceKittenDictionary) -> T?) -> [T] {
var result: [T] = [] var result: [T] = []
traverseEntitiesDepthFirst(collectingValuesInto: &result, traverseBlock: traverseBlock) traverseEntitiesDepthFirst(collectingValuesInto: &result, traverseBlock: traverseBlock)
return result return result
@ -230,7 +230,7 @@ extension SourceKittenDictionary {
} }
} }
extension Dictionary where Key == Example { public extension Dictionary where Key == Example {
/// Returns a dictionary with SwiftLint violation markers () removed from keys. /// Returns a dictionary with SwiftLint violation markers () removed from keys.
/// ///
/// - returns: A new `Dictionary`. /// - returns: A new `Dictionary`.

View File

@ -14,8 +14,8 @@ private struct RegexCacheKey: Hashable {
} }
} }
extension NSRegularExpression { public extension NSRegularExpression {
internal static func cached(pattern: String, options: Options? = nil) throws -> NSRegularExpression { static func cached(pattern: String, options: Options? = nil) throws -> NSRegularExpression {
let options = options ?? [.anchorsMatchLines, .dotMatchesLineSeparators] let options = options ?? [.anchorsMatchLines, .dotMatchesLineSeparators]
let key = RegexCacheKey(pattern: pattern, options: options) let key = RegexCacheKey(pattern: pattern, options: options)
regexCacheLock.lock() regexCacheLock.lock()
@ -29,19 +29,19 @@ extension NSRegularExpression {
return result return result
} }
internal func matches(in stringView: StringView, func matches(in stringView: StringView,
options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] { options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] {
return matches(in: stringView.string, options: options, range: stringView.range) return matches(in: stringView.string, options: options, range: stringView.range)
} }
internal func matches(in stringView: StringView, func matches(in stringView: StringView,
options: NSRegularExpression.MatchingOptions = [], options: NSRegularExpression.MatchingOptions = [],
range: NSRange) -> [NSTextCheckingResult] { range: NSRange) -> [NSTextCheckingResult] {
return matches(in: stringView.string, options: options, range: range) return matches(in: stringView.string, options: options, range: range)
} }
internal func matches(in file: SwiftLintFile, func matches(in file: SwiftLintFile,
options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] { options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] {
return matches(in: file.stringView.string, options: options, range: file.stringView.range) return matches(in: file.stringView.string, options: options, range: file.stringView.range)
} }
} }

View File

@ -1,4 +1,4 @@
extension RandomAccessCollection where Index == Int { public extension RandomAccessCollection where Index == Int {
/// Returns the first index in which an element of the collection satisfies the given predicate. /// Returns the first index in which an element of the collection satisfies the given predicate.
/// The collection assumed to be sorted. If collection is not have sorted values the result is undefined. /// The collection assumed to be sorted. If collection is not have sorted values the result is undefined.
/// ///

View File

@ -1,7 +1,7 @@
import Foundation import Foundation
import SourceKittenFramework import SourceKittenFramework
extension Request { public extension Request {
static let disableSourceKit = ProcessInfo.processInfo.environment["SWIFTLINT_DISABLE_SOURCEKIT"] != nil static let disableSourceKit = ProcessInfo.processInfo.environment["SWIFTLINT_DISABLE_SOURCEKIT"] != nil
func sendIfNotDisabled() throws -> [String: SourceKitRepresentable] { func sendIfNotDisabled() throws -> [String: SourceKitRepresentable] {

View File

@ -1,13 +1,13 @@
import SourceKittenFramework import SourceKittenFramework
extension SourceKittenDictionary { public extension SourceKittenDictionary {
/// Returns array of tuples containing "key.kind" and "byteRange" from Structure /// Returns array of tuples containing "key.kind" and "byteRange" from Structure
/// that contains the byte offset. Returns all kinds if no parameter specified. /// that contains the byte offset. Returns all kinds if no parameter specified.
/// ///
/// - parameter byteOffset: Int? /// - parameter byteOffset: Int?
/// ///
/// - returns: The kinds and byte ranges. /// - returns: The kinds and byte ranges.
internal func kinds(forByteOffset byteOffset: ByteCount? = nil) func kinds(forByteOffset byteOffset: ByteCount? = nil)
-> [(kind: String, byteRange: ByteRange)] { -> [(kind: String, byteRange: ByteRange)] {
var results = [(kind: String, byteRange: ByteRange)]() var results = [(kind: String, byteRange: ByteRange)]()
@ -27,7 +27,7 @@ extension SourceKittenDictionary {
return results return results
} }
internal func structures(forByteOffset byteOffset: ByteCount) -> [SourceKittenDictionary] { func structures(forByteOffset byteOffset: ByteCount) -> [SourceKittenDictionary] {
var results = [SourceKittenDictionary]() var results = [SourceKittenDictionary]()
func parse(_ dictionary: SourceKittenDictionary) { func parse(_ dictionary: SourceKittenDictionary) {

View File

@ -1,6 +1,6 @@
import SwiftSyntax import SwiftSyntax
extension SourceRange { public extension SourceRange {
/// Check if a position is contained within this range. /// Check if a position is contained within this range.
/// ///
/// - parameter position: The position to check. /// - parameter position: The position to check.

View File

@ -1,8 +1,8 @@
import Foundation import Foundation
import SourceKittenFramework import SourceKittenFramework
extension String { public extension String {
internal func hasTrailingWhitespace() -> Bool { func hasTrailingWhitespace() -> Bool {
if isEmpty { if isEmpty {
return false return false
} }
@ -14,22 +14,14 @@ extension String {
return false return false
} }
internal func isUppercase() -> Bool { func isUppercase() -> Bool {
return self == uppercased() return self == uppercased()
} }
internal func isLowercase() -> Bool { func isLowercase() -> Bool {
return self == lowercased() return self == lowercased()
} }
internal func nameStrippingLeadingUnderscoreIfPrivate(_ dict: SourceKittenDictionary) -> String {
if let acl = dict.accessibility,
acl.isPrivate && first == "_" {
return String(self[index(after: startIndex)...])
}
return self
}
private subscript (range: Range<Int>) -> String { private subscript (range: Range<Int>) -> String {
let nsrange = NSRange(location: range.lowerBound, let nsrange = NSRange(location: range.lowerBound,
length: range.upperBound - range.lowerBound) length: range.upperBound - range.lowerBound)
@ -39,21 +31,21 @@ extension String {
queuedFatalError("invalid range") queuedFatalError("invalid range")
} }
internal func substring(from: Int, length: Int? = nil) -> String { func substring(from: Int, length: Int? = nil) -> String {
if let length { if let length {
return self[from..<from + length] return self[from..<from + length]
} }
return String(self[index(startIndex, offsetBy: from, limitedBy: endIndex)!...]) return String(self[index(startIndex, offsetBy: from, limitedBy: endIndex)!...])
} }
internal func lastIndex(of search: String) -> Int? { func lastIndex(of search: String) -> Int? {
if let range = range(of: search, options: [.literal, .backwards]) { if let range = range(of: search, options: [.literal, .backwards]) {
return distance(from: startIndex, to: range.lowerBound) return distance(from: startIndex, to: range.lowerBound)
} }
return nil return nil
} }
internal func nsrangeToIndexRange(_ nsrange: NSRange) -> Range<Index>? { func nsrangeToIndexRange(_ nsrange: NSRange) -> Range<Index>? {
guard nsrange.location != NSNotFound else { guard nsrange.location != NSNotFound else {
return nil return nil
} }
@ -70,18 +62,18 @@ extension String {
return fromIndex..<toIndex return fromIndex..<toIndex
} }
internal var fullNSRange: NSRange { var fullNSRange: NSRange {
return NSRange(location: 0, length: utf16.count) return NSRange(location: 0, length: utf16.count)
} }
/// Returns a new string, converting the path to a canonical absolute path. /// Returns a new string, converting the path to a canonical absolute path.
/// ///
/// - returns: A new `String`. /// - returns: A new `String`.
public func absolutePathStandardized() -> String { func absolutePathStandardized() -> String {
return bridge().absolutePathRepresentation().bridge().standardizingPath return bridge().absolutePathRepresentation().bridge().standardizingPath
} }
internal var isFile: Bool { var isFile: Bool {
if self.isEmpty { if self.isEmpty {
return false return false
} }
@ -95,14 +87,14 @@ extension String {
/// Count the number of occurrences of the given character in `self` /// Count the number of occurrences of the given character in `self`
/// - Parameter character: Character to count /// - Parameter character: Character to count
/// - Returns: Number of times `character` occurs in `self` /// - Returns: Number of times `character` occurs in `self`
public func countOccurrences(of character: Character) -> Int { func countOccurrences(of character: Character) -> Int {
return self.reduce(0, { return self.reduce(0, {
$1 == character ? $0 + 1 : $0 $1 == character ? $0 + 1 : $0
}) })
} }
/// If self is a path, this method can be used to get a path expression relative to a root directory /// If self is a path, this method can be used to get a path expression relative to a root directory
public func path(relativeTo rootDirectory: String) -> String { func path(relativeTo rootDirectory: String) -> String {
let normalizedRootDir = rootDirectory.bridge().standardizingPath let normalizedRootDir = rootDirectory.bridge().standardizingPath
let normalizedSelf = bridge().standardizingPath let normalizedSelf = bridge().standardizingPath
if normalizedRootDir.isEmpty { if normalizedRootDir.isEmpty {
@ -123,7 +115,7 @@ extension String {
} }
} }
internal func deletingPrefix(_ prefix: String) -> String { func deletingPrefix(_ prefix: String) -> String {
guard hasPrefix(prefix) else { return self } guard hasPrefix(prefix) else { return self }
return String(dropFirst(prefix.count)) return String(dropFirst(prefix.count))
} }

View File

@ -1,6 +1,6 @@
import SourceKittenFramework import SourceKittenFramework
extension StringView { public extension StringView {
/// Converts a line and column position in a code snippet to a byte offset. /// Converts a line and column position in a code snippet to a byte offset.
/// - Parameters: /// - Parameters:
/// - line: Line in code snippet /// - line: Line in code snippet

View File

@ -2,7 +2,7 @@ import Foundation
import SourceKittenFramework import SourceKittenFramework
import SwiftSyntax import SwiftSyntax
extension StringView { public extension StringView {
/// Converts two absolute positions from SwiftSyntax to a valid `NSRange` if possible. /// Converts two absolute positions from SwiftSyntax to a valid `NSRange` if possible.
/// ///
/// - parameter start: Starting position. /// - parameter start: Starting position.

View File

@ -1,6 +1,6 @@
import SourceKittenFramework import SourceKittenFramework
extension SwiftDeclarationAttributeKind { public extension SwiftDeclarationAttributeKind {
static var attributesRequiringFoundation: Set<SwiftDeclarationAttributeKind> { static var attributesRequiringFoundation: Set<SwiftDeclarationAttributeKind> {
return [ return [
.objc, .objc,
@ -24,7 +24,7 @@ extension SwiftDeclarationAttributeKind {
case `dynamic` case `dynamic`
case atPrefixed case atPrefixed
init?(rawAttribute: String) { public init?(rawAttribute: String) {
let allModifierGroups: Set<SwiftDeclarationAttributeKind.ModifierGroup> = [ let allModifierGroups: Set<SwiftDeclarationAttributeKind.ModifierGroup> = [
.acl, .setterACL, .mutators, .override, .owned, .atPrefixed, .dynamic, .final, .typeMethods, .acl, .setterACL, .mutators, .override, .owned, .atPrefixed, .dynamic, .final, .typeMethods,
.required, .convenience, .lazy .required, .convenience, .lazy
@ -40,7 +40,7 @@ extension SwiftDeclarationAttributeKind {
} }
} }
var swiftDeclarationAttributeKinds: Set<SwiftDeclarationAttributeKind> { public var swiftDeclarationAttributeKinds: Set<SwiftDeclarationAttributeKind> {
switch self { switch self {
case .acl: case .acl:
return [ return [
@ -94,7 +94,7 @@ extension SwiftDeclarationAttributeKind {
} }
} }
var debugDescription: String { public var debugDescription: String {
return self.rawValue return self.rawValue
} }
} }

View File

@ -1,7 +1,7 @@
import SourceKittenFramework import SourceKittenFramework
extension SwiftDeclarationKind { public extension SwiftDeclarationKind {
internal static let variableKinds: Set<SwiftDeclarationKind> = [ static let variableKinds: Set<SwiftDeclarationKind> = [
.varClass, .varClass,
.varGlobal, .varGlobal,
.varInstance, .varInstance,
@ -10,7 +10,7 @@ extension SwiftDeclarationKind {
.varStatic .varStatic
] ]
internal static let functionKinds: Set<SwiftDeclarationKind> = [ static let functionKinds: Set<SwiftDeclarationKind> = [
.functionAccessorAddress, .functionAccessorAddress,
.functionAccessorDidset, .functionAccessorDidset,
.functionAccessorGetter, .functionAccessorGetter,
@ -27,7 +27,7 @@ extension SwiftDeclarationKind {
.functionSubscript .functionSubscript
] ]
internal static let typeKinds: Set<SwiftDeclarationKind> = [ static let typeKinds: Set<SwiftDeclarationKind> = [
.class, .class,
.struct, .struct,
.typealias, .typealias,
@ -35,7 +35,7 @@ extension SwiftDeclarationKind {
.enum .enum
] ]
internal static let extensionKinds: Set<SwiftDeclarationKind> = [ static let extensionKinds: Set<SwiftDeclarationKind> = [
.extension, .extension,
.extensionClass, .extensionClass,
.extensionEnum, .extensionEnum,

View File

@ -1,6 +1,6 @@
import SwiftSyntax import SwiftSyntax
extension SwiftLintFile { public extension SwiftLintFile {
/// This function determines if given a scope with a left/right brace, such as a function, closure, type, etc, how /// This function determines if given a scope with a left/right brace, such as a function, closure, type, etc, how
/// many lines the "body" spans when you ignore lines only containing comments and/or whitespace. /// many lines the "body" spans when you ignore lines only containing comments and/or whitespace.
/// ///

View File

@ -101,7 +101,7 @@ extension SwiftLintFile {
return id return id
} }
internal var sourcekitdFailed: Bool { public var sourcekitdFailed: Bool {
get { get {
return responseCache.get(self) == nil return responseCache.get(self) == nil
} }
@ -123,7 +123,7 @@ extension SwiftLintFile {
} }
} }
internal var parserDiagnostics: [String]? { public var parserDiagnostics: [String]? {
if parserDiagnosticsDisabledForTests { if parserDiagnosticsDisabledForTests {
return nil return nil
} }
@ -133,9 +133,9 @@ extension SwiftLintFile {
.map(\.message) .map(\.message)
} }
internal var linesWithTokens: Set<Int> { linesWithTokensCache.get(self) } public var linesWithTokens: Set<Int> { linesWithTokensCache.get(self) }
internal var structureDictionary: SourceKittenDictionary { public var structureDictionary: SourceKittenDictionary {
guard let structureDictionary = structureDictionaryCache.get(self) else { guard let structureDictionary = structureDictionaryCache.get(self) else {
if let handler = assertHandler { if let handler = assertHandler {
handler() handler()
@ -146,9 +146,9 @@ extension SwiftLintFile {
return structureDictionary return structureDictionary
} }
internal var syntaxClassifications: SyntaxClassifications { syntaxClassificationsCache.get(self) } public var syntaxClassifications: SyntaxClassifications { syntaxClassificationsCache.get(self) }
internal var syntaxMap: SwiftLintSyntaxMap { public var syntaxMap: SwiftLintSyntaxMap {
guard let syntaxMap = syntaxMapCache.get(self) else { guard let syntaxMap = syntaxMapCache.get(self) else {
if let handler = assertHandler { if let handler = assertHandler {
handler() handler()
@ -159,16 +159,17 @@ extension SwiftLintFile {
return syntaxMap return syntaxMap
} }
internal var syntaxTree: SourceFileSyntax { syntaxTreeCache.get(self) } public var syntaxTree: SourceFileSyntax { syntaxTreeCache.get(self) }
internal var foldedSyntaxTree: SourceFileSyntax? { foldedSyntaxTreeCache.get(self) } public var foldedSyntaxTree: SourceFileSyntax? { foldedSyntaxTreeCache.get(self) }
internal var locationConverter: SourceLocationConverter { locationConverterCache.get(self) } public var locationConverter: SourceLocationConverter { locationConverterCache.get(self) }
internal var commands: [Command] { commandsCache.get(self).filter { $0.isValid } } public var commands: [Command] { commandsCache.get(self).filter { $0.isValid } }
internal var invalidCommands: [Command] { commandsCache.get(self).filter { !$0.isValid } }
internal var syntaxTokensByLines: [[SwiftLintSyntaxToken]] { public var invalidCommands: [Command] { commandsCache.get(self).filter { !$0.isValid } }
public var syntaxTokensByLines: [[SwiftLintSyntaxToken]] {
guard let syntaxTokensByLines = syntaxTokensByLinesCache.get(self) else { guard let syntaxTokensByLines = syntaxTokensByLinesCache.get(self) else {
if let handler = assertHandler { if let handler = assertHandler {
handler() handler()
@ -179,7 +180,7 @@ extension SwiftLintFile {
return syntaxTokensByLines return syntaxTokensByLines
} }
internal var syntaxKindsByLines: [[SourceKittenFramework.SyntaxKind]] { public var syntaxKindsByLines: [[SourceKittenFramework.SyntaxKind]] {
guard let syntaxKindsByLines = syntaxKindsByLinesCache.get(self) else { guard let syntaxKindsByLines = syntaxKindsByLinesCache.get(self) else {
if let handler = assertHandler { if let handler = assertHandler {
handler() handler()

View File

@ -1,8 +1,8 @@
import Foundation import Foundation
import SourceKittenFramework import SourceKittenFramework
internal func regex(_ pattern: String, public func regex(_ pattern: String,
options: NSRegularExpression.Options? = nil) -> NSRegularExpression { options: NSRegularExpression.Options? = nil) -> NSRegularExpression {
// all patterns used for regular expressions in SwiftLint are string literals which have been // all patterns used for regular expressions in SwiftLint are string literals which have been
// confirmed to work, so it's ok to force-try here. // confirmed to work, so it's ok to force-try here.
@ -12,7 +12,7 @@ internal func regex(_ pattern: String,
} }
extension SwiftLintFile { extension SwiftLintFile {
internal func regions(restrictingRuleIdentifiers: Set<RuleIdentifier>? = nil) -> [Region] { public func regions(restrictingRuleIdentifiers: Set<RuleIdentifier>? = nil) -> [Region] {
var regions = [Region]() var regions = [Region]()
var disabledRules = Set<RuleIdentifier>() var disabledRules = Set<RuleIdentifier>()
let commands: [Command] let commands: [Command]
@ -57,7 +57,7 @@ extension SwiftLintFile {
return regions return regions
} }
internal func commands(in range: NSRange? = nil) -> [Command] { public func commands(in range: NSRange? = nil) -> [Command] {
guard let range else { guard let range else {
return commands return commands
.flatMap { $0.expand() } .flatMap { $0.expand() }
@ -93,14 +93,14 @@ extension SwiftLintFile {
return Location(file: path, line: nextLine, character: nextCharacter) return Location(file: path, line: nextLine, character: nextCharacter)
} }
internal func match(pattern: String, with syntaxKinds: [SyntaxKind], range: NSRange? = nil) -> [NSRange] { public func match(pattern: String, with syntaxKinds: [SyntaxKind], range: NSRange? = nil) -> [NSRange] {
return match(pattern: pattern, range: range) return match(pattern: pattern, range: range)
.filter { $0.1 == syntaxKinds } .filter { $0.1 == syntaxKinds }
.map { $0.0 } .map { $0.0 }
} }
internal func matchesAndTokens(matching pattern: String, public func matchesAndTokens(matching pattern: String,
range: NSRange? = nil) -> [(NSTextCheckingResult, [SwiftLintSyntaxToken])] { range: NSRange? = nil) -> [(NSTextCheckingResult, [SwiftLintSyntaxToken])] {
let contents = stringView let contents = stringView
let range = range ?? contents.range let range = range ?? contents.range
let syntax = syntaxMap let syntax = syntaxMap
@ -110,25 +110,25 @@ extension SwiftLintFile {
} }
} }
internal func matchesAndSyntaxKinds(matching pattern: String, public func matchesAndSyntaxKinds(matching pattern: String,
range: NSRange? = nil) -> [(NSTextCheckingResult, [SyntaxKind])] { range: NSRange? = nil) -> [(NSTextCheckingResult, [SyntaxKind])] {
return matchesAndTokens(matching: pattern, range: range).map { textCheckingResult, tokens in return matchesAndTokens(matching: pattern, range: range).map { textCheckingResult, tokens in
(textCheckingResult, tokens.kinds) (textCheckingResult, tokens.kinds)
} }
} }
internal func rangesAndTokens(matching pattern: String, public func rangesAndTokens(matching pattern: String,
range: NSRange? = nil) -> [(NSRange, [SwiftLintSyntaxToken])] { range: NSRange? = nil) -> [(NSRange, [SwiftLintSyntaxToken])] {
return matchesAndTokens(matching: pattern, range: range).map { ($0.0.range, $0.1) } return matchesAndTokens(matching: pattern, range: range).map { ($0.0.range, $0.1) }
} }
internal func match(pattern: String, range: NSRange? = nil, captureGroup: Int = 0) -> [(NSRange, [SyntaxKind])] { public func match(pattern: String, range: NSRange? = nil, captureGroup: Int = 0) -> [(NSRange, [SyntaxKind])] {
return matchesAndSyntaxKinds(matching: pattern, range: range).map { textCheckingResult, syntaxKinds in return matchesAndSyntaxKinds(matching: pattern, range: range).map { textCheckingResult, syntaxKinds in
(textCheckingResult.range(at: captureGroup), syntaxKinds) (textCheckingResult.range(at: captureGroup), syntaxKinds)
} }
} }
internal func swiftDeclarationKindsByLine() -> [[SwiftDeclarationKind]]? { public func swiftDeclarationKindsByLine() -> [[SwiftDeclarationKind]]? {
if sourcekitdFailed { if sourcekitdFailed {
return nil return nil
} }
@ -151,7 +151,7 @@ extension SwiftLintFile {
return results return results
} }
internal func syntaxTokensByLine() -> [[SwiftLintSyntaxToken]]? { public func syntaxTokensByLine() -> [[SwiftLintSyntaxToken]]? {
if sourcekitdFailed { if sourcekitdFailed {
return nil return nil
} }
@ -180,7 +180,7 @@ extension SwiftLintFile {
return results return results
} }
internal func syntaxKindsByLine() -> [[SyntaxKind]]? { public func syntaxKindsByLine() -> [[SyntaxKind]]? {
guard !sourcekitdFailed, let tokens = syntaxTokensByLine() else { guard !sourcekitdFailed, let tokens = syntaxTokensByLine() else {
return nil return nil
} }
@ -199,22 +199,22 @@ extension SwiftLintFile {
- returns: An array of [NSRange] objects consisting of regex matches inside - returns: An array of [NSRange] objects consisting of regex matches inside
file contents. file contents.
*/ */
internal func match(pattern: String, public func match(pattern: String,
excludingSyntaxKinds syntaxKinds: Set<SyntaxKind>, excludingSyntaxKinds syntaxKinds: Set<SyntaxKind>,
range: NSRange? = nil, range: NSRange? = nil,
captureGroup: Int = 0) -> [NSRange] { captureGroup: Int = 0) -> [NSRange] {
return match(pattern: pattern, range: range, captureGroup: captureGroup) return match(pattern: pattern, range: range, captureGroup: captureGroup)
.filter { syntaxKinds.isDisjoint(with: $0.1) } .filter { syntaxKinds.isDisjoint(with: $0.1) }
.map { $0.0 } .map { $0.0 }
} }
internal typealias MatchMapping = (NSTextCheckingResult) -> NSRange public typealias MatchMapping = (NSTextCheckingResult) -> NSRange
internal func match(pattern: String, public func match(pattern: String,
range: NSRange? = nil, range: NSRange? = nil,
excludingSyntaxKinds: Set<SyntaxKind>, excludingSyntaxKinds: Set<SyntaxKind>,
excludingPattern: String, excludingPattern: String,
exclusionMapping: MatchMapping = { $0.range }) -> [NSRange] { exclusionMapping: MatchMapping = { $0.range }) -> [NSRange] {
let matches = match(pattern: pattern, excludingSyntaxKinds: excludingSyntaxKinds) let matches = match(pattern: pattern, excludingSyntaxKinds: excludingSyntaxKinds)
if matches.isEmpty { if matches.isEmpty {
return [] return []
@ -225,7 +225,7 @@ extension SwiftLintFile {
return matches.filter { !$0.intersects(exclusionRanges) } return matches.filter { !$0.intersects(exclusionRanges) }
} }
internal func append(_ string: String) { public func append(_ string: String) {
guard string.isNotEmpty else { guard string.isNotEmpty else {
return return
} }
@ -245,7 +245,7 @@ extension SwiftLintFile {
invalidateCache() invalidateCache()
} }
internal func write<S: StringProtocol>(_ string: S) { public func write<S: StringProtocol>(_ string: S) {
guard string != contents else { guard string != contents else {
return return
} }
@ -267,7 +267,7 @@ extension SwiftLintFile {
invalidateCache() invalidateCache()
} }
internal func ruleEnabled(violatingRanges: [NSRange], for rule: Rule) -> [NSRange] { public func ruleEnabled(violatingRanges: [NSRange], for rule: Rule) -> [NSRange] {
let fileRegions = regions() let fileRegions = regions()
if fileRegions.isEmpty { return violatingRanges } if fileRegions.isEmpty { return violatingRanges }
return violatingRanges.filter { range in return violatingRanges.filter { range in
@ -278,11 +278,11 @@ extension SwiftLintFile {
} }
} }
internal func ruleEnabled(violatingRange: NSRange, for rule: Rule) -> NSRange? { public func ruleEnabled(violatingRange: NSRange, for rule: Rule) -> NSRange? {
return ruleEnabled(violatingRanges: [violatingRange], for: rule).first return ruleEnabled(violatingRanges: [violatingRange], for: rule).first
} }
internal func isACL(token: SwiftLintSyntaxToken) -> Bool { public func isACL(token: SwiftLintSyntaxToken) -> Bool {
guard token.kind == .attributeBuiltin else { guard token.kind == .attributeBuiltin else {
return false return false
} }
@ -291,7 +291,7 @@ extension SwiftLintFile {
return aclString.flatMap(AccessControlLevel.init(description:)) != nil return aclString.flatMap(AccessControlLevel.init(description:)) != nil
} }
internal func contents(for token: SwiftLintSyntaxToken) -> String? { public func contents(for token: SwiftLintSyntaxToken) -> String? {
return stringView.substringWithByteRange(token.range) return stringView.substringWithByteRange(token.range)
} }
} }

View File

@ -3,10 +3,10 @@ import SourceKittenFramework
import SwiftSyntax import SwiftSyntax
// workaround for https://bugs.swift.org/browse/SR-10121 so we can use `Self` in a closure // workaround for https://bugs.swift.org/browse/SR-10121 so we can use `Self` in a closure
protocol SwiftLintSyntaxVisitor: SyntaxVisitor {} public protocol SwiftLintSyntaxVisitor: SyntaxVisitor {}
extension SyntaxVisitor: SwiftLintSyntaxVisitor {} extension SyntaxVisitor: SwiftLintSyntaxVisitor {}
extension SwiftLintSyntaxVisitor { public extension SwiftLintSyntaxVisitor {
func walk<T, SyntaxType: SyntaxProtocol>(tree: SyntaxType, handler: (Self) -> T) -> T { func walk<T, SyntaxType: SyntaxProtocol>(tree: SyntaxType, handler: (Self) -> T) -> T {
#if DEBUG #if DEBUG
// workaround for stack overflow when running in debug // workaround for stack overflow when running in debug
@ -44,7 +44,7 @@ extension SwiftLintSyntaxVisitor {
} }
} }
extension SyntaxProtocol { public extension SyntaxProtocol {
func windowsOfThreeTokens() -> [(TokenSyntax, TokenSyntax, TokenSyntax)] { func windowsOfThreeTokens() -> [(TokenSyntax, TokenSyntax, TokenSyntax)] {
Array(tokens(viewMode: .sourceAccurate)) Array(tokens(viewMode: .sourceAccurate))
.windows(ofCount: 3) .windows(ofCount: 3)
@ -61,7 +61,7 @@ extension SyntaxProtocol {
} }
} }
extension AbsolutePosition { public extension AbsolutePosition {
func isContainedIn(regions: [SourceRange], locationConverter: SourceLocationConverter) -> Bool { func isContainedIn(regions: [SourceRange], locationConverter: SourceLocationConverter) -> Bool {
regions.contains { region in regions.contains { region in
region.contains(self, locationConverter: locationConverter) region.contains(self, locationConverter: locationConverter)
@ -69,13 +69,13 @@ extension AbsolutePosition {
} }
} }
extension ByteSourceRange { public extension ByteSourceRange {
func toSourceKittenByteRange() -> ByteRange { func toSourceKittenByteRange() -> ByteRange {
ByteRange(location: ByteCount(offset), length: ByteCount(length)) ByteRange(location: ByteCount(offset), length: ByteCount(length))
} }
} }
extension ClassDeclSyntax { public extension ClassDeclSyntax {
func isXCTestCase(_ testParentClasses: Set<String>) -> Bool { func isXCTestCase(_ testParentClasses: Set<String>) -> Bool {
guard let inheritanceList = inheritanceClause?.inheritedTypeCollection else { guard let inheritanceList = inheritanceClause?.inheritedTypeCollection else {
return false return false
@ -85,7 +85,7 @@ extension ClassDeclSyntax {
} }
} }
extension ExprSyntax { public extension ExprSyntax {
var asFunctionCall: FunctionCallExprSyntax? { var asFunctionCall: FunctionCallExprSyntax? {
if let functionCall = self.as(FunctionCallExprSyntax.self) { if let functionCall = self.as(FunctionCallExprSyntax.self) {
return functionCall return functionCall
@ -99,19 +99,19 @@ extension ExprSyntax {
} }
} }
extension StringLiteralExprSyntax { public extension StringLiteralExprSyntax {
var isEmptyString: Bool { var isEmptyString: Bool {
segments.onlyElement?.contentLength == .zero segments.onlyElement?.contentLength == .zero
} }
} }
extension TokenKind { public extension TokenKind {
var isEqualityComparison: Bool { var isEqualityComparison: Bool {
self == .binaryOperator("==") || self == .binaryOperator("!=") self == .binaryOperator("==") || self == .binaryOperator("!=")
} }
} }
extension ModifierListSyntax? { public extension ModifierListSyntax? {
var containsLazy: Bool { var containsLazy: Bool {
contains(tokenKind: .keyword(.lazy)) contains(tokenKind: .keyword(.lazy))
} }
@ -160,26 +160,26 @@ extension ModifierListSyntax? {
} }
} }
extension AttributeSyntax { public extension AttributeSyntax {
var attributeNameText: String { var attributeNameText: String {
attributeName.as(SimpleTypeIdentifierSyntax.self)?.name.text ?? attributeName.as(SimpleTypeIdentifierSyntax.self)?.name.text ??
attributeName.description attributeName.description
} }
} }
extension AttributeListSyntax? { public extension AttributeListSyntax? {
func contains(attributeNamed attributeName: String) -> Bool { func contains(attributeNamed attributeName: String) -> Bool {
self?.contains { $0.as(AttributeSyntax.self)?.attributeNameText == attributeName } == true self?.contains { $0.as(AttributeSyntax.self)?.attributeNameText == attributeName } == true
} }
} }
extension TokenKind { public extension TokenKind {
var isUnavailableKeyword: Bool { var isUnavailableKeyword: Bool {
self == .keyword(.unavailable) || self == .identifier("unavailable") self == .keyword(.unavailable) || self == .identifier("unavailable")
} }
} }
extension VariableDeclSyntax { public extension VariableDeclSyntax {
var isIBOutlet: Bool { var isIBOutlet: Bool {
attributes.contains(attributeNamed: "IBOutlet") attributes.contains(attributeNamed: "IBOutlet")
} }
@ -220,7 +220,7 @@ public extension EnumDeclSyntax {
} }
} }
extension FunctionDeclSyntax { public extension FunctionDeclSyntax {
var isIBAction: Bool { var isIBAction: Bool {
attributes.contains(attributeNamed: "IBAction") attributes.contains(attributeNamed: "IBAction")
} }
@ -251,7 +251,7 @@ extension FunctionDeclSyntax {
} }
} }
extension AccessorBlockSyntax { public extension AccessorBlockSyntax {
var getAccessor: AccessorDeclSyntax? { var getAccessor: AccessorDeclSyntax? {
accessors.first { accessor in accessors.first { accessor in
accessor.accessorKind.tokenKind == .keyword(.get) accessor.accessorKind.tokenKind == .keyword(.get)
@ -273,7 +273,7 @@ extension AccessorBlockSyntax {
} }
} }
extension TypeInheritanceClauseSyntax? { public extension TypeInheritanceClauseSyntax? {
func containsInheritedType(inheritedTypes: Set<String>) -> Bool { func containsInheritedType(inheritedTypes: Set<String>) -> Bool {
self?.inheritedTypeCollection.contains { elem in self?.inheritedTypeCollection.contains { elem in
guard let simpleType = elem.typeName.as(SimpleTypeIdentifierSyntax.self) else { guard let simpleType = elem.typeName.as(SimpleTypeIdentifierSyntax.self) else {
@ -285,7 +285,7 @@ extension TypeInheritanceClauseSyntax? {
} }
} }
extension Trivia { public extension Trivia {
func containsNewlines() -> Bool { func containsNewlines() -> Bool {
contains { piece in contains { piece in
if case .newlines = piece { if case .newlines = piece {
@ -312,7 +312,7 @@ extension Trivia {
} }
} }
extension TriviaPiece { public extension TriviaPiece {
var isHorizontalWhitespace: Bool { var isHorizontalWhitespace: Bool {
switch self { switch self {
case .spaces, .tabs: case .spaces, .tabs:
@ -323,7 +323,7 @@ extension TriviaPiece {
} }
} }
extension IntegerLiteralExprSyntax { public extension IntegerLiteralExprSyntax {
var isZero: Bool { var isZero: Bool {
guard case let .integerLiteral(number) = digits.tokenKind else { guard case let .integerLiteral(number) = digits.tokenKind else {
return false return false
@ -333,7 +333,7 @@ extension IntegerLiteralExprSyntax {
} }
} }
extension FloatLiteralExprSyntax { public extension FloatLiteralExprSyntax {
var isZero: Bool { var isZero: Bool {
guard case let .floatingLiteral(number) = floatingDigits.tokenKind else { guard case let .floatingLiteral(number) = floatingDigits.tokenKind else {
return false return false

View File

@ -1,6 +1,6 @@
import IDEUtils import IDEUtils
extension SyntaxClassification { public extension SyntaxClassification {
// True if it is any kind of comment. // True if it is any kind of comment.
var isComment: Bool { var isComment: Bool {
switch self { switch self {

View File

@ -1,6 +1,6 @@
import SourceKittenFramework import SourceKittenFramework
extension SyntaxKind { public extension SyntaxKind {
init(shortName: Swift.String) throws { init(shortName: Swift.String) throws {
let prefix = "source.lang.swift.syntaxtype." let prefix = "source.lang.swift.syntaxtype."
guard let kind = SyntaxKind(rawValue: prefix + shortName.lowercased()) else { guard let kind = SyntaxKind(rawValue: prefix + shortName.lowercased()) else {

View File

@ -1,31 +1,43 @@
/// A basic stack type implementing the LIFO principle - only the last inserted element can be accessed and removed. /// A basic stack type implementing the LIFO principle - only the last inserted element can be accessed and removed.
struct Stack<Element> { public struct Stack<Element> {
private var elements = [Element]() private var elements = [Element]()
var isEmpty: Bool { /// Creates an empty `Stack`.
public init() {}
/// True if the stack has no elements. False otherwise.
public var isEmpty: Bool {
elements.isEmpty elements.isEmpty
} }
var count: Int { /// The number of elements in this stack.
public var count: Int {
elements.count elements.count
} }
mutating func push(_ element: Element) { /// Pushes (appends) an element onto the stack.
///
/// - parameter element: The element to push onto the stack.
public mutating func push(_ element: Element) {
elements.append(element) elements.append(element)
} }
/// Removes and returns the last element of the stack.
///
/// - returns: The last element of the stack if the stack is not empty; otherwise, nil.
@discardableResult @discardableResult
mutating func pop() -> Element? { public mutating func pop() -> Element? {
elements.popLast() elements.popLast()
} }
func peek() -> Element? { /// Returns the last element of the stack if the stack is not empty; otherwise, nil.
public func peek() -> Element? {
elements.last elements.last
} }
} }
extension Stack: CustomDebugStringConvertible where Element == CustomDebugStringConvertible { extension Stack: CustomDebugStringConvertible where Element == CustomDebugStringConvertible {
var debugDescription: String { public var debugDescription: String {
let intermediateElements = count > 1 ? elements[1 ..< count - 1] : [] let intermediateElements = count > 1 ? elements[1 ..< count - 1] : []
return """ return """
Stack with \(count) elements: Stack with \(count) elements:

View File

@ -16,7 +16,7 @@ public enum AccessControlLevel: String, CustomStringConvertible {
/// Initializes an access control level by its Swift source keyword value. /// Initializes an access control level by its Swift source keyword value.
/// ///
/// - parameter value: The value used to describe this level in Swift source code. /// - parameter value: The value used to describe this level in Swift source code.
internal init?(description value: String) { public init?(description value: String) {
switch value { switch value {
case "private": self = .private case "private": self = .private
case "fileprivate": self = .fileprivate case "fileprivate": self = .fileprivate
@ -45,7 +45,7 @@ public enum AccessControlLevel: String, CustomStringConvertible {
} }
/// Returns true if is `private` or `fileprivate` /// Returns true if is `private` or `fileprivate`
var isPrivate: Bool { public var isPrivate: Bool {
return self == .private || self == .fileprivate return self == .private || self == .fileprivate
} }
} }

View File

@ -46,15 +46,15 @@ public struct Command: Equatable {
} }
/// The action (verb) that SwiftLint should perform when interpreting this command. /// The action (verb) that SwiftLint should perform when interpreting this command.
internal let action: Action public let action: Action
/// The identifiers for the rules associated with this command. /// The identifiers for the rules associated with this command.
internal let ruleIdentifiers: Set<RuleIdentifier> public let ruleIdentifiers: Set<RuleIdentifier>
/// The line in the source file where this command is defined. /// The line in the source file where this command is defined.
internal let line: Int public let line: Int
/// The character offset within the line in the source file where this command is defined. /// The character offset within the line in the source file where this command is defined.
internal let character: Int? public let character: Int?
/// This command's modifier, if any. /// This command's modifier, if any.
internal let modifier: Modifier? public let modifier: Modifier?
/// The comment following this command's `-` delimiter, if any. /// The comment following this command's `-` delimiter, if any.
internal let trailingComment: String? internal let trailingComment: String?

View File

@ -147,7 +147,7 @@ extension Example: Comparable {
} }
} }
extension Array where Element == Example { public extension Array where Element == Example {
/// Make these examples skip wrapping in comment tests. /// Make these examples skip wrapping in comment tests.
func skipWrappingInCommentTests() -> Self { func skipWrappingInCommentTests() -> Self {
map { $0.skipWrappingInCommentTest() } map { $0.skipWrappingInCommentTest() }

View File

@ -4,10 +4,10 @@ import SourceKittenFramework
/// A unit of Swift source code, either on disk or in memory. /// A unit of Swift source code, either on disk or in memory.
public final class SwiftLintFile { public final class SwiftLintFile {
/// The underlying SourceKitten file. /// The underlying SourceKitten file.
let file: File public let file: File
let id: UUID let id: UUID
/// Whether or not this is a file generated for testing purposes. /// Whether or not this is a file generated for testing purposes.
private(set) var isTestFile = false public private(set) var isTestFile = false
/// A file is virtual if it is not backed by a filesystem path. /// A file is virtual if it is not backed by a filesystem path.
private(set) var isVirtual = false private(set) var isVirtual = false

View File

@ -21,7 +21,7 @@ public struct SwiftLintSyntaxMap {
/// - parameter byteRange: Byte-based NSRange. /// - parameter byteRange: Byte-based NSRange.
/// ///
/// - returns: The array of syntax tokens intersecting with byte range. /// - returns: The array of syntax tokens intersecting with byte range.
internal func tokens(inByteRange byteRange: ByteRange) -> [SwiftLintSyntaxToken] { public func tokens(inByteRange byteRange: ByteRange) -> [SwiftLintSyntaxToken] {
func intersect(_ token: SwiftLintSyntaxToken) -> Bool { func intersect(_ token: SwiftLintSyntaxToken) -> Bool {
return token.range.intersects(byteRange) return token.range.intersects(byteRange)
} }
@ -48,7 +48,7 @@ public struct SwiftLintSyntaxMap {
/// - parameter byteRange: Byte range. /// - parameter byteRange: Byte range.
/// ///
/// - returns: The syntax kinds in the specified byte range. /// - returns: The syntax kinds in the specified byte range.
internal func kinds(inByteRange byteRange: ByteRange) -> [SyntaxKind] { public func kinds(inByteRange byteRange: ByteRange) -> [SyntaxKind] {
return tokens(inByteRange: byteRange).compactMap { $0.kind } return tokens(inByteRange: byteRange).compactMap { $0.kind }
} }
} }

View File

@ -32,7 +32,7 @@ public struct SwiftLintSyntaxToken {
} }
} }
extension Array where Element == SwiftLintSyntaxToken { public extension Array where Element == SwiftLintSyntaxToken {
/// The kinds for these tokens. /// The kinds for these tokens.
var kinds: [SyntaxKind] { var kinds: [SyntaxKind] {
return compactMap { $0.kind } return compactMap { $0.kind }

View File

@ -1,5 +1,5 @@
/// Interface providing access to a cache description. /// Interface providing access to a cache description.
internal protocol CacheDescriptionProvider { public protocol CacheDescriptionProvider {
/// The cache description which will be used to determine if a previous /// The cache description which will be used to determine if a previous
/// cached value is still valid given the new cache value. /// cached value is still valid given the new cache value.
var cacheDescription: String { get } var cacheDescription: String { get }

View File

@ -63,27 +63,27 @@ public protocol Rule {
func validate(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [StyleViolation] func validate(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [StyleViolation]
} }
extension Rule { public extension Rule {
public func validate(file: SwiftLintFile, using storage: RuleStorage, func validate(file: SwiftLintFile, using storage: RuleStorage,
compilerArguments: [String]) -> [StyleViolation] { compilerArguments: [String]) -> [StyleViolation] {
return validate(file: file, compilerArguments: compilerArguments) return validate(file: file, compilerArguments: compilerArguments)
} }
public func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] { func validate(file: SwiftLintFile, compilerArguments: [String]) -> [StyleViolation] {
return validate(file: file) return validate(file: file)
} }
public func isEqualTo(_ rule: Rule) -> Bool { func isEqualTo(_ rule: Rule) -> Bool {
return Self.description == type(of: rule).description return Self.description == type(of: rule).description
} }
public func collectInfo(for file: SwiftLintFile, into storage: RuleStorage, compilerArguments: [String]) { func collectInfo(for file: SwiftLintFile, into storage: RuleStorage, compilerArguments: [String]) {
// no-op: only CollectingRules mutate their storage // no-op: only CollectingRules mutate their storage
} }
/// The cache description which will be used to determine if a previous /// The cache description which will be used to determine if a previous
/// cached value is still valid given the new cache value. /// cached value is still valid given the new cache value.
internal var cacheDescription: String { var cacheDescription: String {
return (self as? CacheDescriptionProvider)?.cacheDescription ?? configurationDescription return (self as? CacheDescriptionProvider)?.cacheDescription ?? configurationDescription
} }
} }
@ -130,7 +130,6 @@ public protocol CorrectableRule: Rule {
func correct(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [Correction] func correct(file: SwiftLintFile, using storage: RuleStorage, compilerArguments: [String]) -> [Correction]
} }
@_spi(TestHelper)
public extension CorrectableRule { public extension CorrectableRule {
func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] { func correct(file: SwiftLintFile, compilerArguments: [String]) -> [Correction] {
return correct(file: file) return correct(file: file)
@ -142,7 +141,6 @@ public extension CorrectableRule {
/// A correctable rule that can apply its corrections by replacing the content of ranges in the offending file with /// A correctable rule that can apply its corrections by replacing the content of ranges in the offending file with
/// updated content. /// updated content.
@_spi(TestHelper)
public protocol SubstitutionCorrectableRule: CorrectableRule { public protocol SubstitutionCorrectableRule: CorrectableRule {
/// Returns the NSString-based `NSRange`s to be replaced in the specified file. /// Returns the NSString-based `NSRange`s to be replaced in the specified file.
/// ///
@ -160,7 +158,6 @@ public protocol SubstitutionCorrectableRule: CorrectableRule {
func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)? func substitution(for violationRange: NSRange, in file: SwiftLintFile) -> (NSRange, String)?
} }
@_spi(TestHelper)
public extension SubstitutionCorrectableRule { public extension SubstitutionCorrectableRule {
func correct(file: SwiftLintFile) -> [Correction] { func correct(file: SwiftLintFile) -> [Correction] {
let violatingRanges = file.ruleEnabled(violatingRanges: violationRanges(in: file), for: self) let violatingRanges = file.ruleEnabled(violatingRanges: violationRanges(in: file), for: self)
@ -184,7 +181,6 @@ public extension SubstitutionCorrectableRule {
} }
/// A `SubstitutionCorrectableRule` that is also an `ASTRule`. /// A `SubstitutionCorrectableRule` that is also an `ASTRule`.
@_spi(TestHelper)
public protocol SubstitutionCorrectableASTRule: SubstitutionCorrectableRule, ASTRule { public protocol SubstitutionCorrectableASTRule: SubstitutionCorrectableRule, ASTRule {
/// Returns the NSString-based `NSRange`s to be replaced in the specified file. /// Returns the NSString-based `NSRange`s to be replaced in the specified file.
/// ///
@ -220,7 +216,6 @@ public extension AnalyzerRule {
} }
/// :nodoc: /// :nodoc:
@_spi(TestHelper)
public extension AnalyzerRule where Self: CorrectableRule { public extension AnalyzerRule where Self: CorrectableRule {
func correct(file: SwiftLintFile) -> [Correction] { func correct(file: SwiftLintFile) -> [Correction] {
queuedFatalError("Must call `correct(file:compilerArguments:)` for AnalyzerRule") queuedFatalError("Must call `correct(file:compilerArguments:)` for AnalyzerRule")

View File

@ -1,7 +1,6 @@
import SwiftSyntax import SwiftSyntax
/// A SwiftLint CorrectableRule that performs its corrections using a SwiftSyntax `SyntaxRewriter`. /// A SwiftLint CorrectableRule that performs its corrections using a SwiftSyntax `SyntaxRewriter`.
@_spi(TestHelper)
public protocol SwiftSyntaxCorrectableRule: SwiftSyntaxRule, CorrectableRule { public protocol SwiftSyntaxCorrectableRule: SwiftSyntaxRule, CorrectableRule {
/// Produce a `ViolationsSyntaxRewriter` for the given file. /// Produce a `ViolationsSyntaxRewriter` for the given file.
/// ///
@ -11,7 +10,6 @@ public protocol SwiftSyntaxCorrectableRule: SwiftSyntaxRule, CorrectableRule {
func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter? func makeRewriter(file: SwiftLintFile) -> ViolationsSyntaxRewriter?
} }
@_spi(TestHelper)
public extension SwiftSyntaxCorrectableRule { public extension SwiftSyntaxCorrectableRule {
func correct(file: SwiftLintFile) -> [Correction] { func correct(file: SwiftLintFile) -> [Correction] {
guard let rewriter = makeRewriter(file: file), guard let rewriter = makeRewriter(file: file),

View File

@ -112,7 +112,7 @@ public struct ReasonedRuleViolation: Comparable {
/// Extension for arrays of `ReasonedRuleViolation`s that provides the automatic conversion of /// Extension for arrays of `ReasonedRuleViolation`s that provides the automatic conversion of
/// `AbsolutePosition`s into `ReasonedRuleViolation`s (without a specific reason). /// `AbsolutePosition`s into `ReasonedRuleViolation`s (without a specific reason).
extension Array where Element == ReasonedRuleViolation { public extension Array where Element == ReasonedRuleViolation {
/// Append a minimal violation for the specified position. /// Append a minimal violation for the specified position.
/// ///
/// - parameter position: The position for the violation to append. /// - parameter position: The position for the violation to append.
@ -131,9 +131,9 @@ extension Array where Element == ReasonedRuleViolation {
/// A SwiftSyntax `SyntaxVisitor` that produces absolute positions where violations should be reported. /// A SwiftSyntax `SyntaxVisitor` that produces absolute positions where violations should be reported.
open class ViolationsSyntaxVisitor: SyntaxVisitor { open class ViolationsSyntaxVisitor: SyntaxVisitor {
/// Positions in a source file where violations should be reported. /// Positions in a source file where violations should be reported.
internal var violations: [ReasonedRuleViolation] = [] public var violations: [ReasonedRuleViolation] = []
/// List of declaration types that shall be skipped while traversing the AST. /// List of declaration types that shall be skipped while traversing the AST.
internal var skippableDeclarations: [DeclSyntaxProtocol.Type] { [] } open var skippableDeclarations: [DeclSyntaxProtocol.Type] { [] }
override open func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind { override open func visit(_ node: ActorDeclSyntax) -> SyntaxVisitorContinueKind {
skippableDeclarations.contains { $0 == ActorDeclSyntax.self } ? .skipChildren : .visitChildren skippableDeclarations.contains { $0 == ActorDeclSyntax.self } ? .skipChildren : .visitChildren
@ -172,7 +172,7 @@ open class ViolationsSyntaxVisitor: SyntaxVisitor {
} }
} }
extension Array where Element == DeclSyntaxProtocol.Type { public extension Array where Element == DeclSyntaxProtocol.Type {
/// All visitable declaration syntax types. /// All visitable declaration syntax types.
static let all: Self = [ static let all: Self = [
ActorDeclSyntax.self, ActorDeclSyntax.self,

View File

@ -26,7 +26,7 @@ public struct RegexConfiguration: SeverityBasedRuleConfiguration, Hashable, Cach
return "\(severity.rawValue): \(regex.pattern)" return "\(severity.rawValue): \(regex.pattern)"
} }
internal var cacheDescription: String { public var cacheDescription: String {
let jsonObject: [String] = [ let jsonObject: [String] = [
identifier, identifier,
name ?? "", name ?? "",

View File

@ -19,21 +19,21 @@ public struct SeverityLevelsConfiguration: RuleConfiguration, Equatable {
} }
/// The threshold for a violation to be a warning. /// The threshold for a violation to be a warning.
var warning: Int public var warning: Int
/// The threshold for a violation to be an error. /// The threshold for a violation to be an error.
var error: Int? public var error: Int?
/// Create a `SeverityLevelsConfiguration` based on the sepecified `warning` and `error` thresholds. /// Create a `SeverityLevelsConfiguration` based on the sepecified `warning` and `error` thresholds.
/// ///
/// - parameter warning: The threshold for a violation to be a warning. /// - parameter warning: The threshold for a violation to be a warning.
/// - parameter error: The threshold for a violation to be an error. /// - parameter error: The threshold for a violation to be an error.
init(warning: Int, error: Int? = nil) { public init(warning: Int, error: Int? = nil) {
self.warning = warning self.warning = warning
self.error = error self.error = error
} }
/// The rule parameters that define the thresholds that should map to each severity. /// The rule parameters that define the thresholds that should map to each severity.
var params: [RuleParameter<Int>] { public var params: [RuleParameter<Int>] {
if let error { if let error {
return [RuleParameter(severity: .error, value: error), return [RuleParameter(severity: .error, value: error),
RuleParameter(severity: .warning, value: warning)] RuleParameter(severity: .warning, value: warning)]

View File

@ -142,4 +142,12 @@ private extension String {
let operators = ["/", "=", "-", "+", "!", "*", "|", "^", "~", "?", ".", "%", "<", ">", "&"] let operators = ["/", "=", "-", "+", "!", "*", "|", "^", "~", "?", ".", "%", "<", ">", "&"]
return operators.contains(where: hasPrefix) return operators.contains(where: hasPrefix)
} }
func nameStrippingLeadingUnderscoreIfPrivate(_ dict: SourceKittenDictionary) -> String {
if let acl = dict.accessibility,
acl.isPrivate && first == "_" {
return String(self[index(after: startIndex)...])
}
return self
}
} }