Skip to content

Commit 6cde0b1

Browse files
committed
Add support for extern crate
This adds syntax highlighting, hover and goto def functionality for extern crate
1 parent a69f19a commit 6cde0b1

File tree

11 files changed

+225
-59
lines changed

11 files changed

+225
-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_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 & 8 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
},
@@ -85,9 +82,7 @@ pub(crate) fn reference_definition(
8582
name_ref: &ast::NameRef,
8683
) -> ReferenceResult {
8784
let name_kind = classify_name_ref(sema, name_ref);
88-
if let Some(def) = name_kind {
89-
let def = def.definition();
90-
85+
if let Some(def) = name_kind.and_then(|def| def.definition(sema.db)) {
9186
return match def.try_to_nav(sema.db) {
9287
Some(nav) => ReferenceResult::Exact(nav),
9388
None => ReferenceResult::Approximate(Vec::new()),
@@ -133,6 +128,32 @@ mod tests {
133128
assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
134129
}
135130

131+
#[test]
132+
fn goto_def_for_extern_crate() {
133+
check(
134+
r#"
135+
//- /main.rs
136+
extern crate std<|>;
137+
//- /std/lib.rs
138+
// empty
139+
//^ file
140+
"#,
141+
)
142+
}
143+
144+
#[test]
145+
fn goto_def_for_renamed_extern_crate() {
146+
check(
147+
r#"
148+
//- /main.rs
149+
extern crate std as abc<|>;
150+
//- /std/lib.rs
151+
// empty
152+
//^ file
153+
"#,
154+
)
155+
}
156+
136157
#[test]
137158
fn goto_def_in_items() {
138159
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).and_then(|d| d.definition(sema.db)),
89+
ast::Name(name) => classify_name(&sema, &name).and_then(|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),
@@ -1106,6 +1109,46 @@ fn bar() { fo<|>o(); }
11061109
);
11071110
}
11081111

1112+
#[test]
1113+
fn test_hover_extern_crate() {
1114+
check(
1115+
r#"
1116+
//- /main.rs
1117+
extern crate st<|>d;
1118+
//- /std/lib.rs
1119+
//! Standard library for this test
1120+
//!
1121+
//! Printed?
1122+
//! abc123
1123+
"#,
1124+
expect![[r#"
1125+
*std*
1126+
Standard library for this test
1127+
1128+
Printed?
1129+
abc123
1130+
"#]],
1131+
);
1132+
check(
1133+
r#"
1134+
//- /main.rs
1135+
extern crate std as ab<|>c;
1136+
//- /std/lib.rs
1137+
//! Standard library for this test
1138+
//!
1139+
//! Printed?
1140+
//! abc123
1141+
"#,
1142+
expect![[r#"
1143+
*abc*
1144+
Standard library for this test
1145+
1146+
Printed?
1147+
abc123
1148+
"#]],
1149+
);
1150+
}
1151+
11091152
#[test]
11101153
fn test_hover_mod_with_same_name_as_function() {
11111154
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
@@ -483,6 +483,7 @@ fn highlight_element(
483483
};
484484

485485
match name_kind {
486+
Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(),
486487
Some(NameClass::Definition(def)) => {
487488
highlight_name(db, def) | HighlightModifier::Definition
488489
}
@@ -500,6 +501,7 @@ fn highlight_element(
500501
let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap();
501502
match classify_name_ref(sema, &name_ref) {
502503
Some(name_kind) => match name_kind {
504+
NameRefClass::ExternCrate(_) => HighlightTag::Module.into(),
503505
NameRefClass::Definition(def) => {
504506
if let Definition::Local(local) = &def {
505507
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
@@ -380,6 +380,23 @@ macro_rules! noop {
380380
);
381381
}
382382

383+
#[test]
384+
fn test_extern_crate() {
385+
check_highlighting(
386+
r#"
387+
//- /main.rs
388+
extern crate std;
389+
extern crate alloc as abc;
390+
//- /std/lib.rs
391+
pub struct S;
392+
//- /alloc/lib.rs
393+
pub struct A
394+
"#,
395+
expect_file!["crates/ra_ide/test_data/highlight_extern_crate.html"],
396+
false,
397+
);
398+
}
399+
383400
/// Highlights the code given by the `ra_fixture` argument, renders the
384401
/// result as HTML, and compares it with the HTML file given as `snapshot`.
385402
/// Note that the `snapshot` file is overwritten by the rendered HTML.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
<style>
3+
body { margin: 0; }
4+
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
5+
6+
.lifetime { color: #DFAF8F; font-style: italic; }
7+
.comment { color: #7F9F7F; }
8+
.documentation { color: #629755; }
9+
.injected { opacity: 0.65 ; }
10+
.struct, .enum { color: #7CB8BB; }
11+
.enum_variant { color: #BDE0F3; }
12+
.string_literal { color: #CC9393; }
13+
.field { color: #94BFF3; }
14+
.function { color: #93E0E3; }
15+
.function.unsafe { color: #BC8383; }
16+
.operator.unsafe { color: #BC8383; }
17+
.parameter { color: #94BFF3; }
18+
.text { color: #DCDCCC; }
19+
.type { color: #7CB8BB; }
20+
.builtin_type { color: #8CD0D3; }
21+
.type_param { color: #DFAF8F; }
22+
.attribute { color: #94BFF3; }
23+
.numeric_literal { color: #BFEBBF; }
24+
.bool_literal { color: #BFE6EB; }
25+
.macro { color: #94BFF3; }
26+
.module { color: #AFD8AF; }
27+
.value_param { color: #DCDCCC; }
28+
.variable { color: #DCDCCC; }
29+
.format_specifier { color: #CC696B; }
30+
.mutable { text-decoration: underline; }
31+
.escape_sequence { color: #94BFF3; }
32+
.keyword { color: #F0DFAF; font-weight: bold; }
33+
.keyword.unsafe { color: #BC8383; font-weight: bold; }
34+
.control { font-style: italic; }
35+
36+
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
37+
</style>
38+
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span>
39+
<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span>
40+
</code></pre>

0 commit comments

Comments
 (0)