Improve macro descension API

This commit is contained in:
Lukas Wirth 2023-12-03 20:20:38 +01:00
parent 986577faaa
commit 5b8e386bae
21 changed files with 179 additions and 139 deletions

View file

@ -629,8 +629,6 @@ impl ExpansionInfo {
pub fn map_range_down<'a>( pub fn map_range_down<'a>(
&'a self, &'a self,
span: SpanData, span: SpanData,
// FIXME: use this for range mapping, so that we can resolve inline format args
_relative_token_offset: Option<TextSize>,
) -> Option<impl Iterator<Item = InMacroFile<SyntaxToken>> + 'a> { ) -> Option<impl Iterator<Item = InMacroFile<SyntaxToken>> + 'a> {
let tokens = self let tokens = self
.exp_map .exp_map

View file

@ -92,7 +92,9 @@ pub use crate::{
attrs::{resolve_doc_path_on, HasAttrs}, attrs::{resolve_doc_path_on, HasAttrs},
diagnostics::*, diagnostics::*,
has_source::HasSource, has_source::HasSource,
semantics::{PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits}, semantics::{
DescendPreference, PathResolution, Semantics, SemanticsScope, TypeInfo, VisibleTraits,
},
}; };
// Be careful with these re-exports. // Be careful with these re-exports.

View file

@ -2,7 +2,11 @@
mod source_to_def; mod source_to_def;
use std::{cell::RefCell, fmt, iter, mem, ops}; use std::{
cell::RefCell,
fmt, iter, mem,
ops::{self, ControlFlow},
};
use base_db::{FileId, FileRange}; use base_db::{FileId, FileRange};
use either::Either; use either::Either;
@ -39,6 +43,12 @@ use crate::{
TypeAlias, TypeParam, VariantDef, TypeAlias, TypeParam, VariantDef,
}; };
pub enum DescendPreference {
SameText,
SameKind,
None,
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum PathResolution { pub enum PathResolution {
/// An item /// An item
@ -397,6 +407,7 @@ impl<'db> SemanticsImpl<'db> {
// This might not be the correct way to do this, but it works for now // This might not be the correct way to do this, but it works for now
let mut res = smallvec![]; let mut res = smallvec![];
let tokens = (|| { let tokens = (|| {
// FIXME: the trivia skipping should not be necessary
let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?; let first = skip_trivia_token(node.syntax().first_token()?, Direction::Next)?;
let last = skip_trivia_token(node.syntax().last_token()?, Direction::Prev)?; let last = skip_trivia_token(node.syntax().last_token()?, Direction::Prev)?;
Some((first, last)) Some((first, last))
@ -407,18 +418,19 @@ impl<'db> SemanticsImpl<'db> {
}; };
if first == last { if first == last {
// node is just the token, so descend the token
self.descend_into_macros_impl(first, 0.into(), &mut |InFile { value, .. }| { self.descend_into_macros_impl(first, 0.into(), &mut |InFile { value, .. }| {
if let Some(node) = value.parent_ancestors().find_map(N::cast) { if let Some(node) = value.parent_ancestors().find_map(N::cast) {
res.push(node) res.push(node)
} }
false ControlFlow::Continue(())
}); });
} else { } else {
// Descend first and last token, then zip them to look for the node they belong to // Descend first and last token, then zip them to look for the node they belong to
let mut scratch: SmallVec<[_; 1]> = smallvec![]; let mut scratch: SmallVec<[_; 1]> = smallvec![];
self.descend_into_macros_impl(first, 0.into(), &mut |token| { self.descend_into_macros_impl(first, 0.into(), &mut |token| {
scratch.push(token); scratch.push(token);
false ControlFlow::Continue(())
}); });
let mut scratch = scratch.into_iter(); let mut scratch = scratch.into_iter();
@ -441,7 +453,7 @@ impl<'db> SemanticsImpl<'db> {
} }
} }
} }
false ControlFlow::Continue(())
}, },
); );
} }
@ -453,32 +465,43 @@ impl<'db> SemanticsImpl<'db> {
/// be considered for the mapping in case of inline format args. /// be considered for the mapping in case of inline format args.
pub fn descend_into_macros( pub fn descend_into_macros(
&self, &self,
mode: DescendPreference,
token: SyntaxToken, token: SyntaxToken,
offset: TextSize, offset: TextSize,
) -> SmallVec<[SyntaxToken; 1]> { ) -> SmallVec<[SyntaxToken; 1]> {
let mut res = smallvec![]; enum Dp<'t> {
self.descend_into_macros_impl(token, offset, &mut |InFile { value, .. }| { SameText(&'t str),
res.push(value); SameKind(SyntaxKind),
false None,
}); }
res let fetch_kind = |token: &SyntaxToken| match token.parent() {
} Some(node) => match node.kind() {
kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => kind,
/// Descend the token into macrocalls to all its mapped counterparts that have the same text as the input token. _ => token.kind(),
/// },
/// Returns the original non descended token if none of the mapped counterparts have the same text. None => token.kind(),
pub fn descend_into_macros_with_same_text( };
&self, let mode = match mode {
token: SyntaxToken, DescendPreference::SameText => Dp::SameText(token.text()),
offset: TextSize, DescendPreference::SameKind => Dp::SameKind(fetch_kind(&token)),
) -> SmallVec<[SyntaxToken; 1]> { DescendPreference::None => Dp::None,
let text = token.text(); };
let mut res = smallvec![]; let mut res = smallvec![];
self.descend_into_macros_impl(token.clone(), offset, &mut |InFile { value, .. }| { self.descend_into_macros_impl(token.clone(), offset, &mut |InFile { value, .. }| {
if value.text() == text { let is_a_match = match mode {
Dp::SameText(text) => value.text() == text,
Dp::SameKind(preferred_kind) => {
let kind = fetch_kind(&value);
kind == preferred_kind
// special case for derive macros
|| (preferred_kind == SyntaxKind::IDENT && kind == SyntaxKind::NAME_REF)
}
Dp::None => true,
};
if is_a_match {
res.push(value); res.push(value);
} }
false ControlFlow::Continue(())
}); });
if res.is_empty() { if res.is_empty() {
res.push(token); res.push(token);
@ -486,44 +509,47 @@ impl<'db> SemanticsImpl<'db> {
res res
} }
pub fn descend_into_macros_with_kind_preference( pub fn descend_into_macros_single(
&self, &self,
mode: DescendPreference,
token: SyntaxToken, token: SyntaxToken,
offset: TextSize, offset: TextSize,
) -> SyntaxToken { ) -> SyntaxToken {
enum Dp<'t> {
SameText(&'t str),
SameKind(SyntaxKind),
None,
}
let fetch_kind = |token: &SyntaxToken| match token.parent() { let fetch_kind = |token: &SyntaxToken| match token.parent() {
Some(node) => match node.kind() { Some(node) => match node.kind() {
kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => { kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => kind,
node.parent().map_or(kind, |it| it.kind())
}
_ => token.kind(), _ => token.kind(),
}, },
None => token.kind(), None => token.kind(),
}; };
let preferred_kind = fetch_kind(&token); let mode = match mode {
let mut res = None; DescendPreference::SameText => Dp::SameText(token.text()),
self.descend_into_macros_impl(token.clone(), offset, &mut |InFile { value, .. }| { DescendPreference::SameKind => Dp::SameKind(fetch_kind(&token)),
if fetch_kind(&value) == preferred_kind { DescendPreference::None => Dp::None,
res = Some(value); };
true
} else {
if let None = res {
res = Some(value)
}
false
}
});
res.unwrap_or(token)
}
/// Descend the token into its macro call if it is part of one, returning the token in the
/// expansion that it is associated with. If `offset` points into the token's range, it will
/// be considered for the mapping in case of inline format args.
pub fn descend_into_macros_single(&self, token: SyntaxToken, offset: TextSize) -> SyntaxToken {
let mut res = token.clone(); let mut res = token.clone();
self.descend_into_macros_impl(token, offset, &mut |InFile { value, .. }| { self.descend_into_macros_impl(token.clone(), offset, &mut |InFile { value, .. }| {
res = value; let is_a_match = match mode {
true Dp::SameText(text) => value.text() == text,
Dp::SameKind(preferred_kind) => {
let kind = fetch_kind(&value);
kind == preferred_kind
// special case for derive macros
|| (preferred_kind == SyntaxKind::IDENT && kind == SyntaxKind::NAME_REF)
}
Dp::None => true,
};
if is_a_match {
res = value;
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}); });
res res
} }
@ -535,7 +561,7 @@ impl<'db> SemanticsImpl<'db> {
// FIXME: We might want this to be Option<TextSize> to be able to opt out of subrange // FIXME: We might want this to be Option<TextSize> to be able to opt out of subrange
// mapping, specifically for node downmapping // mapping, specifically for node downmapping
_offset: TextSize, _offset: TextSize,
f: &mut dyn FnMut(InFile<SyntaxToken>) -> bool, f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
) { ) {
// FIXME: Clean this up // FIXME: Clean this up
let _p = profile::span("descend_into_macros"); let _p = profile::span("descend_into_macros");
@ -560,25 +586,24 @@ impl<'db> SemanticsImpl<'db> {
let def_map = sa.resolver.def_map(); let def_map = sa.resolver.def_map();
let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)]; let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)];
let mut process_expansion_for_token = let mut process_expansion_for_token = |stack: &mut SmallVec<_>, macro_file| {
|stack: &mut SmallVec<_>, macro_file, _token: InFile<&_>| { let expansion_info = cache
let expansion_info = cache .entry(macro_file)
.entry(macro_file) .or_insert_with(|| macro_file.expansion_info(self.db.upcast()));
.or_insert_with(|| macro_file.expansion_info(self.db.upcast()));
{ {
let InFile { file_id, value } = expansion_info.expanded(); let InFile { file_id, value } = expansion_info.expanded();
self.cache(value, file_id); self.cache(value, file_id);
} }
let mapped_tokens = expansion_info.map_range_down(span, None)?; let mapped_tokens = expansion_info.map_range_down(span)?;
let len = stack.len(); let len = stack.len();
// requeue the tokens we got from mapping our current token down // requeue the tokens we got from mapping our current token down
stack.extend(mapped_tokens.map(Into::into)); stack.extend(mapped_tokens.map(Into::into));
// if the length changed we have found a mapping for the token // if the length changed we have found a mapping for the token
(stack.len() != len).then_some(()) (stack.len() != len).then_some(())
}; };
// Remap the next token in the queue into a macro call its in, if it is not being remapped // Remap the next token in the queue into a macro call its in, if it is not being remapped
// either due to not being in a macro-call or because its unused push it into the result vec, // either due to not being in a macro-call or because its unused push it into the result vec,
@ -598,7 +623,7 @@ impl<'db> SemanticsImpl<'db> {
}); });
if let Some(call_id) = containing_attribute_macro_call { if let Some(call_id) = containing_attribute_macro_call {
let file_id = call_id.as_macro_file(); let file_id = call_id.as_macro_file();
return process_expansion_for_token(&mut stack, file_id, token.as_ref()); return process_expansion_for_token(&mut stack, file_id);
} }
// Then check for token trees, that means we are either in a function-like macro or // Then check for token trees, that means we are either in a function-like macro or
@ -624,7 +649,7 @@ impl<'db> SemanticsImpl<'db> {
it it
} }
}; };
process_expansion_for_token(&mut stack, file_id, token.as_ref()) process_expansion_for_token(&mut stack, file_id)
} else if let Some(meta) = ast::Meta::cast(parent) { } else if let Some(meta) = ast::Meta::cast(parent) {
// attribute we failed expansion for earlier, this might be a derive invocation // attribute we failed expansion for earlier, this might be a derive invocation
// or derive helper attribute // or derive helper attribute
@ -646,11 +671,7 @@ impl<'db> SemanticsImpl<'db> {
Some(call_id) => { Some(call_id) => {
// resolved to a derive // resolved to a derive
let file_id = call_id.as_macro_file(); let file_id = call_id.as_macro_file();
return process_expansion_for_token( return process_expansion_for_token(&mut stack, file_id);
&mut stack,
file_id,
token.as_ref(),
);
} }
None => Some(adt), None => Some(adt),
} }
@ -682,11 +703,8 @@ impl<'db> SemanticsImpl<'db> {
def_map.derive_helpers_in_scope(InFile::new(token.file_id, id))?; def_map.derive_helpers_in_scope(InFile::new(token.file_id, id))?;
let mut res = None; let mut res = None;
for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) { for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) {
res = res.or(process_expansion_for_token( res =
&mut stack, res.or(process_expansion_for_token(&mut stack, derive.as_macro_file()));
derive.as_macro_file(),
token.as_ref(),
));
} }
res res
} else { } else {
@ -695,7 +713,7 @@ impl<'db> SemanticsImpl<'db> {
})() })()
.is_none(); .is_none();
if was_not_remapped && f(token) { if was_not_remapped && f(token).is_break() {
break; break;
} }
} }
@ -711,7 +729,7 @@ impl<'db> SemanticsImpl<'db> {
offset: TextSize, offset: TextSize,
) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ { ) -> impl Iterator<Item = impl Iterator<Item = SyntaxNode> + '_> + '_ {
node.token_at_offset(offset) node.token_at_offset(offset)
.map(move |token| self.descend_into_macros(token, offset)) .map(move |token| self.descend_into_macros(DescendPreference::None, token, offset))
.map(|descendants| { .map(|descendants| {
descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it)) descendants.into_iter().map(move |it| self.token_ancestors_with_macros(it))
}) })

