|
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