@@ -47,7 +47,7 @@ public final class UseExplicitNilCheckInConditions: SyntaxFormatRule {
47
47
operatorExpr. trailingTrivia = [ . spaces( 1 ) ]
48
48
49
49
var inequalExpr = InfixOperatorExprSyntax (
50
- leftOperand: value,
50
+ leftOperand: addingParenthesesIfNecessary ( to : value) ,
51
51
operator: operatorExpr,
52
52
rightOperand: NilLiteralExprSyntax ( ) )
53
53
inequalExpr. leadingTrivia = node. leadingTrivia
@@ -69,6 +69,54 @@ public final class UseExplicitNilCheckInConditions: SyntaxFormatRule {
69
69
}
70
70
return exprPattern. expression. is ( DiscardAssignmentExprSyntax . self)
71
71
}
72
+
73
+ /// Adds parentheses around the given expression if necessary to ensure that it will be parsed
74
+ /// correctly when followed by `!= nil`.
75
+ ///
76
+ /// Specifically, if `expr` is a `try` expression, ternary expression, or an infix operator with
77
+ /// the same or lower precedence, we wrap it.
78
+ private func addingParenthesesIfNecessary( to expr: ExprSyntax ) -> ExprSyntax {
79
+ func addingParentheses( to expr: ExprSyntax ) -> ExprSyntax {
80
+ var expr = expr
81
+ let leadingTrivia = expr. leadingTrivia
82
+ let trailingTrivia = expr. trailingTrivia
83
+ expr. leadingTrivia = [ ]
84
+ expr. trailingTrivia = [ ]
85
+
86
+ var tupleExpr = TupleExprSyntax ( elements: [ LabeledExprSyntax ( expression: expr) ] )
87
+ tupleExpr. leadingTrivia = leadingTrivia
88
+ tupleExpr. trailingTrivia = trailingTrivia
89
+ return ExprSyntax ( tupleExpr)
90
+ }
91
+
92
+ switch Syntax ( expr) . as ( SyntaxEnum . self) {
93
+ case . tryExpr, . ternaryExpr:
94
+ return addingParentheses ( to: expr)
95
+
96
+ case . infixOperatorExpr:
97
+ // There's no public API in SwiftSyntax to get the relationship between two precedence groups.
98
+ // Until that exists, here's a workaround I'm only mildly ashamed of: we reparse
99
+ // "\(expr) != nil" and then fold it. If the top-level node is anything but an
100
+ // `InfixOperatorExpr` whose operator is `!=` and whose RHS is `nil`, then it parsed
101
+ // incorrectly and we need to add parentheses around `expr`.
102
+ //
103
+ // Note that we could also cover the `tryExpr` and `ternaryExpr` cases above with this, but
104
+ // this reparsing trick is going to be slower so we should avoid it whenever we can.
105
+ let reparsedExpr = " \( expr) != nil " as ExprSyntax
106
+ if
107
+ let infixExpr = reparsedExpr. as ( InfixOperatorExprSyntax . self) ,
108
+ let binOp = infixExpr. operator. as ( BinaryOperatorExprSyntax . self) ,
109
+ binOp. operator. text == " != " ,
110
+ infixExpr. rightOperand. is ( NilLiteralExprSyntax . self)
111
+ {
112
+ return expr
113
+ }
114
+ return addingParentheses ( to: expr)
115
+
116
+ default :
117
+ return expr
118
+ }
119
+ }
72
120
}
73
121
74
122
extension Finding . Message {
0 commit comments