forked from dobkeratops/rustfind
-
Notifications
You must be signed in to change notification settings - Fork 0
/
crosscratemap.rs
215 lines (194 loc) · 8.39 KB
/
crosscratemap.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
use std::io::println;
use std::path::posix::Path;
use std::path::posix;
use std::io::fs;
use rf_common::*;
use syntax::ast;
use syntax::ast::NodeId;
use syntax::codemap::Pos;
use find_ast_node::FNodeInfoMap;
use jumptodefmap::{JumpToDefMap};
use codemaput::ToZTextFilePos;
use ioutil;
use rustfindctx::{RustFindCtx, str_of_opt_ident};
use find_ast_node::{AstNodeAccessors,NodeKind};
/*new file*/
pub type ZeroBasedIndex=uint;
/// cross crate map, extra info written out when compiling links of a crate
/// allows sunsequent crates to jump to definitions in that crate
/// TODO - check if this already exists in the 'cstore/create metadata'
/// specificially we need node->span info
#[deriving(Clone,Hash,TotalEq,Eq)]
pub struct CrossCrateMapItem {
pub item_name:StrBuf,
pub file_name:StrBuf,
pub line:ZeroBasedIndex,
pub col:uint,
pub len:uint,
pub kind:NodeKind,
}
/*
impl<S> std::hash::Hash<S> for CrossCrateMapItem {
fn hash(&self, state:&mut S) {
}
}
*/
/// Cross Crate Map - resolves file locations from DefIds, across crates
/// also caches item paths
pub type CrossCrateMap = HashMap<ast::DefId,CrossCrateMapItem>;
fn get_def_id_name<'a>(xcm:&'a CrossCrateMap, def_id:&ast::DefId)->&'a str {
xcm.find(def_id).map(|x|x.item_name.as_slice()).unwrap_or("")
}
pub trait FindNode {
fn find_local_node<'a>(&'a self,id:NodeId)->&'a CrossCrateMapItem;
}
impl FindNode for CrossCrateMap {
fn find_local_node<'a>(&'a self, id:NodeId)->&'a CrossCrateMapItem {
let item_defid = ast::DefId{krate:0, node:id};
let xcmi=self.find(&item_defid).unwrap();
xcmi
}
}
pub fn read_cross_crate_map(crate_num:int, crate_name:&str,lib_path:&str)->Box<CrossCrateMap> {
let mut raw_bytes=ioutil::fileLoad(crate_name);
if raw_bytes.len()==0 {
println("loading lib crosscratemap "+lib_path+"/"+crate_name);
raw_bytes=ioutil::fileLoad(lib_path+"/"+crate_name);
if raw_bytes.len()<=0 {
println("must run rustfind in library directories if you want links to work (needs html & .rfx files)\n");
}
}
let rfx=str::from_utf8(raw_bytes.as_slice());
println("loaded cratemap "+rfx.get_ref().len().to_str()+" bytes"+" as crate "+crate_num.to_str());
// for &x in raw_bytes.iter() { rfx.push_char(x as char); }
let mut xcm=box HashMap::new();
for s in rfx.get_ref().lines() {
// println(s.to_str());
let toks=s.split('\t').collect::<Vec<&str>>();
if toks.len()>=6 {
match *toks.get(0) {
"jdef"=> {
// jimp- to def info, we dont need this here as we already generated it
// for the current crate. TODO , genarlized rfx would use it..
}
"node"=> {
// node cratename nodeid parentid sourcefile line col len type [ident]
//cratename is ignoredd, because we already know it.
// parent id ignored, we use span information to reconstruct AST
let node_id: int= from_str::<int>(*toks.get(2)).unwrap_or(0);
xcm.insert(ast::DefId{krate:crate_num as u32, node:node_id as u32,},
CrossCrateMapItem{
item_name: toks.iter().nth(9).map_or(StrBuf::from_str(""),|x|x.to_strbuf()),
file_name: toks.get(4).to_strbuf(),
line: from_str(*toks.get(5)).unwrap_or(0)-1,
col: from_str(*toks.get(6)).unwrap_or(0),
len: from_str(*toks.get(7)).unwrap_or(0),
kind: NodeKind::from_str(*toks.get(8))
}
);
}
// legacy noode definitons,no keyword
_=>{
let node_id:int=from_str(*toks.get(1)).unwrap_or(0);
xcm.insert(ast::DefId{krate:crate_num as u32, node:node_id as u32,},
CrossCrateMapItem{
item_name: toks.iter().nth(9).map_or(StrBuf::from_str(""),|x|x.to_strbuf()),
file_name: toks.get(2).to_strbuf(),
line: from_str(*toks.get(3)).unwrap_or(0)-1,
col: from_str(*toks.get(4)).unwrap_or(0),
len: from_str(*toks.get(5)).unwrap_or(0),
kind: NodeKind::from_str(*toks.get(6))
}
);
}
}
}
}
//dump!(xcm);
println("from cratemap "+rfx.get_ref().len().to_str()+" bytes");
xcm
}
pub fn cross_crate_map_combine(dst:&mut CrossCrateMap, src:&CrossCrateMap) {
for (k,v) in src.iter() {
dst.insert(*k,(*v).clone());
}
}
pub fn cross_crate_map_read_into(dst:&mut CrossCrateMap,crate_num:int, crate_name:&str,lib_path:&str){
let xcm_sub=read_cross_crate_map(crate_num, crate_name, lib_path);
cross_crate_map_combine(dst, xcm_sub);
}
pub fn cross_crate_map_combine_current_crate(xcm:&mut CrossCrateMap,dc:&RustFindCtx, nim:&FNodeInfoMap, def_map:&HashMap<ast::NodeId, ast::DefId>, jdm:&JumpToDefMap) {
let (_,crate_name)=get_crate_name(dc);
for (node_id,node_info) in nim.iter() {
match node_info.rf_span().lo.to_text_file_pos(dc.tycx_ref()) { // f this node has a place in the codemap..
Some(ref tfp)=>{
xcm.insert(ast::DefId{krate:0, node:*node_id as u32,},
CrossCrateMapItem{
item_name: str_of_opt_ident(node_info.rf_get_ident()),
file_name: tfp.name.to_strbuf(),
line: tfp.line as uint,
col: tfp.col as uint,
len: (node_info.rf_span().hi - node_info.rf_span().lo).to_uint(),
kind: node_info.rf_kind()
}
);
}
_=>{}
}
}
}
fn get_crate_name(dc:&RustFindCtx)->(posix::Path,StrBuf) {
let crate_rel_path_name= dc.codemap().files.borrow();
let crate_rel_path_name = Path::new(crate_rel_path_name.get(0).name.as_slice());
let curr_crate_name_only = crate_rel_path_name.filestem_str().unwrap_or("");
(crate_rel_path_name.clone(),curr_crate_name_only.to_strbuf())
}
pub fn cross_crate_map_write(dc:&RustFindCtx, _:&str,nim:&FNodeInfoMap, _:&HashMap<ast::NodeId, ast::DefId>, jdm:&JumpToDefMap) {
// write inter-crate node map
let new_format:bool=true;
let (crate_rel_path_name, curr_crate_name_only) = get_crate_name(dc);
println!("Writing rustfind cross-crate link info for {}", curr_crate_name_only);
let out_path = crate_rel_path_name.with_extension("rfx");
let out = ioutil::file_create_with_dirs(&out_path).map(|out| {
let mut out_file = out;
// todo - idents to a seperate block, they're rare.
for (k,ni) in nim.iter() {
match ni.rf_span().lo.to_text_file_pos(dc.tycx_ref()) {
Some(tfp)=>{
// new format, a little more verbose,
// and includes parent id for easier reconstruction of full AST
// "node" cratename id parent_id filename line col len type [ident]
if new_format {
try!(writeln!(&mut out_file, "node\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
curr_crate_name_only, k, ni.rf_get_parent_id().unwrap_or(0), tfp.name, (tfp.line + 1), tfp.col,
(ni.rf_span().hi - ni.rf_span().lo).to_uint(), ni.rf_kind().as_str(), str_of_opt_ident(ni.rf_get_ident())));
} else {
// old format, relies on spans to reconstruct AST.
// cratename id filename line col len type [ident]
try!(writeln!(&mut out_file, "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}",
curr_crate_name_only, k, tfp.name, (tfp.line+1), tfp.col,
(ni.rf_span().hi-ni.rf_span().lo).to_uint(), ni.rf_kind().as_str(), str_of_opt_ident(ni.rf_get_ident())));
}
},
None=>{}
}
}
for (k,v) in jdm.iter() {
let cname: StrBuf = if v.krate > 0 {
dc.cstore().get_crate_data(v.krate).name.to_strbuf()
} else {
curr_crate_name_only.to_strbuf()
};
//println(cdata.name);
try!(writeln!(&mut out_file, "jdef\t{}\t{}\t{}", k, cname, v.node));
}
Ok(())
});
match out {
Err(e) => println!("Error while writing to {}: {}", out_path.display(), e),
_ => ()
};
// for (k,v) in ndm.iter() {
// outp.push_str("def\t"+k.to_str()+"\t"+dc.tycx.cstore.crate() +v.node.to_str()+"\n");
// }
}