Skip to content

Commit 0050b48

Browse files
committed
Clean up XCTest import state representation.
1 parent c74c6dd commit 0050b48

File tree

5 files changed

+25
-15
lines changed

5 files changed

+25
-15
lines changed

Sources/SwiftFormatCore/Context.swift

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ import SwiftSyntax
1919
/// Specifically, it is the container for the shared configuration, diagnostic engine, and URL of
2020
/// the current file.
2121
public class Context {
22+
23+
/// Tracks whether `XCTest` has been imported so that certain logic can be modified for files that
24+
/// are known to be tests.
25+
public enum XCTestImportState {
26+
27+
/// Whether `XCTest` is imported or not has not yet been determined.
28+
case notDetermined
29+
30+
/// The file is known to import `XCTest`.
31+
case importsXCTest
32+
33+
/// The file is known to not import `XCTest`.
34+
case doesNotImportXCTest
35+
}
36+
2237
/// The configuration for this run of the pipeline, provided by a configuration JSON file.
2338
public let configuration: Configuration
2439

@@ -28,11 +43,8 @@ public class Context {
2843
/// The URL of the file being linted or formatted.
2944
public let fileURL: URL
3045

31-
/// Indicates whether the file imports XCTest, and is test code
32-
public var importsXCTest: Bool
33-
34-
/// Indicates whether the visitor has already determined a value for importsXCTest
35-
public var didSetImportsXCTest: Bool
46+
/// Indicates whether the file is known to import XCTest.
47+
public var importsXCTest: XCTestImportState
3648

3749
/// An object that converts `AbsolutePosition` values to `SourceLocation` values.
3850
public let sourceLocationConverter: SourceLocationConverter
@@ -50,8 +62,7 @@ public class Context {
5062
self.configuration = configuration
5163
self.diagnosticEngine = diagnosticEngine
5264
self.fileURL = fileURL
53-
self.importsXCTest = false
54-
self.didSetImportsXCTest = false
65+
self.importsXCTest = .notDetermined
5566
self.sourceLocationConverter = SourceLocationConverter(
5667
file: fileURL.path, tree: sourceFileSyntax)
5768
self.ruleMask = RuleMask(

Sources/SwiftFormatRules/ImportsXCTestVisitor.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,11 @@ private struct ImportsXCTestVisitor: SyntaxVisitor {
2727
guard let importDecl = statement.item as? ImportDeclSyntax else { continue }
2828
for component in importDecl.path {
2929
guard component.name.text == "XCTest" else { continue }
30-
context.importsXCTest = true
31-
context.didSetImportsXCTest = true
30+
context.importsXCTest = .importsXCTest
3231
return .skipChildren
3332
}
3433
}
35-
context.didSetImportsXCTest = true
34+
context.importsXCTest = .doesNotImportXCTest
3635
return .skipChildren
3736
}
3837
}
@@ -47,7 +46,7 @@ private struct ImportsXCTestVisitor: SyntaxVisitor {
4746
/// - context: The context information of the target source file.
4847
/// - sourceFile: The file to be visited.
4948
func setImportsXCTest(context: Context, sourceFile: SourceFileSyntax) {
50-
guard !context.didSetImportsXCTest else { return }
49+
guard context.importsXCTest == .notDetermined else { return }
5150
var visitor = ImportsXCTestVisitor(context: context)
5251
sourceFile.walk(&visitor)
5352
}

Sources/SwiftFormatRules/NeverForceUnwrap.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ public struct NeverForceUnwrap: SyntaxLintRule {
3434
}
3535

3636
public func visit(_ node: ForcedValueExprSyntax) -> SyntaxVisitorContinueKind {
37-
guard !context.importsXCTest else { return .skipChildren }
37+
guard context.importsXCTest == .doesNotImportXCTest else { return .skipChildren }
3838
diagnose(.doNotForceUnwrap(name: node.expression.description), on: node)
3939
return .skipChildren
4040
}
4141

4242
public func visit(_ node: AsExprSyntax) -> SyntaxVisitorContinueKind {
4343
// Only fire if we're not in a test file and if there is an exclamation mark following the `as`
4444
// keyword.
45-
guard !context.importsXCTest else { return .skipChildren }
45+
guard context.importsXCTest == .doesNotImportXCTest else { return .skipChildren }
4646
guard let questionOrExclamation = node.questionOrExclamationMark else { return .skipChildren }
4747
guard questionOrExclamation.tokenKind == .exclamationMark else { return .skipChildren }
4848
diagnose(.doNotForceCast(name: node.typeName.description), on: node)

Sources/SwiftFormatRules/NeverUseForceTry.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public struct NeverUseForceTry: SyntaxLintRule {
4141
// TODO: Generalize the `isRuleDisabled` check so it doesn't need to be performed manually for
4242
// each rule.
4343
guard !context.isRuleDisabled(self.ruleName, node: node) else { return .visitChildren }
44-
guard !context.importsXCTest else { return .skipChildren }
44+
guard context.importsXCTest == .doesNotImportXCTest else { return .skipChildren }
4545
guard let mark = node.questionOrExclamationMark else { return .visitChildren }
4646
if mark.tokenKind == .exclamationMark {
4747
diagnose(.doNotForceTry, on: node.tryKeyword)

Sources/SwiftFormatRules/NeverUseImplicitlyUnwrappedOptionals.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public struct NeverUseImplicitlyUnwrappedOptionals: SyntaxLintRule {
4141
}
4242

4343
public func visit(_ node: VariableDeclSyntax) -> SyntaxVisitorContinueKind {
44-
guard !context.importsXCTest else { return .skipChildren }
44+
guard context.importsXCTest == .doesNotImportXCTest else { return .skipChildren }
4545
// Ignores IBOutlet variables
4646
if let attributes = node.attributes {
4747
for attribute in attributes {

0 commit comments

Comments
 (0)