macros: introduce build_field_mapping

Move the logic for building a field mapping (which is used by the
building of format strings in `suggestion` annotations) into a helper
function.

Signed-off-by: David Wood <david.wood@huawei.com>
This commit is contained in:
David Wood 2022-06-29 16:13:01 +01:00
parent 540eaf985d
commit 406579ae13
2 changed files with 22 additions and 20 deletions

View File

@ -5,8 +5,8 @@ use crate::diagnostics::error::{
SessionDiagnosticDeriveError,
};
use crate::diagnostics::utils::{
report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
build_field_mapping, report_error_if_not_applied_to_span, report_type_error, type_is_unit,
type_matches_path, Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
@ -25,26 +25,11 @@ pub(crate) struct SessionDiagnosticDerive<'a> {
impl<'a> SessionDiagnosticDerive<'a> {
pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self {
// Build the mapping of field names to fields. This allows attributes to peek values from
// other fields.
let mut fields_map = HashMap::new();
// Convenience bindings.
let ast = structure.ast();
if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
for field in fields.iter() {
if let Some(ident) = &field.ident {
fields_map.insert(ident.to_string(), quote! { &self.#ident });
}
}
}
Self {
builder: SessionDiagnosticDeriveBuilder {
diag,
sess,
fields: fields_map,
fields: build_field_mapping(&structure),
kind: None,
code: None,
slug: None,

View File

@ -2,10 +2,10 @@ use crate::diagnostics::error::{span_err, throw_span_err, SessionDiagnosticDeriv
use proc_macro::Span;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use std::collections::BTreeSet;
use std::collections::{BTreeSet, HashMap};
use std::str::FromStr;
use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple};
use synstructure::BindingInfo;
use synstructure::{BindingInfo, Structure};
/// Checks whether the type name of `ty` matches `name`.
///
@ -325,3 +325,20 @@ impl quote::ToTokens for Applicability {
});
}
}
/// Build the mapping of field names to fields. This allows attributes to peek values from
/// other fields.
pub(crate) fn build_field_mapping<'a>(structure: &Structure<'a>) -> HashMap<String, TokenStream> {
let mut fields_map = HashMap::new();
let ast = structure.ast();
if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
for field in fields.iter() {
if let Some(ident) = &field.ident {
fields_map.insert(ident.to_string(), quote! { &self.#ident });
}
}
}
fields_map
}