fix XCTestRule

This commit is contained in:
Roy Cao 2019-12-21 15:19:22 +08:00
parent 88b9011d45
commit bf4f13abcd
7 changed files with 54 additions and 42 deletions

View File

@ -8,7 +8,7 @@ struct AttributesRule: SourceCollectRule {
case ibaction = "IBAction" case ibaction = "IBAction"
} }
func skip(_ node: Syntax) -> Bool { func skip(_ node: Syntax, location: SourceLocation) -> Bool {
if let funcDecl = node as? FunctionDeclSyntax { if let funcDecl = node as? FunctionDeclSyntax {
return skip(funcDecl) return skip(funcDecl)
} }

View File

@ -12,7 +12,7 @@ struct CommentRule: SourceCollectRule {
static let all = "pecker:ignore all" static let all = "pecker:ignore all"
} }
func skip(_ node: Syntax) -> Bool { func skip(_ node: Syntax, location: SourceLocation) -> Bool {
guard let node = node as? ModifierSyntax else { return true } guard let node = node as? ModifierSyntax else { return true }
let comments = node.leadingTrivia?.compactMap({ $0.comment }) ?? [] let comments = node.leadingTrivia?.compactMap({ $0.comment }) ?? []
if comments.contains(where: { $0.contains(Comment.signal) }) || comments.contains(where: { $0.contains(Comment.all) }) { if comments.contains(where: { $0.contains(Comment.signal) }) || comments.contains(where: { $0.contains(Comment.all) }) {
@ -25,26 +25,26 @@ struct CommentRule: SourceCollectRule {
} }
} }
if let classDel: StructDeclSyntax = node.searchParent() { if let structDel: StructDeclSyntax = node.searchParent() {
if containAllSkip(classDel) { if containAllSkip(structDel) {
return true return true
} }
} }
if let classDel: EnumDeclSyntax = node.searchParent() { if let enumDel: EnumDeclSyntax = node.searchParent() {
if containAllSkip(classDel) { if containAllSkip(enumDel) {
return true return true
} }
} }
if let classDel: ProtocolDeclSyntax = node.searchParent() { if let protocolDel: ProtocolDeclSyntax = node.searchParent() {
if containAllSkip(classDel) { if containAllSkip(protocolDel) {
return true return true
} }
} }
if let classDel: ExtensionDeclSyntax = node.searchParent() { if let extensionDel: ExtensionDeclSyntax = node.searchParent() {
if containAllSkip(classDel) { if containAllSkip(extensionDel) {
return true return true
} }
} }

View File

@ -6,7 +6,7 @@ public protocol Rule {}
public protocol SourceCollectRule: Rule { public protocol SourceCollectRule: Rule {
func skip(_ node: Syntax) -> Bool func skip(_ node: Syntax, location: SourceLocation) -> Bool
} }
public protocol AnalyzeRule: Rule { public protocol AnalyzeRule: Rule {

View File

@ -4,7 +4,7 @@ import SwiftSyntax
/// Skip public syntax /// Skip public syntax
struct SkipPublicRule: SourceCollectRule { struct SkipPublicRule: SourceCollectRule {
func skip(_ node: Syntax) -> Bool { func skip(_ node: Syntax, location: SourceLocation) -> Bool {
if let modifierSyntax = node as? ModifierSyntax { if let modifierSyntax = node as? ModifierSyntax {
return modifierSyntax.isPublic() return modifierSyntax.isPublic()
} }

View File

@ -7,7 +7,7 @@ struct SuperClassRule: SourceCollectRule {
var blacklist: Set<String> = ["NotificationService", var blacklist: Set<String> = ["NotificationService",
"PreviewProvider"] "PreviewProvider"]
func skip(_ node: Syntax) -> Bool { func skip(_ node: Syntax, location: SourceLocation) -> Bool {
if let node = node as? InheritableSyntax { if let node = node as? InheritableSyntax {
if blacklist.contains(where: node.isInherited(from:)) { if blacklist.contains(where: node.isInherited(from:)) {
return true return true

View File

@ -4,32 +4,44 @@ import SwiftSyntax
/// The rules for UITest and UnitTests /// The rules for UITest and UnitTests
struct XCTestRule: SourceCollectRule { struct XCTestRule: SourceCollectRule {
func skip(_ node: Syntax) -> Bool { func skip(_ node: Syntax, location: SourceLocation) -> Bool {
if let clsDecl = node as? ClassDeclSyntax { if let clsDecl = node as? ClassDeclSyntax {
return skip(clsDecl) return skip(clsDecl, location: location)
} }
if let funcDecl = node as? FunctionDeclSyntax { if let funcDecl = node as? FunctionDeclSyntax {
return skip(funcDecl) return skip(funcDecl, location: location)
} }
return false return false
} }
/// If a class is Inherited from XCTestCase, skip it /// If a class is Inherited from XCTestCase, skip it
/// - Parameter node: ClassDeclSyntax /// - Parameter node: ClassDeclSyntax
func skip(_ node: ClassDeclSyntax) -> Bool { func skip(_ node: ClassDeclSyntax, location: SourceLocation) -> Bool {
return isInheritedFromXCTestCase(node) return isInheritedFromXCTestCase(node) || fuzzyRule(location: location)
} }
/// If a UITest funciton hasPrefix "test" and has parameters, skip it /// If a UITest funciton hasPrefix "test" and has parameters, skip it
/// - Parameter node: FunctionDeclSyntax /// - Parameter node: FunctionDeclSyntax
func skip(_ node: FunctionDeclSyntax) -> Bool { func skip(_ node: FunctionDeclSyntax, location: SourceLocation) -> Bool {
if let classDecl: ClassDeclSyntax = node.searchParent(), isInheritedFromXCTestCase(classDecl) { if let classDecl: ClassDeclSyntax = node.searchParent(), isInheritedFromXCTestCase(classDecl) {
if node.identifier.text.hasPrefix("test") && node.signature.input.parameterList.count == 0 { if node.identifier.text.hasPrefix("test") && node.signature.input.parameterList.count == 0 {
return true return true
} }
} }
// Fuzzy recognition
if fuzzyRule(location: location) {
if node.identifier.text.hasPrefix("test") && node.signature.input.parameterList.count == 0 {
return true
}
}
return false return false
} }
private func fuzzyRule(location: SourceLocation) -> Bool {
let array = location.description.components(separatedBy: "/")
return array.contains(where: { $0.hasSuffix("Tests") })
}
} }
private func isInheritedFromXCTestCase(_ node: ClassDeclSyntax) -> Bool { private func isInheritedFromXCTestCase(_ node: ClassDeclSyntax) -> Bool {

View File

@ -14,74 +14,74 @@ class SwiftSourceCollectPipeline: SyntaxVisitor {
} }
func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren return .visitChildren
} }
if let position = findLocaiton(syntax: node.identifier) {
collect(SourceDetail(name: node.identifier.text, sourceKind: .class, location: position)) collect(SourceDetail(name: node.identifier.text, sourceKind: .class, location: position))
} }
return .visitChildren return .visitChildren
} }
func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren return .visitChildren
} }
if let position = findLocaiton(syntax: node.identifier) {
collect(SourceDetail(name: node.identifier.text, sourceKind: .struct, location: position)) collect(SourceDetail(name: node.identifier.text, sourceKind: .struct, location: position))
} }
return .visitChildren return .visitChildren
} }
func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) {
return .visitChildren
}
let ps = node.signature.input.parameterList.compactMap { let ps = node.signature.input.parameterList.compactMap {
$0.firstName?.text $0.firstName?.text
} }
let function = Function(name: node.identifier.text, parameters: ps) let function = Function(name: node.identifier.text, parameters: ps)
if let position = findLocaiton(syntax: node.identifier) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren
}
collect(SourceDetail(name: function.description, sourceKind: .function, location: position)) collect(SourceDetail(name: function.description, sourceKind: .function, location: position))
} }
return .visitChildren return .visitChildren
} }
func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren return .visitChildren
} }
if let position = findLocaiton(syntax: node.identifier) {
collect(SourceDetail(name: node.identifier.text, sourceKind: .enum, location: position)) collect(SourceDetail(name: node.identifier.text, sourceKind: .enum, location: position))
} }
return .visitChildren return .visitChildren
} }
func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: ProtocolDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren return .visitChildren
} }
if let position = findLocaiton(syntax: node.identifier) {
collect(SourceDetail(name: node.identifier.text, sourceKind: .protocol, location: position)) collect(SourceDetail(name: node.identifier.text, sourceKind: .protocol, location: position))
} }
return .visitChildren return .visitChildren
} }
func visit(_ node: TypealiasDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: TypealiasDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren return .visitChildren
} }
if let position = findLocaiton(syntax: node.identifier) {
collect(SourceDetail(name: node.identifier.text, sourceKind: .typealias, location: position)) collect(SourceDetail(name: node.identifier.text, sourceKind: .typealias, location: position))
} }
return .visitChildren return .visitChildren
} }
func visit(_ node: OperatorDeclSyntax) -> SyntaxVisitorContinueKind { func visit(_ node: OperatorDeclSyntax) -> SyntaxVisitorContinueKind {
if skip(syntax: node) { if let position = findLocaiton(syntax: node.identifier) {
if skip(syntax: node, location: position) {
return .visitChildren return .visitChildren
} }
if let position = findLocaiton(syntax: node.identifier) {
collect(SourceDetail(name: node.identifier.text, sourceKind: .operator, location: position)) collect(SourceDetail(name: node.identifier.text, sourceKind: .operator, location: position))
} }
return .visitChildren return .visitChildren
@ -100,13 +100,13 @@ class SwiftSourceCollectPipeline: SyntaxVisitor {
extension SwiftSourceCollectPipeline { extension SwiftSourceCollectPipeline {
func skip(syntax: IdentifierSyntax) -> Bool { func skip(syntax: IdentifierSyntax, location: SourceLocation) -> Bool {
// Skip the symbol in blacklist // Skip the symbol in blacklist
if context.configuration.blacklistSymbols.contains(syntax.identifier.text) { if context.configuration.blacklistSymbols.contains(syntax.identifier.text) {
return true return true
} }
// Rules check // Rules check
if rules.contains(where: { $0.skip(syntax) }) { if rules.contains(where: { $0.skip(syntax, location: location) }) {
return true return true
} }
return false return false