Merge commit '1d8491b120223272b13451fc81265aa64f7f4d5b' into sync-from-rustfmt
This commit is contained in:
@@ -22,7 +22,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustfmt-config_proc_macro"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rustfmt-config_proc_macro"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
edition = "2018"
|
||||
description = "A collection of procedural macros for rustfmt"
|
||||
license = "Apache-2.0/MIT"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
//! This module provides utilities for handling attributes on variants
|
||||
//! of `config_type` enum. Currently there are two types of attributes
|
||||
//! that could appear on the variants of `config_type` enum: `doc_hint`
|
||||
//! and `value`. Both comes in the form of name-value pair whose value
|
||||
//! is string literal.
|
||||
//! of `config_type` enum. Currently there are the following attributes
|
||||
//! that could appear on the variants of `config_type` enum:
|
||||
//!
|
||||
//! - `doc_hint`: name-value pair whose value is string literal
|
||||
//! - `value`: name-value pair whose value is string literal
|
||||
//! - `unstable_variant`: name only
|
||||
|
||||
/// Returns the value of the first `doc_hint` attribute in the given slice or
|
||||
/// `None` if `doc_hint` attribute is not available.
|
||||
@@ -27,6 +29,11 @@ pub fn find_config_value(attrs: &[syn::Attribute]) -> Option<String> {
|
||||
attrs.iter().filter_map(config_value).next()
|
||||
}
|
||||
|
||||
/// Returns `true` if the there is at least one `unstable` attribute in the given slice.
|
||||
pub fn any_unstable_variant(attrs: &[syn::Attribute]) -> bool {
|
||||
attrs.iter().any(is_unstable_variant)
|
||||
}
|
||||
|
||||
/// Returns a string literal value if the given attribute is `value`
|
||||
/// attribute or `None` otherwise.
|
||||
pub fn config_value(attr: &syn::Attribute) -> Option<String> {
|
||||
@@ -38,6 +45,11 @@ pub fn is_config_value(attr: &syn::Attribute) -> bool {
|
||||
is_attr_name_value(attr, "value")
|
||||
}
|
||||
|
||||
/// Returns `true` if the given attribute is an `unstable` attribute.
|
||||
pub fn is_unstable_variant(attr: &syn::Attribute) -> bool {
|
||||
is_attr_path(attr, "unstable_variant")
|
||||
}
|
||||
|
||||
fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
|
||||
attr.parse_meta().ok().map_or(false, |meta| match meta {
|
||||
syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true,
|
||||
@@ -45,6 +57,13 @@ fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
|
||||
attr.parse_meta().ok().map_or(false, |meta| match meta {
|
||||
syn::Meta::Path(path) if path.is_ident(name) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> {
|
||||
attr.parse_meta().ok().and_then(|meta| match meta {
|
||||
syn::Meta::NameValue(syn::MetaNameValue {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
use crate::attrs::*;
|
||||
use crate::utils::*;
|
||||
@@ -47,12 +48,23 @@ fn process_variant(variant: &syn::Variant) -> TokenStream {
|
||||
let metas = variant
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|attr| !is_doc_hint(attr) && !is_config_value(attr));
|
||||
.filter(|attr| !is_doc_hint(attr) && !is_config_value(attr) && !is_unstable_variant(attr));
|
||||
let attrs = fold_quote(metas, |meta| quote!(#meta));
|
||||
let syn::Variant { ident, fields, .. } = variant;
|
||||
quote!(#attrs #ident #fields)
|
||||
}
|
||||
|
||||
/// Return the correct syntax to pattern match on the enum variant, discarding all
|
||||
/// internal field data.
|
||||
fn fields_in_variant(variant: &syn::Variant) -> TokenStream {
|
||||
// With thanks to https://stackoverflow.com/a/65182902
|
||||
match &variant.fields {
|
||||
syn::Fields::Unnamed(_) => quote_spanned! { variant.span() => (..) },
|
||||
syn::Fields::Unit => quote_spanned! { variant.span() => },
|
||||
syn::Fields::Named(_) => quote_spanned! { variant.span() => {..} },
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
|
||||
let doc_hint = variants
|
||||
.iter()
|
||||
@@ -60,12 +72,26 @@ fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
|
||||
.collect::<Vec<_>>()
|
||||
.join("|");
|
||||
let doc_hint = format!("[{}]", doc_hint);
|
||||
|
||||
let variant_stables = variants
|
||||
.iter()
|
||||
.map(|v| (&v.ident, fields_in_variant(&v), !unstable_of_variant(v)));
|
||||
let match_patterns = fold_quote(variant_stables, |(v, fields, stable)| {
|
||||
quote! {
|
||||
#ident::#v #fields => #stable,
|
||||
}
|
||||
});
|
||||
quote! {
|
||||
use crate::config::ConfigType;
|
||||
impl ConfigType for #ident {
|
||||
fn doc_hint() -> String {
|
||||
#doc_hint.to_owned()
|
||||
}
|
||||
fn stable_variant(&self) -> bool {
|
||||
match self {
|
||||
#match_patterns
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,13 +149,21 @@ fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream {
|
||||
}
|
||||
|
||||
fn doc_hint_of_variant(variant: &syn::Variant) -> String {
|
||||
find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string())
|
||||
let mut text = find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string());
|
||||
if unstable_of_variant(&variant) {
|
||||
text.push_str(" (unstable)")
|
||||
};
|
||||
text
|
||||
}
|
||||
|
||||
fn config_value_of_variant(variant: &syn::Variant) -> String {
|
||||
find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string())
|
||||
}
|
||||
|
||||
fn unstable_of_variant(variant: &syn::Variant) -> bool {
|
||||
any_unstable_variant(&variant.attrs)
|
||||
}
|
||||
|
||||
fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream {
|
||||
let arms = fold_quote(variants.iter(), |v| {
|
||||
let v_ident = &v.ident;
|
||||
|
||||
@@ -69,3 +69,16 @@ pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
TokenStream::from_str("").unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to conditionally output the TokenStream for tests that should be run as part of rustfmts
|
||||
/// test suite, but should be ignored when running in the rust-lang/rust test suite.
|
||||
#[proc_macro_attribute]
|
||||
pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
if option_env!("RUSTFMT_CI").is_some() {
|
||||
input
|
||||
} else {
|
||||
let mut token_stream = TokenStream::from_str("#[ignore]").unwrap();
|
||||
token_stream.extend(input);
|
||||
token_stream
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod config {
|
||||
pub trait ConfigType: Sized {
|
||||
fn doc_hint() -> String;
|
||||
fn stable_variant(&self) -> bool;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user