aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/paths/src/lib.rs100
-rw-r--r--crates/ra_arena/src/lib.rs3
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs2
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs92
-rw-r--r--crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ra_assists/src/handlers/fix_visibility.rs157
-rw-r--r--crates/ra_assists/src/handlers/introduce_variable.rs20
-rw-r--r--crates/ra_assists/src/handlers/merge_imports.rs12
-rw-r--r--crates/ra_assists/src/handlers/raw_string.rs48
-rw-r--r--crates/ra_assists/src/handlers/split_import.rs10
-rw-r--r--crates/ra_assists/src/tests.rs43
-rw-r--r--crates/ra_assists/src/utils.rs3
-rw-r--r--crates/ra_db/Cargo.toml2
-rw-r--r--crates/ra_db/src/fixture.rs180
-rw-r--r--crates/ra_db/src/input.rs110
-rw-r--r--crates/ra_db/src/lib.rs30
-rw-r--r--crates/ra_hir/src/code_model.rs125
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/has_source.rs10
-rw-r--r--crates/ra_hir/src/semantics.rs15
-rw-r--r--crates/ra_hir/src/source_analyzer.rs40
-rw-r--r--crates/ra_hir_def/Cargo.toml1
-rw-r--r--crates/ra_hir_def/src/attr.rs49
-rw-r--r--crates/ra_hir_def/src/body/lower.rs177
-rw-r--r--crates/ra_hir_def/src/body/scope.rs127
-rw-r--r--crates/ra_hir_def/src/data.rs382
-rw-r--r--crates/ra_hir_def/src/db.rs7
-rw-r--r--crates/ra_hir_def/src/generics.rs62
-rw-r--r--crates/ra_hir_def/src/item_scope.rs31
-rw-r--r--crates/ra_hir_def/src/item_tree.rs697
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs695
-rw-r--r--crates/ra_hir_def/src/item_tree/tests.rs435
-rw-r--r--crates/ra_hir_def/src/lib.rs101
-rw-r--r--crates/ra_hir_def/src/nameres.rs9
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs401
-rw-r--r--crates/ra_hir_def/src/nameres/mod_resolution.rs7
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs482
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs25
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs47
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs38
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs12
-rw-r--r--crates/ra_hir_def/src/src.rs31
-rw-r--r--crates/ra_hir_def/src/visibility.rs21
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs13
-rw-r--r--crates/ra_hir_ty/src/_match.rs77
-rw-r--r--crates/ra_hir_ty/src/db.rs15
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs12
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs81
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs33
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs2
-rw-r--r--crates/ra_hir_ty/src/lib.rs63
-rw-r--r--crates/ra_hir_ty/src/lower.rs25
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs198
-rw-r--r--crates/ra_hir_ty/src/tests.rs16
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs632
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs120
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs380
-rw-r--r--crates/ra_hir_ty/src/tests/never_type.rs190
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs627
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs447
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs1654
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs1597
-rw-r--r--crates/ra_hir_ty/src/traits.rs43
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs20
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs28
-rw-r--r--crates/ra_hir_ty/src/utils.rs14
-rw-r--r--crates/ra_ide/Cargo.toml2
-rw-r--r--crates/ra_ide/src/call_hierarchy.rs172
-rw-r--r--crates/ra_ide/src/call_info.rs6
-rw-r--r--crates/ra_ide/src/completion/complete_attribute.rs590
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs116
-rw-r--r--crates/ra_ide/src/completion/complete_fn_param.rs12
-rw-r--r--crates/ra_ide/src/completion/complete_macro_in_item_position.rs16
-rw-r--r--crates/ra_ide/src/completion/complete_pattern.rs28
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs220
-rw-r--r--crates/ra_ide/src/completion/complete_qualified_path.rs180
-rw-r--r--crates/ra_ide/src/completion/complete_record.rs314
-rw-r--r--crates/ra_ide/src/completion/complete_snippet.rs16
-rw-r--r--crates/ra_ide/src/completion/complete_trait_impl.rs44
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs310
-rw-r--r--crates/ra_ide/src/completion/presentation.rs217
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs6
-rw-r--r--crates/ra_ide/src/diagnostics.rs140
-rw-r--r--crates/ra_ide/src/display/function_signature.rs4
-rw-r--r--crates/ra_ide/src/extend_selection.rs12
-rw-r--r--crates/ra_ide/src/goto_definition.rs226
-rw-r--r--crates/ra_ide/src/hover.rs1192
-rw-r--r--crates/ra_ide/src/inlay_hints.rs178
-rw-r--r--crates/ra_ide/src/lib.rs21
-rw-r--r--crates/ra_ide/src/mock_analysis.rs190
-rw-r--r--crates/ra_ide/src/parent_module.rs13
-rw-r--r--crates/ra_ide/src/references.rs506
-rw-r--r--crates/ra_ide/src/references/rename.rs202
-rw-r--r--crates/ra_ide/src/runnables.rs16
-rw-r--r--crates/ra_ide/src/snapshots/highlight_doctest.html92
-rw-r--r--crates/ra_ide/src/snapshots/highlight_injection.html2
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html2
-rw-r--r--crates/ra_ide/src/snapshots/highlight_unsafe.html2
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html2
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html2
-rw-r--r--crates/ra_ide/src/ssr.rs566
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs76
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/injection.rs26
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs8
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tests.rs36
-rw-r--r--crates/ra_ide/src/syntax_tree.rs12
-rw-r--r--crates/ra_ide/src/typing/on_enter.rs15
-rw-r--r--crates/ra_ide_db/src/change.rs89
-rw-r--r--crates/ra_ide_db/src/search.rs4
-rw-r--r--crates/ra_ide_db/src/symbol_index.rs10
-rw-r--r--crates/ra_parser/src/grammar/paths.rs8
-rw-r--r--crates/ra_proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt2
-rw-r--r--crates/ra_project_model/Cargo.toml2
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs44
-rw-r--r--crates/ra_project_model/src/json_project.rs95
-rw-r--r--crates/ra_project_model/src/lib.rs135
-rw-r--r--crates/ra_project_model/src/project_json.rs117
-rw-r--r--crates/ra_project_model/src/sysroot.rs23
-rw-r--r--crates/ra_ssr/Cargo.toml19
-rw-r--r--crates/ra_ssr/src/lib.rs122
-rw-r--r--crates/ra_ssr/src/matching.rs591
-rw-r--r--crates/ra_ssr/src/parsing.rs272
-rw-r--r--crates/ra_ssr/src/replacing.rs63
-rw-r--r--crates/ra_ssr/src/tests.rs549
-rw-r--r--crates/ra_syntax/src/ast/make.rs4
-rw-r--r--crates/ra_syntax/src/lib.rs35
-rw-r--r--crates/ra_syntax/src/parsing.rs32
-rw-r--r--crates/ra_syntax/src/tests.rs66
-rw-r--r--crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.rast5
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/expr/err/0000_truncated_add.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/expr/ok/0000_add.rast8
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/expr/ok/0000_add.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/item/err/0000_extra_keyword.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rast12
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/item/ok/0000_fn.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/err/0000_reserved_word.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/err/0000_reserved_word.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/err/0001_expression.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/err/0001_expression.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/ok/0000_single_ident.rast4
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/ok/0000_single_ident.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/ok/0001_multipart.rast14
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/path/ok/0001_multipart.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/pattern/err/0000_reserved_word.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/pattern/err/0001_missing_paren.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/pattern/ok/0000_enum.rast10
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/pattern/ok/0000_enum.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/type/err/0000_missing_close.rast1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/type/err/0000_missing_close.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/type/ok/0000_result.rast22
-rw-r--r--crates/ra_syntax/test_data/parser/fragments/type/ok/0000_result.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rast15
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0015_empty_segment.rs1
-rw-r--r--crates/rust-analyzer/Cargo.toml6
-rw-r--r--crates/rust-analyzer/build.rs5
-rw-r--r--crates/rust-analyzer/src/bin/main.rs37
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs5
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs27
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs27
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs73
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs167
-rw-r--r--crates/rust-analyzer/src/config.rs39
-rw-r--r--crates/rust-analyzer/src/from_proto.rs16
-rw-r--r--crates/rust-analyzer/src/global_state.rs361
-rw-r--r--crates/rust-analyzer/src/handlers.rs (renamed from crates/rust-analyzer/src/main_loop/handlers.rs)274
-rw-r--r--crates/rust-analyzer/src/lib.rs36
-rw-r--r--crates/rust-analyzer/src/line_endings.rs64
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs (renamed from crates/rust-analyzer/src/main_loop/lsp_utils.rs)0
-rw-r--r--crates/rust-analyzer/src/main_loop.rs627
-rw-r--r--crates/rust-analyzer/src/main_loop/pending_requests.rs75
-rw-r--r--crates/rust-analyzer/src/main_loop/subscriptions.rs22
-rw-r--r--crates/rust-analyzer/src/request_metrics.rs37
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs19
-rw-r--r--crates/rust-analyzer/src/vfs_glob.rs98
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs76
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs58
-rw-r--r--crates/stdx/src/lib.rs85
-rw-r--r--crates/test_utils/Cargo.toml6
-rw-r--r--crates/test_utils/src/fixture.rs142
-rw-r--r--crates/test_utils/src/lib.rs296
-rw-r--r--crates/vfs-notify/Cargo.toml17
-rw-r--r--crates/vfs-notify/src/include.rs43
-rw-r--r--crates/vfs-notify/src/lib.rs244
-rw-r--r--crates/vfs/Cargo.toml4
-rw-r--r--crates/vfs/src/file_set.rs37
-rw-r--r--crates/vfs/src/lib.rs4
-rw-r--r--crates/vfs/src/loader.rs26
-rw-r--r--crates/vfs/src/vfs_path.rs70
-rw-r--r--crates/vfs/src/walkdir_loader.rs108
196 files changed, 13911 insertions, 8649 deletions
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index c7ce0c42f..1b259682d 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -28,6 +28,12 @@ impl AsRef<Path> for AbsPathBuf {
28 } 28 }
29} 29}
30 30
31impl AsRef<AbsPath> for AbsPathBuf {
32 fn as_ref(&self) -> &AbsPath {
33 self.as_path()
34 }
35}
36
31impl TryFrom<PathBuf> for AbsPathBuf { 37impl TryFrom<PathBuf> for AbsPathBuf {
32 type Error = PathBuf; 38 type Error = PathBuf;
33 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { 39 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
@@ -45,9 +51,19 @@ impl TryFrom<&str> for AbsPathBuf {
45 } 51 }
46} 52}
47 53
54impl PartialEq<AbsPath> for AbsPathBuf {
55 fn eq(&self, other: &AbsPath) -> bool {
56 self.as_path() == other
57 }
58}
59
48impl AbsPathBuf { 60impl AbsPathBuf {
61 pub fn assert(path: PathBuf) -> AbsPathBuf {
62 AbsPathBuf::try_from(path)
63 .unwrap_or_else(|path| panic!("expected absolute path, got {}", path.display()))
64 }
49 pub fn as_path(&self) -> &AbsPath { 65 pub fn as_path(&self) -> &AbsPath {
50 AbsPath::new_unchecked(self.0.as_path()) 66 AbsPath::assert(self.0.as_path())
51 } 67 }
52 pub fn pop(&mut self) -> bool { 68 pub fn pop(&mut self) -> bool {
53 self.0.pop() 69 self.0.pop()
@@ -77,21 +93,99 @@ impl<'a> TryFrom<&'a Path> for &'a AbsPath {
77 if !path.is_absolute() { 93 if !path.is_absolute() {
78 return Err(path); 94 return Err(path);
79 } 95 }
80 Ok(AbsPath::new_unchecked(path)) 96 Ok(AbsPath::assert(path))
81 } 97 }
82} 98}
83 99
84impl AbsPath { 100impl AbsPath {
85 fn new_unchecked(path: &Path) -> &AbsPath { 101 pub fn assert(path: &Path) -> &AbsPath {
102 assert!(path.is_absolute());
86 unsafe { &*(path as *const Path as *const AbsPath) } 103 unsafe { &*(path as *const Path as *const AbsPath) }
87 } 104 }
88 105
106 pub fn parent(&self) -> Option<&AbsPath> {
107 self.0.parent().map(AbsPath::assert)
108 }
89 pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { 109 pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf {
90 self.as_ref().join(path).try_into().unwrap() 110 self.as_ref().join(path).try_into().unwrap()
91 } 111 }
92 pub fn normalize(&self) -> AbsPathBuf { 112 pub fn normalize(&self) -> AbsPathBuf {
93 AbsPathBuf(normalize_path(&self.0)) 113 AbsPathBuf(normalize_path(&self.0))
94 } 114 }
115 pub fn to_path_buf(&self) -> AbsPathBuf {
116 AbsPathBuf::try_from(self.0.to_path_buf()).unwrap()
117 }
118 pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> {
119 self.0.strip_prefix(base).ok().map(RelPath::new_unchecked)
120 }
121}
122
123#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
124pub struct RelPathBuf(PathBuf);
125
126impl From<RelPathBuf> for PathBuf {
127 fn from(RelPathBuf(path_buf): RelPathBuf) -> PathBuf {
128 path_buf
129 }
130}
131
132impl ops::Deref for RelPathBuf {
133 type Target = RelPath;
134 fn deref(&self) -> &RelPath {
135 self.as_path()
136 }
137}
138
139impl AsRef<Path> for RelPathBuf {
140 fn as_ref(&self) -> &Path {
141 self.0.as_path()
142 }
143}
144
145impl TryFrom<PathBuf> for RelPathBuf {
146 type Error = PathBuf;
147 fn try_from(path_buf: PathBuf) -> Result<RelPathBuf, PathBuf> {
148 if !path_buf.is_relative() {
149 return Err(path_buf);
150 }
151 Ok(RelPathBuf(path_buf))
152 }
153}
154
155impl TryFrom<&str> for RelPathBuf {
156 type Error = PathBuf;
157 fn try_from(path: &str) -> Result<RelPathBuf, PathBuf> {
158 RelPathBuf::try_from(PathBuf::from(path))
159 }
160}
161
162impl RelPathBuf {
163 pub fn as_path(&self) -> &RelPath {
164 RelPath::new_unchecked(self.0.as_path())
165 }
166}
167
168#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
169#[repr(transparent)]
170pub struct RelPath(Path);
171
172impl ops::Deref for RelPath {
173 type Target = Path;
174 fn deref(&self) -> &Path {
175 &self.0
176 }
177}
178
179impl AsRef<Path> for RelPath {
180 fn as_ref(&self) -> &Path {
181 &self.0
182 }
183}
184
185impl RelPath {
186 pub fn new_unchecked(path: &Path) -> &RelPath {
187 unsafe { &*(path as *const Path as *const RelPath) }
188 }
95} 189}
96 190
97// https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85 191// https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index 441fbb3cb..3169aa5b8 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -116,6 +116,9 @@ impl<T> Arena<T> {
116 ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator { 116 ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator {
117 self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value)) 117 self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawId(idx as u32)), value))
118 } 118 }
119 pub fn shrink_to_fit(&mut self) {
120 self.data.shrink_to_fit();
121 }
119} 122}
120 123
121impl<T> Default for Arena<T> { 124impl<T> Default for Arena<T> {
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index 776bddf91..b0e56e1b5 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -128,7 +128,7 @@ impl From<foo::bar::baz::Boo> for A {
128 128
129 fn check_not_applicable(ra_fixture: &str) { 129 fn check_not_applicable(ra_fixture: &str) {
130 let fixture = 130 let fixture =
131 format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); 131 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
132 check_assist_not_applicable(add_from_impl_for_enum, &fixture) 132 check_assist_not_applicable(add_from_impl_for_enum, &fixture)
133 } 133 }
134 134
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index 5092bf336..d1cafa7d9 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -488,16 +488,17 @@ mod tests {
488 check_assist( 488 check_assist(
489 auto_import, 489 auto_import,
490 r" 490 r"
491 //- /lib.rs crate:crate_with_macro 491//- /lib.rs crate:crate_with_macro
492 #[macro_export] 492#[macro_export]
493 macro_rules! foo { 493macro_rules! foo {
494 () => () 494 () => ()
495 } 495}
496 496
497 //- /main.rs crate:main deps:crate_with_macro 497//- /main.rs crate:main deps:crate_with_macro
498 fn main() { 498fn main() {
499 foo<|> 499 foo<|>
500 }", 500}
501",
501 r"use crate_with_macro::foo; 502 r"use crate_with_macro::foo;
502 503
503fn main() { 504fn main() {
@@ -847,13 +848,14 @@ fn main() {
847 check_assist( 848 check_assist(
848 auto_import, 849 auto_import,
849 r" 850 r"
850 //- /lib.rs crate:dep 851//- /lib.rs crate:dep
851 pub struct Struct; 852pub struct Struct;
852 853
853 //- /main.rs crate:main deps:dep 854//- /main.rs crate:main deps:dep
854 fn main() { 855fn main() {
855 Struct<|> 856 Struct<|>
856 }", 857}
858",
857 r"use dep::Struct; 859 r"use dep::Struct;
858 860
859fn main() { 861fn main() {
@@ -869,20 +871,22 @@ fn main() {
869 check_assist( 871 check_assist(
870 auto_import, 872 auto_import,
871 r" 873 r"
872 //- /lib.rs crate:dep 874//- /lib.rs crate:dep
873 pub mod fmt { 875pub mod fmt {
874 pub trait Display {} 876 pub trait Display {}
875 } 877}
876 878
877 pub fn panic_fmt() {} 879pub fn panic_fmt() {}
878 880
879 //- /main.rs crate:main deps:dep 881//- /main.rs crate:main deps:dep
880 struct S; 882struct S;
881 883
882 impl f<|>mt::Display for S {}", 884impl f<|>mt::Display for S {}
885",
883 r"use dep::fmt; 886 r"use dep::fmt;
884 887
885struct S; 888struct S;
889
886impl fmt::Display for S {} 890impl fmt::Display for S {}
887", 891",
888 ); 892 );
@@ -894,21 +898,20 @@ impl fmt::Display for S {}
894 check_assist( 898 check_assist(
895 auto_import, 899 auto_import,
896 r" 900 r"
897 //- /lib.rs crate:dep 901//- /lib.rs crate:dep
898 902macro_rules! mac {
899 macro_rules! mac { 903 () => {
900 () => { 904 pub struct Cheese;
901 pub struct Cheese; 905 };
902 }; 906}
903 }
904
905 mac!();
906 907
907 //- /main.rs crate:main deps:dep 908mac!();
908 909
909 fn main() { 910//- /main.rs crate:main deps:dep
910 Cheese<|>; 911fn main() {
911 }", 912 Cheese<|>;
913}
914",
912 r"use dep::Cheese; 915 r"use dep::Cheese;
913 916
914fn main() { 917fn main() {
@@ -924,16 +927,15 @@ fn main() {
924 check_assist( 927 check_assist(
925 auto_import, 928 auto_import,
926 r" 929 r"
927 //- /lib.rs crate:dep 930//- /lib.rs crate:dep
928 931pub struct FMT;
929 pub struct FMT; 932pub struct fmt;
930 pub struct fmt;
931
932 //- /main.rs crate:main deps:dep
933 933
934 fn main() { 934//- /main.rs crate:main deps:dep
935 FMT<|>; 935fn main() {
936 }", 936 FMT<|>;
937}
938",
937 r"use dep::FMT; 939 r"use dep::FMT;
938 940
939fn main() { 941fn main() {
diff --git a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
index 44db7917a..43b4584b4 100644
--- a/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ra_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -301,7 +301,7 @@ fn another_fn() {
301 301
302 fn check_not_applicable(ra_fixture: &str) { 302 fn check_not_applicable(ra_fixture: &str) {
303 let fixture = 303 let fixture =
304 format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); 304 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
305 check_assist_not_applicable(extract_struct_from_enum_variant, &fixture) 305 check_assist_not_applicable(extract_struct_from_enum_variant, &fixture)
306 } 306 }
307 307
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 569efb768..64270c86f 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -763,9 +763,9 @@ mod tests {
763fn foo(opt: Option<i32>) { 763fn foo(opt: Option<i32>) {
764 match opt<|> { 764 match opt<|> {
765 } 765 }
766}"#; 766}
767 let before = 767"#;
768 &format!("//- main.rs crate:main deps:core\n{}{}", before, FamousDefs::FIXTURE); 768 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
769 769
770 check_assist( 770 check_assist(
771 fill_match_arms, 771 fill_match_arms,
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 531b3560f..54601d1f3 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -255,15 +255,14 @@ mod tests {
255 check_assist( 255 check_assist(
256 fix_visibility, 256 fix_visibility,
257 r" 257 r"
258 //- /main.rs 258//- /main.rs
259 mod foo; 259mod foo;
260 fn main() { foo::Foo<|> } 260fn main() { foo::Foo<|> }
261 261
262 //- /foo.rs 262//- /foo.rs
263 struct Foo; 263struct Foo;
264 ", 264",
265 r"$0pub(crate) struct Foo; 265 r"$0pub(crate) struct Foo;
266
267", 266",
268 ); 267 );
269 } 268 }
@@ -279,14 +278,14 @@ mod tests {
279 ); 278 );
280 check_assist( 279 check_assist(
281 fix_visibility, 280 fix_visibility,
282 r"//- /lib.rs 281 r"
283 mod foo; 282//- /lib.rs
284 fn main() { foo::Foo { <|>bar: () }; } 283mod foo;
285 //- /foo.rs 284fn main() { foo::Foo { <|>bar: () }; }
286 pub struct Foo { bar: () } 285//- /foo.rs
287 ", 286pub struct Foo { bar: () }
287",
288 r"pub struct Foo { $0pub(crate) bar: () } 288 r"pub struct Foo { $0pub(crate) bar: () }
289
290", 289",
291 ); 290 );
292 check_assist_not_applicable( 291 check_assist_not_applicable(
@@ -296,12 +295,13 @@ mod tests {
296 ); 295 );
297 check_assist_not_applicable( 296 check_assist_not_applicable(
298 fix_visibility, 297 fix_visibility,
299 r"//- /lib.rs 298 r"
300 mod foo; 299//- /lib.rs
301 fn main() { foo::Foo { <|>bar: () }; } 300mod foo;
302 //- /foo.rs 301fn main() { foo::Foo { <|>bar: () }; }
303 pub struct Foo { pub bar: () } 302//- /foo.rs
304 ", 303pub struct Foo { pub bar: () }
304",
305 ); 305 );
306 } 306 }
307 307
@@ -316,14 +316,14 @@ mod tests {
316 ); 316 );
317 check_assist( 317 check_assist(
318 fix_visibility, 318 fix_visibility,
319 r"//- /lib.rs 319 r"
320 mod foo; 320//- /lib.rs
321 fn main() { foo::Foo::Bar { <|>bar: () }; } 321mod foo;
322 //- /foo.rs 322fn main() { foo::Foo::Bar { <|>bar: () }; }
323 pub enum Foo { Bar { bar: () } } 323//- /foo.rs
324 ", 324pub enum Foo { Bar { bar: () } }
325",
325 r"pub enum Foo { Bar { $0pub(crate) bar: () } } 326 r"pub enum Foo { Bar { $0pub(crate) bar: () } }
326
327", 327",
328 ); 328 );
329 check_assist_not_applicable( 329 check_assist_not_applicable(
@@ -333,12 +333,13 @@ mod tests {
333 ); 333 );
334 check_assist_not_applicable( 334 check_assist_not_applicable(
335 fix_visibility, 335 fix_visibility,
336 r"//- /lib.rs 336 r"
337 mod foo; 337//- /lib.rs
338 fn main() { foo::Foo { <|>bar: () }; } 338mod foo;
339 //- /foo.rs 339fn main() { foo::Foo { <|>bar: () }; }
340 pub struct Foo { pub bar: () } 340//- /foo.rs
341 ", 341pub struct Foo { pub bar: () }
342",
342 ); 343 );
343 } 344 }
344 345
@@ -355,14 +356,14 @@ mod tests {
355 ); 356 );
356 check_assist( 357 check_assist(
357 fix_visibility, 358 fix_visibility,
358 r"//- /lib.rs 359 r"
359 mod foo; 360//- /lib.rs
360 fn main() { foo::Foo { <|>bar: () }; } 361mod foo;
361 //- /foo.rs 362fn main() { foo::Foo { <|>bar: () }; }
362 pub union Foo { bar: () } 363//- /foo.rs
363 ", 364pub union Foo { bar: () }
365",
364 r"pub union Foo { $0pub(crate) bar: () } 366 r"pub union Foo { $0pub(crate) bar: () }
365
366", 367",
367 ); 368 );
368 check_assist_not_applicable( 369 check_assist_not_applicable(
@@ -372,12 +373,13 @@ mod tests {
372 ); 373 );
373 check_assist_not_applicable( 374 check_assist_not_applicable(
374 fix_visibility, 375 fix_visibility,
375 r"//- /lib.rs 376 r"
376 mod foo; 377//- /lib.rs
377 fn main() { foo::Foo { <|>bar: () }; } 378mod foo;
378 //- /foo.rs 379fn main() { foo::Foo { <|>bar: () }; }
379 pub union Foo { pub bar: () } 380//- /foo.rs
380 ", 381pub union Foo { pub bar: () }
382",
381 ); 383 );
382 } 384 }
383 385
@@ -458,19 +460,18 @@ mod tests {
458 check_assist( 460 check_assist(
459 fix_visibility, 461 fix_visibility,
460 r" 462 r"
461 //- /main.rs 463//- /main.rs
462 mod foo; 464mod foo;
463 fn main() { foo::bar<|>::baz(); } 465fn main() { foo::bar<|>::baz(); }
464 466
465 //- /foo.rs 467//- /foo.rs
466 mod bar { 468mod bar {
467 pub fn baz() {} 469 pub fn baz() {}
468 } 470}
469 ", 471",
470 r"$0pub(crate) mod bar { 472 r"$0pub(crate) mod bar {
471 pub fn baz() {} 473 pub fn baz() {}
472} 474}
473
474", 475",
475 ); 476 );
476 477
@@ -486,17 +487,15 @@ mod tests {
486 check_assist( 487 check_assist(
487 fix_visibility, 488 fix_visibility,
488 r" 489 r"
489 //- /main.rs 490//- /main.rs
490 mod foo; 491mod foo;
491 fn main() { foo::bar<|>::baz(); } 492fn main() { foo::bar<|>::baz(); }
492 493
493 //- /foo.rs 494//- /foo.rs
494 mod bar; 495mod bar;
495 496//- /foo/bar.rs
496 //- /foo/bar.rs 497pub fn baz() {}
497 pub fn baz() {} 498",
498 }
499 ",
500 r"$0pub(crate) mod bar; 499 r"$0pub(crate) mod bar;
501", 500",
502 ); 501 );
@@ -506,14 +505,16 @@ mod tests {
506 fn fix_visibility_of_module_declaration_in_other_file() { 505 fn fix_visibility_of_module_declaration_in_other_file() {
507 check_assist( 506 check_assist(
508 fix_visibility, 507 fix_visibility,
509 r"//- /main.rs 508 r"
510 mod foo; 509//- /main.rs
511 fn main() { foo::bar<|>>::baz(); } 510mod foo;
511fn main() { foo::bar<|>>::baz(); }
512 512
513 //- /foo.rs 513//- /foo.rs
514 mod bar { 514mod bar {
515 pub fn baz() {} 515 pub fn baz() {}
516 }", 516}
517",
517 r"$0pub(crate) mod bar { 518 r"$0pub(crate) mod bar {
518 pub fn baz() {} 519 pub fn baz() {}
519} 520}
@@ -525,10 +526,12 @@ mod tests {
525 fn adds_pub_when_target_is_in_another_crate() { 526 fn adds_pub_when_target_is_in_another_crate() {
526 check_assist( 527 check_assist(
527 fix_visibility, 528 fix_visibility,
528 r"//- /main.rs crate:a deps:foo 529 r"
529 foo::Bar<|> 530//- /main.rs crate:a deps:foo
530 //- /lib.rs crate:foo 531foo::Bar<|>
531 struct Bar;", 532//- /lib.rs crate:foo
533struct Bar;
534",
532 r"$0pub struct Bar; 535 r"$0pub struct Bar;
533", 536",
534 ) 537 )
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs
index 31d6539f7..88b62278f 100644
--- a/crates/ra_assists/src/handlers/introduce_variable.rs
+++ b/crates/ra_assists/src/handlers/introduce_variable.rs
@@ -226,27 +226,31 @@ fn foo() {
226 mark::check!(test_introduce_var_last_expr); 226 mark::check!(test_introduce_var_last_expr);
227 check_assist( 227 check_assist(
228 introduce_variable, 228 introduce_variable,
229 " 229 r#"
230fn foo() { 230fn foo() {
231 bar(<|>1 + 1<|>) 231 bar(<|>1 + 1<|>)
232}", 232}
233 " 233"#,
234 r#"
234fn foo() { 235fn foo() {
235 let $0var_name = 1 + 1; 236 let $0var_name = 1 + 1;
236 bar(var_name) 237 bar(var_name)
237}", 238}
239"#,
238 ); 240 );
239 check_assist( 241 check_assist(
240 introduce_variable, 242 introduce_variable,
241 " 243 r#"
242fn foo() { 244fn foo() {
243 <|>bar(1 + 1)<|> 245 <|>bar(1 + 1)<|>
244}", 246}
245 " 247"#,
248 r#"
246fn foo() { 249fn foo() {
247 let $0var_name = bar(1 + 1); 250 let $0var_name = bar(1 + 1);
248 var_name 251 var_name
249}", 252}
253"#,
250 ) 254 )
251 } 255 }
252 256
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs
index 972d16241..ac0b3035c 100644
--- a/crates/ra_assists/src/handlers/merge_imports.rs
+++ b/crates/ra_assists/src/handlers/merge_imports.rs
@@ -127,7 +127,7 @@ fn first_path(path: &ast::Path) -> ast::Path {
127 127
128#[cfg(test)] 128#[cfg(test)]
129mod tests { 129mod tests {
130 use crate::tests::check_assist; 130 use crate::tests::{check_assist, check_assist_not_applicable};
131 131
132 use super::*; 132 use super::*;
133 133
@@ -276,4 +276,14 @@ bar::baz};
276", 276",
277 ) 277 )
278 } 278 }
279
280 #[test]
281 fn test_empty_use() {
282 check_assist_not_applicable(
283 merge_imports,
284 r"
285use std::<|>
286fn main() {}",
287 );
288 }
279} 289}
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs
index 16002d2ac..d22d0aa55 100644
--- a/crates/ra_assists/src/handlers/raw_string.rs
+++ b/crates/ra_assists/src/handlers/raw_string.rs
@@ -158,16 +158,16 @@ mod test {
158 check_assist( 158 check_assist(
159 make_raw_string, 159 make_raw_string,
160 r#" 160 r#"
161 fn f() { 161fn f() {
162 let s = <|>"random\nstring"; 162 let s = <|>"random\nstring";
163 } 163}
164 "#, 164"#,
165 r##" 165 r##"
166 fn f() { 166fn f() {
167 let s = r#"random 167 let s = r#"random
168string"#; 168string"#;
169 } 169}
170 "##, 170"##,
171 ) 171 )
172 } 172 }
173 173
@@ -193,16 +193,16 @@ string"#;
193 check_assist( 193 check_assist(
194 make_raw_string, 194 make_raw_string,
195 r###" 195 r###"
196 fn f() { 196fn f() {
197 let s = <|>"#random##\nstring"; 197 let s = <|>"#random##\nstring";
198 } 198}
199 "###, 199"###,
200 r####" 200 r####"
201 fn f() { 201fn f() {
202 let s = r#"#random## 202 let s = r#"#random##
203string"#; 203string"#;
204 } 204}
205 "####, 205"####,
206 ) 206 )
207 } 207 }
208 208
@@ -211,16 +211,16 @@ string"#;
211 check_assist( 211 check_assist(
212 make_raw_string, 212 make_raw_string,
213 r###" 213 r###"
214 fn f() { 214fn f() {
215 let s = <|>"#random\"##\nstring"; 215 let s = <|>"#random\"##\nstring";
216 } 216}
217 "###, 217"###,
218 r####" 218 r####"
219 fn f() { 219fn f() {
220 let s = r###"#random"## 220 let s = r###"#random"##
221string"###; 221string"###;
222 } 222}
223 "####, 223"####,
224 ) 224 )
225 } 225 }
226 226
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs
index c7a874480..38aa199a0 100644
--- a/crates/ra_assists/src/handlers/split_import.rs
+++ b/crates/ra_assists/src/handlers/split_import.rs
@@ -66,4 +66,14 @@ mod tests {
66 fn issue4044() { 66 fn issue4044() {
67 check_assist_not_applicable(split_import, "use crate::<|>:::self;") 67 check_assist_not_applicable(split_import, "use crate::<|>:::self;")
68 } 68 }
69
70 #[test]
71 fn test_empty_use() {
72 check_assist_not_applicable(
73 split_import,
74 r"
75use std::<|>
76fn main() {}",
77 );
78 }
69} 79}
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs
index 62dd3547f..858f5ca80 100644
--- a/crates/ra_assists/src/tests.rs
+++ b/crates/ra_assists/src/tests.rs
@@ -1,27 +1,21 @@
1mod generated; 1mod generated;
2 2
3use std::sync::Arc;
4
5use hir::Semantics; 3use hir::Semantics;
6use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; 4use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
7use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; 5use ra_ide_db::RootDatabase;
8use ra_syntax::TextRange; 6use ra_syntax::TextRange;
9use test_utils::{ 7use test_utils::{assert_eq_text, extract_offset, extract_range};
10 assert_eq_text, extract_offset, extract_range, extract_range_or_offset, RangeOrOffset,
11};
12 8
13use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; 9use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists};
10use stdx::trim_indent;
14 11
15pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { 12pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
16 let (mut db, file_id) = RootDatabase::with_single_file(text); 13 RootDatabase::with_single_file(text)
17 // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`,
18 // but it looks like this might need specialization? :(
19 db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)]));
20 (db, file_id)
21} 14}
22 15
23pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { 16pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) {
24 check(assist, ra_fixture_before, ExpectedResult::After(ra_fixture_after)); 17 let ra_fixture_after = trim_indent(ra_fixture_after);
18 check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after));
25} 19}
26 20
27// FIXME: instead of having a separate function here, maybe use 21// FIXME: instead of having a separate function here, maybe use
@@ -36,8 +30,9 @@ pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) {
36} 30}
37 31
38fn check_doc_test(assist_id: &str, before: &str, after: &str) { 32fn check_doc_test(assist_id: &str, before: &str, after: &str) {
39 let (selection, before) = extract_range_or_offset(before); 33 let after = trim_indent(after);
40 let (db, file_id) = crate::tests::with_single_file(&before); 34 let (db, file_id, selection) = RootDatabase::with_range_or_offset(&before);
35 let before = db.file_text(file_id).to_string();
41 let frange = FileRange { file_id, range: selection.into() }; 36 let frange = FileRange { file_id, range: selection.into() };
42 37
43 let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange) 38 let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange)
@@ -57,11 +52,11 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
57 52
58 let actual = { 53 let actual = {
59 let change = assist.source_change.source_file_edits.pop().unwrap(); 54 let change = assist.source_change.source_file_edits.pop().unwrap();
60 let mut actual = before.clone(); 55 let mut actual = before;
61 change.edit.apply(&mut actual); 56 change.edit.apply(&mut actual);
62 actual 57 actual
63 }; 58 };
64 assert_eq_text!(after, &actual); 59 assert_eq_text!(&after, &actual);
65} 60}
66 61
67enum ExpectedResult<'a> { 62enum ExpectedResult<'a> {
@@ -71,20 +66,8 @@ enum ExpectedResult<'a> {
71} 66}
72 67
73fn check(handler: Handler, before: &str, expected: ExpectedResult) { 68fn check(handler: Handler, before: &str, expected: ExpectedResult) {
74 let (text_without_caret, file_with_caret_id, range_or_offset, db) = if before.contains("//-") { 69 let (db, file_with_caret_id, range_or_offset) = RootDatabase::with_range_or_offset(before);
75 let (mut db, position) = RootDatabase::with_position(before); 70 let text_without_caret = db.file_text(file_with_caret_id).to_string();
76 db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)]));
77 (
78 db.file_text(position.file_id).as_ref().to_owned(),
79 position.file_id,
80 RangeOrOffset::Offset(position.offset),
81 db,
82 )
83 } else {
84 let (range_or_offset, text_without_caret) = extract_range_or_offset(before);
85 let (db, file_id) = with_single_file(&text_without_caret);
86 (text_without_caret, file_id, range_or_offset, db)
87 };
88 71
89 let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; 72 let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
90 73
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index c1ff0de7b..b7c45a619 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -198,8 +198,7 @@ pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>,
198#[allow(non_snake_case)] 198#[allow(non_snake_case)]
199impl FamousDefs<'_, '_> { 199impl FamousDefs<'_, '_> {
200 #[cfg(test)] 200 #[cfg(test)]
201 pub(crate) const FIXTURE: &'static str = r#" 201 pub(crate) const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
202//- /libcore.rs crate:core
203pub mod convert { 202pub mod convert {
204 pub trait From<T> { 203 pub trait From<T> {
205 fn from(T) -> Self; 204 fn from(T) -> Self;
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index 8ab409158..372fb242b 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -17,3 +17,5 @@ ra_cfg = { path = "../ra_cfg" }
17ra_prof = { path = "../ra_prof" } 17ra_prof = { path = "../ra_prof" }
18ra_tt = { path = "../ra_tt" } 18ra_tt = { path = "../ra_tt" }
19test_utils = { path = "../test_utils" } 19test_utils = { path = "../test_utils" }
20vfs = { path = "../vfs" }
21stdx = { path = "../stdx" }
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs
index 482a2f3e6..4f4fb4494 100644
--- a/crates/ra_db/src/fixture.rs
+++ b/crates/ra_db/src/fixture.rs
@@ -57,17 +57,16 @@
57//! fn insert_source_code_here() {} 57//! fn insert_source_code_here() {}
58//! " 58//! "
59//! ``` 59//! ```
60 60use std::{str::FromStr, sync::Arc};
61use std::str::FromStr;
62use std::sync::Arc;
63 61
64use ra_cfg::CfgOptions; 62use ra_cfg::CfgOptions;
65use rustc_hash::FxHashMap; 63use rustc_hash::FxHashMap;
66use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER}; 64use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER};
65use vfs::{file_set::FileSet, VfsPath};
67 66
68use crate::{ 67use crate::{
69 input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, 68 input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, SourceDatabaseExt,
70 SourceDatabaseExt, SourceRoot, SourceRootId, 69 SourceRoot, SourceRootId,
71}; 70};
72 71
73pub const WORKSPACE: SourceRootId = SourceRootId(0); 72pub const WORKSPACE: SourceRootId = SourceRootId(0);
@@ -75,21 +74,32 @@ pub const WORKSPACE: SourceRootId = SourceRootId(0);
75pub trait WithFixture: Default + SourceDatabaseExt + 'static { 74pub trait WithFixture: Default + SourceDatabaseExt + 'static {
76 fn with_single_file(text: &str) -> (Self, FileId) { 75 fn with_single_file(text: &str) -> (Self, FileId) {
77 let mut db = Self::default(); 76 let mut db = Self::default();
78 let file_id = with_single_file(&mut db, text); 77 let (_, files) = with_files(&mut db, text);
79 (db, file_id) 78 assert_eq!(files.len(), 1);
79 (db, files[0])
80 } 80 }
81 81
82 fn with_files(ra_fixture: &str) -> Self { 82 fn with_files(ra_fixture: &str) -> Self {
83 let mut db = Self::default(); 83 let mut db = Self::default();
84 let pos = with_files(&mut db, ra_fixture); 84 let (pos, _) = with_files(&mut db, ra_fixture);
85 assert!(pos.is_none()); 85 assert!(pos.is_none());
86 db 86 db
87 } 87 }
88 88
89 fn with_position(ra_fixture: &str) -> (Self, FilePosition) { 89 fn with_position(ra_fixture: &str) -> (Self, FilePosition) {
90 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
91 let offset = match range_or_offset {
92 RangeOrOffset::Range(_) => panic!(),
93 RangeOrOffset::Offset(it) => it,
94 };
95 (db, FilePosition { file_id, offset })
96 }
97
98 fn with_range_or_offset(ra_fixture: &str) -> (Self, FileId, RangeOrOffset) {
90 let mut db = Self::default(); 99 let mut db = Self::default();
91 let pos = with_files(&mut db, ra_fixture); 100 let (pos, _) = with_files(&mut db, ra_fixture);
92 (db, pos.unwrap()) 101 let (file_id, range_or_offset) = pos.unwrap();
102 (db, file_id, range_or_offset)
93 } 103 }
94 104
95 fn test_crate(&self) -> CrateId { 105 fn test_crate(&self) -> CrateId {
@@ -103,83 +113,36 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
103 113
104impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} 114impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {}
105 115
106fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId { 116fn with_files(
107 let file_id = FileId(0); 117 db: &mut dyn SourceDatabaseExt,
108 let rel_path: RelativePathBuf = "/main.rs".into(); 118 fixture: &str,
109 119) -> (Option<(FileId, RangeOrOffset)>, Vec<FileId>) {
110 let mut source_root = SourceRoot::new_local(); 120 let fixture = Fixture::parse(fixture);
111 source_root.insert_file(rel_path.clone(), file_id);
112
113 let fixture = parse_single_fixture(ra_fixture);
114
115 let crate_graph = if let Some(entry) = fixture {
116 let meta = match ParsedMeta::from(&entry.meta) {
117 ParsedMeta::File(it) => it,
118 _ => panic!("with_single_file only support file meta"),
119 };
120
121 let mut crate_graph = CrateGraph::default();
122 crate_graph.add_crate_root(
123 file_id,
124 meta.edition,
125 meta.krate.map(|name| {
126 CrateName::new(&name).expect("Fixture crate name should not contain dashes")
127 }),
128 meta.cfg,
129 meta.env,
130 Default::default(),
131 Default::default(),
132 );
133 crate_graph
134 } else {
135 let mut crate_graph = CrateGraph::default();
136 crate_graph.add_crate_root(
137 file_id,
138 Edition::Edition2018,
139 None,
140 CfgOptions::default(),
141 Env::default(),
142 Default::default(),
143 Default::default(),
144 );
145 crate_graph
146 };
147
148 db.set_file_text(file_id, Arc::new(ra_fixture.to_string()));
149 db.set_file_relative_path(file_id, rel_path);
150 db.set_file_source_root(file_id, WORKSPACE);
151 db.set_source_root(WORKSPACE, Arc::new(source_root));
152 db.set_crate_graph(Arc::new(crate_graph));
153
154 file_id
155}
156
157fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosition> {
158 let fixture = parse_fixture(fixture);
159 121
122 let mut files = Vec::new();
160 let mut crate_graph = CrateGraph::default(); 123 let mut crate_graph = CrateGraph::default();
161 let mut crates = FxHashMap::default(); 124 let mut crates = FxHashMap::default();
162 let mut crate_deps = Vec::new(); 125 let mut crate_deps = Vec::new();
163 let mut default_crate_root: Option<FileId> = None; 126 let mut default_crate_root: Option<FileId> = None;
164 127
165 let mut source_root = SourceRoot::new_local(); 128 let mut file_set = FileSet::default();
166 let mut source_root_id = WORKSPACE; 129 let source_root_id = WORKSPACE;
167 let mut source_root_prefix: RelativePathBuf = "/".into(); 130 let source_root_prefix = "/".to_string();
168 let mut file_id = FileId(0); 131 let mut file_id = FileId(0);
169 132
170 let mut file_position = None; 133 let mut file_position = None;
171 134
172 for entry in fixture.iter() { 135 for entry in fixture {
173 let meta = match ParsedMeta::from(&entry.meta) { 136 let text = if entry.text.contains(CURSOR_MARKER) {
174 ParsedMeta::Root { path } => { 137 let (range_or_offset, text) = extract_range_or_offset(&entry.text);
175 let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); 138 assert!(file_position.is_none());
176 db.set_source_root(source_root_id, Arc::new(source_root)); 139 file_position = Some((file_id, range_or_offset));
177 source_root_id.0 += 1; 140 text.to_string()
178 source_root_prefix = path; 141 } else {
179 continue; 142 entry.text.clone()
180 }
181 ParsedMeta::File(it) => it,
182 }; 143 };
144
145 let meta = FileMeta::from(entry);
183 assert!(meta.path.starts_with(&source_root_prefix)); 146 assert!(meta.path.starts_with(&source_root_prefix));
184 147
185 if let Some(krate) = meta.krate { 148 if let Some(krate) = meta.krate {
@@ -190,7 +153,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
190 meta.cfg, 153 meta.cfg,
191 meta.env, 154 meta.env,
192 Default::default(), 155 Default::default(),
193 Default::default(),
194 ); 156 );
195 let prev = crates.insert(krate.clone(), crate_id); 157 let prev = crates.insert(krate.clone(), crate_id);
196 assert!(prev.is_none()); 158 assert!(prev.is_none());
@@ -202,20 +164,11 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
202 default_crate_root = Some(file_id); 164 default_crate_root = Some(file_id);
203 } 165 }
204 166
205 let text = if entry.text.contains(CURSOR_MARKER) {
206 let (offset, text) = extract_offset(&entry.text);
207 assert!(file_position.is_none());
208 file_position = Some(FilePosition { file_id, offset });
209 text.to_string()
210 } else {
211 entry.text.to_string()
212 };
213
214 db.set_file_text(file_id, Arc::new(text)); 167 db.set_file_text(file_id, Arc::new(text));
215 db.set_file_relative_path(file_id, meta.path.clone());
216 db.set_file_source_root(file_id, source_root_id); 168 db.set_file_source_root(file_id, source_root_id);
217 source_root.insert_file(meta.path, file_id); 169 let path = VfsPath::new_virtual_path(meta.path);
218 170 file_set.insert(file_id, path.into());
171 files.push(file_id);
219 file_id.0 += 1; 172 file_id.0 += 1;
220 } 173 }
221 174
@@ -228,7 +181,6 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
228 CfgOptions::default(), 181 CfgOptions::default(),
229 Env::default(), 182 Env::default(),
230 Default::default(), 183 Default::default(),
231 Default::default(),
232 ); 184 );
233 } else { 185 } else {
234 for (from, to) in crate_deps { 186 for (from, to) in crate_deps {
@@ -238,19 +190,14 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit
238 } 190 }
239 } 191 }
240 192
241 db.set_source_root(source_root_id, Arc::new(source_root)); 193 db.set_source_root(source_root_id, Arc::new(SourceRoot::new_local(file_set)));
242 db.set_crate_graph(Arc::new(crate_graph)); 194 db.set_crate_graph(Arc::new(crate_graph));
243 195
244 file_position 196 (file_position, files)
245}
246
247enum ParsedMeta {
248 Root { path: RelativePathBuf },
249 File(FileMeta),
250} 197}
251 198
252struct FileMeta { 199struct FileMeta {
253 path: RelativePathBuf, 200 path: String,
254 krate: Option<String>, 201 krate: Option<String>,
255 deps: Vec<String>, 202 deps: Vec<String>,
256 cfg: CfgOptions, 203 cfg: CfgOptions,
@@ -258,25 +205,22 @@ struct FileMeta {
258 env: Env, 205 env: Env,
259} 206}
260 207
261impl From<&FixtureMeta> for ParsedMeta { 208impl From<Fixture> for FileMeta {
262 fn from(meta: &FixtureMeta) -> Self { 209 fn from(f: Fixture) -> FileMeta {
263 match meta { 210 let mut cfg = CfgOptions::default();
264 FixtureMeta::Root { path } => { 211 f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into()));
265 // `Self::Root` causes a false warning: 'variant is never constructed: `Root` ' 212 f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into()));
266 // see https://github.com/rust-lang/rust/issues/69018 213
267 ParsedMeta::Root { path: path.to_owned() } 214 FileMeta {
268 } 215 path: f.path,
269 FixtureMeta::File(f) => Self::File(FileMeta { 216 krate: f.krate,
270 path: f.path.to_owned(), 217 deps: f.deps,
271 krate: f.crate_name.to_owned(), 218 cfg,
272 deps: f.deps.to_owned(), 219 edition: f
273 cfg: f.cfg.to_owned(), 220 .edition
274 edition: f 221 .as_ref()
275 .edition 222 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()),
276 .as_ref() 223 env: Env::from(f.env.iter()),
277 .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()),
278 env: Env::from(f.env.iter()),
279 }),
280 } 224 }
281 } 225 }
282} 226}
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index bf26048f2..7f3660118 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -6,27 +6,15 @@
6//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how 6//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
7//! actual IO is done and lowered to input. 7//! actual IO is done and lowered to input.
8 8
9use std::{ 9use std::{fmt, ops, str::FromStr, sync::Arc};
10 fmt, ops,
11 path::{Path, PathBuf},
12 str::FromStr,
13 sync::Arc,
14};
15 10
16use ra_cfg::CfgOptions; 11use ra_cfg::CfgOptions;
17use ra_syntax::SmolStr; 12use ra_syntax::SmolStr;
18use ra_tt::TokenExpander; 13use ra_tt::TokenExpander;
19use rustc_hash::{FxHashMap, FxHashSet}; 14use rustc_hash::{FxHashMap, FxHashSet};
15use vfs::file_set::FileSet;
20 16
21use crate::{RelativePath, RelativePathBuf}; 17pub use vfs::FileId;
22
23/// `FileId` is an integer which uniquely identifies a file. File paths are
24/// messy and system-dependent, so most of the code should work directly with
25/// `FileId`, without inspecting the path. The mapping between `FileId` and path
26/// and `SourceRoot` is constant. A file rename is represented as a pair of
27/// deletion/creation.
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct FileId(pub u32);
30 18
31/// Files are grouped into source roots. A source root is a directory on the 19/// Files are grouped into source roots. A source root is a directory on the
32/// file systems which is watched for changes. Typically it corresponds to a 20/// file systems which is watched for changes. Typically it corresponds to a
@@ -45,27 +33,18 @@ pub struct SourceRoot {
45 /// Libraries are considered mostly immutable, this assumption is used to 33 /// Libraries are considered mostly immutable, this assumption is used to
46 /// optimize salsa's query structure 34 /// optimize salsa's query structure
47 pub is_library: bool, 35 pub is_library: bool,
48 files: FxHashMap<RelativePathBuf, FileId>, 36 pub(crate) file_set: FileSet,
49} 37}
50 38
51impl SourceRoot { 39impl SourceRoot {
52 pub fn new_local() -> SourceRoot { 40 pub fn new_local(file_set: FileSet) -> SourceRoot {
53 SourceRoot { is_library: false, files: Default::default() } 41 SourceRoot { is_library: false, file_set }
54 }
55 pub fn new_library() -> SourceRoot {
56 SourceRoot { is_library: true, files: Default::default() }
57 }
58 pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
59 self.files.insert(path, file_id);
60 } 42 }
61 pub fn remove_file(&mut self, path: &RelativePath) { 43 pub fn new_library(file_set: FileSet) -> SourceRoot {
62 self.files.remove(path); 44 SourceRoot { is_library: true, file_set }
63 } 45 }
64 pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ { 46 pub fn iter(&self) -> impl Iterator<Item = FileId> + '_ {
65 self.files.values().copied() 47 self.file_set.iter()
66 }
67 pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
68 self.files.get(path).copied()
69 } 48 }
70} 49}
71 50
@@ -141,7 +120,6 @@ pub struct CrateData {
141 pub display_name: Option<CrateName>, 120 pub display_name: Option<CrateName>,
142 pub cfg_options: CfgOptions, 121 pub cfg_options: CfgOptions,
143 pub env: Env, 122 pub env: Env,
144 pub extern_source: ExternSource,
145 pub dependencies: Vec<Dependency>, 123 pub dependencies: Vec<Dependency>,
146 pub proc_macro: Vec<ProcMacro>, 124 pub proc_macro: Vec<ProcMacro>,
147} 125}
@@ -152,22 +130,11 @@ pub enum Edition {
152 Edition2015, 130 Edition2015,
153} 131}
154 132
155#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
156pub struct ExternSourceId(pub u32);
157
158#[derive(Default, Debug, Clone, PartialEq, Eq)] 133#[derive(Default, Debug, Clone, PartialEq, Eq)]
159pub struct Env { 134pub struct Env {
160 entries: FxHashMap<String, String>, 135 entries: FxHashMap<String, String>,
161} 136}
162 137
163// FIXME: Redesign vfs for solve the following limitation ?
164// Note: Some env variables (e.g. OUT_DIR) are located outside of the
165// crate. We store a map to allow remap it to ExternSourceId
166#[derive(Default, Debug, Clone, PartialEq, Eq)]
167pub struct ExternSource {
168 extern_paths: FxHashMap<PathBuf, ExternSourceId>,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq)] 138#[derive(Debug, Clone, PartialEq, Eq)]
172pub struct Dependency { 139pub struct Dependency {
173 pub crate_id: CrateId, 140 pub crate_id: CrateId,
@@ -182,7 +149,6 @@ impl CrateGraph {
182 display_name: Option<CrateName>, 149 display_name: Option<CrateName>,
183 cfg_options: CfgOptions, 150 cfg_options: CfgOptions,
184 env: Env, 151 env: Env,
185 extern_source: ExternSource,
186 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>, 152 proc_macro: Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)>,
187 ) -> CrateId { 153 ) -> CrateId {
188 let proc_macro = 154 let proc_macro =
@@ -194,7 +160,6 @@ impl CrateGraph {
194 display_name, 160 display_name,
195 cfg_options, 161 cfg_options,
196 env, 162 env,
197 extern_source,
198 proc_macro, 163 proc_macro,
199 dependencies: Vec::new(), 164 dependencies: Vec::new(),
200 }; 165 };
@@ -254,12 +219,12 @@ impl CrateGraph {
254 return false; 219 return false;
255 } 220 }
256 221
222 if target == from {
223 return true;
224 }
225
257 for dep in &self[from].dependencies { 226 for dep in &self[from].dependencies {
258 let crate_id = dep.crate_id; 227 let crate_id = dep.crate_id;
259 if crate_id == target {
260 return true;
261 }
262
263 if self.dfs_find(target, crate_id, visited) { 228 if self.dfs_find(target, crate_id, visited) {
264 return true; 229 return true;
265 } 230 }
@@ -334,20 +299,6 @@ impl Env {
334 } 299 }
335} 300}
336 301
337impl ExternSource {
338 pub fn extern_path(&self, path: &Path) -> Option<(ExternSourceId, RelativePathBuf)> {
339 self.extern_paths.iter().find_map(|(root_path, id)| {
340 let rel_path = path.strip_prefix(root_path).ok()?;
341 let rel_path = RelativePathBuf::from_path(rel_path).ok()?;
342 Some((*id, rel_path))
343 })
344 }
345
346 pub fn set_extern_path(&mut self, root_path: &Path, root: ExternSourceId) {
347 self.extern_paths.insert(root_path.to_path_buf(), root);
348 }
349}
350
351#[derive(Debug)] 302#[derive(Debug)]
352pub struct ParseEditionError { 303pub struct ParseEditionError {
353 invalid_input: String, 304 invalid_input: String,
@@ -369,7 +320,7 @@ mod tests {
369 use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId}; 320 use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId};
370 321
371 #[test] 322 #[test]
372 fn it_should_panic_because_of_cycle_dependencies() { 323 fn detect_cyclic_dependency_indirect() {
373 let mut graph = CrateGraph::default(); 324 let mut graph = CrateGraph::default();
374 let crate1 = graph.add_crate_root( 325 let crate1 = graph.add_crate_root(
375 FileId(1u32), 326 FileId(1u32),
@@ -378,7 +329,6 @@ mod tests {
378 CfgOptions::default(), 329 CfgOptions::default(),
379 Env::default(), 330 Env::default(),
380 Default::default(), 331 Default::default(),
381 Default::default(),
382 ); 332 );
383 let crate2 = graph.add_crate_root( 333 let crate2 = graph.add_crate_root(
384 FileId(2u32), 334 FileId(2u32),
@@ -387,7 +337,6 @@ mod tests {
387 CfgOptions::default(), 337 CfgOptions::default(),
388 Env::default(), 338 Env::default(),
389 Default::default(), 339 Default::default(),
390 Default::default(),
391 ); 340 );
392 let crate3 = graph.add_crate_root( 341 let crate3 = graph.add_crate_root(
393 FileId(3u32), 342 FileId(3u32),
@@ -396,7 +345,6 @@ mod tests {
396 CfgOptions::default(), 345 CfgOptions::default(),
397 Env::default(), 346 Env::default(),
398 Default::default(), 347 Default::default(),
399 Default::default(),
400 ); 348 );
401 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); 349 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
402 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); 350 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
@@ -404,7 +352,7 @@ mod tests {
404 } 352 }
405 353
406 #[test] 354 #[test]
407 fn it_works() { 355 fn detect_cyclic_dependency_direct() {
408 let mut graph = CrateGraph::default(); 356 let mut graph = CrateGraph::default();
409 let crate1 = graph.add_crate_root( 357 let crate1 = graph.add_crate_root(
410 FileId(1u32), 358 FileId(1u32),
@@ -413,7 +361,6 @@ mod tests {
413 CfgOptions::default(), 361 CfgOptions::default(),
414 Env::default(), 362 Env::default(),
415 Default::default(), 363 Default::default(),
416 Default::default(),
417 ); 364 );
418 let crate2 = graph.add_crate_root( 365 let crate2 = graph.add_crate_root(
419 FileId(2u32), 366 FileId(2u32),
@@ -422,6 +369,28 @@ mod tests {
422 CfgOptions::default(), 369 CfgOptions::default(),
423 Env::default(), 370 Env::default(),
424 Default::default(), 371 Default::default(),
372 );
373 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
374 assert!(graph.add_dep(crate2, CrateName::new("crate2").unwrap(), crate2).is_err());
375 }
376
377 #[test]
378 fn it_works() {
379 let mut graph = CrateGraph::default();
380 let crate1 = graph.add_crate_root(
381 FileId(1u32),
382 Edition2018,
383 None,
384 CfgOptions::default(),
385 Env::default(),
386 Default::default(),
387 );
388 let crate2 = graph.add_crate_root(
389 FileId(2u32),
390 Edition2018,
391 None,
392 CfgOptions::default(),
393 Env::default(),
425 Default::default(), 394 Default::default(),
426 ); 395 );
427 let crate3 = graph.add_crate_root( 396 let crate3 = graph.add_crate_root(
@@ -431,7 +400,6 @@ mod tests {
431 CfgOptions::default(), 400 CfgOptions::default(),
432 Env::default(), 401 Env::default(),
433 Default::default(), 402 Default::default(),
434 Default::default(),
435 ); 403 );
436 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok()); 404 assert!(graph.add_dep(crate1, CrateName::new("crate2").unwrap(), crate2).is_ok());
437 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok()); 405 assert!(graph.add_dep(crate2, CrateName::new("crate3").unwrap(), crate3).is_ok());
@@ -447,7 +415,6 @@ mod tests {
447 CfgOptions::default(), 415 CfgOptions::default(),
448 Env::default(), 416 Env::default(),
449 Default::default(), 417 Default::default(),
450 Default::default(),
451 ); 418 );
452 let crate2 = graph.add_crate_root( 419 let crate2 = graph.add_crate_root(
453 FileId(2u32), 420 FileId(2u32),
@@ -456,7 +423,6 @@ mod tests {
456 CfgOptions::default(), 423 CfgOptions::default(),
457 Env::default(), 424 Env::default(),
458 Default::default(), 425 Default::default(),
459 Default::default(),
460 ); 426 );
461 assert!(graph 427 assert!(graph
462 .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2) 428 .add_dep(crate1, CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index 80ddb6058..4a3ba57da 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -12,12 +12,13 @@ use rustc_hash::FxHashSet;
12pub use crate::{ 12pub use crate::{
13 cancellation::Canceled, 13 cancellation::Canceled,
14 input::{ 14 input::{
15 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, ExternSource, 15 CrateData, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacroId,
16 ExternSourceId, FileId, ProcMacroId, SourceRoot, SourceRootId, 16 SourceRoot, SourceRootId,
17 }, 17 },
18}; 18};
19pub use relative_path::{RelativePath, RelativePathBuf}; 19pub use relative_path::{RelativePath, RelativePathBuf};
20pub use salsa; 20pub use salsa;
21pub use vfs::{file_set::FileSet, AbsPathBuf, VfsPath};
21 22
22#[macro_export] 23#[macro_export]
23macro_rules! impl_intern_key { 24macro_rules! impl_intern_key {
@@ -113,7 +114,7 @@ pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
113} 114}
114 115
115fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { 116fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
116 let _p = profile("parse_query"); 117 let _p = profile("parse_query").detail(|| format!("{:?}", file_id));
117 let text = db.file_text(file_id); 118 let text = db.file_text(file_id);
118 SourceFile::parse(&*text) 119 SourceFile::parse(&*text)
119} 120}
@@ -125,8 +126,6 @@ pub trait SourceDatabaseExt: SourceDatabase {
125 #[salsa::input] 126 #[salsa::input]
126 fn file_text(&self, file_id: FileId) -> Arc<String>; 127 fn file_text(&self, file_id: FileId) -> Arc<String>;
127 /// Path to a file, relative to the root of its source root. 128 /// Path to a file, relative to the root of its source root.
128 #[salsa::input]
129 fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
130 /// Source root of the file. 129 /// Source root of the file.
131 #[salsa::input] 130 #[salsa::input]
132 fn file_source_root(&self, file_id: FileId) -> SourceRootId; 131 fn file_source_root(&self, file_id: FileId) -> SourceRootId;
@@ -161,24 +160,9 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
161 } 160 }
162 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { 161 fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
163 // FIXME: this *somehow* should be platform agnostic... 162 // FIXME: this *somehow* should be platform agnostic...
164 if std::path::Path::new(path).is_absolute() { 163 let source_root = self.0.file_source_root(anchor);
165 let krate = *self.relevant_crates(anchor).iter().next()?; 164 let source_root = self.0.source_root(source_root);
166 let (extern_source_id, relative_file) = 165 source_root.file_set.resolve_path(anchor, path)
167 self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?;
168
169 let source_root = self.0.source_root(SourceRootId(extern_source_id.0));
170 source_root.file_by_relative_path(&relative_file)
171 } else {
172 let rel_path = {
173 let mut rel_path = self.0.file_relative_path(anchor);
174 assert!(rel_path.pop());
175 rel_path.push(path);
176 rel_path.normalize()
177 };
178 let source_root = self.0.file_source_root(anchor);
179 let source_root = self.0.source_root(source_root);
180 source_root.file_by_relative_path(&rel_path)
181 }
182 } 166 }
183 167
184 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { 168 fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 1a9f6cc76..a379b9f49 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -26,15 +26,12 @@ use hir_ty::{
26 autoderef, 26 autoderef,
27 display::{HirDisplayError, HirFormatter}, 27 display::{HirDisplayError, HirFormatter},
28 expr::ExprValidator, 28 expr::ExprValidator,
29 method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, Ty, 29 method_resolution, ApplicationTy, Canonical, GenericPredicate, InEnvironment, Substs,
30 TyDefId, TypeCtor, 30 TraitEnvironment, Ty, TyDefId, TypeCtor,
31}; 31};
32use ra_db::{CrateId, CrateName, Edition, FileId}; 32use ra_db::{CrateId, CrateName, Edition, FileId};
33use ra_prof::profile; 33use ra_prof::profile;
34use ra_syntax::{ 34use ra_syntax::ast::{self, AttrsOwner, NameOwner};
35 ast::{self, AttrsOwner, NameOwner},
36 AstNode,
37};
38use rustc_hash::FxHashSet; 35use rustc_hash::FxHashSet;
39 36
40use crate::{ 37use crate::{
@@ -186,10 +183,27 @@ impl ModuleDef {
186 183
187 module.visibility_of(db, self) 184 module.visibility_of(db, self)
188 } 185 }
186
187 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
188 match self {
189 ModuleDef::Adt(it) => Some(it.name(db)),
190 ModuleDef::Trait(it) => Some(it.name(db)),
191 ModuleDef::Function(it) => Some(it.name(db)),
192 ModuleDef::EnumVariant(it) => Some(it.name(db)),
193 ModuleDef::TypeAlias(it) => Some(it.name(db)),
194
195 ModuleDef::Module(it) => it.name(db),
196 ModuleDef::Const(it) => it.name(db),
197 ModuleDef::Static(it) => it.name(db),
198
199 ModuleDef::BuiltinType(it) => Some(it.as_name()),
200 }
201 }
189} 202}
190 203
191pub use hir_def::{ 204pub use hir_def::{
192 attr::Attrs, item_scope::ItemInNs, visibility::Visibility, AssocItemId, AssocItemLoc, 205 attr::Attrs, item_scope::ItemInNs, item_tree::ItemTreeNode, visibility::Visibility,
206 AssocItemId, AssocItemLoc,
193}; 207};
194 208
195impl Module { 209impl Module {
@@ -856,7 +870,7 @@ where
856 ID: Lookup<Data = AssocItemLoc<AST>>, 870 ID: Lookup<Data = AssocItemLoc<AST>>,
857 DEF: From<ID>, 871 DEF: From<ID>,
858 CTOR: FnOnce(DEF) -> AssocItem, 872 CTOR: FnOnce(DEF) -> AssocItem,
859 AST: AstNode, 873 AST: ItemTreeNode,
860{ 874{
861 match id.lookup(db.upcast()).container { 875 match id.lookup(db.upcast()).container {
862 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))), 876 AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
@@ -1359,6 +1373,27 @@ impl Type {
1359 Some(adt.into()) 1373 Some(adt.into())
1360 } 1374 }
1361 1375
1376 pub fn as_dyn_trait(&self) -> Option<Trait> {
1377 self.ty.value.dyn_trait().map(Into::into)
1378 }
1379
1380 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
1381 self.ty.value.impl_trait_bounds(db).map(|it| {
1382 it.into_iter()
1383 .filter_map(|pred| match pred {
1384 hir_ty::GenericPredicate::Implemented(trait_ref) => {
1385 Some(Trait::from(trait_ref.trait_))
1386 }
1387 _ => None,
1388 })
1389 .collect()
1390 })
1391 }
1392
1393 pub fn as_associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<Trait> {
1394 self.ty.value.associated_type_parent_trait(db).map(Into::into)
1395 }
1396
1362 // FIXME: provide required accessors such that it becomes implementable from outside. 1397 // FIXME: provide required accessors such that it becomes implementable from outside.
1363 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { 1398 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1364 match (&self.ty.value, &other.ty.value) { 1399 match (&self.ty.value, &other.ty.value) {
@@ -1380,6 +1415,80 @@ impl Type {
1380 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() }, 1415 ty: InEnvironment { value: ty, environment: self.ty.environment.clone() },
1381 } 1416 }
1382 } 1417 }
1418
1419 pub fn walk(&self, db: &dyn HirDatabase, mut cb: impl FnMut(Type)) {
1420 // TypeWalk::walk for a Ty at first visits parameters and only after that the Ty itself.
1421 // We need a different order here.
1422
1423 fn walk_substs(
1424 db: &dyn HirDatabase,
1425 type_: &Type,
1426 substs: &Substs,
1427 cb: &mut impl FnMut(Type),
1428 ) {
1429 for ty in substs.iter() {
1430 walk_type(db, &type_.derived(ty.clone()), cb);
1431 }
1432 }
1433
1434 fn walk_bounds(
1435 db: &dyn HirDatabase,
1436 type_: &Type,
1437 bounds: &[GenericPredicate],
1438 cb: &mut impl FnMut(Type),
1439 ) {
1440 for pred in bounds {
1441 match pred {
1442 GenericPredicate::Implemented(trait_ref) => {
1443 cb(type_.clone());
1444 walk_substs(db, type_, &trait_ref.substs, cb);
1445 }
1446 _ => (),
1447 }
1448 }
1449 }
1450
1451 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
1452 let ty = type_.ty.value.strip_references();
1453 match ty {
1454 Ty::Apply(ApplicationTy { ctor, parameters }) => {
1455 match ctor {
1456 TypeCtor::Adt(_) => {
1457 cb(type_.derived(ty.clone()));
1458 }
1459 TypeCtor::AssociatedType(_) => {
1460 if let Some(_) = ty.associated_type_parent_trait(db) {
1461 cb(type_.derived(ty.clone()));
1462 }
1463 }
1464 _ => (),
1465 }
1466
1467 // adt params, tuples, etc...
1468 walk_substs(db, type_, parameters, cb);
1469 }
1470 Ty::Opaque(opaque_ty) => {
1471 if let Some(bounds) = ty.impl_trait_bounds(db) {
1472 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1473 }
1474
1475 walk_substs(db, type_, &opaque_ty.parameters, cb);
1476 }
1477 Ty::Placeholder(_) => {
1478 if let Some(bounds) = ty.impl_trait_bounds(db) {
1479 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
1480 }
1481 }
1482 Ty::Dyn(bounds) => {
1483 walk_bounds(db, &type_.derived(ty.clone()), bounds.as_ref(), cb);
1484 }
1485
1486 _ => (),
1487 }
1488 }
1489
1490 walk_type(db, self, &mut cb);
1491 }
1383} 1492}
1384 1493
1385impl HirDisplay for Type { 1494impl HirDisplay for Type {
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index b6b665de1..bb67952de 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -6,7 +6,7 @@ pub use hir_def::db::{
6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery, 6 ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery, ImportMapQuery,
7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery, 7 InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery, InternFunctionQuery,
8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery, 8 InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery, InternTypeAliasQuery,
9 InternUnionQuery, LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, 9 InternUnionQuery, ItemTreeQuery, LangItemQuery, ModuleLangItemsQuery, StaticDataQuery,
10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery, 10 StructDataQuery, TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11}; 11};
12pub use hir_expand::db::{ 12pub use hir_expand::db::{
@@ -16,7 +16,7 @@ pub use hir_expand::db::{
16pub use hir_ty::db::{ 16pub use hir_ty::db::{
17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery, 17 AssociatedTyDataQuery, AssociatedTyValueQuery, CallableItemSignatureQuery, FieldTypesQuery,
18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, 18 GenericDefaultsQuery, GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase,
19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsForTraitQuery, 19 HirDatabaseStorage, ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, ImplsFromDepsQuery,
20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery, 20 ImplsInCrateQuery, InferQueryQuery, InternAssocTyValueQuery, InternChalkImplQuery,
21 InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery, 21 InternTypeCtorQuery, InternTypeParamIdQuery, ReturnTypeImplTraitsQuery, StructDatumQuery,
22 TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery, 22 TraitDatumQuery, TraitSolveQuery, TyQuery, ValueTyQuery,
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs
index 63b8fd369..76c32fc17 100644
--- a/crates/ra_hir/src/has_source.rs
+++ b/crates/ra_hir/src/has_source.rs
@@ -2,7 +2,7 @@
2 2
3use either::Either; 3use either::Either;
4use hir_def::{ 4use hir_def::{
5 nameres::ModuleSource, 5 nameres::{ModuleOrigin, ModuleSource},
6 src::{HasChildSource, HasSource as _}, 6 src::{HasChildSource, HasSource as _},
7 Lookup, VariantId, 7 Lookup, VariantId,
8}; 8};
@@ -29,6 +29,14 @@ impl Module {
29 def_map[self.id.local_id].definition_source(db.upcast()) 29 def_map[self.id.local_id].definition_source(db.upcast())
30 } 30 }
31 31
32 pub fn is_mod_rs(self, db: &dyn HirDatabase) -> bool {
33 let def_map = db.crate_def_map(self.id.krate);
34 match def_map[self.id.local_id].origin {
35 ModuleOrigin::File { is_mod_rs, .. } => is_mod_rs,
36 _ => false,
37 }
38 }
39
32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 40 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
33 /// `None` for the crate root. 41 /// `None` for the crate root.
34 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> { 42 pub fn declaration_source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Module>> {
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs
index a232a5856..6a49c424a 100644
--- a/crates/ra_hir/src/semantics.rs
+++ b/crates/ra_hir/src/semantics.rs
@@ -6,9 +6,9 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use hir_def::{ 7use hir_def::{
8 resolver::{self, HasResolver, Resolver}, 8 resolver::{self, HasResolver, Resolver},
9 AsMacroCall, TraitId, 9 AsMacroCall, TraitId, VariantId,
10}; 10};
11use hir_expand::{hygiene::Hygiene, ExpansionInfo}; 11use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
12use hir_ty::associated_type_shorthand_candidates; 12use hir_ty::associated_type_shorthand_candidates;
13use itertools::Itertools; 13use itertools::Itertools;
14use ra_db::{FileId, FileRange}; 14use ra_db::{FileId, FileRange};
@@ -104,6 +104,13 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
104 tree 104 tree
105 } 105 }
106 106
107 pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST {
108 let file_id = d.source().file_id;
109 let root = self.db.parse_or_expand(file_id).unwrap();
110 self.cache(root, file_id);
111 d.ast(self.db)
112 }
113
107 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { 114 pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
108 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call); 115 let macro_call = self.find_file(macro_call.syntax().clone()).with_value(macro_call);
109 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); 116 let sa = self.analyze2(macro_call.map(|it| it.syntax()), None);
@@ -247,6 +254,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
247 self.analyze(path.syntax()).resolve_path(self.db, path) 254 self.analyze(path.syntax()).resolve_path(self.db, path)
248 } 255 }
249 256
257 pub fn resolve_variant(&self, record_lit: ast::RecordLit) -> Option<VariantId> {
258 self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
259 }
260
250 pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { 261 pub fn lower_path(&self, path: &ast::Path) -> Option<Path> {
251 let src = self.find_file(path.syntax().clone()); 262 let src = self.find_file(path.syntax().clone());
252 Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) 263 Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into()))
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 7c6bbea13..1d6c47103 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -216,13 +216,43 @@ impl SourceAnalyzer {
216 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { 216 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
217 return Some(PathResolution::AssocItem(assoc.into())); 217 return Some(PathResolution::AssocItem(assoc.into()));
218 } 218 }
219 if let Some(VariantId::EnumVariantId(variant)) =
220 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
221 {
222 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
223 }
219 } 224 }
225
220 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { 226 if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
221 let pat_id = self.pat_id(&path_pat.into())?; 227 let pat_id = self.pat_id(&path_pat.into())?;
222 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { 228 if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
223 return Some(PathResolution::AssocItem(assoc.into())); 229 return Some(PathResolution::AssocItem(assoc.into()));
224 } 230 }
231 if let Some(VariantId::EnumVariantId(variant)) =
232 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
233 {
234 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
235 }
236 }
237
238 if let Some(rec_lit) = path.syntax().parent().and_then(ast::RecordLit::cast) {
239 let expr_id = self.expr_id(db, &rec_lit.into())?;
240 if let Some(VariantId::EnumVariantId(variant)) =
241 self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
242 {
243 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
244 }
225 } 245 }
246
247 if let Some(rec_pat) = path.syntax().parent().and_then(ast::RecordPat::cast) {
248 let pat_id = self.pat_id(&rec_pat.into())?;
249 if let Some(VariantId::EnumVariantId(variant)) =
250 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
251 {
252 return Some(PathResolution::Def(ModuleDef::EnumVariant(variant.into())));
253 }
254 }
255
226 // This must be a normal source file rather than macro file. 256 // This must be a normal source file rather than macro file.
227 let hir_path = 257 let hir_path =
228 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; 258 crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?;
@@ -313,6 +343,16 @@ impl SourceAnalyzer {
313 })?; 343 })?;
314 Some(macro_call_id.as_file()) 344 Some(macro_call_id.as_file())
315 } 345 }
346
347 pub(crate) fn resolve_variant(
348 &self,
349 db: &dyn HirDatabase,
350 record_lit: ast::RecordLit,
351 ) -> Option<VariantId> {
352 let infer = self.infer.as_ref()?;
353 let expr_id = self.expr_id(db, &record_lit.into())?;
354 infer.variant_resolution_for_expr(expr_id)
355 }
316} 356}
317 357
318fn scope_for( 358fn scope_for(
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index ef1f65ee0..6d43924e3 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -17,6 +17,7 @@ drop_bomb = "0.1.4"
17fst = { version = "0.4", default-features = false } 17fst = { version = "0.4", default-features = false }
18itertools = "0.9.0" 18itertools = "0.9.0"
19indexmap = "1.4.0" 19indexmap = "1.4.0"
20smallvec = "1.4.0"
20 21
21stdx = { path = "../stdx" } 22stdx = { path = "../stdx" }
22 23
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 2eeba0572..197737ffc 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -13,7 +13,11 @@ use ra_syntax::{
13use tt::Subtree; 13use tt::Subtree;
14 14
15use crate::{ 15use crate::{
16 db::DefDatabase, nameres::ModuleSource, path::ModPath, src::HasChildSource, src::HasSource, 16 db::DefDatabase,
17 item_tree::{ItemTreeId, ItemTreeNode},
18 nameres::ModuleSource,
19 path::ModPath,
20 src::HasChildSource,
17 AdtId, AttrDefId, Lookup, 21 AdtId, AttrDefId, Lookup,
18}; 22};
19 23
@@ -34,6 +38,8 @@ impl ops::Deref for Attrs {
34} 38}
35 39
36impl Attrs { 40impl Attrs {
41 pub const EMPTY: Attrs = Attrs { entries: None };
42
37 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 43 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
38 match def { 44 match def {
39 AttrDefId::ModuleId(module) => { 45 AttrDefId::ModuleId(module) => {
@@ -65,19 +71,19 @@ impl Attrs {
65 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) 71 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
66 } 72 }
67 AttrDefId::AdtId(it) => match it { 73 AttrDefId::AdtId(it) => match it {
68 AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db), 74 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
69 AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db), 75 AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
70 AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db), 76 AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
71 }, 77 },
72 AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db), 78 AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
73 AttrDefId::MacroDefId(it) => { 79 AttrDefId::MacroDefId(it) => {
74 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)) 80 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
75 } 81 }
76 AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db), 82 AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
77 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), 83 AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
78 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), 84 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
79 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), 85 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
80 AttrDefId::TypeAliasId(it) => attrs_from_loc(it.lookup(db), db), 86 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
81 } 87 }
82 } 88 }
83 89
@@ -103,6 +109,18 @@ impl Attrs {
103 Attrs { entries } 109 Attrs { entries }
104 } 110 }
105 111
112 pub fn merge(&self, other: Attrs) -> Attrs {
113 match (&self.entries, &other.entries) {
114 (None, None) => Attrs { entries: None },
115 (Some(entries), None) | (None, Some(entries)) => {
116 Attrs { entries: Some(entries.clone()) }
117 }
118 (Some(a), Some(b)) => {
119 Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
120 }
121 }
122 }
123
106 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { 124 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
107 AttrQuery { attrs: self, key } 125 AttrQuery { attrs: self, key }
108 } 126 }
@@ -187,11 +205,8 @@ where
187 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 205 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
188} 206}
189 207
190fn attrs_from_loc<T>(node: T, db: &dyn DefDatabase) -> Attrs 208fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs {
191where 209 let tree = db.item_tree(id.file_id);
192 T: HasSource, 210 let mod_item = N::id_to_mod_item(id.value);
193 T::Value: ast::AttrsOwner, 211 tree.attrs(mod_item).clone()
194{
195 let src = node.source(db);
196 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
197} 212}
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index f159f80af..3ced648e5 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -5,7 +5,7 @@ use either::Either;
5use hir_expand::{ 5use hir_expand::{
6 hygiene::Hygiene, 6 hygiene::Hygiene,
7 name::{name, AsName, Name}, 7 name::{name, AsName, Name},
8 HirFileId, MacroDefId, MacroDefKind, 8 AstId, HirFileId, MacroDefId, MacroDefKind,
9}; 9};
10use ra_arena::Arena; 10use ra_arena::Arena;
11use ra_syntax::{ 11use ra_syntax::{
@@ -27,6 +27,7 @@ use crate::{
27 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, 27 LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
28 }, 28 },
29 item_scope::BuiltinShadowMode, 29 item_scope::BuiltinShadowMode,
30 item_tree::{FileItemTreeId, ItemTree, ItemTreeNode},
30 path::{GenericArgs, Path}, 31 path::{GenericArgs, Path},
31 type_ref::{Mutability, Rawness, TypeRef}, 32 type_ref::{Mutability, Rawness, TypeRef},
32 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, 33 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
@@ -35,6 +36,8 @@ use crate::{
35 36
36use super::{ExprSource, PatSource}; 37use super::{ExprSource, PatSource};
37use ast::AstChildren; 38use ast::AstChildren;
39use rustc_hash::FxHashMap;
40use std::sync::Arc;
38 41
39pub(crate) struct LowerCtx { 42pub(crate) struct LowerCtx {
40 hygiene: Hygiene, 43 hygiene: Hygiene,
@@ -60,10 +63,10 @@ pub(super) fn lower(
60 params: Option<ast::ParamList>, 63 params: Option<ast::ParamList>,
61 body: Option<ast::Expr>, 64 body: Option<ast::Expr>,
62) -> (Body, BodySourceMap) { 65) -> (Body, BodySourceMap) {
66 let item_tree = db.item_tree(expander.current_file_id);
63 ExprCollector { 67 ExprCollector {
64 db, 68 db,
65 def, 69 def,
66 expander,
67 source_map: BodySourceMap::default(), 70 source_map: BodySourceMap::default(),
68 body: Body { 71 body: Body {
69 exprs: Arena::default(), 72 exprs: Arena::default(),
@@ -72,6 +75,12 @@ pub(super) fn lower(
72 body_expr: dummy_expr_id(), 75 body_expr: dummy_expr_id(),
73 item_scope: Default::default(), 76 item_scope: Default::default(),
74 }, 77 },
78 item_trees: {
79 let mut map = FxHashMap::default();
80 map.insert(expander.current_file_id, item_tree);
81 map
82 },
83 expander,
75 } 84 }
76 .collect(params, body) 85 .collect(params, body)
77} 86}
@@ -82,6 +91,8 @@ struct ExprCollector<'a> {
82 expander: Expander, 91 expander: Expander,
83 body: Body, 92 body: Body,
84 source_map: BodySourceMap, 93 source_map: BodySourceMap,
94
95 item_trees: FxHashMap<HirFileId, Arc<ItemTree>>,
85} 96}
86 97
87impl ExprCollector<'_> { 98impl ExprCollector<'_> {
@@ -533,6 +544,9 @@ impl ExprCollector<'_> {
533 self.source_map 544 self.source_map
534 .expansions 545 .expansions
535 .insert(macro_call, self.expander.current_file_id); 546 .insert(macro_call, self.expander.current_file_id);
547
548 let item_tree = self.db.item_tree(self.expander.current_file_id);
549 self.item_trees.insert(self.expander.current_file_id, item_tree);
536 let id = self.collect_expr(expansion); 550 let id = self.collect_expr(expansion);
537 self.expander.exit(self.db, mark); 551 self.expander.exit(self.db, mark);
538 id 552 id
@@ -547,6 +561,19 @@ impl ExprCollector<'_> {
547 } 561 }
548 } 562 }
549 563
564 fn find_inner_item<S: ItemTreeNode>(&self, id: AstId<ast::ModuleItem>) -> FileItemTreeId<S> {
565 let tree = &self.item_trees[&id.file_id];
566
567 // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
568
569 // Root file (non-macro).
570 tree.all_inner_items()
571 .chain(tree.top_level_items().iter().copied())
572 .filter_map(|mod_item| mod_item.downcast::<S>())
573 .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value)
574 .unwrap_or_else(|| panic!("couldn't find inner item for {:?}", id))
575 }
576
550 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId { 577 fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
551 if let Some(expr) = expr { 578 if let Some(expr) = expr {
552 self.collect_expr(expr) 579 self.collect_expr(expr)
@@ -578,56 +605,102 @@ impl ExprCollector<'_> {
578 605
579 fn collect_block_items(&mut self, block: &ast::BlockExpr) { 606 fn collect_block_items(&mut self, block: &ast::BlockExpr) {
580 let container = ContainerId::DefWithBodyId(self.def); 607 let container = ContainerId::DefWithBodyId(self.def);
581 for item in block.items() { 608
582 let (def, name): (ModuleDefId, Option<ast::Name>) = match item { 609 let items = block
583 ast::ModuleItem::FnDef(def) => { 610 .items()
584 let ast_id = self.expander.ast_id(&def); 611 .filter_map(|item| {
585 ( 612 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
586 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(), 613 ast::ModuleItem::FnDef(def) => {
587 def.name(), 614 let ast_id = self.expander.ast_id(&def);
588 ) 615 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
589 } 616 (
590 ast::ModuleItem::TypeAliasDef(def) => { 617 FunctionLoc { container: container.into(), id: ast_id.with_value(id) }
591 let ast_id = self.expander.ast_id(&def); 618 .intern(self.db)
592 ( 619 .into(),
593 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(), 620 def.name(),
594 def.name(), 621 )
595 ) 622 }
596 } 623 ast::ModuleItem::TypeAliasDef(def) => {
597 ast::ModuleItem::ConstDef(def) => { 624 let ast_id = self.expander.ast_id(&def);
598 let ast_id = self.expander.ast_id(&def); 625 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
599 ( 626 (
600 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(), 627 TypeAliasLoc { container: container.into(), id: ast_id.with_value(id) }
601 def.name(), 628 .intern(self.db)
602 ) 629 .into(),
603 } 630 def.name(),
604 ast::ModuleItem::StaticDef(def) => { 631 )
605 let ast_id = self.expander.ast_id(&def); 632 }
606 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name()) 633 ast::ModuleItem::ConstDef(def) => {
607 } 634 let ast_id = self.expander.ast_id(&def);
608 ast::ModuleItem::StructDef(def) => { 635 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
609 let ast_id = self.expander.ast_id(&def); 636 (
610 (StructLoc { container, ast_id }.intern(self.db).into(), def.name()) 637 ConstLoc { container: container.into(), id: ast_id.with_value(id) }
611 } 638 .intern(self.db)
612 ast::ModuleItem::EnumDef(def) => { 639 .into(),
613 let ast_id = self.expander.ast_id(&def); 640 def.name(),
614 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name()) 641 )
615 } 642 }
616 ast::ModuleItem::UnionDef(def) => { 643 ast::ModuleItem::StaticDef(def) => {
617 let ast_id = self.expander.ast_id(&def); 644 let ast_id = self.expander.ast_id(&def);
618 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name()) 645 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
619 } 646 (
620 ast::ModuleItem::TraitDef(def) => { 647 StaticLoc { container, id: ast_id.with_value(id) }
621 let ast_id = self.expander.ast_id(&def); 648 .intern(self.db)
622 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) 649 .into(),
623 } 650 def.name(),
624 ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks 651 )
625 ast::ModuleItem::ImplDef(_) 652 }
626 | ast::ModuleItem::UseItem(_) 653 ast::ModuleItem::StructDef(def) => {
627 | ast::ModuleItem::ExternCrateItem(_) 654 let ast_id = self.expander.ast_id(&def);
628 | ast::ModuleItem::Module(_) 655 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
629 | ast::ModuleItem::MacroCall(_) => continue, 656 (
630 }; 657 StructLoc { container, id: ast_id.with_value(id) }
658 .intern(self.db)
659 .into(),
660 def.name(),
661 )
662 }
663 ast::ModuleItem::EnumDef(def) => {
664 let ast_id = self.expander.ast_id(&def);
665 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
666 (
667 EnumLoc { container, id: ast_id.with_value(id) }.intern(self.db).into(),
668 def.name(),
669 )
670 }
671 ast::ModuleItem::UnionDef(def) => {
672 let ast_id = self.expander.ast_id(&def);
673 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
674 (
675 UnionLoc { container, id: ast_id.with_value(id) }
676 .intern(self.db)
677 .into(),
678 def.name(),
679 )
680 }
681 ast::ModuleItem::TraitDef(def) => {
682 let ast_id = self.expander.ast_id(&def);
683 let id = self.find_inner_item(ast_id.map(|id| id.upcast()));
684 (
685 TraitLoc { container, id: ast_id.with_value(id) }
686 .intern(self.db)
687 .into(),
688 def.name(),
689 )
690 }
691 ast::ModuleItem::ExternBlock(_) => return None, // FIXME: collect from extern blocks
692 ast::ModuleItem::ImplDef(_)
693 | ast::ModuleItem::UseItem(_)
694 | ast::ModuleItem::ExternCrateItem(_)
695 | ast::ModuleItem::Module(_)
696 | ast::ModuleItem::MacroCall(_) => return None,
697 };
698
699 Some((def, name))
700 })
701 .collect::<Vec<_>>();
702
703 for (def, name) in items {
631 self.body.item_scope.define_def(def); 704 self.body.item_scope.define_def(def);
632 if let Some(name) = name { 705 if let Some(name) = name {
633 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly 706 let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index e48ff38f9..81397b063 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -87,15 +87,13 @@ impl ExprScopes {
87 } 87 }
88 88
89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { 89 fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
90 match &body[pat] { 90 let pattern = &body[pat];
91 Pat::Bind { name, .. } => { 91 if let Pat::Bind { name, .. } = pattern {
92 // bind can have a sub pattern, but it's actually not allowed 92 let entry = ScopeEntry { name: name.clone(), pat };
93 // to bind to things in there 93 self.scopes[scope].entries.push(entry);
94 let entry = ScopeEntry { name: name.clone(), pat };
95 self.scopes[scope].entries.push(entry)
96 }
97 p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
98 } 94 }
95
96 pattern.walk_child_pats(|pat| self.add_bindings(body, scope, pat));
99 } 97 }
100 98
101 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { 99 fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
@@ -190,21 +188,23 @@ mod tests {
190 } 188 }
191 } 189 }
192 190
193 fn do_check(code: &str, expected: &[&str]) { 191 fn do_check(ra_fixture: &str, expected: &[&str]) {
194 let (off, code) = extract_offset(code); 192 let (offset, code) = extract_offset(ra_fixture);
195 let code = { 193 let code = {
196 let mut buf = String::new(); 194 let mut buf = String::new();
197 let off: usize = off.into(); 195 let off: usize = offset.into();
198 buf.push_str(&code[..off]); 196 buf.push_str(&code[..off]);
199 buf.push_str("marker"); 197 buf.push_str("<|>marker");
200 buf.push_str(&code[off..]); 198 buf.push_str(&code[off..]);
201 buf 199 buf
202 }; 200 };
203 201
204 let (db, file_id) = TestDB::with_single_file(&code); 202 let (db, position) = TestDB::with_position(&code);
203 let file_id = position.file_id;
204 let offset = position.offset;
205 205
206 let file_syntax = db.parse(file_id).syntax_node(); 206 let file_syntax = db.parse(file_id).syntax_node();
207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, off).unwrap(); 207 let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
208 let function = find_function(&db, file_id); 208 let function = find_function(&db, file_id);
209 209
210 let scopes = db.expr_scopes(function.into()); 210 let scopes = db.expr_scopes(function.into());
@@ -300,15 +300,52 @@ mod tests {
300 ); 300 );
301 } 301 }
302 302
303 fn do_check_local_name(code: &str, expected_offset: u32) { 303 #[test]
304 let (off, code) = extract_offset(code); 304 fn test_bindings_after_at() {
305 do_check(
306 r"
307fn foo() {
308 match Some(()) {
309 opt @ Some(unit) => {
310 <|>
311 }
312 _ => {}
313 }
314}
315",
316 &["opt", "unit"],
317 );
318 }
319
320 #[test]
321 fn macro_inner_item() {
322 do_check(
323 r"
324 macro_rules! mac {
325 () => {{
326 fn inner() {}
327 inner();
328 }};
329 }
330
331 fn foo() {
332 mac!();
333 <|>
334 }
335 ",
336 &[],
337 );
338 }
305 339
306 let (db, file_id) = TestDB::with_single_file(&code); 340 fn do_check_local_name(ra_fixture: &str, expected_offset: u32) {
341 let (db, position) = TestDB::with_position(ra_fixture);
342 let file_id = position.file_id;
343 let offset = position.offset;
307 344
308 let file = db.parse(file_id).ok().unwrap(); 345 let file = db.parse(file_id).ok().unwrap();
309 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()) 346 let expected_name = find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into())
310 .expect("failed to find a name at the target offset"); 347 .expect("failed to find a name at the target offset");
311 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 348 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset).unwrap();
312 349
313 let function = find_function(&db, file_id); 350 let function = find_function(&db, file_id);
314 351
@@ -336,15 +373,16 @@ mod tests {
336 fn test_resolve_local_name() { 373 fn test_resolve_local_name() {
337 do_check_local_name( 374 do_check_local_name(
338 r#" 375 r#"
339 fn foo(x: i32, y: u32) { 376fn foo(x: i32, y: u32) {
340 { 377 {
341 let z = x * 2; 378 let z = x * 2;
342 } 379 }
343 { 380 {
344 let t = x<|> * 3; 381 let t = x<|> * 3;
345 } 382 }
346 }"#, 383}
347 21, 384"#,
385 7,
348 ); 386 );
349 } 387 }
350 388
@@ -352,10 +390,11 @@ mod tests {
352 fn test_resolve_local_name_declaration() { 390 fn test_resolve_local_name_declaration() {
353 do_check_local_name( 391 do_check_local_name(
354 r#" 392 r#"
355 fn foo(x: String) { 393fn foo(x: String) {
356 let x : &str = &x<|>; 394 let x : &str = &x<|>;
357 }"#, 395}
358 21, 396"#,
397 7,
359 ); 398 );
360 } 399 }
361 400
@@ -363,12 +402,12 @@ mod tests {
363 fn test_resolve_local_name_shadow() { 402 fn test_resolve_local_name_shadow() {
364 do_check_local_name( 403 do_check_local_name(
365 r" 404 r"
366 fn foo(x: String) { 405fn foo(x: String) {
367 let x : &str = &x; 406 let x : &str = &x;
368 x<|> 407 x<|>
369 } 408}
370 ", 409",
371 53, 410 28,
372 ); 411 );
373 } 412 }
374 413
@@ -376,13 +415,13 @@ mod tests {
376 fn ref_patterns_contribute_bindings() { 415 fn ref_patterns_contribute_bindings() {
377 do_check_local_name( 416 do_check_local_name(
378 r" 417 r"
379 fn foo() { 418fn foo() {
380 if let Some(&from) = bar() { 419 if let Some(&from) = bar() {
381 from<|>; 420 from<|>;
382 } 421 }
383 } 422}
384 ", 423",
385 53, 424 28,
386 ); 425 );
387 } 426 }
388 427
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 53599e74a..f9e5701db 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -2,27 +2,19 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{name::Name, InFile};
6 hygiene::Hygiene,
7 name::{name, AsName, Name},
8 AstId, InFile,
9};
10use ra_prof::profile; 6use ra_prof::profile;
11use ra_syntax::ast::{ 7use ra_syntax::ast;
12 self, AssocItem, AstNode, ModuleItemOwner, NameOwner, TypeAscriptionOwner, TypeBoundsOwner,
13 VisibilityOwner,
14};
15 8
16use crate::{ 9use crate::{
17 attr::Attrs, 10 attr::Attrs,
18 body::LowerCtx, 11 body::Expander,
19 db::DefDatabase, 12 db::DefDatabase,
20 path::{path, AssociatedTypeBinding, GenericArgs, Path}, 13 item_tree::{AssocItem, ItemTreeId, ModItem},
21 src::HasSource, 14 type_ref::{TypeBound, TypeRef},
22 type_ref::{Mutability, TypeBound, TypeRef},
23 visibility::RawVisibility, 15 visibility::RawVisibility,
24 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, 16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
25 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 17 Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
26}; 18};
27 19
28#[derive(Debug, Clone, PartialEq, Eq)] 20#[derive(Debug, Clone, PartialEq, Eq)]
@@ -41,82 +33,27 @@ pub struct FunctionData {
41impl FunctionData { 33impl FunctionData {
42 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { 34 pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> {
43 let loc = func.lookup(db); 35 let loc = func.lookup(db);
44 let src = loc.source(db); 36 let item_tree = db.item_tree(loc.id.file_id);
45 let ctx = LowerCtx::new(db, src.file_id); 37 let func = &item_tree[loc.id.value];
46 let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); 38
47 let mut params = Vec::new(); 39 Arc::new(FunctionData {
48 let mut has_self_param = false; 40 name: func.name.clone(),
49 if let Some(param_list) = src.value.param_list() { 41 params: func.params.to_vec(),
50 if let Some(self_param) = param_list.self_param() { 42 ret_type: func.ret_type.clone(),
51 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 43 attrs: item_tree.attrs(loc.id.value.into()).clone(),
52 TypeRef::from_ast(&ctx, type_ref) 44 has_self_param: func.has_self_param,
53 } else { 45 is_unsafe: func.is_unsafe,
54 let self_type = TypeRef::Path(name![Self].into()); 46 visibility: item_tree[func.visibility].clone(),
55 match self_param.kind() { 47 })
56 ast::SelfParamKind::Owned => self_type,
57 ast::SelfParamKind::Ref => {
58 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
59 }
60 ast::SelfParamKind::MutRef => {
61 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
62 }
63 }
64 };
65 params.push(self_type);
66 has_self_param = true;
67 }
68 for param in param_list.params() {
69 let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type());
70 params.push(type_ref);
71 }
72 }
73 let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));
74
75 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
76 TypeRef::from_ast(&ctx, type_ref)
77 } else {
78 TypeRef::unit()
79 };
80
81 let ret_type = if src.value.async_token().is_some() {
82 let future_impl = desugar_future_path(ret_type);
83 let ty_bound = TypeBound::Path(future_impl);
84 TypeRef::ImplTrait(vec![ty_bound])
85 } else {
86 ret_type
87 };
88
89 let is_unsafe = src.value.unsafe_token().is_some();
90
91 let vis_default = RawVisibility::default_for_container(loc.container);
92 let visibility =
93 RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
94
95 let sig =
96 FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs };
97 Arc::new(sig)
98 } 48 }
99} 49}
100 50
101fn desugar_future_path(orig: TypeRef) -> Path {
102 let path = path![core::future::Future];
103 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
104 let mut last = GenericArgs::empty();
105 last.bindings.push(AssociatedTypeBinding {
106 name: name![Output],
107 type_ref: Some(orig),
108 bounds: Vec::new(),
109 });
110 generic_args.push(Some(Arc::new(last)));
111
112 Path::from_known_path(path, generic_args)
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)] 51#[derive(Debug, Clone, PartialEq, Eq)]
116pub struct TypeAliasData { 52pub struct TypeAliasData {
117 pub name: Name, 53 pub name: Name,
118 pub type_ref: Option<TypeRef>, 54 pub type_ref: Option<TypeRef>,
119 pub visibility: RawVisibility, 55 pub visibility: RawVisibility,
56 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
120 pub bounds: Vec<TypeBound>, 57 pub bounds: Vec<TypeBound>,
121} 58}
122 59
@@ -126,22 +63,15 @@ impl TypeAliasData {
126 typ: TypeAliasId, 63 typ: TypeAliasId,
127 ) -> Arc<TypeAliasData> { 64 ) -> Arc<TypeAliasData> {
128 let loc = typ.lookup(db); 65 let loc = typ.lookup(db);
129 let node = loc.source(db); 66 let item_tree = db.item_tree(loc.id.file_id);
130 let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); 67 let typ = &item_tree[loc.id.value];
131 let lower_ctx = LowerCtx::new(db, node.file_id); 68
132 let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); 69 Arc::new(TypeAliasData {
133 let vis_default = RawVisibility::default_for_container(loc.container); 70 name: typ.name.clone(),
134 let visibility = RawVisibility::from_ast_with_default( 71 type_ref: typ.type_ref.clone(),
135 db, 72 visibility: item_tree[typ.visibility].clone(),
136 vis_default, 73 bounds: typ.bounds.to_vec(),
137 node.as_ref().map(|n| n.visibility()), 74 })
138 );
139 let bounds = if let Some(bound_list) = node.value.type_bound_list() {
140 bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect()
141 } else {
142 Vec::new()
143 };
144 Arc::new(TypeAliasData { name, type_ref, visibility, bounds })
145 } 75 }
146} 76}
147 77
@@ -155,30 +85,24 @@ pub struct TraitData {
155impl TraitData { 85impl TraitData {
156 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { 86 pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> {
157 let tr_loc = tr.lookup(db); 87 let tr_loc = tr.lookup(db);
158 let src = tr_loc.source(db); 88 let item_tree = db.item_tree(tr_loc.id.file_id);
159 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 89 let tr_def = &item_tree[tr_loc.id.value];
160 let auto = src.value.auto_token().is_some(); 90 let name = tr_def.name.clone();
91 let auto = tr_def.auto;
161 let module_id = tr_loc.container.module(db); 92 let module_id = tr_loc.container.module(db);
162
163 let container = AssocContainerId::TraitId(tr); 93 let container = AssocContainerId::TraitId(tr);
164 let mut items = Vec::new(); 94 let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
165 95
166 if let Some(item_list) = src.value.item_list() { 96 let items = collect_items(
167 let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); 97 db,
168 items.extend(collect_items( 98 module_id,
169 db, 99 &mut expander,
170 &mut expander, 100 tr_def.items.iter().copied(),
171 item_list.assoc_items(), 101 tr_loc.id.file_id,
172 src.file_id, 102 container,
173 container, 103 100,
174 )); 104 );
175 items.extend(collect_items_in_macros( 105
176 db,
177 &mut expander,
178 &src.with_value(item_list),
179 container,
180 ));
181 }
182 Arc::new(TraitData { name, items, auto }) 106 Arc::new(TraitData { name, items, auto })
183 } 107 }
184 108
@@ -209,33 +133,28 @@ impl ImplData {
209 pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> { 133 pub(crate) fn impl_data_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplData> {
210 let _p = profile("impl_data_query"); 134 let _p = profile("impl_data_query");
211 let impl_loc = id.lookup(db); 135 let impl_loc = id.lookup(db);
212 let src = impl_loc.source(db);
213 let lower_ctx = LowerCtx::new(db, src.file_id);
214 136
215 let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); 137 let item_tree = db.item_tree(impl_loc.id.file_id);
216 let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); 138 let impl_def = &item_tree[impl_loc.id.value];
217 let is_negative = src.value.excl_token().is_some(); 139 let target_trait = impl_def.target_trait.clone();
140 let target_type = impl_def.target_type.clone();
141 let is_negative = impl_def.is_negative;
218 let module_id = impl_loc.container.module(db); 142 let module_id = impl_loc.container.module(db);
219 let container = AssocContainerId::ImplId(id); 143 let container = AssocContainerId::ImplId(id);
144 let mut expander = Expander::new(db, impl_loc.id.file_id, module_id);
220 145
221 let mut items: Vec<AssocItemId> = Vec::new(); 146 let items = collect_items(
222 147 db,
223 if let Some(item_list) = src.value.item_list() { 148 module_id,
224 let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); 149 &mut expander,
225 items.extend( 150 impl_def.items.iter().copied(),
226 collect_items(db, &mut expander, item_list.assoc_items(), src.file_id, container) 151 impl_loc.id.file_id,
227 .into_iter() 152 container,
228 .map(|(_, item)| item), 153 100,
229 ); 154 );
230 items.extend( 155 let items = items.into_iter().map(|(_, item)| item).collect();
231 collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container)
232 .into_iter()
233 .map(|(_, item)| item),
234 );
235 }
236 156
237 let res = ImplData { target_trait, target_type, items, is_negative }; 157 Arc::new(ImplData { target_trait, target_type, items, is_negative })
238 Arc::new(res)
239 } 158 }
240} 159}
241 160
@@ -250,22 +169,14 @@ pub struct ConstData {
250impl ConstData { 169impl ConstData {
251 pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> { 170 pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<ConstData> {
252 let loc = konst.lookup(db); 171 let loc = konst.lookup(db);
253 let node = loc.source(db); 172 let item_tree = db.item_tree(loc.id.file_id);
254 let vis_default = RawVisibility::default_for_container(loc.container); 173 let konst = &item_tree[loc.id.value];
255 Arc::new(ConstData::new(db, vis_default, node))
256 }
257 174
258 fn new<N: NameOwner + TypeAscriptionOwner + VisibilityOwner>( 175 Arc::new(ConstData {
259 db: &dyn DefDatabase, 176 name: konst.name.clone(),
260 vis_default: RawVisibility, 177 type_ref: konst.type_ref.clone(),
261 node: InFile<N>, 178 visibility: item_tree[konst.visibility].clone(),
262 ) -> ConstData { 179 })
263 let ctx = LowerCtx::new(db, node.file_id);
264 let name = node.value.name().map(|n| n.as_name());
265 let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type());
266 let visibility =
267 RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility()));
268 ConstData { name, type_ref, visibility }
269 } 180 }
270} 181}
271 182
@@ -279,44 +190,25 @@ pub struct StaticData {
279 190
280impl StaticData { 191impl StaticData {
281 pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> { 192 pub(crate) fn static_data_query(db: &dyn DefDatabase, konst: StaticId) -> Arc<StaticData> {
282 let node = konst.lookup(db).source(db); 193 let node = konst.lookup(db);
283 let ctx = LowerCtx::new(db, node.file_id); 194 let item_tree = db.item_tree(node.id.file_id);
284 195 let statik = &item_tree[node.id.value];
285 let name = node.value.name().map(|n| n.as_name()); 196
286 let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); 197 Arc::new(StaticData {
287 let mutable = node.value.mut_token().is_some(); 198 name: Some(statik.name.clone()),
288 let visibility = RawVisibility::from_ast_with_default( 199 type_ref: statik.type_ref.clone(),
289 db, 200 visibility: item_tree[statik.visibility].clone(),
290 RawVisibility::private(), 201 mutable: statik.mutable,
291 node.map(|n| n.visibility()), 202 })
292 );
293
294 Arc::new(StaticData { name, type_ref, visibility, mutable })
295 }
296}
297
298fn collect_items_in_macros(
299 db: &dyn DefDatabase,
300 expander: &mut Expander,
301 impl_def: &InFile<ast::ItemList>,
302 container: AssocContainerId,
303) -> Vec<(Name, AssocItemId)> {
304 let mut res = Vec::new();
305
306 // We set a limit to protect against infinite recursion
307 let limit = 100;
308
309 for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) {
310 res.extend(collect_items_in_macro(db, expander, m, container, limit))
311 } 203 }
312
313 res
314} 204}
315 205
316fn collect_items_in_macro( 206fn collect_items(
317 db: &dyn DefDatabase, 207 db: &dyn DefDatabase,
208 module: ModuleId,
318 expander: &mut Expander, 209 expander: &mut Expander,
319 m: ast::MacroCall, 210 assoc_items: impl Iterator<Item = AssocItem>,
211 file_id: crate::HirFileId,
320 container: AssocContainerId, 212 container: AssocContainerId,
321 limit: usize, 213 limit: usize,
322) -> Vec<(Name, AssocItemId)> { 214) -> Vec<(Name, AssocItemId)> {
@@ -324,62 +216,62 @@ fn collect_items_in_macro(
324 return Vec::new(); 216 return Vec::new();
325 } 217 }
326 218
327 if let Some((mark, items)) = expander.enter_expand(db, None, m) { 219 let item_tree = db.item_tree(file_id);
328 let items: InFile<ast::MacroItems> = expander.to_source(items); 220 let cfg_options = db.crate_graph()[module.krate].cfg_options.clone();
329 let mut res = collect_items( 221
330 db, 222 let mut items = Vec::new();
331 expander, 223 for item in assoc_items {
332 items.value.items().filter_map(|it| AssocItem::cast(it.syntax().clone())), 224 match item {
333 items.file_id, 225 AssocItem::Function(id) => {
334 container, 226 let item = &item_tree[id];
335 ); 227 let attrs = item_tree.attrs(id.into());
336 228 if !attrs.is_cfg_enabled(&cfg_options) {
337 // Recursive collect macros 229 continue;
338 // Note that ast::ModuleItem do not include ast::MacroCall
339 // We cannot use ModuleItemOwner::items here
340 for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
341 res.extend(collect_items_in_macro(db, expander, it, container, limit - 1))
342 }
343 expander.exit(db, mark);
344 res
345 } else {
346 Vec::new()
347 }
348}
349
350fn collect_items(
351 db: &dyn DefDatabase,
352 expander: &mut Expander,
353 assoc_items: impl Iterator<Item = AssocItem>,
354 file_id: crate::HirFileId,
355 container: AssocContainerId,
356) -> Vec<(Name, AssocItemId)> {
357 let items = db.ast_id_map(file_id);
358
359 assoc_items
360 .filter_map(|item_node| match item_node {
361 ast::AssocItem::FnDef(it) => {
362 let name = it.name().map_or_else(Name::missing, |it| it.as_name());
363 if !expander.is_cfg_enabled(&it) {
364 return None;
365 } 230 }
366 let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 231 let def = FunctionLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
367 .intern(db); 232 items.push((item.name.clone(), def.into()));
368 Some((name, def.into()))
369 } 233 }
370 ast::AssocItem::ConstDef(it) => { 234 // FIXME: cfg?
371 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 235 AssocItem::Const(id) => {
372 let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 236 let item = &item_tree[id];
373 .intern(db); 237 let name = match item.name.clone() {
374 Some((name, def.into())) 238 Some(name) => name,
239 None => continue,
240 };
241 let def = ConstLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
242 items.push((name, def.into()));
375 } 243 }
376 ast::AssocItem::TypeAliasDef(it) => { 244 AssocItem::TypeAlias(id) => {
377 let name = it.name().map_or_else(Name::missing, |it| it.as_name()); 245 let item = &item_tree[id];
378 let def = 246 let def = TypeAliasLoc { container, id: ItemTreeId::new(file_id, id) }.intern(db);
379 TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } 247 items.push((item.name.clone(), def.into()));
380 .intern(db);
381 Some((name, def.into()))
382 } 248 }
383 }) 249 AssocItem::MacroCall(call) => {
384 .collect() 250 let call = &item_tree[call];
251 let ast_id_map = db.ast_id_map(file_id);
252 let root = db.parse_or_expand(file_id).unwrap();
253 let call = ast_id_map.get(call.ast_id).to_node(&root);
254
255 if let Some((mark, mac)) = expander.enter_expand(db, None, call) {
256 let src: InFile<ast::MacroItems> = expander.to_source(mac);
257 let item_tree = db.item_tree(src.file_id);
258 let iter =
259 item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item);
260 items.extend(collect_items(
261 db,
262 module,
263 expander,
264 iter,
265 src.file_id,
266 container,
267 limit - 1,
268 ));
269
270 expander.exit(db, mark);
271 }
272 }
273 }
274 }
275
276 items
385} 277}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index 10cc26480..9c3ede2d7 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -14,8 +14,9 @@ use crate::{
14 docs::Documentation, 14 docs::Documentation,
15 generics::GenericParams, 15 generics::GenericParams,
16 import_map::ImportMap, 16 import_map::ImportMap,
17 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 18 lang_item::{LangItemTarget, LangItems},
18 nameres::{raw::RawItems, CrateDefMap}, 19 nameres::CrateDefMap,
19 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, 20 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
20 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId, 21 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
21 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, 22 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
@@ -45,8 +46,8 @@ pub trait InternDatabase: SourceDatabase {
45 46
46#[salsa::query_group(DefDatabaseStorage)] 47#[salsa::query_group(DefDatabaseStorage)]
47pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { 48pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
48 #[salsa::invoke(RawItems::raw_items_query)] 49 #[salsa::invoke(ItemTree::item_tree_query)]
49 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 50 fn item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
50 51
51 #[salsa::invoke(crate_def_map_wait)] 52 #[salsa::invoke(crate_def_map_wait)]
52 #[salsa::transparent] 53 #[salsa::transparent]
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 09a5241f7..6a0f493a7 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -42,7 +42,7 @@ pub enum TypeParamProvenance {
42} 42}
43 43
44/// Data about the generic parameters of a function, struct, impl, etc. 44/// Data about the generic parameters of a function, struct, impl, etc.
45#[derive(Clone, PartialEq, Eq, Debug)] 45#[derive(Clone, PartialEq, Eq, Debug, Default)]
46pub struct GenericParams { 46pub struct GenericParams {
47 pub types: Arena<TypeParamData>, 47 pub types: Arena<TypeParamData>,
48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, 48 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
@@ -74,8 +74,53 @@ impl GenericParams {
74 def: GenericDefId, 74 def: GenericDefId,
75 ) -> Arc<GenericParams> { 75 ) -> Arc<GenericParams> {
76 let _p = profile("generic_params_query"); 76 let _p = profile("generic_params_query");
77 let (params, _source_map) = GenericParams::new(db, def); 77
78 Arc::new(params) 78 let generics = match def {
79 GenericDefId::FunctionId(id) => {
80 let id = id.lookup(db).id;
81 let tree = db.item_tree(id.file_id);
82 let item = &tree[id.value];
83 tree[item.generic_params].clone()
84 }
85 GenericDefId::AdtId(AdtId::StructId(id)) => {
86 let id = id.lookup(db).id;
87 let tree = db.item_tree(id.file_id);
88 let item = &tree[id.value];
89 tree[item.generic_params].clone()
90 }
91 GenericDefId::AdtId(AdtId::EnumId(id)) => {
92 let id = id.lookup(db).id;
93 let tree = db.item_tree(id.file_id);
94 let item = &tree[id.value];
95 tree[item.generic_params].clone()
96 }
97 GenericDefId::AdtId(AdtId::UnionId(id)) => {
98 let id = id.lookup(db).id;
99 let tree = db.item_tree(id.file_id);
100 let item = &tree[id.value];
101 tree[item.generic_params].clone()
102 }
103 GenericDefId::TraitId(id) => {
104 let id = id.lookup(db).id;
105 let tree = db.item_tree(id.file_id);
106 let item = &tree[id.value];
107 tree[item.generic_params].clone()
108 }
109 GenericDefId::TypeAliasId(id) => {
110 let id = id.lookup(db).id;
111 let tree = db.item_tree(id.file_id);
112 let item = &tree[id.value];
113 tree[item.generic_params].clone()
114 }
115 GenericDefId::ImplId(id) => {
116 let id = id.lookup(db).id;
117 let tree = db.item_tree(id.file_id);
118 let item = &tree[id.value];
119 tree[item.generic_params].clone()
120 }
121 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
122 };
123 Arc::new(generics)
79 } 124 }
80 125
81 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { 126 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
@@ -156,7 +201,12 @@ impl GenericParams {
156 (generics, InFile::new(file_id, sm)) 201 (generics, InFile::new(file_id, sm))
157 } 202 }
158 203
159 fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { 204 pub(crate) fn fill(
205 &mut self,
206 lower_ctx: &LowerCtx,
207 sm: &mut SourceMap,
208 node: &dyn TypeParamsOwner,
209 ) {
160 if let Some(params) = node.type_param_list() { 210 if let Some(params) = node.type_param_list() {
161 self.fill_params(lower_ctx, sm, params) 211 self.fill_params(lower_ctx, sm, params)
162 } 212 }
@@ -165,7 +215,7 @@ impl GenericParams {
165 } 215 }
166 } 216 }
167 217
168 fn fill_bounds( 218 pub(crate) fn fill_bounds(
169 &mut self, 219 &mut self,
170 lower_ctx: &LowerCtx, 220 lower_ctx: &LowerCtx,
171 node: &dyn ast::TypeBoundsOwner, 221 node: &dyn ast::TypeBoundsOwner,
@@ -229,7 +279,7 @@ impl GenericParams {
229 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); 279 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
230 } 280 }
231 281
232 fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { 282 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
233 type_ref.walk(&mut |type_ref| { 283 type_ref.walk(&mut |type_ref| {
234 if let TypeRef::ImplTrait(bounds) = type_ref { 284 if let TypeRef::ImplTrait(bounds) = type_ref {
235 let param = TypeParamData { 285 let param = TypeParamData {
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index b03ba939a..c81b966c3 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -5,6 +5,7 @@ use hir_expand::name::Name;
5use once_cell::sync::Lazy; 5use once_cell::sync::Lazy;
6use ra_db::CrateId; 6use ra_db::CrateId;
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8use test_utils::mark;
8 9
9use crate::{ 10use crate::{
10 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, 11 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId,
@@ -126,19 +127,27 @@ impl ItemScope {
126 let mut changed = false; 127 let mut changed = false;
127 let existing = self.visible.entry(name).or_default(); 128 let existing = self.visible.entry(name).or_default();
128 129
129 if existing.types.is_none() && def.types.is_some() { 130 macro_rules! check_changed {
130 existing.types = def.types; 131 ($changed:ident, $existing:expr, $def:expr) => {
131 changed = true; 132 match ($existing, $def) {
132 } 133 (None, Some(_)) => {
133 if existing.values.is_none() && def.values.is_some() { 134 $existing = $def;
134 existing.values = def.values; 135 $changed = true;
135 changed = true; 136 }
136 } 137 (Some(e), Some(d)) if e.0 != d.0 => {
137 if existing.macros.is_none() && def.macros.is_some() { 138 mark::hit!(import_shadowed);
138 existing.macros = def.macros; 139 $existing = $def;
139 changed = true; 140 $changed = true;
141 }
142 _ => {}
143 }
144 };
140 } 145 }
141 146
147 check_changed!(changed, existing.types, def.types);
148 check_changed!(changed, existing.values, def.values);
149 check_changed!(changed, existing.macros, def.macros);
150
142 changed 151 changed
143 } 152 }
144 153
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
new file mode 100644
index 000000000..d7bc64e6c
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -0,0 +1,697 @@
1//! A simplified AST that only contains items.
2
3mod lower;
4#[cfg(test)]
5mod tests;
6
7use std::{
8 fmt::{self, Debug},
9 hash::{Hash, Hasher},
10 marker::PhantomData,
11 ops::{Index, Range},
12 sync::Arc,
13};
14
15use ast::{AstNode, AttrsOwner, NameOwner, StructKind, TypeAscriptionOwner};
16use either::Either;
17use hir_expand::{
18 ast_id_map::FileAstId,
19 hygiene::Hygiene,
20 name::{name, AsName, Name},
21 HirFileId, InFile,
22};
23use ra_arena::{Arena, Idx, RawId};
24use ra_syntax::{ast, match_ast};
25use rustc_hash::FxHashMap;
26use smallvec::SmallVec;
27use test_utils::mark;
28
29use crate::{
30 attr::Attrs,
31 db::DefDatabase,
32 generics::GenericParams,
33 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
34 type_ref::{Mutability, TypeBound, TypeRef},
35 visibility::RawVisibility,
36};
37
38#[derive(Copy, Clone, Eq, PartialEq)]
39pub struct RawVisibilityId(u32);
40
41impl RawVisibilityId {
42 pub const PUB: Self = RawVisibilityId(u32::max_value());
43 pub const PRIV: Self = RawVisibilityId(u32::max_value() - 1);
44 pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 2);
45}
46
47impl fmt::Debug for RawVisibilityId {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 let mut f = f.debug_tuple("RawVisibilityId");
50 match *self {
51 Self::PUB => f.field(&"pub"),
52 Self::PRIV => f.field(&"pub(self)"),
53 Self::PUB_CRATE => f.field(&"pub(crate)"),
54 _ => f.field(&self.0),
55 };
56 f.finish()
57 }
58}
59
60#[derive(Debug, Copy, Clone, Eq, PartialEq)]
61pub struct GenericParamsId(u32);
62
63impl GenericParamsId {
64 pub const EMPTY: Self = GenericParamsId(u32::max_value());
65}
66
67/// The item tree of a source file.
68#[derive(Debug, Eq, PartialEq)]
69pub struct ItemTree {
70 top_level: SmallVec<[ModItem; 1]>,
71 attrs: FxHashMap<AttrOwner, Attrs>,
72 inner_items: FxHashMap<FileAstId<ast::ModuleItem>, SmallVec<[ModItem; 1]>>,
73
74 data: Option<Box<ItemTreeData>>,
75}
76
77impl ItemTree {
78 pub fn item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
79 let _p = ra_prof::profile("item_tree_query").detail(|| format!("{:?}", file_id));
80 let syntax = if let Some(node) = db.parse_or_expand(file_id) {
81 node
82 } else {
83 return Arc::new(Self::empty());
84 };
85
86 let hygiene = Hygiene::new(db.upcast(), file_id);
87 let ctx = lower::Ctx::new(db, hygiene.clone(), file_id);
88 let mut top_attrs = None;
89 let mut item_tree = match_ast! {
90 match syntax {
91 ast::SourceFile(file) => {
92 top_attrs = Some(Attrs::new(&file, &hygiene));
93 ctx.lower_module_items(&file)
94 },
95 ast::MacroItems(items) => {
96 ctx.lower_module_items(&items)
97 },
98 // Macros can expand to expressions. We return an empty item tree in this case, but
99 // still need to collect inner items.
100 ast::Expr(e) => {
101 ctx.lower_inner_items(e.syntax())
102 },
103 _ => {
104 panic!("cannot create item tree from {:?}", syntax);
105 },
106 }
107 };
108
109 if let Some(attrs) = top_attrs {
110 item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
111 }
112 item_tree.shrink_to_fit();
113 Arc::new(item_tree)
114 }
115
116 fn empty() -> Self {
117 Self {
118 top_level: Default::default(),
119 attrs: Default::default(),
120 inner_items: Default::default(),
121 data: Default::default(),
122 }
123 }
124
125 fn shrink_to_fit(&mut self) {
126 if let Some(data) = &mut self.data {
127 let ItemTreeData {
128 imports,
129 extern_crates,
130 functions,
131 structs,
132 fields,
133 unions,
134 enums,
135 variants,
136 consts,
137 statics,
138 traits,
139 impls,
140 type_aliases,
141 mods,
142 macro_calls,
143 exprs,
144 vis,
145 generics,
146 } = &mut **data;
147
148 imports.shrink_to_fit();
149 extern_crates.shrink_to_fit();
150 functions.shrink_to_fit();
151 structs.shrink_to_fit();
152 fields.shrink_to_fit();
153 unions.shrink_to_fit();
154 enums.shrink_to_fit();
155 variants.shrink_to_fit();
156 consts.shrink_to_fit();
157 statics.shrink_to_fit();
158 traits.shrink_to_fit();
159 impls.shrink_to_fit();
160 type_aliases.shrink_to_fit();
161 mods.shrink_to_fit();
162 macro_calls.shrink_to_fit();
163 exprs.shrink_to_fit();
164
165 vis.arena.shrink_to_fit();
166 generics.arena.shrink_to_fit();
167 }
168 }
169
170 /// Returns an iterator over all items located at the top level of the `HirFileId` this
171 /// `ItemTree` was created from.
172 pub fn top_level_items(&self) -> &[ModItem] {
173 &self.top_level
174 }
175
176 /// Returns the inner attributes of the source file.
177 pub fn top_level_attrs(&self) -> &Attrs {
178 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY)
179 }
180
181 pub fn attrs(&self, of: ModItem) -> &Attrs {
182 self.attrs.get(&AttrOwner::ModItem(of)).unwrap_or(&Attrs::EMPTY)
183 }
184
185 /// Returns the lowered inner items that `ast` corresponds to.
186 ///
187 /// Most AST items are lowered to a single `ModItem`, but some (eg. `use` items) may be lowered
188 /// to multiple items in the `ItemTree`.
189 pub fn inner_items(&self, ast: FileAstId<ast::ModuleItem>) -> &[ModItem] {
190 &self.inner_items[&ast]
191 }
192
193 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
194 self.inner_items.values().flatten().copied()
195 }
196
197 pub fn source<S: ItemTreeNode>(&self, db: &dyn DefDatabase, of: ItemTreeId<S>) -> S::Source {
198 // This unwrap cannot fail, since it has either succeeded above, or resulted in an empty
199 // ItemTree (in which case there is no valid `FileItemTreeId` to call this method with).
200 let root =
201 db.parse_or_expand(of.file_id).expect("parse_or_expand failed on constructed ItemTree");
202
203 let id = self[of.value].ast_id();
204 let map = db.ast_id_map(of.file_id);
205 let ptr = map.get(id);
206 ptr.to_node(&root)
207 }
208
209 fn data(&self) -> &ItemTreeData {
210 self.data.as_ref().expect("attempted to access data of empty ItemTree")
211 }
212
213 fn data_mut(&mut self) -> &mut ItemTreeData {
214 self.data.get_or_insert_with(Box::default)
215 }
216}
217
218#[derive(Default, Debug, Eq, PartialEq)]
219struct ItemVisibilities {
220 arena: Arena<RawVisibility>,
221}
222
223impl ItemVisibilities {
224 fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
225 match &vis {
226 RawVisibility::Public => RawVisibilityId::PUB,
227 RawVisibility::Module(path) if path.segments.is_empty() => match &path.kind {
228 PathKind::Super(0) => RawVisibilityId::PRIV,
229 PathKind::Crate => RawVisibilityId::PUB_CRATE,
230 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
231 },
232 _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
233 }
234 }
235}
236
237static VIS_PUB: RawVisibility = RawVisibility::Public;
238static VIS_PRIV: RawVisibility =
239 RawVisibility::Module(ModPath { kind: PathKind::Super(0), segments: Vec::new() });
240static VIS_PUB_CRATE: RawVisibility =
241 RawVisibility::Module(ModPath { kind: PathKind::Crate, segments: Vec::new() });
242
243#[derive(Default, Debug, Eq, PartialEq)]
244struct GenericParamsStorage {
245 arena: Arena<GenericParams>,
246}
247
248impl GenericParamsStorage {
249 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
250 if params.types.is_empty() && params.where_predicates.is_empty() {
251 return GenericParamsId::EMPTY;
252 }
253
254 GenericParamsId(self.arena.alloc(params).into_raw().into())
255 }
256}
257
258static EMPTY_GENERICS: GenericParams =
259 GenericParams { types: Arena::new(), where_predicates: Vec::new() };
260
261#[derive(Default, Debug, Eq, PartialEq)]
262struct ItemTreeData {
263 imports: Arena<Import>,
264 extern_crates: Arena<ExternCrate>,
265 functions: Arena<Function>,
266 structs: Arena<Struct>,
267 fields: Arena<Field>,
268 unions: Arena<Union>,
269 enums: Arena<Enum>,
270 variants: Arena<Variant>,
271 consts: Arena<Const>,
272 statics: Arena<Static>,
273 traits: Arena<Trait>,
274 impls: Arena<Impl>,
275 type_aliases: Arena<TypeAlias>,
276 mods: Arena<Mod>,
277 macro_calls: Arena<MacroCall>,
278 exprs: Arena<Expr>,
279
280 vis: ItemVisibilities,
281 generics: GenericParamsStorage,
282}
283
284#[derive(Debug, Eq, PartialEq, Hash)]
285enum AttrOwner {
286 /// Attributes on an item.
287 ModItem(ModItem),
288 /// Inner attributes of the source file.
289 TopLevel,
290 // FIXME: Store variant and field attrs, and stop reparsing them in `attrs_query`.
291}
292
293/// Trait implemented by all nodes in the item tree.
294pub trait ItemTreeNode: Clone {
295 type Source: AstNode + Into<ast::ModuleItem>;
296
297 fn ast_id(&self) -> FileAstId<Self::Source>;
298
299 /// Looks up an instance of `Self` in an item tree.
300 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
301
302 /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
303 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
304
305 /// Upcasts a `FileItemTreeId` to a generic `ModItem`.
306 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
307}
308
309pub struct FileItemTreeId<N: ItemTreeNode> {
310 index: Idx<N>,
311 _p: PhantomData<N>,
312}
313
314impl<N: ItemTreeNode> Clone for FileItemTreeId<N> {
315 fn clone(&self) -> Self {
316 Self { index: self.index, _p: PhantomData }
317 }
318}
319impl<N: ItemTreeNode> Copy for FileItemTreeId<N> {}
320
321impl<N: ItemTreeNode> PartialEq for FileItemTreeId<N> {
322 fn eq(&self, other: &FileItemTreeId<N>) -> bool {
323 self.index == other.index
324 }
325}
326impl<N: ItemTreeNode> Eq for FileItemTreeId<N> {}
327
328impl<N: ItemTreeNode> Hash for FileItemTreeId<N> {
329 fn hash<H: Hasher>(&self, state: &mut H) {
330 self.index.hash(state)
331 }
332}
333
334impl<N: ItemTreeNode> fmt::Debug for FileItemTreeId<N> {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 self.index.fmt(f)
337 }
338}
339
340pub type ItemTreeId<N> = InFile<FileItemTreeId<N>>;
341
342macro_rules! mod_items {
343 ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
344 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
345 pub enum ModItem {
346 $(
347 $typ(FileItemTreeId<$typ>),
348 )+
349 }
350
351 $(
352 impl From<FileItemTreeId<$typ>> for ModItem {
353 fn from(id: FileItemTreeId<$typ>) -> ModItem {
354 ModItem::$typ(id)
355 }
356 }
357 )+
358
359 $(
360 impl ItemTreeNode for $typ {
361 type Source = $ast;
362
363 fn ast_id(&self) -> FileAstId<Self::Source> {
364 self.ast_id
365 }
366
367 fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
368 &tree.data().$fld[index]
369 }
370
371 fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
372 if let ModItem::$typ(id) = mod_item {
373 Some(id)
374 } else {
375 None
376 }
377 }
378
379 fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem {
380 ModItem::$typ(id)
381 }
382 }
383
384 impl Index<Idx<$typ>> for ItemTree {
385 type Output = $typ;
386
387 fn index(&self, index: Idx<$typ>) -> &Self::Output {
388 &self.data().$fld[index]
389 }
390 }
391 )+
392 };
393}
394
395mod_items! {
396 Import in imports -> ast::UseItem,
397 ExternCrate in extern_crates -> ast::ExternCrateItem,
398 Function in functions -> ast::FnDef,
399 Struct in structs -> ast::StructDef,
400 Union in unions -> ast::UnionDef,
401 Enum in enums -> ast::EnumDef,
402 Const in consts -> ast::ConstDef,
403 Static in statics -> ast::StaticDef,
404 Trait in traits -> ast::TraitDef,
405 Impl in impls -> ast::ImplDef,
406 TypeAlias in type_aliases -> ast::TypeAliasDef,
407 Mod in mods -> ast::Module,
408 MacroCall in macro_calls -> ast::MacroCall,
409}
410
411macro_rules! impl_index {
412 ( $($fld:ident: $t:ty),+ $(,)? ) => {
413 $(
414 impl Index<Idx<$t>> for ItemTree {
415 type Output = $t;
416
417 fn index(&self, index: Idx<$t>) -> &Self::Output {
418 &self.data().$fld[index]
419 }
420 }
421 )+
422 };
423}
424
425impl_index!(fields: Field, variants: Variant, exprs: Expr);
426
427impl Index<RawVisibilityId> for ItemTree {
428 type Output = RawVisibility;
429 fn index(&self, index: RawVisibilityId) -> &Self::Output {
430 match index {
431 RawVisibilityId::PRIV => &VIS_PRIV,
432 RawVisibilityId::PUB => &VIS_PUB,
433 RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
434 _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
435 }
436 }
437}
438
439impl Index<GenericParamsId> for ItemTree {
440 type Output = GenericParams;
441
442 fn index(&self, index: GenericParamsId) -> &Self::Output {
443 match index {
444 GenericParamsId::EMPTY => &EMPTY_GENERICS,
445 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
446 }
447 }
448}
449
450impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
451 type Output = N;
452 fn index(&self, id: FileItemTreeId<N>) -> &N {
453 N::lookup(self, id.index)
454 }
455}
456
457/// A desugared `use` import.
458#[derive(Debug, Clone, Eq, PartialEq)]
459pub struct Import {
460 pub path: ModPath,
461 pub alias: Option<ImportAlias>,
462 pub visibility: RawVisibilityId,
463 pub is_glob: bool,
464 pub is_prelude: bool,
465 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
466 /// `Import`s can map to the same `use` item.
467 pub ast_id: FileAstId<ast::UseItem>,
468}
469
470#[derive(Debug, Clone, Eq, PartialEq)]
471pub struct ExternCrate {
472 pub path: ModPath,
473 pub alias: Option<ImportAlias>,
474 pub visibility: RawVisibilityId,
475 /// Whether this is a `#[macro_use] extern crate ...`.
476 pub is_macro_use: bool,
477 pub ast_id: FileAstId<ast::ExternCrateItem>,
478}
479
480#[derive(Debug, Clone, Eq, PartialEq)]
481pub struct Function {
482 pub name: Name,
483 pub visibility: RawVisibilityId,
484 pub generic_params: GenericParamsId,
485 pub has_self_param: bool,
486 pub is_unsafe: bool,
487 pub params: Box<[TypeRef]>,
488 pub ret_type: TypeRef,
489 pub ast_id: FileAstId<ast::FnDef>,
490}
491
492#[derive(Debug, Clone, Eq, PartialEq)]
493pub struct Struct {
494 pub name: Name,
495 pub visibility: RawVisibilityId,
496 pub generic_params: GenericParamsId,
497 pub fields: Fields,
498 pub ast_id: FileAstId<ast::StructDef>,
499 pub kind: StructDefKind,
500}
501
502#[derive(Debug, Clone, Eq, PartialEq)]
503pub enum StructDefKind {
504 /// `struct S { ... }` - type namespace only.
505 Record,
506 /// `struct S(...);`
507 Tuple,
508 /// `struct S;`
509 Unit,
510}
511
512#[derive(Debug, Clone, Eq, PartialEq)]
513pub struct Union {
514 pub name: Name,
515 pub visibility: RawVisibilityId,
516 pub generic_params: GenericParamsId,
517 pub fields: Fields,
518 pub ast_id: FileAstId<ast::UnionDef>,
519}
520
521#[derive(Debug, Clone, Eq, PartialEq)]
522pub struct Enum {
523 pub name: Name,
524 pub visibility: RawVisibilityId,
525 pub generic_params: GenericParamsId,
526 pub variants: Range<Idx<Variant>>,
527 pub ast_id: FileAstId<ast::EnumDef>,
528}
529
530#[derive(Debug, Clone, Eq, PartialEq)]
531pub struct Const {
532 /// const _: () = ();
533 pub name: Option<Name>,
534 pub visibility: RawVisibilityId,
535 pub type_ref: TypeRef,
536 pub ast_id: FileAstId<ast::ConstDef>,
537}
538
539#[derive(Debug, Clone, Eq, PartialEq)]
540pub struct Static {
541 pub name: Name,
542 pub visibility: RawVisibilityId,
543 pub mutable: bool,
544 pub type_ref: TypeRef,
545 pub ast_id: FileAstId<ast::StaticDef>,
546}
547
548#[derive(Debug, Clone, Eq, PartialEq)]
549pub struct Trait {
550 pub name: Name,
551 pub visibility: RawVisibilityId,
552 pub generic_params: GenericParamsId,
553 pub auto: bool,
554 pub items: Box<[AssocItem]>,
555 pub ast_id: FileAstId<ast::TraitDef>,
556}
557
558#[derive(Debug, Clone, Eq, PartialEq)]
559pub struct Impl {
560 pub generic_params: GenericParamsId,
561 pub target_trait: Option<TypeRef>,
562 pub target_type: TypeRef,
563 pub is_negative: bool,
564 pub items: Box<[AssocItem]>,
565 pub ast_id: FileAstId<ast::ImplDef>,
566}
567
568#[derive(Debug, Clone, PartialEq, Eq)]
569pub struct TypeAlias {
570 pub name: Name,
571 pub visibility: RawVisibilityId,
572 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
573 pub bounds: Box<[TypeBound]>,
574 pub generic_params: GenericParamsId,
575 pub type_ref: Option<TypeRef>,
576 pub ast_id: FileAstId<ast::TypeAliasDef>,
577}
578
579#[derive(Debug, Clone, Eq, PartialEq)]
580pub struct Mod {
581 pub name: Name,
582 pub visibility: RawVisibilityId,
583 pub kind: ModKind,
584 pub ast_id: FileAstId<ast::Module>,
585}
586
587#[derive(Debug, Clone, Eq, PartialEq)]
588pub enum ModKind {
589 /// `mod m { ... }`
590 Inline { items: Box<[ModItem]> },
591
592 /// `mod m;`
593 Outline {},
594}
595
596#[derive(Debug, Clone, Eq, PartialEq)]
597pub struct MacroCall {
598 /// For `macro_rules!` declarations, this is the name of the declared macro.
599 pub name: Option<Name>,
600 /// Path to the called macro.
601 pub path: ModPath,
602 /// Has `#[macro_export]`.
603 pub is_export: bool,
604 /// Has `#[macro_export(local_inner_macros)]`.
605 pub is_local_inner: bool,
606 /// Has `#[rustc_builtin_macro]`.
607 pub is_builtin: bool,
608 pub ast_id: FileAstId<ast::MacroCall>,
609}
610
611// NB: There's no `FileAstId` for `Expr`. The only case where this would be useful is for array
612// lengths, but we don't do much with them yet.
613#[derive(Debug, Clone, Eq, PartialEq)]
614pub struct Expr;
615
616macro_rules! impl_froms {
617 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
618 $(
619 impl From<$t> for $e {
620 fn from(it: $t) -> $e {
621 $e::$v(it)
622 }
623 }
624 )*
625 }
626}
627
628impl ModItem {
629 pub fn as_assoc_item(&self) -> Option<AssocItem> {
630 match self {
631 ModItem::Import(_)
632 | ModItem::ExternCrate(_)
633 | ModItem::Struct(_)
634 | ModItem::Union(_)
635 | ModItem::Enum(_)
636 | ModItem::Static(_)
637 | ModItem::Trait(_)
638 | ModItem::Impl(_)
639 | ModItem::Mod(_) => None,
640 ModItem::MacroCall(call) => Some(AssocItem::MacroCall(*call)),
641 ModItem::Const(konst) => Some(AssocItem::Const(*konst)),
642 ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(*alias)),
643 ModItem::Function(func) => Some(AssocItem::Function(*func)),
644 }
645 }
646
647 pub fn downcast<N: ItemTreeNode>(self) -> Option<FileItemTreeId<N>> {
648 N::id_from_mod_item(self)
649 }
650}
651
652#[derive(Debug, Copy, Clone, Eq, PartialEq)]
653pub enum AssocItem {
654 Function(FileItemTreeId<Function>),
655 TypeAlias(FileItemTreeId<TypeAlias>),
656 Const(FileItemTreeId<Const>),
657 MacroCall(FileItemTreeId<MacroCall>),
658}
659
660impl_froms!(AssocItem {
661 Function(FileItemTreeId<Function>),
662 TypeAlias(FileItemTreeId<TypeAlias>),
663 Const(FileItemTreeId<Const>),
664 MacroCall(FileItemTreeId<MacroCall>),
665});
666
667impl From<AssocItem> for ModItem {
668 fn from(item: AssocItem) -> Self {
669 match item {
670 AssocItem::Function(it) => it.into(),
671 AssocItem::TypeAlias(it) => it.into(),
672 AssocItem::Const(it) => it.into(),
673 AssocItem::MacroCall(it) => it.into(),
674 }
675 }
676}
677
678#[derive(Debug, Eq, PartialEq)]
679pub struct Variant {
680 pub name: Name,
681 pub fields: Fields,
682}
683
684#[derive(Debug, Clone, PartialEq, Eq)]
685pub enum Fields {
686 Record(Range<Idx<Field>>),
687 Tuple(Range<Idx<Field>>),
688 Unit,
689}
690
691/// A single field of an enum variant or struct
692#[derive(Debug, Clone, PartialEq, Eq)]
693pub struct Field {
694 pub name: Name,
695 pub type_ref: TypeRef,
696 pub visibility: RawVisibilityId,
697}
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
new file mode 100644
index 000000000..f10ad25f7
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -0,0 +1,695 @@
1//! AST -> `ItemTree` lowering code.
2
3use super::*;
4use crate::{
5 attr::Attrs,
6 generics::{GenericParams, TypeParamData, TypeParamProvenance},
7};
8use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, HirFileId};
9use ra_arena::map::ArenaMap;
10use ra_syntax::{
11 ast::{self, ModuleItemOwner},
12 SyntaxNode,
13};
14use smallvec::SmallVec;
15use std::{collections::hash_map::Entry, mem, sync::Arc};
16
17fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
18 FileItemTreeId { index, _p: PhantomData }
19}
20
21struct ModItems(SmallVec<[ModItem; 1]>);
22
23impl<T> From<T> for ModItems
24where
25 T: Into<ModItem>,
26{
27 fn from(t: T) -> Self {
28 ModItems(SmallVec::from_buf([t.into(); 1]))
29 }
30}
31
32pub(super) struct Ctx {
33 tree: ItemTree,
34 hygiene: Hygiene,
35 file: HirFileId,
36 source_ast_id_map: Arc<AstIdMap>,
37 body_ctx: crate::body::LowerCtx,
38 inner_items: Vec<ModItem>,
39 forced_visibility: Option<RawVisibilityId>,
40}
41
42impl Ctx {
43 pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
44 Self {
45 tree: ItemTree::empty(),
46 hygiene,
47 file,
48 source_ast_id_map: db.ast_id_map(file),
49 body_ctx: crate::body::LowerCtx::new(db, file),
50 inner_items: Vec::new(),
51 forced_visibility: None,
52 }
53 }
54
55 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
56 self.tree.top_level = item_owner
57 .items()
58 .flat_map(|item| self.lower_mod_item(&item, false))
59 .flat_map(|items| items.0)
60 .collect();
61 self.tree
62 }
63
64 pub(super) fn lower_inner_items(mut self, within: &SyntaxNode) -> ItemTree {
65 self.collect_inner_items(within);
66 self.tree
67 }
68
69 fn data(&mut self) -> &mut ItemTreeData {
70 self.tree.data_mut()
71 }
72
73 fn lower_mod_item(&mut self, item: &ast::ModuleItem, inner: bool) -> Option<ModItems> {
74 assert!(inner || self.inner_items.is_empty());
75
76 // Collect inner items for 1-to-1-lowered items.
77 match item {
78 ast::ModuleItem::StructDef(_)
79 | ast::ModuleItem::UnionDef(_)
80 | ast::ModuleItem::EnumDef(_)
81 | ast::ModuleItem::FnDef(_)
82 | ast::ModuleItem::TypeAliasDef(_)
83 | ast::ModuleItem::ConstDef(_)
84 | ast::ModuleItem::StaticDef(_)
85 | ast::ModuleItem::MacroCall(_) => {
86 // Skip this if we're already collecting inner items. We'll descend into all nodes
87 // already.
88 if !inner {
89 self.collect_inner_items(item.syntax());
90 }
91 }
92
93 // These are handled in their respective `lower_X` method (since we can't just blindly
94 // walk them).
95 ast::ModuleItem::TraitDef(_)
96 | ast::ModuleItem::ImplDef(_)
97 | ast::ModuleItem::ExternBlock(_) => {}
98
99 // These don't have inner items.
100 ast::ModuleItem::Module(_)
101 | ast::ModuleItem::ExternCrateItem(_)
102 | ast::ModuleItem::UseItem(_) => {}
103 };
104
105 let attrs = Attrs::new(item, &self.hygiene);
106 let items = match item {
107 ast::ModuleItem::StructDef(ast) => self.lower_struct(ast).map(Into::into),
108 ast::ModuleItem::UnionDef(ast) => self.lower_union(ast).map(Into::into),
109 ast::ModuleItem::EnumDef(ast) => self.lower_enum(ast).map(Into::into),
110 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into),
111 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into),
112 ast::ModuleItem::StaticDef(ast) => self.lower_static(ast).map(Into::into),
113 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()),
114 ast::ModuleItem::Module(ast) => self.lower_module(ast).map(Into::into),
115 ast::ModuleItem::TraitDef(ast) => self.lower_trait(ast).map(Into::into),
116 ast::ModuleItem::ImplDef(ast) => self.lower_impl(ast).map(Into::into),
117 ast::ModuleItem::UseItem(ast) => Some(ModItems(
118 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(),
119 )),
120 ast::ModuleItem::ExternCrateItem(ast) => self.lower_extern_crate(ast).map(Into::into),
121 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
122 ast::ModuleItem::ExternBlock(ast) => {
123 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
124 }
125 };
126
127 if !attrs.is_empty() {
128 for item in items.iter().flat_map(|items| &items.0) {
129 self.add_attrs(*item, attrs.clone());
130 }
131 }
132
133 items
134 }
135
136 fn add_attrs(&mut self, item: ModItem, attrs: Attrs) {
137 match self.tree.attrs.entry(AttrOwner::ModItem(item)) {
138 Entry::Occupied(mut entry) => {
139 *entry.get_mut() = entry.get().merge(attrs);
140 }
141 Entry::Vacant(entry) => {
142 entry.insert(attrs);
143 }
144 }
145 }
146
147 fn collect_inner_items(&mut self, container: &SyntaxNode) {
148 let forced_vis = self.forced_visibility.take();
149 let mut inner_items = mem::take(&mut self.tree.inner_items);
150 inner_items.extend(
151 container.descendants().skip(1).filter_map(ast::ModuleItem::cast).filter_map(|item| {
152 let ast_id = self.source_ast_id_map.ast_id(&item);
153 Some((ast_id, self.lower_mod_item(&item, true)?.0))
154 }),
155 );
156 self.tree.inner_items = inner_items;
157 self.forced_visibility = forced_vis;
158 }
159
160 fn lower_assoc_item(&mut self, item: &ast::ModuleItem) -> Option<AssocItem> {
161 match item {
162 ast::ModuleItem::FnDef(ast) => self.lower_function(ast).map(Into::into),
163 ast::ModuleItem::TypeAliasDef(ast) => self.lower_type_alias(ast).map(Into::into),
164 ast::ModuleItem::ConstDef(ast) => Some(self.lower_const(ast).into()),
165 ast::ModuleItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
166 _ => None,
167 }
168 }
169
170 fn lower_struct(&mut self, strukt: &ast::StructDef) -> Option<FileItemTreeId<Struct>> {
171 let visibility = self.lower_visibility(strukt);
172 let name = strukt.name()?.as_name();
173 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
174 let fields = self.lower_fields(&strukt.kind());
175 let ast_id = self.source_ast_id_map.ast_id(strukt);
176 let kind = match strukt.kind() {
177 ast::StructKind::Record(_) => StructDefKind::Record,
178 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
179 ast::StructKind::Unit => StructDefKind::Unit,
180 };
181 let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
182 Some(id(self.data().structs.alloc(res)))
183 }
184
185 fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
186 match strukt_kind {
187 ast::StructKind::Record(it) => {
188 let range = self.lower_record_fields(it);
189 Fields::Record(range)
190 }
191 ast::StructKind::Tuple(it) => {
192 let range = self.lower_tuple_fields(it);
193 Fields::Tuple(range)
194 }
195 ast::StructKind::Unit => Fields::Unit,
196 }
197 }
198
199 fn lower_record_fields(&mut self, fields: &ast::RecordFieldDefList) -> Range<Idx<Field>> {
200 let start = self.next_field_idx();
201 for field in fields.fields() {
202 if let Some(data) = self.lower_record_field(&field) {
203 self.data().fields.alloc(data);
204 }
205 }
206 let end = self.next_field_idx();
207 start..end
208 }
209
210 fn lower_record_field(&mut self, field: &ast::RecordFieldDef) -> Option<Field> {
211 let name = field.name()?.as_name();
212 let visibility = self.lower_visibility(field);
213 let type_ref = self.lower_type_ref(&field.ascribed_type()?);
214 let res = Field { name, type_ref, visibility };
215 Some(res)
216 }
217
218 fn lower_tuple_fields(&mut self, fields: &ast::TupleFieldDefList) -> Range<Idx<Field>> {
219 let start = self.next_field_idx();
220 for (i, field) in fields.fields().enumerate() {
221 if let Some(data) = self.lower_tuple_field(i, &field) {
222 self.data().fields.alloc(data);
223 }
224 }
225 let end = self.next_field_idx();
226 start..end
227 }
228
229 fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleFieldDef) -> Option<Field> {
230 let name = Name::new_tuple_field(idx);
231 let visibility = self.lower_visibility(field);
232 let type_ref = self.lower_type_ref(&field.type_ref()?);
233 let res = Field { name, type_ref, visibility };
234 Some(res)
235 }
236
237 fn lower_union(&mut self, union: &ast::UnionDef) -> Option<FileItemTreeId<Union>> {
238 let visibility = self.lower_visibility(union);
239 let name = union.name()?.as_name();
240 let generic_params = self.lower_generic_params(GenericsOwner::Union, union);
241 let fields = match union.record_field_def_list() {
242 Some(record_field_def_list) => {
243 self.lower_fields(&StructKind::Record(record_field_def_list))
244 }
245 None => Fields::Record(self.next_field_idx()..self.next_field_idx()),
246 };
247 let ast_id = self.source_ast_id_map.ast_id(union);
248 let res = Union { name, visibility, generic_params, fields, ast_id };
249 Some(id(self.data().unions.alloc(res)))
250 }
251
252 fn lower_enum(&mut self, enum_: &ast::EnumDef) -> Option<FileItemTreeId<Enum>> {
253 let visibility = self.lower_visibility(enum_);
254 let name = enum_.name()?.as_name();
255 let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_);
256 let variants = match &enum_.variant_list() {
257 Some(variant_list) => self.lower_variants(variant_list),
258 None => self.next_variant_idx()..self.next_variant_idx(),
259 };
260 let ast_id = self.source_ast_id_map.ast_id(enum_);
261 let res = Enum { name, visibility, generic_params, variants, ast_id };
262 Some(id(self.data().enums.alloc(res)))
263 }
264
265 fn lower_variants(&mut self, variants: &ast::EnumVariantList) -> Range<Idx<Variant>> {
266 let start = self.next_variant_idx();
267 for variant in variants.variants() {
268 if let Some(data) = self.lower_variant(&variant) {
269 self.data().variants.alloc(data);
270 }
271 }
272 let end = self.next_variant_idx();
273 start..end
274 }
275
276 fn lower_variant(&mut self, variant: &ast::EnumVariant) -> Option<Variant> {
277 let name = variant.name()?.as_name();
278 let fields = self.lower_fields(&variant.kind());
279 let res = Variant { name, fields };
280 Some(res)
281 }
282
283 fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Function>> {
284 let visibility = self.lower_visibility(func);
285 let name = func.name()?.as_name();
286
287 let mut params = Vec::new();
288 let mut has_self_param = false;
289 if let Some(param_list) = func.param_list() {
290 if let Some(self_param) = param_list.self_param() {
291 let self_type = match self_param.ascribed_type() {
292 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
293 None => {
294 let self_type = TypeRef::Path(name![Self].into());
295 match self_param.kind() {
296 ast::SelfParamKind::Owned => self_type,
297 ast::SelfParamKind::Ref => {
298 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
299 }
300 ast::SelfParamKind::MutRef => {
301 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
302 }
303 }
304 }
305 };
306 params.push(self_type);
307 has_self_param = true;
308 }
309 for param in param_list.params() {
310 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ascribed_type());
311 params.push(type_ref);
312 }
313 }
314 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) {
315 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
316 _ => TypeRef::unit(),
317 };
318
319 let ret_type = if func.async_token().is_some() {
320 let future_impl = desugar_future_path(ret_type);
321 let ty_bound = TypeBound::Path(future_impl);
322 TypeRef::ImplTrait(vec![ty_bound])
323 } else {
324 ret_type
325 };
326
327 let ast_id = self.source_ast_id_map.ast_id(func);
328 let mut res = Function {
329 name,
330 visibility,
331 generic_params: GenericParamsId::EMPTY,
332 has_self_param,
333 is_unsafe: func.unsafe_token().is_some(),
334 params: params.into_boxed_slice(),
335 ret_type,
336 ast_id,
337 };
338 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
339
340 Some(id(self.data().functions.alloc(res)))
341 }
342
343 fn lower_type_alias(
344 &mut self,
345 type_alias: &ast::TypeAliasDef,
346 ) -> Option<FileItemTreeId<TypeAlias>> {
347 let name = type_alias.name()?.as_name();
348 let type_ref = type_alias.type_ref().map(|it| self.lower_type_ref(&it));
349 let visibility = self.lower_visibility(type_alias);
350 let bounds = self.lower_type_bounds(type_alias);
351 let generic_params = self.lower_generic_params(GenericsOwner::TypeAlias, type_alias);
352 let ast_id = self.source_ast_id_map.ast_id(type_alias);
353 let res = TypeAlias {
354 name,
355 visibility,
356 bounds: bounds.into_boxed_slice(),
357 generic_params,
358 type_ref,
359 ast_id,
360 };
361 Some(id(self.data().type_aliases.alloc(res)))
362 }
363
364 fn lower_static(&mut self, static_: &ast::StaticDef) -> Option<FileItemTreeId<Static>> {
365 let name = static_.name()?.as_name();
366 let type_ref = self.lower_type_ref_opt(static_.ascribed_type());
367 let visibility = self.lower_visibility(static_);
368 let mutable = static_.mut_token().is_some();
369 let ast_id = self.source_ast_id_map.ast_id(static_);
370 let res = Static { name, visibility, mutable, type_ref, ast_id };
371 Some(id(self.data().statics.alloc(res)))
372 }
373
374 fn lower_const(&mut self, konst: &ast::ConstDef) -> FileItemTreeId<Const> {
375 let name = konst.name().map(|it| it.as_name());
376 let type_ref = self.lower_type_ref_opt(konst.ascribed_type());
377 let visibility = self.lower_visibility(konst);
378 let ast_id = self.source_ast_id_map.ast_id(konst);
379 let res = Const { name, visibility, type_ref, ast_id };
380 id(self.data().consts.alloc(res))
381 }
382
383 fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
384 let name = module.name()?.as_name();
385 let visibility = self.lower_visibility(module);
386 let kind = if module.semicolon_token().is_some() {
387 ModKind::Outline {}
388 } else {
389 ModKind::Inline {
390 items: module
391 .item_list()
392 .map(|list| {
393 list.items()
394 .flat_map(|item| self.lower_mod_item(&item, false))
395 .flat_map(|items| items.0)
396 .collect()
397 })
398 .unwrap_or_else(|| {
399 mark::hit!(name_res_works_for_broken_modules);
400 Box::new([]) as Box<[_]>
401 }),
402 }
403 };
404 let ast_id = self.source_ast_id_map.ast_id(module);
405 let res = Mod { name, visibility, kind, ast_id };
406 Some(id(self.data().mods.alloc(res)))
407 }
408
409 fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option<FileItemTreeId<Trait>> {
410 let name = trait_def.name()?.as_name();
411 let visibility = self.lower_visibility(trait_def);
412 let generic_params =
413 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
414 let auto = trait_def.auto_token().is_some();
415 let items = trait_def.item_list().map(|list| {
416 self.with_inherited_visibility(visibility, |this| {
417 list.items()
418 .filter_map(|item| {
419 let attrs = Attrs::new(&item, &this.hygiene);
420 this.collect_inner_items(item.syntax());
421 this.lower_assoc_item(&item).map(|item| {
422 this.add_attrs(item.into(), attrs);
423 item
424 })
425 })
426 .collect()
427 })
428 });
429 let ast_id = self.source_ast_id_map.ast_id(trait_def);
430 let res = Trait {
431 name,
432 visibility,
433 generic_params,
434 auto,
435 items: items.unwrap_or_default(),
436 ast_id,
437 };
438 Some(id(self.data().traits.alloc(res)))
439 }
440
441 fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option<FileItemTreeId<Impl>> {
442 let generic_params =
443 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
444 let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr));
445 let target_type = self.lower_type_ref(&impl_def.target_type()?);
446 let is_negative = impl_def.excl_token().is_some();
447
448 // We cannot use `assoc_items()` here as that does not include macro calls.
449 let items = impl_def
450 .item_list()?
451 .items()
452 .filter_map(|item| {
453 self.collect_inner_items(item.syntax());
454 let assoc = self.lower_assoc_item(&item)?;
455 let attrs = Attrs::new(&item, &self.hygiene);
456 self.add_attrs(assoc.into(), attrs);
457 Some(assoc)
458 })
459 .collect();
460 let ast_id = self.source_ast_id_map.ast_id(impl_def);
461 let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id };
462 Some(id(self.data().impls.alloc(res)))
463 }
464
465 fn lower_use(&mut self, use_item: &ast::UseItem) -> Vec<FileItemTreeId<Import>> {
466 // FIXME: cfg_attr
467 let is_prelude = use_item.has_atom_attr("prelude_import");
468 let visibility = self.lower_visibility(use_item);
469 let ast_id = self.source_ast_id_map.ast_id(use_item);
470
471 // Every use item can expand to many `Import`s.
472 let mut imports = Vec::new();
473 let tree = self.tree.data_mut();
474 ModPath::expand_use_item(
475 InFile::new(self.file, use_item.clone()),
476 &self.hygiene,
477 |path, _tree, is_glob, alias| {
478 imports.push(id(tree.imports.alloc(Import {
479 path,
480 alias,
481 visibility,
482 is_glob,
483 is_prelude,
484 ast_id,
485 })));
486 },
487 );
488
489 imports
490 }
491
492 fn lower_extern_crate(
493 &mut self,
494 extern_crate: &ast::ExternCrateItem,
495 ) -> Option<FileItemTreeId<ExternCrate>> {
496 let path = ModPath::from_name_ref(&extern_crate.name_ref()?);
497 let alias = extern_crate.alias().map(|a| {
498 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
499 });
500 let visibility = self.lower_visibility(extern_crate);
501 let ast_id = self.source_ast_id_map.ast_id(extern_crate);
502 // FIXME: cfg_attr
503 let is_macro_use = extern_crate.has_atom_attr("macro_use");
504
505 let res = ExternCrate { path, alias, visibility, is_macro_use, ast_id };
506 Some(id(self.data().extern_crates.alloc(res)))
507 }
508
509 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
510 let name = m.name().map(|it| it.as_name());
511 let attrs = Attrs::new(m, &self.hygiene);
512 let path = ModPath::from_src(m.path()?, &self.hygiene)?;
513
514 let ast_id = self.source_ast_id_map.ast_id(m);
515
516 // FIXME: cfg_attr
517 let export_attr = attrs.by_key("macro_export");
518
519 let is_export = export_attr.exists();
520 let is_local_inner = if is_export {
521 export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it {
522 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
523 ident.text.contains("local_inner_macros")
524 }
525 _ => false,
526 })
527 } else {
528 false
529 };
530
531 let is_builtin = attrs.by_key("rustc_builtin_macro").exists();
532 let res = MacroCall { name, path, is_export, is_builtin, is_local_inner, ast_id };
533 Some(id(self.data().macro_calls.alloc(res)))
534 }
535
536 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> {
537 block.extern_item_list().map_or(Vec::new(), |list| {
538 list.extern_items()
539 .filter_map(|item| {
540 self.collect_inner_items(item.syntax());
541 let attrs = Attrs::new(&item, &self.hygiene);
542 let id = match item {
543 ast::ExternItem::FnDef(ast) => {
544 let func = self.lower_function(&ast)?;
545 func.into()
546 }
547 ast::ExternItem::StaticDef(ast) => {
548 let statik = self.lower_static(&ast)?;
549 statik.into()
550 }
551 };
552 self.add_attrs(id, attrs);
553 Some(id)
554 })
555 .collect()
556 })
557 }
558
559 /// Lowers generics defined on `node` and collects inner items defined within.
560 fn lower_generic_params_and_inner_items(
561 &mut self,
562 owner: GenericsOwner<'_>,
563 node: &impl ast::TypeParamsOwner,
564 ) -> GenericParamsId {
565 // Generics are part of item headers and may contain inner items we need to collect.
566 if let Some(params) = node.type_param_list() {
567 self.collect_inner_items(params.syntax());
568 }
569 if let Some(clause) = node.where_clause() {
570 self.collect_inner_items(clause.syntax());
571 }
572
573 self.lower_generic_params(owner, node)
574 }
575
576 fn lower_generic_params(
577 &mut self,
578 owner: GenericsOwner<'_>,
579 node: &impl ast::TypeParamsOwner,
580 ) -> GenericParamsId {
581 let mut sm = &mut ArenaMap::default();
582 let mut generics = GenericParams::default();
583 match owner {
584 GenericsOwner::Function(func) => {
585 generics.fill(&self.body_ctx, sm, node);
586 // lower `impl Trait` in arguments
587 for param in &*func.params {
588 generics.fill_implicit_impl_trait_args(param);
589 }
590 }
591 GenericsOwner::Struct
592 | GenericsOwner::Enum
593 | GenericsOwner::Union
594 | GenericsOwner::TypeAlias => {
595 generics.fill(&self.body_ctx, sm, node);
596 }
597 GenericsOwner::Trait(trait_def) => {
598 // traits get the Self type as an implicit first type parameter
599 let self_param_id = generics.types.alloc(TypeParamData {
600 name: Some(name![Self]),
601 default: None,
602 provenance: TypeParamProvenance::TraitSelf,
603 });
604 sm.insert(self_param_id, Either::Left(trait_def.clone()));
605 // add super traits as bounds on Self
606 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
607 let self_param = TypeRef::Path(name![Self].into());
608 generics.fill_bounds(&self.body_ctx, trait_def, self_param);
609
610 generics.fill(&self.body_ctx, &mut sm, node);
611 }
612 GenericsOwner::Impl => {
613 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
614 // type-parameter, but rather is a type-alias for impl's target
615 // type, so this is handled by the resolver.
616 generics.fill(&self.body_ctx, &mut sm, node);
617 }
618 }
619
620 self.data().generics.alloc(generics)
621 }
622
623 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> {
624 match node.type_bound_list() {
625 Some(bound_list) => {
626 bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect()
627 }
628 None => Vec::new(),
629 }
630 }
631
632 fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
633 let vis = match self.forced_visibility {
634 Some(vis) => return vis,
635 None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene),
636 };
637
638 self.data().vis.alloc(vis)
639 }
640
641 fn lower_type_ref(&self, type_ref: &ast::TypeRef) -> TypeRef {
642 TypeRef::from_ast(&self.body_ctx, type_ref.clone())
643 }
644 fn lower_type_ref_opt(&self, type_ref: Option<ast::TypeRef>) -> TypeRef {
645 type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error)
646 }
647
648 /// Forces the visibility `vis` to be used for all items lowered during execution of `f`.
649 fn with_inherited_visibility<R>(
650 &mut self,
651 vis: RawVisibilityId,
652 f: impl FnOnce(&mut Self) -> R,
653 ) -> R {
654 let old = mem::replace(&mut self.forced_visibility, Some(vis));
655 let res = f(self);
656 self.forced_visibility = old;
657 res
658 }
659
660 fn next_field_idx(&self) -> Idx<Field> {
661 Idx::from_raw(RawId::from(
662 self.tree.data.as_ref().map_or(0, |data| data.fields.len() as u32),
663 ))
664 }
665 fn next_variant_idx(&self) -> Idx<Variant> {
666 Idx::from_raw(RawId::from(
667 self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
668 ))
669 }
670}
671
672fn desugar_future_path(orig: TypeRef) -> Path {
673 let path = path![core::future::Future];
674 let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect();
675 let mut last = GenericArgs::empty();
676 let binding =
677 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
678 last.bindings.push(binding);
679 generic_args.push(Some(Arc::new(last)));
680
681 Path::from_known_path(path, generic_args)
682}
683
684enum GenericsOwner<'a> {
685 /// We need access to the partially-lowered `Function` for lowering `impl Trait` in argument
686 /// position.
687 Function(&'a Function),
688 Struct,
689 Enum,
690 Union,
691 /// The `TraitDef` is needed to fill the source map for the implicit `Self` parameter.
692 Trait(&'a ast::TraitDef),
693 TypeAlias,
694 Impl,
695}
diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs
new file mode 100644
index 000000000..dc035d809
--- /dev/null
+++ b/crates/ra_hir_def/src/item_tree/tests.rs
@@ -0,0 +1,435 @@
1use super::{ItemTree, ModItem, ModKind};
2use crate::{db::DefDatabase, test_db::TestDB};
3use hir_expand::{db::AstDatabase, HirFileId, InFile};
4use insta::assert_snapshot;
5use ra_db::fixture::WithFixture;
6use ra_syntax::{ast, AstNode};
7use rustc_hash::FxHashSet;
8use std::sync::Arc;
9use stdx::format_to;
10
11fn test_inner_items(ra_fixture: &str) {
12 let (db, file_id) = TestDB::with_single_file(ra_fixture