Skip to content

Commit

Permalink
Update SwiftSyntax to latest development snapshot (realm#4759)
Browse files Browse the repository at this point in the history
* Merge `spacedBinaryOperator` and `unspacedBinaryOperator`

* New contextual keyword enums

* Update for removed `UnavailabilityConditionSyntax`

* Handle how attributes are now defined

This partially reverts commit 325d0ee.

* 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
  • Loading branch information
jpsim authored Feb 20, 2023
1 parent 393318d commit 2f0e537
Show file tree
Hide file tree
Showing 96 changed files with 450 additions and 473 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@
[#3399](https://github.com/realm/SwiftLint/issues/3399)
[#3605](https://github.com/realm/SwiftLint/issues/3605)

* Speed up linting by up to 6% updating to use a newer version of
`SwiftSyntax`.
[JP Simard](https://github.com/jpsim)

* Catch more valid `legacy_multiple` violations.
[JP Simard](https://github.com/jpsim)

* Catch more valid `no_magic_numbers` violations.
[JP Simard](https://github.com/jpsim)

#### Bug Fixes

* Report violations in all `<scope>_length` rules when the error threshold is
Expand Down Expand Up @@ -125,6 +135,10 @@
[Mathias Schreck](https://github.com/lo1tuma)
[#4772](https://github.com/realm/SwiftLint/issues/4772)

* Fix false positives in `attributes` rule when using property wrappers
with keypath arguments.
[JP Simard](https://github.com/jpsim)

## 0.50.3: Bundle of Towels

#### Breaking
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "edd2d0cdb988ac45e2515e0dd0624e4a6de54a94",
"version" : "0.50800.0-SNAPSHOT-2022-12-29-a"
"revision" : "013a48e2312e57b7b355db25bd3ea75282ebf274",
"version" : "0.50900.0-swift-DEVELOPMENT-SNAPSHOT-2023-02-06-a"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ let package = Package(
],
dependencies: [
.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: "0.50800.0-SNAPSHOT-2022-12-29-a"),
.package(url: "https://github.com/apple/swift-syntax.git", exact: "0.50900.0-swift-DEVELOPMENT-SNAPSHOT-2023-02-06-a"),
.package(url: "https://github.com/jpsim/SourceKitten.git", .upToNextMinor(from: "0.34.0")),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.4"),
.package(url: "https://github.com/scottrhoyt/SwiftyTextTable.git", from: "0.9.0"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ extension SwiftLintFile {
.tokens(viewMode: .sourceAccurate)
.reduce(into: []) { linesWithTokens, token in
if case .stringSegment = token.tokenKind {
let sourceRange = token.withoutTrivia().sourceRange(converter: locationConverter)
let sourceRange = token
.trimmed
.sourceRange(converter: locationConverter)
let startLine = sourceRange.start.line!
let endLine = sourceRange.end.line!
linesWithTokens.formUnion(startLine...endLine)
Expand Down
59 changes: 36 additions & 23 deletions Source/SwiftLintFramework/Extensions/SwiftSyntax+SwiftLint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extension SyntaxVisitor: SwiftLintSyntaxVisitor {}

extension SwiftLintSyntaxVisitor {
func walk<T, SyntaxType: SyntaxProtocol>(tree: SyntaxType, handler: (Self) -> T) -> T {
#if DEBUG
#if DEBUG
// workaround for stack overflow when running in debug
// https://bugs.swift.org/browse/SR-11170
let lock = NSLock()
Expand All @@ -31,10 +31,10 @@ extension SwiftLintSyntaxVisitor {
}

return handler(self)
#else
#else
walk(tree)
return handler(self)
#endif
#endif
}

func walk<T>(file: SwiftLintFile, handler: (Self) -> [T]) -> [T] {
Expand Down Expand Up @@ -107,35 +107,33 @@ extension StringLiteralExprSyntax {

extension TokenKind {
var isEqualityComparison: Bool {
self == .spacedBinaryOperator("==") ||
self == .spacedBinaryOperator("!=") ||
self == .unspacedBinaryOperator("==")
self == .binaryOperator("==") || self == .binaryOperator("!=")
}
}

extension ModifierListSyntax? {
var containsLazy: Bool {
contains(tokenKind: .contextualKeyword("lazy"))
contains(tokenKind: .keyword(.lazy))
}

var containsOverride: Bool {
contains(tokenKind: .contextualKeyword("override"))
contains(tokenKind: .keyword(.override))
}

var containsStaticOrClass: Bool {
isStatic || isClass
}

var isStatic: Bool {
contains(tokenKind: .staticKeyword)
contains(tokenKind: .keyword(.static))
}

var isClass: Bool {
contains(tokenKind: .classKeyword)
contains(tokenKind: .keyword(.class))
}

var isFileprivate: Bool {
contains(tokenKind: .fileprivateKeyword)
contains(tokenKind: .keyword(.fileprivate))
}

var isPrivateOrFileprivate: Bool {
Expand All @@ -144,13 +142,13 @@ extension ModifierListSyntax? {
}

return modifiers.contains { elem in
(elem.name.tokenKind == .privateKeyword || elem.name.tokenKind == .fileprivateKeyword) &&
(elem.name.tokenKind == .keyword(.private) || elem.name.tokenKind == .keyword(.fileprivate)) &&
elem.detail == nil
}
}

var isFinal: Bool {
contains(tokenKind: .contextualKeyword("final"))
contains(tokenKind: .keyword(.final))
}

private func contains(tokenKind: TokenKind) -> Bool {
Expand All @@ -162,17 +160,34 @@ extension ModifierListSyntax? {
}
}

extension AttributeSyntax {
var attributeNameText: String {
attributeName.as(SimpleTypeIdentifierSyntax.self)?.name.text ??
attributeName.description
}
}

extension AttributeListSyntax? {
func contains(attributeNamed attributeName: String) -> Bool {
self?.contains { $0.as(AttributeSyntax.self)?.attributeNameText == attributeName } == true
}
}

extension TokenKind {
var isUnavailableKeyword: Bool {
self == .keyword(.unavailable) || self == .identifier("unavailable")
}
}

extension VariableDeclSyntax {
var isIBOutlet: Bool {
attributes?.contains { attr in
attr.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("IBOutlet")
} ?? false
attributes.contains(attributeNamed: "IBOutlet")
}

var weakOrUnownedModifier: DeclModifierSyntax? {
modifiers?.first { decl in
decl.name.tokenKind == .contextualKeyword("weak") ||
decl.name.tokenKind == .contextualKeyword("unowned")
decl.name.tokenKind == .keyword(.weak) ||
decl.name.tokenKind == .keyword(.unowned)
}
}

Expand Down Expand Up @@ -207,9 +222,7 @@ public extension EnumDeclSyntax {

extension FunctionDeclSyntax {
var isIBAction: Bool {
attributes?.contains { attr in
attr.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("IBAction")
} ?? false
attributes.contains(attributeNamed: "IBAction")
}

/// Returns the signature including arguments, e.g "setEditing(_:animated:)"
Expand Down Expand Up @@ -241,13 +254,13 @@ extension FunctionDeclSyntax {
extension AccessorBlockSyntax {
var getAccessor: AccessorDeclSyntax? {
accessors.first { accessor in
accessor.accessorKind.tokenKind == .contextualKeyword("get")
accessor.accessorKind.tokenKind == .keyword(.get)
}
}

var setAccessor: AccessorDeclSyntax? {
accessors.first { accessor in
accessor.accessorKind.tokenKind == .contextualKeyword("set")
accessor.accessorKind.tokenKind == .keyword(.set)
}
}

Expand Down
13 changes: 5 additions & 8 deletions Source/SwiftLintFramework/Helpers/LegacyFunctionRuleHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ enum LegacyFunctionRuleHelper {

correctionPositions.append(node.positionAfterSkippingLeadingTrivia)

let trimmedArguments = node.argumentList.map { $0.trimmed() }
let trimmedArguments = node.argumentList.map { $0.trimmingTrailingComma() }
let rewriteStrategy = legacyFunctions[funcName]

let expr: ExprSyntax
Expand All @@ -82,8 +82,8 @@ enum LegacyFunctionRuleHelper {
}

return expr
.withLeadingTrivia(node.leadingTrivia ?? .zero)
.withTrailingTrivia(node.trailingTrivia ?? .zero)
.with(\.leadingTrivia, node.leadingTrivia ?? .zero)
.with(\.trailingTrivia, node.trailingTrivia ?? .zero)
}
}
}
Expand All @@ -103,10 +103,7 @@ private extension FunctionCallExprSyntax {
}

private extension TupleExprElementSyntax {
func trimmed() -> TupleExprElementSyntax {
self
.withoutTrivia()
.withTrailingComma(nil)
.withoutTrivia()
func trimmingTrailingComma() -> TupleExprElementSyntax {
self.trimmed.with(\.trailingComma, nil).trimmed
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private extension BlockBasedKVORule {
}

let types = parameterList
.compactMap { $0.type?.withoutTrivia().description.replacingOccurrences(of: " ", with: "") }
.compactMap { $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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,11 @@ private extension TypeInheritanceClauseSyntax? {

private extension AttributeListSyntax? {
var containsObjcMembers: Bool {
self?.contains { elem in
elem.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("objcMembers")
} ?? false
contains(attributeNamed: "objcMembers")
}

var containsObjc: Bool {
self?.contains { elem in
elem.as(AttributeSyntax.self)?.attributeName.tokenKind == .contextualKeyword("objc")
} ?? false
contains(attributeNamed: "objc")
}
}

Expand All @@ -218,12 +214,12 @@ private extension AttributeListSyntax? {

return attrs.contains { elem in
guard let attr = elem.as(AttributeSyntax.self),
let arguments = attr.argument?.as(AvailabilitySpecListSyntax.self) else {
let arguments = attr.argument?.as(AvailabilitySpecListSyntax.self) else {
return false
}

return attr.attributeName.tokenKind == .contextualKeyword("available") && arguments.contains { arg in
arg.entry.as(TokenSyntax.self)?.tokenKind == .contextualKeyword("unavailable")
return attr.attributeNameText == "available" && arguments.contains { arg in
arg.entry.as(TokenSyntax.self)?.tokenKind.isUnavailableKeyword == true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ struct DiscouragedAssertRule: SwiftSyntaxRule, OptInRule, ConfigurationProviderR
private extension DiscouragedAssertRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard node.calledExpression.as(IdentifierExprSyntax.self)?.identifier.withoutTrivia().text == "assert",
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 == .falseKeyword else {
boolExpr.booleanLiteral.tokenKind == .keyword(.false) else {
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ private extension ExplicitInitRule {
}

correctionPositions.append(violationPosition)
return super.visit(node.withCalledExpression("\(calledBase.withoutTrivia())"))
let newNode = node.with(\.calledExpression, calledBase.trimmed)
return super.visit(newNode)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ private extension ExplicitTopLevelACLRule {
private extension DeclModifierSyntax {
var isACLModifier: Bool {
let aclModifiers: Set<TokenKind> = [
.privateKeyword,
.fileprivateKeyword,
.internalKeyword,
.publicKeyword,
.contextualKeyword("open")
.keyword(.private),
.keyword(.fileprivate),
.keyword(.internal),
.keyword(.public),
.keyword(.open)
]

return detail == nil && aclModifiers.contains(name.tokenKind)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private extension InitializerClauseSyntax {
}

var isTypeReference: Bool {
value.as(MemberAccessExprSyntax.self)?.name.tokenKind == .selfKeyword
value.as(MemberAccessExprSyntax.self)?.name.tokenKind == .keyword(.self)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private extension FatalErrorMessageRule {
final class Visitor: ViolationsSyntaxVisitor {
override func visitPost(_ node: FunctionCallExprSyntax) {
guard let expression = node.calledExpression.as(IdentifierExprSyntax.self),
expression.identifier.withoutTrivia().text == "fatalError",
expression.identifier.text == "fatalError",
node.argumentList.isEmptyOrEmptyString else {
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ private class TypeNameCollectingVisitor: SyntaxVisitor {
}

override func visitPost(_ node: ExtensionDeclSyntax) {
names.insert(node.extendedType.withoutTrivia().description)
names.insert(node.extendedType.trimmedDescription)
}
}
18 changes: 9 additions & 9 deletions Source/SwiftLintFramework/Rules/Idiomatic/ForWhereRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,26 +134,26 @@ private extension ForWhereRule {

override func visitPost(_ node: ForInStmtSyntax) {
guard node.whereClause == nil,
case let statements = node.body.statements,
let ifStatement = statements.onlyElement?.item.as(IfStmtSyntax.self),
ifStatement.elseBody == nil,
!ifStatement.containsOptionalBinding,
!ifStatement.containsPatternCondition,
let condition = ifStatement.conditions.onlyElement,
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, ifStatement.containsReturnStatement {
if allowForAsFilter, ifExpr.containsReturnStatement {
return
}

violations.append(ifStatement.positionAfterSkippingLeadingTrivia)
violations.append(ifExpr.positionAfterSkippingLeadingTrivia)
}
}
}

private extension IfStmtSyntax {
private extension IfExprSyntax {
var containsOptionalBinding: Bool {
conditions.contains { element in
element.condition.is(OptionalBindingConditionSyntax.self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ private extension FunctionParameterSyntax {
return false
}

return attrType.attributes?.contains { attr in
attr.as(AttributeSyntax.self)?.attributeName.tokenKind == .identifier("escaping")
} ?? false
return attrType.attributes.contains(attributeNamed: "escaping")
}
}
Loading

0 comments on commit 2f0e537

Please sign in to comment.