mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
Support goto-definition for include macro paths
This commit is contained in:
parent
98395f29a4
commit
5391f9c63c
1 changed files with 49 additions and 3 deletions
|
@ -1,10 +1,15 @@
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{InFile, Semantics};
|
use hir::{InFile, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
|
base_db::{AnchoredPath, FileId, FileLoader},
|
||||||
defs::{NameClass, NameRefClass},
|
defs::{NameClass, NameRefClass},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
|
use syntax::{
|
||||||
|
ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, TokenAtOffset, T,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
display::TryToNav,
|
display::TryToNav,
|
||||||
|
@ -32,7 +37,7 @@ pub(crate) fn goto_definition(
|
||||||
let original_token = pick_best(file.token_at_offset(position.offset))?;
|
let original_token = pick_best(file.token_at_offset(position.offset))?;
|
||||||
let token = sema.descend_into_macros(original_token.clone());
|
let token = sema.descend_into_macros(original_token.clone());
|
||||||
let parent = token.parent()?;
|
let parent = token.parent()?;
|
||||||
if let Some(_) = ast::Comment::cast(token) {
|
if let Some(_) = ast::Comment::cast(token.clone()) {
|
||||||
let (attributes, def) = doc_attributes(&sema, &parent)?;
|
let (attributes, def) = doc_attributes(&sema, &parent)?;
|
||||||
|
|
||||||
let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
|
let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
|
||||||
|
@ -45,7 +50,6 @@ pub(crate) fn goto_definition(
|
||||||
let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?;
|
let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?;
|
||||||
return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
|
return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
|
||||||
}
|
}
|
||||||
|
|
||||||
let nav = match_ast! {
|
let nav = match_ast! {
|
||||||
match parent {
|
match parent {
|
||||||
ast::NameRef(name_ref) => {
|
ast::NameRef(name_ref) => {
|
||||||
|
@ -61,6 +65,7 @@ pub(crate) fn goto_definition(
|
||||||
} else {
|
} else {
|
||||||
reference_definition(&sema, Either::Left(<))
|
reference_definition(&sema, Either::Left(<))
|
||||||
},
|
},
|
||||||
|
ast::TokenTree(tt) => try_lookup_include_path(sema.db, tt, token, position.file_id),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -68,6 +73,32 @@ pub(crate) fn goto_definition(
|
||||||
Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect()))
|
Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn try_lookup_include_path(
|
||||||
|
db: &RootDatabase,
|
||||||
|
tt: ast::TokenTree,
|
||||||
|
token: SyntaxToken,
|
||||||
|
file_id: FileId,
|
||||||
|
) -> Option<NavigationTarget> {
|
||||||
|
let path = ast::String::cast(token)?.value()?.into_owned();
|
||||||
|
let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
|
||||||
|
let name = macro_call.path()?.segment()?.name_ref()?;
|
||||||
|
if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let file_id = db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
|
||||||
|
let size = db.file_text(file_id).len().try_into().ok()?;
|
||||||
|
Some(NavigationTarget {
|
||||||
|
file_id,
|
||||||
|
full_range: TextRange::new(0.into(), size),
|
||||||
|
name: path.into(),
|
||||||
|
focus_range: None,
|
||||||
|
kind: None,
|
||||||
|
container_name: None,
|
||||||
|
description: None,
|
||||||
|
docs: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
|
||||||
return tokens.max_by_key(priority);
|
return tokens.max_by_key(priority);
|
||||||
fn priority(n: &SyntaxToken) -> usize {
|
fn priority(n: &SyntaxToken) -> usize {
|
||||||
|
@ -1213,6 +1244,21 @@ fn f(e: Enum) {
|
||||||
Enum::Variant2 => {}
|
Enum::Variant2 => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_include() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
fn main() {
|
||||||
|
let str = include_str!("foo.txt$0");
|
||||||
|
}
|
||||||
|
//- /foo.txt
|
||||||
|
// empty
|
||||||
|
//^ file
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue