1111//===----------------------------------------------------------------------===//
1212
1313import Foundation
14+ import SwiftFormatCore
1415import SwiftSyntax
1516
1617// These rules will not be added to the pipeline.
@@ -19,7 +20,7 @@ let suppressRules = ["UseEarlyExits", "UseWhereClausesInForLoops"]
1920/// Collects information about rules in the formatter code base.
2021final class RuleCollector {
2122 /// Information about a detected rule.
22- private struct DetectedRule {
23+ struct DetectedRule : Hashable {
2324 /// The type name of the rule.
2425 let typeName : String
2526
@@ -28,13 +29,16 @@ final class RuleCollector {
2829
2930 /// Indicates whether the rule can format code (all rules can lint).
3031 let canFormat : Bool
32+
33+ /// Indicates whether the rule is disabled by default, i.e. requires opting in to use it.
34+ let isOptIn : Bool
3135 }
3236
3337 /// A list of all rules that can lint (thus also including format rules) found in the code base.
34- var allLinters = Set < String > ( )
38+ var allLinters = Set < DetectedRule > ( )
3539
3640 /// A list of all the format-only rules found in the code base.
37- var allFormatters = Set < String > ( )
41+ var allFormatters = Set < DetectedRule > ( )
3842
3943 /// A dictionary mapping syntax node types to the lint/format rules that visit them.
4044 var syntaxNodeLinters = [ String: [ String] ] ( )
@@ -63,13 +67,13 @@ final class RuleCollector {
6367 if detectedRule. canFormat {
6468 // Format rules just get added to their own list; we run them each over the entire tree in
6569 // succession.
66- allFormatters. insert ( detectedRule. typeName )
70+ allFormatters. insert ( detectedRule)
6771 }
6872
6973 // Lint rules (this includes format rules, which can also lint) get added to a mapping over
7074 // the names of the types they touch so that they can be interleaved into one pass over the
7175 // tree.
72- allLinters. insert ( detectedRule. typeName )
76+ allLinters. insert ( detectedRule)
7377 for visitedNode in detectedRule. visitedNodes {
7478 syntaxNodeLinters [ visitedNode, default: [ ] ] . append ( detectedRule. typeName)
7579 }
@@ -132,7 +136,12 @@ final class RuleCollector {
132136 /// Ignore it if it doesn't have any; there's no point in putting no-op rules in the pipeline.
133137 /// Otherwise, return it (we don't need to look at the rest of the inheritances).
134138 guard !visitedNodes. isEmpty else { return nil }
135- return DetectedRule ( typeName: typeName, visitedNodes: visitedNodes, canFormat: canFormat)
139+ guard let ruleType = _typeByName ( " SwiftFormatRules. \( typeName) " ) as? Rule . Type else {
140+ preconditionFailure ( " Failed to find type for rule named \( typeName) " )
141+ }
142+ return DetectedRule (
143+ typeName: typeName, visitedNodes: visitedNodes, canFormat: canFormat,
144+ isOptIn: ruleType. isOptIn)
136145 }
137146
138147 return nil
0 commit comments