Skip to content

Commit 7a03f05

Browse files
Merge #5692
5692: Add support for extern crate r=jonas-schievink a=Nashenas88 This adds syntax highlighting, hover and goto def functionality for extern crate. Fixes #5690 Co-authored-by: Paul Daniel Faria <[email protected]>
2 parents b1cb4ac + bf9b457 commit 7a03f05

File tree

15 files changed

+224
-59
lines changed

15 files changed

+224
-59
lines changed

crates/ra_assists/src/handlers/add_turbo_fish.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<(
4141
let name_ref = ast::NameRef::cast(ident.parent())?;
4242
let def = match classify_name_ref(&ctx.sema, &name_ref)? {
4343
NameRefClass::Definition(def) => def,
44-
NameRefClass::FieldShorthand { .. } => return None,
44+
NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
4545
};
4646
let fun = match def {
4747
Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,

crates/ra_assists/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub use prelude::*;
257257
.find(|dep| &dep.name.to_string() == std_crate)?
258258
.krate;
259259

260-
let mut module = std_crate.root_module(db)?;
260+
let mut module = std_crate.root_module(db);
261261
for segment in path {
262262
module = module.children(db).find_map(|child| {
263263
let name = child.name(db)?;

crates/ra_hir/src/code_model.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ impl Crate {
8383
.collect()
8484
}
8585

86-
pub fn root_module(self, db: &dyn HirDatabase) -> Option<Module> {
86+
pub fn root_module(self, db: &dyn HirDatabase) -> Module {
8787
let module_id = db.crate_def_map(self.id).root;
88-
Some(Module::new(self, module_id))
88+
Module::new(self, module_id)
8989
}
9090

9191
pub fn root_file(self, db: &dyn HirDatabase) -> FileId {

crates/ra_hir/src/semantics.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use hir_def::{
88
resolver::{self, HasResolver, Resolver},
99
AsMacroCall, FunctionId, TraitId, VariantId,
1010
};
11-
use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo};
11+
use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, name::AsName, ExpansionInfo};
1212
use hir_ty::associated_type_shorthand_candidates;
1313
use itertools::Itertools;
1414
use ra_db::{FileId, FileRange};
@@ -24,8 +24,8 @@ use crate::{
2424
diagnostics::Diagnostic,
2525
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
2626
source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer},
27-
AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module,
28-
ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
27+
AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef,
28+
Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef,
2929
};
3030
use resolver::TypeNs;
3131

@@ -228,6 +228,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
228228
self.imp.resolve_path(path)
229229
}
230230

231+
pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
232+
self.imp.resolve_extern_crate(extern_crate)
233+
}
234+
231235
pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
232236
self.imp.resolve_variant(record_lit).map(VariantDef::from)
233237
}
@@ -443,6 +447,17 @@ impl<'db> SemanticsImpl<'db> {
443447
self.analyze(path.syntax()).resolve_path(self.db, path)
444448
}
445449

450+
fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
451+
let krate = self.scope(extern_crate.syntax()).krate()?;
452+
krate.dependencies(self.db).into_iter().find_map(|dep| {
453+
if dep.name == extern_crate.name_ref()?.as_name() {
454+
Some(dep.krate)
455+
} else {
456+
None
457+
}
458+
})
459+
}
460+
446461
fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
447462
self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
448463
}
@@ -612,6 +627,10 @@ impl<'a> SemanticsScope<'a> {
612627
Some(Module { id: self.resolver.module()? })
613628
}
614629

630+
pub fn krate(&self) -> Option<Crate> {
631+
Some(Crate { id: self.resolver.krate()? })
632+
}
633+
615634
/// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
616635
// FIXME: rename to visible_traits to not repeat scope?
617636
pub fn traits_in_scope(&self) -> FxHashSet<TraitId> {

crates/ra_ide/src/display/short_label.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ impl ShortLabel for ast::Module {
4747
}
4848
}
4949

