|
13 | 13 | import SwiftFormatCore |
14 | 14 | import SwiftSyntax |
15 | 15 |
|
16 | | -/// Visitor that determines if the target source file imports XCTest |
17 | | -fileprivate class ImportsXCTestVisitor: SyntaxVisitor { |
| 16 | +/// A visitor that determines if the target source file imports `XCTest`. |
| 17 | +private class ImportsXCTestVisitor: SyntaxVisitor { |
18 | 18 | private let context: Context |
19 | 19 |
|
20 | 20 | init(context: Context) { |
21 | 21 | self.context = context |
22 | 22 | super.init(viewMode: .sourceAccurate) |
23 | 23 | } |
24 | 24 |
|
25 | | - override func visit(_ node: SourceFileSyntax) -> SyntaxVisitorContinueKind { |
26 | | - for statement in node.statements { |
27 | | - guard let importDecl = statement.item.as(ImportDeclSyntax.self) else { continue } |
28 | | - for component in importDecl.path { |
29 | | - guard component.name.text == "XCTest" else { continue } |
30 | | - context.importsXCTest = .importsXCTest |
31 | | - return .skipChildren |
32 | | - } |
| 25 | + override func visit(_ node: ImportDeclSyntax) -> SyntaxVisitorContinueKind { |
| 26 | + // If we already know whether or not `XCTest` is imported, don't bother doing anything else. |
| 27 | + guard context.importsXCTest == .notDetermined else { return .skipChildren } |
| 28 | + |
| 29 | + // If the first import path component is the `XCTest` module, record that fact. Checking in this |
| 30 | + // way lets us catch `import XCTest` but also specific decl imports like |
| 31 | + // `import class XCTest.XCTestCase`, if someone wants to do that. |
| 32 | + if node.path.first!.name.tokenKind == .identifier("XCTest") { |
| 33 | + context.importsXCTest = .importsXCTest |
33 | 34 | } |
34 | | - context.importsXCTest = .doesNotImportXCTest |
| 35 | + |
35 | 36 | return .skipChildren |
36 | 37 | } |
| 38 | + |
| 39 | + override func visitPost(_ node: SourceFileSyntax) { |
| 40 | + // If we visited the entire source file and didn't find an `XCTest` import, record that fact. |
| 41 | + if context.importsXCTest == .notDetermined { |
| 42 | + context.importsXCTest = .doesNotImportXCTest |
| 43 | + } |
| 44 | + } |
37 | 45 | } |
38 | 46 |
|
39 | | -/// Sets the appropriate value of the importsXCTest field in the Context class, which |
40 | | -/// indicates whether the file contains test code or not. |
| 47 | +/// Sets the appropriate value of the `importsXCTest` field in the context, which approximates |
| 48 | +/// whether the file contains test code or not. |
41 | 49 | /// |
42 | 50 | /// This setter will only run the visitor if another rule hasn't already called this function to |
43 | | -/// determine if the source file imports XCTest. |
| 51 | +/// determine if the source file imports `XCTest`. |
44 | 52 | /// |
45 | 53 | /// - Parameters: |
46 | 54 | /// - context: The context information of the target source file. |
47 | 55 | /// - sourceFile: The file to be visited. |
48 | | -func setImportsXCTest(context: Context, sourceFile: SourceFileSyntax) { |
| 56 | +public func setImportsXCTest(context: Context, sourceFile: SourceFileSyntax) { |
49 | 57 | guard context.importsXCTest == .notDetermined else { return } |
50 | 58 | let visitor = ImportsXCTestVisitor(context: context) |
51 | 59 | visitor.walk(sourceFile) |
|
0 commit comments