Skip to content
This repository has been archived by the owner on Mar 1, 2019. It is now read-only.

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
algesten committed Mar 12, 2018
1 parent 9ceb58e commit 367b46e
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 24 deletions.
30 changes: 23 additions & 7 deletions src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<Span, Ref>,
/// All definitions that can be Ref:ed.
pub defs: HashMap<Id, Def>,
/// Map of id to Impl.
pub impl_defs: HashMap<Id, Impl>,
pub defs_per_file: HashMap<PathBuf, Vec<Id>>,
pub children: HashMap<Id, HashSet<Id>>,
pub def_names: HashMap<String, Vec<Id>>,
pub def_trie: Trie<String, Vec<Id>>,
pub ref_spans: HashMap<Id, Vec<Span>>,
pub globs: HashMap<Span, Glob>,
pub impls: HashMap<Id, Vec<Span>>,

/// Map of self_type id and trait_id to impl id
pub impl_ids: HashMap<Id, HashSet<Id>>,
/// Map of impl id to the span of the impl.
pub impls: HashMap<Id, Span>,
pub root_id: Option<Id>,
pub timestamp: SystemTime,
}
Expand Down Expand Up @@ -88,6 +93,13 @@ pub struct Def {
// pub sig: Option<Signature>,
}

#[derive(Debug, Clone)]
pub struct Impl {
pub kind: ImplKind,
pub span: Span,
pub children: Vec<Id>,
}

#[derive(Debug, Clone)]
pub struct Signature {
pub span: Span,
Expand Down Expand Up @@ -122,7 +134,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,
}
Expand Down Expand Up @@ -253,7 +267,9 @@ impl Analysis {
where
F: Fn(&Vec<Span>) -> Option<T>,
{
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<F, T>(&self, file: &Path, f: F) -> Option<T>
Expand All @@ -268,7 +284,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()
})
Expand Down
11 changes: 10 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,16 @@ impl<L: AnalysisLoader> AnalysisHost<L> {

pub fn find_impls(&self, id: Id) -> AResult<Vec<Span>> {
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()
)
))
})
}

Expand Down
51 changes: 39 additions & 12 deletions src/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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 = <u64>::max_value() - 1_000_000;

// f is a function used to record the lowered crate into analysis.
pub fn lower<F, L>(
raw_analysis: Vec<raw::Crate>,
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -305,37 +309,60 @@ impl CrateReader {
}

fn read_impls<L: AnalysisLoader>(
&self,
impls: Vec<raw::Impl>,
analysis: &mut PerCrateAnalysis,
_project_analysis: &AnalysisHost<L>,
) {
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<L: AnalysisLoader>(
&self,
relations: Vec<raw::Relation>,
analysis: &mut PerCrateAnalysis,
project_analysis: &AnalysisHost<L>,
) {
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);
if self_id != NULL {
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);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -67,7 +67,7 @@ pub fn read_analysis_from_files<L: AnalysisLoader>(
read_crate_data(&path).map(|analysis| {
let is_fresh = {
let id = &analysis.prelude.as_ref().unwrap().crate_id;
crate_timestamps.get(id).map_or(true, |t| time > t)
crate_timestamps.get(id).map_or(true, |t| time > t)
};
if is_fresh {
result.push(Crate::new(analysis, *time));
Expand Down
59 changes: 57 additions & 2 deletions src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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);

}
4 changes: 4 additions & 0 deletions test_data/make_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,3 +34,6 @@ build types types/save-analysis

# Expressions
build exprs exprs/save-analysis

# Traits
build traits traits/save-analysis
4 changes: 4 additions & 0 deletions test_data/traits/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions test_data/traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "traits"
version = "0.1.0"
authors = ["Martin Algesten <[email protected]>"]

[dependencies]
1 change: 1 addition & 0 deletions test_data/traits/save-analysis/traits.json
Original file line number Diff line number Diff line change
@@ -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":"<MyStruct as mymod::MyTrait>::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":"<MyStruct as mymod::MyTrait>::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}}]}
Loading

0 comments on commit 367b46e

Please sign in to comment.