Skip to content

Commit c5f6742

Browse files
committed
Rust: crate_graph: generate 'use' statements for re-exported items
1 parent c3bc651 commit c5f6742

File tree

1 file changed

+107
-4
lines changed

1 file changed

+107
-4
lines changed

rust/extractor/src/crate_graph.rs

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ use ra_ap_base_db::CrateGraph;
1111
use ra_ap_base_db::CrateId;
1212
use ra_ap_base_db::SourceDatabase;
1313
use ra_ap_cfg::CfgAtom;
14-
use ra_ap_hir::{DefMap, ModuleDefId, db::HirDatabase};
14+
use ra_ap_hir::{DefMap, ModuleDefId, PathKind, db::HirDatabase};
1515
use ra_ap_hir::{VariantId, Visibility, db::DefDatabase};
16-
use ra_ap_hir_def::{AssocItemId, LocalModuleId, data::adt::VariantData, nameres::ModuleData};
16+
use ra_ap_hir_def::Lookup;
17+
use ra_ap_hir_def::{
18+
AssocItemId, LocalModuleId, data::adt::VariantData, item_scope::ImportOrGlob,
19+
item_tree::ImportKind, nameres::ModuleData, path::ImportAlias,
20+
};
1721
use ra_ap_hir_def::{HasModule, visibility::VisibilityExplicitness};
1822
use ra_ap_hir_def::{ModuleId, resolver::HasResolver};
1923
use ra_ap_hir_ty::TraitRefExt;
@@ -24,6 +28,7 @@ use ra_ap_hir_ty::{Binders, FnPointer};
2428
use ra_ap_hir_ty::{Interner, ProjectionTy};
2529
use ra_ap_ide_db::RootDatabase;
2630
use ra_ap_vfs::{Vfs, VfsPath};
31+
2732
use std::hash::Hasher;
2833
use std::{cmp::Ordering, collections::HashMap, path::PathBuf};
2934
use std::{hash::Hash, vec};
@@ -178,20 +183,106 @@ fn emit_module_children(
178183
.collect()
179184
}
180185

186+
fn emit_reexport(
187+
db: &dyn HirDatabase,
188+
trap: &mut TrapFile,
189+
uses: &mut HashMap<String, trap::Label<generated::Item>>,
190+
import: ImportOrGlob,
191+
name: &str,
192+
) {
193+
let (use_, idx) = match import {
194+
ImportOrGlob::Glob(import) => (import.use_, import.idx),
195+
ImportOrGlob::Import(import) => (import.use_, import.idx),
196+
};
197+
let def_db = db.upcast();
198+
let loc = use_.lookup(def_db);
199+
let use_ = &loc.id.item_tree(def_db)[loc.id.value];
200+
201+
use_.use_tree.expand(|id, path, kind, alias| {
202+
if id == idx {
203+
let mut path_components = Vec::new();
204+
match path.kind {
205+
PathKind::Plain => (),
206+
PathKind::Super(0) => path_components.push("self".to_owned()),
207+
PathKind::Super(n) => {
208+
path_components.extend(std::iter::repeat_n("parent".to_owned(), n.into()));
209+
}
210+
PathKind::Crate => path_components.push("crate".to_owned()),
211+
PathKind::Abs => path_components.push("".to_owned()),
212+
PathKind::DollarCrate(_) => path_components.push("$crate".to_owned()),
213+
}
214+
path_components.extend(path.segments().iter().map(|x| x.as_str().to_owned()));
215+
match kind {
216+
ImportKind::Plain => (),
217+
ImportKind::Glob => path_components.push(name.to_owned()),
218+
ImportKind::TypeOnly => path_components.push("self".to_owned()),
219+
};
220+
let key = path_components.join("::");
221+
// prevent duplicate imports
222+
if uses.contains_key(&key) {
223+
return;
224+
}
225+
226+
let alias = alias.map(|alias| match alias {
227+
ImportAlias::Underscore => "_".to_owned(),
228+
ImportAlias::Alias(name) => name.as_str().to_owned(),
229+
});
230+
let rename = alias.map(|name| {
231+
let name = Some(trap.emit(generated::Name {
232+
id: trap::TrapId::Star,
233+
text: Some(name),
234+
}));
235+
trap.emit(generated::Rename {
236+
id: trap::TrapId::Star,
237+
name,
238+
})
239+
});
240+
let path = make_qualified_path(trap, path_components);
241+
let use_tree = trap.emit(generated::UseTree {
242+
id: trap::TrapId::Star,
243+
is_glob: false,
244+
path,
245+
rename,
246+
use_tree_list: None,
247+
});
248+
let visibility = emit_visibility(db, trap, Visibility::Public);
249+
uses.insert(
250+
key,
251+
trap.emit(generated::Use {
252+
id: trap::TrapId::Star,
253+
attrs: vec![],
254+
use_tree: Some(use_tree),
255+
visibility,
256+
})
257+
.into(),
258+
);
259+
}
260+
});
261+
}
262+
181263
fn emit_module_items(
182264
crate_graph: &CrateGraph,
183265
db: &dyn HirDatabase,
184266
module: &ModuleData,
185267
trap: &mut TrapFile,
186268
) -> Vec<trap::Label<generated::Item>> {
187269
let mut items = Vec::new();
270+
let mut uses = HashMap::new();
188271
let item_scope = &module.scope;
189272
for (name, item) in item_scope.entries() {
190273
let def = item.filter_visibility(|x| matches!(x, ra_ap_hir::Visibility::Public));
274+
if let Some(ra_ap_hir_def::per_ns::Item {
275+
def: _,
276+
vis: _,
277+
import: Some(import),
278+
}) = def.values
279+
{
280+
emit_reexport(db, trap, &mut uses, import, name.as_str());
281+
}
191282
if let Some(ra_ap_hir_def::per_ns::Item {
192283
def: value,
193284
vis,
194-
import: _,
285+
import: None,
195286
}) = def.values
196287
{
197288
match value {
@@ -231,10 +322,21 @@ fn emit_module_items(
231322
_ => (),
232323
}
233324
}
325+
if let Some(ra_ap_hir_def::per_ns::Item {
326+
def: _,
327+
vis: _,
328+
import: Some(import),
329+
}) = def.types
330+
{
331+
// TODO: handle ExternCrate as well?
332+
if let Some(import) = import.import_or_glob() {
333+
emit_reexport(db, trap, &mut uses, import, name.as_str());
334+
}
335+
}
234336
if let Some(ra_ap_hir_def::per_ns::Item {
235337
def: type_id,
236338
vis,
237-
import: _,
339+
import: None,
238340
}) = def.types
239341
{
240342
match type_id {
@@ -255,6 +357,7 @@ fn emit_module_items(
255357
}
256358
}
257359
}
360+
items.extend(uses.values());
258361
items
259362
}
260363

0 commit comments

Comments
 (0)