diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs index 37e2a99e60ff..710bffcefe90 100644 --- a/crates/hir-def/src/attr.rs +++ b/crates/hir-def/src/attr.rs @@ -122,6 +122,11 @@ impl Attrs { AttrQuery { attrs: self, key } } + pub fn rust_analyzer_tool(&self) -> impl Iterator { + self.iter() + .filter(|&attr| attr.path.segments().first().is_some_and(|s| *s == sym::rust_analyzer)) + } + pub fn cfg(&self) -> Option { let mut cfgs = self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse); let first = cfgs.next()?; diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 49c48a5d5904..d7e28da644ab 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -8,6 +8,7 @@ use std::mem; use base_db::CrateId; use either::Either; use hir_expand::{ + mod_path::tool_path, name::{AsName, Name}, span_map::{ExpansionSpanMap, SpanMap}, InFile, MacroDefId, @@ -27,6 +28,7 @@ use text_size::TextSize; use triomphe::Arc; use crate::{ + attr::Attrs, body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr}, builtin_type::BuiltinUint, data::adt::StructKind, @@ -212,6 +214,43 @@ impl ExprCollector<'_> { body: Option, is_async_fn: bool, ) -> (Body, BodySourceMap) { + let skip_body = match self.owner { + DefWithBodyId::FunctionId(it) => self.db.attrs(it.into()), + DefWithBodyId::StaticId(it) => self.db.attrs(it.into()), + DefWithBodyId::ConstId(it) => self.db.attrs(it.into()), + DefWithBodyId::InTypeConstId(_) => Attrs::EMPTY, + DefWithBodyId::VariantId(it) => self.db.attrs(it.into()), + } + .rust_analyzer_tool() + .any(|attr| *attr.path() == tool_path![skip]); + // If #[rust_analyzer::skip] annotated, only construct enough information for the signature + // and skip the body. + if skip_body { + self.body.body_expr = self.missing_expr(); + if let Some((param_list, mut attr_enabled)) = param_list { + if let Some(self_param) = + param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) + { + let is_mutable = + self_param.mut_token().is_some() && self_param.amp_token().is_none(); + let binding_id: la_arena::Idx = self.alloc_binding( + Name::new_symbol_root(sym::self_.clone()), + BindingAnnotation::new(is_mutable, false), + ); + self.body.self_param = Some(binding_id); + self.source_map.self_param = + Some(self.expander.in_file(AstPtr::new(&self_param))); + } + self.body.params = param_list + .params() + .zip(attr_enabled) + .filter(|(_, enabled)| *enabled) + .map(|_| self.missing_pat()) + .collect(); + }; + return (self.body, self.source_map); + } + self.awaitable_context.replace(if is_async_fn { Awaitable::Yes } else { diff --git a/crates/hir-def/src/body/tests.rs b/crates/hir-def/src/body/tests.rs index 7e15a9f2d618..a9ca1c5069af 100644 --- a/crates/hir-def/src/body/tests.rs +++ b/crates/hir-def/src/body/tests.rs @@ -444,3 +444,18 @@ fn foo() { }"# ); } + +#[test] +fn skip_skips_body() { + let (db, body, owner) = lower( + r#" +#[rust_analyzer::skip] +async fn foo(a: (), b: i32) -> u32 { + 0 + 1 + b() +} +"#, + ); + let printed = body.pretty_print(&db, owner, Edition::CURRENT); + expect!["fn foo(�: (), �: i32) -> impl ::core::future::Future:: �"] + .assert_eq(&printed); +} diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs index 876919f3ed73..4f2f9ec40d0b 100644 --- a/crates/hir-expand/src/mod_path.rs +++ b/crates/hir-expand/src/mod_path.rs @@ -414,3 +414,14 @@ macro_rules! __path { } pub use crate::__path as path; + +#[macro_export] +macro_rules! __tool_path { + ($start:ident $(:: $seg:ident)*) => ({ + $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Plain, vec![ + $crate::name::Name::new_symbol_root(intern::sym::rust_analyzer.clone()), $crate::name::Name::new_symbol_root(intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root(intern::sym::$seg.clone()),)* + ]) + }); +} + +pub use crate::__tool_path as tool_path; diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 5f0f341f393e..156366045705 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -3802,3 +3802,15 @@ fn foo() { "#, ); } + +#[test] +fn tool_attr_skip() { + check_no_mismatches( + r#" +#[rust_analyzer::skip] +async fn foo(a: (), b: i32) -> u32 { + 0 + 1 + b() +} + "#, + ); +} diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index c7ebd9a35317..512b7e62fd2b 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs @@ -24,9 +24,10 @@ pub(crate) fn goto_type_definition( let file: ast::SourceFile = sema.parse_guess_edition(file_id); let token: SyntaxToken = pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | T![self] => 2, + IDENT | INT_NUMBER | T![self] => 3, kind if kind.is_trivia() => 0, - _ => 1, + T![;] => 1, + _ => 2, })?; let mut res = Vec::new(); diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs index 66b8900109c2..131b21a46b8d 100644 --- a/crates/intern/src/symbol/symbols.rs +++ b/crates/intern/src/symbol/symbols.rs @@ -429,6 +429,7 @@ define_symbols! { shr, simd, sized, + skip, slice_len_fn, Some, start,