mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +00:00 
			
		
		
		
	Merge pull request #18853 from ChayimFriedman2/no-completion
Fix case where completion inside macro that expands to `#[test]` was unavailable
This commit is contained in:
		
						commit
						cd12ef8547
					
				
					 3 changed files with 105 additions and 5 deletions
				
			
		|  | @ -1316,6 +1316,7 @@ impl DefCollector<'_> { | ||||||
|                     // being cfg'ed out).
 |                     // being cfg'ed out).
 | ||||||
|                     // Ideally we will just expand them to nothing here. But we are only collecting macro calls,
 |                     // Ideally we will just expand them to nothing here. But we are only collecting macro calls,
 | ||||||
|                     // not expanding them, so we have no way to do that.
 |                     // not expanding them, so we have no way to do that.
 | ||||||
|  |                     // If you add an ignored attribute here, also add it to `Semantics::might_be_inside_macro_call()`.
 | ||||||
|                     if matches!( |                     if matches!( | ||||||
|                         def.kind, |                         def.kind, | ||||||
|                         MacroDefKind::BuiltInAttr(_, expander) |                         MacroDefKind::BuiltInAttr(_, expander) | ||||||
|  |  | ||||||
|  | @ -30,7 +30,7 @@ use hir_expand::{ | ||||||
|     name::AsName, |     name::AsName, | ||||||
|     ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, |     ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, | ||||||
| }; | }; | ||||||
| use intern::Symbol; | use intern::{sym, Symbol}; | ||||||
| use itertools::Itertools; | use itertools::Itertools; | ||||||
| use rustc_hash::{FxHashMap, FxHashSet}; | use rustc_hash::{FxHashMap, FxHashSet}; | ||||||
| use smallvec::{smallvec, SmallVec}; | use smallvec::{smallvec, SmallVec}; | ||||||
|  | @ -811,10 +811,37 @@ impl<'db> SemanticsImpl<'db> { | ||||||
|             item.attrs().any(|attr| { |             item.attrs().any(|attr| { | ||||||
|                 let Some(meta) = attr.meta() else { return false }; |                 let Some(meta) = attr.meta() else { return false }; | ||||||
|                 let Some(path) = meta.path() else { return false }; |                 let Some(path) = meta.path() else { return false }; | ||||||
|                 let Some(attr_name) = path.as_single_name_ref() else { return true }; |                 if let Some(attr_name) = path.as_single_name_ref() { | ||||||
|                     let attr_name = attr_name.text(); |                     let attr_name = attr_name.text(); | ||||||
|                 let attr_name = attr_name.as_str(); |                     let attr_name = Symbol::intern(attr_name.as_str()); | ||||||
|                 attr_name == "derive" || find_builtin_attr_idx(&Symbol::intern(attr_name)).is_none() |                     if attr_name == sym::derive { | ||||||
|  |                         return true; | ||||||
|  |                     } | ||||||
|  |                     // We ignore `#[test]` and friends in the def map, so we cannot expand them.
 | ||||||
|  |                     // FIXME: We match by text. This is both hacky and incorrect (people can, and do, create
 | ||||||
|  |                     // other macros named `test`). We cannot fix that unfortunately because we use this method
 | ||||||
|  |                     // for speculative expansion in completion, which we cannot analyze. Fortunately, most macros
 | ||||||
|  |                     // named `test` are test-like, meaning their expansion is not terribly important for IDE.
 | ||||||
|  |                     if attr_name == sym::test | ||||||
|  |                         || attr_name == sym::bench | ||||||
|  |                         || attr_name == sym::test_case | ||||||
|  |                         || find_builtin_attr_idx(&attr_name).is_some() | ||||||
|  |                     { | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 let mut segments = path.segments(); | ||||||
|  |                 let mut next_segment_text = || segments.next().and_then(|it| it.name_ref()); | ||||||
|  |                 // `#[core::prelude::rust_2024::test]` or `#[std::prelude::rust_2024::test]`.
 | ||||||
|  |                 if next_segment_text().is_some_and(|it| matches!(&*it.text(), "core" | "std")) | ||||||
|  |                     && next_segment_text().is_some_and(|it| it.text() == "prelude") | ||||||
|  |                     && next_segment_text().is_some() | ||||||
|  |                     && next_segment_text() | ||||||
|  |                         .is_some_and(|it| matches!(&*it.text(), "test" | "bench" | "test_case")) | ||||||
|  |                 { | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 true | ||||||
|             }) |             }) | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -241,3 +241,75 @@ impl Copy for S where $0 | ||||||
| "#,
 | "#,
 | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #[test] | ||||||
|  | fn test_is_not_considered_macro() { | ||||||
|  |     check( | ||||||
|  |         r#" | ||||||
|  | #[rustc_builtin] | ||||||
|  | pub macro test($item:item) { | ||||||
|  |     /* compiler built-in */ | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | macro_rules! expand_to_test { | ||||||
|  |     ( $i:ident ) => { | ||||||
|  |         #[test] | ||||||
|  |         fn foo() { $i; } | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn bar() { | ||||||
|  |     let value = 5; | ||||||
|  |     expand_to_test!(v$0); | ||||||
|  | } | ||||||
|  |     "#,
 | ||||||
|  |         expect![[r#" | ||||||
|  |             ct CONST                                     Unit | ||||||
|  |             en Enum                                      Enum | ||||||
|  |             fn bar()                                     fn() | ||||||
|  |             fn foo()                                     fn() | ||||||
|  |             fn function()                                fn() | ||||||
|  |             ma expand_to_test!(…) macro_rules! expand_to_test | ||||||
|  |             ma makro!(…)                   macro_rules! makro | ||||||
|  |             ma test!(…)                            macro test | ||||||
|  |             md module | ||||||
|  |             sc STATIC                                    Unit | ||||||
|  |             st Record                                  Record | ||||||
|  |             st Tuple                                    Tuple | ||||||
|  |             st Unit                                      Unit | ||||||
|  |             un Union                                    Union | ||||||
|  |             ev TupleV(…)                          TupleV(u32) | ||||||
|  |             bt u32                                        u32 | ||||||
|  |             kw async | ||||||
|  |             kw const | ||||||
|  |             kw crate:: | ||||||
|  |             kw enum | ||||||
|  |             kw extern | ||||||
|  |             kw false | ||||||
|  |             kw fn | ||||||
|  |             kw for | ||||||
|  |             kw if | ||||||
|  |             kw if let | ||||||
|  |             kw impl | ||||||
|  |             kw let | ||||||
|  |             kw loop | ||||||
|  |             kw match | ||||||
|  |             kw mod | ||||||
|  |             kw return | ||||||
|  |             kw self:: | ||||||
|  |             kw static | ||||||
|  |             kw struct | ||||||
|  |             kw trait | ||||||
|  |             kw true | ||||||
|  |             kw type | ||||||
|  |             kw union | ||||||
|  |             kw unsafe | ||||||
|  |             kw use | ||||||
|  |             kw while | ||||||
|  |             kw while let | ||||||
|  |             sn macro_rules | ||||||
|  |             sn pd | ||||||
|  |             sn ppd | ||||||
|  |         "#]],
 | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Laurențiu Nicola
						Laurențiu Nicola