Skip to content

Commit 60c840e

Browse files
committed
add updated lint rules for s! macros
1 parent e13e036 commit 60c840e

File tree

2 files changed

+201
-51
lines changed

2 files changed

+201
-51
lines changed

libc-test/test/style/mod.rs

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@
1717
//! 5. f! { ... } functions
1818
//! 6. extern functions
1919
//! 7. modules + pub use
20-
//! * Use cfg_if! over #[cfg(...)]
2120
//! * No manual deriving Copy/Clone
2221
//! * Only one f! per module
22+
//! * Multiple s! macros are allowed as long as there isn't a duplicate cfg,
23+
//! whether as a standalone attribute (#[cfg]) or in a cfg_if!
24+
//! * s! macros should not just have a positive cfg since they should
25+
//! just go into the relevant file but combined cfgs with all(...) and
26+
//! any(...) are allowed
2327
28+
use std::collections::HashMap;
2429
use std::fs;
2530
use std::ops::Deref;
2631
use std::path::{Path, PathBuf};
@@ -42,8 +47,7 @@ pub struct StyleChecker {
4247
/// Span of the first item encountered in this state to use in help
4348
/// diagnostic text.
4449
state_span: Option<Span>,
45-
// FIXME: see StyleChecker::set_state
46-
_s_macros: usize,
50+
seen_s_macro_cfgs: HashMap<String, Span>,
4751
/// Span of the first f! macro seen, used to enforce only one f! macro
4852
/// per module.
4953
first_f_macro: Option<Span>,
@@ -167,13 +171,6 @@ impl StyleChecker {
167171
);
168172
}
169173

