mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	feat: Make unqualified derive attributes flyimportable
This commit is contained in:
		
							parent
							
								
									7fdbdc4ab2
								
							
						
					
					
						commit
						ebd63ec1cf
					
				
							
								
								
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -99,6 +99,7 @@ dependencies = [
 | 
				
			|||||||
 "profile",
 | 
					 "profile",
 | 
				
			||||||
 "rustc-hash",
 | 
					 "rustc-hash",
 | 
				
			||||||
 "salsa",
 | 
					 "salsa",
 | 
				
			||||||
 | 
					 "stdx",
 | 
				
			||||||
 "syntax",
 | 
					 "syntax",
 | 
				
			||||||
 "test_utils",
 | 
					 "test_utils",
 | 
				
			||||||
 "tt",
 | 
					 "tt",
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ salsa = "0.17.0-pre.2"
 | 
				
			|||||||
rustc-hash = "1.1.0"
 | 
					rustc-hash = "1.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
syntax = { path = "../syntax", version = "0.0.0" }
 | 
					syntax = { path = "../syntax", version = "0.0.0" }
 | 
				
			||||||
 | 
					stdx = { path = "../stdx", version = "0.0.0" }
 | 
				
			||||||
cfg = { path = "../cfg", version = "0.0.0" }
 | 
					cfg = { path = "../cfg", version = "0.0.0" }
 | 
				
			||||||
profile = { path = "../profile", version = "0.0.0" }
 | 
					profile = { path = "../profile", version = "0.0.0" }
 | 
				
			||||||
tt = { path = "../tt", version = "0.0.0" }
 | 
					tt = { path = "../tt", version = "0.0.0" }
 | 
				
			||||||
 | 
				
			|||||||
@ -270,7 +270,7 @@ fn test_proc_macros(proc_macros: &[String]) -> (Vec<ProcMacro>, String) {
 | 
				
			|||||||
pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
 | 
					pub fn identity(_attr: TokenStream, item: TokenStream) -> TokenStream {
 | 
				
			||||||
    item
 | 
					    item
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#[proc_macro_derive(derive_identity)]
 | 
					#[proc_macro_derive(DeriveIdentity)]
 | 
				
			||||||
pub fn derive_identity(item: TokenStream) -> TokenStream {
 | 
					pub fn derive_identity(item: TokenStream) -> TokenStream {
 | 
				
			||||||
    item
 | 
					    item
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -290,7 +290,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
 | 
				
			|||||||
            expander: Arc::new(IdentityProcMacroExpander),
 | 
					            expander: Arc::new(IdentityProcMacroExpander),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        ProcMacro {
 | 
					        ProcMacro {
 | 
				
			||||||
            name: "derive_identity".into(),
 | 
					            name: "DeriveIdentity".into(),
 | 
				
			||||||
            kind: crate::ProcMacroKind::CustomDerive,
 | 
					            kind: crate::ProcMacroKind::CustomDerive,
 | 
				
			||||||
            expander: Arc::new(IdentityProcMacroExpander),
 | 
					            expander: Arc::new(IdentityProcMacroExpander),
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -306,7 +306,7 @@ pub fn mirror(input: TokenStream) -> TokenStream {
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    .into_iter()
 | 
					    .into_iter()
 | 
				
			||||||
    .filter(|pm| proc_macros.iter().any(|name| name == pm.name))
 | 
					    .filter(|pm| proc_macros.iter().any(|name| name == &stdx::to_lower_snake_case(&pm.name)))
 | 
				
			||||||
    .collect();
 | 
					    .collect();
 | 
				
			||||||
    (proc_macros, source.into())
 | 
					    (proc_macros, source.into())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1623,7 +1623,12 @@ impl MacroDef {
 | 
				
			|||||||
    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 | 
					    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
 | 
				
			||||||
        match self.source(db)?.value {
 | 
					        match self.source(db)?.value {
 | 
				
			||||||
            Either::Left(it) => it.name().map(|it| it.as_name()),
 | 
					            Either::Left(it) => it.name().map(|it| it.as_name()),
 | 
				
			||||||
            Either::Right(it) => it.name().map(|it| it.as_name()),
 | 
					            Either::Right(_) => {
 | 
				
			||||||
 | 
					                let krate = self.id.krate;
 | 
				
			||||||
 | 
					                let def_map = db.crate_def_map(krate);
 | 
				
			||||||
 | 
					                let (_, name) = def_map.exported_proc_macros().find(|&(id, _)| id == self.id)?;
 | 
				
			||||||
 | 
					                Some(name)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ fn derive_censoring() {
 | 
				
			|||||||
//- proc_macros: derive_identity
 | 
					//- proc_macros: derive_identity
 | 
				
			||||||
#[attr1]
 | 
					#[attr1]
 | 
				
			||||||
#[derive(Foo)]
 | 
					#[derive(Foo)]
 | 
				
			||||||
#[derive(proc_macros::derive_identity)]
 | 
					#[derive(proc_macros::DeriveIdentity)]
 | 
				
			||||||
#[derive(Bar)]
 | 
					#[derive(Bar)]
 | 
				
			||||||
#[attr2]
 | 
					#[attr2]
 | 
				
			||||||
struct S;
 | 
					struct S;
 | 
				
			||||||
@ -41,7 +41,7 @@ struct S;
 | 
				
			|||||||
        expect![[r##"
 | 
					        expect![[r##"
 | 
				
			||||||
#[attr1]
 | 
					#[attr1]
 | 
				
			||||||
#[derive(Foo)]
 | 
					#[derive(Foo)]
 | 
				
			||||||
#[derive(proc_macros::derive_identity)]
 | 
					#[derive(proc_macros::DeriveIdentity)]
 | 
				
			||||||
#[derive(Bar)]
 | 
					#[derive(Bar)]
 | 
				
			||||||
#[attr2]
 | 
					#[attr2]
 | 
				
			||||||
struct S;
 | 
					struct S;
 | 
				
			||||||
 | 
				
			|||||||
@ -103,7 +103,7 @@ pub struct DefMap {
 | 
				
			|||||||
    /// Side table with additional proc. macro info, for use by name resolution in downstream
 | 
					    /// Side table with additional proc. macro info, for use by name resolution in downstream
 | 
				
			||||||
    /// crates.
 | 
					    /// crates.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// (the primary purpose is to resolve derive helpers)
 | 
					    /// (the primary purpose is to resolve derive helpers and fetch a proc-macros name)
 | 
				
			||||||
    exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
 | 
					    exported_proc_macros: FxHashMap<MacroDefId, ProcMacroDef>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    edition: Edition,
 | 
					    edition: Edition,
 | 
				
			||||||
@ -279,7 +279,9 @@ impl DefMap {
 | 
				
			|||||||
    pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
 | 
					    pub fn modules(&self) -> impl Iterator<Item = (LocalModuleId, &ModuleData)> + '_ {
 | 
				
			||||||
        self.modules.iter()
 | 
					        self.modules.iter()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    pub fn exported_proc_macros(&self) -> impl Iterator<Item = (MacroDefId, Name)> + '_ {
 | 
				
			||||||
 | 
					        self.exported_proc_macros.iter().map(|(id, def)| (*id, def.name.clone()))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn root(&self) -> LocalModuleId {
 | 
					    pub fn root(&self) -> LocalModuleId {
 | 
				
			||||||
        self.root
 | 
					        self.root
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -63,8 +63,8 @@ impl Name {
 | 
				
			|||||||
    /// Ideally, we want a `gensym` semantics for missing names -- each missing
 | 
					    /// Ideally, we want a `gensym` semantics for missing names -- each missing
 | 
				
			||||||
    /// name is equal only to itself. It's not clear how to implement this in
 | 
					    /// name is equal only to itself. It's not clear how to implement this in
 | 
				
			||||||
    /// salsa though, so we punt on that bit for a moment.
 | 
					    /// salsa though, so we punt on that bit for a moment.
 | 
				
			||||||
    pub fn missing() -> Name {
 | 
					    pub const fn missing() -> Name {
 | 
				
			||||||
        Name::new_text("[missing name]".into())
 | 
					        Name::new_inline("[missing name]")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Returns the tuple index this name represents if it is a tuple field.
 | 
					    /// Returns the tuple index this name represents if it is a tuple field.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,15 @@
 | 
				
			|||||||
//! Completion for derives
 | 
					//! Completion for derives
 | 
				
			||||||
use hir::{HasAttrs, MacroDef, MacroKind};
 | 
					use hir::{HasAttrs, MacroDef, MacroKind};
 | 
				
			||||||
use ide_db::helpers::FamousDefs;
 | 
					use ide_db::helpers::{import_assets::ImportAssets, insert_use::ImportScope, FamousDefs};
 | 
				
			||||||
use itertools::Itertools;
 | 
					use itertools::Itertools;
 | 
				
			||||||
use rustc_hash::FxHashSet;
 | 
					use rustc_hash::FxHashSet;
 | 
				
			||||||
use syntax::ast;
 | 
					use syntax::{ast, SyntaxKind};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
 | 
					    completions::flyimport::compute_fuzzy_completion_order_key,
 | 
				
			||||||
    context::CompletionContext,
 | 
					    context::CompletionContext,
 | 
				
			||||||
    item::{CompletionItem, CompletionItemKind},
 | 
					    item::{CompletionItem, CompletionItemKind},
 | 
				
			||||||
    Completions,
 | 
					    Completions, ImportEdit,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(super) fn complete_derive(
 | 
					pub(super) fn complete_derive(
 | 
				
			||||||
@ -66,6 +67,8 @@ pub(super) fn complete_derive(
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        item.add_to(acc);
 | 
					        item.add_to(acc);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    flyimport_attribute(ctx, acc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
 | 
					fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
 | 
				
			||||||
@ -80,6 +83,50 @@ fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, MacroDef)> {
 | 
				
			|||||||
    result
 | 
					    result
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn flyimport_attribute(ctx: &CompletionContext, acc: &mut Completions) -> Option<()> {
 | 
				
			||||||
 | 
					    if ctx.token.kind() != SyntaxKind::IDENT {
 | 
				
			||||||
 | 
					        return None;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    let potential_import_name = ctx.token.to_string();
 | 
				
			||||||
 | 
					    let module = ctx.scope.module()?;
 | 
				
			||||||
 | 
					    let parent = ctx.token.parent()?;
 | 
				
			||||||
 | 
					    let user_input_lowercased = potential_import_name.to_lowercase();
 | 
				
			||||||
 | 
					    let import_assets = ImportAssets::for_fuzzy_path(
 | 
				
			||||||
 | 
					        module,
 | 
				
			||||||
 | 
					        None,
 | 
				
			||||||
 | 
					        potential_import_name,
 | 
				
			||||||
 | 
					        &ctx.sema,
 | 
				
			||||||
 | 
					        parent.clone(),
 | 
				
			||||||
 | 
					    )?;
 | 
				
			||||||
 | 
					    let import_scope = ImportScope::find_insert_use_container_with_macros(&parent, &ctx.sema)?;
 | 
				
			||||||
 | 
					    acc.add_all(
 | 
				
			||||||
 | 
					        import_assets
 | 
				
			||||||
 | 
					            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
 | 
				
			||||||
 | 
					            .into_iter()
 | 
				
			||||||
 | 
					            .filter_map(|import| match import.original_item {
 | 
				
			||||||
 | 
					                hir::ItemInNs::Macros(mac) => Some((import, mac)),
 | 
				
			||||||
 | 
					                _ => None,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .filter(|&(_, mac)| !ctx.is_item_hidden(&hir::ItemInNs::Macros(mac)))
 | 
				
			||||||
 | 
					            .sorted_by_key(|(import, _)| {
 | 
				
			||||||
 | 
					                compute_fuzzy_completion_order_key(&import.import_path, &user_input_lowercased)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .filter_map(|(import, mac)| {
 | 
				
			||||||
 | 
					                let mut item = CompletionItem::new(
 | 
				
			||||||
 | 
					                    CompletionItemKind::Attribute,
 | 
				
			||||||
 | 
					                    ctx.source_range(),
 | 
				
			||||||
 | 
					                    mac.name(ctx.db)?.to_string(),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                item.add_import(ImportEdit { import, scope: import_scope.clone() });
 | 
				
			||||||
 | 
					                if let Some(docs) = mac.docs(ctx.db) {
 | 
				
			||||||
 | 
					                    item.documentation(docs);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                Some(item.build())
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    Some(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct DeriveDependencies {
 | 
					struct DeriveDependencies {
 | 
				
			||||||
    label: &'static str,
 | 
					    label: &'static str,
 | 
				
			||||||
    dependencies: &'static [&'static str],
 | 
					    dependencies: &'static [&'static str],
 | 
				
			||||||
 | 
				
			|||||||
@ -125,12 +125,12 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
 | 
					    let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let user_input_lowercased = potential_import_name.to_lowercase();
 | 
					    let user_input_lowercased = potential_import_name.to_lowercase();
 | 
				
			||||||
    let import_assets = import_assets(ctx, potential_import_name)?;
 | 
					    let import_assets = import_assets(ctx, potential_import_name)?;
 | 
				
			||||||
    let import_scope = ImportScope::find_insert_use_container_with_macros(
 | 
					    let import_scope = ImportScope::find_insert_use_container_with_macros(
 | 
				
			||||||
        position_for_import(ctx, Some(import_assets.import_candidate()))?,
 | 
					        &position_for_import(ctx, Some(import_assets.import_candidate()))?,
 | 
				
			||||||
        &ctx.sema,
 | 
					        &ctx.sema,
 | 
				
			||||||
    )?;
 | 
					    )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -158,21 +158,19 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
 | 
				
			|||||||
    Some(())
 | 
					    Some(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) fn position_for_import<'a>(
 | 
					pub(crate) fn position_for_import(
 | 
				
			||||||
    ctx: &'a CompletionContext,
 | 
					    ctx: &CompletionContext,
 | 
				
			||||||
    import_candidate: Option<&ImportCandidate>,
 | 
					    import_candidate: Option<&ImportCandidate>,
 | 
				
			||||||
) -> Option<&'a SyntaxNode> {
 | 
					) -> Option<SyntaxNode> {
 | 
				
			||||||
    Some(match import_candidate {
 | 
					    Some(
 | 
				
			||||||
        Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
 | 
					        match import_candidate {
 | 
				
			||||||
        Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
 | 
					            Some(ImportCandidate::Path(_)) => ctx.name_syntax.as_ref()?.syntax(),
 | 
				
			||||||
        Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
 | 
					            Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
 | 
				
			||||||
        None => ctx
 | 
					            Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
 | 
				
			||||||
            .name_syntax
 | 
					            None => return ctx.original_token.parent(),
 | 
				
			||||||
            .as_ref()
 | 
					        }
 | 
				
			||||||
            .map(|name_ref| name_ref.syntax())
 | 
					        .clone(),
 | 
				
			||||||
            .or_else(|| ctx.path_qual().map(|path| path.syntax()))
 | 
					    )
 | 
				
			||||||
            .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?,
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
 | 
					fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
 | 
				
			||||||
@ -205,7 +203,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn compute_fuzzy_completion_order_key(
 | 
					pub(crate) fn compute_fuzzy_completion_order_key(
 | 
				
			||||||
    proposed_mod_path: &hir::ModPath,
 | 
					    proposed_mod_path: &hir::ModPath,
 | 
				
			||||||
    user_input_lowercased: &str,
 | 
					    user_input_lowercased: &str,
 | 
				
			||||||
) -> usize {
 | 
					) -> usize {
 | 
				
			||||||
 | 
				
			|||||||
@ -182,7 +182,7 @@ pub fn resolve_completion_edits(
 | 
				
			|||||||
) -> Option<Vec<TextEdit>> {
 | 
					) -> Option<Vec<TextEdit>> {
 | 
				
			||||||
    let _p = profile::span("resolve_completion_edits");
 | 
					    let _p = profile::span("resolve_completion_edits");
 | 
				
			||||||
    let ctx = CompletionContext::new(db, position, config)?;
 | 
					    let ctx = CompletionContext::new(db, position, config)?;
 | 
				
			||||||
    let position_for_import = position_for_import(&ctx, None)?;
 | 
					    let position_for_import = &position_for_import(&ctx, None)?;
 | 
				
			||||||
    let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
 | 
					    let scope = ImportScope::find_insert_use_container_with_macros(position_for_import, &ctx.sema)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let current_module = ctx.sema.scope(position_for_import).module()?;
 | 
					    let current_module = ctx.sema.scope(position_for_import).module()?;
 | 
				
			||||||
 | 
				
			|||||||
@ -640,6 +640,45 @@ mod derive {
 | 
				
			|||||||
            "#]],
 | 
					            "#]],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn derive_flyimport() {
 | 
				
			||||||
 | 
					        check_derive(
 | 
				
			||||||
 | 
					            r#"
 | 
				
			||||||
 | 
					//- proc_macros: derive_identity
 | 
				
			||||||
 | 
					#[derive(der$0)] struct Test;
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					            expect![[r#"
 | 
				
			||||||
 | 
					                at DeriveIdentity (use proc_macros::DeriveIdentity)
 | 
				
			||||||
 | 
					            "#]],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        check_derive(
 | 
				
			||||||
 | 
					            r#"
 | 
				
			||||||
 | 
					//- proc_macros: derive_identity
 | 
				
			||||||
 | 
					use proc_macros::DeriveIdentity;
 | 
				
			||||||
 | 
					#[derive(der$0)] struct Test;
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					            expect![[r#"
 | 
				
			||||||
 | 
					                at DeriveIdentity
 | 
				
			||||||
 | 
					            "#]],
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn derive_flyimport_edit() {
 | 
				
			||||||
 | 
					        check_edit(
 | 
				
			||||||
 | 
					            "DeriveIdentity",
 | 
				
			||||||
 | 
					            r#"
 | 
				
			||||||
 | 
					//- proc_macros: derive_identity
 | 
				
			||||||
 | 
					#[derive(der$0)] struct Test;
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					            r#"
 | 
				
			||||||
 | 
					use proc_macros::DeriveIdentity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(DeriveIdentity)] struct Test;
 | 
				
			||||||
 | 
					"#,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod lint {
 | 
					mod lint {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user