11use crate :: core:: { Edition , Feature , Features , Manifest , Package } ;
22use crate :: { CargoResult , GlobalContext } ;
3- use annotate_snippets:: { Level , Snippet } ;
3+ use annotate_snippets:: { AnnotationKind , Group , Level , Snippet } ;
44use cargo_util_schemas:: manifest:: { TomlLintLevel , TomlToolLints } ;
55use pathdiff:: diff_paths;
66use std:: fmt:: Display ;
@@ -133,78 +133,69 @@ fn verify_feature_enabled(
133133 dash_feature_name
134134 ) ;
135135
136- let message = if let Some ( span) =
137- get_span ( manifest. document ( ) , & [ "lints" , "cargo" , lint_name] , false )
136+ let ( contents , path , span ) = if let Some ( span) =
137+ get_key_value_span ( manifest. document ( ) , & [ "lints" , "cargo" , lint_name] )
138138 {
139- Level :: Error
140- . title ( & title)
141- . snippet (
142- Snippet :: source ( manifest. contents ( ) )
143- . origin ( & manifest_path)
144- . annotation ( Level :: Error . span ( span) . label ( & label) )
145- . fold ( true ) ,
146- )
147- . footer ( Level :: Help . title ( & help) )
139+ ( manifest. contents ( ) , manifest_path, span)
140+ } else if let Some ( lint_span) =
141+ get_key_value_span ( ws_document, & [ "workspace" , "lints" , "cargo" , lint_name] )
142+ {
143+ ( ws_contents, ws_path, lint_span)
148144 } else {
149- let lint_span = get_span (
150- ws_document,
151- & [ "workspace" , "lints" , "cargo" , lint_name] ,
152- false ,
153- )
154- . unwrap_or_else ( || {
155- panic ! ( "could not find `cargo::{lint_name}` in `[lints]`, or `[workspace.lints]` " )
156- } ) ;
145+ panic ! ( "could not find `cargo::{lint_name}` in `[lints]`, or `[workspace.lints]` " )
146+ } ;
157147
158- let inherited_note = if let ( Some ( inherit_span_key) , Some ( inherit_span_value) ) = (
159- get_span ( manifest. document ( ) , & [ "lints" , "workspace" ] , false ) ,
160- get_span ( manifest. document ( ) , & [ "lints" , "workspace" ] , true ) ,
161- ) {
162- Level :: Note . title ( & second_title) . snippet (
148+ let mut report = Vec :: new ( ) ;
149+ report. push (
150+ Group :: with_title ( Level :: ERROR . primary_title ( title) )
151+ . element (
152+ Snippet :: source ( contents)
153+ . path ( path)
154+ . annotation ( AnnotationKind :: Primary . span ( span. key ) . label ( label) ) ,
155+ )
156+ . element ( Level :: HELP . message ( help) ) ,
157+ ) ;
158+
159+ if let Some ( inherit_span) = get_key_value_span ( manifest. document ( ) , & [ "lints" , "workspace" ] )
160+ {
161+ report. push (
162+ Group :: with_title ( Level :: NOTE . secondary_title ( second_title) ) . element (
163163 Snippet :: source ( manifest. contents ( ) )
164- . origin ( & manifest_path)
164+ . path ( manifest_path)
165165 . annotation (
166- Level :: Note . span ( inherit_span_key. start ..inherit_span_value. end ) ,
167- )
168- . fold ( true ) ,
169- )
170- } else {
171- Level :: Note . title ( & second_title)
172- } ;
173-
174- Level :: Error
175- . title ( & title)
176- . snippet (
177- Snippet :: source ( ws_contents)
178- . origin ( & ws_path)
179- . annotation ( Level :: Error . span ( lint_span) . label ( & label) )
180- . fold ( true ) ,
181- )
182- . footer ( inherited_note)
183- . footer ( Level :: Help . title ( & help) )
184- } ;
166+ AnnotationKind :: Context
167+ . span ( inherit_span. key . start ..inherit_span. value . end ) ,
168+ ) ,
169+ ) ,
170+ ) ;
171+ }
185172
186173 * error_count += 1 ;
187- gctx. shell ( ) . print_message ( message ) ?;
174+ gctx. shell ( ) . print_report ( & report ) ?;
188175 }
189176 Ok ( ( ) )
190177}
191178
192- pub fn get_span (
179+ #[ derive( Clone ) ]
180+ pub struct TomlSpan {
181+ pub key : Range < usize > ,
182+ pub value : Range < usize > ,
183+ }
184+
185+ pub fn get_key_value_span (
193186 document : & toml:: Spanned < toml:: de:: DeTable < ' static > > ,
194187 path : & [ & str ] ,
195- get_value : bool ,
196- ) -> Option < Range < usize > > {
188+ ) -> Option < TomlSpan > {
197189 let mut table = document. get_ref ( ) ;
198190 let mut iter = path. into_iter ( ) . peekable ( ) ;
199191 while let Some ( key) = iter. next ( ) {
200192 let key_s: & str = key. as_ref ( ) ;
201193 let ( key, item) = table. get_key_value ( key_s) ?;
202194 if iter. peek ( ) . is_none ( ) {
203- return if get_value {
204- Some ( item. span ( ) )
205- } else {
206- Some ( key. span ( ) )
207- } ;
195+ return Some ( TomlSpan {
196+ key : key. span ( ) ,
197+ value : item. span ( ) ,
198+ } ) ;
208199 }
209200 if let Some ( next_table) = item. get_ref ( ) . as_table ( ) {
210201 table = next_table;
@@ -213,7 +204,10 @@ pub fn get_span(
213204 if let Some ( array) = item. get_ref ( ) . as_array ( ) {
214205 let next = iter. next ( ) . unwrap ( ) ;
215206 return array. iter ( ) . find_map ( |item| match item. get_ref ( ) {
216- toml:: de:: DeValue :: String ( s) if s == next => Some ( item. span ( ) ) ,
207+ toml:: de:: DeValue :: String ( s) if s == next => Some ( TomlSpan {
208+ key : key. span ( ) ,
209+ value : item. span ( ) ,
210+ } ) ,
217211 _ => None ,
218212 } ) ;
219213 }
@@ -337,12 +331,12 @@ impl LintLevel {
337331 self == & LintLevel :: Forbid || self == & LintLevel :: Deny
338332 }
339333
340- pub fn to_diagnostic_level ( self ) -> Level {
334+ pub fn to_diagnostic_level ( self ) -> Level < ' static > {
341335 match self {
342336 LintLevel :: Allow => unreachable ! ( "allow does not map to a diagnostic level" ) ,
343- LintLevel :: Warn => Level :: Warning ,
344- LintLevel :: Deny => Level :: Error ,
345- LintLevel :: Forbid => Level :: Error ,
337+ LintLevel :: Warn => Level :: WARNING ,
338+ LintLevel :: Deny => Level :: ERROR ,
339+ LintLevel :: Forbid => Level :: ERROR ,
346340 }
347341 }
348342}
@@ -455,19 +449,17 @@ pub fn check_im_a_teapot(
455449 let manifest_path = rel_cwd_manifest_path ( path, gctx) ;
456450 let emitted_reason = IM_A_TEAPOT . emitted_source ( lint_level, reason) ;
457451
458- let key_span = get_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] , false ) . unwrap ( ) ;
459- let value_span = get_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] , true ) . unwrap ( ) ;
460- let message = level
461- . title ( IM_A_TEAPOT . desc )
462- . snippet (
452+ let span = get_key_value_span ( manifest. document ( ) , & [ "package" , "im-a-teapot" ] ) . unwrap ( ) ;
453+
454+ let report = & [ Group :: with_title ( level. primary_title ( IM_A_TEAPOT . desc ) )
455+ . element (
463456 Snippet :: source ( manifest. contents ( ) )
464- . origin ( & manifest_path)
465- . annotation ( level. span ( key_span. start ..value_span. end ) )
466- . fold ( true ) ,
457+ . path ( & manifest_path)
458+ . annotation ( AnnotationKind :: Primary . span ( span. key . start ..span. value . end ) ) ,
467459 )
468- . footer ( Level :: Note . title ( & emitted_reason) ) ;
460+ . element ( Level :: NOTE . message ( & emitted_reason) ) ] ;
469461
470- gctx. shell ( ) . print_message ( message ) ?;
462+ gctx. shell ( ) . print_report ( report ) ?;
471463 }
472464 Ok ( ( ) )
473465}
@@ -535,64 +527,48 @@ fn output_unknown_lints(
535527 let help =
536528 matching. map ( |( name, kind) | format ! ( "there is a {kind} with a similar name: `{name}`" ) ) ;
537529
538- let mut footers = Vec :: new ( ) ;
530+ let ( contents, path, span) = if let Some ( span) =
531+ get_key_value_span ( manifest. document ( ) , & [ "lints" , "cargo" , lint_name] )
532+ {
533+ ( manifest. contents ( ) , manifest_path, span)
534+ } else if let Some ( lint_span) =
535+ get_key_value_span ( ws_document, & [ "workspace" , "lints" , "cargo" , lint_name] )
536+ {
537+ ( ws_contents, ws_path, lint_span)
538+ } else {
539+ panic ! ( "could not find `cargo::{lint_name}` in `[lints]`, or `[workspace.lints]` " )
540+ } ;
541+
542+ let mut report = Vec :: new ( ) ;
543+ let mut group = Group :: with_title ( level. clone ( ) . primary_title ( title) ) . element (
544+ Snippet :: source ( contents)
545+ . path ( path)
546+ . annotation ( AnnotationKind :: Primary . span ( span. key ) ) ,
547+ ) ;
539548 if emitted_source. is_none ( ) {
540549 emitted_source = Some ( UNKNOWN_LINTS . emitted_source ( lint_level, reason) ) ;
541- footers . push ( Level :: Note . title ( emitted_source. as_ref ( ) . unwrap ( ) ) ) ;
550+ group = group . element ( Level :: NOTE . message ( emitted_source. as_ref ( ) . unwrap ( ) ) ) ;
542551 }
552+ if let Some ( help) = help. as_ref ( ) {
553+ group = group. element ( Level :: HELP . message ( help) ) ;
554+ }
555+ report. push ( group) ;
543556
544- let mut message = if let Some ( span) =
545- get_span ( manifest. document ( ) , & [ "lints" , "cargo" , lint_name] , false )
557+ if let Some ( inherit_span) = get_key_value_span ( manifest. document ( ) , & [ "lints" , "workspace" ] )
546558 {
547- level. title ( & title) . snippet (
548- Snippet :: source ( manifest. contents ( ) )
549- . origin ( & manifest_path)
550- . annotation ( Level :: Error . span ( span) )
551- . fold ( true ) ,
552- )
553- } else {
554- let lint_span = get_span (
555- ws_document,
556- & [ "workspace" , "lints" , "cargo" , lint_name] ,
557- false ,
558- )
559- . unwrap_or_else ( || {
560- panic ! ( "could not find `cargo::{lint_name}` in `[lints]`, or `[workspace.lints]` " )
561- } ) ;
562-
563- let inherited_note = if let ( Some ( inherit_span_key) , Some ( inherit_span_value) ) = (
564- get_span ( manifest. document ( ) , & [ "lints" , "workspace" ] , false ) ,
565- get_span ( manifest. document ( ) , & [ "lints" , "workspace" ] , true ) ,
566- ) {
567- Level :: Note . title ( & second_title) . snippet (
559+ report. push (
560+ Group :: with_title ( Level :: NOTE . secondary_title ( second_title) ) . element (
568561 Snippet :: source ( manifest. contents ( ) )
569- . origin ( & manifest_path)
562+ . path ( manifest_path)
570563 . annotation (
571- Level :: Note . span ( inherit_span_key. start ..inherit_span_value. end ) ,
572- )
573- . fold ( true ) ,
574- )
575- } else {
576- Level :: Note . title ( & second_title)
577- } ;
578- footers. push ( inherited_note) ;
579-
580- level. title ( & title) . snippet (
581- Snippet :: source ( ws_contents)
582- . origin ( & ws_path)
583- . annotation ( Level :: Error . span ( lint_span) )
584- . fold ( true ) ,
585- )
586- } ;
587-
588- if let Some ( help) = help. as_ref ( ) {
589- footers. push ( Level :: Help . title ( help) ) ;
590- }
591- for footer in footers {
592- message = message. footer ( footer) ;
564+ AnnotationKind :: Context
565+ . span ( inherit_span. key . start ..inherit_span. value . end ) ,
566+ ) ,
567+ ) ,
568+ ) ;
593569 }
594570
595- gctx. shell ( ) . print_message ( message ) ?;
571+ gctx. shell ( ) . print_report ( & report ) ?;
596572 }
597573
598574 Ok ( ( ) )
0 commit comments