Skip to content

Commit 4dfe759

Browse files
authored
Merge pull request #19113 from github/aibaars/crate-graph-reexport
Rust: crate_graph: generate 'use' statements for re-exported items
2 parents 840abbf + ec9fe80 commit 4dfe759

File tree

15 files changed

+254
-35
lines changed

15 files changed

+254
-35
lines changed

rust/extractor/src/crate_graph.rs

+118-4
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ use chalk_ir::{FloatTy, Safety};
99
use itertools::Itertools;
1010
use ra_ap_base_db::{Crate, RootQueryDb};
1111
use ra_ap_cfg::CfgAtom;
12-
use ra_ap_hir::{DefMap, ModuleDefId, db::HirDatabase};
12+
use ra_ap_hir::{DefMap, ModuleDefId, PathKind, db::HirDatabase};
1313
use ra_ap_hir::{VariantId, Visibility, db::DefDatabase};
14-
use ra_ap_hir_def::{AssocItemId, LocalModuleId, data::adt::VariantData, nameres::ModuleData};
14+
use ra_ap_hir_def::Lookup;
15+
use ra_ap_hir_def::{
16+
AssocItemId, LocalModuleId, data::adt::VariantData, item_scope::ImportOrGlob,
17+
item_tree::ImportKind, nameres::ModuleData, path::ImportAlias,
18+
};
1519
use ra_ap_hir_def::{HasModule, visibility::VisibilityExplicitness};
1620
use ra_ap_hir_def::{ModuleId, resolver::HasResolver};
1721
use ra_ap_hir_ty::TraitRefExt;
@@ -22,6 +26,7 @@ use ra_ap_hir_ty::{Binders, FnPointer};
2226
use ra_ap_hir_ty::{Interner, ProjectionTy};
2327
use ra_ap_ide_db::RootDatabase;
2428
use ra_ap_vfs::{Vfs, VfsPath};
29+
2530
use std::hash::Hasher;
2631
use std::{cmp::Ordering, collections::HashMap, path::PathBuf};
2732
use std::{hash::Hash, vec};
@@ -172,19 +177,116 @@ fn emit_module_children(
172177
.collect()
173178
}
174179

