|
14 | 14 | (contract-out |
15 | 15 | [refactoring-rule? (-> any/c boolean?)] |
16 | 16 | [refactoring-rule-description (-> refactoring-rule? immutable-string?)] |
| 17 | + [refactoring-rule-analyzers (-> refactoring-rule? (set/c expansion-analyzer?))] |
17 | 18 | [refactoring-suite? (-> any/c boolean?)] |
18 | 19 | [refactoring-suite |
19 | 20 | (->* () |
20 | 21 | (#:rules (sequence/c refactoring-rule?) #:name (or/c interned-symbol? #false)) |
21 | 22 | refactoring-suite?)] |
22 | | - [refactoring-suite-rules (-> refactoring-suite? (listof refactoring-rule?))])) |
| 23 | + [refactoring-suite-rules (-> refactoring-suite? (listof refactoring-rule?))] |
| 24 | + [refactoring-suite-analyzers (-> refactoring-suite? (set/c expansion-analyzer?))])) |
23 | 25 |
|
24 | 26 |
|
25 | 27 | (module+ private |
|
33 | 35 | racket/list |
34 | 36 | racket/syntax |
35 | 37 | resyntax/private/more-syntax-parse-classes) |
| 38 | + racket/list |
36 | 39 | racket/sequence |
| 40 | + racket/set |
37 | 41 | rebellion/base/immutable-string |
38 | 42 | rebellion/base/option |
39 | 43 | rebellion/base/symbol |
40 | 44 | rebellion/type/object |
| 45 | + resyntax/default-recommendations/analyzers/identifier-usage |
| 46 | + resyntax/default-recommendations/analyzers/ignored-result-values |
| 47 | + resyntax/default-recommendations/analyzers/variable-mutability |
41 | 48 | resyntax/default-recommendations/private/definition-context |
| 49 | + resyntax/private/analyzer |
42 | 50 | resyntax/private/logger |
43 | 51 | resyntax/private/source |
44 | 52 | resyntax/private/syntax-neighbors |
|
98 | 106 | [(_ new-stx) (syntax-property #'new-stx 'focus-replacement-on #true)])) |
99 | 107 |
|
100 | 108 |
|
101 | | -(define-object-type refactoring-rule (transformer description uses-universal-tagged-syntax?) |
| 109 | +(define-object-type refactoring-rule (transformer description uses-universal-tagged-syntax? analyzers) |
102 | 110 | #:omit-root-binding |
103 | 111 | #:constructor-name constructor:refactoring-rule) |
104 | 112 |
|
|
149 | 157 | #:name 'id |
150 | 158 | #:description (string->immutable-string description.c) |
151 | 159 | #:uses-universal-tagged-syntax? (~? uses-universal-tagged-syntax? #false) |
| 160 | + #:analyzers (set identifier-usage-analyzer |
| 161 | + ignored-result-values-analyzer |
| 162 | + variable-mutability-analyzer) |
152 | 163 | #:transformer |
153 | 164 | (λ (stx) |
154 | 165 | (syntax-parse stx |
|
218 | 229 | expression.refactored))) |
219 | 230 |
|
220 | 231 |
|
221 | | -(define-object-type refactoring-suite (rules) |
| 232 | +(define-object-type refactoring-suite (rules analyzers) |
222 | 233 | #:constructor-name constructor:refactoring-suite |
223 | 234 | #:omit-root-binding) |
224 | 235 |
|
225 | 236 |
|
226 | 237 | (define (refactoring-suite #:rules [rules '()] #:name [name #false]) |
227 | | - (constructor:refactoring-suite #:rules (sequence->list rules) #:name name)) |
| 238 | + (define rule-list (sequence->list rules)) |
| 239 | + (define combined-analyzers |
| 240 | + (for*/set ([rule (in-list rule-list)] |
| 241 | + [analyzer (in-set (refactoring-rule-analyzers rule))]) |
| 242 | + analyzer)) |
| 243 | + (constructor:refactoring-suite #:rules rule-list #:analyzers combined-analyzers #:name name)) |
228 | 244 |
|
229 | 245 |
|
230 | 246 | (begin-for-syntax |
|
249 | 265 | (refactoring-suite |
250 | 266 | #:name 'id |
251 | 267 | #:rules (append rules.as-list-expr suites.as-list-expr)))) |
| 268 | + |
| 269 | + |
| 270 | +(module+ test |
| 271 | + (require rackunit |
| 272 | + resyntax/private/analyzer) |
| 273 | + |
| 274 | + (test-case "refactoring-rule stores analyzers" |
| 275 | + (define-refactoring-rule test-rule |
| 276 | + #:description "test rule" |
| 277 | + pattern |
| 278 | + replacement) |
| 279 | + |
| 280 | + (check-true (refactoring-rule? test-rule)) |
| 281 | + (check-true (set? (refactoring-rule-analyzers test-rule))) |
| 282 | + (check-equal? (set-count (refactoring-rule-analyzers test-rule)) 3) |
| 283 | + (check-true (for/and ([analyzer (in-set (refactoring-rule-analyzers test-rule))]) |
| 284 | + (expansion-analyzer? analyzer)))) |
| 285 | + |
| 286 | + (test-case "refactoring-suite combines analyzers from rules" |
| 287 | + (define-refactoring-rule rule1 |
| 288 | + #:description "rule 1" |
| 289 | + pattern1 |
| 290 | + replacement1) |
| 291 | + |
| 292 | + (define-refactoring-rule rule2 |
| 293 | + #:description "rule 2" |
| 294 | + pattern2 |
| 295 | + replacement2) |
| 296 | + |
| 297 | + (define suite (refactoring-suite #:rules (list rule1 rule2))) |
| 298 | + |
| 299 | + (check-true (refactoring-suite? suite)) |
| 300 | + (check-equal? (length (refactoring-suite-rules suite)) 2) |
| 301 | + (check-true (set? (refactoring-suite-analyzers suite))) |
| 302 | + ;; All rules have the same analyzers, so the combined set should have 3 unique analyzers |
| 303 | + (check-equal? (set-count (refactoring-suite-analyzers suite)) 3) |
| 304 | + (check-true (for/and ([analyzer (in-set (refactoring-suite-analyzers suite))]) |
| 305 | + (expansion-analyzer? analyzer)))) |
| 306 | + |
| 307 | + (test-case "nested suites combine analyzers correctly" |
| 308 | + (define-refactoring-rule inner-rule |
| 309 | + #:description "inner rule" |
| 310 | + inner-pattern |
| 311 | + inner-replacement) |
| 312 | + |
| 313 | + (define inner-suite (refactoring-suite #:rules (list inner-rule))) |
| 314 | + |
| 315 | + (define-refactoring-rule outer-rule |
| 316 | + #:description "outer rule" |
| 317 | + outer-pattern |
| 318 | + outer-replacement) |
| 319 | + |
| 320 | + (define outer-suite (refactoring-suite #:rules (list outer-rule inner-rule))) |
| 321 | + |
| 322 | + (check-equal? (set-count (refactoring-suite-analyzers inner-suite)) 3) |
| 323 | + ;; Both rules have the same analyzers, so deduplicated should still be 3 |
| 324 | + (check-equal? (set-count (refactoring-suite-analyzers outer-suite)) 3)) |
| 325 | + |
| 326 | + (test-case "define-refactoring-suite with nested suites preserves analyzers" |
| 327 | + (define-refactoring-rule rule-a |
| 328 | + #:description "Rule A" |
| 329 | + pattern-a |
| 330 | + replacement-a) |
| 331 | + |
| 332 | + (define-refactoring-suite suite-a |
| 333 | + #:rules (rule-a)) |
| 334 | + |
| 335 | + (define-refactoring-rule rule-b |
| 336 | + #:description "Rule B" |
| 337 | + pattern-b |
| 338 | + replacement-b) |
| 339 | + |
| 340 | + (define-refactoring-suite suite-b |
| 341 | + #:rules (rule-b) |
| 342 | + #:suites (suite-a)) |
| 343 | + |
| 344 | + ;; Suite B should have both rules |
| 345 | + (check-equal? (length (refactoring-suite-rules suite-b)) 2) |
| 346 | + ;; And should have 3 analyzers (deduplicated from both rules) |
| 347 | + (check-equal? (set-count (refactoring-suite-analyzers suite-b)) 3) |
| 348 | + (check-true (for/and ([analyzer (in-set (refactoring-suite-analyzers suite-b))]) |
| 349 | + (expansion-analyzer? analyzer))))) |
0 commit comments