@@ -26,7 +26,7 @@ use syntax::ast;
26
26
use syntax:: abi;
27
27
use syntax:: attr;
28
28
use syntax:: attr:: AttrMetaMethods ;
29
- use syntax:: codemap:: { Span , mk_sp} ;
29
+ use syntax:: codemap:: { self , Span , mk_sp, Pos } ;
30
30
use syntax:: parse;
31
31
use syntax:: parse:: token:: InternedString ;
32
32
use syntax:: parse:: token;
@@ -373,15 +373,17 @@ impl<'a> CrateReader<'a> {
373
373
// Maintain a reference to the top most crate.
374
374
let root = if root. is_some ( ) { root } else { & crate_paths } ;
375
375
376
- let cnum_map = self . resolve_crate_deps ( root , lib . metadata . as_slice ( ) , span ) ;
376
+ let loader :: Library { dylib , rlib , metadata } = lib ;
377
377
378
- let loader:: Library { dylib, rlib, metadata } = lib;
378
+ let cnum_map = self . resolve_crate_deps ( root, metadata. as_slice ( ) , span) ;
379
+ let codemap_import_info = import_codemap ( self . sess . codemap ( ) , & metadata) ;
379
380
380
381
let cmeta = Rc :: new ( cstore:: crate_metadata {
381
382
name : name. to_string ( ) ,
382
383
data : metadata,
383
384
cnum_map : cnum_map,
384
385
cnum : cnum,
386
+ codemap_import_info : codemap_import_info,
385
387
span : span,
386
388
} ) ;
387
389
@@ -586,3 +588,131 @@ impl<'a> CrateReader<'a> {
586
588
}
587
589
}
588
590
}
591
+
592
+ /// Imports the codemap from an external crate into the codemap of the crate
593
+ /// currently being compiled (the "local crate").
594
+ ///
595
+ /// The import algorithm works analogous to how AST items are inlined from an
596
+ /// external crate's metadata:
597
+ /// For every FileMap in the external codemap an 'inline' copy is created in the
598
+ /// local codemap. The correspondence relation between external and local
599
+ /// FileMaps is recorded in the `ImportedFileMap` objects returned from this
600
+ /// function. When an item from an external crate is later inlined into this
601
+ /// crate, this correspondence information is used to translate the span
602
+ /// information of the inlined item so that it refers the correct positions in
603
+ /// the local codemap (see `astencode::DecodeContext::tr_span()`).
604
+ ///
605
+ /// The import algorithm in the function below will reuse FileMaps already
606
+ /// existing in the local codemap. For example, even if the FileMap of some
607
+ /// source file of libstd gets imported many times, there will only ever be
608
+ /// one FileMap object for the corresponding file in the local codemap.
609
+ ///
610
+ /// Note that imported FileMaps do not actually contain the source code of the
611
+ /// file they represent, just information about length, line breaks, and
612
+ /// multibyte characters. This information is enough to generate valid debuginfo
613
+ /// for items inlined from other crates.
614
+ fn import_codemap ( local_codemap : & codemap:: CodeMap ,
615
+ metadata : & MetadataBlob )
616
+ -> Vec < cstore:: ImportedFileMap > {
617
+ let external_codemap = decoder:: get_imported_filemaps ( metadata. as_slice ( ) ) ;
618
+
619
+ let imported_filemaps = external_codemap. into_iter ( ) . map ( |filemap_to_import| {
620
+ // Try to find an existing FileMap that can be reused for the filemap to
621
+ // be imported. A FileMap is reusable if it is exactly the same, just
622
+ // positioned at a different offset within the codemap.
623
+ let reusable_filemap = {
624
+ local_codemap. files
625
+ . borrow ( )
626
+ . iter ( )
627
+ . find ( |fm| are_equal_modulo_startpos ( & fm, & filemap_to_import) )
628
+ . map ( |rc| rc. clone ( ) )
629
+ } ;
630
+
631
+ match reusable_filemap {
632
+ Some ( fm) => {
633
+ cstore:: ImportedFileMap {
634
+ original_start_pos : filemap_to_import. start_pos ,
635
+ original_end_pos : filemap_to_import. end_pos ,
636
+ translated_filemap : fm
637
+ }
638
+ }
639
+ None => {
640
+ // We can't reuse an existing FileMap, so allocate a new one
641
+ // containing the information we need.
642
+ let codemap:: FileMap {
643
+ name,
644
+ start_pos,
645
+ end_pos,
646
+ lines,
647
+ multibyte_chars,
648
+ ..
649
+ } = filemap_to_import;
650
+
651
+ let source_length = ( end_pos - start_pos) . to_usize ( ) ;
652
+
653
+ // Translate line-start positions and multibyte character
654
+ // position into frame of reference local to file.
655
+ // `CodeMap::new_imported_filemap()` will then translate those
656
+ // coordinates to their new global frame of reference when the
657
+ // offset of the FileMap is known.
658
+ let lines = lines. into_inner ( ) . map_in_place ( |pos| pos - start_pos) ;
659
+ let multibyte_chars = multibyte_chars
660
+ . into_inner ( )
661
+ . map_in_place ( |mbc|
662
+ codemap:: MultiByteChar {
663
+ pos : mbc. pos + start_pos,
664
+ bytes : mbc. bytes
665
+ } ) ;
666
+
667
+ let local_version = local_codemap. new_imported_filemap ( name,
668
+ source_length,
669
+ lines,
670
+ multibyte_chars) ;
671
+ cstore:: ImportedFileMap {
672
+ original_start_pos : start_pos,
673
+ original_end_pos : end_pos,
674
+ translated_filemap : local_version
675
+ }
676
+ }
677
+ }
678
+ } ) . collect ( ) ;
679
+
680
+ return imported_filemaps;
681
+
682
+ fn are_equal_modulo_startpos ( fm1 : & codemap:: FileMap ,
683
+ fm2 : & codemap:: FileMap )
684
+ -> bool {
685
+ if fm1. name != fm2. name {
686
+ return false ;
687
+ }
688
+
689
+ let lines1 = fm1. lines . borrow ( ) ;
690
+ let lines2 = fm2. lines . borrow ( ) ;
691
+
692
+ if lines1. len ( ) != lines2. len ( ) {
693
+ return false ;
694
+ }
695
+
696
+ for ( & line1, & line2) in lines1. iter ( ) . zip ( lines2. iter ( ) ) {
697
+ if ( line1 - fm1. start_pos ) != ( line2 - fm2. start_pos ) {
698
+ return false ;
699
+ }
700
+ }
701
+
702
+ let multibytes1 = fm1. multibyte_chars . borrow ( ) ;
703
+ let multibytes2 = fm2. multibyte_chars . borrow ( ) ;
704
+
705
+ if multibytes1. len ( ) != multibytes2. len ( ) {
706
+ return false ;
707
+ }
708
+
709
+ for ( mb1, mb2) in multibytes1. iter ( ) . zip ( multibytes2. iter ( ) ) {
710
+ if ( mb1. bytes != mb2. bytes ) ||
711
+ ( ( mb1. pos - fm1. start_pos ) != ( mb2. pos - fm2. start_pos ) ) {
712
+ return false ;
713
+ }
714
+ }
715
+
716
+ true
717
+ }
718
+ }
0 commit comments