@@ -8,8 +8,9 @@ use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
88use serde:: Deserialize ;
99use std:: fmt:: { Debug , Display , Formatter } ;
1010use std:: ops:: Range ;
11- use std:: path:: { Path , PathBuf } ;
11+ use std:: path:: PathBuf ;
1212use std:: str:: FromStr ;
13+ use std:: sync:: OnceLock ;
1314use std:: { cmp, env, fmt, fs, io} ;
1415
1516#[ rustfmt:: skip]
@@ -78,62 +79,35 @@ pub struct TryConf {
7879
7980impl TryConf {
8081 fn from_toml_error ( file : & SourceFile , error : & toml:: de:: Error ) -> Self {
81- ConfError :: from_toml ( file, error) . into ( )
82- }
83- }
84-
85- impl From < ConfError > for TryConf {
86- fn from ( value : ConfError ) -> Self {
8782 Self {
8883 conf : Conf :: default ( ) ,
89- errors : vec ! [ value ] ,
84+ errors : vec ! [ ConfError :: from_toml ( file , error ) ] ,
9085 warnings : vec ! [ ] ,
9186 }
9287 }
9388}
9489
95- impl From < io:: Error > for TryConf {
96- fn from ( value : io:: Error ) -> Self {
97- ConfError :: from ( value) . into ( )
98- }
99- }
100-
10190#[ derive( Debug ) ]
10291pub struct ConfError {
10392 pub message : String ,
104- pub span : Option < Span > ,
93+ pub span : Span ,
10594}
10695
10796impl ConfError {
10897 fn from_toml ( file : & SourceFile , error : & toml:: de:: Error ) -> Self {
109- if let Some ( span) = error. span ( ) {
110- Self :: spanned ( file, error. message ( ) , span)
111- } else {
112- Self {
113- message : error. message ( ) . to_string ( ) ,
114- span : None ,
115- }
116- }
98+ let span = error. span ( ) . unwrap_or ( 0 ..file. source_len . 0 as usize ) ;
99+ Self :: spanned ( file, error. message ( ) , span)
117100 }
118101
119102 fn spanned ( file : & SourceFile , message : impl Into < String > , span : Range < usize > ) -> Self {
120103 Self {
121104 message : message. into ( ) ,
122- span : Some ( Span :: new (
105+ span : Span :: new (
123106 file. start_pos + BytePos :: from_usize ( span. start ) ,
124107 file. start_pos + BytePos :: from_usize ( span. end ) ,
125108 SyntaxContext :: root ( ) ,
126109 None ,
127- ) ) ,
128- }
129- }
130- }
131-
132- impl From < io:: Error > for ConfError {
133- fn from ( value : io:: Error ) -> Self {
134- Self {
135- message : value. to_string ( ) ,
136- span : None ,
110+ ) ,
137111 }
138112 }
139113}
@@ -297,7 +271,7 @@ define_Conf! {
297271 /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE.
298272 ///
299273 /// The minimum rust version that the project supports
300- ( msrv: Option < String > = None ) ,
274+ ( msrv: crate :: Msrv = crate :: Msrv :: empty ( ) ) ,
301275 /// DEPRECATED LINT: BLACKLISTED_NAME.
302276 ///
303277 /// Use the Disallowed Names lint instead
@@ -645,15 +619,8 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
645619 }
646620}
647621
648- /// Read the `toml` configuration file.
649- ///
650- /// In case of error, the function tries to continue as much as possible.
651- pub fn read ( sess : & Session , path : & Path ) -> TryConf {
652- let file = match sess. source_map ( ) . load_file ( path) {
653- Err ( e) => return e. into ( ) ,
654- Ok ( file) => file,
655- } ;
656- match toml:: de:: Deserializer :: new ( file. src . as_ref ( ) . unwrap ( ) ) . deserialize_map ( ConfVisitor ( & file) ) {
622+ fn deserialize ( file : & SourceFile ) -> TryConf {
623+ match toml:: de:: Deserializer :: new ( file. src . as_ref ( ) . unwrap ( ) ) . deserialize_map ( ConfVisitor ( file) ) {
657624 Ok ( mut conf) => {
658625 extend_vec_if_indicator_present ( & mut conf. conf . doc_valid_idents , DEFAULT_DOC_VALID_IDENTS ) ;
659626 extend_vec_if_indicator_present ( & mut conf. conf . disallowed_names , DEFAULT_DISALLOWED_NAMES ) ;
@@ -666,7 +633,7 @@ pub fn read(sess: &Session, path: &Path) -> TryConf {
666633
667634 conf
668635 } ,
669- Err ( e) => TryConf :: from_toml_error ( & file, & e) ,
636+ Err ( e) => TryConf :: from_toml_error ( file, & e) ,
670637 }
671638}
672639
@@ -676,6 +643,60 @@ fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
676643 }
677644}
678645
646+ impl Conf {
647+ pub fn read ( sess : & Session , path : & io:: Result < ( Option < PathBuf > , Vec < String > ) > ) -> & ' static Conf {
648+ static CONF : OnceLock < Conf > = OnceLock :: new ( ) ;
649+ CONF . get_or_init ( || Conf :: read_inner ( sess, path) )
650+ }
651+
652+ fn read_inner ( sess : & Session , path : & io:: Result < ( Option < PathBuf > , Vec < String > ) > ) -> Conf {
653+ match path {
654+ Ok ( ( _, warnings) ) => {
655+ for warning in warnings {
656+ sess. warn ( warning. clone ( ) ) ;
657+ }
658+ } ,
659+ Err ( error) => {
660+ sess. err ( format ! ( "error finding Clippy's configuration file: {error}" ) ) ;
661+ } ,
662+ }
663+
664+ let TryConf {
665+ mut conf,
666+ errors,
667+ warnings,
668+ } = match path {
669+ Ok ( ( Some ( path) , _) ) => match sess. source_map ( ) . load_file ( path) {
670+ Ok ( file) => deserialize ( & file) ,
671+ Err ( error) => {
672+ sess. err ( format ! ( "failed to read `{}`: {error}" , path. display( ) ) ) ;
673+ TryConf :: default ( )
674+ } ,
675+ } ,
676+ _ => TryConf :: default ( ) ,
677+ } ;
678+
679+ conf. msrv . read_cargo ( sess) ;
680+
681+ // all conf errors are non-fatal, we just use the default conf in case of error
682+ for error in errors {
683+ sess. span_err (
684+ error. span ,
685+ format ! ( "error reading Clippy's configuration file: {}" , error. message) ,
686+ ) ;
687+ }
688+
689+ for warning in warnings {
690+ sess. span_warn (
691+ warning. span ,
692+ format ! ( "error reading Clippy's configuration file: {}" , warning. message) ,
693+ ) ;
694+ }
695+
696+ conf
697+ }
698+ }
699+
679700const SEPARATOR_WIDTH : usize = 4 ;
680701
681702#[ derive( Debug ) ]
0 commit comments