View file

@ -1,4 +1,5 @@
use crate::{AssistContext, Assists}; use crate::{AssistContext, Assists};
use hir::DescendPreference;
use ide_db::{ use ide_db::{
assists::{AssistId, AssistKind}, assists::{AssistId, AssistKind},
syntax_helpers::{ syntax_helpers::{
@ -34,9 +35,11 @@ pub(crate) fn extract_expressions_from_format_string(
let fmt_string = ctx.find_token_at_offset::<ast::String>()?; let fmt_string = ctx.find_token_at_offset::<ast::String>()?;
let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?; let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
let expanded_t = ast::String::cast( let expanded_t = ast::String::cast(ctx.sema.descend_into_macros_single(
ctx.sema.descend_into_macros_with_kind_preference(fmt_string.syntax().clone(), 0.into()), DescendPreference::SameKind,
)?; fmt_string.syntax().clone(),
0.into(),
))?;
if !is_format_string(&expanded_t) { if !is_format_string(&expanded_t) {
return None; return None;
} }

View file

@ -3,8 +3,8 @@ use std::iter;
use ast::make; use ast::make;
use either::Either; use either::Either;
use hir::{ use hir::{
HasSource, HirDisplay, InFile, Local, LocalSource, ModuleDef, PathResolution, Semantics, DescendPreference, HasSource, HirDisplay, InFile, Local, LocalSource, ModuleDef,
TypeInfo, TypeParam, PathResolution, Semantics, TypeInfo, TypeParam,
}; };
use ide_db::{ use ide_db::{
defs::{Definition, NameRefClass}, defs::{Definition, NameRefClass},
@ -751,7 +751,9 @@ impl FunctionBody {
.descendants_with_tokens() .descendants_with_tokens()
.filter_map(SyntaxElement::into_token) .filter_map(SyntaxElement::into_token)
.filter(|it| matches!(it.kind(), SyntaxKind::IDENT | T![self])) .filter(|it| matches!(it.kind(), SyntaxKind::IDENT | T![self]))
.flat_map(|t| sema.descend_into_macros(t, 0.into())) .flat_map(|t| {
sema.descend_into_macros(DescendPreference::None, t, 0.into())
})
.for_each(|t| add_name_if_local(t.parent().and_then(ast::NameRef::cast))); .for_each(|t| add_name_if_local(t.parent().and_then(ast::NameRef::cast)));
} }
} }

View file

@ -3,7 +3,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use base_db::{FileId, SourceDatabaseExt}; use base_db::{FileId, SourceDatabaseExt};
use hir::{Crate, ItemInNs, ModuleDef, Name, Semantics}; use hir::{Crate, DescendPreference, ItemInNs, ModuleDef, Name, Semantics};
use syntax::{ use syntax::{
ast::{self, make}, ast::{self, make},
AstToken, SyntaxKind, SyntaxToken, TokenAtOffset, AstToken, SyntaxKind, SyntaxToken, TokenAtOffset,
@ -117,7 +117,7 @@ pub fn get_definition(
sema: &Semantics<'_, RootDatabase>, sema: &Semantics<'_, RootDatabase>,
token: SyntaxToken, token: SyntaxToken,
) -> Option<Definition> { ) -> Option<Definition> {
for token in sema.descend_into_macros(token, 0.into()) { for token in sema.descend_into_macros(DescendPreference::None, token, 0.into()) {
let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops); let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
if let Some(&[x]) = def.as_deref() { if let Some(&[x]) = def.as_deref() {
return Some(x); return Some(x);

View file

@ -8,8 +8,8 @@ use std::mem;
use base_db::{salsa::Database, FileId, FileRange, SourceDatabase, SourceDatabaseExt}; use base_db::{salsa::Database, FileId, FileRange, SourceDatabase, SourceDatabaseExt};
use hir::{ use hir::{
AsAssocItem, DefWithBody, HasAttrs, HasSource, HirFileIdExt, InFile, InRealFile, ModuleSource, AsAssocItem, DefWithBody, DescendPreference, HasAttrs, HasSource, HirFileIdExt, InFile,
Semantics, Visibility, InRealFile, ModuleSource, Semantics, Visibility,
}; };
use memchr::memmem::Finder; use memchr::memmem::Finder;
use nohash_hasher::IntMap; use nohash_hasher::IntMap;
@ -467,7 +467,9 @@ impl<'a> FindUsages<'a> {
// every textual hit. That function is notoriously // every textual hit. That function is notoriously
// expensive even for things that do not get down mapped // expensive even for things that do not get down mapped
// into macros. // into macros.
sema.descend_into_macros(token, offset).into_iter().filter_map(|it| it.parent()) sema.descend_into_macros(DescendPreference::None, token, offset)
.into_iter()
.filter_map(|it| it.parent())
}) })
}; };

View file

@ -1,6 +1,6 @@
//! Entry point for call-hierarchy //! Entry point for call-hierarchy
use hir::Semantics; use hir::{DescendPreference, Semantics};
use ide_db::{ use ide_db::{
defs::{Definition, NameClass, NameRefClass}, defs::{Definition, NameClass, NameRefClass},
helpers::pick_best_token, helpers::pick_best_token,
@ -87,7 +87,7 @@ pub(crate) fn outgoing_calls(
})?; })?;
let mut calls = CallLocations::default(); let mut calls = CallLocations::default();
sema.descend_into_macros(token, offset) sema.descend_into_macros(DescendPreference::None, token, offset)
.into_iter() .into_iter()
.filter_map(|it| it.parent_ancestors().nth(1).and_then(ast::Item::cast)) .filter_map(|it| it.parent_ancestors().nth(1).and_then(ast::Item::cast))
.filter_map(|item| match item { .filter_map(|item| match item {

View file

@ -12,7 +12,9 @@ use pulldown_cmark_to_cmark::{cmark_resume_with_options, Options as CMarkOptions
use stdx::format_to; use stdx::format_to;
use url::Url; use url::Url;
use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs}; use hir::{
db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, DescendPreference, HasAttrs,
};
use ide_db::{ use ide_db::{
base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase}, base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase},
defs::{Definition, NameClass, NameRefClass}, defs::{Definition, NameClass, NameRefClass},
@ -144,7 +146,7 @@ pub(crate) fn external_docs(
kind if kind.is_trivia() => 0, kind if kind.is_trivia() => 0,
_ => 1, _ => 1,
})?; })?;
let token = sema.descend_into_macros_single(token, offset); let token = sema.descend_into_macros_single(DescendPreference::None, token, offset);
let node = token.parent()?; let node = token.parent()?;
let definition = match_ast! { let definition = match_ast! {
@ -286,7 +288,7 @@ impl DocCommentToken {
let original_start = doc_token.text_range().start(); let original_start = doc_token.text_range().start();
let relative_comment_offset = offset - original_start - prefix_len; let relative_comment_offset = offset - original_start - prefix_len;
sema.descend_into_macros(doc_token, offset).into_iter().find_map(|t| { sema.descend_into_macros(DescendPreference::None,doc_token, offset).into_iter().find_map(|t| {
let (node, descended_prefix_len) = match_ast! { let (node, descended_prefix_len) = match_ast! {
match t { match t {
ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?), ast::Comment(comment) => (t.parent()?, TextSize::try_from(comment.prefix().len()).ok()?),

View file

@ -1,4 +1,4 @@
use hir::{HirFileIdExt, InFile, Semantics}; use hir::{DescendPreference, HirFileIdExt, InFile, Semantics};
use ide_db::{ use ide_db::{
base_db::FileId, helpers::pick_best_token, base_db::FileId, helpers::pick_best_token,
syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase,
@ -40,8 +40,10 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
// struct Bar; // struct Bar;
// ``` // ```
let derive = let derive = sema
sema.descend_into_macros(tok.clone(), 0.into()).into_iter().find_map(|descended| { .descend_into_macros(DescendPreference::None, tok.clone(), 0.into())
.into_iter()
.find_map(|descended| {
let hir_file = sema.hir_file_for(&descended.parent()?); let hir_file = sema.hir_file_for(&descended.parent()?);
if !hir_file.is_derive_attr_pseudo_expansion(db) { if !hir_file.is_derive_attr_pseudo_expansion(db) {
return None; return None;

View file

@ -1,6 +1,6 @@
use std::iter::successors; use std::iter::successors;
use hir::Semantics; use hir::{DescendPreference, Semantics};
use ide_db::RootDatabase; use ide_db::RootDatabase;
use syntax::{ use syntax::{
algo::{self, skip_trivia_token}, algo::{self, skip_trivia_token},
@ -140,10 +140,16 @@ fn extend_tokens_from_range(
// compute original mapped token range // compute original mapped token range
let extended = { let extended = {
let fst_expanded = let fst_expanded = sema.descend_into_macros_single(
sema.descend_into_macros_single(first_token.clone(), original_range.start()); DescendPreference::None,
let lst_expanded = first_token.clone(),
sema.descend_into_macros_single(last_token.clone(), original_range.end()); original_range.start(),
);
let lst_expanded = sema.descend_into_macros_single(
DescendPreference::None,
last_token.clone(),
original_range.end(),
);
let mut lca = let mut lca =
algo::least_common_ancestor(&fst_expanded.parent()?, &lst_expanded.parent()?)?; algo::least_common_ancestor(&fst_expanded.parent()?, &lst_expanded.parent()?)?;
lca = shallowest_node(&lca); lca = shallowest_node(&lca);
@ -157,7 +163,8 @@ fn extend_tokens_from_range(
let validate = |offset: TextSize| { let validate = |offset: TextSize| {
let extended = &extended; let extended = &extended;
move |token: &SyntaxToken| -> bool { move |token: &SyntaxToken| -> bool {
let expanded = sema.descend_into_macros_single(token.clone(), offset); let expanded =
sema.descend_into_macros_single(DescendPreference::None, token.clone(), offset);
let parent = match expanded.parent() { let parent = match expanded.parent() {
Some(it) => it, Some(it) => it,
None => return false, None => return false,

View file

@ -1,4 +1,4 @@
use hir::{AsAssocItem, Semantics}; use hir::{AsAssocItem, DescendPreference, Semantics};
use ide_db::{ use ide_db::{
defs::{Definition, NameClass, NameRefClass}, defs::{Definition, NameClass, NameRefClass},
RootDatabase, RootDatabase,
@ -29,7 +29,7 @@ pub(crate) fn goto_declaration(
.find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?; .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?;
let range = original_token.text_range(); let range = original_token.text_range();
let info: Vec<NavigationTarget> = sema let info: Vec<NavigationTarget> = sema
.descend_into_macros(original_token, offset) .descend_into_macros(DescendPreference::None, original_token, offset)
.iter() .iter()
.filter_map(|token| { .filter_map(|token| {
let parent = token.parent()?; let parent = token.parent()?;

View file

@ -4,7 +4,7 @@ use crate::{
doc_links::token_as_doc_comment, navigation_target::ToNav, FilePosition, NavigationTarget, doc_links::token_as_doc_comment, navigation_target::ToNav, FilePosition, NavigationTarget,
RangeInfo, TryToNav, RangeInfo, TryToNav,
}; };
use hir::{AsAssocItem, AssocItem, Semantics}; use hir::{AsAssocItem, AssocItem, DescendPreference, Semantics};
use ide_db::{ use ide_db::{
base_db::{AnchoredPath, FileId, FileLoader}, base_db::{AnchoredPath, FileId, FileLoader},
defs::{Definition, IdentClass}, defs::{Definition, IdentClass},
@ -56,7 +56,7 @@ pub(crate) fn goto_definition(
}); });
} }
let navs = sema let navs = sema
.descend_into_macros(original_token.clone(), offset) .descend_into_macros(DescendPreference::None, original_token.clone(), offset)
.into_iter() .into_iter()
.filter_map(|token| { .filter_map(|token| {
let parent = token.parent()?; let parent = token.parent()?;

View file

@ -1,4 +1,4 @@
use hir::{AsAssocItem, Impl, Semantics}; use hir::{AsAssocItem, DescendPreference, Impl, Semantics};
use ide_db::{ use ide_db::{
defs::{Definition, NameClass, NameRefClass}, defs::{Definition, NameClass, NameRefClass},
helpers::pick_best_token, helpers::pick_best_token,
@ -34,7 +34,7 @@ pub(crate) fn goto_implementation(
})?; })?;
let range = original_token.text_range(); let range = original_token.text_range();
let navs = let navs =
sema.descend_into_macros(original_token, offset) sema.descend_into_macros(DescendPreference::None, original_token, offset)
.into_iter() .into_iter()
.filter_map(|token| token.parent().and_then(ast::NameLike::cast)) .filter_map(|token| token.parent().and_then(ast::NameLike::cast))
.filter_map(|node| match &node { .filter_map(|node| match &node {

View file

@ -1,3 +1,4 @@
use hir::DescendPreference;
use ide_db::{base_db::Upcast, defs::Definition, helpers::pick_best_token, RootDatabase}; use ide_db::{base_db::Upcast, defs::Definition, helpers::pick_best_token, RootDatabase};
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T}; use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, T};
@ -37,7 +38,7 @@ pub(crate) fn goto_type_definition(
} }
}; };
let range = token.text_range(); let range = token.text_range();
sema.descend_into_macros(token, offset) sema.descend_into_macros(DescendPreference::None,token, offset)
.into_iter() .into_iter()
.filter_map(|token| { .filter_map(|token| {
let ty = sema let ty = sema

View file

@ -1,4 +1,4 @@
use hir::Semantics; use hir::{DescendPreference, Semantics};
use ide_db::{ use ide_db::{
base_db::{FileId, FilePosition, FileRange}, base_db::{FileId, FilePosition, FileRange},
defs::{Definition, IdentClass}, defs::{Definition, IdentClass},
@ -461,7 +461,7 @@ fn find_defs(
token: SyntaxToken, token: SyntaxToken,
offset: TextSize, offset: TextSize,
) -> FxHashSet<Definition> { ) -> FxHashSet<Definition> {
sema.descend_into_macros(token, offset) sema.descend_into_macros(DescendPreference::None, token, offset)
.into_iter() .into_iter()
.filter_map(|token| IdentClass::classify_token(sema, &token)) .filter_map(|token| IdentClass::classify_token(sema, &token))
.map(IdentClass::definitions_no_ops) .map(IdentClass::definitions_no_ops)

View file

@ -6,7 +6,7 @@ mod tests;
use std::iter; use std::iter;
use either::Either; use either::Either;
use hir::{db::DefDatabase, HasSource, LangItem, Semantics}; use hir::{db::DefDatabase, DescendPreference, HasSource, LangItem, Semantics};
use ide_db::{ use ide_db::{
base_db::FileRange, base_db::FileRange,
defs::{Definition, IdentClass, NameRefClass, OperatorClass}, defs::{Definition, IdentClass, NameRefClass, OperatorClass},
@ -161,11 +161,11 @@ fn hover_simple(
// prefer descending the same token kind in attribute expansions, in normal macros text // prefer descending the same token kind in attribute expansions, in normal macros text
// equivalency is more important // equivalency is more important
let descended = if in_attr { let descended = sema.descend_into_macros(
[sema.descend_into_macros_with_kind_preference(original_token.clone(), offset)].into() if in_attr { DescendPreference::SameKind } else { DescendPreference::SameText },
} else { original_token.clone(),
sema.descend_into_macros_with_same_text(original_token.clone(), offset) offset,
}; );
let descended = || descended.iter(); let descended = || descended.iter();
let result = descended() let result = descended()

View file

@ -1,7 +1,7 @@
//! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports) //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
//! for LSIF and LSP. //! for LSIF and LSP.
use hir::{AsAssocItem, AssocItemContainer, Crate, Semantics}; use hir::{AsAssocItem, AssocItemContainer, Crate, DescendPreference, Semantics};
use ide_db::{ use ide_db::{
base_db::{CrateOrigin, FilePosition, LangCrateOrigin}, base_db::{CrateOrigin, FilePosition, LangCrateOrigin},
defs::{Definition, IdentClass}, defs::{Definition, IdentClass},
@ -99,7 +99,7 @@ pub(crate) fn moniker(
}); });
} }
let navs = sema let navs = sema
.descend_into_macros(original_token.clone(), offset) .descend_into_macros(DescendPreference::None, original_token.clone(), offset)
.into_iter() .into_iter()
.filter_map(|token| { .filter_map(|token| {
IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| { IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops).map(|it| {

View file

@ -9,7 +9,7 @@
//! at the index that the match starts at and its tree parent is //! at the index that the match starts at and its tree parent is
//! resolved to the search element definition, we get a reference. //! resolved to the search element definition, we get a reference.
use hir::{PathResolution, Semantics}; use hir::{DescendPreference, PathResolution, Semantics};
use ide_db::{ use ide_db::{
base_db::FileId, base_db::FileId,
defs::{Definition, NameClass, NameRefClass}, defs::{Definition, NameClass, NameRefClass},
@ -126,7 +126,7 @@ pub(crate) fn find_defs<'a>(
) )
}); });
token.map(|token| { token.map(|token| {
sema.descend_into_macros_with_same_text(token, offset) sema.descend_into_macros(DescendPreference::SameText, token, offset)
.into_iter() .into_iter()
.filter_map(|it| ast::NameLike::cast(it.parent()?)) .filter_map(|it| ast::NameLike::cast(it.parent()?))
.filter_map(move |name_like| { .filter_map(move |name_like| {

View file

@ -4,7 +4,10 @@
use std::collections::BTreeSet; use std::collections::BTreeSet;
use either::Either; use either::Either;
use hir::{AssocItem, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait}; use hir::{
AssocItem, DescendPreference, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics,
Trait,
};
use ide_db::{ use ide_db::{
active_parameter::{callable_for_node, generic_def_for_node}, active_parameter::{callable_for_node, generic_def_for_node},
base_db::FilePosition, base_db::FilePosition,
@ -79,7 +82,7 @@ pub(crate) fn signature_help(
// if the cursor is sandwiched between two space tokens and the call is unclosed // if the cursor is sandwiched between two space tokens and the call is unclosed
// this prevents us from leaving the CallExpression // this prevents us from leaving the CallExpression
.and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?; .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
let token = sema.descend_into_macros_single(token, offset); let token = sema.descend_into_macros_single(DescendPreference::None, token, offset);
for node in token.parent_ancestors() { for node in token.parent_ancestors() {
match_ast! { match_ast! {

View file

@ -13,7 +13,7 @@ mod html;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use hir::{Name, Semantics}; use hir::{DescendPreference, Name, Semantics};
use ide_db::{FxHashMap, RootDatabase, SymbolKind}; use ide_db::{FxHashMap, RootDatabase, SymbolKind};
use syntax::{ use syntax::{
ast::{self, IsString}, ast::{self, IsString},
@ -393,14 +393,14 @@ fn traverse(
// Attempt to descend tokens into macro-calls. // Attempt to descend tokens into macro-calls.
let res = match element { let res = match element {
NodeOrToken::Token(token) if token.kind() != COMMENT => { NodeOrToken::Token(token) if token.kind() != COMMENT => {
let token = match attr_or_derive_item { let token = sema.descend_into_macros_single(
Some(AttrOrDerive::Attr(_)) => { match attr_or_derive_item {
sema.descend_into_macros_with_kind_preference(token, 0.into()) Some(AttrOrDerive::Attr(_)) => DescendPreference::SameKind,
} Some(AttrOrDerive::Derive(_)) | None => DescendPreference::None,
Some(AttrOrDerive::Derive(_)) | None => { },
sema.descend_into_macros_single(token, 0.into()) token,
} 0.into(),
}; );
match token.parent().and_then(ast::NameLike::cast) { match token.parent().and_then(ast::NameLike::cast) {
// Remap the token into the wrapping single token nodes // Remap the token into the wrapping single token nodes
Some(parent) => match (token.kind(), parent.syntax().kind()) { Some(parent) => match (token.kind(), parent.syntax().kind()) {