Skip to content

Commit

Permalink
Apply minor changes to the syntactic sugar rewrite (#3915)
Browse files Browse the repository at this point in the history
* 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`
  • Loading branch information
jpsim authored Mar 24, 2022
1 parent 9ace4bb commit a773c3e
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 193 deletions.
8 changes: 5 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@
[JP Simard](https://github.com/jpsim)
[#3628](https://github.com/realm/SwiftLint/issues/3628)

* Improved the `syntactic_sugar` rule's detection accuracy and fixed some
corrections leading to invalid code.
[Paul Taykalo](https://github.com/PaulTaykalo)
[#3866](https://github.com/realm/SwiftLint/issues/3866)

## 0.47.0: Smart Appliance

#### Breaking
Expand Down Expand Up @@ -133,9 +138,6 @@
#### Experimental

* None.
* Fix incorrect autocorrection in `syntactic_sugar` rule
[Paul Taykalo](https://github.com/PaulTaykalo)
[#3866](https://github.com/realm/SwiftLint/issues/3866)

#### Enhancements

Expand Down
11 changes: 11 additions & 0 deletions Source/SwiftLintFramework/Extensions/ByteCount+SwiftSyntax.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import SourceKittenFramework
import SwiftSyntax

extension ByteCount {
/// Converts a SwiftSyntax `AbsolutePosition` to a SourceKitten `ByteCount`.
///
/// - parameter position: The SwiftSyntax position to convert.
init(_ position: AbsolutePosition) {
self.init(position.utf8Offset)
}
}
30 changes: 16 additions & 14 deletions Source/SwiftLintFramework/Extensions/StringView+SwiftSyntax.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,25 @@ import SourceKittenFramework
import SwiftSyntax

extension StringView {
/// Converts two absolute positions from SwiftSyntax to valid NSRange if possible
/// - Parameters:
/// - start: starting poisiition
/// - end: end position
/// - Returns: NSRange or nil in case of empty string
/// Converts two absolute positions from SwiftSyntax to a valid `NSRange` if possible.
///
/// - parameter start: Starting position.
/// - parameter end: End position.
///
/// - returns: `NSRange` or nil in case of empty string.
func NSRange(start: AbsolutePosition, end: AbsolutePosition) -> NSRange? {
precondition(end.utf8Offset >= start.utf8Offset, "End position should be beigger than start position")
return NSRange(start: start, length: end.utf8Offset - start.utf8Offset)
precondition(end >= start, "End position should be bigger than the start position")
return NSRange(start: start, length: ByteCount(end.utf8Offset - start.utf8Offset))
}

/// Converts absolute position with length from SwiftSyntax to valid NSRange if possible
/// - Parameters:
/// - start: starting position
/// - length: length in bytes
/// - Returns: NSRange or nil in case of empty string
private func NSRange(start: AbsolutePosition, length: Int) -> NSRange? {
let byteRange = ByteRange(location: ByteCount(start.utf8Offset), length: ByteCount(length))
/// Converts absolute position with length from SwiftSyntax to a valid `NSRange` if possible.
///
/// - parameter start: Starting position.
/// - parameter length: Length in bytes.
///
/// - returns: `NSRange` or nil in case of empty string.
private func NSRange(start: AbsolutePosition, length: ByteCount) -> NSRange? {
let byteRange = ByteRange(location: ByteCount(start), length: length)
return byteRangeToNSRange(byteRange)
}
}
17 changes: 15 additions & 2 deletions Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import SwiftSyntax
import SwiftSyntaxParser
#endif

private let warnSyntaxParserFailureOnceImpl: Void = {
queuedPrintError("Could not parse the syntax tree for at least one file. Results may be invalid.")
}()

private func warnSyntaxParserFailureOnce() {
_ = warnSyntaxParserFailureOnceImpl
}

private typealias FileCacheKey = UUID
private var responseCache = Cache({ file -> [String: SourceKitRepresentable]? in
do {
Expand All @@ -28,8 +36,13 @@ private var structureDictionaryCache = Cache({ file in
return structureCache.get(file).map { SourceKittenDictionary($0.dictionary) }
})

private var syntaxTreeCache = Cache({ file in
return try? SyntaxParser.parse(source: file.contents)
private var syntaxTreeCache = Cache({ file -> SourceFileSyntax? in
do {
return try SyntaxParser.parse(source: file.contents)
} catch {
warnSyntaxParserFailureOnce()
return nil
}
})

private var commandsCache = Cache({ file -> [Command] in
Expand Down
16 changes: 3 additions & 13 deletions Source/SwiftLintFramework/Rules/Idiomatic/ForceCastRule.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import SourceKittenFramework
import SwiftSyntax

private let warnSyntaxParserFailureOnceImpl: Void = {
queuedPrintError("The force_cast rule is disabled because the Swift Syntax tree could not be parsed")
}()

private func warnSyntaxParserFailureOnce() {
_ = warnSyntaxParserFailureOnceImpl
}

public struct ForceCastRule: ConfigurationProviderRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.error)

Expand All @@ -26,16 +18,14 @@ public struct ForceCastRule: ConfigurationProviderRule, AutomaticTestableRule {
)

public func validate(file: SwiftLintFile) -> [StyleViolation] {
guard let tree = file.syntaxTree else {
warnSyntaxParserFailureOnce()
return []
}
guard let tree = file.syntaxTree else { return [] }

let visitor = ForceCastRuleVisitor()
visitor.walk(tree)
return visitor.positions.map { position in
StyleViolation(ruleDescription: Self.description,
severity: configuration.severity,
location: Location(file: file, byteOffset: ByteCount(position.utf8Offset)))
location: Location(file: file, byteOffset: ByteCount(position)))
}
}
}
Expand Down
Loading

0 comments on commit a773c3e

Please sign in to comment.