@@ -29,8 +29,13 @@ extension LintPipeline {
29
29
_ visitor: ( Rule ) -> ( Node ) -> SyntaxVisitorContinueKind , for node: Node
30
30
) {
31
31
guard context. isRuleEnabled ( Rule . self, node: Syntax ( node) ) else { return }
32
+ let ruleId = ObjectIdentifier ( Rule . self)
33
+ guard self . shouldSkipChildren [ ruleId] == nil else { return }
32
34
let rule = self . rule ( Rule . self)
33
- _ = visitor ( rule) ( node)
35
+ let continueKind = visitor ( rule) ( node)
36
+ if case . skipChildren = continueKind {
37
+ self . shouldSkipChildren [ ruleId] = node
38
+ }
34
39
}
35
40
36
41
/// Calls the `visit` method of a rule for the given node if that rule is enabled for the node.
@@ -50,10 +55,27 @@ extension LintPipeline {
50
55
// cannot currently be expressed as constraints without duplicating this function for each of
51
56
// them individually.
52
57
guard context. isRuleEnabled ( Rule . self, node: Syntax ( node) ) else { return }
58
+ guard self . shouldSkipChildren [ ObjectIdentifier ( Rule . self) ] == nil else { return }
53
59
let rule = self . rule ( Rule . self)
54
60
_ = visitor ( rule) ( node)
55
61
}
56
62
63
+ /// Cleans up any state associated with `rule` when we leave syntax node `node`
64
+ ///
65
+ /// - Parameters:
66
+ /// - rule: The type of the syntax rule we're cleaning up.
67
+ /// - node: The syntax node htat our traversal has left.
68
+ func onVisitPost< R: Rule , Node: SyntaxProtocol > (
69
+ rule: R . Type , for node: Node
70
+ ) {
71
+ let rule = ObjectIdentifier ( rule)
72
+ if case . some( let skipNode) = self . shouldSkipChildren [ rule] {
73
+ if node. id == skipNode. id {
74
+ self . shouldSkipChildren. removeValue ( forKey: rule)
75
+ }
76
+ }
77
+ }
78
+
57
79
/// Retrieves an instance of a lint or format rule based on its type.
58
80
///
59
81
/// There is at most 1 instance of each rule allocated per `LintPipeline`. This method will
0 commit comments