aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src')
-rw-r--r--crates/ra_ide/src/diagnostics.rs98
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs23
-rw-r--r--crates/ra_ide/src/hover.rs1142
-rw-r--r--crates/ra_ide/src/lib.rs4
-rw-r--r--crates/ra_ide/src/runnables.rs18
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html85
-rw-r--r--crates/ra_ide/src/status.rs15
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs12
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs8
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs3
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs9
11 files changed, 1335 insertions, 82 deletions
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index fd9abb55b..a88a978d7 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -8,7 +8,7 @@ use std::cell::RefCell;
8 8
9use hir::{ 9use hir::{
10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink}, 10 diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink},
11 Semantics, 11 HasSource, HirDisplay, Semantics, VariantDef,
12}; 12};
13use itertools::Itertools; 13use itertools::Itertools;
14use ra_db::SourceDatabase; 14use ra_db::SourceDatabase;
@@ -16,7 +16,7 @@ use ra_ide_db::RootDatabase;
16use ra_prof::profile; 16use ra_prof::profile;
17use ra_syntax::{ 17use ra_syntax::{
18 algo, 18 algo,
19 ast::{self, make, AstNode}, 19 ast::{self, edit::IndentLevel, make, AstNode},
20 SyntaxNode, TextRange, T, 20 SyntaxNode, TextRange, T,
21}; 21};
22use ra_text_edit::{TextEdit, TextEditBuilder}; 22use ra_text_edit::{TextEdit, TextEditBuilder};
@@ -119,7 +119,16 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
119 severity: Severity::Error, 119 severity: Severity::Error,
120 fix: Some(fix), 120 fix: Some(fix),
121 }) 121 })
122 })
123 .on::<hir::diagnostics::NoSuchField, _>(|d| {
124 res.borrow_mut().push(Diagnostic {
125 range: sema.diagnostics_range(d).range,
126 message: d.message(),
127 severity: Severity::Error,
128 fix: missing_struct_field_fix(&sema, file_id, d),
129 })
122 }); 130 });
131
123 if let Some(m) = sema.to_module_def(file_id) { 132 if let Some(m) = sema.to_module_def(file_id) {
124 m.diagnostics(db, &mut sink); 133 m.diagnostics(db, &mut sink);
125 }; 134 };
@@ -127,6 +136,68 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
127 res.into_inner() 136 res.into_inner()
128} 137}
129 138
139fn missing_struct_field_fix(
140 sema: &Semantics<RootDatabase>,
141 file_id: FileId,
142 d: &hir::diagnostics::NoSuchField,
143) -> Option<Fix> {
144 let record_expr = sema.ast(d);
145
146 let record_lit = ast::RecordLit::cast(record_expr.syntax().parent()?.parent()?)?;
147 let def_id = sema.resolve_variant(record_lit)?;
148 let module;
149 let record_fields = match VariantDef::from(def_id) {
150 VariantDef::Struct(s) => {
151 module = s.module(sema.db);
152 let source = s.source(sema.db);
153 let fields = source.value.field_def_list()?;
154 record_field_def_list(fields)?
155 }
156 VariantDef::Union(u) => {
157 module = u.module(sema.db);
158 let source = u.source(sema.db);
159 source.value.record_field_def_list()?
160 }
161 VariantDef::EnumVariant(e) => {
162 module = e.module(sema.db);
163 let source = e.source(sema.db);
164 let fields = source.value.field_def_list()?;
165 record_field_def_list(fields)?
166 }
167 };
168
169 let new_field_type = sema.type_of_expr(&record_expr.expr()?)?;
170 let new_field = make::record_field_def(
171 record_expr.field_name()?,
172 make::type_ref(&new_field_type.display_source_code(sema.db, module.into()).ok()?),
173 );
174
175 let last_field = record_fields.fields().last()?;
176 let last_field_syntax = last_field.syntax();
177 let indent = IndentLevel::from_node(last_field_syntax);
178
179 let mut new_field = format!("\n{}{}", indent, new_field);
180
181 let needs_comma = !last_field_syntax.to_string().ends_with(",");
182 if needs_comma {
183 new_field = format!(",{}", new_field);
184 }
185
186 let source_change = SourceFileEdit {
187 file_id,
188 edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field),
189 };
190 let fix = Fix::new("Create field", source_change.into());
191 return Some(fix);
192
193 fn record_field_def_list(field_def_list: ast::FieldDefList) -> Option<ast::RecordFieldDefList> {
194 match field_def_list {
195 ast::FieldDefList::RecordFieldDefList(it) => Some(it),
196 ast::FieldDefList::TupleFieldDefList(_) => None,
197 }
198 }
199}
200
130fn check_unnecessary_braces_in_use_statement( 201fn check_unnecessary_braces_in_use_statement(
131 acc: &mut Vec<Diagnostic>, 202 acc: &mut Vec<Diagnostic>,
132 file_id: FileId, 203 file_id: FileId,
@@ -791,4 +862,27 @@ fn main() {
791 check_struct_shorthand_initialization, 862 check_struct_shorthand_initialization,
792 ); 863 );
793 } 864 }
865
866 #[test]
867 fn test_add_field_from_usage() {
868 check_apply_diagnostic_fix(
869 r"
870 fn main() {
871 Foo { bar: 3, baz: false};
872 }
873 struct Foo {
874 bar: i32
875 }
876 ",
877 r"
878 fn main() {
879 Foo { bar: 3, baz: false};
880 }
881 struct Foo {
882 bar: i32,
883 baz: bool
884 }
885 ",
886 )
887 }
794} 888}
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index c7bb1e69f..0b52b01ab 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -135,8 +135,8 @@ impl NavigationTarget {
135 db: &RootDatabase, 135 db: &RootDatabase,
136 node: InFile<&dyn ast::NameOwner>, 136 node: InFile<&dyn ast::NameOwner>,
137 ) -> NavigationTarget { 137 ) -> NavigationTarget {
138 //FIXME: use `_` instead of empty string 138 let name =
139 let name = node.value.name().map(|it| it.text().clone()).unwrap_or_default(); 139 node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
140 let focus_range = 140 let focus_range =
141 node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range); 141 node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range);
142 let frange = original_range(db, node.map(|it| it.syntax())); 142 let frange = original_range(db, node.map(|it| it.syntax()));
@@ -150,6 +150,25 @@ impl NavigationTarget {
150 ) 150 )
151 } 151 }
152 152
153 /// Allows `NavigationTarget` to be created from a `DocCommentsOwner` and a `NameOwner`
154 pub(crate) fn from_doc_commented(
155 db: &RootDatabase,
156 named: InFile<&dyn ast::NameOwner>,
157 node: InFile<&dyn ast::DocCommentsOwner>,
158 ) -> NavigationTarget {
159 let name =
160 named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_"));
161 let frange = original_range(db, node.map(|it| it.syntax()));
162
163 NavigationTarget::from_syntax(
164 frange.file_id,
165 name,
166 None,
167 frange.range,
168 node.value.syntax().kind(),
169 )
170 }
171
153 fn from_syntax( 172 fn from_syntax(
154 file_id: FileId, 173 file_id: FileId,
155 name: SmolStr, 174 name: SmolStr,
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index ad78b7671..d870e4cbc 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -2,7 +2,7 @@ use std::iter::once;
2 2
3use hir::{ 3use hir::{
4 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay, 4 Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
5 ModuleDef, ModuleSource, Semantics, 5 Module, ModuleDef, ModuleSource, Semantics,
6}; 6};
7use itertools::Itertools; 7use itertools::Itertools;
8use ra_db::SourceDatabase; 8use ra_db::SourceDatabase;
@@ -13,7 +13,9 @@ use ra_ide_db::{
13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset}; 13use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
14 14
15use crate::{ 15use crate::{
16 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav}, 16 display::{
17 macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel, ToNav, TryToNav,
18 },
17 runnables::runnable, 19 runnables::runnable,
18 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, 20 FileId, FilePosition, NavigationTarget, RangeInfo, Runnable,
19}; 21};
@@ -24,19 +26,21 @@ pub struct HoverConfig {
24 pub implementations: bool, 26 pub implementations: bool,
25 pub run: bool, 27 pub run: bool,
26 pub debug: bool, 28 pub debug: bool,
29 pub goto_type_def: bool,
27} 30}
28 31
29impl Default for HoverConfig { 32impl Default for HoverConfig {
30 fn default() -> Self { 33 fn default() -> Self {
31 Self { implementations: true, run: true, debug: true } 34 Self { implementations: true, run: true, debug: true, goto_type_def: true }
32 } 35 }
33} 36}
34 37
35impl HoverConfig { 38impl HoverConfig {
36 pub const NO_ACTIONS: Self = Self { implementations: false, run: false, debug: false }; 39 pub const NO_ACTIONS: Self =
40 Self { implementations: false, run: false, debug: false, goto_type_def: false };
37 41
38 pub fn any(&self) -> bool { 42 pub fn any(&self) -> bool {
39 self.implementations || self.runnable() 43 self.implementations || self.runnable() || self.goto_type_def
40 } 44 }
41 45
42 pub fn none(&self) -> bool { 46 pub fn none(&self) -> bool {
@@ -52,6 +56,13 @@ impl HoverConfig {
52pub enum HoverAction { 56pub enum HoverAction {
53 Runnable(Runnable), 57 Runnable(Runnable),
54 Implementaion(FilePosition), 58 Implementaion(FilePosition),
59 GoToType(Vec<HoverGotoTypeData>),
60}
61
62#[derive(Debug, Clone, Eq, PartialEq)]
63pub struct HoverGotoTypeData {
64 pub mod_path: String,
65 pub nav: NavigationTarget,
55} 66}
56 67
57/// Contains the results when hovering over an item 68/// Contains the results when hovering over an item
@@ -138,6 +149,10 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
138 res.push_action(action); 149 res.push_action(action);
139 } 150 }
140 151
152 if let Some(action) = goto_type_action(db, name_kind) {
153 res.push_action(action);
154 }
155
141 return Some(RangeInfo::new(range, res)); 156 return Some(RangeInfo::new(range, res));
142 } 157 }
143 } 158 }
@@ -218,6 +233,44 @@ fn runnable_action(
218 } 233 }
219} 234}
220 235
236fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
237 match def {
238 Definition::Local(it) => {
239 let mut targets: Vec<ModuleDef> = Vec::new();
240 let mut push_new_def = |item: ModuleDef| {
241 if !targets.contains(&item) {
242 targets.push(item);
243 }
244 };
245
246 it.ty(db).walk(db, |t| {
247 if let Some(adt) = t.as_adt() {
248 push_new_def(adt.into());
249 } else if let Some(trait_) = t.as_dyn_trait() {
250 push_new_def(trait_.into());
251 } else if let Some(traits) = t.as_impl_traits(db) {
252 traits.into_iter().for_each(|it| push_new_def(it.into()));
253 } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
254 push_new_def(trait_.into());
255 }
256 });
257
258 let targets = targets
259 .into_iter()
260 .filter_map(|it| {
261 Some(HoverGotoTypeData {
262 mod_path: mod_path(db, &it)?,
263 nav: it.try_to_nav(db)?,
264 })
265 })
266 .collect();
267
268 Some(HoverAction::GoToType(targets))
269 }
270 _ => None,
271 }
272}
273
221fn hover_text( 274fn hover_text(
222 docs: Option<String>, 275 docs: Option<String>,
223 desc: Option<String>, 276 desc: Option<String>,
@@ -248,25 +301,31 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
248 .map(|name| name.to_string()) 301 .map(|name| name.to_string())
249} 302}
250 303
251fn determine_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> { 304fn determine_mod_path(db: &RootDatabase, module: Module, name: Option<String>) -> String {
252 let mod_path = def.module(db).map(|module| { 305 once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string))
253 once(db.crate_graph()[module.krate().into()].display_name.as_ref().map(ToString::to_string)) 306 .chain(
254 .chain( 307 module
255 module 308 .path_to_root(db)
256 .path_to_root(db) 309 .into_iter()
257 .into_iter() 310 .rev()
258 .rev() 311 .map(|it| it.name(db).map(|name| name.to_string())),
259 .map(|it| it.name(db).map(|name| name.to_string())), 312 )
260 ) 313 .chain(once(name))
261 .chain(once(definition_owner_name(db, def))) 314 .flatten()
262 .flatten() 315 .join("::")
263 .join("::") 316}
264 }); 317
265 mod_path 318// returns None only for ModuleDef::BuiltinType
319fn mod_path(db: &RootDatabase, item: &ModuleDef) -> Option<String> {
320 Some(determine_mod_path(db, item.module(db)?, item.name(db).map(|name| name.to_string())))
321}
322
323fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
324 def.module(db).map(|module| determine_mod_path(db, module, definition_owner_name(db, def)))
266} 325}
267 326
268fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> { 327fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<String> {
269 let mod_path = determine_mod_path(db, &def); 328 let mod_path = definition_mod_path(db, &def);
270 return match def { 329 return match def {
271 Definition::Macro(it) => { 330 Definition::Macro(it) => {
272 let src = it.source(db); 331 let src = it.source(db);
@@ -1310,4 +1369,1045 @@ fn func(foo: i32) { if true { <|>foo; }; }
1310 ] 1369 ]
1311 "###); 1370 "###);
1312 } 1371 }
1372
1373 #[test]
1374 fn test_hover_struct_has_goto_type_action() {
1375 let (_, actions) = check_hover_result(
1376 "
1377 //- /main.rs
1378 struct S{ f1: u32 }
1379
1380 fn main() {
1381 let s<|>t = S{ f1:0 };
1382 }
1383 ",
1384 &["S"],
1385 );
1386 assert_debug_snapshot!(actions,
1387 @r###"
1388 [
1389 GoToType(
1390 [
1391 HoverGotoTypeData {
1392 mod_path: "S",
1393 nav: NavigationTarget {
1394 file_id: FileId(
1395 1,
1396 ),
1397 full_range: 0..19,
1398 name: "S",
1399 kind: STRUCT_DEF,
1400 focus_range: Some(
1401 7..8,
1402 ),
1403 container_name: None,
1404 description: Some(
1405 "struct S",
1406 ),
1407 docs: None,
1408 },
1409 },
1410 ],
1411 ),
1412 ]
1413 "###);
1414 }
1415
1416 #[test]
1417 fn test_hover_generic_struct_has_goto_type_actions() {
1418 let (_, actions) = check_hover_result(
1419 "
1420 //- /main.rs
1421 struct Arg(u32);
1422 struct S<T>{ f1: T }
1423
1424 fn main() {
1425 let s<|>t = S{ f1:Arg(0) };
1426 }
1427 ",
1428 &["S<Arg>"],
1429 );
1430 assert_debug_snapshot!(actions,
1431 @r###"
1432 [
1433 GoToType(
1434 [
1435 HoverGotoTypeData {
1436 mod_path: "S",
1437 nav: NavigationTarget {
1438 file_id: FileId(
1439 1,
1440 ),
1441 full_range: 17..37,
1442 name: "S",
1443 kind: STRUCT_DEF,
1444 focus_range: Some(
1445 24..25,
1446 ),
1447 container_name: None,
1448 description: Some(
1449 "struct S",
1450 ),
1451 docs: None,
1452 },
1453 },
1454 HoverGotoTypeData {
1455 mod_path: "Arg",
1456 nav: NavigationTarget {
1457 file_id: FileId(
1458 1,
1459 ),
1460 full_range: 0..16,
1461 name: "Arg",
1462 kind: STRUCT_DEF,
1463 focus_range: Some(
1464 7..10,
1465 ),
1466 container_name: None,
1467 description: Some(
1468 "struct Arg",
1469 ),
1470 docs: None,
1471 },
1472 },
1473 ],
1474 ),
1475 ]
1476 "###);
1477 }
1478
1479 #[test]
1480 fn test_hover_generic_struct_has_flattened_goto_type_actions() {
1481 let (_, actions) = check_hover_result(
1482 "
1483 //- /main.rs
1484 struct Arg(u32);
1485 struct S<T>{ f1: T }
1486
1487 fn main() {
1488 let s<|>t = S{ f1: S{ f1: Arg(0) } };
1489 }
1490 ",
1491 &["S<S<Arg>>"],
1492 );
1493 assert_debug_snapshot!(actions,
1494 @r###"
1495 [
1496 GoToType(
1497 [
1498 HoverGotoTypeData {
1499 mod_path: "S",
1500 nav: NavigationTarget {
1501 file_id: FileId(
1502 1,
1503 ),
1504 full_range: 17..37,
1505 name: "S",
1506 kind: STRUCT_DEF,
1507 focus_range: Some(
1508 24..25,
1509 ),
1510 container_name: None,
1511 description: Some(
1512 "struct S",
1513 ),
1514 docs: None,
1515 },
1516 },
1517 HoverGotoTypeData {
1518 mod_path: "Arg",
1519 nav: NavigationTarget {
1520 file_id: FileId(
1521 1,
1522 ),
1523 full_range: 0..16,
1524 name: "Arg",
1525 kind: STRUCT_DEF,
1526 focus_range: Some(
1527 7..10,
1528 ),
1529 container_name: None,
1530 description: Some(
1531 "struct Arg",
1532 ),
1533 docs: None,
1534 },
1535 },
1536 ],
1537 ),
1538 ]
1539 "###);
1540 }
1541
1542 #[test]
1543 fn test_hover_tuple_has_goto_type_actions() {
1544 let (_, actions) = check_hover_result(
1545 "
1546 //- /main.rs
1547 struct A(u32);
1548 struct B(u32);
1549 mod M {
1550 pub struct C(u32);
1551 }
1552
1553 fn main() {
1554 let s<|>t = (A(1), B(2), M::C(3) );
1555 }
1556 ",
1557 &["(A, B, C)"],
1558 );
1559 assert_debug_snapshot!(actions,
1560 @r###"
1561 [
1562 GoToType(
1563 [
1564 HoverGotoTypeData {
1565 mod_path: "A",
1566 nav: NavigationTarget {
1567 file_id: FileId(
1568 1,
1569 ),
1570 full_range: 0..14,
1571 name: "A",
1572 kind: STRUCT_DEF,
1573 focus_range: Some(
1574 7..8,
1575 ),
1576 container_name: None,
1577 description: Some(
1578 "struct A",
1579 ),
1580 docs: None,
1581 },
1582 },
1583 HoverGotoTypeData {
1584 mod_path: "B",
1585 nav: NavigationTarget {
1586 file_id: FileId(
1587 1,
1588 ),
1589 full_range: 15..29,
1590 name: "B",
1591 kind: STRUCT_DEF,
1592 focus_range: Some(
1593 22..23,
1594 ),
1595 container_name: None,
1596 description: Some(
1597 "struct B",
1598 ),
1599 docs: None,
1600 },
1601 },
1602 HoverGotoTypeData {
1603 mod_path: "M::C",
1604 nav: NavigationTarget {
1605 file_id: FileId(
1606 1,
1607 ),
1608 full_range: 42..60,
1609 name: "C",
1610 kind: STRUCT_DEF,
1611 focus_range: Some(
1612 53..54,
1613 ),
1614 container_name: None,
1615 description: Some(
1616 "pub struct C",
1617 ),
1618 docs: None,
1619 },
1620 },
1621 ],
1622 ),
1623 ]
1624 "###);
1625 }
1626
1627 #[test]
1628 fn test_hover_return_impl_trait_has_goto_type_action() {
1629 let (_, actions) = check_hover_result(
1630 "
1631 //- /main.rs
1632 trait Foo {}
1633
1634 fn foo() -> impl Foo {}
1635
1636 fn main() {
1637 let s<|>t = foo();
1638 }
1639 ",
1640 &["impl Foo"],
1641 );
1642 assert_debug_snapshot!(actions,
1643 @r###"
1644 [
1645 GoToType(
1646 [
1647 HoverGotoTypeData {
1648 mod_path: "Foo",
1649 nav: NavigationTarget {
1650 file_id: FileId(
1651 1,
1652 ),
1653 full_range: 0..12,
1654 name: "Foo",
1655 kind: TRAIT_DEF,
1656 focus_range: Some(
1657 6..9,
1658 ),
1659 container_name: None,
1660 description: Some(
1661 "trait Foo",
1662 ),
1663 docs: None,
1664 },
1665 },
1666 ],
1667 ),
1668 ]
1669 "###);
1670 }
1671
1672 #[test]
1673 fn test_hover_generic_return_impl_trait_has_goto_type_action() {
1674 let (_, actions) = check_hover_result(
1675 "
1676 //- /main.rs
1677 trait Foo<T> {}
1678 struct S;
1679
1680 fn foo() -> impl Foo<S> {}
1681
1682 fn main() {
1683 let s<|>t = foo();
1684 }
1685 ",
1686 &["impl Foo<S>"],
1687 );
1688 assert_debug_snapshot!(actions,
1689 @r###"
1690 [
1691 GoToType(
1692 [
1693 HoverGotoTypeData {
1694 mod_path: "Foo",
1695 nav: NavigationTarget {
1696 file_id: FileId(
1697 1,
1698 ),
1699 full_range: 0..15,
1700 name: "Foo",
1701 kind: TRAIT_DEF,
1702 focus_range: Some(
1703 6..9,
1704 ),
1705 container_name: None,
1706 description: Some(
1707 "trait Foo",
1708 ),
1709 docs: None,
1710 },
1711 },
1712 HoverGotoTypeData {
1713 mod_path: "S",
1714 nav: NavigationTarget {
1715 file_id: FileId(
1716 1,
1717 ),
1718 full_range: 16..25,
1719 name: "S",
1720 kind: STRUCT_DEF,
1721 focus_range: Some(
1722 23..24,
1723 ),
1724 container_name: None,
1725 description: Some(
1726 "struct S",
1727 ),
1728 docs: None,
1729 },
1730 },
1731 ],
1732 ),
1733 ]
1734 "###);
1735 }
1736
1737 #[test]
1738 fn test_hover_return_impl_traits_has_goto_type_action() {
1739 let (_, actions) = check_hover_result(
1740 "
1741 //- /main.rs
1742 trait Foo {}
1743 trait Bar {}
1744
1745 fn foo() -> impl Foo + Bar {}
1746
1747 fn main() {
1748 let s<|>t = foo();
1749 }
1750 ",
1751 &["impl Foo + Bar"],
1752 );
1753 assert_debug_snapshot!(actions,
1754 @r###"
1755 [
1756 GoToType(
1757 [
1758 HoverGotoTypeData {
1759 mod_path: "Foo",
1760 nav: NavigationTarget {
1761 file_id: FileId(
1762 1,
1763 ),
1764 full_range: 0..12,
1765 name: "Foo",
1766 kind: TRAIT_DEF,
1767 focus_range: Some(
1768 6..9,
1769 ),
1770 container_name: None,
1771 description: Some(
1772 "trait Foo",
1773 ),
1774 docs: None,
1775 },
1776 },
1777 HoverGotoTypeData {
1778 mod_path: "Bar",
1779 nav: NavigationTarget {
1780 file_id: FileId(
1781 1,
1782 ),
1783 full_range: 13..25,
1784 name: "Bar",
1785 kind: TRAIT_DEF,
1786 focus_range: Some(
1787 19..22,
1788 ),
1789 container_name: None,
1790 description: Some(
1791 "trait Bar",
1792 ),
1793 docs: None,
1794 },
1795 },
1796 ],
1797 ),
1798 ]
1799 "###);
1800 }
1801
1802 #[test]
1803 fn test_hover_generic_return_impl_traits_has_goto_type_action() {
1804 let (_, actions) = check_hover_result(
1805 "
1806 //- /main.rs
1807 trait Foo<T> {}
1808 trait Bar<T> {}
1809 struct S1 {}
1810 struct S2 {}
1811
1812 fn foo() -> impl Foo<S1> + Bar<S2> {}
1813
1814 fn main() {
1815 let s<|>t = foo();
1816 }
1817 ",
1818 &["impl Foo<S1> + Bar<S2>"],
1819 );
1820 assert_debug_snapshot!(actions,
1821 @r###"
1822 [
1823 GoToType(
1824 [
1825 HoverGotoTypeData {
1826 mod_path: "Foo",
1827 nav: NavigationTarget {
1828 file_id: FileId(
1829 1,
1830 ),
1831 full_range: 0..15,
1832 name: "Foo",
1833 kind: TRAIT_DEF,
1834 focus_range: Some(
1835 6..9,
1836 ),
1837 container_name: None,
1838 description: Some(
1839 "trait Foo",
1840 ),
1841 docs: None,
1842 },
1843 },
1844 HoverGotoTypeData {
1845 mod_path: "Bar",
1846 nav: NavigationTarget {
1847 file_id: FileId(
1848 1,
1849 ),
1850 full_range: 16..31,
1851 name: "Bar",
1852 kind: TRAIT_DEF,
1853 focus_range: Some(
1854 22..25,
1855 ),
1856 container_name: None,
1857 description: Some(
1858 "trait Bar",
1859 ),
1860 docs: None,
1861 },
1862 },
1863 HoverGotoTypeData {
1864 mod_path: "S1",
1865 nav: NavigationTarget {
1866 file_id: FileId(
1867 1,
1868 ),
1869 full_range: 32..44,
1870 name: "S1",
1871 kind: STRUCT_DEF,
1872 focus_range: Some(
1873 39..41,
1874 ),
1875 container_name: None,
1876 description: Some(
1877 "struct S1",
1878 ),
1879 docs: None,
1880 },
1881 },
1882 HoverGotoTypeData {
1883 mod_path: "S2",
1884 nav: NavigationTarget {
1885 file_id: FileId(
1886 1,
1887 ),
1888 full_range: 45..57,
1889 name: "S2",
1890 kind: STRUCT_DEF,
1891 focus_range: Some(
1892 52..54,
1893 ),
1894 container_name: None,
1895 description: Some(
1896 "struct S2",
1897 ),
1898 docs: None,
1899 },
1900 },
1901 ],
1902 ),
1903 ]
1904 "###);
1905 }
1906
1907 #[test]
1908 fn test_hover_arg_impl_trait_has_goto_type_action() {
1909 let (_, actions) = check_hover_result(
1910 "
1911 //- /lib.rs
1912 trait Foo {}
1913 fn foo(ar<|>g: &impl Foo) {}
1914 ",
1915 &["&impl Foo"],
1916 );
1917 assert_debug_snapshot!(actions,
1918 @r###"
1919 [
1920 GoToType(
1921 [
1922 HoverGotoTypeData {
1923 mod_path: "Foo",
1924 nav: NavigationTarget {
1925 file_id: FileId(
1926 1,
1927 ),
1928 full_range: 0..12,
1929 name: "Foo",
1930 kind: TRAIT_DEF,
1931 focus_range: Some(
1932 6..9,
1933 ),
1934 container_name: None,
1935 description: Some(
1936 "trait Foo",
1937 ),
1938 docs: None,
1939 },
1940 },
1941 ],
1942 ),
1943 ]
1944 "###);
1945 }
1946
1947 #[test]
1948 fn test_hover_arg_impl_traits_has_goto_type_action() {
1949 let (_, actions) = check_hover_result(
1950 "
1951 //- /lib.rs
1952 trait Foo {}
1953 trait Bar<T> {}
1954 struct S{}
1955
1956 fn foo(ar<|>g: &impl Foo + Bar<S>) {}
1957 ",
1958 &["&impl Foo + Bar<S>"],
1959 );
1960 assert_debug_snapshot!(actions,
1961 @r###"
1962 [
1963 GoToType(
1964 [
1965 HoverGotoTypeData {
1966 mod_path: "Foo",
1967 nav: NavigationTarget {
1968 file_id: FileId(
1969 1,
1970 ),
1971 full_range: 0..12,
1972 name: "Foo",
1973 kind: TRAIT_DEF,
1974 focus_range: Some(
1975 6..9,
1976 ),
1977 container_name: None,
1978 description: Some(
1979 "trait Foo",
1980 ),
1981 docs: None,
1982 },
1983 },
1984 HoverGotoTypeData {
1985 mod_path: "Bar",
1986 nav: NavigationTarget {
1987 file_id: FileId(
1988 1,
1989 ),
1990 full_range: 13..28,
1991 name: "Bar",
1992 kind: TRAIT_DEF,
1993 focus_range: Some(
1994 19..22,
1995 ),
1996 container_name: None,
1997 description: Some(
1998 "trait Bar",
1999 ),
2000 docs: None,
2001 },
2002 },
2003 HoverGotoTypeData {
2004 mod_path: "S",
2005 nav: NavigationTarget {
2006 file_id: FileId(
2007 1,
2008 ),
2009 full_range: 29..39,
2010 name: "S",
2011 kind: STRUCT_DEF,
2012 focus_range: Some(
2013 36..37,
2014 ),
2015 container_name: None,
2016 description: Some(
2017 "struct S",
2018 ),
2019 docs: None,
2020 },
2021 },
2022 ],
2023 ),
2024 ]
2025 "###);
2026 }
2027
2028 #[test]
2029 fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
2030 let (_, actions) = check_hover_result(
2031 "
2032 //- /lib.rs
2033 trait Foo<T> {}
2034 struct S {}
2035 fn foo(ar<|>g: &impl Foo<S>) {}
2036 ",
2037 &["&impl Foo<S>"],
2038 );
2039 assert_debug_snapshot!(actions,
2040 @r###"
2041 [
2042 GoToType(
2043 [
2044 HoverGotoTypeData {
2045 mod_path: "Foo",
2046 nav: NavigationTarget {
2047 file_id: FileId(
2048 1,
2049 ),
2050 full_range: 0..15,
2051 name: "Foo",
2052 kind: TRAIT_DEF,
2053 focus_range: Some(
2054 6..9,
2055 ),
2056 container_name: None,
2057 description: Some(
2058 "trait Foo",
2059 ),
2060 docs: None,
2061 },
2062 },
2063 HoverGotoTypeData {
2064 mod_path: "S",
2065 nav: NavigationTarget {
2066 file_id: FileId(
2067 1,
2068 ),
2069 full_range: 16..27,
2070 name: "S",
2071 kind: STRUCT_DEF,
2072 focus_range: Some(
2073 23..24,
2074 ),
2075 container_name: None,
2076 description: Some(
2077 "struct S",
2078 ),
2079 docs: None,
2080 },
2081 },
2082 ],
2083 ),
2084 ]
2085 "###);
2086 }
2087
2088 #[test]
2089 fn test_hover_dyn_return_has_goto_type_action() {
2090 let (_, actions) = check_hover_result(
2091 "
2092 //- /main.rs
2093 trait Foo {}
2094 struct S;
2095 impl Foo for S {}
2096
2097 struct B<T>{}
2098
2099 fn foo() -> B<dyn Foo> {}
2100
2101 fn main() {
2102 let s<|>t = foo();
2103 }
2104 ",
2105 &["B<dyn Foo>"],
2106 );
2107 assert_debug_snapshot!(actions,
2108 @r###"
2109 [
2110 GoToType(
2111 [
2112 HoverGotoTypeData {
2113 mod_path: "B",
2114 nav: NavigationTarget {
2115 file_id: FileId(
2116 1,
2117 ),
2118 full_range: 41..54,
2119 name: "B",
2120 kind: STRUCT_DEF,
2121 focus_range: Some(
2122 48..49,
2123 ),
2124 container_name: None,
2125 description: Some(
2126 "struct B",
2127 ),
2128 docs: None,
2129 },
2130 },
2131 HoverGotoTypeData {
2132 mod_path: "Foo",
2133 nav: NavigationTarget {
2134 file_id: FileId(
2135 1,
2136 ),
2137 full_range: 0..12,
2138 name: "Foo",
2139 kind: TRAIT_DEF,
2140 focus_range: Some(
2141 6..9,
2142 ),
2143 container_name: None,
2144 description: Some(
2145 "trait Foo",
2146 ),
2147 docs: None,
2148 },
2149 },
2150 ],
2151 ),
2152 ]
2153 "###);
2154 }
2155
2156 #[test]
2157 fn test_hover_dyn_arg_has_goto_type_action() {
2158 let (_, actions) = check_hover_result(
2159 "
2160 //- /lib.rs
2161 trait Foo {}
2162 fn foo(ar<|>g: &dyn Foo) {}
2163 ",
2164 &["&dyn Foo"],
2165 );
2166 assert_debug_snapshot!(actions,
2167 @r###"
2168 [
2169 GoToType(
2170 [
2171 HoverGotoTypeData {
2172 mod_path: "Foo",
2173 nav: NavigationTarget {
2174 file_id: FileId(
2175 1,
2176 ),
2177 full_range: 0..12,
2178 name: "Foo",
2179 kind: TRAIT_DEF,
2180 focus_range: Some(
2181 6..9,
2182 ),
2183 container_name: None,
2184 description: Some(
2185 "trait Foo",
2186 ),
2187 docs: None,
2188 },
2189 },
2190 ],
2191 ),
2192 ]
2193 "###);
2194 }
2195
2196 #[test]
2197 fn test_hover_generic_dyn_arg_has_goto_type_action() {
2198 let (_, actions) = check_hover_result(
2199 "
2200 //- /lib.rs
2201 trait Foo<T> {}
2202 struct S {}
2203 fn foo(ar<|>g: &dyn Foo<S>) {}
2204 ",
2205 &["&dyn Foo<S>"],
2206 );
2207 assert_debug_snapshot!(actions,
2208 @r###"
2209 [
2210 GoToType(
2211 [
2212 HoverGotoTypeData {
2213 mod_path: "Foo",
2214 nav: NavigationTarget {
2215 file_id: FileId(
2216 1,
2217 ),
2218 full_range: 0..15,
2219 name: "Foo",
2220 kind: TRAIT_DEF,
2221 focus_range: Some(
2222 6..9,
2223 ),
2224 container_name: None,
2225 description: Some(
2226 "trait Foo",
2227 ),
2228 docs: None,
2229 },
2230 },
2231 HoverGotoTypeData {
2232 mod_path: "S",
2233 nav: NavigationTarget {
2234 file_id: FileId(
2235 1,
2236 ),
2237 full_range: 16..27,
2238 name: "S",
2239 kind: STRUCT_DEF,
2240 focus_range: Some(
2241 23..24,
2242 ),
2243 container_name: None,
2244 description: Some(
2245 "struct S",
2246 ),
2247 docs: None,
2248 },
2249 },
2250 ],
2251 ),
2252 ]
2253 "###);
2254 }
2255
2256 #[test]
2257 fn test_hover_goto_type_action_links_order() {
2258 let (_, actions) = check_hover_result(
2259 "
2260 //- /lib.rs
2261 trait ImplTrait<T> {}
2262 trait DynTrait<T> {}
2263 struct B<T> {}
2264 struct S {}
2265
2266 fn foo(a<|>rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
2267 ",
2268 &["&impl ImplTrait<B<dyn DynTrait<B<S>>>>"],
2269 );
2270 assert_debug_snapshot!(actions,
2271 @r###"
2272 [
2273 GoToType(
2274 [
2275 HoverGotoTypeData {
2276 mod_path: "ImplTrait",
2277 nav: NavigationTarget {
2278 file_id: FileId(
2279 1,
2280 ),
2281 full_range: 0..21,
2282 name: "ImplTrait",
2283 kind: TRAIT_DEF,
2284 focus_range: Some(
2285 6..15,
2286 ),
2287 container_name: None,
2288 description: Some(
2289 "trait ImplTrait",
2290 ),
2291 docs: None,
2292 },
2293 },
2294 HoverGotoTypeData {
2295 mod_path: "B",
2296 nav: NavigationTarget {
2297 file_id: FileId(
2298 1,
2299 ),
2300 full_range: 43..57,
2301 name: "B",
2302 kind: STRUCT_DEF,
2303 focus_range: Some(
2304 50..51,
2305 ),
2306 container_name: None,
2307 description: Some(
2308 "struct B",
2309 ),
2310 docs: None,
2311 },
2312 },
2313 HoverGotoTypeData {
2314 mod_path: "DynTrait",
2315 nav: NavigationTarget {
2316 file_id: FileId(
2317 1,
2318 ),
2319 full_range: 22..42,
2320 name: "DynTrait",
2321 kind: TRAIT_DEF,
2322 focus_range: Some(
2323 28..36,
2324 ),
2325 container_name: None,
2326 description: Some(
2327 "trait DynTrait",
2328 ),
2329 docs: None,
2330 },
2331 },
2332 HoverGotoTypeData {
2333 mod_path: "S",
2334 nav: NavigationTarget {
2335 file_id: FileId(
2336 1,
2337 ),
2338 full_range: 58..69,
2339 name: "S",
2340 kind: STRUCT_DEF,
2341 focus_range: Some(
2342 65..66,
2343 ),
2344 container_name: None,
2345 description: Some(
2346 "struct S",
2347 ),
2348 docs: None,
2349 },
2350 },
2351 ],
2352 ),
2353 ]
2354 "###);
2355 }
2356
2357 #[test]
2358 fn test_hover_associated_type_has_goto_type_action() {
2359 let (_, actions) = check_hover_result(
2360 "
2361 //- /main.rs
2362 trait Foo {
2363 type Item;
2364 fn get(self) -> Self::Item {}
2365 }
2366
2367 struct Bar{}
2368 struct S{}
2369
2370 impl Foo for S{
2371 type Item = Bar;
2372 }
2373
2374 fn test() -> impl Foo {
2375 S{}
2376 }
2377
2378 fn main() {
2379 let s<|>t = test().get();
2380 }
2381 ",
2382 &["Foo::Item<impl Foo>"],
2383 );
2384 assert_debug_snapshot!(actions,
2385 @r###"
2386 [
2387 GoToType(
2388 [
2389 HoverGotoTypeData {
2390 mod_path: "Foo",
2391 nav: NavigationTarget {
2392 file_id: FileId(
2393 1,
2394 ),
2395 full_range: 0..62,
2396 name: "Foo",
2397 kind: TRAIT_DEF,
2398 focus_range: Some(
2399 6..9,
2400 ),
2401 container_name: None,
2402 description: Some(
2403 "trait Foo",
2404 ),
2405 docs: None,
2406 },
2407 },
2408 ],
2409 ),
2410 ]
2411 "###);
2412 }
1313} 2413}
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 375da1f45..be9ab62c0 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -66,7 +66,7 @@ pub use crate::{
66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 66 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
67 expand_macro::ExpandedMacro, 67 expand_macro::ExpandedMacro,
68 folding_ranges::{Fold, FoldKind}, 68 folding_ranges::{Fold, FoldKind},
69 hover::{HoverAction, HoverConfig, HoverResult}, 69 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind}, 70 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, 71 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
72 runnables::{Runnable, RunnableKind, TestId}, 72 runnables::{Runnable, RunnableKind, TestId},
@@ -82,7 +82,7 @@ pub use ra_db::{
82 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, 82 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId,
83}; 83};
84pub use ra_ide_db::{ 84pub use ra_ide_db::{
85 change::{AnalysisChange, LibraryData}, 85 change::AnalysisChange,
86 line_index::{LineCol, LineIndex}, 86 line_index::{LineCol, LineIndex},
87 search::SearchScope, 87 search::SearchScope,
88 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 88 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index fc57dc33d..8105ef373 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -171,7 +171,15 @@ fn runnable_fn(
171 let cfg_exprs = 171 let cfg_exprs =
172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect(); 172 attrs.by_key("cfg").tt_values().map(|subtree| ra_cfg::parse_cfg(subtree)).collect();
173 173
174 let nav = NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def)); 174 let nav = if let RunnableKind::DocTest { .. } = kind {
175 NavigationTarget::from_doc_commented(
176 sema.db,
177 InFile::new(file_id.into(), &fn_def),
178 InFile::new(file_id.into(), &fn_def),
179 )
180 } else {
181 NavigationTarget::from_named(sema.db, InFile::new(file_id.into(), &fn_def))
182 };
175 Some(Runnable { nav, kind, cfg_exprs }) 183 Some(Runnable { nav, kind, cfg_exprs })
176} 184}
177 185
@@ -419,9 +427,7 @@ mod tests {
419 full_range: 22..64, 427 full_range: 22..64,
420 name: "foo", 428 name: "foo",
421 kind: FN_DEF, 429 kind: FN_DEF,
422 focus_range: Some( 430 focus_range: None,
423 56..59,
424 ),
425 container_name: None, 431 container_name: None,
426 description: None, 432 description: None,
427 docs: None, 433 docs: None,
@@ -486,9 +492,7 @@ mod tests {
486 full_range: 51..105, 492 full_range: 51..105,
487 name: "foo", 493 name: "foo",
488 kind: FN_DEF, 494 kind: FN_DEF,
489 focus_range: Some( 495 focus_range: None,
490 97..100,
491 ),
492 container_name: None, 496 container_name: None,
493 description: None, 497 description: None,
494 docs: None, 498 docs: None,
diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html
index f92a0aba5..63199cdbe 100644
--- a/crates/ra_ide/src/snapshots/highlight_doctest.html
+++ b/crates/ra_ide/src/snapshots/highlight_doctest.html
@@ -39,49 +39,58 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
39<span class="keyword">impl</span> <span class="struct">Foo</span> { 39<span class="keyword">impl</span> <span class="struct">Foo</span> {
40 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span>: <span class="builtin_type">bool</span> = <span class="bool_literal">true</span>; 40 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="constant declaration">bar</span>: <span class="builtin_type">bool</span> = <span class="bool_literal">true</span>;
41 41
42 <span class="comment">/// Constructs a new `Foo`.</span> 42 <span class="comment documentation">/// Constructs a new `Foo`.</span>
43 <span class="comment">///</span> 43 <span class="comment documentation">///</span>
44 <span class="comment">/// # Examples</span> 44 <span class="comment documentation">/// # Examples</span>
45 <span class="comment">///</span> 45 <span class="comment documentation">///</span>
46 <span class="comment">/// ```</span> 46 <span class="comment documentation">/// ```</span>
47 <span class="comment">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span> 47 <span class="comment documentation">/// #</span> <span class="attribute">#![</span><span class="function attribute">allow</span><span class="attribute">(unused_mut)]</span>
48 <span class="comment">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="struct">Foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>(); 48 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">foo</span>: <span class="struct">Foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>();
49 <span class="comment">/// ```</span> 49 <span class="comment documentation">/// ```</span>
50 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="struct">Foo</span> { 50 <span class="keyword">pub</span> <span class="keyword">const</span> <span class="keyword">fn</span> <span class="function declaration">new</span>() -&gt; <span class="struct">Foo</span> {
51 <span class="struct">Foo</span> { <span class="field">bar</span>: <span class="bool_literal">true</span> } 51 <span class="struct">Foo</span> { <span class="field">bar</span>: <span class="bool_literal">true</span> }
52 } 52 }
53 53
54 <span class="comment">/// `bar` method on `Foo`.</span> 54 <span class="comment documentation">/// `bar` method on `Foo`.</span>
55 <span class="comment">///</span> 55 <span class="comment documentation">///</span>
56 <span class="comment">/// # Examples</span> 56 <span class="comment documentation">/// # Examples</span>
57 <span class="comment">///</span> 57 <span class="comment documentation">///</span>
58 <span class="comment">/// ```</span> 58 <span class="comment documentation">/// ```</span>
59 <span class="comment">/// </span><span class="keyword">use</span> <span class="module">x</span>::<span class="module">y</span>; 59 <span class="comment documentation">/// </span><span class="keyword">use</span> <span class="module">x</span>::<span class="module">y</span>;
60 <span class="comment">///</span> 60 <span class="comment documentation">///</span>
61 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>(); 61 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">foo</span> = <span class="struct">Foo</span>::<span class="function">new</span>();
62 <span class="comment">///</span> 62 <span class="comment documentation">///</span>
63 <span class="comment">/// </span><span class="comment">// calls bar on foo</span> 63 <span class="comment documentation">/// </span><span class="comment">// calls bar on foo</span>
64 <span class="comment">/// </span><span class="macro">assert!</span>(foo.bar()); 64 <span class="comment documentation">/// </span><span class="macro">assert!</span>(foo.bar());
65 <span class="comment">///</span> 65 <span class="comment documentation">///</span>
66 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">bar</span> = <span class="variable">foo</span>.<span class="field">bar</span> || <span class="struct">Foo</span>::<span class="constant">bar</span>; 66 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">bar</span> = <span class="variable">foo</span>.<span class="field">bar</span> || <span class="struct">Foo</span>::<span class="constant">bar</span>;
67 <span class="comment">///</span> 67 <span class="comment documentation">///</span>
68 <span class="comment">/// </span><span class="comment">/* multi-line 68 <span class="comment documentation">/// </span><span class="comment">/* multi-line
69 </span><span class="comment">/// </span><span class="comment"> comment */</span> 69 </span><span class="comment documentation">/// </span><span class="comment"> comment */</span>
70 <span class="comment">///</span> 70 <span class="comment documentation">///</span>
71 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">multi_line_string</span> = <span class="string_literal">"Foo 71 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">multi_line_string</span> = <span class="string_literal">"Foo
72 </span><span class="comment">/// </span><span class="string_literal"> bar 72 </span><span class="comment documentation">/// </span><span class="string_literal"> bar
73 </span><span class="comment">/// </span><span class="string_literal"> "</span>; 73 </span><span class="comment documentation">/// </span><span class="string_literal"> "</span>;
74 <span class="comment">///</span> 74 <span class="comment documentation">///</span>
75 <span class="comment">/// ```</span> 75 <span class="comment documentation">/// ```</span>
76 <span class="comment">///</span> 76 <span class="comment documentation">///</span>
77 <span class="comment">/// ```rust,no_run</span> 77 <span class="comment documentation">/// ```rust,no_run</span>
78 <span class="comment">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>(); 78 <span class="comment documentation">/// </span><span class="keyword">let</span> <span class="variable declaration">foobar</span> = <span class="struct">Foo</span>::<span class="function">new</span>().<span class="function">bar</span>();
79 <span class="comment">/// ```</span> 79 <span class="comment documentation">/// ```</span>
80 <span class="comment">///</span> 80 <span class="comment documentation">///</span>
81 <span class="comment">/// ```sh</span> 81 <span class="comment documentation">/// ```sh</span>
82 <span class="comment">/// echo 1</span> 82 <span class="comment documentation">/// echo 1</span>
83 <span class="comment">/// ```</span> 83 <span class="comment documentation">/// ```</span>
84 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> { 84 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">foo</span>(&<span class="self_keyword">self</span>) -&gt; <span class="builtin_type">bool</span> {
85 <span class="bool_literal">true</span> 85 <span class="bool_literal">true</span>
86 } 86 }
87}
88
89<span class="comment documentation">/// ```</span>
90<span class="comment documentation">/// </span><span class="macro">noop!</span>(<span class="numeric_literal">1</span>);
91<span class="comment documentation">/// ```</span>
92<span class="macro">macro_rules!</span> <span class="macro declaration">noop</span> {
93 ($expr:expr) =&gt; {
94 $expr
95 }
87}</code></pre> \ No newline at end of file 96}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/status.rs b/crates/ra_ide/src/status.rs
index 5b7992920..45411b357 100644
--- a/crates/ra_ide/src/status.rs
+++ b/crates/ra_ide/src/status.rs
@@ -16,6 +16,7 @@ use ra_prof::{memory_usage, Bytes};
16use ra_syntax::{ast, Parse, SyntaxNode}; 16use ra_syntax::{ast, Parse, SyntaxNode};
17 17
18use crate::FileId; 18use crate::FileId;
19use rustc_hash::FxHashMap;
19 20
20fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { 21fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
21 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>() 22 db.query(ra_db::ParseQuery).entries::<SyntaxTreeStats>()
@@ -123,20 +124,24 @@ struct LibrarySymbolsStats {
123 124
124impl fmt::Display for LibrarySymbolsStats { 125impl fmt::Display for LibrarySymbolsStats {
125 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 126 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
126 write!(fmt, "{} ({}) symbols", self.total, self.size,) 127 write!(fmt, "{} ({}) symbols", self.total, self.size)
127 } 128 }
128} 129}
129 130
130impl FromIterator<TableEntry<SourceRootId, Arc<SymbolIndex>>> for LibrarySymbolsStats { 131impl FromIterator<TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>
132 for LibrarySymbolsStats
133{
131 fn from_iter<T>(iter: T) -> LibrarySymbolsStats 134 fn from_iter<T>(iter: T) -> LibrarySymbolsStats
132 where 135 where
133 T: IntoIterator<Item = TableEntry<SourceRootId, Arc<SymbolIndex>>>, 136 T: IntoIterator<Item = TableEntry<(), Arc<FxHashMap<SourceRootId, SymbolIndex>>>>,
134 { 137 {
135 let mut res = LibrarySymbolsStats::default(); 138 let mut res = LibrarySymbolsStats::default();
136 for entry in iter { 139 for entry in iter {
137 let value = entry.value.unwrap(); 140 let value = entry.value.unwrap();
138 res.total += value.len(); 141 for symbols in value.values() {
139 res.size += value.memory_size(); 142 res.total += symbols.len();
143 res.size += symbols.memory_size();
144 }
140 } 145 }
141 res 146 res
142 } 147 }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 854b6cc6d..448645bdc 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -121,7 +121,6 @@ pub(crate) fn highlight(
121 assert!(current_macro_call == Some(mc)); 121 assert!(current_macro_call == Some(mc));
122 current_macro_call = None; 122 current_macro_call = None;
123 format_string = None; 123 format_string = None;
124 continue;
125 } 124 }
126 _ => (), 125 _ => (),
127 } 126 }
@@ -150,7 +149,7 @@ pub(crate) fn highlight(
150 149
151 let range = element.text_range(); 150 let range = element.text_range();
152 151
153 let element_to_highlight = if current_macro_call.is_some() { 152 let element_to_highlight = if current_macro_call.is_some() && element.kind() != COMMENT {
154 // Inside a macro -- expand it first 153 // Inside a macro -- expand it first
155 let token = match element.clone().into_token() { 154 let token = match element.clone().into_token() {
156 Some(it) if it.parent().kind() == TOKEN_TREE => it, 155 Some(it) if it.parent().kind() == TOKEN_TREE => it,
@@ -489,7 +488,14 @@ fn highlight_element(
489 } 488 }
490 489
491 // Simple token-based highlighting 490 // Simple token-based highlighting
492 COMMENT => HighlightTag::Comment.into(), 491 COMMENT => {
492 let comment = element.into_token().and_then(ast::Comment::cast)?;
493 let h = HighlightTag::Comment;
494 match comment.kind().doc {
495 Some(_) => h | HighlightModifier::Documentation,
496 None => h.into(),
497 }
498 }
493 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::StringLiteral.into(), 499 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => HighlightTag::StringLiteral.into(),
494 ATTR => HighlightTag::Attribute.into(), 500 ATTR => HighlightTag::Attribute.into(),
495 INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(), 501 INT_NUMBER | FLOAT_NUMBER => HighlightTag::NumericLiteral.into(),
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index 929a5cc5c..415f24a6d 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -7,7 +7,10 @@ use hir::Semantics;
7use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; 7use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
8use stdx::SepBy; 8use stdx::SepBy;
9 9
10use crate::{call_info::ActiveParameter, Analysis, HighlightTag, HighlightedRange, RootDatabase}; 10use crate::{
11 call_info::ActiveParameter, Analysis, HighlightModifier, HighlightTag, HighlightedRange,
12 RootDatabase,
13};
11 14
12use super::HighlightedRangeStack; 15use super::HighlightedRangeStack;
13 16
@@ -118,7 +121,7 @@ pub(super) fn extract_doc_comments(
118 range.start(), 121 range.start(),
119 range.start() + TextSize::try_from(pos).unwrap(), 122 range.start() + TextSize::try_from(pos).unwrap(),
120 ), 123 ),
121 highlight: HighlightTag::Comment.into(), 124 highlight: HighlightTag::Comment | HighlightModifier::Documentation,
122 binding_hash: None, 125 binding_hash: None,
123 }); 126 });
124 line_start += range.len() - TextSize::try_from(pos).unwrap(); 127 line_start += range.len() - TextSize::try_from(pos).unwrap();
@@ -164,6 +167,7 @@ pub(super) fn highlight_doc_comment(
164 h.range.start() + start_offset, 167 h.range.start() + start_offset,
165 h.range.end() + end_offset.unwrap_or(start_offset), 168 h.range.end() + end_offset.unwrap_or(start_offset),
166 ); 169 );
170
167 stack.add(h); 171 stack.add(h);
168 } 172 }
169 } 173 }
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index 400d22fb6..93bbb4b4d 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -56,6 +56,7 @@ pub enum HighlightModifier {
56 /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is 56 /// `foo` in `fn foo(x: i32)` is a definition, `foo` in `foo(90 + 2)` is
57 /// not. 57 /// not.
58 Definition, 58 Definition,
59 Documentation,
59 Mutable, 60 Mutable,
60 Unsafe, 61 Unsafe,
61} 62}
@@ -108,6 +109,7 @@ impl HighlightModifier {
108 HighlightModifier::Attribute, 109 HighlightModifier::Attribute,
109 HighlightModifier::ControlFlow, 110 HighlightModifier::ControlFlow,
110 HighlightModifier::Definition, 111 HighlightModifier::Definition,
112 HighlightModifier::Documentation,
111 HighlightModifier::Mutable, 113 HighlightModifier::Mutable,
112 HighlightModifier::Unsafe, 114 HighlightModifier::Unsafe,
113 ]; 115 ];
@@ -117,6 +119,7 @@ impl HighlightModifier {
117 HighlightModifier::Attribute => "attribute", 119 HighlightModifier::Attribute => "attribute",
118 HighlightModifier::ControlFlow => "control", 120 HighlightModifier::ControlFlow => "control",
119 HighlightModifier::Definition => "declaration", 121 HighlightModifier::Definition => "declaration",
122 HighlightModifier::Documentation => "documentation",
120 HighlightModifier::Mutable => "mutable", 123 HighlightModifier::Mutable => "mutable",
121 HighlightModifier::Unsafe => "unsafe", 124 HighlightModifier::Unsafe => "unsafe",
122 } 125 }
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs
index b4d56a7a0..93a276ffe 100644
--- a/crates/ra_ide/src/syntax_highlighting/tests.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tests.rs
@@ -344,6 +344,15 @@ impl Foo {
344 true 344 true
345 } 345 }
346} 346}
347
348/// ```
349/// noop!(1);
350/// ```
351macro_rules! noop {
352 ($expr:expr) => {
353 $expr
354 }
355}
347"# 356"#
348 .trim(), 357 .trim(),
349 "crates/ra_ide/src/snapshots/highlight_doctest.html", 358 "crates/ra_ide/src/snapshots/highlight_doctest.html",