@@ -4,7 +4,7 @@ use c2rust_ast_exporter::clang_ast::LRValue;
44use indexmap:: { IndexMap , IndexSet } ;
55use itertools:: Itertools ;
66use std:: cell:: RefCell ;
7- use std:: cmp:: Ordering ;
7+ use std:: cmp:: { Ordering , Reverse } ;
88use std:: collections:: { HashMap , HashSet } ;
99use std:: fmt:: { self , Debug , Display } ;
1010use std:: ops:: Index ;
@@ -141,6 +141,34 @@ impl<T> Located<T> {
141141 }
142142}
143143
144+ /// This holds a [`SrcLoc`] and its [`include_path`](TypedAstContext::include_path)
145+ /// such that it is naturally ordered.
146+ ///
147+ /// The include path starts from where the item is first included,
148+ /// working its way back to the last include path,
149+ /// which contains the definition of the item.
150+ /// Thus, to compare them, we compare the include path first
151+ /// and then the definition's location.
152+ #[ derive( PartialEq , Eq , Ord , Debug ) ]
153+ struct SrcLocInclude < ' a > {
154+ loc : SrcLoc ,
155+ include_path : & ' a [ SrcLoc ] ,
156+ }
157+
158+ impl SrcLocInclude < ' _ > {
159+ fn cmp_iter < ' a > ( & ' a self ) -> impl Iterator < Item = SrcLoc > + ' a {
160+ // See docs on `Self` for why this is the right comparison.
161+ let Self { loc, include_path } = * self ;
162+ include_path. iter ( ) . copied ( ) . chain ( [ loc] )
163+ }
164+ }
165+
166+ impl PartialOrd for SrcLocInclude < ' _ > {
167+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
168+ Some ( self . cmp_iter ( ) . cmp ( other. cmp_iter ( ) ) )
169+ }
170+ }
171+
144172impl TypedAstContext {
145173 // TODO: build the TypedAstContext during initialization, rather than
146174 // building an empty one and filling it later.
@@ -216,6 +244,27 @@ impl TypedAstContext {
216244 includes
217245 }
218246
247+ /// Compare a [`SrcLoc`] based on its include path.
248+ pub fn cmp_loc_include < ' a > ( & ' a self , loc : SrcLoc ) -> impl Eq + Ord + Debug + ' a {
249+ SrcLocInclude {
250+ loc,
251+ include_path : self . include_path ( loc) ,
252+ }
253+ }
254+
255+ /// Compare a [`SrcSpan`] based on its include path.
256+ pub fn cmp_span_include < ' a > ( & ' a self , span : & SrcSpan ) -> impl Eq + Ord + Debug + ' a {
257+ self . cmp_loc_include ( span. begin ( ) )
258+ }
259+
260+ /// Compare a [`Located`] based on its include path.
261+ pub fn cmp_located_include < ' a , T > (
262+ & ' a self ,
263+ located : & Located < T > ,
264+ ) -> impl Eq + Ord + Debug + ' a {
265+ located. loc . map ( |span| self . cmp_span_include ( & span) )
266+ }
267+
219268 pub fn loc_to_string ( & self , loc : SrcLoc ) -> String {
220269 let SrcLoc {
221270 fileid,
@@ -237,43 +286,6 @@ impl TypedAstContext {
237286 . join ( "\n included from " )
238287 }
239288
240- /// Compare two [`SrcLoc`]s based on their include path.
241- pub fn compare_src_locs ( & self , a : & SrcLoc , b : & SrcLoc ) -> Ordering {
242- /// Compare without regard to `fileid`.
243- fn cmp_pos ( a : & SrcLoc , b : & SrcLoc ) -> Ordering {
244- ( a. line , a. column ) . cmp ( & ( b. line , b. column ) )
245- }
246-
247- use Ordering :: * ;
248- let path_a = self . include_path ( * a) ;
249- let path_b = self . include_path ( * b) ;
250-
251- // Find the first include that does not match between the two
252- let common_len = path_a. len ( ) . min ( path_b. len ( ) ) ;
253- let order = path_a[ ..common_len] . cmp ( & path_b[ ..common_len] ) ;
254- if order != Equal {
255- return order;
256- }
257-
258- // Either all parent includes are the same, or the include paths are of different lengths
259- // because .zip() stops when one of the iterators is empty.
260- match path_a. len ( ) . cmp ( & path_b. len ( ) ) {
261- Less => {
262- // a has the shorter path, which means b was included in a's file
263- // so extract that include and compare the position to a
264- let b = & path_b[ path_a. len ( ) ] ;
265- cmp_pos ( a, b)
266- }
267- Equal => a. cmp ( b) , // a and b have the same include path and are thus in the same file
268- Greater => {
269- // b has the shorter path, which means a was included in b's file
270- // so extract that include and compare the position to b
271- let a = & path_a[ path_b. len ( ) ] ;
272- cmp_pos ( a, b)
273- }
274- }
275- }
276-
277289 pub fn get_file_include_line_number ( & self , file : FileId ) -> Option < u64 > {
278290 self . include_map [ file] . first ( ) . map ( |loc| loc. line )
279291 }
@@ -1171,17 +1183,7 @@ impl TypedAstContext {
11711183 /// This preserves the order when we emit the converted declarations.
11721184 pub fn sort_top_decls_for_emitting ( & mut self ) {
11731185 let mut decls_top = mem:: take ( & mut self . c_decls_top ) ;
1174- decls_top. sort_unstable_by ( |a, b| {
1175- let a = self . index ( * a) ;
1176- let b = self . index ( * b) ;
1177- use Ordering :: * ;
1178- match ( & a. loc , & b. loc ) {
1179- ( None , None ) => Equal ,
1180- ( None , _) => Less ,
1181- ( _, None ) => Greater ,
1182- ( Some ( a) , Some ( b) ) => self . compare_src_locs ( & a. begin ( ) , & b. begin ( ) ) ,
1183- }
1184- } ) ;
1186+ decls_top. sort_unstable_by_key ( |& decl| self . cmp_located_include ( self . index ( decl) ) ) ;
11851187 self . c_decls_top = decls_top;
11861188 }
11871189
@@ -1249,9 +1251,10 @@ impl CommentContext {
12491251 // Sort in REVERSE! Last element is the first in file source
12501252 // ordering. This makes it easy to pop the next comment off.
12511253 for comments in comments_by_file. values_mut ( ) {
1252- comments. sort_by ( |a, b| {
1253- ast_context. compare_src_locs ( & b. loc . unwrap ( ) . begin ( ) , & a. loc . unwrap ( ) . begin ( ) )
1254- } ) ;
1254+ for comment in comments. iter ( ) {
1255+ comment. loc . unwrap ( ) ;
1256+ }
1257+ comments. sort_by_key ( |comment| Reverse ( ast_context. cmp_located_include ( comment) ) ) ;
12551258 }
12561259
12571260 let comments_by_file = comments_by_file
@@ -1275,7 +1278,10 @@ impl CommentContext {
12751278 . unwrap ( )
12761279 . begin_loc ( )
12771280 . expect ( "All comments must have a source location" ) ;
1278- if ctx. compare_src_locs ( & next_comment_loc, & loc) != Ordering :: Less {
1281+
1282+ let loc = ctx. cmp_loc_include ( loc) ;
1283+ let next_comment_loc = ctx. cmp_loc_include ( next_comment_loc) ;
1284+ if next_comment_loc >= loc {
12791285 break ;
12801286 }
12811287
@@ -2723,6 +2729,8 @@ impl CTypeKind {
27232729
27242730#[ cfg( test) ]
27252731mod tests {
2732+ use std:: cmp:: Ordering ;
2733+
27262734 use super :: * ;
27272735
27282736 #[ track_caller]
@@ -2972,11 +2980,15 @@ c = {c}
29722980
29732981 check_transitivity (
29742982 locs,
2975- |a, b| ctx. compare_src_locs ( a, b) ,
2983+ |& a, & b| -> Ordering {
2984+ let a = ctx. cmp_loc_include ( a) ;
2985+ let b = ctx. cmp_loc_include ( b) ;
2986+ a. cmp ( & b)
2987+ } ,
29762988 |loc| format ! ( "{loc}" ) ,
29772989 ) ;
29782990
29792991 // This should not panic.
2980- locs. sort_unstable_by ( |a , b | ctx. compare_src_locs ( a , b ) ) ;
2992+ locs. sort_unstable_by_key ( | & loc | ctx. cmp_loc_include ( loc ) ) ;
29812993 }
29822994}
0 commit comments