diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-24 10:17:12 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-24 10:17:12 +0000 |
commit | 2aa64831e578406f85e68adf27e519175e1e532d (patch) | |
tree | ac288ca7b8a25ea41d8b66ed2deeedb33d5c8df8 /crates | |
parent | 5f9ba2d589afaaec91ee79bfc7fa3aba636916f2 (diff) | |
parent | 903a2e98f93df87af19375e951c56e7c285989d4 (diff) |
Merge #8183
8183: Fix missing command error with macros r=Veykril a=brandondong
**Reproduction:**
1. Define a struct through a macro (can be via `macro_rules`, proc macro, or `include!()`).
2. !!MISSING: command!! annotation appears. Clicking on it results in an error message. No matter where the macro is called/defined, the annotation is always at the start of the file.
![image](https://user-images.githubusercontent.com/13722457/112268785-bce14500-8c34-11eb-9a23-bafd63ffd6ef.png)
**Cause:**
- For struct `A`, a `HasImpls` annotation is added just like for struct `B`. Unlike `B`, the file id for `A` is not the file we are adding annotations to but a macro file.
- The resolving step of the code lens does not succeed.
**Fix:**
- Check that the files match before computing offsets and adding `HasImpls`/`HasReferences` annotations.
Co-authored-by: Brandon <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/annotations.rs | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 72492f826..64bc926f1 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{HasSource, Semantics}; | 2 | use hir::{HasSource, InFile, Semantics}; |
3 | use ide_db::{ | 3 | use ide_db::{ |
4 | base_db::{FileId, FilePosition, FileRange}, | 4 | base_db::{FileId, FilePosition, FileRange}, |
5 | helpers::visit_file_defs, | 5 | helpers::visit_file_defs, |
@@ -80,19 +80,19 @@ pub(crate) fn annotations( | |||
80 | Either::Left(def) => { | 80 | Either::Left(def) => { |
81 | let node = match def { | 81 | let node = match def { |
82 | hir::ModuleDef::Const(konst) => { | 82 | hir::ModuleDef::Const(konst) => { |
83 | konst.source(db).and_then(|node| range_and_position_of(&node.value)) | 83 | konst.source(db).and_then(|node| range_and_position_of(&node, file_id)) |
84 | } | 84 | } |
85 | hir::ModuleDef::Trait(trait_) => { | 85 | hir::ModuleDef::Trait(trait_) => { |
86 | trait_.source(db).and_then(|node| range_and_position_of(&node.value)) | 86 | trait_.source(db).and_then(|node| range_and_position_of(&node, file_id)) |
87 | } | 87 | } |
88 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { | 88 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { |
89 | strukt.source(db).and_then(|node| range_and_position_of(&node.value)) | 89 | strukt.source(db).and_then(|node| range_and_position_of(&node, file_id)) |
90 | } | 90 | } |
91 | hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => { | 91 | hir::ModuleDef::Adt(hir::Adt::Enum(enum_)) => { |
92 | enum_.source(db).and_then(|node| range_and_position_of(&node.value)) | 92 | enum_.source(db).and_then(|node| range_and_position_of(&node, file_id)) |
93 | } | 93 | } |
94 | hir::ModuleDef::Adt(hir::Adt::Union(union)) => { | 94 | hir::ModuleDef::Adt(hir::Adt::Union(union)) => { |
95 | union.source(db).and_then(|node| range_and_position_of(&node.value)) | 95 | union.source(db).and_then(|node| range_and_position_of(&node, file_id)) |
96 | } | 96 | } |
97 | _ => None, | 97 | _ => None, |
98 | }; | 98 | }; |
@@ -120,8 +120,19 @@ pub(crate) fn annotations( | |||
120 | }); | 120 | }); |
121 | } | 121 | } |
122 | 122 | ||
123 | fn range_and_position_of(node: &dyn NameOwner) -> Option<(TextSize, TextRange)> { | 123 | fn range_and_position_of<T: NameOwner>( |
124 | Some((node.name()?.syntax().text_range().start(), node.syntax().text_range())) | 124 | node: &InFile<T>, |
125 | file_id: FileId, | ||
126 | ) -> Option<(TextSize, TextRange)> { | ||
127 | if node.file_id != file_id.into() { | ||
128 | // Node is outside the file we are adding annotations to (e.g. macros). | ||
129 | None | ||
130 | } else { | ||
131 | Some(( | ||
132 | node.value.name()?.syntax().text_range().start(), | ||
133 | node.value.syntax().text_range(), | ||
134 | )) | ||
135 | } | ||
125 | } | 136 | } |
126 | } | 137 | } |
127 | Either::Right(_) => (), | 138 | Either::Right(_) => (), |
@@ -967,4 +978,23 @@ struct Foo; | |||
967 | "#]], | 978 | "#]], |
968 | ); | 979 | ); |
969 | } | 980 | } |
981 | |||
982 | #[test] | ||
983 | fn test_no_annotations_macro_struct_def() { | ||
984 | check( | ||
985 | r#" | ||
986 | //- /lib.rs | ||
987 | macro_rules! m { | ||
988 | () => { | ||
989 | struct A {} | ||
990 | }; | ||
991 | } | ||
992 | |||
993 | m!(); | ||
994 | "#, | ||
995 | expect![[r#" | ||
996 | [] | ||
997 | "#]], | ||
998 | ); | ||
999 | } | ||
970 | } | 1000 | } |