Skip to content

Commit 8ef3b43

Browse files
authored
Merge pull request swiftlang#226 from dylansturg/fewer_linter_allocs
Allocate 1 instance of each rule per LintPipeline.
2 parents 5461498 + d0e96a4 commit 8ef3b43

File tree

3 files changed

+123
-99
lines changed

3 files changed

+123
-99
lines changed

Sources/SwiftFormat/LintPipeline.swift

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ extension LintPipeline {
2727
/// - node: The syntax node on which the rule will be applied. This lets us check whether the
2828
/// rule is enabled for the particular source range where the node occurs.
2929
func visitIfEnabled<Rule: SyntaxLintRule, Node: SyntaxProtocol>(
30-
_ visitor: (Rule) -> (Node) -> SyntaxVisitorContinueKind, in context: Context, for node: Node
30+
_ visitor: (Rule) -> (Node) -> SyntaxVisitorContinueKind, for node: Node
3131
) {
3232
guard context.isRuleEnabled(Rule.self.ruleName, node: Syntax(node)) else { return }
33-
let rule = Rule(context: context)
33+
let rule = self.rule(Rule.self)
3434
_ = visitor(rule)(node)
3535
}
3636

@@ -44,14 +44,30 @@ extension LintPipeline {
4444
/// - node: The syntax node on which the rule will be applied. This lets us check whether the
4545
/// rule is enabled for the particular source range where the node occurs.
4646
func visitIfEnabled<Rule: SyntaxFormatRule, Node: SyntaxProtocol>(
47-
_ visitor: (Rule) -> (Node) -> Any, in context: Context, for node: Node
47+
_ visitor: (Rule) -> (Node) -> Any, for node: Node
4848
) {
4949
// Note that visitor function type is expressed as `Any` because we ignore the return value, but
5050
// more importantly because the `visit` methods return protocol refinements of `Syntax` that
5151
// cannot currently be expressed as constraints without duplicating this function for each of
5252
// them individually.
5353
guard context.isRuleEnabled(Rule.self.ruleName, node: Syntax(node)) else { return }
54-
let rule = Rule(context: context)
54+
let rule = self.rule(Rule.self)
5555
_ = visitor(rule)(node)
5656
}
57+
58+
/// Retrieves an instance of a lint or format rule based on its type.
59+
///
60+
/// There is at most 1 instance of each rule allocated per `LintPipeline`. This method will
61+
/// create that instance as needed, using `ruleCache` to cache rules.
62+
/// - Parameter type: The type of the rule to retrieve.
63+
/// - Returns: An instance of the given type.
64+
private func rule<R: Rule>(_ type: R.Type) -> R {
65+
let identifier = ObjectIdentifier(type)
66+
if let cachedRule = ruleCache[identifier] {
67+
return cachedRule as! R
68+
}
69+
let rule = R(context: context)
70+
ruleCache[identifier] = rule
71+
return rule
72+
}
5773
}

0 commit comments

Comments
 (0)