Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use trybuild and move to proc-macro-error #60

Merged
merged 4 commits into from
Jan 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ travis-ci = { repository = "auto-impl-rs/auto_impl" }
proc-macro = true

[features]
nightly = ["proc-macro2/nightly"]
nightly = []

[dependencies]
proc-macro2 = { version = "1.0" }
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full", "visit", "visit-mut"] }
proc-macro-error = "0.4.4"

[dev-dependencies]
trybuild = "1"
Expand Down
2 changes: 0 additions & 2 deletions examples/error_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
//! ```
//! cargo build --example error_messages
//! ```
//!
//! If you want to see nicer error messages, add `--features=nightly`.
#![allow(unused_imports, dead_code)]

use auto_impl::auto_impl;
Expand Down
83 changes: 40 additions & 43 deletions src/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@
//! attached to trait items.

use proc_macro2::{Delimiter, TokenTree};
use proc_macro_error::{abort, emit_error};
use syn::{
spanned::Spanned,
visit_mut::{visit_item_trait_mut, VisitMut},
Attribute, TraitItem,
visit_mut::{VisitMut, visit_item_trait_mut},
};

use crate::{
diag::{DiagnosticExt, SpanExt},
proxy::{parse_types, ProxyType},
spanned::Spanned
};

use crate::proxy::{parse_types, ProxyType};

/// Removes all `#[auto_impl]` attributes that are attached to methods of the
/// given trait.
Expand All @@ -26,14 +23,19 @@ pub(crate) fn remove_our_attrs(trait_def: &mut syn::ItemTrait) {
TraitItem::Const(c) => (&mut c.attrs, false),
TraitItem::Type(t) => (&mut t.attrs, false),
TraitItem::Macro(m) => (&mut m.attrs, false),
_ => panic!("encountered unexpected `TraitItem`, cannot handle that, sorry!"),
_ => abort!(
item.span(),
"encountered unexpected `TraitItem`, cannot handle that, sorry!";
note = "auto-impl supports only methods, consts, types and macros currently";
),
};

// Make sure non-methods do not have our attributes.
if !is_method && attrs.iter().any(|a| is_our_attr(a)) {
item_span
.err("`auto_impl` attributes are only allowed on methods")
.emit();
emit_error!(
item_span,
"`#[auto_impl]` attributes are only allowed on methods",
);
}

attrs.retain(|a| !is_our_attr(a));
Expand All @@ -46,10 +48,7 @@ pub(crate) fn remove_our_attrs(trait_def: &mut syn::ItemTrait) {
/// Checks if the given attribute is "our" attribute. That means that it's path
/// is `auto_impl`.
pub(crate) fn is_our_attr(attr: &Attribute) -> bool {
attr.path.segments.len() == 1
&& attr.path.segments.iter().next().map(|seg| {
seg.ident == "auto_impl" && seg.arguments.is_empty()
}).unwrap()
attr.path.is_ident("auto_impl")
}

/// Tries to parse the given attribute as one of our own `auto_impl`
Expand All @@ -66,9 +65,12 @@ pub(crate) fn parse_our_attr(attr: &Attribute) -> Result<OurAttr, ()> {
let body = match &*tokens {
[TokenTree::Group(g)] => g.stream(),
_ => {
return attr.tokens.span()
.err(format!("expected single group delimitted by`()`, found '{:?}'", tokens))
.emit_with_attr_note();
emit_error!(
attr.tokens.span(),
"expected single group delimited by `()`, found '{:?}'",
tokens,
);
return Err(());
}
};

Expand All @@ -78,55 +80,50 @@ pub(crate) fn parse_our_attr(attr: &Attribute) -> Result<OurAttr, ()> {
let name = match it.next() {
Some(TokenTree::Ident(x)) => x,
Some(other) => {
return Spanned::span(&other)
.err(format!("expected ident, found '{}'", other))
.emit_with_attr_note();
emit_error!(other.span(), "expected ident, found '{}'", other);
return Err(());
}
None => {
return attr.tokens.span()
.err("expected ident, found nothing")
.emit_with_attr_note();
emit_error!(attr.tokens.span(), "expected ident, found nothing");
return Err(());
}
};

// Extract the parameters (which again, have to be a group delimitted by
// Extract the parameters (which again, have to be a group delimited by
// `()`)
let params = match it.next() {
Some(TokenTree::Group(ref g)) if g.delimiter() == Delimiter::Parenthesis => {
g.stream()
}
Some(other) => {
let msg = format!(
emit_error!(
other.span(),
"expected arguments for '{}' in parenthesis `()`, found `{}`",
name,
other,
);
return Spanned::span(&other)
.err(msg)
.emit_with_attr_note();
return Err(());
}
None => {
let msg = format!(
emit_error!(
body.span(),
"expected arguments for '{}' in parenthesis `()`, found nothing",
name,
);
return body.span()
.err(msg)
.emit_with_attr_note();
return Err(());
}
};

// Finally match over the name of the attribute.
let out = match () {
() if name == "keep_default_for" => {
let proxy_types = parse_types(params.into())?;
OurAttr::KeepDefaultFor(proxy_types)
}
_ => {
return Spanned::span(&name)
.err(format!("invalid attribute '{}'", name))
.emit_with_attr_note();
}
let out = if name == "keep_default_for" {
let proxy_types = parse_types(params.into());
OurAttr::KeepDefaultFor(proxy_types)
} else {
emit_error!(
name.span(), "invalid attribute '{}'", name;
note = "only `keep_default_for` is supported";
);
return Err(());
};

Ok(out)
Expand Down
190 changes: 0 additions & 190 deletions src/diag.rs

This file was deleted.

Loading