diff options
Diffstat (limited to 'crates/ra_hir/src/resolve.rs')
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 89 |
1 files changed, 83 insertions, 6 deletions
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 91a531801..57e7d0b9a 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -33,6 +33,67 @@ pub(crate) struct ExprScope { | |||
33 | } | 33 | } |
34 | 34 | ||
35 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone)] |
36 | pub(crate) struct PathResult { | ||
37 | /// The actual path resolution | ||
38 | resolution: PerNs<Resolution>, | ||
39 | /// The first index in the path that we | ||
40 | /// were unable to resolve. | ||
41 | /// When path is fully resolved, this is 0. | ||
42 | remaining_index: usize, | ||
43 | } | ||
44 | |||
45 | impl PathResult { | ||
46 | /// Returns the remaining index in the result | ||
47 | /// returns None if the path was fully resolved | ||
48 | pub(crate) fn remaining_index(&self) -> Option<usize> { | ||
49 | if self.remaining_index > 0 { | ||
50 | Some(self.remaining_index) | ||
51 | } else { | ||
52 | None | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /// Consumes `PathResult` and returns the contained `PerNs<Resolution>` | ||
57 | /// if the path was fully resolved, meaning we have no remaining items | ||
58 | pub(crate) fn into_fully_resolved(self) -> PerNs<Resolution> { | ||
59 | if self.is_fully_resolved() { | ||
60 | self.resolution | ||
61 | } else { | ||
62 | PerNs::none() | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /// Consumes `PathResult` and returns the resolution and the | ||
67 | /// remaining_index as a tuple. | ||
68 | pub(crate) fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) { | ||
69 | let index = self.remaining_index(); | ||
70 | (self.resolution, index) | ||
71 | } | ||
72 | |||
73 | /// Path is fully resolved when `remaining_index` is none | ||
74 | /// and the resolution contains anything | ||
75 | pub(crate) fn is_fully_resolved(&self) -> bool { | ||
76 | !self.resolution.is_none() && self.remaining_index().is_none() | ||
77 | } | ||
78 | |||
79 | fn empty() -> PathResult { | ||
80 | PathResult { resolution: PerNs::none(), remaining_index: 0 } | ||
81 | } | ||
82 | |||
83 | fn from_resolution(res: PerNs<Resolution>) -> PathResult { | ||
84 | PathResult::from_resolution_with_index(res, 0) | ||
85 | } | ||
86 | |||
87 | fn from_resolution_with_index(res: PerNs<Resolution>, remaining_index: usize) -> PathResult { | ||
88 | if res.is_none() { | ||
89 | PathResult::empty() | ||
90 | } else { | ||
91 | PathResult { resolution: res, remaining_index } | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | #[derive(Debug, Clone)] | ||
36 | pub(crate) enum Scope { | 97 | pub(crate) enum Scope { |
37 | /// All the items and imported names of a module | 98 | /// All the items and imported names of a module |
38 | ModuleScope(ModuleItemMap), | 99 | ModuleScope(ModuleItemMap), |
@@ -67,21 +128,37 @@ impl Resolver { | |||
67 | resolution | 128 | resolution |
68 | } | 129 | } |
69 | 130 | ||
70 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { | 131 | /// Returns the resolved path segments |
132 | /// Which may be fully resolved, empty or partially resolved. | ||
133 | pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult { | ||
71 | if let Some(name) = path.as_ident() { | 134 | if let Some(name) = path.as_ident() { |
72 | self.resolve_name(db, name) | 135 | PathResult::from_resolution(self.resolve_name(db, name)) |
73 | } else if path.is_self() { | 136 | } else if path.is_self() { |
74 | self.resolve_name(db, &Name::self_param()) | 137 | PathResult::from_resolution(self.resolve_name(db, &Name::self_param())) |
75 | } else { | 138 | } else { |
76 | let (item_map, module) = match self.module() { | 139 | let (item_map, module) = match self.module() { |
77 | Some(m) => m, | 140 | Some(m) => m, |
78 | _ => return PerNs::none(), | 141 | _ => return PathResult::empty(), |
79 | }; | 142 | }; |
80 | let module_res = item_map.resolve_path(db, module, path); | 143 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); |
81 | module_res.map(Resolution::Def) | 144 | |
145 | let def = module_res.map(Resolution::Def); | ||
146 | |||
147 | if let Some(index) = segment_index { | ||
148 | PathResult::from_resolution_with_index(def, index) | ||
149 | } else { | ||
150 | PathResult::from_resolution(def) | ||
151 | } | ||
82 | } | 152 | } |
83 | } | 153 | } |
84 | 154 | ||
155 | /// Returns the fully resolved path if we were able to resolve it. | ||
156 | /// otherwise returns `PerNs::none` | ||
157 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { | ||
158 | // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise | ||
159 | self.resolve_path_segments(db, path).into_fully_resolved() | ||
160 | } | ||
161 | |||
85 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { | 162 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { |
86 | let mut names = FxHashMap::default(); | 163 | let mut names = FxHashMap::default(); |
87 | for scope in self.scopes.iter().rev() { | 164 | for scope in self.scopes.iter().rev() { |