diff --git a/default-recommendations/for-loop-shortcuts-test.rkt b/default-recommendations/for-loop-shortcuts-test.rkt index ec70a73..07c4f67 100644 --- a/default-recommendations/for-loop-shortcuts-test.rkt +++ b/default-recommendations/for-loop-shortcuts-test.rkt @@ -788,3 +788,14 @@ test: "(unless ...) in a for* loop refactored to #:when clause" #:unless (number? x)) (displayln x)) ------------------------------------------------------------ + + +test: "in-range with add1 in a for loop can be refactored to in-inclusive-range" +------------------------------------------------------------ +(for ([i (in-range 1 (add1 5))]) + (displayln i)) +------------------------------------------------------------ +------------------------------------------------------------ +(for ([i (in-inclusive-range 1 5)]) + (displayln i)) +------------------------------------------------------------ diff --git a/default-recommendations/for-loop-shortcuts.rkt b/default-recommendations/for-loop-shortcuts.rkt index 5154a89..9e4ba59 100644 --- a/default-recommendations/for-loop-shortcuts.rkt +++ b/default-recommendations/for-loop-shortcuts.rkt @@ -462,6 +462,13 @@ return just that result." (for-id (clause ... #:unless condition) body ...)) +(define-refactoring-rule in-range-with-add1-to-in-inclusive-range + #:description "Use `in-inclusive-range` to include the upper bound value in the iterated sequence." + #:literals (in-range add1 +) + (in-range start (~or (add1 end) (+ end 1) (+ 1 end))) + (in-inclusive-range start end)) + + (define-refactoring-suite for-loop-shortcuts #:rules (andmap-to-for/and append-map-for/list-to-for*/list @@ -472,6 +479,7 @@ return just that result." for/fold-with-conditional-body-to-unless-keyword for/fold-with-conditional-body-to-when-keyword for-each-to-for + in-range-with-add1-to-in-inclusive-range list->set-to-for/set list->vector-to-for/vector map-to-for diff --git a/private/fully-expanded-syntax.rkt b/private/fully-expanded-syntax.rkt index b375ca7..7074a4a 100644 --- a/private/fully-expanded-syntax.rkt +++ b/private/fully-expanded-syntax.rkt @@ -10,14 +10,19 @@ (-> syntax? (hash/c (or/c exact-integer? #false) (free-id-table/c identifier? (listof identifier?) #:immutable #true) - #:immutable #true))])) + #:immutable #true))] + [fully-expanded-syntax-disappeared-visits + (-> syntax? (vectorof syntax? #:immutable #true #:flat? #true))])) (require racket/hash racket/list + racket/match racket/set racket/treelist rebellion/collection/hash + rebellion/collection/vector/builder + resyntax/private/syntax-traversal syntax/id-table syntax/parse) @@ -305,3 +310,24 @@ (syntax-parse stx [:fully-expanded-top-level-form (identifier-binding-table (attribute bound-ids-by-phase) (attribute used-ids-by-phase))])) + + +(define (fully-expanded-syntax-disappeared-visits stx) + (define builder (make-vector-builder)) + (let loop ([stx stx]) + (syntax-traverse stx + [form + #:when (syntax-property #'form 'disappeared-visit) + (vector-builder-add-cons-tree builder (syntax-property #'form 'disappeared-visit)) + (loop (syntax-property #'form 'disappeared-visit #false))])) + (build-vector builder)) + + +(define (vector-builder-add-cons-tree builder cons-tree) + (match cons-tree + [(cons left right) + (vector-builder-add-cons-tree builder left) + (vector-builder-add-cons-tree builder right)] + ['() builder] + [_ + (vector-builder-add builder cons-tree)])) diff --git a/private/source.rkt b/private/source.rkt index e42c86a..7a423ac 100644 --- a/private/source.rkt +++ b/private/source.rkt @@ -149,6 +149,12 @@ (define expanded (parameterize ([current-expand-observe observe-event!]) (expand program-stx))) + + (for ([visited (in-vector (fully-expanded-syntax-disappeared-visits expanded))] + #:when (resyntax-should-analyze-syntax? visited)) + (vector-builder-add original-visits visited) + (add-all-original-subforms! visited)) + (define binding-table (fully-expanded-syntax-binding-table expanded)) (define original-binding-table-by-position (for*/fold ([table (hash)])