170-
// FIXME(#4109): multiple should be allowed if at least one is `cfg(not) within `cfg_if`.
171-
// For now just disable this and check by hand.
172-
// if self.s_macros == 2 {
173-
// self.s_macros += 1;
174-
// (self.on_err)(line, "multiple s! macros in one module");
175-
// }
176-
177174
if self.state != new_state {
178175
self.state = new_state;
179176
self.state_span = Some(span);
@@ -182,22 +179,22 @@ impl StyleChecker {
182179

183180
/// Visit the items inside the [ExprCfgIf], restoring the state after
184181
/// each branch.
185-
fn visit_cfg_expr_if(&mut self, cfg_expr_if: &ExprCfgIf) {
182+
fn visit_expr_cfg_if(&mut self, expr_cfg_if: &ExprCfgIf) {
186183
let initial_state = self.state;
187184

188-
for item in &cfg_expr_if.then_branch {
185+
for item in &expr_cfg_if.then_branch {
189186
self.visit_item(item);
190187
}
191188
self.state = initial_state;
192189

193-
if let Some(else_branch) = &cfg_expr_if.else_branch {
190+
if let Some(else_branch) = &expr_cfg_if.else_branch {
194191
match else_branch.deref() {
195192
ExprCfgElse::Block(items) => {
196193
for item in items {
197194
self.visit_item(item);
198195
}
199196
}
200-
ExprCfgElse::If(cfg_expr_if) => self.visit_cfg_expr_if(&cfg_expr_if),
197+
ExprCfgElse::If(expr_cfg_if) => self.visit_expr_cfg_if(&expr_cfg_if),
201198
}
202199
}
203200
self.state = initial_state;
@@ -222,19 +219,7 @@ impl<'ast> Visit<'ast> for StyleChecker {
222219
fn visit_meta_list(&mut self, meta_list: &'ast syn::MetaList) {
223220
let span = meta_list.span();
224221
let meta_str = meta_list.tokens.to_string();
225-
if meta_list.path.is_ident("cfg")
226-
&& !(meta_str.contains("target_endian") || meta_str.contains("target_arch"))
227-
{
228-
self.error(
229-
"cfg_if! over #[cfg]".to_string(),
230-
span,
231-
String::new(),
232-
(
233-
None,
234-
"use cfg_if! and submodules instead of #[cfg]".to_string(),
235-
),
236-
);
237-
} else if meta_list.path.is_ident("derive")
222+
if meta_list.path.is_ident("derive")
238223
&& (meta_str.contains("Copy") || meta_str.contains("Clone"))
239224
{
240225
self.error(
@@ -287,18 +272,76 @@ impl<'ast> Visit<'ast> for StyleChecker {
287272
visit::visit_item_type(self, item_type);
288273
}
289274

275+
fn visit_item_macro(&mut self, item_macro: &'ast syn::ItemMacro) {
276+
if item_macro.mac.path.is_ident("s") {
277+
if item_macro.attrs.is_empty() {
278+
let span = item_macro.span();
279+
match self.seen_s_macro_cfgs.get("") {
280+
Some(seen_span) => {
281+
self.error(
282+
"duplicate s! macro".to_string(),
283+
span,
284+
format!("other s! macro"),
285+
(Some(*seen_span), "combine the two".to_string()),
286+
);
287+
}
288+
None => {
289+
self.seen_s_macro_cfgs.insert(String::new(), span);
290+
}
291+
}
292+
} else {
293+
for attr in &item_macro.attrs {
294+
if let Ok(meta_list) = attr.meta.require_list() {
295+
if meta_list.path.is_ident("cfg") {
296+
let span = meta_list.span();
297+
let meta_str = meta_list.tokens.to_string();
298+
299+
match self.seen_s_macro_cfgs.get(&meta_str) {
300+
Some(seen_span) => {
301+
self.error(
302+
"duplicate #[cfg] for s! macro".to_string(),
303+
span,
304+
"duplicated #[cfg]".to_string(),
305+
(Some(*seen_span), "combine the two".to_string()),
306+
);
307+
}
308+
None => {
309+
self.seen_s_macro_cfgs.insert(meta_str.clone(), span);
310+
}
311+
}
312+
313+
if !meta_str.starts_with("not")
314+
&& !meta_str.starts_with("any")
315+
&& !meta_str.starts_with("all")
316+
{
317+
self.error(
318+
"positive #[cfg] for s! macro".to_string(),
319+
span,
320+
String::new(),
321+
(None, "move it to the relevant file".to_string()),
322+
);
323+
}
324+
}
325+
}
326+
}
327+
}
328+
}
329+
330+
visit::visit_item_macro(self, item_macro);
331+
}
332+
290333
fn visit_macro(&mut self, mac: &'ast syn::Macro) {
291334
let span = mac.span();
292335
if mac.path.is_ident("cfg_if") {
293-
let cfg_expr_if: ExprCfgIf = mac
336+
let expr_cfg_if: ExprCfgIf = mac
294337
.parse_body()
295338
.expect("cfg_if! should be parsed since it compiled");
296339

297-
self.visit_cfg_expr_if(&cfg_expr_if);
340+
self.visit_expr_cfg_if(&expr_cfg_if);
298341
} else {
299342
let new_state = if mac.path.is_ident("s") {
300-
// FIXME: see StyleChecker::set_state
301-
// self.s_macros += 1;
343+
// multiple macros are allowed if they have proper #[cfg(...)]
344+
// attributes, see Self::visit_item_macro
302345
State::Structs
303346
} else if mac.path.is_ident("s_no_extra_traits") {
304347
// multiple macros of this type are allowed
@@ -362,7 +405,11 @@ impl Parse for ExprCfgIf {
362405
let then_branch: Vec<syn::Item> = {
363406
let mut items = Vec::new();
364407
while !content.is_empty() {
365-
items.push(content.parse()?);
408+
let mut value = content.parse()?;
409+
if let syn::Item::Macro(item_macro) = &mut value {
410+
item_macro.attrs.push(attr.clone());
411+
}
412+
items.push(value);
366413
}
367414
items
368415
};

0 commit comments

Comments
 (0)