mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Improve macro descension API
This commit is contained in:
parent
986577faaa
commit
5b8e386bae
21 changed files with 179 additions and 139 deletions
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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))
|
||||||
})
|
})
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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())
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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()?),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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| {
|
||||||
|
|
|
@ -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| {
|
||||||
|
|
|
@ -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! {
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
Loading…
Reference in a new issue