E0707, // multiple elided lifetimes used in arguments of `async fn`
E0708, // `async` non-`move` closures with arguments are not currently supported
E0709, // multiple different lifetimes used in arguments of `async fn`
+ E0710, // an unknown tool name found in scoped lint
}
use syntax::ast;
use syntax::attr;
use syntax::codemap::MultiSpan;
+use syntax::feature_gate;
use syntax::symbol::Symbol;
use util::nodemap::FxHashMap;
continue
}
};
+ if word.is_scoped() {
+ if !self.sess.features_untracked().tool_lints {
+ feature_gate::emit_feature_err(&sess.parse_sess,
+ "tool_lints",
+ word.span,
+ feature_gate::GateIssue::Language,
+ &format!("scoped lint `{}` is experimental",
+ word.ident));
+ }
+
+ if !attr::is_known_lint_tool(word) {
+ span_err!(
+ sess,
+ word.span,
+ E0710,
+ "an unknown tool name found in scoped lint: `{}`.",
+ word.ident
+ );
+ }
+
+ continue
+ }
let name = word.name();
match store.check_lint_name(&name.as_str()) {
CheckLintNameResult::Ok(ids) => {
}
const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"];
+const RUST_KNOWN_LINT_TOOL: &[&str] = &["clippy"];
pub fn is_known_tool(attr: &Attribute) -> bool {
let tool_name =
RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref())
}
+pub fn is_known_lint_tool(m_item: &MetaItem) -> bool {
+ let tool_name =
+ m_item.ident.segments.iter().next().expect("empty path in meta item").ident.name;
+ RUST_KNOWN_LINT_TOOL.contains(&tool_name.as_str().as_ref())
+}
+
impl NestedMetaItem {
/// Returns the MetaItem if self is a NestedMetaItemKind::MetaItem.
pub fn meta_item(&self) -> Option<&MetaItem> {
pub fn is_meta_item_list(&self) -> bool {
self.meta_item_list().is_some()
}
+
+ pub fn is_scoped(&self) -> bool {
+ self.ident.segments.len() > 1
+ }
}
impl Attribute {
// Scoped attributes
(active, tool_attributes, "1.25.0", Some(44690), None),
+ // Scoped lints
+ (active, tool_lints, "1.28.0", Some(44690), None),
// allow irrefutable patterns in if-let and while-let statements (RFC 2086)
(active, irrefutable_let_patterns, "1.27.0", Some(44495), None),