@@ -29,8 +29,13 @@ extension LintPipeline {
2929 _ visitor: ( Rule ) -> ( Node ) -> SyntaxVisitorContinueKind , for node: Node
3030 ) {
3131 guard context. isRuleEnabled ( Rule . self, node: Syntax ( node) ) else { return }
32+ let ruleId = ObjectIdentifier ( Rule . self)
33+ guard self . shouldSkipChildren [ ruleId] == nil else { return }
3234 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+ }
3439 }
3540
3641 /// 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 {
5055 // cannot currently be expressed as constraints without duplicating this function for each of
5156 // them individually.
5257 guard context. isRuleEnabled ( Rule . self, node: Syntax ( node) ) else { return }
58+ guard self . shouldSkipChildren [ ObjectIdentifier ( Rule . self) ] == nil else { return }
5359 let rule = self . rule ( Rule . self)
5460 _ = visitor ( rule) ( node)
5561 }
5662
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+
5779 /// Retrieves an instance of a lint or format rule based on its type.
5880 ///
5981 /// There is at most 1 instance of each rule allocated per `LintPipeline`. This method will
0 commit comments