1+ use std:: sync:: Arc ;
2+
3+ use super :: prelude:: * ;
4+ use rustc_middle:: { bug, ty:: RegisteredTools } ;
5+ use rustc_session:: { DynLintStore , lint:: CheckLintNameResult } ;
6+
7+ pub ( crate ) struct AllowParser ;
8+
9+ impl < S : Stage > SingleAttributeParser < S > for AllowParser {
10+ const PATH : & [ Symbol ] = & [ sym:: allow] ;
11+
12+ const ATTRIBUTE_ORDER : AttributeOrder = AttributeOrder :: KeepAll ;
13+
14+ const ON_DUPLICATE : OnDuplicate < S > = OnDuplicate :: WarnButFutureError ;
15+
16+ const ALLOWED_TARGETS : AllowedTargets = AllowedTargets :: AllowList ( ALL_TARGETS ) ;
17+
18+ const TEMPLATE : AttributeTemplate = template ! (
19+ List : & [ "lint1" , "lint1, lint2, ..." , r#"lint1, lint2, lint3, reason = "...""# ] ,
20+ "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
21+ ) ;
22+ fn convert ( cx : & mut AcceptContext < ' _ , ' _ , S > , args : & ArgParser ) -> Option < AttributeKind > {
23+ let Some ( lint_store) = & cx. sess . lint_store else {
24+ bug ! ( "lint_store required while parsing attributes" ) ;
25+ } ;
26+
27+
28+ let Some ( list) = args. list ( ) . map ( MetaItemListParser :: mixed) else {
29+ cx. expected_list ( cx. inner_span , args) ;
30+ return None ;
31+ } ;
32+
33+ let mut errored = false ;
34+ let mut lint_ids = ThinVec :: new ( ) ;
35+ let mut list = list. peekable ( ) ;
36+ let mut reason = None ;
37+
38+
39+ while let Some ( item) = list. next ( ) {
40+ let Some ( meta_item ) = item. meta_item ( ) else {
41+ return None ;
42+ } ;
43+ if let Some ( args) = meta_item. word_is ( sym:: reason) {
44+ let ArgParser :: NameValue ( nv) = args else {
45+ // TODO: proper error
46+ errored = true ;
47+ continue ;
48+ } ;
49+ if list. peek ( ) . is_some ( ) {
50+ // TODO: proper error
51+ errored = true ;
52+ continue ;
53+ }
54+ let Some ( s) = nv. value_as_str ( ) else {
55+ // TODO: proper error
56+ errored = true ;
57+ continue ;
58+ } ;
59+ reason = Some ( s) ;
60+ } else {
61+
62+ let mut segments = meta_item. path ( ) . segments ( ) ;
63+
64+ let Some ( tool_or_name) = segments. next ( ) else {
65+ bug ! ( "first segment should always exist" ) ;
66+ } ;
67+
68+ let rest = segments. collect :: < Vec < _ > > ( ) ;
69+ let ( tool, name) : ( Option < Symbol > , _ ) = if rest. is_empty ( ) {
70+ let name = tool_or_name. name ;
71+ ( None , name. to_string ( ) )
72+ } else {
73+ let tool = tool_or_name;
74+ let name = rest. into_iter ( ) . map ( |ident|ident. to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" ) ;
75+ ( Some ( tool. name ) , name)
76+ } ;
77+
78+
79+ if let Some ( ids) = check_lint ( & name, tool, & cx. tools , lint_store, meta_item. span ( ) ) {
80+ lint_ids. extend ( ids) ;
81+ }
82+
83+
84+ }
85+
86+
87+
88+ }
89+
90+
91+ if errored {
92+ None
93+ } else {
94+
95+
96+
97+ Some ( AttributeKind :: Allow { lint_ids, reason} ) }
98+ }
99+ }
100+
101+
102+ fn check_lint ( name : & str , tool : Option < Symbol > , tools : & RegisteredTools , lint_store : & Arc < dyn DynLintStore > , meta_item_span : Span ) -> Option < Vec < ( Symbol , Span ) > > {
103+ let mut lint_ids = Vec :: new ( ) ;
104+ match lint_store. check_lint_name ( name, tool, tools) {
105+ CheckLintNameResult :: Ok ( ids) => {
106+ for id in ids {
107+ lint_ids. push ( ( Symbol :: intern ( & id. to_string ( ) ) , meta_item_span) ) ;
108+ }
109+ }
110+
111+ CheckLintNameResult :: Tool ( ids, new_lint_name) => {
112+ let name = match new_lint_name {
113+ None => {
114+ let complete_name =
115+ & format ! ( "{}::{}" , tool. unwrap( ) , name) ;
116+ Symbol :: intern ( complete_name)
117+ }
118+ Some ( new_lint_name) => {
119+ /*self.emit_span_lint(
120+ builtin::RENAMED_AND_REMOVED_LINTS,
121+ sp.into(),
122+ DeprecatedLintName {
123+ name,
124+ suggestion: sp,
125+ replace: &new_lint_name,
126+ },
127+ );*/
128+ Symbol :: intern ( & new_lint_name)
129+ }
130+ } ;
131+ for id in ids {
132+ lint_ids. push ( ( name, meta_item_span) ) ;
133+ }
134+
135+ }
136+
137+ CheckLintNameResult :: MissingTool => {
138+ // If `MissingTool` is returned, then either the lint does not
139+ // exist in the tool or the code was not compiled with the tool and
140+ // therefore the lint was never added to the `LintStore`. To detect
141+ // this is the responsibility of the lint tool.
142+ return None ;
143+ }
144+
145+ CheckLintNameResult :: NoTool => {
146+ /*self.dcx().emit_err(UnknownToolInScopedLint {
147+ span: tool_ident.map(|ident| ident.span),
148+ tool_name: tool_name.unwrap(),
149+ lint_name: pprust::path_to_string(&meta_item.path),
150+ is_nightly_build: sess.is_nightly_build(),
151+ });*/
152+ return None ;
153+ }
154+
155+ CheckLintNameResult :: Renamed ( ref replace) => {
156+ /*if self.lint_added_lints {
157+ let suggestion =
158+ RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
159+ let name =
160+ tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
161+ let lint = RenamedLint { name: name.as_str(), replace, suggestion };
162+ self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
163+ }*/
164+
165+ // If this lint was renamed, apply the new lint instead of ignoring the
166+ // attribute. Ignore any errors or warnings that happen because the new
167+ // name is inaccurate.
168+ // NOTE: `new_name` already includes the tool name, so we don't
169+ // have to add it again.
170+ let CheckLintNameResult :: Ok ( ids) =
171+ lint_store. check_lint_name ( replace, None , tools)
172+ else {
173+ panic ! ( "renamed lint does not exist: {replace}" ) ;
174+ } ;
175+ let name = Symbol :: intern ( replace) ;
176+
177+ for id in ids {
178+ lint_ids. push ( ( name, meta_item_span) ) ;
179+ }
180+ }
181+
182+ CheckLintNameResult :: Removed ( ref reason) => {
183+ /*if self.lint_added_lints {
184+ let name =
185+ tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
186+ let lint = RemovedLint { name: name.as_str(), reason };
187+ self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
188+ }*/
189+ return None ;
190+ }
191+
192+ CheckLintNameResult :: NoLint ( suggestion) => {
193+ /*if self.lint_added_lints {
194+ let name =
195+ tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
196+ let suggestion = suggestion.map(|(replace, from_rustc)| {
197+ UnknownLintSuggestion::WithSpan {
198+ suggestion: sp,
199+ replace,
200+ from_rustc,
201+ }
202+ });
203+ let lint = UnknownLint { name, suggestion };
204+ self.emit_span_lint(UNKNOWN_LINTS, sp.into(), lint);
205+ }
206+ */
207+ return None ;
208+ }
209+ }
210+ Some ( lint_ids)
211+ }
0 commit comments