mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-28 10:39:45 +00:00
fix: Handle included files better in IDE layer
This does not fully fix things, but it introduces a function that can be used to fix occurences. When using `to_def` functionality, the input node needs to come from the macro expanded include, not the real file that was included. This does unfortunately add more caller burden, but there is not really a way around it.
This commit is contained in:
parent
6440fe2a01
commit
e72738de99
3 changed files with 97 additions and 31 deletions
|
|
@ -769,6 +769,31 @@ impl<'db> SemanticsImpl<'db> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Descends the token into the include expansion, if its file is an included file.
|
||||
pub fn descend_token_into_include_expansion(
|
||||
&self,
|
||||
tok: InRealFile<SyntaxToken>,
|
||||
) -> InFile<SyntaxToken> {
|
||||
let Some(include) =
|
||||
self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, tok.file_id)
|
||||
else {
|
||||
return tok.into();
|
||||
};
|
||||
let span = self.db.real_span_map(tok.file_id).span_for_range(tok.value.text_range());
|
||||
let Some(InMacroFile { file_id, value: mut mapped_tokens }) = self.with_ctx(|ctx| {
|
||||
Some(
|
||||
ctx.cache
|
||||
.get_or_insert_expansion(ctx.db, include)
|
||||
.map_range_down(span)?
|
||||
.map(SmallVec::<[_; 2]>::from_iter),
|
||||
)
|
||||
}) else {
|
||||
return tok.into();
|
||||
};
|
||||
// We should only get one result at most
|
||||
mapped_tokens.pop().map_or_else(|| tok.into(), |(tok, _)| InFile::new(file_id.into(), tok))
|
||||
}
|
||||
|
||||
/// Maps a node down by mapping its first and last token down.
|
||||
pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
|
||||
// This might not be the correct way to do this, but it works for now
|
||||
|
|
@ -1528,11 +1553,9 @@ impl<'db> SemanticsImpl<'db> {
|
|||
}
|
||||
|
||||
pub fn resolve_macro_call2(&self, macro_call: InFile<&ast::MacroCall>) -> Option<Macro> {
|
||||
self.with_ctx(|ctx| {
|
||||
ctx.macro_call_to_macro_call(macro_call)
|
||||
.and_then(|call| macro_call_to_macro_id(ctx, call))
|
||||
.map(Into::into)
|
||||
})
|
||||
self.to_def2(macro_call)
|
||||
.and_then(|call| self.with_ctx(|ctx| macro_call_to_macro_id(ctx, call)))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool {
|
||||
|
|
@ -1647,6 +1670,10 @@ impl<'db> SemanticsImpl<'db> {
|
|||
T::to_def(self, src)
|
||||
}
|
||||
|
||||
pub fn to_def2<T: ToDef>(&self, src: InFile<&T>) -> Option<T::Def> {
|
||||
T::to_def(self, src)
|
||||
}
|
||||
|
||||
fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
|
||||
self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,19 +399,6 @@ impl SourceToDefCtx<'_, '_> {
|
|||
Some((container, label?))
|
||||
}
|
||||
|
||||
pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> {
|
||||
let map = self.dyn_map(src)?;
|
||||
map[keys::ATTR_MACRO_CALL].get(&AstPtr::new(src.value)).copied()
|
||||
}
|
||||
|
||||
pub(super) fn macro_call_to_macro_call(
|
||||
&mut self,
|
||||
src: InFile<&ast::MacroCall>,
|
||||
) -> Option<MacroCallId> {
|
||||
let map = self.dyn_map(src)?;
|
||||
map[keys::MACRO_CALL].get(&AstPtr::new(src.value)).copied()
|
||||
}
|
||||
|
||||
/// (AttrId, derive attribute call id, derive call ids)
|
||||
pub(super) fn attr_to_derive_macro_call(
|
||||
&mut self,
|
||||
|
|
@ -449,6 +436,17 @@ impl SourceToDefCtx<'_, '_> {
|
|||
.or_insert_with(|| container.child_by_source(db, file_id))
|
||||
}
|
||||
|
||||
pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> {
|
||||
self.to_def(src, keys::ATTR_MACRO_CALL)
|
||||
}
|
||||
|
||||
pub(super) fn macro_call_to_macro_call(
|
||||
&mut self,
|
||||
src: InFile<&ast::MacroCall>,
|
||||
) -> Option<MacroCallId> {
|
||||
self.to_def(src, keys::MACRO_CALL)
|
||||
}
|
||||
|
||||
pub(super) fn type_param_to_def(
|
||||
&mut self,
|
||||
src: InFile<&ast::TypeParam>,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use hir::db::ExpandDatabase;
|
||||
use hir::{ExpandResult, InFile, Semantics};
|
||||
use hir::{ExpandResult, InFile, InRealFile, Semantics};
|
||||
use ide_db::{
|
||||
FileId, RootDatabase, base_db::Crate, helpers::pick_best_token,
|
||||
syntax_helpers::prettify_macro_expansion,
|
||||
};
|
||||
use span::{Edition, SpanMap, SyntaxContext, TextRange, TextSize};
|
||||
use span::{SpanMap, SyntaxContext, TextRange, TextSize};
|
||||
use stdx::format_to;
|
||||
use syntax::{AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, ast, ted};
|
||||
|
||||
|
|
@ -26,8 +26,9 @@ pub struct ExpandedMacro {
|
|||
// 
|
||||
pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
|
||||
let sema = Semantics::new(db);
|
||||
let file = sema.parse_guess_edition(position.file_id);
|
||||
let krate = sema.file_to_module_def(position.file_id)?.krate().into();
|
||||
let file_id = sema.attach_first_edition(position.file_id)?;
|
||||
let file = sema.parse(file_id);
|
||||
let krate = sema.file_to_module_def(file_id.file_id(db))?.krate().into();
|
||||
|
||||
let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
|
||||
SyntaxKind::IDENT => 1,
|
||||
|
|
@ -86,7 +87,10 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
return derive;
|
||||
}
|
||||
|
||||
let mut anc = tok.parent_ancestors();
|
||||
let mut anc = sema
|
||||
.descend_token_into_include_expansion(InRealFile::new(file_id, tok))
|
||||
.value
|
||||
.parent_ancestors();
|
||||
let mut span_map = SpanMap::empty();
|
||||
let mut error = String::new();
|
||||
let (name, expanded, kind) = loop {
|
||||
|
|
@ -95,14 +99,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
if let Some(item) = ast::Item::cast(node.clone()) {
|
||||
if let Some(def) = sema.resolve_attr_macro_call(&item) {
|
||||
break (
|
||||
def.name(db)
|
||||
.display(
|
||||
db,
|
||||
sema.attach_first_edition(position.file_id)
|
||||
.map(|it| it.edition(db))
|
||||
.unwrap_or(Edition::CURRENT),
|
||||
)
|
||||
.to_string(),
|
||||
def.name(db).display(db, file_id.edition(db)).to_string(),
|
||||
expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?,
|
||||
SyntaxKind::MACRO_ITEMS,
|
||||
);
|
||||
|
|
@ -759,4 +756,48 @@ fn test() {
|
|||
"<>hi""#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn in_included() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: include
|
||||
//- /main.rs crate:main
|
||||
include!("./included.rs");
|
||||
//- /included.rs
|
||||
macro_rules! foo {
|
||||
() => { fn item() {} };
|
||||
}
|
||||
foo$0!();
|
||||
"#,
|
||||
expect![[r#"
|
||||
foo!
|
||||
fn item(){}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn include() {
|
||||
check(
|
||||
r#"
|
||||
//- minicore: include
|
||||
//- /main.rs crate:main
|
||||
include$0!("./included.rs");
|
||||
//- /included.rs
|
||||
macro_rules! foo {
|
||||
() => { fn item() {} };
|
||||
}
|
||||
foo();
|
||||
"#,
|
||||
expect![[r#"
|
||||
include!
|
||||
macro_rules! foo {
|
||||
() => {
|
||||
fn item(){}
|
||||
|
||||
};
|
||||
}
|
||||
foo();"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue