From 8dc6e16933f2792a3c6210787b9916908e1e76d0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 6 May 2015 22:08:36 +0530 Subject: Add support for registering attributes with rustc in plugins This lets plugin authors opt attributes out of the `custom_attribute` and `unused_attribute` checks. --- src/libsyntax/feature_gate.rs | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 28deb4eec3f..abb4ce15996 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -359,6 +359,7 @@ struct Context<'a> { features: Vec<&'static str>, span_handler: &'a SpanHandler, cm: &'a CodeMap, + plugin_attributes: &'a [(String, AttributeType)], } impl<'a> Context<'a> { @@ -373,7 +374,7 @@ impl<'a> Context<'a> { self.features.iter().any(|&n| n == feature) } - fn check_attribute(&self, attr: &ast::Attribute) { + fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { debug!("check_attribute(attr = {:?})", attr); let name = &*attr.name(); for &(n, ty) in KNOWN_ATTRIBUTES { @@ -385,6 +386,13 @@ impl<'a> Context<'a> { return; } } + for &(ref n, ref ty) in self.plugin_attributes.iter() { + if &*n == name { + // Plugins can't gate attributes, so we don't check for it + debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty); + return; + } + } if name.starts_with("rustc_") { self.gate_feature("rustc_attrs", attr.span, "unless otherwise specified, attributes \ @@ -395,12 +403,15 @@ impl<'a> Context<'a> { "attributes of the form `#[derive_*]` are reserved \ for the compiler"); } else { - self.gate_feature("custom_attribute", attr.span, - &format!("The attribute `{}` is currently \ - unknown to the compiler and \ - may have meaning \ - added to it in the future", - name)); + // Only do the custom attribute lint post-expansion + if !is_macro { + self.gate_feature("custom_attribute", attr.span, + &format!("The attribute `{}` is currently \ + unknown to the compiler and \ + may have meaning \ + added to it in the future", + name)); + } } } } @@ -479,7 +490,7 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { - self.context.check_attribute(attr); + self.context.check_attribute(attr, true); } } @@ -498,7 +509,7 @@ impl<'a> PostExpansionVisitor<'a> { impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_attribute(&mut self, attr: &ast::Attribute) { if !self.context.cm.span_allows_unstable(attr.span) { - self.context.check_attribute(attr); + self.context.check_attribute(attr, false); } } @@ -685,6 +696,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, + plugin_attributes: &[(String, AttributeType)], check: F) -> Features where F: FnOnce(&mut Context, &ast::Crate) @@ -693,6 +705,7 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, features: Vec::new(), span_handler: span_handler, cm: cm, + plugin_attributes: plugin_attributes, }; let mut accepted_features = Vec::new(); @@ -765,14 +778,14 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) -> Features { - check_crate_inner(cm, span_handler, krate, + check_crate_inner(cm, span_handler, krate, &[] as &'static [_], |ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate)) } -pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate) - -> Features +pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate, + plugin_attributes: &[(String, AttributeType)]) -> Features { - check_crate_inner(cm, span_handler, krate, + check_crate_inner(cm, span_handler, krate, plugin_attributes, |ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx }, krate)) } -- cgit 1.4.1-3-g733a5 From 22b720a920612211d83f7176d7cf2f184c74d294 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 13 May 2015 12:23:43 +0530 Subject: address more review comments --- src/librustc/plugin/registry.rs | 2 +- src/librustc_lint/builtin.rs | 7 ++----- src/libsyntax/feature_gate.rs | 7 ++++++- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/plugin/registry.rs b/src/librustc/plugin/registry.rs index d532ad38d04..8fc032572c3 100644 --- a/src/librustc/plugin/registry.rs +++ b/src/librustc/plugin/registry.rs @@ -137,7 +137,7 @@ impl<'a> Registry<'a> { } - /// Register an attribute with an attribute type + /// Register an attribute with an attribute type. /// /// Registered attributes will bypass the `custom_attribute` feature gate. /// `Whitelisted` attributes will additionally not trigger the `unused_attribute` diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 27c70213151..8d8fbd5bf9a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -643,11 +643,8 @@ impl LintPass for UnusedAttributes { let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); for &(ref name, ty) in plugin_attributes.iter() { - match ty { - AttributeType::Whitelisted if attr.check_name(&*name) => { - break; - }, - _ => () + if ty == AttributeType::Whitelisted && attr.check_name(&*name) { + break; } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index abb4ce15996..495f152d315 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -389,6 +389,8 @@ impl<'a> Context<'a> { for &(ref n, ref ty) in self.plugin_attributes.iter() { if &*n == name { // Plugins can't gate attributes, so we don't check for it + // unlike the code above; we only use this loop to + // short-circuit to avoid the checks below debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty); return; } @@ -403,7 +405,10 @@ impl<'a> Context<'a> { "attributes of the form `#[derive_*]` are reserved \ for the compiler"); } else { - // Only do the custom attribute lint post-expansion + // Only run the custom attribute lint during regular + // feature gate checking. Macro gating runs + // before the plugin attributes are registered + // so we skip this then if !is_macro { self.gate_feature("custom_attribute", attr.span, &format!("The attribute `{}` is currently \ -- cgit 1.4.1-3-g733a5