948: Fix test_missing_module_code_action_in_json_project on Windows r=matklad a=vipentti
The test would fail on Windows due to the paths not being properly escaped for
JSON.
In addition adds extra braces around the fn main to actually introduce braces in
the file.
Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com>
// TODO const/static/array length
None
}
- } else if let Some(module) = ast::Module::cast(node) {
- Some(module_from_declaration(db, file_id, module)?.resolver(db))
- } else if let Some(_) = ast::SourceFile::cast(node) {
- Some(module_from_source(db, file_id.into(), None)?.resolver(db))
- } else if let Some(s) = ast::StructDef::cast(node) {
- let module = module_from_child_node(db, file_id, s.syntax())?;
- Some(struct_from_module(db, module, s).resolver(db))
- } else if let Some(e) = ast::EnumDef::cast(node) {
- let module = module_from_child_node(db, file_id, e.syntax())?;
- Some(enum_from_module(db, module, e).resolver(db))
} else {
- // TODO add missing cases
- None
+ try_get_resolver_for_node(db, file_id, node)
}
})
})
// TODO const/static/array length
None
}
- } else if let Some(module) = ast::Module::cast(node) {
- Some(module_from_declaration(db, file_id, module)?.resolver(db))
- } else if let Some(_) = ast::SourceFile::cast(node) {
- Some(module_from_source(db, file_id.into(), None)?.resolver(db))
- } else if let Some(s) = ast::StructDef::cast(node) {
- let module = module_from_child_node(db, file_id, s.syntax())?;
- Some(struct_from_module(db, module, s).resolver(db))
- } else if let Some(e) = ast::EnumDef::cast(node) {
- let module = module_from_child_node(db, file_id, e.syntax())?;
- Some(enum_from_module(db, module, e).resolver(db))
} else {
- // TODO add missing cases
- None
+ try_get_resolver_for_node(db, file_id, node)
}
})
.unwrap_or_default()
}
+
+fn try_get_resolver_for_node(
+ db: &impl HirDatabase,
+ file_id: FileId,
+ node: &SyntaxNode,
+) -> Option<Resolver> {
+ if let Some(module) = ast::Module::cast(node) {
+ Some(module_from_declaration(db, file_id, module)?.resolver(db))
+ } else if let Some(_) = ast::SourceFile::cast(node) {
+ Some(module_from_source(db, file_id.into(), None)?.resolver(db))
+ } else if let Some(s) = ast::StructDef::cast(node) {
+ let module = module_from_child_node(db, file_id, s.syntax())?;
+ Some(struct_from_module(db, module, s).resolver(db))
+ } else if let Some(e) = ast::EnumDef::cast(node) {
+ let module = module_from_child_node(db, file_id, e.syntax())?;
+ Some(enum_from_module(db, module, e).resolver(db))
+ } else if let Some(f) = ast::FnDef::cast(node) {
+ function_from_source(db, file_id, f).map(|f| f.resolver(db))
+ } else {
+ // TODO add missing cases
+ None
+ }
+}
Some(Resolution::GenericParam(..)) => {
// TODO: go to the generic param def
}
- Some(Resolution::SelfType(_impl_block)) => {
- // TODO: go to the implemented type
+ Some(Resolution::SelfType(impl_block)) => {
+ let ty = impl_block.target_ty(db);
+
+ if let hir::Ty::Adt { def_id, .. } = ty {
+ return Exact(NavigationTarget::from_adt_def(db, def_id));
+ }
}
None => {
// If we failed to resolve then check associated items
"spam NAMED_FIELD_DEF FileId(1) [17; 26) [17; 21)",
);
}
+ #[test]
+ fn goto_definition_on_self() {
+ check_goto(
+ "
+ //- /lib.rs
+ struct Foo;
+ impl Foo {
+ pub fn new() -> Self {
+ Self<|> {}
+ }
+ }
+ ",
+ "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
+ );
+
+ check_goto(
+ "
+ //- /lib.rs
+ struct Foo;
+ impl Foo {
+ pub fn new() -> Self<|> {
+ Self {}
+ }
+ }
+ ",
+ "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
+ );
+
+ check_goto(
+ "
+ //- /lib.rs
+ enum Foo { A }
+ impl Foo {
+ pub fn new() -> Self<|> {
+ Foo::A
+ }
+ }
+ ",
+ "Foo ENUM_DEF FileId(1) [0; 14) [5; 8)",
+ );
+
+ check_goto(
+ "
+ //- /lib.rs
+ enum Foo { A }
+ impl Foo {
+ pub fn thing(a: &Self<|>) {
+ }
+ }
+ ",
+ "Foo ENUM_DEF FileId(1) [0; 14) [5; 8)",
+ );
+ }
+
+ #[test]
+ fn goto_definition_on_self_in_trait_impl() {
+ check_goto(
+ "
+ //- /lib.rs
+ struct Foo;
+ trait Make {
+ fn new() -> Self;
+ }
+ impl Make for Foo {
+ fn new() -> Self {
+ Self<|> {}
+ }
+ }
+ ",
+ "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
+ );
+
+ check_goto(
+ "
+ //- /lib.rs
+ struct Foo;
+ trait Make {
+ fn new() -> Self;
+ }
+ impl Make for Foo {
+ fn new() -> Self<|> {
+ Self{}
+ }
+ }
+ ",
+ "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
+ );
+ }
#[test]
fn goto_definition_works_when_used_on_definition_name_itself() {
assert_eq!(trim_markup_opt(hover.info.first()), Some("const C: u32"));
assert_eq!(hover.info.is_exact(), true);
}
+
+ #[test]
+ fn test_hover_self() {
+ let (analysis, position) = single_file_with_position(
+ "
+ struct Thing { x: u32 };
+ impl Thing {
+ fn new() -> Self {
+ Self<|> { x: 0 }
+ }
+ }
+ ",
+ );
+ let hover = analysis.hover(position).unwrap().unwrap();
+ assert_eq!(trim_markup_opt(hover.info.first()), Some("struct Thing"));
+ assert_eq!(hover.info.is_exact(), true);
+
+ let (analysis, position) = single_file_with_position(
+ "
+ struct Thing { x: u32 };
+ impl Thing {
+ fn new() -> Self<|> {
+ Self { x: 0 }
+ }
+ }
+ ",
+ );
+ let hover = analysis.hover(position).unwrap().unwrap();
+ assert_eq!(trim_markup_opt(hover.info.first()), Some("struct Thing"));
+ assert_eq!(hover.info.is_exact(), true);
+
+ let (analysis, position) = single_file_with_position(
+ "
+ enum Thing { A };
+ impl Thing {
+ pub fn new() -> Self<|> {
+ Thing::A
+ }
+ }
+ ",
+ );
+ let hover = analysis.hover(position).unwrap().unwrap();
+ assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing"));
+ assert_eq!(hover.info.is_exact(), true);
+
+ let (analysis, position) = single_file_with_position(
+ "
+ enum Thing { A };
+ impl Thing {
+ pub fn thing(a: Self<|>) {
+ }
+ }
+ ",
+ );
+ let hover = analysis.hover(position).unwrap().unwrap();
+ assert_eq!(trim_markup_opt(hover.info.first()), Some("enum Thing"));
+ assert_eq!(hover.info.is_exact(), true);
+ }
}
}
}
+ pub(crate) fn from_adt_def(db: &RootDatabase, adt_def: hir::AdtDef) -> NavigationTarget {
+ match adt_def {
+ hir::AdtDef::Struct(s) => {
+ let (file_id, node) = s.source(db);
+ NavigationTarget::from_named(file_id.original_file(db), &*node)
+ }
+ hir::AdtDef::Enum(s) => {
+ let (file_id, node) = s.source(db);
+ NavigationTarget::from_named(file_id.original_file(db), &*node)
+ }
+ }
+ }
+
pub(crate) fn from_def(db: &RootDatabase, module_def: hir::ModuleDef) -> NavigationTarget {
match module_def {
hir::ModuleDef::Module(module) => NavigationTarget::from_module(db, module),
failure = "0.1.4"
failure_derive = "0.1.4"
serde_json = "1.0.34"
-serde = "1.0.83"
+serde = { version = "1.0.83", features = ["derive"] }
crossbeam-channel = "0.3.5"
flexi_logger = "0.11.0"
log = "0.4.3"
ra_arena = { path = "../ra_arena" }
ra_db = { path = "../ra_db" }
-serde = "1.0.89"
+serde = { version = "1.0.89", features = ["derive"] }
serde_json = "1.0.39"
[dev-dependencies]