180+
fn emit_reexport(
181+
db: &dyn HirDatabase,
182+
trap: &mut TrapFile,
183+
uses: &mut HashMap<String, trap::Label<generated::Item>>,
184+
import: ImportOrGlob,
185+
name: &str,
186+
) {
187+
let (use_, idx) = match import {
188+
ImportOrGlob::Glob(import) => (import.use_, import.idx),
189+
ImportOrGlob::Import(import) => (import.use_, import.idx),
190+
};
191+
let def_db = db.upcast();
192+
let loc = use_.lookup(def_db);
193+
let use_ = &loc.id.item_tree(def_db)[loc.id.value];
194+
195+
use_.use_tree.expand(|id, path, kind, alias| {
196+
if id == idx {
197+
let mut path_components = Vec::new();
198+
match path.kind {
199+
PathKind::Plain => (),
200+
PathKind::Super(0) => path_components.push("self".to_owned()),
201+
PathKind::Super(n) => {
202+
path_components.extend(std::iter::repeat_n("super".to_owned(), n.into()));
203+
}
204+
PathKind::Crate => path_components.push("crate".to_owned()),
205+
PathKind::Abs => path_components.push("".to_owned()),
206+
PathKind::DollarCrate(crate_id) => {
207+
let crate_extra = crate_id.extra_data(db);
208+
let crate_name = crate_extra
209+
.display_name
210+
.as_ref()
211+
.map(|x| x.canonical_name().to_string());
212+
path_components.push(crate_name.unwrap_or("crate".to_owned()));
213+
}
214+
}
215+
path_components.extend(path.segments().iter().map(|x| x.as_str().to_owned()));
216+
match kind {
217+
ImportKind::Plain => (),
218+
ImportKind::Glob => path_components.push(name.to_owned()),
219+
ImportKind::TypeOnly => path_components.push("self".to_owned()),
220+
};
221+
222+
let alias = alias.map(|alias| match alias {
223+
ImportAlias::Underscore => "_".to_owned(),
224+
ImportAlias::Alias(name) => name.as_str().to_owned(),
225+
});
226+
let key = format!(
227+
"{} as {}",
228+
path_components.join("::"),
229+
alias.as_ref().unwrap_or(&"".to_owned())
230+
);
231+
// prevent duplicate imports
232+
if uses.contains_key(&key) {
233+
return;
234+
}
235+
let rename = alias.map(|name| {
236+
let name = Some(trap.emit(generated::Name {
237+
id: trap::TrapId::Star,
238+
text: Some(name),
239+
}));
240+
trap.emit(generated::Rename {
241+
id: trap::TrapId::Star,
242+
name,
243+
})
244+
});
245+
let path = make_qualified_path(trap, path_components);
246+
let use_tree = trap.emit(generated::UseTree {
247+
id: trap::TrapId::Star,
248+
is_glob: false,
249+
path,
250+
rename,
251+
use_tree_list: None,
252+
});
253+
let visibility = emit_visibility(db, trap, Visibility::Public);
254+
uses.insert(
255+
key,
256+
trap.emit(generated::Use {
257+
id: trap::TrapId::Star,
258+
attrs: vec![],
259+
use_tree: Some(use_tree),
260+
visibility,
261+
})
262+
.into(),
263+
);
264+
}
265+
});
266+
}
267+
175268
fn emit_module_items(
176269
db: &dyn HirDatabase,
177270
module: &ModuleData,
178271
trap: &mut TrapFile,
179272
) -> Vec<trap::Label<generated::Item>> {
180273
let mut items = Vec::new();
274+
let mut uses = HashMap::new();
181275
let item_scope = &module.scope;
182276
for (name, item) in item_scope.entries() {
183277
let def = item.filter_visibility(|x| matches!(x, ra_ap_hir::Visibility::Public));
278+
if let Some(ra_ap_hir_def::per_ns::Item {
279+
def: _,
280+
vis: _,
281+
import: Some(import),
282+
}) = def.values
283+
{
284+
emit_reexport(db, trap, &mut uses, import, name.as_str());
285+
}
184286
if let Some(ra_ap_hir_def::per_ns::Item {
185287
def: value,
186288
vis,
187-
import: _,
289+
import: None,
188290
}) = def.values
189291
{
190292
match value {
@@ -203,10 +305,21 @@ fn emit_module_items(
203305
_ => (),
204306
}
205307
}
308+
if let Some(ra_ap_hir_def::per_ns::Item {
309+
def: _,
310+
vis: _,
311+
import: Some(import),
312+
}) = def.types
313+
{
314+
// TODO: handle ExternCrate as well?
315+
if let Some(import) = import.import_or_glob() {
316+
emit_reexport(db, trap, &mut uses, import, name.as_str());
317+
}
318+
}
206319
if let Some(ra_ap_hir_def::per_ns::Item {
207320
def: type_id,
208321
vis,
209-
import: _,
322+
import: None,
210323
}) = def.types
211324
{
212325
match type_id {
@@ -220,6 +333,7 @@ fn emit_module_items(
220333
}
221334
}
222335
}
336+
items.extend(uses.values());
223337
items
224338
}
225339

rust/ql/.generated.list

-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/.gitattributes

-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/elements/internal/UseImpl.qll

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// generated by codegen, remove this comment if you wish to edit this file
21
/**
32
* This module provides a hand-modifiable wrapper around the generated class `Use`.
43
*
@@ -12,11 +11,14 @@ private import codeql.rust.elements.internal.generated.Use
1211
* be referenced directly.
1312
*/
1413
module Impl {
14+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1515
/**
1616
* A Use. For example:
1717
* ```rust
1818
* todo!()
1919
* ```
2020
*/
21-
class Use extends Generated::Use { }
21+
class Use extends Generated::Use {
22+
override string toStringImpl() { result = "use " + this.getUseTree() }
23+
}
2224
}

rust/ql/lib/codeql/rust/elements/internal/UseTreeImpl.qll

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// generated by codegen, remove this comment if you wish to edit this file
21
/**
32
* This module provides a hand-modifiable wrapper around the generated class `UseTree`.
43
*
@@ -12,6 +11,7 @@ private import codeql.rust.elements.internal.generated.UseTree
1211
* be referenced directly.
1312
*/
1413
module Impl {
14+
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1515
/**
1616
* A UseTree. For example:
1717
* ```rust
@@ -21,5 +21,19 @@ module Impl {
2121
* use std::collections::{self, HashMap, HashSet};
2222
* ```
2323
*/
24-
class UseTree extends Generated::UseTree { }
24+
class UseTree extends Generated::UseTree {
25+
override string toStringImpl() {
26+
result = strictconcat(int i | | this.toStringPart(i) order by i)
27+
}
28+
29+
private string toStringPart(int index) {
30+
result = this.getPath().toStringImpl() and index = 0
31+
or
32+
result = "::{...}" and this.hasUseTreeList() and index = 1
33+
or
34+
result = "::*" and this.isGlob() and index = 2
35+
or
36+
result = " as " + this.getRename().getName().getText() and index = 3
37+
}
38+
}
2539
}

rust/ql/test/extractor-tests/canonical_path/canonical_paths.expected

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
canonicalPaths
2-
| anonymous.rs:1:1:1:26 | Use | None | None |
2+
| anonymous.rs:1:1:1:26 | use ...::Trait | None | None |
33
| anonymous.rs:3:1:32:1 | fn canonicals | repo::test | crate::anonymous::canonicals |
44
| anonymous.rs:4:5:4:23 | struct OtherStruct | None | None |
55
| anonymous.rs:6:5:8:5 | trait OtherTrait | None | None |
@@ -33,7 +33,7 @@ canonicalPaths
3333
| regular.rs:34:1:38:1 | enum MyEnum | repo::test | crate::regular::MyEnum |
3434
| regular.rs:40:1:46:1 | fn enum_qualified_usage | repo::test | crate::regular::enum_qualified_usage |
3535
| regular.rs:48:1:55:1 | fn enum_unqualified_usage | repo::test | crate::regular::enum_unqualified_usage |
36-
| regular.rs:51:5:51:18 | Use | None | None |
36+
| regular.rs:51:5:51:18 | use MyEnum::* | None | None |
3737
| regular.rs:57:1:63:1 | fn enum_match | repo::test | crate::regular::enum_match |
3838
resolvedPaths
3939
| anonymous.rs:27:17:27:30 | OtherStruct {...} | None | None |

rust/ql/test/extractor-tests/canonical_path_disabled/canonical_paths.expected

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
canonicalPaths
2-
| anonymous.rs:4:1:4:26 | Use | None | None |
2+
| anonymous.rs:4:1:4:26 | use ...::Trait | None | None |
33
| anonymous.rs:6:1:35:1 | fn canonicals | None | None |
44
| anonymous.rs:7:5:7:23 | struct OtherStruct | None | None |
55
| anonymous.rs:9:5:11:5 | trait OtherTrait | None | None |
@@ -33,7 +33,7 @@ canonicalPaths
3333
| regular.rs:37:1:41:1 | enum MyEnum | None | None |
3434
| regular.rs:43:1:49:1 | fn enum_qualified_usage | None | None |
3535
| regular.rs:51:1:58:1 | fn enum_unqualified_usage | None | None |
36-
| regular.rs:54:5:54:18 | Use | None | None |
36+
| regular.rs:54:5:54:18 | use MyEnum::* | None | None |
3737
| regular.rs:60:1:66:1 | fn enum_match | None | None |
3838
resolvedPaths
3939
| anonymous.rs:30:17:30:30 | OtherStruct {...} | None | None |

rust/ql/test/extractor-tests/crate_graph/module.rs

+3
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@ impl fmt::Display for X {
4040

4141
pub const X_A: X = X::A;
4242
pub static X_B: X = X::B;
43+
44+
pub use std::fs::create_dir as mkdir;
45+
pub use std::{fs::*, path::PathBuf};

rust/ql/test/extractor-tests/crate_graph/modules.expected

+90
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,98 @@ lib.rs:
3131
#-----| -> impl AsString for ...::X { ... }
3232
#-----| -> struct X_List
3333
#-----| -> trait AsString
34+
#-----| -> use ...::DirBuilder
35+
#-----| -> use ...::DirEntry
36+
#-----| -> use ...::File
37+
#-----| -> use ...::FileTimes
38+
#-----| -> use ...::FileType
39+
#-----| -> use ...::Metadata
40+
#-----| -> use ...::OpenOptions
41+
#-----| -> use ...::PathBuf
42+
#-----| -> use ...::Permissions
43+
#-----| -> use ...::ReadDir
44+
#-----| -> use ...::canonicalize
45+
#-----| -> use ...::copy
46+
#-----| -> use ...::create_dir
47+
#-----| -> use ...::create_dir as mkdir
48+
#-----| -> use ...::create_dir_all
49+
#-----| -> use ...::exists
50+
#-----| -> use ...::hard_link
51+
#-----| -> use ...::metadata
52+
#-----| -> use ...::read
53+
#-----| -> use ...::read_dir
54+
#-----| -> use ...::read_link
55+
#-----| -> use ...::read_to_string
56+
#-----| -> use ...::remove_dir
57+
#-----| -> use ...::remove_dir_all
58+
#-----| -> use ...::remove_file
59+
#-----| -> use ...::rename
60+
#-----| -> use ...::set_permissions
61+
#-----| -> use ...::soft_link
62+
#-----| -> use ...::symlink_metadata
63+
#-----| -> use ...::write
3464

3565
#-----| struct X_List
3666

3767
#-----| trait AsString
3868
#-----| -> fn as_string
69+
70+
#-----| use ...::DirBuilder
71+
72+
#-----| use ...::DirEntry
73+
74+
#-----| use ...::File
75+
76+
#-----| use ...::FileTimes
77+
78+
#-----| use ...::FileType
79+
80+
#-----| use ...::Metadata
81+
82+
#-----| use ...::OpenOptions
83+
84+
#-----| use ...::PathBuf
85+
86+
#-----| use ...::Permissions
87+
88+
#-----| use ...::ReadDir
89+
90+
#-----| use ...::canonicalize
91+
92+
#-----| use ...::copy
93+
94+
#-----| use ...::create_dir
95+
96+
#-----| use ...::create_dir as mkdir
97+
98+
#-----| use ...::create_dir_all
99+
100+
#-----| use ...::exists
101+
102+
#-----| use ...::hard_link
103+
104+
#-----| use ...::metadata
105+
106+
#-----| use ...::read
107+
108+
#-----| use ...::read_dir
109+
110+
#-----| use ...::read_link
111+
112+
#-----| use ...::read_to_string
113+
114+
#-----| use ...::remove_dir
115+
116+
#-----| use ...::remove_dir_all
117+
118+
#-----| use ...::remove_file
119+
120+
#-----| use ...::rename
121+
122+
#-----| use ...::set_permissions
123+
124+
#-----| use ...::soft_link
125+
126+
#-----| use ...::symlink_metadata
127+
128+
#-----| use ...::write

0 commit comments

Comments
 (0)