50+
impl ShortLabel for ast::SourceFile {
51+
fn short_label(&self) -> Option<String> {
52+
None
53+
}
54+
}
55+
5056
impl ShortLabel for ast::TypeAlias {
5157
fn short_label(&self) -> Option<String> {
5258
short_label_from_node(self, "type ")

crates/ra_ide/src/goto_definition.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use hir::Semantics;
22
use ra_ide_db::{
3-
defs::{classify_name, classify_name_ref, NameClass},
3+
defs::{classify_name, classify_name_ref},
44
symbol_index, RootDatabase,
55
};
66
use ra_syntax::{
@@ -40,10 +40,7 @@ pub(crate) fn goto_definition(
4040
reference_definition(&sema, &name_ref).to_vec()
4141
},
4242
ast::Name(name) => {
43-
let def = match classify_name(&sema, &name)? {
44-
NameClass::Definition(def) | NameClass::ConstReference(def) => def,
45-
NameClass::FieldShorthand { local: _, field } => field,
46-
};
43+
let def = classify_name(&sema, &name)?.definition(sema.db);
4744
let nav = def.try_to_nav(sema.db)?;
4845
vec![nav]
4946
},
@@ -86,8 +83,7 @@ pub(crate) fn reference_definition(
8683
) -> ReferenceResult {
8784
let name_kind = classify_name_ref(sema, name_ref);
8885
if let Some(def) = name_kind {
89-
let def = def.definition();
90-
86+
let def = def.definition(sema.db);
9187
return match def.try_to_nav(sema.db) {
9288
Some(nav) => ReferenceResult::Exact(nav),
9389
None => ReferenceResult::Approximate(Vec::new()),
@@ -133,6 +129,32 @@ mod tests {
133129
assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
134130
}
135131

132+
#[test]
133+
fn goto_def_for_extern_crate() {
134+
check(
135+
r#"
136+
//- /main.rs
137+
extern crate std<|>;
138+
//- /std/lib.rs
139+
// empty
140+
//^ file
141+
"#,
142+
)
143+
}
144+
145+
#[test]
146+
fn goto_def_for_renamed_extern_crate() {
147+
check(
148+
r#"
149+
//- /main.rs
150+
extern crate std as abc<|>;
151+
//- /std/lib.rs
152+
// empty
153+
//^ file
154+
"#,
155+
)
156+
}
157+
136158
#[test]
137159
fn goto_def_in_items() {
138160
check(

crates/ra_ide/src/hover.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
8585
let node = token.parent();
8686
let definition = match_ast! {
8787
match node {
88-
ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()),
89-
ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()),
88+
ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)),
89+
ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition(sema.db)),
9090
_ => None,
9191
}
9292
};
@@ -304,7 +304,10 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
304304
let docs = Documentation::from_ast(&it).map(Into::into);
305305
hover_markup(docs, it.short_label(), mod_path)
306306
}
307-
_ => None,
307+
ModuleSource::SourceFile(it) => {
308+
let docs = Documentation::from_ast(&it).map(Into::into);
309+
hover_markup(docs, it.short_label(), mod_path)
310+
}
308311
},
309312
ModuleDef::Function(it) => from_def_source(db, it, mod_path),
310313
ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
@@ -1137,6 +1140,46 @@ fn bar() { fo<|>o(); }
11371140
);
11381141
}
11391142

1143+
#[test]
1144+
fn test_hover_extern_crate() {
1145+
check(
1146+
r#"
1147+
//- /main.rs
1148+
extern crate st<|>d;
1149+
//- /std/lib.rs
1150+
//! Standard library for this test
1151+
//!
1152+
//! Printed?
1153+
//! abc123
1154+
"#,
1155+
expect![[r#"
1156+
*std*
1157+
Standard library for this test
1158+
1159+
Printed?
1160+
abc123
1161+
"#]],
1162+
);
1163+
check(
1164+
r#"
1165+
//- /main.rs
1166+
extern crate std as ab<|>c;
1167+
//- /std/lib.rs
1168+
//! Standard library for this test
1169+
//!
1170+
//! Printed?
1171+
//! abc123
1172+
"#,
1173+
expect![[r#"
1174+
*abc*
1175+
Standard library for this test
1176+
1177+
Printed?
1178+
abc123
1179+
"#]],
1180+
);
1181+
}
1182+
11401183
#[test]
11411184
fn test_hover_mod_with_same_name_as_function() {
11421185
check(

crates/ra_ide/src/references.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,13 @@ fn find_name(
130130
opt_name: Option<ast::Name>,
131131
) -> Option<RangeInfo<Definition>> {
132132
if let Some(name) = opt_name {
133-
let def = classify_name(sema, &name)?.definition();
133+
let def = classify_name(sema, &name)?.definition(sema.db);
134134
let range = name.syntax().text_range();
135135
return Some(RangeInfo::new(range, def));
136136
}
137137
let name_ref =
138138
sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?;
139-
let def = classify_name_ref(sema, &name_ref)?.definition();
139+
let def = classify_name_ref(sema, &name_ref)?.definition(sema.db);
140140
let range = name_ref.syntax().text_range();
141141
Some(RangeInfo::new(range, def))
142142
}

crates/ra_ide/src/syntax_highlighting.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ fn highlight_element(
495495
};
496496

497497
match name_kind {
498+
Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
498499
Some(NameClass::Definition(def)) => {
499500
highlight_name(db, def, false) | HighlightModifier::Definition
500501
}
@@ -522,6 +523,7 @@ fn highlight_element(
522523
let possibly_unsafe = is_possibly_unsafe(&name_ref);
523524
match classify_name_ref(sema, &name_ref) {
524525
Some(name_kind) => match name_kind {
526+
NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
525527
NameRefClass::Definition(def) => {
526528
if let Definition::Local(local) = &def {
527529
if let Some(name) = local.name(db) {

crates/ra_ide/src/syntax_highlighting/tests.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,23 @@ macro_rules! noop {
391391
);
392392
}
393393

394+
#[test]
395+
fn test_extern_crate() {
396+
check_highlighting(
397+
r#"
398+
//- /main.rs
399+
extern crate std;
400+
extern crate alloc as abc;
401+
//- /std/lib.rs
402+
pub struct S;
403+
//- /alloc/lib.rs
404+
pub struct A
405+
"#,
406+
expect_file!["crates/ra_ide/test_data/highlight_extern_crate.html"],
407+
false,
408+
);
409+
}
410+
394411
/// Highlights the code given by the `ra_fixture` argument, renders the
395412
/// result as HTML, and compares it with the HTML file given as `snapshot`.
396413
/// Note that the `snapshot` file is overwritten by the rendered HTML.

0 commit comments

Comments
 (0)