From 50281323ab17dd5a40257e035f73c315be20a988 Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Mon, 12 Mar 2018 10:31:08 +0100 Subject: [PATCH] wip --- src/analysis.rs | 30 ++++++++--- src/lib.rs | 11 +++- src/lowering.rs | 51 ++++++++++++++----- src/raw.rs | 2 +- src/test/mod.rs | 59 +++++++++++++++++++++- test_data/make_data.sh | 4 ++ test_data/traits/Cargo.lock | 4 ++ test_data/traits/Cargo.toml | 6 +++ test_data/traits/save-analysis/traits.json | 1 + test_data/traits/src/main.rs | 18 +++++++ 10 files changed, 163 insertions(+), 23 deletions(-) create mode 100644 test_data/traits/Cargo.lock create mode 100644 test_data/traits/Cargo.toml create mode 100644 test_data/traits/save-analysis/traits.json create mode 100644 test_data/traits/src/main.rs diff --git a/src/analysis.rs b/src/analysis.rs index e3c4982..979837a 100644 --- a/src/analysis.rs +++ b/src/analysis.rs @@ -12,7 +12,7 @@ use std::time::SystemTime; use radix_trie::{Trie, TrieCommon}; use {Id, Span}; -use raw::{CrateId, DefKind}; +use raw::{CrateId, DefKind, ImplKind}; /// This is the main database that contains all the collected symbol information, /// such as definitions, their mapping between spans, hierarchy and so on, @@ -28,18 +28,23 @@ pub struct Analysis { #[derive(Debug)] pub struct PerCrateAnalysis { - // Map span to id of def (either because it is the span of the def, or of - // the def for the ref). + /// Map span to id of def (either because it is the span of the def, or of + /// the def for the ref). pub def_id_for_span: HashMap, + /// All definitions that can be Ref:ed. pub defs: HashMap, + /// Map of id to Impl. + pub impl_defs: HashMap, pub defs_per_file: HashMap>, pub children: HashMap>, pub def_names: HashMap>, pub def_trie: Trie>, pub ref_spans: HashMap>, pub globs: HashMap, - pub impls: HashMap>, - + /// Map of self_type id and trait_id to impl id + pub impl_ids: HashMap>, + /// Map of impl id to the span of the impl. + pub impls: HashMap, pub root_id: Option, pub timestamp: SystemTime, pub path: Option, @@ -89,6 +94,13 @@ pub struct Def { // pub sig: Option, } +#[derive(Debug, Clone)] +pub struct Impl { + pub kind: ImplKind, + pub span: Span, + pub children: Vec, +} + #[derive(Debug, Clone)] pub struct Signature { pub span: Span, @@ -123,7 +135,9 @@ impl PerCrateAnalysis { def_trie: Trie::new(), ref_spans: HashMap::new(), globs: HashMap::new(), + impl_ids: HashMap::new(), impls: HashMap::new(), + impl_defs: HashMap::new(), root_id: None, timestamp, path, @@ -256,7 +270,9 @@ impl Analysis { where F: Fn(&Vec) -> Option, { - self.for_each_crate(|c| c.ref_spans.get(&id).and_then(&f)) + self.for_each_crate(|c| { + c.ref_spans.get(&id).and_then(&f) + }) } pub fn with_defs_per_file(&self, file: &Path, f: F) -> Option @@ -271,7 +287,7 @@ impl Analysis { self.for_all_crates(|c| { c.def_trie.get_raw_descendant(&lowered_stem).map(|s| { - s.values().flat_map(|ids| + s.values().flat_map(|ids| ids.iter().flat_map(|id| c.defs.get(id)).cloned() ).collect() }) diff --git a/src/lib.rs b/src/lib.rs index 11e9594..c149676 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -425,7 +425,16 @@ impl AnalysisHost { pub fn find_impls(&self, id: Id) -> AResult> { self.with_analysis(|a| { - Some(a.for_all_crates(|c| c.impls.get(&id).cloned())) + Some(a.for_all_crates(|c| c.impl_ids.get(&id) + .map(|ids| ids + .iter() + // relations and impls are emitted at the same time by save-analysis, + // unwrap() should be ok. + .map(|impl_id| c.impls.get(impl_id).unwrap()) + .cloned() + .collect() + ) + )) }) } diff --git a/src/lowering.rs b/src/lowering.rs index d27bec6..bae735a 100644 --- a/src/lowering.rs +++ b/src/lowering.rs @@ -9,7 +9,7 @@ //! For processing the raw save-analysis data from rustc into the rls //! in-memory representation. -use analysis::{Def, Glob, PerCrateAnalysis, Ref}; +use analysis::{Def, Impl, Glob, PerCrateAnalysis, Ref}; use data; use raw::{self, RelationKind, CrateId}; use {AResult, AnalysisHost, Id, Span, NULL}; @@ -25,6 +25,9 @@ use std::path::{Path, PathBuf}; use std::time::Instant; use std::u32; +// impl ids are just a counter from 0. +static IMPL_ID_START: u64 = ::max_value() - 1_000_000; + // f is a function used to record the lowered crate into analysis. pub fn lower( raw_analysis: Vec, @@ -153,7 +156,8 @@ impl CrateReader { reader.read_defs(krate.analysis.defs, &mut per_crate, is_distro_crate); reader.read_imports(krate.analysis.imports, &mut per_crate, project_analysis); reader.read_refs(krate.analysis.refs, &mut per_crate, project_analysis); - reader.read_impls(krate.analysis.relations, &mut per_crate, project_analysis); + reader.read_impls(krate.analysis.impls, &mut per_crate, project_analysis); + reader.read_relations(krate.analysis.relations, &mut per_crate, project_analysis); (per_crate, krate.id) } @@ -236,7 +240,7 @@ impl CrateReader { if d.name != "" { analysis.def_trie.map_with_default(d.name.to_lowercase(), |v| v.push(id), vec![id]); } - + let parent = d.parent.map(|id| self.id_from_compiler_id(&id)); if let Some(parent) = parent { let children = analysis @@ -305,16 +309,39 @@ impl CrateReader { } fn read_impls( + &self, + impls: Vec, + analysis: &mut PerCrateAnalysis, + _project_analysis: &AnalysisHost, + ) { + for i in impls { + let impl_id = Id(IMPL_ID_START + i.id as u64); + let span = lower_span(&i.span, &self.base_dir); + analysis.impls.insert(impl_id, span.clone()); + let def = Impl { + kind: i.kind, + span: span, + children: i.children + .iter() + .map(|id| self.id_from_compiler_id(&id)) + .collect() + }; + analysis.impl_defs.insert(impl_id, def); + } + } + + fn read_relations( &self, relations: Vec, analysis: &mut PerCrateAnalysis, project_analysis: &AnalysisHost, ) { for r in relations { - match r.kind { - RelationKind::Impl { .. } => {} + // impl_id is a u32 "local" id to tie the relation to the impl. + let impl_id = match r.kind { + RelationKind::Impl { ref id } => Id(IMPL_ID_START + *id as u64), _ => continue, - } + }; let self_id = self.id_from_compiler_id(&r.from); let trait_id = self.id_from_compiler_id(&r.to); let span = lower_span(&r.span, &self.base_dir); @@ -322,20 +349,20 @@ impl CrateReader { if let Some(self_id) = abs_ref_id(self_id, analysis, project_analysis) { trace!("record impl for self type {:?} {}", span, self_id); analysis - .impls + .impl_ids .entry(self_id) - .or_insert_with(|| vec![]) - .push(span.clone()); + .or_insert_with(|| HashSet::new()) + .insert(impl_id); } } if trait_id != NULL { if let Some(trait_id) = abs_ref_id(trait_id, analysis, project_analysis) { trace!("record impl for trait {:?} {}", span, trait_id); analysis - .impls + .impl_ids .entry(trait_id) - .or_insert_with(|| vec![]) - .push(span); + .or_insert_with(|| HashSet::new()) + .insert(impl_id); } } } diff --git a/src/raw.rs b/src/raw.rs index 744a396..dcbbfbe 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -9,7 +9,7 @@ use {AnalysisLoader, Blacklist}; use listings::{DirectoryListing, ListingKind}; pub use data::{CratePreludeData, Def, DefKind, GlobalCrateId as CrateId, Import, - Ref, Relation, RelationKind, SigElement, Signature, SpanData}; + Ref, Relation, RelationKind, Impl, ImplKind, SigElement, Signature, SpanData}; use data::Analysis; use std::collections::HashMap; diff --git a/src/test/mod.rs b/src/test/mod.rs index 6e49d6b..107cc6d 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -6,16 +6,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {AnalysisHost, AnalysisLoader}; +use {AnalysisHost, AnalysisLoader, Span}; use raw::DefKind; use std::collections::HashSet; use std::path::{Path, PathBuf}; +use span::{Row, Column, Position, Range}; #[cfg(test)] extern crate env_logger; -#[derive(Clone, new)] +#[derive(Clone, new, Debug)] struct TestAnalysisLoader { path: PathBuf, } @@ -377,3 +378,57 @@ fn test_extern_fn() { let def = host.goto_def(&spans[1]); assert_eq!(def.unwrap(), spans[0]); } + +#[test] +fn test_trait_refs_defs() { + let host = AnalysisHost::new_with_loader(TestAnalysisLoader::new( + Path::new("test_data/traits/save-analysis").to_owned(), + )); + host.reload( + Path::new("test_data/traits"), + Path::new("test_data/traits"), + ).unwrap(); + + // make a span for row 4: + // let _ignored = mymod::MyStruct.trait_fn(); + // -------- + let row = Row::new_one_indexed(4); + let col_start = Column::new_one_indexed(36); + let col_end = Column::new_one_indexed(44); + let pos_start = Position::new(row, col_start); + let pos_end = Position::new(row, col_end); + let range = Range::from_positions(pos_start, pos_end).zero_indexed(); + + let span = Span::from_range(range, "test_data/traits/src/main.rs"); + + // this is an id for a Method of the Trait (not the Impl). + let id = host.crate_local_id(&span).expect("No id for span"); + + println!("id for span {:?}", id); + + // Def { kind: Method, ... } of the Trait + let def = host.get_def(id.clone()).expect("No def for id"); + + println!("def for id {:?}", def); + + // references to the method + let _spans = host.find_all_refs(&span, true, true).expect("No refs for span"); + + println!("ref spans {:?}", _spans); + + // TODO below we go awry... we don't necessarily want to step up to the + // type level, just to go down on method level again in the trait, or do we? + // regardless, it seems the find_impls() needs some help to work with + // type id connected to trait id, rather than the span. + + // // the type that owns the method + // let typ = def.parent.expect("No parent for method"); + + // // the impls of the type, which are just spans for the + // // impl rows i.e.: + // // impl MyTrait for MyStruct { + // let impls = host.find_impls(typ); + + // println!("{:?}", impls); + +} diff --git a/test_data/make_data.sh b/test_data/make_data.sh index 43a9eb4..7bf2a1b 100755 --- a/test_data/make_data.sh +++ b/test_data/make_data.sh @@ -8,6 +8,7 @@ function build { output="$(pwd)/$2" pushd "$1" > /dev/null RUSTFLAGS=-Zsave-analysis cargo build + mkdir -p "$output" cp target/debug/deps/save-analysis/*.json "$output" # strip all hashes from filenames libfoo-[hash].json -> libfoo.json for from in $output/*.json; do @@ -33,3 +34,6 @@ build types types/save-analysis # Expressions build exprs exprs/save-analysis + +# Traits +build traits traits/save-analysis diff --git a/test_data/traits/Cargo.lock b/test_data/traits/Cargo.lock new file mode 100644 index 0000000..3eff52b --- /dev/null +++ b/test_data/traits/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "traits" +version = "0.1.0" + diff --git a/test_data/traits/Cargo.toml b/test_data/traits/Cargo.toml new file mode 100644 index 0000000..c2d7c33 --- /dev/null +++ b/test_data/traits/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "traits" +version = "0.1.0" +authors = ["Martin Algesten "] + +[dependencies] diff --git a/test_data/traits/save-analysis/traits.json b/test_data/traits/save-analysis/traits.json new file mode 100644 index 0000000..88c9943 --- /dev/null +++ b/test_data/traits/save-analysis/traits.json @@ -0,0 +1 @@ +{"config":{"output_file":null,"full_docs":false,"pub_only":false,"reachable_only":false,"distro_crate":false,"signatures":false,"borrow_data":false},"prelude":{"crate_id":{"name":"traits","disambiguator":[9834285854511471743,11986377825196509713]},"crate_root":"src","external_crates":[{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":1,"id":{"name":"std","disambiguator":[16908046677263206360,15608585996220974956]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":2,"id":{"name":"core","disambiguator":[265854671877483652,7509856743425468126]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":3,"id":{"name":"alloc","disambiguator":[7464960686499081871,14975191818600169300]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":4,"id":{"name":"std_unicode","disambiguator":[6545616104026717450,18290903305805074798]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":5,"id":{"name":"alloc_system","disambiguator":[933858897868640912,3181242634312403434]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":6,"id":{"name":"libc","disambiguator":[7923155387865240769,14589553178726802507]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":7,"id":{"name":"unwind","disambiguator":[15369053486114929769,10993836436858370164]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":8,"id":{"name":"compiler_builtins","disambiguator":[5420709578077943918,7267737470173610552]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":9,"id":{"name":"alloc_jemalloc","disambiguator":[3928795565666290148,2262383683626321904]}},{"file_name":"/Users/martin/dev/_dist/rls-analysis/test_data/traits/src/main.rs","num":10,"id":{"name":"panic_unwind","disambiguator":[12477021650613093167,18048873155028682792]}}],"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":0,"byte_end":262,"line_start":1,"line_end":18,"column_start":1,"column_end":2}},"imports":[{"kind":"Use","ref_id":{"krate":0,"index":14},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":11,"byte_end":18,"line_start":1,"line_end":1,"column_start":12,"column_end":19},"name":"MyTrait","value":"","parent":{"krate":0,"index":0}}],"defs":[{"kind":"Mod","id":{"krate":0,"index":0},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":0,"byte_end":262,"line_start":1,"line_end":18,"column_start":1,"column_end":2},"name":"","qualname":"::","value":"src/main.rs","parent":null,"children":[{"krate":0,"index":2},{"krate":0,"index":4},{"krate":0,"index":6},{"krate":0,"index":8},{"krate":0,"index":10}],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Function","id":{"krate":0,"index":8},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":28,"byte_end":32,"line_start":3,"line_end":3,"column_start":8,"column_end":12},"name":"main","qualname":"::main","value":"fn () -> ()","parent":null,"children":[],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Local","id":{"krate":0,"index":4294967286},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":45,"byte_end":53,"line_start":4,"line_end":4,"column_start":9,"column_end":17},"name":"_ignored","qualname":"_ignored$9","value":"()","parent":null,"children":[],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Mod","id":{"krate":0,"index":10},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":91,"byte_end":96,"line_start":7,"line_end":7,"column_start":5,"column_end":10},"name":"mymod","qualname":"::mymod","value":"src/main.rs","parent":null,"children":[{"krate":0,"index":12},{"krate":0,"index":14},{"krate":0,"index":18}],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Struct","id":{"krate":0,"index":12},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":114,"byte_end":122,"line_start":8,"line_end":8,"column_start":16,"column_end":24},"name":"MyStruct","qualname":"::mymod::MyStruct","value":"","parent":null,"children":[],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Trait","id":{"krate":0,"index":14},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":139,"byte_end":146,"line_start":10,"line_end":10,"column_start":15,"column_end":22},"name":"MyTrait","qualname":"::mymod::MyTrait","value":"MyTrait","parent":null,"children":[{"krate":0,"index":16}],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Method","id":{"krate":0,"index":16},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":160,"byte_end":168,"line_start":11,"line_end":11,"column_start":12,"column_end":20},"name":"trait_fn","qualname":"::mymod::MyTrait::trait_fn","value":"fn (&self) -> ()","parent":{"krate":0,"index":14},"children":[],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Local","id":{"krate":0,"index":4294967264},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":237,"byte_end":241,"line_start":15,"line_end":15,"column_start":22,"column_end":26},"name":"self","qualname":"::trait_fn::self","value":"&mymod::MyStruct","parent":null,"children":[],"decl_id":null,"docs":"","sig":null,"attributes":[]},{"kind":"Method","id":{"krate":0,"index":20},"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":227,"byte_end":235,"line_start":15,"line_end":15,"column_start":12,"column_end":20},"name":"trait_fn","qualname":"::trait_fn","value":"fn (&self) -> ()","parent":{"krate":0,"index":14},"children":[],"decl_id":{"krate":0,"index":16},"docs":"","sig":null,"attributes":[]}],"impls":[{"id":0,"kind":"Direct","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":205,"byte_end":213,"line_start":14,"line_end":14,"column_start":22,"column_end":30},"value":"","parent":null,"children":[{"krate":0,"index":20}],"docs":"","sig":null,"attributes":[]}],"refs":[{"kind":"Mod","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1},"ref_id":{"krate":4294967295,"index":4294967295}},{"kind":"Mod","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1},"ref_id":{"krate":4294967295,"index":4294967295}},{"kind":"Mod","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":0,"byte_end":0,"line_start":1,"line_end":1,"column_start":1,"column_end":1},"ref_id":{"krate":4294967295,"index":4294967295}},{"kind":"Type","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":11,"byte_end":18,"line_start":1,"line_end":1,"column_start":12,"column_end":19},"ref_id":{"krate":0,"index":14}},{"kind":"Mod","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":4,"byte_end":9,"line_start":1,"line_end":1,"column_start":5,"column_end":10},"ref_id":{"krate":4294967295,"index":4294967295}},{"kind":"Function","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":72,"byte_end":80,"line_start":4,"line_end":4,"column_start":36,"column_end":44},"ref_id":{"krate":0,"index":16}},{"kind":"Type","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":63,"byte_end":71,"line_start":4,"line_end":4,"column_start":27,"column_end":35},"ref_id":{"krate":0,"index":12}},{"kind":"Mod","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":56,"byte_end":61,"line_start":4,"line_end":4,"column_start":20,"column_end":25},"ref_id":{"krate":4294967295,"index":4294967295}},{"kind":"Type","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":205,"byte_end":213,"line_start":14,"line_end":14,"column_start":22,"column_end":30},"ref_id":{"krate":0,"index":12}},{"kind":"Type","span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":193,"byte_end":200,"line_start":14,"line_end":14,"column_start":10,"column_end":17},"ref_id":{"krate":0,"index":14}}],"macro_refs":[],"relations":[{"span":{"file_name":[115,114,99,47,109,97,105,110,46,114,115],"byte_start":205,"byte_end":213,"line_start":14,"line_end":14,"column_start":22,"column_end":30},"kind":{"variant":"Impl","fields":[0]},"from":{"krate":0,"index":12},"to":{"krate":0,"index":14}}]} \ No newline at end of file diff --git a/test_data/traits/src/main.rs b/test_data/traits/src/main.rs new file mode 100644 index 0000000..acfdc6c --- /dev/null +++ b/test_data/traits/src/main.rs @@ -0,0 +1,18 @@ +use mymod::MyTrait; + +pub fn main() { + let _ignored = mymod::MyStruct.trait_fn(); +} + +mod mymod { + pub struct MyStruct; + + pub trait MyTrait { + fn trait_fn(&self); + } + + impl MyTrait for MyStruct { + fn trait_fn(&self) { + } + } +}