88use crate :: emitter:: FileWithAnnotatedLines ;
99use crate :: snippet:: Line ;
1010use crate :: { CodeSuggestion , Diagnostic , DiagnosticId , Emitter , Level , SubDiagnostic } ;
11- use annotate_snippets:: display_list:: DisplayList ;
12- use annotate_snippets:: formatter:: DisplayListFormatter ;
11+ use annotate_snippets:: display_list:: { DisplayList , FormatOptions } ;
1312use annotate_snippets:: snippet:: * ;
1413use rustc_data_structures:: sync:: Lrc ;
1514use rustc_span:: source_map:: SourceMap ;
16- use rustc_span:: { Loc , MultiSpan , SourceFile } ;
15+ use rustc_span:: { MultiSpan , SourceFile } ;
1716
1817/// Generates diagnostics using annotate-snippet
1918pub struct AnnotateSnippetEmitterWriter {
@@ -59,112 +58,20 @@ impl Emitter for AnnotateSnippetEmitterWriter {
5958 }
6059}
6160
62- /// Collects all the data needed to generate the data structures needed for the
63- /// `annotate-snippets` library.
64- struct DiagnosticConverter < ' a > {
65- source_map : Option < Lrc < SourceMap > > ,
66- level : Level ,
67- message : String ,
68- code : Option < DiagnosticId > ,
69- msp : MultiSpan ,
70- #[ allow( dead_code) ]
71- children : & ' a [ SubDiagnostic ] ,
72- #[ allow( dead_code) ]
73- suggestions : & ' a [ CodeSuggestion ] ,
61+ /// Provides the source string for the given `line` of `file`
62+ fn source_string ( file : Lrc < SourceFile > , line : & Line ) -> String {
63+ file. get_line ( line. line_index - 1 ) . map ( |a| a. to_string ( ) ) . unwrap_or_default ( )
7464}
7565
76- impl < ' a > DiagnosticConverter < ' a > {
77- /// Turns rustc Diagnostic information into a `annotate_snippets::snippet::Snippet`.
78- fn to_annotation_snippet ( & self ) -> Option < Snippet > {
79- if let Some ( source_map) = & self . source_map {
80- // Make sure our primary file comes first
81- let primary_lo = if let Some ( ref primary_span) = self . msp . primary_span ( ) . as_ref ( ) {
82- source_map. lookup_char_pos ( primary_span. lo ( ) )
83- } else {
84- // FIXME(#59346): Not sure when this is the case and what
85- // should be done if it happens
86- return None ;
87- } ;
88- let annotated_files =
89- FileWithAnnotatedLines :: collect_annotations ( & self . msp , & self . source_map ) ;
90- let slices = self . slices_for_files ( annotated_files, primary_lo) ;
91-
92- Some ( Snippet {
93- title : Some ( Annotation {
94- label : Some ( self . message . to_string ( ) ) ,
95- id : self . code . clone ( ) . map ( |c| match c {
96- DiagnosticId :: Error ( val) | DiagnosticId :: Lint ( val) => val,
97- } ) ,
98- annotation_type : Self :: annotation_type_for_level ( self . level ) ,
99- } ) ,
100- footer : vec ! [ ] ,
101- slices,
102- } )
103- } else {
104- // FIXME(#59346): Is it ok to return None if there's no source_map?
105- None
106- }
107- }
108-
109- fn slices_for_files (
110- & self ,
111- annotated_files : Vec < FileWithAnnotatedLines > ,
112- primary_lo : Loc ,
113- ) -> Vec < Slice > {
114- // FIXME(#64205): Provide a test case where `annotated_files` is > 1
115- annotated_files
116- . iter ( )
117- . flat_map ( |annotated_file| {
118- annotated_file
119- . lines
120- . iter ( )
121- . map ( |line| {
122- let line_source = Self :: source_string ( annotated_file. file . clone ( ) , & line) ;
123- Slice {
124- source : line_source,
125- line_start : line. line_index ,
126- origin : Some ( primary_lo. file . name . to_string ( ) ) ,
127- // FIXME(#59346): Not really sure when `fold` should be true or false
128- fold : false ,
129- annotations : line
130- . annotations
131- . iter ( )
132- . map ( |a| self . annotation_to_source_annotation ( a. clone ( ) ) )
133- . collect ( ) ,
134- }
135- } )
136- . collect :: < Vec < Slice > > ( )
137- } )
138- . collect :: < Vec < Slice > > ( )
139- }
140-
141- /// Turns a `crate::snippet::Annotation` into a `SourceAnnotation`
142- fn annotation_to_source_annotation (
143- & self ,
144- annotation : crate :: snippet:: Annotation ,
145- ) -> SourceAnnotation {
146- SourceAnnotation {
147- range : ( annotation. start_col , annotation. end_col ) ,
148- label : annotation. label . unwrap_or ( "" . to_string ( ) ) ,
149- annotation_type : Self :: annotation_type_for_level ( self . level ) ,
150- }
151- }
152-
153- /// Provides the source string for the given `line` of `file`
154- fn source_string ( file : Lrc < SourceFile > , line : & Line ) -> String {
155- file. get_line ( line. line_index - 1 ) . map ( |a| a. to_string ( ) ) . unwrap_or ( String :: new ( ) )
156- }
157-
158- /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
159- fn annotation_type_for_level ( level : Level ) -> AnnotationType {
160- match level {
161- Level :: Bug | Level :: Fatal | Level :: Error => AnnotationType :: Error ,
162- Level :: Warning => AnnotationType :: Warning ,
163- Level :: Note => AnnotationType :: Note ,
164- Level :: Help => AnnotationType :: Help ,
165- // FIXME(#59346): Not sure how to map these two levels
166- Level :: Cancelled | Level :: FailureNote => AnnotationType :: Error ,
167- }
66+ /// Maps `Diagnostic::Level` to `snippet::AnnotationType`
67+ fn annotation_type_for_level ( level : Level ) -> AnnotationType {
68+ match level {
69+ Level :: Bug | Level :: Fatal | Level :: Error => AnnotationType :: Error ,
70+ Level :: Warning => AnnotationType :: Warning ,
71+ Level :: Note => AnnotationType :: Note ,
72+ Level :: Help => AnnotationType :: Help ,
73+ // FIXME(#59346): Not sure how to map these two levels
74+ Level :: Cancelled | Level :: FailureNote => AnnotationType :: Error ,
16875 }
16976}
17077
@@ -191,25 +98,76 @@ impl AnnotateSnippetEmitterWriter {
19198 message : String ,
19299 code : & Option < DiagnosticId > ,
193100 msp : & MultiSpan ,
194- children : & [ SubDiagnostic ] ,
195- suggestions : & [ CodeSuggestion ] ,
101+ _children : & [ SubDiagnostic ] ,
102+ _suggestions : & [ CodeSuggestion ] ,
196103 ) {
197- let converter = DiagnosticConverter {
198- source_map : self . source_map . clone ( ) ,
199- level : * level,
200- message,
201- code : code. clone ( ) ,
202- msp : msp. clone ( ) ,
203- children,
204- suggestions,
205- } ;
206- if let Some ( snippet) = converter. to_annotation_snippet ( ) {
207- let dl = DisplayList :: from ( snippet) ;
208- let dlf = DisplayListFormatter :: new ( true , self . ui_testing ) ;
104+ if let Some ( source_map) = & self . source_map {
105+ // Make sure our primary file comes first
106+ let primary_lo = if let Some ( ref primary_span) = msp. primary_span ( ) . as_ref ( ) {
107+ source_map. lookup_char_pos ( primary_span. lo ( ) )
108+ } else {
109+ // FIXME(#59346): Not sure when this is the case and what
110+ // should be done if it happens
111+ return ;
112+ } ;
113+ let annotated_files =
114+ FileWithAnnotatedLines :: collect_annotations ( msp, & self . source_map ) ;
115+ // owned: line source, line index, annotations
116+ type Owned = ( String , usize , Vec < crate :: snippet:: Annotation > ) ;
117+ let origin = primary_lo. file . name . to_string ( ) ;
118+ let annotated_files: Vec < Owned > = annotated_files
119+ . into_iter ( )
120+ . flat_map ( |annotated_file| {
121+ let file = annotated_file. file ;
122+ annotated_file
123+ . lines
124+ . into_iter ( )
125+ . map ( |line| {
126+ ( source_string ( file. clone ( ) , & line) , line. line_index , line. annotations )
127+ } )
128+ . collect :: < Vec < Owned > > ( )
129+ } )
130+ . collect ( ) ;
131+ let snippet = Snippet {
132+ title : Some ( Annotation {
133+ label : Some ( & message) ,
134+ id : code. as_ref ( ) . map ( |c| match c {
135+ DiagnosticId :: Error ( val) | DiagnosticId :: Lint ( val) => val. as_str ( ) ,
136+ } ) ,
137+ annotation_type : annotation_type_for_level ( * level) ,
138+ } ) ,
139+ footer : vec ! [ ] ,
140+ opt : FormatOptions { color : true , anonymized_line_numbers : self . ui_testing } ,
141+ slices : annotated_files
142+ . iter ( )
143+ . map ( |( source, line_index, annotations) | {
144+ Slice {
145+ source,
146+ line_start : * line_index,
147+ origin : Some ( & origin) ,
148+ // FIXME(#59346): Not really sure when `fold` should be true or false
149+ fold : false ,
150+ annotations : annotations
151+ . into_iter ( )
152+ . map ( |annotation| SourceAnnotation {
153+ range : ( annotation. start_col , annotation. end_col ) ,
154+ label : annotation
155+ . label
156+ . as_ref ( )
157+ . map ( |s| s. as_str ( ) )
158+ . unwrap_or_default ( ) ,
159+ annotation_type : annotation_type_for_level ( * level) ,
160+ } )
161+ . collect ( ) ,
162+ }
163+ } )
164+ . collect ( ) ,
165+ } ;
209166 // FIXME(#59346): Figure out if we can _always_ print to stderr or not.
210167 // `emitter.rs` has the `Destination` enum that lists various possible output
211168 // destinations.
212- eprintln ! ( "{}" , dlf. format( & dl) ) ;
213- } ;
169+ eprintln ! ( "{}" , DisplayList :: from( snippet) )
170+ }
171+ // FIXME(#59346): Is it ok to return None if there's no source_map?
214172 }
215173}
0 commit comments