mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-28 04:45:05 +00:00
Remove DescendPreference::SameText
This commit is contained in:
parent
011e3bb9ac
commit
f979667fb5
13 changed files with 303 additions and 228 deletions
|
@ -184,6 +184,8 @@ style = { level = "warn", priority = -1 }
|
||||||
suspicious = { level = "warn", priority = -1 }
|
suspicious = { level = "warn", priority = -1 }
|
||||||
|
|
||||||
## allow following lints
|
## allow following lints
|
||||||
|
# subjective
|
||||||
|
single_match = "allow"
|
||||||
# () makes a fine error in most cases
|
# () makes a fine error in most cases
|
||||||
result_unit_err = "allow"
|
result_unit_err = "allow"
|
||||||
# We don't expose public APIs that matter like this
|
# We don't expose public APIs that matter like this
|
||||||
|
|
|
@ -279,6 +279,7 @@ pub enum MacroCallKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HirFileIdExt {
|
pub trait HirFileIdExt {
|
||||||
|
fn edition(self, db: &dyn ExpandDatabase) -> Edition;
|
||||||
/// Returns the original file of this macro call hierarchy.
|
/// Returns the original file of this macro call hierarchy.
|
||||||
fn original_file(self, db: &dyn ExpandDatabase) -> EditionedFileId;
|
fn original_file(self, db: &dyn ExpandDatabase) -> EditionedFileId;
|
||||||
|
|
||||||
|
@ -293,6 +294,12 @@ pub trait HirFileIdExt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirFileIdExt for HirFileId {
|
impl HirFileIdExt for HirFileId {
|
||||||
|
fn edition(self, db: &dyn ExpandDatabase) -> Edition {
|
||||||
|
match self.repr() {
|
||||||
|
HirFileIdRepr::FileId(file_id) => file_id.edition(),
|
||||||
|
HirFileIdRepr::MacroFile(m) => m.macro_call_id.lookup(db).def.edition,
|
||||||
|
}
|
||||||
|
}
|
||||||
fn original_file(self, db: &dyn ExpandDatabase) -> EditionedFileId {
|
fn original_file(self, db: &dyn ExpandDatabase) -> EditionedFileId {
|
||||||
let mut file_id = self;
|
let mut file_id = self;
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod source_to_def;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
|
convert::Infallible,
|
||||||
fmt, iter, mem,
|
fmt, iter, mem,
|
||||||
ops::{self, ControlFlow, Not},
|
ops::{self, ControlFlow, Not},
|
||||||
};
|
};
|
||||||
|
@ -48,12 +49,46 @@ use crate::{
|
||||||
Variant, VariantDef,
|
Variant, VariantDef,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CONTINUE_NO_BREAKS: ControlFlow<Infallible, ()> = ControlFlow::Continue(());
|
||||||
|
|
||||||
pub enum DescendPreference {
|
pub enum DescendPreference {
|
||||||
SameText,
|
|
||||||
SameKind,
|
SameKind,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum MacroInputKind {
|
||||||
|
Root,
|
||||||
|
Bang,
|
||||||
|
AttrInput,
|
||||||
|
AttrTarget,
|
||||||
|
Derive,
|
||||||
|
DeriveHelper,
|
||||||
|
// Include,
|
||||||
|
}
|
||||||
|
impl MacroInputKind {
|
||||||
|
pub fn is_tt(self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
MacroInputKind::AttrInput
|
||||||
|
| MacroInputKind::Bang
|
||||||
|
| MacroInputKind::DeriveHelper
|
||||||
|
| MacroInputKind::Derive
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::BitOr for MacroInputKind {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Self::Root => rhs,
|
||||||
|
_ => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum PathResolution {
|
pub enum PathResolution {
|
||||||
/// An item
|
/// An item
|
||||||
|
@ -545,51 +580,50 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves all the formatting parts of the format_args! template string.
|
||||||
pub fn as_format_args_parts(
|
pub fn as_format_args_parts(
|
||||||
&self,
|
&self,
|
||||||
string: &ast::String,
|
string: &ast::String,
|
||||||
) -> Option<Vec<(TextRange, Option<PathResolution>)>> {
|
) -> Option<Vec<(TextRange, Option<PathResolution>)>> {
|
||||||
if let Some(quote) = string.open_quote_text_range() {
|
let quote = string.open_quote_text_range()?;
|
||||||
return self
|
self.descend_into_macros_ng_b(string.syntax().clone(), |kind, token| {
|
||||||
.descend_into_macros(DescendPreference::SameText, string.syntax().clone())
|
(|| {
|
||||||
.into_iter()
|
let token = token.value;
|
||||||
.find_map(|token| {
|
let string = ast::String::cast(token)?;
|
||||||
let string = ast::String::cast(token)?;
|
let literal =
|
||||||
let literal =
|
string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
|
||||||
string.syntax().parent().filter(|it| it.kind() == SyntaxKind::LITERAL)?;
|
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
|
||||||
let format_args = ast::FormatArgsExpr::cast(literal.parent()?)?;
|
let source_analyzer = self.analyze_no_infer(format_args.syntax())?;
|
||||||
let source_analyzer = self.analyze_no_infer(format_args.syntax())?;
|
let format_args = self.wrap_node_infile(format_args);
|
||||||
let format_args = self.wrap_node_infile(format_args);
|
let res = source_analyzer
|
||||||
let res = source_analyzer
|
.as_format_args_parts(self.db, format_args.as_ref())?
|
||||||
.as_format_args_parts(self.db, format_args.as_ref())?
|
.map(|(range, res)| (range + quote.end(), res))
|
||||||
.map(|(range, res)| (range + quote.end(), res))
|
.collect();
|
||||||
.collect();
|
Some(res)
|
||||||
Some(res)
|
})()
|
||||||
});
|
.map_or(ControlFlow::Continue(()), ControlFlow::Break)
|
||||||
}
|
})
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the formatting part of the format_args! template string at the given offset.
|
||||||
pub fn check_for_format_args_template(
|
pub fn check_for_format_args_template(
|
||||||
&self,
|
&self,
|
||||||
original_token: SyntaxToken,
|
original_token: SyntaxToken,
|
||||||
offset: TextSize,
|
offset: TextSize,
|
||||||
) -> Option<(TextRange, Option<PathResolution>)> {
|
) -> Option<(TextRange, Option<PathResolution>)> {
|
||||||
if let Some(original_string) = ast::String::cast(original_token.clone()) {
|
let original_string = ast::String::cast(original_token.clone())?;
|
||||||
if let Some(quote) = original_string.open_quote_text_range() {
|
let quote = original_string.open_quote_text_range()?;
|
||||||
return self
|
self.descend_into_macros_ng_b(original_token.clone(), |kind, token| {
|
||||||
.descend_into_macros(DescendPreference::SameText, original_token)
|
(|| {
|
||||||
.into_iter()
|
let token = token.value;
|
||||||
.find_map(|token| {
|
self.resolve_offset_in_format_args(
|
||||||
self.resolve_offset_in_format_args(
|
ast::String::cast(token)?,
|
||||||
ast::String::cast(token)?,
|
offset.checked_sub(quote.end())?,
|
||||||
offset.checked_sub(quote.end())?,
|
)
|
||||||
)
|
.map(|(range, res)| (range + quote.end(), res))
|
||||||
})
|
})()
|
||||||
.map(|(range, res)| (range + quote.end(), res));
|
.map_or(ControlFlow::Continue(()), ControlFlow::Break)
|
||||||
}
|
})
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_offset_in_format_args(
|
fn resolve_offset_in_format_args(
|
||||||
|
@ -622,7 +656,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
|
|
||||||
if first == last {
|
if first == last {
|
||||||
// node is just the token, so descend the token
|
// node is just the token, so descend the token
|
||||||
self.descend_into_macros_impl(first, &mut |InFile { value, .. }| {
|
self.descend_into_macros_impl(first, &mut |_kind, InFile { value, .. }| {
|
||||||
if let Some(node) = value
|
if let Some(node) = value
|
||||||
.parent_ancestors()
|
.parent_ancestors()
|
||||||
.take_while(|it| it.text_range() == value.text_range())
|
.take_while(|it| it.text_range() == value.text_range())
|
||||||
|
@ -630,20 +664,20 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
{
|
{
|
||||||
res.push(node)
|
res.push(node)
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(())
|
CONTINUE_NO_BREAKS
|
||||||
});
|
});
|
||||||
} 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, &mut |token| {
|
self.descend_into_macros_impl(first, &mut |_kind, token| {
|
||||||
scratch.push(token);
|
scratch.push(token);
|
||||||
ControlFlow::Continue(())
|
CONTINUE_NO_BREAKS
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut scratch = scratch.into_iter();
|
let mut scratch = scratch.into_iter();
|
||||||
self.descend_into_macros_impl(
|
self.descend_into_macros_impl(
|
||||||
last,
|
last,
|
||||||
&mut |InFile { value: last, file_id: last_fid }| {
|
&mut |_kind, InFile { value: last, file_id: last_fid }| {
|
||||||
if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
|
if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
|
||||||
if first_fid == last_fid {
|
if first_fid == last_fid {
|
||||||
if let Some(p) = first.parent() {
|
if let Some(p) = first.parent() {
|
||||||
|
@ -659,7 +693,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ControlFlow::Continue(())
|
CONTINUE_NO_BREAKS
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -673,8 +707,8 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
mode: DescendPreference,
|
mode: DescendPreference,
|
||||||
token: SyntaxToken,
|
token: SyntaxToken,
|
||||||
) -> SmallVec<[SyntaxToken; 1]> {
|
) -> SmallVec<[SyntaxToken; 1]> {
|
||||||
enum Dp<'t> {
|
enum Dp {
|
||||||
SameText(&'t str),
|
// SameText(&'t str),
|
||||||
SameKind(SyntaxKind),
|
SameKind(SyntaxKind),
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
@ -686,104 +720,123 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
None => token.kind(),
|
None => token.kind(),
|
||||||
};
|
};
|
||||||
let mode = match mode {
|
let mode = match mode {
|
||||||
DescendPreference::SameText => Dp::SameText(token.text()),
|
// DescendPreference::SameText => Dp::SameText(token.text()),
|
||||||
DescendPreference::SameKind => Dp::SameKind(fetch_kind(&token)),
|
DescendPreference::SameKind => Dp::SameKind(fetch_kind(&token)),
|
||||||
DescendPreference::None => Dp::None,
|
DescendPreference::None => Dp::None,
|
||||||
};
|
};
|
||||||
let mut res = smallvec![];
|
let mut res = smallvec![];
|
||||||
self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
|
self.descend_into_macros_impl::<Infallible>(
|
||||||
let is_a_match = match mode {
|
token.clone(),
|
||||||
Dp::SameText(text) => value.text() == text,
|
&mut |kind, InFile { value, .. }| {
|
||||||
Dp::SameKind(preferred_kind) => {
|
let is_a_match = match mode {
|
||||||
let kind = fetch_kind(&value);
|
// Dp::SameText(text) => value.text() == text,
|
||||||
kind == preferred_kind
|
Dp::SameKind(preferred_kind) => {
|
||||||
|
let kind = fetch_kind(&value);
|
||||||
|
kind == preferred_kind
|
||||||
// special case for derive macros
|
// special case for derive macros
|
||||||
|| (preferred_kind == SyntaxKind::IDENT && kind == SyntaxKind::NAME_REF)
|
|| (preferred_kind == SyntaxKind::IDENT && kind == SyntaxKind::NAME_REF)
|
||||||
|
}
|
||||||
|
Dp::None => true,
|
||||||
|
};
|
||||||
|
if is_a_match {
|
||||||
|
res.push(value);
|
||||||
}
|
}
|
||||||
Dp::None => true,
|
ControlFlow::Continue(())
|
||||||
};
|
},
|
||||||
if is_a_match {
|
);
|
||||||
res.push(value);
|
|
||||||
}
|
|
||||||
ControlFlow::Continue(())
|
|
||||||
});
|
|
||||||
if res.is_empty() {
|
if res.is_empty() {
|
||||||
res.push(token);
|
res.push(token);
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn descend_into_macros_single(
|
pub fn descend_into_macros_ng(
|
||||||
&self,
|
&self,
|
||||||
mode: DescendPreference,
|
|
||||||
token: SyntaxToken,
|
token: SyntaxToken,
|
||||||
) -> SyntaxToken {
|
mut cb: impl FnMut(MacroInputKind, InFile<SyntaxToken>),
|
||||||
enum Dp<'t> {
|
) {
|
||||||
SameText(&'t str),
|
self.descend_into_macros_impl(token.clone(), &mut |kind, t| {
|
||||||
SameKind(SyntaxKind),
|
cb(kind, t);
|
||||||
None,
|
CONTINUE_NO_BREAKS
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn descend_into_macros_ng_b<T>(
|
||||||
|
&self,
|
||||||
|
token: SyntaxToken,
|
||||||
|
mut cb: impl FnMut(MacroInputKind, InFile<SyntaxToken>) -> ControlFlow<T>,
|
||||||
|
) -> Option<T> {
|
||||||
|
self.descend_into_macros_impl(token.clone(), &mut |kind, t| cb(kind, t))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Descends the token into expansions, returning the tokens that matches the input
|
||||||
|
/// token's [`SyntaxKind`] and text.
|
||||||
|
pub fn descend_into_macros_exact(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
|
||||||
|
let mut r = smallvec![];
|
||||||
|
let text = token.text();
|
||||||
|
let kind = token.kind();
|
||||||
|
|
||||||
|
self.descend_into_macros_ng(token.clone(), |m_kind, InFile { value, file_id }| {
|
||||||
|
let mapped_kind = value.kind();
|
||||||
|
let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
|
||||||
|
let matches = (kind == mapped_kind || any_ident_match()) && text == value.text();
|
||||||
|
if matches {
|
||||||
|
r.push(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if r.is_empty() {
|
||||||
|
r.push(token);
|
||||||
}
|
}
|
||||||
let fetch_kind = |token: &SyntaxToken| match token.parent() {
|
r
|
||||||
Some(node) => match node.kind() {
|
}
|
||||||
kind @ (SyntaxKind::NAME | SyntaxKind::NAME_REF) => kind,
|
|
||||||
_ => token.kind(),
|
/// Descends the token into expansions, returning the first token that matches the input
|
||||||
},
|
/// token's [`SyntaxKind`] and text.
|
||||||
None => token.kind(),
|
pub fn descend_into_macros_single_exact(&self, token: SyntaxToken) -> SyntaxToken {
|
||||||
};
|
let text = token.text();
|
||||||
let mode = match mode {
|
let kind = token.kind();
|
||||||
DescendPreference::SameText => Dp::SameText(token.text()),
|
|
||||||
DescendPreference::SameKind => Dp::SameKind(fetch_kind(&token)),
|
self.descend_into_macros_ng_b(token.clone(), |m_kind, InFile { value, file_id }| {
|
||||||
DescendPreference::None => Dp::None,
|
let mapped_kind = value.kind();
|
||||||
};
|
let any_ident_match = || kind.is_any_identifier() && value.kind().is_any_identifier();
|
||||||
let mut res = token.clone();
|
let matches = (kind == mapped_kind || any_ident_match()) && text == value.text();
|
||||||
self.descend_into_macros_impl(token.clone(), &mut |InFile { value, .. }| {
|
if matches {
|
||||||
let is_a_match = match mode {
|
ControlFlow::Break(value)
|
||||||
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,
|
|
||||||
};
|
|
||||||
res = value;
|
|
||||||
if is_a_match {
|
|
||||||
ControlFlow::Break(())
|
|
||||||
} else {
|
} else {
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
res
|
.unwrap_or(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn descend_into_macros_impl(
|
fn descend_into_macros_impl<T>(
|
||||||
&self,
|
&self,
|
||||||
token: SyntaxToken,
|
token: SyntaxToken,
|
||||||
f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
|
f: &mut dyn FnMut(MacroInputKind, InFile<SyntaxToken>) -> ControlFlow<T>,
|
||||||
) {
|
) -> Option<T> {
|
||||||
let _p = tracing::info_span!("descend_into_macros_impl").entered();
|
let _p = tracing::info_span!("descend_into_macros_impl").entered();
|
||||||
let (sa, span, file_id) =
|
let (sa, span, file_id) =
|
||||||
match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) {
|
token.parent().and_then(|parent| self.analyze_no_infer(&parent)).and_then(|sa| {
|
||||||
Some(sa) => match sa.file_id.file_id() {
|
let file_id = sa.file_id.file_id()?;
|
||||||
Some(file_id) => (
|
Some((
|
||||||
sa,
|
sa,
|
||||||
self.db.real_span_map(file_id).span_for_range(token.text_range()),
|
self.db.real_span_map(file_id).span_for_range(token.text_range()),
|
||||||
file_id.into(),
|
HirFileId::from(file_id),
|
||||||
),
|
))
|
||||||
None => {
|
})?;
|
||||||
stdx::never!();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut m_cache = self.macro_call_cache.borrow_mut();
|
let mut m_cache = self.macro_call_cache.borrow_mut();
|
||||||
let def_map = sa.resolver.def_map();
|
let def_map = sa.resolver.def_map();
|
||||||
|
|
||||||
let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])];
|
// A stack of tokens to process, along with the file they came from
|
||||||
let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
|
// These are tracked to know which macro calls we still have to look into
|
||||||
|
// the tokens themselves aren't that interesting as the span that is being used to map
|
||||||
|
// things down never changes.
|
||||||
|
let mut stack: Vec<(_, _, SmallVec<[_; 2]>)> =
|
||||||
|
vec![(file_id, MacroInputKind::Root, smallvec![token])];
|
||||||
|
|
||||||
|
// Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
|
||||||
|
let process_expansion_for_token = |stack: &mut Vec<_>, macro_file, remap_kind| {
|
||||||
let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| {
|
let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| {
|
||||||
Some(
|
Some(
|
||||||
ctx.cache
|
ctx.cache
|
||||||
|
@ -805,11 +858,17 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
// we have found a mapping for the token if the vec is non-empty
|
// we have found a mapping for the token if the vec is non-empty
|
||||||
let res = mapped_tokens.is_empty().not().then_some(());
|
let res = mapped_tokens.is_empty().not().then_some(());
|
||||||
// requeue the tokens we got from mapping our current token down
|
// requeue the tokens we got from mapping our current token down
|
||||||
stack.push((HirFileId::from(file_id), mapped_tokens));
|
stack.push((HirFileId::from(file_id), remap_kind, mapped_tokens));
|
||||||
res
|
res
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some((file_id, mut tokens)) = stack.pop() {
|
// Filters out all tokens that contain the given range (usually the macro call), any such
|
||||||
|
// token is redundant as the corresponding macro call has already been processed
|
||||||
|
let filter_duplicates = |tokens: &mut SmallVec<_>, range: TextRange| {
|
||||||
|
tokens.retain(|t: &mut SyntaxToken| !range.contains_range(t.text_range()))
|
||||||
|
};
|
||||||
|
|
||||||
|
while let Some((expansion, remap_kind, ref mut tokens)) = stack.pop() {
|
||||||
while let Some(token) = tokens.pop() {
|
while let Some(token) = tokens.pop() {
|
||||||
let was_not_remapped = (|| {
|
let was_not_remapped = (|| {
|
||||||
// First expand into attribute invocations
|
// First expand into attribute invocations
|
||||||
|
@ -817,7 +876,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
|
token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
|
||||||
// Don't force populate the dyn cache for items that don't have an attribute anyways
|
// Don't force populate the dyn cache for items that don't have an attribute anyways
|
||||||
item.attrs().next()?;
|
item.attrs().next()?;
|
||||||
Some((ctx.item_to_macro_call(InFile::new(file_id, &item))?, item))
|
Some((ctx.item_to_macro_call(InFile::new(expansion, &item))?, item))
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
if let Some((call_id, item)) = containing_attribute_macro_call {
|
if let Some((call_id, item)) = containing_attribute_macro_call {
|
||||||
|
@ -849,10 +908,12 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| text_range.start());
|
.unwrap_or_else(|| text_range.start());
|
||||||
let text_range = TextRange::new(start, text_range.end());
|
let text_range = TextRange::new(start, text_range.end());
|
||||||
// remove any other token in this macro input, all their mappings are the
|
filter_duplicates(tokens, text_range);
|
||||||
// same as this one
|
return process_expansion_for_token(
|
||||||
tokens.retain(|t| !text_range.contains_range(t.text_range()));
|
&mut stack,
|
||||||
return process_expansion_for_token(&mut stack, file_id);
|
file_id,
|
||||||
|
remap_kind | MacroInputKind::AttrTarget,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -862,6 +923,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
.map_while(Either::<ast::TokenTree, ast::Meta>::cast)
|
||||||
.last()?;
|
.last()?;
|
||||||
match tt {
|
match tt {
|
||||||
|
// function-like macro call
|
||||||
Either::Left(tt) => {
|
Either::Left(tt) => {
|
||||||
if tt.left_delimiter_token().map_or(false, |it| it == token) {
|
if tt.left_delimiter_token().map_or(false, |it| it == token) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -870,7 +932,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
|
let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
|
||||||
let mcall = InFile::new(file_id, macro_call);
|
let mcall = InFile::new(expansion, macro_call);
|
||||||
let file_id = match m_cache.get(&mcall) {
|
let file_id = match m_cache.get(&mcall) {
|
||||||
Some(&it) => it,
|
Some(&it) => it,
|
||||||
None => {
|
None => {
|
||||||
|
@ -888,17 +950,25 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let text_range = tt.syntax().text_range();
|
let text_range = tt.syntax().text_range();
|
||||||
// remove any other token in this macro input, all their mappings are the
|
filter_duplicates(tokens, text_range);
|
||||||
// same as this one
|
|
||||||
tokens.retain(|t| !text_range.contains_range(t.text_range()));
|
|
||||||
|
|
||||||
process_expansion_for_token(&mut stack, file_id).or(file_id
|
process_expansion_for_token(
|
||||||
|
&mut stack,
|
||||||
|
file_id,
|
||||||
|
remap_kind | MacroInputKind::Bang,
|
||||||
|
)
|
||||||
|
.or(file_id
|
||||||
.eager_arg(self.db.upcast())
|
.eager_arg(self.db.upcast())
|
||||||
.and_then(|arg| {
|
.and_then(|arg| {
|
||||||
// also descend into eager expansions
|
// also descend into eager expansions
|
||||||
process_expansion_for_token(&mut stack, arg.as_macro_file())
|
process_expansion_for_token(
|
||||||
|
&mut stack,
|
||||||
|
arg.as_macro_file(),
|
||||||
|
remap_kind | MacroInputKind::Bang,
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
// derive or derive helper
|
||||||
Either::Right(meta) => {
|
Either::Right(meta) => {
|
||||||
// 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
|
||||||
|
@ -910,8 +980,8 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
// so try downmapping the token into the pseudo derive expansion
|
// so try downmapping the token into the pseudo derive expansion
|
||||||
// see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
|
// see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
|
||||||
ctx.attr_to_derive_macro_call(
|
ctx.attr_to_derive_macro_call(
|
||||||
InFile::new(file_id, &adt),
|
InFile::new(expansion, &adt),
|
||||||
InFile::new(file_id, attr.clone()),
|
InFile::new(expansion, attr.clone()),
|
||||||
)
|
)
|
||||||
.map(|(_, call_id, _)| call_id)
|
.map(|(_, call_id, _)| call_id)
|
||||||
});
|
});
|
||||||
|
@ -927,7 +997,9 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
!text_range.contains_range(t.text_range())
|
!text_range.contains_range(t.text_range())
|
||||||
});
|
});
|
||||||
return process_expansion_for_token(
|
return process_expansion_for_token(
|
||||||
&mut stack, file_id,
|
&mut stack,
|
||||||
|
file_id,
|
||||||
|
remap_kind | MacroInputKind::Derive,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
None => Some(adt),
|
None => Some(adt),
|
||||||
|
@ -945,31 +1017,33 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}?;
|
}?;
|
||||||
if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(file_id, &adt))) {
|
if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(expansion, &adt))) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let attr_name =
|
let attr_name =
|
||||||
attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
|
attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
|
||||||
// Not an attribute, nor a derive, so it's either a builtin or a derive helper
|
// Not an attribute, nor a derive, so it's either an intert attribute or a derive helper
|
||||||
// Try to resolve to a derive helper and downmap
|
// Try to resolve to a derive helper and downmap
|
||||||
let id = self.db.ast_id_map(file_id).ast_id(&adt);
|
let id = self.db.ast_id_map(expansion).ast_id(&adt);
|
||||||
let helpers =
|
let helpers =
|
||||||
def_map.derive_helpers_in_scope(InFile::new(file_id, id))?;
|
def_map.derive_helpers_in_scope(InFile::new(expansion, id))?;
|
||||||
|
|
||||||
if !helpers.is_empty() {
|
if !helpers.is_empty() {
|
||||||
let text_range = attr.syntax().text_range();
|
let text_range = attr.syntax().text_range();
|
||||||
// remove any other token in this macro input, all their mappings are the
|
filter_duplicates(tokens, text_range);
|
||||||
// same as this
|
|
||||||
tokens.retain(|t| !text_range.contains_range(t.text_range()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
for (.., derive) in
|
for (.., derive) in
|
||||||
helpers.iter().filter(|(helper, ..)| *helper == attr_name)
|
helpers.iter().filter(|(helper, ..)| *helper == attr_name)
|
||||||
{
|
{
|
||||||
|
// as there may be multiple derives registering the same helper
|
||||||
|
// name, we gotta make sure to call this for all of them!
|
||||||
|
// FIXME: We need to call `f` for all of them as well though!
|
||||||
res = res.or(process_expansion_for_token(
|
res = res.or(process_expansion_for_token(
|
||||||
&mut stack,
|
&mut stack,
|
||||||
derive.as_macro_file(),
|
derive.as_macro_file(),
|
||||||
|
remap_kind | MacroInputKind::DeriveHelper,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
|
@ -978,11 +1052,14 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
})()
|
})()
|
||||||
.is_none();
|
.is_none();
|
||||||
|
|
||||||
if was_not_remapped && f(InFile::new(file_id, token)).is_break() {
|
if was_not_remapped {
|
||||||
break;
|
if let ControlFlow::Break(b) = f(remap_kind, InFile::new(expansion, token)) {
|
||||||
|
return Some(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop
|
// Note this return type is deliberate as [`find_nodes_at_offset_with_descend`] wants to stop
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
use crate::{utils, AssistContext, Assists};
|
use crate::{utils, AssistContext, Assists};
|
||||||
use hir::DescendPreference;
|
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
assists::{AssistId, AssistKind},
|
assists::{AssistId, AssistKind},
|
||||||
syntax_helpers::{
|
syntax_helpers::format_string_exprs::{parse_format_exprs, Arg},
|
||||||
format_string::is_format_string,
|
|
||||||
format_string_exprs::{parse_format_exprs, Arg},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
|
@ -40,13 +36,7 @@ pub(crate) fn extract_expressions_from_format_string(
|
||||||
let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
|
let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
|
||||||
let tt_delimiter = tt.left_delimiter_token()?.kind();
|
let tt_delimiter = tt.left_delimiter_token()?.kind();
|
||||||
|
|
||||||
let expanded_t = ast::String::cast(
|
let _ = ctx.sema.as_format_args_parts(&fmt_string)?;
|
||||||
ctx.sema
|
|
||||||
.descend_into_macros_single(DescendPreference::SameKind, fmt_string.syntax().clone()),
|
|
||||||
)?;
|
|
||||||
if !is_format_string(&expanded_t) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?;
|
let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?;
|
||||||
if extracted_args.is_empty() {
|
if extracted_args.is_empty() {
|
||||||
|
|
|
@ -31,6 +31,7 @@ pub fn with_placeholders(args: Vec<Arg>) -> Vec<String> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME Remove this, we have this information in the HIR now
|
||||||
/// Parser for a format-like string. It is more allowing in terms of string contents,
|
/// Parser for a format-like string. It is more allowing in terms of string contents,
|
||||||
/// as we expect variable placeholders to be filled with expressions.
|
/// as we expect variable placeholders to be filled with expressions.
|
||||||
///
|
///
|
||||||
|
|
|
@ -144,7 +144,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(DescendPreference::None, token);
|
let token = sema.descend_into_macros_single_exact(token);
|
||||||
|
|
||||||
let node = token.parent()?;
|
let node = token.parent()?;
|
||||||
let definition = match_ast! {
|
let definition = match_ast! {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::iter::successors;
|
use std::iter::successors;
|
||||||
|
|
||||||
use hir::{DescendPreference, Semantics};
|
use hir::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,8 @@ 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_exact(first_token.clone());
|
||||||
sema.descend_into_macros_single(DescendPreference::None, first_token.clone());
|
let lst_expanded = sema.descend_into_macros_single_exact(last_token.clone());
|
||||||
let lst_expanded =
|
|
||||||
sema.descend_into_macros_single(DescendPreference::None, last_token.clone());
|
|
||||||
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 +155,7 @@ fn extend_tokens_from_range(
|
||||||
let validate = || {
|
let validate = || {
|
||||||
let extended = &extended;
|
let extended = &extended;
|
||||||
move |token: &SyntaxToken| -> bool {
|
move |token: &SyntaxToken| -> bool {
|
||||||
let expanded = sema.descend_into_macros_single(DescendPreference::None, token.clone());
|
let expanded = sema.descend_into_macros_single_exact(token.clone());
|
||||||
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, DescendPreference, Impl, Semantics};
|
use hir::{AsAssocItem, Impl, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::{Definition, NameClass, NameRefClass},
|
||||||
helpers::pick_best_token,
|
helpers::pick_best_token,
|
||||||
|
@ -10,7 +10,7 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
|
||||||
|
|
||||||
// Feature: Go to Implementation
|
// Feature: Go to Implementation
|
||||||
//
|
//
|
||||||
// Navigates to the impl blocks of types.
|
// Navigates to the impl items of types.
|
||||||
//
|
//
|
||||||
// |===
|
// |===
|
||||||
// | Editor | Shortcut
|
// | Editor | Shortcut
|
||||||
|
@ -32,48 +32,55 @@ pub(crate) fn goto_implementation(
|
||||||
_ => 0,
|
_ => 0,
|
||||||
})?;
|
})?;
|
||||||
let range = original_token.text_range();
|
let range = original_token.text_range();
|
||||||
let navs =
|
let navs = sema
|
||||||
sema.descend_into_macros_single(DescendPreference::SameText, original_token)
|
.descend_into_macros_exact(original_token)
|
||||||
.parent()
|
.iter()
|
||||||
.and_then(ast::NameLike::cast)
|
.filter_map(|token| {
|
||||||
.and_then(|node| match &node {
|
token
|
||||||
ast::NameLike::Name(name) => {
|
.parent()
|
||||||
NameClass::classify(&sema, name).and_then(|class| match class {
|
.and_then(ast::NameLike::cast)
|
||||||
NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it),
|
.and_then(|node| match &node {
|
||||||
NameClass::PatFieldShorthand { .. } => None,
|
ast::NameLike::Name(name) => {
|
||||||
})
|
NameClass::classify(&sema, name).and_then(|class| match class {
|
||||||
}
|
NameClass::Definition(it) | NameClass::ConstReference(it) => Some(it),
|
||||||
ast::NameLike::NameRef(name_ref) => NameRefClass::classify(&sema, name_ref)
|
NameClass::PatFieldShorthand { .. } => None,
|
||||||
.and_then(|class| match class {
|
})
|
||||||
NameRefClass::Definition(def) => Some(def),
|
|
||||||
NameRefClass::FieldShorthand { .. }
|
|
||||||
| NameRefClass::ExternCrateShorthand { .. } => None,
|
|
||||||
}),
|
|
||||||
ast::NameLike::Lifetime(_) => None,
|
|
||||||
})
|
|
||||||
.and_then(|def| {
|
|
||||||
let navs = match def {
|
|
||||||
Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
|
|
||||||
Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
|
|
||||||
Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
|
|
||||||
Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)),
|
|
||||||
Definition::Function(f) => {
|
|
||||||
let assoc = f.as_assoc_item(sema.db)?;
|
|
||||||
let name = assoc.name(sema.db)?;
|
|
||||||
let trait_ = assoc.container_or_implemented_trait(sema.db)?;
|
|
||||||
impls_for_trait_item(&sema, trait_, name)
|
|
||||||
}
|
}
|
||||||
Definition::Const(c) => {
|
ast::NameLike::NameRef(name_ref) => NameRefClass::classify(&sema, name_ref)
|
||||||
let assoc = c.as_assoc_item(sema.db)?;
|
.and_then(|class| match class {
|
||||||
let name = assoc.name(sema.db)?;
|
NameRefClass::Definition(def) => Some(def),
|
||||||
let trait_ = assoc.container_or_implemented_trait(sema.db)?;
|
NameRefClass::FieldShorthand { .. }
|
||||||
impls_for_trait_item(&sema, trait_, name)
|
| NameRefClass::ExternCrateShorthand { .. } => None,
|
||||||
}
|
}),
|
||||||
_ => return None,
|
ast::NameLike::Lifetime(_) => None,
|
||||||
};
|
})
|
||||||
Some(navs)
|
.and_then(|def| {
|
||||||
})
|
let navs = match def {
|
||||||
.unwrap_or_default();
|
Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
|
||||||
|
Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
|
||||||
|
Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
|
||||||
|
Definition::BuiltinType(builtin) => {
|
||||||
|
impls_for_ty(&sema, builtin.ty(sema.db))
|
||||||
|
}
|
||||||
|
Definition::Function(f) => {
|
||||||
|
let assoc = f.as_assoc_item(sema.db)?;
|
||||||
|
let name = assoc.name(sema.db)?;
|
||||||
|
let trait_ = assoc.container_or_implemented_trait(sema.db)?;
|
||||||
|
impls_for_trait_item(&sema, trait_, name)
|
||||||
|
}
|
||||||
|
Definition::Const(c) => {
|
||||||
|
let assoc = c.as_assoc_item(sema.db)?;
|
||||||
|
let name = assoc.name(sema.db)?;
|
||||||
|
let trait_ = assoc.container_or_implemented_trait(sema.db)?;
|
||||||
|
impls_for_trait_item(&sema, trait_, name)
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(navs)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
Some(RangeInfo { range, info: navs })
|
Some(RangeInfo { range, info: navs })
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ mod tests;
|
||||||
use std::{iter, ops::Not};
|
use std::{iter, ops::Not};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{db::DefDatabase, DescendPreference, HasCrate, HasSource, LangItem, Semantics};
|
use hir::{db::DefDatabase, HasCrate, HasSource, LangItem, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
defs::{Definition, IdentClass, NameRefClass, OperatorClass},
|
defs::{Definition, IdentClass, NameRefClass, OperatorClass},
|
||||||
famous_defs::FamousDefs,
|
famous_defs::FamousDefs,
|
||||||
|
@ -178,29 +178,24 @@ fn hover_simple(
|
||||||
return Some(RangeInfo::new(range, res));
|
return Some(RangeInfo::new(range, res));
|
||||||
}
|
}
|
||||||
|
|
||||||
let in_attr = original_token
|
|
||||||
.parent_ancestors()
|
|
||||||
.filter_map(ast::Item::cast)
|
|
||||||
.any(|item| sema.is_attr_macro_call(&item))
|
|
||||||
&& !matches!(
|
|
||||||
original_token.parent().and_then(ast::TokenTree::cast),
|
|
||||||
Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))
|
|
||||||
);
|
|
||||||
|
|
||||||
// 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 = sema.descend_into_macros(
|
let mut descended = vec![];
|
||||||
if in_attr { DescendPreference::SameKind } else { DescendPreference::SameText },
|
sema.descend_into_macros_ng(original_token.clone(), |_, token| {
|
||||||
original_token.clone(),
|
descended.push(token.value);
|
||||||
);
|
});
|
||||||
let descended = || descended.iter();
|
let descended = || descended.iter();
|
||||||
|
|
||||||
let result = descended()
|
// FIXME: WE should not try these step by step, instead to accommodate for macros we should run
|
||||||
|
// all of these in "parallel" and rank their results
|
||||||
|
let result = None
|
||||||
// try lint hover
|
// try lint hover
|
||||||
.find_map(|token| {
|
.or_else(|| {
|
||||||
// FIXME: Definition should include known lints and the like instead of having this special case here
|
descended().find_map(|token| {
|
||||||
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
|
// FIXME: Definition should include known lints and the like instead of having this special case here
|
||||||
render::try_for_lint(&attr, token)
|
let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
|
||||||
|
render::try_for_lint(&attr, token)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
// try definitions
|
// try definitions
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
|
|
@ -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::{DescendPreference, PathResolution, Semantics};
|
use hir::{PathResolution, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
defs::{Definition, NameClass, NameRefClass},
|
defs::{Definition, NameClass, NameRefClass},
|
||||||
search::{ReferenceCategory, SearchScope, UsageSearchResult},
|
search::{ReferenceCategory, SearchScope, UsageSearchResult},
|
||||||
|
@ -149,7 +149,7 @@ pub(crate) fn find_defs<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
sema.descend_into_macros(DescendPreference::SameText, token)
|
sema.descend_into_macros_exact(token)
|
||||||
.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,10 +4,7 @@
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{
|
use hir::{AssocItem, GenericParam, HirDisplay, ModuleDef, PathResolution, Semantics, Trait};
|
||||||
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},
|
||||||
documentation::{Documentation, HasDocs},
|
documentation::{Documentation, HasDocs},
|
||||||
|
@ -82,7 +79,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(DescendPreference::None, token);
|
let token = sema.descend_into_macros_single_exact(token);
|
||||||
let edition =
|
let edition =
|
||||||
sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
|
sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
|
||||||
|
|
||||||
|
|
|
@ -410,7 +410,8 @@ fn traverse(
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
sema.descend_into_macros_single(DescendPreference::SameKind, token)
|
// FIXME: We should probably rank the tokens and find the most suitable?
|
||||||
|
sema.descend_into_macros_single_exact(token)
|
||||||
};
|
};
|
||||||
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
|
||||||
|
|
|
@ -58,7 +58,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="brace">}</span>
|
<span class="brace">}</span>
|
||||||
|
|
||||||
<span class="macro">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
|
<span class="macro">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
|
||||||
<span class="keyword macro">fn</span> <span class="function declaration macro">bar</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="operator macro">-</span><span class="operator macro">></span> <span class="builtin_type macro">u32</span> <span class="brace macro">{</span>
|
<span class="keyword macro">fn</span> <span class="function declaration macro">bar</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="punctuation macro">-</span><span class="angle macro">></span> <span class="builtin_type macro">u32</span> <span class="brace macro">{</span>
|
||||||
<span class="numeric_literal macro">100</span>
|
<span class="numeric_literal macro">100</span>
|
||||||
<span class="brace macro">}</span>
|
<span class="brace macro">}</span>
|
||||||
<span class="brace macro">}</span>
|
<span class="brace macro">}</span>
|
||||||
|
@ -100,7 +100,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="brace">}</span><span class="semicolon">;</span>
|
<span class="brace">}</span><span class="semicolon">;</span>
|
||||||
<span class="brace">}</span>
|
<span class="brace">}</span>
|
||||||
|
|
||||||
<span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="string_literal macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro default_library library">include</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"foo/"</span><span class="comma macro">,</span> <span class="string_literal macro">"foo.rs"</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="keyword">struct</span> <span class="struct declaration">S</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
<span class="keyword">struct</span> <span class="struct declaration">S</span><span class="angle"><</span><span class="type_param declaration">T</span><span class="angle">></span><span class="parenthesis">(</span><span class="type_param">T</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||||
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||||
|
|
Loading…
Reference in a new issue