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

[wip] Expand Impl API #131

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
pub path: Option<PathBuf>,
Expand Down Expand Up @@ -89,6 +94,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 @@ -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,
Expand Down Expand Up @@ -256,7 +270,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 @@ -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()
})
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
2 changes: 1 addition & 1 deletion 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
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 <martin@algesten.se>"]

[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}}]}
18 changes: 18 additions & 0 deletions test_data/traits/src/main.rs
Original file line number Diff line number Diff line change
@@ -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) {
}
}
}