Skip to content

Commit 92bd26c

Browse files
authored
Disallow @Test on member functions of XCTestCase subclasses. (#626)
This PR adds a diagnostic if we detect that `@Test` has been used on a member function of an `XCTestCase` subclass. This was meant to be disallowed, but we neglected to add a check after adopting `lexicalContext`. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent 3fc7f59 commit 92bd26c

File tree

3 files changed

+19
-1
lines changed

3 files changed

+19
-1
lines changed

Diff for: Sources/TestingMacros/SuiteDeclarationMacro.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ public struct SuiteDeclarationMacro: MemberMacro, PeerMacro, Sendable {
6363
diagnostics += diagnoseIssuesWithLexicalContext(context.lexicalContext, containing: declaration, attribute: suiteAttribute)
6464
diagnostics += diagnoseIssuesWithLexicalContext(declaration, containing: declaration, attribute: suiteAttribute)
6565

66-
// Suites inheriting from XCTestCase are not supported.
66+
// Suites inheriting from XCTestCase are not supported. This check is
67+
// duplicated in TestDeclarationMacro but is not part of
68+
// diagnoseIssuesWithLexicalContext() because it doesn't need to recurse
69+
// across the entire lexical context list, just the innermost type
70+
// declaration.
6771
if let declaration = declaration.asProtocol((any DeclGroupSyntax).self),
6872
declaration.inherits(fromTypeNamed: "XCTestCase", inModuleNamed: "XCTest") {
6973
diagnostics.append(.xcTestCaseNotSupported(declaration, whenUsing: suiteAttribute))

Diff for: Sources/TestingMacros/TestDeclarationMacro.swift

+10
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ public struct TestDeclarationMacro: PeerMacro, Sendable {
5959
// Check if the lexical context is appropriate for a suite or test.
6060
diagnostics += diagnoseIssuesWithLexicalContext(context.lexicalContext, containing: declaration, attribute: testAttribute)
6161

62+
// Suites inheriting from XCTestCase are not supported. We are a bit
63+
// conservative here in this check and only check the immediate context.
64+
// Presumably, if there's an intermediate lexical context that is *not* a
65+
// type declaration, then it must be a function or closure (disallowed
66+
// elsewhere) and thus the test function is not a member of any type.
67+
if let containingTypeDecl = context.lexicalContext.first?.asProtocol((any DeclGroupSyntax).self),
68+
containingTypeDecl.inherits(fromTypeNamed: "XCTestCase", inModuleNamed: "XCTest") {
69+
diagnostics.append(.containingNodeUnsupported(containingTypeDecl, whenUsing: testAttribute, on: declaration))
70+
}
71+
6272
// Only one @Test attribute is supported.
6373
let suiteAttributes = function.attributes(named: "Test")
6474
if suiteAttributes.count > 1 {

Diff for: Tests/TestingMacrosTests/TestDeclarationMacroTests.swift

+4
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ struct TestDeclarationMacroTests {
8282
"Attribute 'Suite' cannot be applied to a subclass of 'XCTestCase'",
8383
"@Suite final class C: XCTest.XCTestCase {}":
8484
"Attribute 'Suite' cannot be applied to a subclass of 'XCTestCase'",
85+
"final class C: XCTestCase { @Test func f() {} }":
86+
"Attribute 'Test' cannot be applied to a function within class 'C'",
87+
"final class C: XCTest.XCTestCase { @Test func f() {} }":
88+
"Attribute 'Test' cannot be applied to a function within class 'C'",
8589
8690
// Unsupported inheritance
8791
"@Suite protocol P {}":

0 commit comments

Comments
 (0)