@@ -60,55 +60,62 @@ impl Serialize for SerializedMessages<'_> {
6060 let mut fingerprints = HashSet :: < u64 > :: with_capacity ( self . diagnostics . len ( ) ) ;
6161
6262 for diagnostic in self . diagnostics {
63- let span = diagnostic. expect_primary_span ( ) ;
64- let file = span. file ( ) ;
65- let filename = diagnostic. expect_ruff_filename ( ) ;
66-
67- let ( start_location, end_location) = if self . resolver . is_notebook ( file) {
68- // We can't give a reasonable location for the structured formats,
69- // so we show one that's clearly a fallback
70- Default :: default ( )
71- } else {
72- (
73- diagnostic. expect_ruff_start_location ( ) ,
74- diagnostic. expect_ruff_end_location ( ) ,
75- )
76- } ;
77-
78- let path = self . project_dir . as_ref ( ) . map_or_else (
79- || file. relative_path ( self . resolver ) . display ( ) . to_string ( ) ,
80- |project_dir| relativize_path_to ( & filename, project_dir) ,
81- ) ;
82-
83- let mut message_fingerprint = fingerprint ( diagnostic, & path, 0 ) ;
84-
85- // Make sure that we do not get a fingerprint that is already in use
86- // by adding in the previously generated one.
87- while fingerprints. contains ( & message_fingerprint) {
88- message_fingerprint = fingerprint ( diagnostic, & path, message_fingerprint) ;
89- }
90- fingerprints. insert ( message_fingerprint) ;
91-
92- let description = diagnostic. body ( ) ;
93- let check_name = diagnostic. secondary_code_or_id ( ) ;
94-
95- let value = json ! ( {
96- "check_name" : check_name,
97- // GitLab doesn't display the separate `check_name` field in a Code Quality report,
98- // so prepend it to the description too.
99- "description" : format!( "{check_name}: {description}" ) ,
100- "severity" : "major" ,
101- "fingerprint" : format!( "{:x}" , message_fingerprint) ,
102- "location" : {
103- "path" : path,
104- "positions" : {
105- "begin" : start_location,
106- "end" : end_location,
63+ if let Some ( span) = diagnostic. primary_span ( ) {
64+ let file = span. file ( ) ;
65+ let filename = file. path ( self . resolver ) ;
66+
67+ let ( start_location, end_location) = if self . resolver . is_notebook ( file) {
68+ // We can't give a reasonable location for the structured formats,
69+ // so we show one that's clearly a fallback
70+ Default :: default ( )
71+ } else {
72+ let diagnostic_source = file. diagnostic_source ( self . resolver ) ;
73+ let source_code = diagnostic_source. as_source_code ( ) ;
74+ span. range ( )
75+ . map ( |range| {
76+ (
77+ source_code. line_column ( range. start ( ) ) ,
78+ source_code. line_column ( range. end ( ) ) ,
79+ )
80+ } )
81+ . unwrap_or_default ( )
82+ } ;
83+
84+ let path = self . project_dir . as_ref ( ) . map_or_else (
85+ || file. relative_path ( self . resolver ) . display ( ) . to_string ( ) ,
86+ |project_dir| relativize_path_to ( filename, project_dir) ,
87+ ) ;
88+
89+ let mut message_fingerprint = fingerprint ( diagnostic, & path, 0 ) ;
90+
91+ // Make sure that we do not get a fingerprint that is already in use
92+ // by adding in the previously generated one.
93+ while fingerprints. contains ( & message_fingerprint) {
94+ message_fingerprint = fingerprint ( diagnostic, & path, message_fingerprint) ;
95+ }
96+ fingerprints. insert ( message_fingerprint) ;
97+
98+ let description = diagnostic. body ( ) ;
99+ let check_name = diagnostic. secondary_code_or_id ( ) ;
100+
101+ let value = json ! ( {
102+ "check_name" : check_name,
103+ // GitLab doesn't display the separate `check_name` field in a Code Quality report,
104+ // so prepend it to the description too.
105+ "description" : format!( "{check_name}: {description}" ) ,
106+ "severity" : "major" ,
107+ "fingerprint" : format!( "{:x}" , message_fingerprint) ,
108+ "location" : {
109+ "path" : path,
110+ "positions" : {
111+ "begin" : start_location,
112+ "end" : end_location,
113+ } ,
107114 } ,
108- } ,
109- } ) ;
115+ } ) ;
110116
111- s. serialize_element ( & value) ?;
117+ s. serialize_element ( & value) ?;
118+ }
112119 }
113120
114121 s. end ( )
0 commit comments