diff options
author | Aleksey Kladov <[email protected]> | 2020-02-18 17:35:10 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-02-26 11:55:50 +0000 |
commit | c3a4c4429de83450654795534e64e878a774a088 (patch) | |
tree | 12d89798f61b276f8bd640db07276a7d4e92b1c2 /crates/ra_ide/src/inlay_hints.rs | |
parent | 04deae3dba7c9b7054f7a1d64e4b93a05aecc132 (diff) |
Refactor primary IDE API
This introduces the new type -- Semantics.
Semantics maps SyntaxNodes to various semantic info, such as type,
name resolution or macro expansions.
To do so, Semantics maintains a HashMap which maps every node it saw
to the file from which the node originated. This is enough to get all
the necessary hir bits just from syntax.
Diffstat (limited to 'crates/ra_ide/src/inlay_hints.rs')
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 48 |
1 files changed, 21 insertions, 27 deletions
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index b42aa1523..35e3f782d 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{Adt, HirDisplay, SourceAnalyzer, SourceBinder, Type}; | 3 | use hir::{Adt, HirDisplay, Semantics, Type}; |
4 | use once_cell::unsync::Lazy; | ||
5 | use ra_ide_db::RootDatabase; | 4 | use ra_ide_db::RootDatabase; |
6 | use ra_prof::profile; | 5 | use ra_prof::profile; |
7 | use ra_syntax::{ | 6 | use ra_syntax::{ |
8 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, | 7 | ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner}, |
9 | match_ast, SmolStr, SourceFile, SyntaxNode, TextRange, | 8 | match_ast, SmolStr, SyntaxNode, TextRange, |
10 | }; | 9 | }; |
11 | 10 | ||
12 | use crate::{FileId, FunctionSignature}; | 11 | use crate::{FileId, FunctionSignature}; |
@@ -27,38 +26,36 @@ pub struct InlayHint { | |||
27 | pub(crate) fn inlay_hints( | 26 | pub(crate) fn inlay_hints( |
28 | db: &RootDatabase, | 27 | db: &RootDatabase, |
29 | file_id: FileId, | 28 | file_id: FileId, |
30 | file: &SourceFile, | ||
31 | max_inlay_hint_length: Option<usize>, | 29 | max_inlay_hint_length: Option<usize>, |
32 | ) -> Vec<InlayHint> { | 30 | ) -> Vec<InlayHint> { |
33 | let mut sb = SourceBinder::new(db); | 31 | let sema = Semantics::new(db); |
32 | let file = sema.parse(file_id); | ||
34 | let mut res = Vec::new(); | 33 | let mut res = Vec::new(); |
35 | for node in file.syntax().descendants() { | 34 | for node in file.syntax().descendants() { |
36 | get_inlay_hints(&mut res, &mut sb, file_id, &node, max_inlay_hint_length); | 35 | get_inlay_hints(&mut res, &sema, &node, max_inlay_hint_length); |
37 | } | 36 | } |
38 | res | 37 | res |
39 | } | 38 | } |
40 | 39 | ||
41 | fn get_inlay_hints( | 40 | fn get_inlay_hints( |
42 | acc: &mut Vec<InlayHint>, | 41 | acc: &mut Vec<InlayHint>, |
43 | sb: &mut SourceBinder<RootDatabase>, | 42 | sema: &Semantics<RootDatabase>, |
44 | file_id: FileId, | ||
45 | node: &SyntaxNode, | 43 | node: &SyntaxNode, |
46 | max_inlay_hint_length: Option<usize>, | 44 | max_inlay_hint_length: Option<usize>, |
47 | ) -> Option<()> { | 45 | ) -> Option<()> { |
48 | let _p = profile("get_inlay_hints"); | 46 | let _p = profile("get_inlay_hints"); |
49 | let db = sb.db; | 47 | let db = sema.db; |
50 | let analyzer = Lazy::new(move || sb.analyze(hir::InFile::new(file_id.into(), node), None)); | ||
51 | match_ast! { | 48 | match_ast! { |
52 | match node { | 49 | match node { |
53 | ast::CallExpr(it) => { | 50 | ast::CallExpr(it) => { |
54 | get_param_name_hints(acc, db, &analyzer, ast::Expr::from(it)); | 51 | get_param_name_hints(acc, sema, ast::Expr::from(it)); |
55 | }, | 52 | }, |
56 | ast::MethodCallExpr(it) => { | 53 | ast::MethodCallExpr(it) => { |
57 | get_param_name_hints(acc, db, &analyzer, ast::Expr::from(it)); | 54 | get_param_name_hints(acc, sema, ast::Expr::from(it)); |
58 | }, | 55 | }, |
59 | ast::BindPat(it) => { | 56 | ast::BindPat(it) => { |
60 | let pat = ast::Pat::from(it.clone()); | 57 | let pat = ast::Pat::from(it.clone()); |
61 | let ty = analyzer.type_of_pat(db, &pat)?; | 58 | let ty = sema.type_of_pat(&pat)?; |
62 | 59 | ||
63 | if should_not_display_type_hint(db, &it, &ty) { | 60 | if should_not_display_type_hint(db, &it, &ty) { |
64 | return None; | 61 | return None; |
@@ -125,8 +122,7 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_ | |||
125 | 122 | ||
126 | fn get_param_name_hints( | 123 | fn get_param_name_hints( |
127 | acc: &mut Vec<InlayHint>, | 124 | acc: &mut Vec<InlayHint>, |
128 | db: &RootDatabase, | 125 | sema: &Semantics<RootDatabase>, |
129 | analyzer: &SourceAnalyzer, | ||
130 | expr: ast::Expr, | 126 | expr: ast::Expr, |
131 | ) -> Option<()> { | 127 | ) -> Option<()> { |
132 | let args = match &expr { | 128 | let args = match &expr { |
@@ -138,7 +134,7 @@ fn get_param_name_hints( | |||
138 | // we need args len to determine whether to skip or not the &self parameter | 134 | // we need args len to determine whether to skip or not the &self parameter |
139 | .collect::<Vec<_>>(); | 135 | .collect::<Vec<_>>(); |
140 | 136 | ||
141 | let fn_signature = get_fn_signature(db, analyzer, &expr)?; | 137 | let fn_signature = get_fn_signature(sema, &expr)?; |
142 | let n_params_to_skip = | 138 | let n_params_to_skip = |
143 | if fn_signature.has_self_param && fn_signature.parameter_names.len() > args.len() { | 139 | if fn_signature.has_self_param && fn_signature.parameter_names.len() > args.len() { |
144 | 1 | 140 | 1 |
@@ -184,28 +180,26 @@ fn should_show_param_hint( | |||
184 | true | 180 | true |
185 | } | 181 | } |
186 | 182 | ||
187 | fn get_fn_signature( | 183 | fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<FunctionSignature> { |
188 | db: &RootDatabase, | ||
189 | analyzer: &SourceAnalyzer, | ||
190 | expr: &ast::Expr, | ||
191 | ) -> Option<FunctionSignature> { | ||
192 | match expr { | 184 | match expr { |
193 | ast::Expr::CallExpr(expr) => { | 185 | ast::Expr::CallExpr(expr) => { |
194 | // FIXME: Type::as_callable is broken for closures | 186 | // FIXME: Type::as_callable is broken for closures |
195 | let callable_def = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; | 187 | let callable_def = sema.type_of_expr(&expr.expr()?)?.as_callable()?; |
196 | match callable_def { | 188 | match callable_def { |
197 | hir::CallableDef::FunctionId(it) => { | 189 | hir::CallableDef::FunctionId(it) => { |
198 | Some(FunctionSignature::from_hir(db, it.into())) | 190 | Some(FunctionSignature::from_hir(sema.db, it.into())) |
191 | } | ||
192 | hir::CallableDef::StructId(it) => { | ||
193 | FunctionSignature::from_struct(sema.db, it.into()) | ||
199 | } | 194 | } |
200 | hir::CallableDef::StructId(it) => FunctionSignature::from_struct(db, it.into()), | ||
201 | hir::CallableDef::EnumVariantId(it) => { | 195 | hir::CallableDef::EnumVariantId(it) => { |
202 | FunctionSignature::from_enum_variant(db, it.into()) | 196 | FunctionSignature::from_enum_variant(sema.db, it.into()) |
203 | } | 197 | } |
204 | } | 198 | } |
205 | } | 199 | } |
206 | ast::Expr::MethodCallExpr(expr) => { | 200 | ast::Expr::MethodCallExpr(expr) => { |
207 | let fn_def = analyzer.resolve_method_call(&expr)?; | 201 | let fn_def = sema.resolve_method_call(&expr)?; |
208 | Some(FunctionSignature::from_hir(db, fn_def)) | 202 | Some(FunctionSignature::from_hir(sema.db, fn_def)) |
209 | } | 203 | } |
210 | _ => None, | 204 | _ => None, |
211 | } | 205 | } |