aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/goto_definition.rs52
1 files changed, 49 insertions, 3 deletions
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a04333e63..b0bfd646e 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,10 +1,15 @@
1use std::convert::TryInto;
2
1use either::Either; 3use either::Either;
2use hir::{InFile, Semantics}; 4use hir::{InFile, Semantics};
3use ide_db::{ 5use ide_db::{
6 base_db::{AnchoredPath, FileId, FileLoader},
4 defs::{NameClass, NameRefClass}, 7 defs::{NameClass, NameRefClass},
5 RootDatabase, 8 RootDatabase,
6}; 9};
7use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 10use syntax::{
11 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, TextRange, TokenAtOffset, T,
12};
8 13
9use crate::{ 14use crate::{
10 display::TryToNav, 15 display::TryToNav,
@@ -32,7 +37,7 @@ pub(crate) fn goto_definition(
32 let original_token = pick_best(file.token_at_offset(position.offset))?; 37 let original_token = pick_best(file.token_at_offset(position.offset))?;
33 let token = sema.descend_into_macros(original_token.clone()); 38 let token = sema.descend_into_macros(original_token.clone());
34 let parent = token.parent()?; 39 let parent = token.parent()?;
35 if let Some(_) = ast::Comment::cast(token) { 40 if let Some(_) = ast::Comment::cast(token.clone()) {
36 let (attributes, def) = doc_attributes(&sema, &parent)?; 41 let (attributes, def) = doc_attributes(&sema, &parent)?;
37 42
38 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?; 43 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
@@ -45,7 +50,6 @@ pub(crate) fn goto_definition(
45 let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?; 50 let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?;
46 return Some(RangeInfo::new(original_token.text_range(), vec![nav])); 51 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
47 } 52 }
48
49 let nav = match_ast! { 53 let nav = match_ast! {
50 match parent { 54 match parent {
51 ast::NameRef(name_ref) => { 55 ast::NameRef(name_ref) => {
@@ -61,6 +65,7 @@ pub(crate) fn goto_definition(
61 } else { 65 } else {
62 reference_definition(&sema, Either::Left(&lt)) 66 reference_definition(&sema, Either::Left(&lt))
63 }, 67 },
68 ast::TokenTree(tt) => try_lookup_include_path(sema.db, tt, token, position.file_id),
64 _ => return None, 69 _ => return None,
65 } 70 }
66 }; 71 };
@@ -68,6 +73,32 @@ pub(crate) fn goto_definition(
68 Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect())) 73 Some(RangeInfo::new(original_token.text_range(), nav.into_iter().collect()))
69} 74}
70 75
76fn try_lookup_include_path(
77 db: &RootDatabase,
78 tt: ast::TokenTree,
79 token: SyntaxToken,
80 file_id: FileId,
81) -> Option<NavigationTarget> {
82 let path = ast::String::cast(token)?.value()?.into_owned();
83 let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
84 let name = macro_call.path()?.segment()?.name_ref()?;
85 if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
86 return None;
87 }
88 let file_id = db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
89 let size = db.file_text(file_id).len().try_into().ok()?;
90 Some(NavigationTarget {
91 file_id,
92 full_range: TextRange::new(0.into(), size),
93 name: path.into(),
94 focus_range: None,
95 kind: None,
96 container_name: None,
97 description: None,
98 docs: None,
99 })
100}
101
71fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 102fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
72 return tokens.max_by_key(priority); 103 return tokens.max_by_key(priority);
73 fn priority(n: &SyntaxToken) -> usize { 104 fn priority(n: &SyntaxToken) -> usize {
@@ -1216,4 +1247,19 @@ fn f(e: Enum) {
1216"#, 1247"#,
1217 ); 1248 );
1218 } 1249 }
1250
1251 #[test]
1252 fn goto_include() {
1253 check(
1254 r#"
1255//- /main.rs
1256fn main() {
1257 let str = include_str!("foo.txt$0");
1258}
1259//- /foo.txt
1260// empty
1261//^ file
1262"#,
1263 );
1264 }
1219} 1265}