Skip to content

Instantly share code, notes, and snippets.

@klutzy
Last active January 3, 2016 08:58
Show Gist options
  • Save klutzy/8439132 to your computer and use it in GitHub Desktop.
Save klutzy/8439132 to your computer and use it in GitHub Desktop.
broken dependency graph impl
#[feature(managed_boxes)];
extern mod extra;
extern mod syntax;
extern mod rustc;
use std::os::args;
use std::hashmap::{HashMap, HashSet};
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util;
use syntax::ast_map::Node;
use syntax::visit;
use syntax::parse::token::get_ident_interner;
use syntax::codemap::Span;
use syntax::visit::Visitor;
use rustc::driver::driver;
use rustc::driver::session;
use rustc::middle::typeck;
struct RotVisitor<'a> {
map: HashSet<(ast::NodeId, ast::NodeId)>, // from -> to
cur_id: ast::NodeId,
def_map: &'a HashMap<ast::NodeId, ast::Def>,
method_map: &'a HashMap<ast::NodeId, typeck::method_map_entry>,
}
impl<'a> Visitor<()> for RotVisitor<'a> {
fn visit_fn(&mut self, fk: &visit::FnKind, decl: &ast::FnDecl,
body: &ast::Block, span: Span, id: ast::NodeId, _: ()) {
let old_id = id;
match fk {
&visit::FkFnBlock => {},
_ => {
self.cur_id = id;
}
}
visit::walk_fn(self, fk, decl, body, span, id, ());
self.cur_id = old_id;
}
fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId, _: ()) {
if self.cur_id != -1 {
let t_node_id = path_to_node_id(self.def_map, id);
self.map.insert((self.cur_id, t_node_id));
}
visit::walk_path(self, path, ());
}
fn visit_expr(&mut self, e: &ast::Expr, _: ()) {
match e.node {
ast::ExprMethodCall(..) => {
match self.method_map.find(&e.id) {
Some(&typeck::method_map_entry { origin, .. }) => {
let node_id = match origin {
typeck::method_static(def_id) => def_id.node,
typeck::method_param(param) => param.trait_id.node,
typeck::method_object(obj) => obj.trait_id.node,
};
self.map.insert((self.cur_id, node_id));
}
None => {},
}
}
_ => {}
}
visit::walk_expr(self, e, ());
}
}
fn node_id_to_name(a: &HashMap<ast::NodeId, Node>, id: ast::NodeId) -> Option<~str> {
let interner = get_ident_interner();
match a.find(&id) {
None => None,
Some(&ast_map::NodeItem(item, path)) => {
Some(ast_map::path_ident_to_str(path, item.ident, interner))
},
Some(&ast_map::NodeMethod(m, _, path)) => {
Some(format!("{}::{}",
ast_map::path_to_str(*path, interner), interner.get(m.ident.name)))
},
s => {
None
},
}
}
fn path_to_node_id(def_map: &HashMap<ast::NodeId, ast::Def>, id: ast::NodeId) -> ast::NodeId {
let def = match def_map.find(&id) {
Some(&def) => def,
_ => return -1,
};
let def_id = match def {
ast::DefVariant(enum_id, _, _) => enum_id,
ast::DefPrimTy(_) => return -1,
_ => ast_util::def_id_of_def(def),
};
def_id.node
}
fn main() {
do rustc::monitor |demitter| {
let mut args = args();
let binary = args.shift();
let matches = extra::getopts::groups::getopts(args, driver::optgroups()).ok().unwrap();
let filename = matches.free[0].as_slice();
let f = Path::new(filename);
let sopts = driver::build_session_options(binary, &matches, demitter);
let sess = driver::build_session(sopts, demitter);
let cfg = driver::build_configuration(sess);
let input = &driver::file_input(f);
let (crate, ast_map) = {
let crate = driver::phase_1_parse_input(sess, cfg.clone(), input);
if driver::stop_after_phase_1(sess) {
return;
}
let res = driver::phase_2_configure_and_expand(sess, cfg, crate);
res
};
let _outputs = driver::build_output_filenames(input, &None, &None, crate.attrs, sess);
//driver::write_out_deps(sess, input, outputs, &crate);
if driver::stop_after_phase_2(sess) {
return;
}
rustc::metadata::creader::read_crates(sess, &crate,
session::sess_os_to_meta_os(sess.targ_cfg.os),
get_ident_interner());
let lang_items = rustc::middle::lang_items::collect_language_items(&crate, sess);
let crate_map = rustc::middle::resolve::resolve_crate(sess, lang_items, &crate);
let rustc::middle::resolve::CrateMap {
def_map: def_map,
exp_map2: _exp_map2,
trait_map: trait_map,
external_exports: _external_exports,
last_private_map: _last_private_map,
} = crate_map;
let named_region_map = rustc::middle::resolve_lifetime::crate(sess, &crate);
let free_vars = rustc::middle::freevars::annotate_freevars(def_map, &crate);
let region_map = rustc::middle::region::resolve_crate(sess, &crate);
let ty_cx = rustc::middle::ty::mk_ctxt(sess, def_map, named_region_map,
ast_map, free_vars,
region_map, lang_items);
let (method_map, _vtable_map) = typeck::check_crate(ty_cx,
trait_map,
&crate);
let items = ty_cx.items.borrow();
let items = items.get();
let def_map = def_map.borrow();
let def_map = def_map.get();
let method_map = method_map.borrow();
let method_map = method_map.get();
let mut visitor = RotVisitor {
map: HashSet::new(),
cur_id: -1,
def_map: def_map,
method_map: method_map,
};
visit::walk_crate(&mut visitor, &crate, ());
println!("digraph \\{");
for &(f, t) in visitor.map.iter() {
let f_name = node_id_to_name(items, f);
let t_name = node_id_to_name(items, t);
if f_name.is_none() || t_name.is_none() {
continue;
}
println!(" \"{}\" -> \"{}\";", f_name.unwrap(), t_name.unwrap());
}
println!("\\}");
}
}
#[crate_type = "lib"];
trait T {
fn d(&self) {}
fn t(&self);
}
struct A;
impl T for A {
fn t(&self) {}
}
impl A {
fn a(&self) {}
fn b() {}
}
fn f() {
A.a();
A::b();
A.t();
A.d();
}
fn g() { f(); f(); }
fn h() { f(); g(); }
fn n() {
do spawn {
g();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment