@@ -10,7 +10,7 @@ use std::fmt;
1010use crate :: ast:: ParsedSqlFile ;
1111
1212/// Represents a line/column location within a source file.
13- #[ derive( Clone , Debug , Eq , PartialEq , PartialOrd ) ]
13+ #[ derive( Clone , Copy , Debug , Eq , PartialEq , PartialOrd ) ]
1414pub struct Location {
1515 line : u64 ,
1616 column : u64 ,
@@ -387,21 +387,52 @@ impl Comments {
387387 pub fn leading_comment ( & self , line : u64 ) -> Option < & Comment > {
388388 self . comments ( ) . iter ( ) . rev ( ) . find ( |comment| comment. span ( ) . end ( ) . line ( ) + 1 == line)
389389 }
390+
391+ /// Method for retrieving all comments that occur directly before a specified line
392+ ///
393+ /// # Parameters
394+ /// - `self` the current [`Comments`] object
395+ /// - The `line` as a [`u64`] to use for reference
396+ pub fn all_valid_leading_comments ( & self , line : u64 ) -> Vec < & Comment > {
397+ let mut found_comments = Vec :: new ( ) ;
398+ let mut current_line = match line. checked_sub ( 1 ) {
399+ Some ( n) => n,
400+ None => return found_comments,
401+ } ;
402+ for comment in self . comments ( ) . iter ( ) . rev ( ) {
403+ let start = comment. span ( ) . end ( ) . line ( ) ;
404+ let end = comment. span ( ) . end ( ) . line ( ) ;
405+ if end == current_line {
406+ found_comments. push ( comment) ;
407+ if current_line == 0 {
408+ break ;
409+ }
410+ current_line = start. saturating_sub ( 1 ) ;
411+ } else if comment. span ( ) . end ( ) . line ( ) < line {
412+ break ;
413+ }
414+ }
415+ found_comments. reverse ( ) ;
416+ found_comments
417+ }
390418}
391419
392- fn combine_leading_comments ( comments : & Comments , line : u64 ) -> Comment {
393- let mut comment: Comment = Comment :: default ( ) ;
420+ fn combine_leading_comments ( comments : Vec < & Comment > ) -> Comment {
421+ let mut final_comment: Comment = Comment :: default ( ) ;
422+ let kind = comments[ 0 ] . kind ( ) ;
423+ final_comment. set_kind ( kind. clone ( ) ) ;
394424 let mut content = String :: new ( ) ;
395- let mut span = Span :: default ( ) ;
396- for possible_comment in comments. comments ( ) {
397- if possible_comment. span ( ) . end ( ) . line ( ) < line {
398- comment. set_kind ( CommentKind :: SingleLine (
399- comment. text ( ) . to_owned ( ) + possible_comment. text ( ) ,
400- ) ) ;
401- }
425+ let start = comments[ 0 ] . span ( ) . start ( ) ;
426+ let mut end = Location :: default ( ) ;
427+ for comment in comments. iter ( ) . rev ( ) {
428+ end = * comment. span ( ) . end ( ) ;
429+ content. push_str ( comment. text ( ) ) ;
402430 }
403431
404- comment
432+ final_comment. kind . set_comment ( & content) ;
433+ final_comment. set_span_locations ( start. to_owned ( ) , end) ;
434+
435+ final_comment
405436}
406437
407438#[ cfg( test) ]
@@ -818,4 +849,42 @@ CREATE TABLE posts (
818849 assert_eq ! ( comment. span( ) . end( ) , comment_vec[ i] . span( ) . end( ) ) ;
819850 }
820851 }
852+
853+ #[ test]
854+ fn test_all_valid_leading_comments ( ) {
855+ // Lines:
856+ // 1: -- old
857+ // 2:
858+ // 3: -- a
859+ // 4: -- b
860+ // 5: implied statement
861+ let comment_vec = vec ! [
862+ Comment :: new(
863+ CommentKind :: SingleLine ( "old" . to_owned( ) ) ,
864+ Span :: new( Location :: new( 1 , 1 ) , Location :: new( 1 , 6 ) ) ,
865+ ) ,
866+ Comment :: new(
867+ CommentKind :: SingleLine ( "a" . to_owned( ) ) ,
868+ Span :: new( Location :: new( 3 , 1 ) , Location :: new( 3 , 4 ) ) ,
869+ ) ,
870+ Comment :: new(
871+ CommentKind :: SingleLine ( "b" . to_owned( ) ) ,
872+ Span :: new( Location :: new( 4 , 1 ) , Location :: new( 4 , 4 ) ) ,
873+ ) ,
874+ ] ;
875+
876+ // IMPORTANT: use Comments::new to enforce ordering invariants
877+ let comments = Comments :: new ( comment_vec) ;
878+
879+ // Statement is on line 5; leading comment block should be lines 3-4 only.
880+ let leading = comments. all_valid_leading_comments ( 5 ) ;
881+
882+ assert_eq ! ( leading. len( ) , 2 ) ;
883+ assert_eq ! ( leading[ 0 ] . text( ) , "a" ) ;
884+ assert_eq ! ( leading[ 1 ] . text( ) , "b" ) ;
885+
886+ // Also confirm the spans align to those lines.
887+ assert_eq ! ( leading[ 0 ] . span( ) . start( ) . line( ) , 3 ) ;
888+ assert_eq ! ( leading[ 1 ] . span( ) . end( ) . line( ) , 4 ) ;
889+ }
821890}
0 commit comments