Skip to content

Commit 7daa73f

Browse files
authored
Merge pull request swiftlang#177 from dabelknap/initializer-literals
Correct the behavior of AvoidInitializersForLiterals
2 parents f555ff9 + 354ee5a commit 7daa73f

File tree

3 files changed

+44
-58
lines changed

3 files changed

+44
-58
lines changed

Sources/SwiftFormatRules/AvoidInitializersForLiterals.swift

+17-34
Original file line numberDiff line numberDiff line change
@@ -25,53 +25,35 @@ fileprivate let knownIntTypes = Set(intSizes.map { "Int\($0)" } + intSizes.map {
2525
/// Lint: If an initializer-style cast is used on a built-in type known to be expressible by
2626
/// that kind of literal type, a lint error is raised.
2727
///
28-
/// Format: Initializer-style casts between known built-in types will be converted to standard
29-
/// casts.
30-
///
3128
/// - SeeAlso: https://google.github.io/swift#numeric-and-string-literals
32-
public final class AvoidInitializersForLiterals: SyntaxFormatRule {
33-
public override func visit(_ node: FunctionCallExprSyntax) -> ExprSyntax {
29+
public final class AvoidInitializersForLiterals: SyntaxLintRule {
30+
public override func visit(_ node: FunctionCallExprSyntax) {
3431
// Ensure we're calling a known Integer initializer.
3532
guard let callee = node.calledExpression as? IdentifierExprSyntax else {
3633
// Ensure we properly visit the children of this node, in case we have other function calls
3734
// as parameters to this one.
3835
return super.visit(node)
3936
}
4037

41-
let typeName = callee.identifier.text
42-
43-
guard let literal = extractLiteral(node, typeName) else {
38+
guard node.argumentList.count == 1 else {
4439
return super.visit(node)
4540
}
4641

47-
diagnose(.avoidInitializerStyleCast, on: callee) {
48-
$0.highlight(callee.sourceRange(in: self.context.fileURL))
42+
for arg in node.argumentList {
43+
if arg.label != nil {
44+
return super.visit(node)
45+
}
4946
}
5047

51-
// Construct an 'as' cast, converting `X(y)` to `y as X`.
52-
let asExpr = AsExprSyntax {
53-
$0.useAsTok(SyntaxFactory.makeAsKeyword(
54-
trailingTrivia: .spaces(1)
55-
))
56-
$0.useTypeName(
57-
SyntaxFactory.makeSimpleTypeIdentifier(
58-
name: callee.identifier,
59-
genericArgumentClause: nil
60-
)
61-
)
62-
}
48+
let typeName = callee.identifier.text
6349

64-
let newLiteral = replaceTrivia(
65-
on: literal,
66-
token: literal.firstToken,
67-
trailingTrivia: .spaces(1)
68-
) as! ExprSyntax
50+
guard let _ = extractLiteral(node, typeName) else {
51+
return super.visit(node)
52+
}
6953

70-
return SyntaxFactory.makeSequenceExpr(
71-
elements: SyntaxFactory.makeExprList([
72-
newLiteral,
73-
asExpr,
74-
]))
54+
diagnose(.avoidInitializerStyleCast(node.description), on: callee) {
55+
$0.highlight(callee.sourceRange(in: self.context.fileURL))
56+
}
7557
}
7658
}
7759

@@ -89,6 +71,7 @@ fileprivate func extractLiteral(_ node: FunctionCallExprSyntax, _ typeName: Stri
8971
}
9072

9173
extension Diagnostic.Message {
92-
static let avoidInitializerStyleCast =
93-
Diagnostic.Message(.warning, "change initializer call with literal argument to an 'as' cast")
74+
static func avoidInitializerStyleCast(_ name: String) -> Diagnostic.Message {
75+
return .init(.warning, "change initializer call '\(name)' with literal argument to an 'as' cast")
76+
}
9477
}

Sources/swift-format/PopulatePipeline.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ func populate(_ pipeline: Pipeline) {
2727

2828
/// MARK: Formatting Passes
2929

30-
pipeline.addFormatter(
31-
AvoidInitializersForLiterals.self,
32-
for:
33-
FunctionCallExprSyntax.self
34-
)
35-
3630
pipeline.addFormatter(
3731
BlankLineBetweenMembers.self,
3832
for:
@@ -266,6 +260,12 @@ func populate(_ pipeline: Pipeline) {
266260
SourceFileSyntax.self
267261
)
268262

263+
pipeline.addLinter(
264+
AvoidInitializersForLiterals.self,
265+
for:
266+
FunctionCallExprSyntax.self
267+
)
268+
269269
pipeline.addLinter(
270270
BeginDocumentationCommentWithOneLineSummary.self,
271271
for:

Tests/SwiftFormatRulesTests/AvoidInitializersForLiteralsTests.swift

+21-18
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,27 @@ import XCTest
55

66
public class AvoidInitializersForLiteralsTests: DiagnosingTestCase {
77
public func testInitializersForLiterals() {
8-
XCTAssertFormatting(
9-
AvoidInitializersForLiterals.self,
10-
input: """
11-
let v1 = UInt32(76)
12-
let v2 = UInt8(257)
13-
performFunction(x: Int16(54))
14-
performFunction(x: Int32(54))
15-
performFunction(x: Int64(54))
16-
let c = Character("s")
17-
""",
18-
expected: """
19-
let v1 = 76 as UInt32
20-
let v2 = 257 as UInt8
21-
performFunction(x: 54 as Int16)
22-
performFunction(x: 54 as Int32)
23-
performFunction(x: 54 as Int64)
24-
let c = "s" as Character
25-
""")
8+
let input =
9+
"""
10+
let v1 = UInt32(76)
11+
let v2 = UInt8(257)
12+
performFunction(x: Int16(54))
13+
performFunction(x: Int32(54))
14+
performFunction(x: Int64(54))
15+
let c = Character("s")
16+
if 3 > Int(2) || someCondition {}
17+
let a = Int(bitPattern: 123456)
18+
"""
19+
20+
performLint(AvoidInitializersForLiterals.self, input: input)
21+
XCTAssertDiagnosed(.avoidInitializerStyleCast("UInt32(76)"))
22+
XCTAssertDiagnosed(.avoidInitializerStyleCast("UInt8(257)"))
23+
XCTAssertDiagnosed(.avoidInitializerStyleCast("Int16(54)"))
24+
XCTAssertDiagnosed(.avoidInitializerStyleCast("Int32(54)"))
25+
XCTAssertDiagnosed(.avoidInitializerStyleCast("Int64(54)"))
26+
XCTAssertDiagnosed(.avoidInitializerStyleCast("Character(\"s\")"))
27+
XCTAssertDiagnosed(.avoidInitializerStyleCast("Int(2) "))
28+
XCTAssertNotDiagnosed(.avoidInitializerStyleCast("Int(bitPattern: 123456)"))
2629
}
2730

2831
#if !os(macOS)

0 commit comments

Comments
 (0)