aboutsummaryrefslogtreecommitdiff
path: root/crates/ide
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide')
-rw-r--r--crates/ide/src/doc_links.rs58
-rw-r--r--crates/ide/src/expand_macro.rs23
-rw-r--r--crates/ide/src/lib.rs6
-rw-r--r--crates/ide/src/prime_caches.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs22
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs2
8 files changed, 63 insertions, 57 deletions
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index c5dc14a23..cb5a8e19a 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -108,13 +108,13 @@ pub(crate) fn external_docs(
108 let node = token.parent()?; 108 let node = token.parent()?;
109 let definition = match_ast! { 109 let definition = match_ast! {
110 match node { 110 match node {
111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), 111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db))?,
112 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), 112 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db))?,
113 _ => None, 113 _ => return None,
114 } 114 }
115 }; 115 };
116 116
117 get_doc_link(db, definition?) 117 get_doc_link(db, definition)
118} 118}
119 119
120/// Extracts all links from a given markdown text. 120/// Extracts all links from a given markdown text.
@@ -214,20 +214,20 @@ fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, Cow
214// This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented 214// This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented
215// https://github.com/rust-lang/rfcs/pull/2988 215// https://github.com/rust-lang/rfcs/pull/2988
216fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { 216fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
217 // Get the outermost definition for the moduledef. This is used to resolve the public path to the type, 217 // Get the outermost definition for the module def. This is used to resolve the public path to the type,
218 // then we can join the method, field, etc onto it if required. 218 // then we can join the method, field, etc onto it if required.
219 let target_def: ModuleDef = match definition { 219 let target_def: ModuleDef = match definition {
220 Definition::ModuleDef(moddef) => match moddef { 220 Definition::ModuleDef(def) => match def {
221 ModuleDef::Function(f) => f 221 ModuleDef::Function(f) => f
222 .as_assoc_item(db) 222 .as_assoc_item(db)
223 .and_then(|assoc| match assoc.container(db) { 223 .and_then(|assoc| match assoc.container(db) {
224 AssocItemContainer::Trait(t) => Some(t.into()), 224 AssocItemContainer::Trait(t) => Some(t.into()),
225 AssocItemContainer::Impl(impld) => { 225 AssocItemContainer::Impl(impl_) => {
226 impld.self_ty(db).as_adt().map(|adt| adt.into()) 226 impl_.self_ty(db).as_adt().map(|adt| adt.into())
227 } 227 }
228 }) 228 })
229 .unwrap_or_else(|| f.clone().into()), 229 .unwrap_or_else(|| def),
230 moddef => moddef, 230 def => def,
231 }, 231 },
232 Definition::Field(f) => f.parent_def(db).into(), 232 Definition::Field(f) => f.parent_def(db).into(),
233 // FIXME: Handle macros 233 // FIXME: Handle macros
@@ -236,17 +236,28 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
236 236
237 let ns = ItemInNs::from(target_def); 237 let ns = ItemInNs::from(target_def);
238 238
239 let module = definition.module(db)?; 239 let krate = match definition {
240 let krate = module.krate(); 240 // Definition::module gives back the parent module, we don't want that as it fails for root modules
241 Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(),
242 _ => definition.module(db)?.krate(),
243 };
241 let import_map = db.import_map(krate.into()); 244 let import_map = db.import_map(krate.into());
242 let base = once(krate.display_name(db)?.to_string()) 245
243 .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string())) 246 let mut base = krate.display_name(db)?.to_string();
244 .join("/") 247 let is_root_module = matches!(
245 + "/"; 248 definition,
249 Definition::ModuleDef(ModuleDef::Module(module)) if krate.root_module(db) == module
250 );
251 if !is_root_module {
252 base = once(base)
253 .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string()))
254 .join("/");
255 }
256 base += "/";
246 257
247 let filename = get_symbol_filename(db, &target_def); 258 let filename = get_symbol_filename(db, &target_def);
248 let fragment = match definition { 259 let fragment = match definition {
249 Definition::ModuleDef(moddef) => match moddef { 260 Definition::ModuleDef(def) => match def {
250 ModuleDef::Function(f) => { 261 ModuleDef::Function(f) => {
251 get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f))) 262 get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f)))
252 } 263 }
@@ -533,6 +544,19 @@ mod tests {
533 } 544 }
534 545
535 #[test] 546 #[test]
547 fn test_doc_url_crate() {
548 check(
549 r#"
550//- /main.rs crate:main deps:test
551use test$0::Foo;
552//- /lib.rs crate:test
553pub struct Foo;
554"#,
555 expect![[r#"https://docs.rs/test/*/test/index.html"#]],
556 );
557 }
558
559 #[test]
536 fn test_doc_url_struct() { 560 fn test_doc_url_struct() {
537 check( 561 check(
538 r#" 562 r#"
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index be0ee03bf..eebae5ebe 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -3,9 +3,7 @@ use std::iter;
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::RootDatabase; 4use ide_db::RootDatabase;
5use syntax::{ 5use syntax::{
6 algo::{find_node_at_offset, SyntaxRewriter}, 6 algo::find_node_at_offset, ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*,
7 ast, AstNode, NodeOrToken, SyntaxKind,
8 SyntaxKind::*,
9 SyntaxNode, WalkEvent, T, 7 SyntaxNode, WalkEvent, T,
10}; 8};
11 9
@@ -46,26 +44,23 @@ fn expand_macro_recur(
46 sema: &Semantics<RootDatabase>, 44 sema: &Semantics<RootDatabase>,
47 macro_call: &ast::MacroCall, 45 macro_call: &ast::MacroCall,
48) -> Option<SyntaxNode> { 46) -> Option<SyntaxNode> {
49 let mut expanded = sema.expand(macro_call)?; 47 let expanded = sema.expand(macro_call)?.clone_for_update();
50 48
51 let children = expanded.descendants().filter_map(ast::MacroCall::cast); 49 let children = expanded.descendants().filter_map(ast::MacroCall::cast);
52 let mut rewriter = SyntaxRewriter::default(); 50 let mut replacements = Vec::new();
53 51
54 for child in children.into_iter() { 52 for child in children {
55 if let Some(new_node) = expand_macro_recur(sema, &child) { 53 if let Some(new_node) = expand_macro_recur(sema, &child) {
56 // Replace the whole node if it is root 54 // check if the whole original syntax is replaced
57 // `replace_descendants` will not replace the parent node
58 // but `SyntaxNode::descendants include itself
59 if expanded == *child.syntax() { 55 if expanded == *child.syntax() {
60 expanded = new_node; 56 return Some(new_node);
61 } else {
62 rewriter.replace(child.syntax(), &new_node)
63 } 57 }
58 replacements.push((child, new_node));
64 } 59 }
65 } 60 }
66 61
67 let res = rewriter.rewrite(&expanded); 62 replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
68 Some(res) 63 Some(expanded)
69} 64}
70 65
71// FIXME: It would also be cool to share logic here and in the mbe tests, 66// FIXME: It would also be cool to share logic here and in the mbe tests,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b24c664ba..99e45633e 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -244,6 +244,12 @@ impl Analysis {
244 self.with_db(|db| db.parse(file_id).tree()) 244 self.with_db(|db| db.parse(file_id).tree())
245 } 245 }
246 246
247 /// Returns true if this file belongs to an immutable library.
248 pub fn is_library_file(&self, file_id: FileId) -> Cancelable<bool> {
249 use ide_db::base_db::SourceDatabaseExt;
250 self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
251 }
252
247 /// Gets the file's `LineIndex`: data structure to convert between absolute 253 /// Gets the file's `LineIndex`: data structure to convert between absolute
248 /// offsets and line/column representation. 254 /// offsets and line/column representation.
249 pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> { 255 pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> {
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index ea0acfaa0..03597f507 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -27,6 +27,7 @@ pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress)
27 let topo = &graph.crates_in_topological_order(); 27 let topo = &graph.crates_in_topological_order();
28 28
29 cb(PrimeCachesProgress::Started); 29 cb(PrimeCachesProgress::Started);
30 let _d = stdx::defer(|| cb(PrimeCachesProgress::Finished));
30 31
31 // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that. 32 // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
32 // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks 33 // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
@@ -41,6 +42,4 @@ pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress)
41 }); 42 });
42 db.crate_def_map(*krate); 43 db.crate_def_map(*krate);
43 } 44 }
44
45 cb(PrimeCachesProgress::Finished);
46} 45}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 8cc877c1c..18552459b 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -222,7 +222,7 @@ pub(super) fn element(
222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=] 222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=]
223 if element.parent().and_then(ast::BinExpr::cast).is_some() => 223 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
224 { 224 {
225 HlTag::Operator(HlOperator::Comparision).into() 225 HlTag::Operator(HlOperator::Comparison).into()
226 } 226 }
227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => { 227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
228 HlTag::Operator(HlOperator::Other).into() 228 HlTag::Operator(HlOperator::Other).into()
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 855c7fba8..bc221d599 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -4,7 +4,7 @@ use std::mem;
4 4
5use either::Either; 5use either::Either;
6use hir::{InFile, Semantics}; 6use hir::{InFile, Semantics};
7use ide_db::{call_info::ActiveParameter, SymbolKind}; 7use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode}, 9 ast::{self, AstNode},
10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
@@ -78,24 +78,6 @@ pub(super) fn ra_fixture(
78} 78}
79 79
80const RUSTDOC_FENCE: &'static str = "```"; 80const RUSTDOC_FENCE: &'static str = "```";
81const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
82 "",
83 "rust",
84 "should_panic",
85 "ignore",
86 "no_run",
87 "compile_fail",
88 "edition2015",
89 "edition2018",
90 "edition2021",
91];
92
93fn is_rustdoc_fence_token(token: &str) -> bool {
94 if RUSTDOC_FENCE_TOKENS.contains(&token) {
95 return true;
96 }
97 token.starts_with('E') && token.len() == 5 && token[1..].parse::<u32>().is_ok()
98}
99 81
100/// Injection of syntax highlighting of doctests. 82/// Injection of syntax highlighting of doctests.
101pub(super) fn doc_comment( 83pub(super) fn doc_comment(
@@ -181,7 +163,7 @@ pub(super) fn doc_comment(
181 is_codeblock = !is_codeblock; 163 is_codeblock = !is_codeblock;
182 // Check whether code is rust by inspecting fence guards 164 // Check whether code is rust by inspecting fence guards
183 let guards = &line[idx + RUSTDOC_FENCE.len()..]; 165 let guards = &line[idx + RUSTDOC_FENCE.len()..];
184 let is_rust = guards.split(',').all(|sub| is_rustdoc_fence_token(sub.trim())); 166 let is_rust = is_rust_fence(guards);
185 is_doctest = is_codeblock && is_rust; 167 is_doctest = is_codeblock && is_rust;
186 continue; 168 continue;
187 } 169 }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 8128d231d..e58392d67 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -96,7 +96,7 @@ pub enum HlOperator {
96 /// &&, ||, ! 96 /// &&, ||, !
97 Logical, 97 Logical,
98 /// >, <, ==, >=, <=, != 98 /// >, <, ==, >=, <=, !=
99 Comparision, 99 Comparison,
100 /// 100 ///
101 Other, 101 Other,
102} 102}
@@ -151,7 +151,7 @@ impl HlTag {
151 HlOperator::Bitwise => "bitwise", 151 HlOperator::Bitwise => "bitwise",
152 HlOperator::Arithmetic => "arithmetic", 152 HlOperator::Arithmetic => "arithmetic",
153 HlOperator::Logical => "logical", 153 HlOperator::Logical => "logical",
154 HlOperator::Comparision => "comparision", 154 HlOperator::Comparison => "comparison",
155 HlOperator::Other => "operator", 155 HlOperator::Other => "operator",
156 }, 156 },
157 HlTag::StringLiteral => "string_literal", 157 HlTag::StringLiteral => "string_literal",
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 933cfa6f3..17cc6334b 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -307,7 +307,7 @@ fn benchmark_syntax_highlighting_parser() {
307 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) 307 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
308 .count() 308 .count()
309 }; 309 };
310 assert_eq!(hash, 1629); 310 assert_eq!(hash, 1632);
311} 311}
312 312
313#[test] 313#[test]