From d085cad4370ab9759e616a7a4513f78cfe0b21be Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 31 Oct 2021 14:35:26 +0530 Subject: rework macros crate, add attr parser for explainations --- macros/src/lib.rs | 173 ++++-------------------------------------------------- 1 file changed, 11 insertions(+), 162 deletions(-) (limited to 'macros/src/lib.rs') diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 127b4cb..86fa509 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,44 +1,12 @@ -use std::collections::HashMap; +mod explain; +mod metadata; +use explain::generate_explain_impl; +use metadata::{generate_meta_impl, RawLintMeta}; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; - -use quote::{format_ident, quote}; -use syn::{ - parse::{Parse, ParseStream, Result as ParseResult}, - parse_macro_input, - punctuated::Punctuated, - Expr, Ident, ItemStruct, Lit, Token, -}; - -struct KeyValue { - key: Ident, - _eq: Token![=], - value: Expr, -} - -impl Parse for KeyValue { - fn parse(input: ParseStream) -> ParseResult { - Ok(Self { - key: input.parse()?, - _eq: input.parse()?, - value: input.parse()?, - }) - } -} - -struct LintMeta(HashMap); - -impl Parse for LintMeta { - fn parse(input: ParseStream) -> ParseResult { - Ok(Self( - Punctuated::::parse_terminated(input)? - .into_iter() - .map(|item| (item.key, item.value)) - .collect(), - )) - } -} +use quote::quote; +use syn::{parse_macro_input, Ident, ItemStruct}; fn generate_self_impl(struct_name: &Ident) -> TokenStream2 { quote! { @@ -50,136 +18,16 @@ fn generate_self_impl(struct_name: &Ident) -> TokenStream2 { } } -fn generate_meta_impl(struct_name: &Ident, meta: &LintMeta) -> TokenStream2 { - let name_fn = generate_name_fn(meta); - let note_fn = generate_note_fn(meta); - let code_fn = generate_code_fn(meta); - let report_fn = generate_report_fn(); - let match_with_fn = generate_match_with_fn(meta); - let match_kind = generate_match_kind(meta); - quote! { - impl Metadata for #struct_name { - #name_fn - #note_fn - #code_fn - #report_fn - #match_with_fn - #match_kind - } - } -} - -fn generate_name_fn(meta: &LintMeta) -> TokenStream2 { - let name = meta - .0 - .get(&format_ident!("name")) - .unwrap_or_else(|| panic!("`name` not present")); - if let syn::Expr::Lit(name_lit) = name { - if let Lit::Str(name_str) = &name_lit.lit { - return quote! { - fn name() -> &'static str { - #name_str - } - }; - } - } - panic!("Invalid value for `name`"); -} - -fn generate_note_fn(meta: &LintMeta) -> TokenStream2 { - let note = meta - .0 - .get(&format_ident!("note")) - .unwrap_or_else(|| panic!("`note` not present")); - if let syn::Expr::Lit(note_lit) = note { - if let Lit::Str(note_str) = ¬e_lit.lit { - return quote! { - fn note() -> &'static str { - #note_str - } - }; - } - } - panic!("Invalid value for `note`"); -} - -fn generate_code_fn(meta: &LintMeta) -> TokenStream2 { - let code = meta - .0 - .get(&format_ident!("code")) - .unwrap_or_else(|| panic!("`code` not present")); - if let syn::Expr::Lit(code_lit) = code { - if let Lit::Int(code_int) = &code_lit.lit { - return quote! { - fn code() -> u32 { - #code_int - } - }; - } - } - panic!("Invalid value for `note`"); -} - -fn generate_report_fn() -> TokenStream2 { - quote! { - fn report() -> Report { - Report::new(Self::note(), Self::code()) - } - } -} - -fn generate_match_with_fn(meta: &LintMeta) -> TokenStream2 { - let match_with_lit = meta - .0 - .get(&format_ident!("match_with")) - .unwrap_or_else(|| panic!("`match_with` not present")); - if let syn::Expr::Path(match_path) = match_with_lit { - quote! { - fn match_with(&self, with: &SyntaxKind) -> bool { - #match_path == *with - } - } - } else if let syn::Expr::Array(array_expr) = match_with_lit { - quote! { - fn match_with(&self, with: &SyntaxKind) -> bool { - #array_expr.contains(with) - } - } - } else { - panic!("`match_with` has non-path value") - } -} - -fn generate_match_kind(meta: &LintMeta) -> TokenStream2 { - let match_with_lit = meta - .0 - .get(&format_ident!("match_with")) - .unwrap_or_else(|| panic!("`match_with` not present")); - if let syn::Expr::Path(match_path) = match_with_lit { - quote! { - fn match_kind(&self) -> Vec { - vec![#match_path] - } - } - } else if let syn::Expr::Array(array_expr) = match_with_lit { - quote! { - fn match_kind(&self) -> Vec { - #array_expr.to_vec() - } - } - } else { - panic!("`match_with` has non-path value") - } -} - #[proc_macro_attribute] pub fn lint(attr: TokenStream, item: TokenStream) -> TokenStream { let struct_item = parse_macro_input!(item as ItemStruct); - let meta = parse_macro_input!(attr as LintMeta); + let meta = parse_macro_input!(attr as RawLintMeta); let struct_name = &struct_item.ident; let self_impl = generate_self_impl(struct_name); let meta_impl = generate_meta_impl(struct_name, &meta); + let explain_impl = generate_explain_impl(&struct_item); + (quote! { #struct_item @@ -189,8 +37,9 @@ pub fn lint(attr: TokenStream, item: TokenStream) -> TokenStream { #self_impl #meta_impl + #explain_impl - impl Lint for #struct_name {} + impl crate::Lint for #struct_name {} }) .into() } -- cgit v1.2.3