diff options
Diffstat (limited to 'crates/ide/src/annotations.rs')
-rw-r--r-- | crates/ide/src/annotations.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs new file mode 100644 index 000000000..6d54b6b57 --- /dev/null +++ b/crates/ide/src/annotations.rs | |||
@@ -0,0 +1,142 @@ | |||
1 | use hir::Semantics; | ||
2 | use ide_db::{ | ||
3 | base_db::{FileId, FilePosition, FileRange, SourceDatabase}, | ||
4 | RootDatabase, SymbolKind, | ||
5 | }; | ||
6 | use syntax::TextRange; | ||
7 | |||
8 | use crate::{ | ||
9 | file_structure::file_structure, | ||
10 | fn_references::find_all_methods, | ||
11 | goto_implementation::goto_implementation, | ||
12 | references::find_all_refs, | ||
13 | runnables::{runnables, Runnable}, | ||
14 | NavigationTarget, RunnableKind, | ||
15 | }; | ||
16 | |||
17 | // Feature: Annotations | ||
18 | // | ||
19 | // Provides user with annotations above items for looking up references or impl blocks | ||
20 | // and running/debugging binaries. | ||
21 | pub struct Annotation { | ||
22 | pub range: TextRange, | ||
23 | pub kind: AnnotationKind, | ||
24 | } | ||
25 | |||
26 | pub enum AnnotationKind { | ||
27 | Runnable { debug: bool, runnable: Runnable }, | ||
28 | HasImpls { position: FilePosition, data: Option<Vec<NavigationTarget>> }, | ||
29 | HasReferences { position: FilePosition, data: Option<Vec<FileRange>> }, | ||
30 | } | ||
31 | |||
32 | pub struct AnnotationConfig { | ||
33 | pub binary_target: bool, | ||
34 | pub annotate_runnables: bool, | ||
35 | pub annotate_impls: bool, | ||
36 | pub annotate_references: bool, | ||
37 | pub annotate_method_references: bool, | ||
38 | pub run: bool, | ||
39 | pub debug: bool, | ||
40 | } | ||
41 | |||
42 | pub(crate) fn annotations( | ||
43 | db: &RootDatabase, | ||
44 | file_id: FileId, | ||
45 | config: AnnotationConfig, | ||
46 | ) -> Vec<Annotation> { | ||
47 | let mut annotations = Vec::default(); | ||
48 | |||
49 | if config.annotate_runnables { | ||
50 | for runnable in runnables(db, file_id) { | ||
51 | if !matches!(runnable.kind, RunnableKind::Bin) || !config.binary_target { | ||
52 | continue; | ||
53 | } | ||
54 | |||
55 | let action = runnable.action(); | ||
56 | let range = runnable.nav.full_range; | ||
57 | |||
58 | if config.run { | ||
59 | annotations.push(Annotation { | ||
60 | range, | ||
61 | // FIXME: This one allocates without reason if run is enabled, but debug is disabled | ||
62 | kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() }, | ||
63 | }); | ||
64 | } | ||
65 | |||
66 | if action.debugee && config.debug { | ||
67 | annotations.push(Annotation { | ||
68 | range, | ||
69 | kind: AnnotationKind::Runnable { debug: true, runnable }, | ||
70 | }); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | |||
75 | file_structure(&db.parse(file_id).tree()) | ||
76 | .into_iter() | ||
77 | .filter(|node| { | ||
78 | matches!( | ||
79 | node.kind, | ||
80 | SymbolKind::Trait | ||
81 | | SymbolKind::Struct | ||
82 | | SymbolKind::Enum | ||
83 | | SymbolKind::Union | ||
84 | | SymbolKind::Const | ||
85 | ) | ||
86 | }) | ||
87 | .for_each(|node| { | ||
88 | if config.annotate_impls && node.kind != SymbolKind::Const { | ||
89 | annotations.push(Annotation { | ||
90 | range: node.node_range, | ||
91 | kind: AnnotationKind::HasImpls { | ||
92 | position: FilePosition { file_id, offset: node.navigation_range.start() }, | ||
93 | data: None, | ||
94 | }, | ||
95 | }); | ||
96 | } | ||
97 | |||
98 | if config.annotate_references { | ||
99 | annotations.push(Annotation { | ||
100 | range: node.node_range, | ||
101 | kind: AnnotationKind::HasReferences { | ||
102 | position: FilePosition { file_id, offset: node.navigation_range.start() }, | ||
103 | data: None, | ||
104 | }, | ||
105 | }); | ||
106 | } | ||
107 | }); | ||
108 | |||
109 | if config.annotate_method_references { | ||
110 | annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation { | ||
111 | range: method.range, | ||
112 | kind: AnnotationKind::HasReferences { | ||
113 | position: FilePosition { file_id, offset: method.range.start() }, | ||
114 | data: None, | ||
115 | }, | ||
116 | })); | ||
117 | } | ||
118 | |||
119 | annotations | ||
120 | } | ||
121 | |||
122 | pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation { | ||
123 | match annotation.kind { | ||
124 | AnnotationKind::HasImpls { position, ref mut data } => { | ||
125 | *data = goto_implementation(db, position).map(|range| range.info); | ||
126 | } | ||
127 | AnnotationKind::HasReferences { position, ref mut data } => { | ||
128 | *data = find_all_refs(&Semantics::new(db), position, None).map(|result| { | ||
129 | result | ||
130 | .references | ||
131 | .into_iter() | ||
132 | .map(|(_, access)| access.into_iter()) | ||
133 | .flatten() | ||
134 | .map(|(range, _)| FileRange { file_id: position.file_id, range }) | ||
135 | .collect() | ||
136 | }); | ||
137 | } | ||
138 | _ => {} | ||
139 | }; | ||
140 | |||
141 | annotation | ||
142 | } | ||