diff --git a/.gitignore b/.gitignore index 1fed469..f5ad7f2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ Cargo.lock *.swp *.swo *~ +.vscode *.aux diff --git a/src/analysis.rs b/src/analysis.rs new file mode 100644 index 0000000..4b52f2e --- /dev/null +++ b/src/analysis.rs @@ -0,0 +1,198 @@ +use std::collections::HashMap; + +use csv; + +// Essentially the CSV file in a more accessible manner. +pub struct AnalysisData { + pub var_map: HashMap>, + pub var_ref_map: HashMap>>, + pub type_map: HashMap>, + pub type_ref_map: HashMap>>, + pub func_map: HashMap>, + pub func_ref_map: HashMap>>, +} + +impl AnalysisData { + pub fn new(analysis: &str) -> AnalysisData { + let mut var_map = HashMap::new(); + let mut var_ref_map = HashMap::new(); + let mut type_map = HashMap::new(); + let mut type_ref_map = HashMap::new(); + let mut ctor_map = HashMap::new(); + let mut qual_type_map = HashMap::new(); + let mut func_map = HashMap::new(); + let mut func_ref_map = HashMap::new(); + + for line in analysis.lines() { + //println!("{}", line); + let mut rdr = csv::Reader::from_string(line).has_headers(false); + for row in rdr.records() { + let row = row.unwrap(); + let mut map_record = HashMap::new(); + //println!("{:?}", row); + + let mut it = row.iter(); + it.next(); // discard first value + while let Some(key) = it.next() { + if let Some(val) = it.next() { + // has pair of values as expected + if key.to_string() == "qualname" { + let new_val = val.trim_left_matches(':'); + map_record.insert(key.clone(), new_val.to_string()); + if !map_record.contains_key("name") { + let name: Vec<&str> = new_val.split("::").collect(); + map_record.insert("name".to_string(), name[name.len()-1].to_string()); + } + } else { + map_record.insert(key.clone(), val.clone()); + } + } else { + break; + } + } + + match &row[0][..] { + "crate" => {}, + "external_crate" => {}, + "end_external_crates" => {}, + "function" | "function_impl" | "method_decl" => { + let rec = map_record.clone(); + let copy = map_record.clone(); + let key = rec.get("id").unwrap(); + func_map.insert(key.clone(), map_record); + + // Treat method impl as a function ref + let declid = rec.get("declid"); + match declid { + Some(x) if *x != "" => { + if !func_ref_map.contains_key(x) { + let v = vec![copy]; + func_ref_map.insert(x.clone(), v); + } else { + let vec = func_ref_map.get_mut(x); + vec.unwrap().push(copy); + } + }, + _ => {} + } + }, + "fn_ref" | "fn_call" | "method_call" => { + let rec = map_record.clone(); + let refid = rec.get("refid"); + let declid = rec.get("declid"); + let mut key = "".to_string(); + + match refid { + Some(x) if *x != "" && *x != "0" => { + key = x.clone(); + }, + _ => { + match declid { + Some(x) if *x != "" => { + key = x.clone(); + }, + None | _ => {} + } + } + } + + if !func_ref_map.contains_key(&key) { + let v = vec![map_record]; + func_ref_map.insert(key, v); + } else { + let vec = func_ref_map.get_mut(&key); + vec.unwrap().push(map_record); + + } + }, + "variable" => { + let key = map_record.get("id").unwrap().clone(); + var_map.insert(key, map_record); + }, + "var_ref" => { + let key = map_record.get("refid").unwrap().clone(); + + if !var_ref_map.contains_key(&key) { + let v = vec![map_record]; + var_ref_map.insert(key, v); + } else { + let vec = var_ref_map.get_mut(&key); + vec.unwrap().push(map_record); + + } + }, + "enum" => { + let rec = map_record.clone(); + let key = rec.get("id").unwrap(); + let q_key = rec.get("qualname").unwrap(); + type_map.insert(key.clone(), map_record); + qual_type_map.insert(q_key.clone(), key.clone()); + }, + "struct" => { + let rec = map_record.clone(); + let key = rec.get("id").unwrap(); + let c_key = rec.get("ctor_id").unwrap(); + let q_key = rec.get("qualname").unwrap(); + type_map.insert(key.clone(), map_record); + ctor_map.insert(c_key.clone(), key.clone()); + qual_type_map.insert(q_key.clone(), key.clone()); + }, + "type_ref" | "struct_ref" | "mod_ref" => { + let key = map_record.get("refid").unwrap().clone(); + + if !type_ref_map.contains_key(&key) { + let v = vec![map_record]; + type_ref_map.insert(key, v); + } else { + let vec = type_ref_map.get_mut(&key); + vec.unwrap().push(map_record); + + } + }, + "module" => {}, + "module_alias" => {}, + "unknown_ref" => {}, + _ => {} + } + } + + } + + // Fixup type_refs with refid = 0 and ctor_id references + let mut to_add = Vec::new(); + for (key, value) in type_ref_map.iter() { + if *key == "0" { + for i in value.iter() { + // must check qualname + let name = i.get("qualname").unwrap(); + if qual_type_map.contains_key(name) { + let mut modified = i.clone(); + modified.insert("refid".to_string(), qual_type_map.get(name).unwrap().clone()); + to_add.push(modified); + } + } + } else if let Some(ctor) = ctor_map.get(key) { + for i in value.iter() { + let mut modified = i.clone(); + modified.insert("refid".to_string(), ctor.clone()); + to_add.push(modified); + } + } + } + + for add in to_add.iter() { + let key = add.get("refid").unwrap().clone(); + if !type_ref_map.contains_key(&key) { + let v = vec![add.clone()]; + type_ref_map.insert(key, v); + } else { + let vec = type_ref_map.get_mut(&key); + vec.unwrap().push(add.clone()); + + } + } + + AnalysisData{ var_map: var_map, var_ref_map: var_ref_map, type_map: type_map, + type_ref_map: type_ref_map, func_map: func_map, func_ref_map: func_ref_map } + } +} diff --git a/src/ast_map.rs b/src/ast_map.rs deleted file mode 100644 index 8573e30..0000000 --- a/src/ast_map.rs +++ /dev/null @@ -1,425 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Adapted from front/map/mod.rs - -pub use self::Node::*; -use self::MapEntry::*; - -use syntax::ast::*;//{Name, NodeId, Ident, CRATE_NODE_ID, DUMMY_NODE_ID}; -use rustc::metadata::inline::InlinedItem; -use syntax::visit::{self, Visitor}; -use syntax::ast_util; -use syntax::codemap::{Span, Spanned}; - -use std::cell::RefCell; -use std::iter::{self, repeat}; - -/// A Visitor that walks over an AST and collects Node's into an AST Map. -struct NodeCollector<'ast> { - map: Vec>, - parent_node: NodeId, -} - - -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum PathElem { - PathMod(Name), - PathName(Name) -} - -pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> { - let mut collector = NodeCollector { - map: vec![], - parent_node: CRATE_NODE_ID, - }; - collector.insert_entry(CRATE_NODE_ID, RootCrate); - visit::walk_crate(&mut collector, &forest.krate); - let map = collector.map; - - Map { - forest: forest, - map: RefCell::new(map) - } -} - -/// Represents a mapping from Node IDs to AST elements and their parent -/// Node IDs -#[derive(Clone)] -pub struct Map<'ast> { - /// The backing storage for all the AST nodes. - pub forest: &'ast Forest, - - /// NodeIds are sequential integers from 0, so we can be - /// super-compact by storing them in a vector. Not everything with - /// a NodeId is in the map, but empirically the occupancy is about - /// 75-80%, so there's not too much overhead (certainly less than - /// a hashmap, since they (at the time of writing) have a maximum - /// of 75% occupancy). - /// - /// Also, indexing is pretty quick when you've got a vector and - /// plain old integers. - map: RefCell>> -} - -/// Stores a crate and any number of inlined items from other crates. -pub struct Forest { - pub krate: Crate// inlined_items: TypedArena -} - -impl Forest { - pub fn new(krate: Crate) -> Forest { - Forest { - krate: krate, - //inlined_items: TypedArena::new() - } - } - - pub fn krate<'ast>(&'ast self) -> &'ast Crate { - &self.krate - } -} - -/// Represents an entry and its parent NodeID. -/// The odd layout is to bring down the total size. -#[derive(Copy, Debug)] -enum MapEntry<'ast> { - /// Placeholder for holes in the map. - NotPresent, - - /// All the node types, with a parent ID. - EntryItem(NodeId, &'ast Item), - EntryForeignItem(NodeId, &'ast ForeignItem), - EntryTraitItem(NodeId, &'ast TraitItem), - EntryImplItem(NodeId, &'ast ImplItem), - EntryVariant(NodeId, &'ast Variant), - EntryExpr(NodeId, &'ast Expr), - EntryStmt(NodeId, &'ast Stmt), - EntryArg(NodeId, &'ast Pat), - EntryLocal(NodeId, &'ast Pat), - EntryPat(NodeId, &'ast Pat), - EntryBlock(NodeId, &'ast Block), - EntryStructCtor(NodeId, &'ast StructDef), - EntryLifetime(NodeId, &'ast Lifetime), - EntryTyParam(NodeId, &'ast TyParam), - - /// Roots for node trees. - RootCrate, - RootInlinedParent(&'ast InlinedParent) -} - -impl<'ast> Clone for MapEntry<'ast> { - fn clone(&self) -> MapEntry<'ast> { - *self - } -} - -#[derive(Debug)] -pub struct InlinedParent { - path: Vec, - ii: InlinedItem -} - -#[derive(Copy, Clone, Debug)] -pub enum Node<'ast> { - NodeItem(&'ast Item), - NodeForeignItem(&'ast ForeignItem), - NodeTraitItem(&'ast TraitItem), - NodeImplItem(&'ast ImplItem), - NodeVariant(&'ast Variant), - NodeExpr(&'ast Expr), - NodeStmt(&'ast Stmt), - NodeArg(&'ast Pat), - NodeLocal(&'ast Pat), - NodePat(&'ast Pat), - NodeBlock(&'ast Block), - - /// NodeStructCtor represents a tuple struct. - NodeStructCtor(&'ast StructDef), - - NodeLifetime(&'ast Lifetime), - NodeTyParam(&'ast TyParam) -} - -impl<'ast> MapEntry<'ast> { - fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> { - match node { - NodeItem(n) => EntryItem(p, n), - NodeForeignItem(n) => EntryForeignItem(p, n), - NodeTraitItem(n) => EntryTraitItem(p, n), - NodeImplItem(n) => EntryImplItem(p, n), - NodeVariant(n) => EntryVariant(p, n), - NodeExpr(n) => EntryExpr(p, n), - NodeStmt(n) => EntryStmt(p, n), - NodeArg(n) => EntryArg(p, n), - NodeLocal(n) => EntryLocal(p, n), - NodePat(n) => EntryPat(p, n), - NodeBlock(n) => EntryBlock(p, n), - NodeStructCtor(n) => EntryStructCtor(p, n), - NodeLifetime(n) => EntryLifetime(p, n), - NodeTyParam(n) => EntryTyParam(p, n), - } - } - - fn parent_node(self) -> Option { - Some(match self { - EntryItem(id, _) => id, - EntryForeignItem(id, _) => id, - EntryTraitItem(id, _) => id, - EntryImplItem(id, _) => id, - EntryVariant(id, _) => id, - EntryExpr(id, _) => id, - EntryStmt(id, _) => id, - EntryArg(id, _) => id, - EntryLocal(id, _) => id, - EntryPat(id, _) => id, - EntryBlock(id, _) => id, - EntryStructCtor(id, _) => id, - EntryLifetime(id, _) => id, - EntryTyParam(id, _) => id, - _ => return None - }) - } - - fn to_node(self) -> Option> { - Some(match self { - EntryItem(_, n) => NodeItem(n), - EntryForeignItem(_, n) => NodeForeignItem(n), - EntryTraitItem(_, n) => NodeTraitItem(n), - EntryImplItem(_, n) => NodeImplItem(n), - EntryVariant(_, n) => NodeVariant(n), - EntryExpr(_, n) => NodeExpr(n), - EntryStmt(_, n) => NodeStmt(n), - EntryArg(_, n) => NodeArg(n), - EntryLocal(_, n) => NodeLocal(n), - EntryPat(_, n) => NodePat(n), - EntryBlock(_, n) => NodeBlock(n), - EntryStructCtor(_, n) => NodeStructCtor(n), - EntryLifetime(_, n) => NodeLifetime(n), - EntryTyParam(_, n) => NodeTyParam(n), - _ => return None - }) - } -} - -impl<'ast> NodeCollector<'ast> { - fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { - debug!("ast_map: {:?} => {:?}", id, entry); - let len = self.map.len(); - if id as usize >= len { - self.map.extend(repeat(NotPresent).take(id as usize - len + 1)); - } - self.map[id as usize] = entry; - } - - fn insert(&mut self, id: NodeId, node: Node<'ast>) { - let entry = MapEntry::from_node(self.parent_node, node); - self.insert_entry(id, entry); - } - - fn visit_fn_decl(&mut self, decl: &'ast FnDecl) { - for a in &decl.inputs { - self.insert(a.id, NodeArg(&*a.pat)); - } - } -} - -impl<'ast> Visitor<'ast> for NodeCollector<'ast> { - fn visit_item(&mut self, i: &'ast Item) { - self.insert(i.id, NodeItem(i)); - - let parent_node = self.parent_node; - self.parent_node = i.id; - - match i.node { - ItemImpl(_, _, _, _, _, ref impl_items) => { - for ii in impl_items { - self.insert(ii.id, NodeImplItem(ii)); - } - } - ItemEnum(ref enum_definition, _) => { - for v in &enum_definition.variants { - self.insert(v.node.id, NodeVariant(&**v)); - } - } - ItemForeignMod(ref nm) => { - for nitem in &nm.items { - self.insert(nitem.id, NodeForeignItem(&**nitem)); - } - } - ItemStruct(ref struct_def, _) => { - // If this is a tuple-like struct, register the constructor. - match struct_def.ctor_id { - Some(ctor_id) => { - self.insert(ctor_id, NodeStructCtor(&**struct_def)); - } - None => {} - } - } - ItemTrait(_, _, ref bounds, ref trait_items) => { - for b in bounds.iter() { - if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b { - self.insert(t.trait_ref.ref_id, NodeItem(i)); - } - } - - for ti in trait_items { - self.insert(ti.id, NodeTraitItem(ti)); - } - } - ItemUse(ref view_path) => { - match view_path.node { - ViewPathList(_, ref paths) => { - for path in paths { - self.insert(path.node.id(), NodeItem(i)); - } - } - _ => () - } - } - _ => {} - } - visit::walk_item(self, i); - self.parent_node = parent_node; - } - - fn visit_generics(&mut self, generics: &'ast Generics) { - for ty_param in generics.ty_params.iter() { - self.insert(ty_param.id, NodeTyParam(ty_param)); - } - - visit::walk_generics(self, generics); - } - - fn visit_trait_item(&mut self, ti: &'ast TraitItem) { - let parent_node = self.parent_node; - self.parent_node = ti.id; - visit::walk_trait_item(self, ti); - self.parent_node = parent_node; - } - - fn visit_impl_item(&mut self, ii: &'ast ImplItem) { - let parent_node = self.parent_node; - self.parent_node = ii.id; - - visit::walk_impl_item(self, ii); - - self.parent_node = parent_node; - } - - fn visit_pat(&mut self, pat: &'ast Pat) { - self.insert(pat.id, match pat.node { - // Note: this is at least *potentially* a pattern... - PatIdent(..) => NodeLocal(pat), - _ => NodePat(pat) - }); - - let parent_node = self.parent_node; - self.parent_node = pat.id; - visit::walk_pat(self, pat); - self.parent_node = parent_node; - } - - fn visit_expr(&mut self, expr: &'ast Expr) { - self.insert(expr.id, NodeExpr(expr)); - let parent_node = self.parent_node; - self.parent_node = expr.id; - visit::walk_expr(self, expr); - self.parent_node = parent_node; - } - - fn visit_stmt(&mut self, stmt: &'ast Stmt) { - let id = ast_util::stmt_id(stmt); - self.insert(id, NodeStmt(stmt)); - let parent_node = self.parent_node; - self.parent_node = id; - visit::walk_stmt(self, stmt); - self.parent_node = parent_node; - } - - fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, id: NodeId) { - let parent_node = self.parent_node; - self.parent_node = id; - self.visit_fn_decl(fd); - visit::walk_fn(self, fk, fd, b, s); - self.parent_node = parent_node; - } - - fn visit_ty(&mut self, ty: &'ast Ty) { - let parent_node = self.parent_node; - self.parent_node = ty.id; - match ty.node { - TyBareFn(ref fd) => { - self.visit_fn_decl(&*fd.decl); - } - _ => {} - } - visit::walk_ty(self, ty); - self.parent_node = parent_node; - } - - fn visit_block(&mut self, block: &'ast Block) { - self.insert(block.id, NodeBlock(block)); - let parent_node = self.parent_node; - self.parent_node = block.id; - visit::walk_block(self, block); - self.parent_node = parent_node; - } - - fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) { - self.insert(lifetime.id, NodeLifetime(lifetime)); - } - - fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { - self.visit_lifetime_ref(&def.lifetime); - } -} - -impl<'ast> Map<'ast> { - fn entry_count(&self) -> usize { - self.map.borrow().len() - } - - fn find_entry(&self, id: NodeId) -> Option> { - self.map.borrow().get(id as usize).cloned() - } - - pub fn krate(&self) -> &'ast Crate { - &self.forest.krate - } - - /// Retrieve the Node corresponding to `id`, panicking if it cannot - /// be found. - pub fn get(&self, id: NodeId) -> Node<'ast> { - match self.find(id) { - Some(node) => node, - None => panic!("couldn't find node id {} in the AST map", id) - } - } - - /// Retrieve the Node corresponding to `id`, returning None if - /// cannot be found. - pub fn find(&self, id: NodeId) -> Option> { - self.find_entry(id).and_then(|x| x.to_node()) - } - - /// Similar to get_parent, returns the parent node id or id if there is no - /// parent. - /// This function returns the immediate parent in the AST, whereas get_parent - /// returns the enclosing item. Note that this might not be the actual parent - /// node in the AST - some kinds of nodes are not in the map and these will - /// never appear as the parent_node. So you can always walk the parent_nodes - /// from a node to the root of the ast (unless you get the same id back here - /// that can happen if the id is not in the map itself or is just weird). - pub fn get_parent_node(&self, id: NodeId) -> NodeId { - self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) - } -} diff --git a/src/folder.rs b/src/compiler/folder.rs similarity index 71% rename from src/folder.rs rename to src/compiler/folder.rs index 444f5f6..c38cdc6 100644 --- a/src/folder.rs +++ b/src/compiler/folder.rs @@ -1,40 +1,33 @@ - -use trans::save::{generated_code, recorder, SaveContext, Data}; - -use rustc::session::Session; - -use rustc::front::map as ast_map; use rustc_front::hir; -use rustc_front::lowering; +use rustc_front::fold::{self, Folder}; +use rustc_front::intravisit::{self as visit, Visitor}; +use rustc_front::lowering::LoweringContext; +use rustc_trans::save::{generated_code, recorder, SaveContext, Data}; +use rustc_trans::save::span_utils::SpanUtils; +use rustc::front::map as ast_map; +use rustc::metadata::cstore::LOCAL_CRATE; use rustc::middle::def::{self, PathResolution}; -use rustc::middle::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::def_id::DefId; use rustc::middle::ty; use rustc_resolve as resolve; use rustc_resolve::Namespace; use std::collections::HashMap; -use syntax; -use syntax::ast::*; +use syntax::ast::{self, NodeId}; use syntax::codemap::{DUMMY_SP, Span, Spanned, NO_EXPANSION}; use syntax::ext::{base, expand}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; -use rustc_front::visit::{self, Visitor}; -use syntax::fold::Folder; -use syntax::fold::{noop_fold_expr, noop_fold_explicit_self_underscore}; -use syntax::util::small_vector::SmallVector; -use trans::save::span_utils::SpanUtils; -use refactor::build_path; +use super::util::build_path; // Fold local variable and replace usages with initializing expression. -pub struct InlineFolder<'l, 'tcx: 'l> { - save_ctxt: SaveContext<'l, 'tcx>, - sess: &'l Session, +pub struct InlineFolder<'l, 'tcx: 'l, 'lcx:'l> { + //save_ctxt: SaveContext<'l, 'tcx>, tcx: &'l ty::ctxt<'tcx>, - analysis: &'l ty::CrateAnalysis, + lcx: &'l LoweringContext<'lcx>, span: SpanUtils<'l>, node_to_find: NodeId, - pub to_replace: Option>, + pub to_replace: Option>, pub type_node_id: NodeId, pub usages: u32, pub mutable: bool, @@ -42,18 +35,17 @@ pub struct InlineFolder<'l, 'tcx: 'l> { pub changed_paths: bool, } -impl <'l, 'tcx> InlineFolder<'l, 'tcx> { +impl <'l, 'tcx, 'lcx> InlineFolder<'l, 'tcx, 'lcx> { pub fn new(tcx: &'l ty::ctxt<'tcx>, - analysis: &'l ty::CrateAnalysis, + lcx: &'l LoweringContext<'lcx>, node_to_find: NodeId) - -> InlineFolder<'l, 'tcx> { - let span_utils = SpanUtils::new(&tcx.sess); + -> InlineFolder<'l, 'tcx, 'lcx> { InlineFolder { - sess: &tcx.sess, tcx: tcx, - save_ctxt: SaveContext::from_span_utils(tcx, span_utils.clone()), - analysis: analysis, - span: span_utils.clone(), + lcx: lcx, + //lcx: lcx, + //save_ctxt: SaveContext::from_span_utils(tcx, span_utils.clone()), + span: SpanUtils::new(&tcx.sess), node_to_find: node_to_find, to_replace: None, type_node_id: 0, @@ -65,40 +57,42 @@ impl <'l, 'tcx> InlineFolder<'l, 'tcx> { } // TODO: Need to make sure that double decl are not inlined... - fn noop_fold_decl(&mut self, d: P) -> SmallVector> { + fn noop_fold_decl(&mut self, d: P) -> P { d.and_then(|Spanned {node, span}| match node { - DeclLocal(ref l) if l.pat.id == self.node_to_find => { + hir::DeclLocal(ref l) if l.pat.id == self.node_to_find => { self.to_replace = l.init.clone(); l.init.clone().unwrap().and_then( - |expr|{ visit::walk_expr(self, &*lowering::lower_expr(&expr.clone())); } + |expr| visit::walk_expr(self, &expr) ); + if let Some(def_type) = l.ty.as_ref() { self.type_node_id = def_type.id; } - match l.pat.node { - PatIdent(ref binding, ref path, ref optpat) => { - self.mutable = match *binding { - BindByRef(MutMutable) => true, - BindByValue(MutMutable) => true, - _ => false - }; - }, - _ => () + + if let hir::PatIdent(ref binding, _, _) = l.pat.node { + self.mutable = match *binding { + hir::BindByRef(hir::MutMutable) => true, + hir::BindByValue(hir::MutMutable) => true, + _ => false + }; } - SmallVector::zero() + + //SmallVector::zero() + // FIXME: return something meaningful + panic!("folder.rs") }, - DeclLocal(l) => SmallVector::one(P(Spanned { - node: DeclLocal(self.fold_local(l)), + hir::DeclLocal(l) => P(Spanned { + node: hir::DeclLocal(self.fold_local(l)), span: self.new_span(span) - })), - DeclItem(it) => self.fold_item(it).into_iter().map(|i| P(Spanned { - node: DeclItem(i), + }), + hir::DeclItem(it) => P(Spanned { + node: hir::DeclItem(self.fold_item_id(it)), span: self.new_span(span) - })).collect() + }) }) } - fn process_path(&mut self, id: NodeId, path: &Path, ref_kind: Option) -> bool { + fn process_path(&mut self, id: NodeId, path: &hir::Path, _: Option) -> bool { let mut not_generated = path.clone(); let mut path = path; if generated_code(path.span) { @@ -106,7 +100,9 @@ impl <'l, 'tcx> InlineFolder<'l, 'tcx> { path = ¬_generated; } - let path_data = self.save_ctxt.get_path_data(id, &self.front_to_ast(path)); + // FIXME: does this work properly? Or should we save the context between calls? + let save_ctxt = SaveContext::from_span_utils(self.tcx, self.lcx, self.span.clone()); + let path_data = save_ctxt.get_path_data(id, &self.front_to_ast(path)); let path_data = match path_data { Some(pd) => pd, None => { @@ -123,34 +119,34 @@ impl <'l, 'tcx> InlineFolder<'l, 'tcx> { Some(vrd.span), vrd.ref_id, vrd.scope);*/ - let DefId { krate, node } = vrd.ref_id; - if krate == LOCAL_CRATE && node == self.node_to_find { + let DefId { krate, index } = vrd.ref_id; + if krate == LOCAL_CRATE && index.as_u32() == self.node_to_find { self.usages += 1; return true; } } - Data::TypeRefData(ref trd) => { + Data::TypeRefData(_) => { /*self.fmt.ref_str(recorder::Row::TypeRef, path.span, Some(trd.span), trd.ref_id, trd.scope);*/ } - Data::MethodCallData(ref mcd) => { + Data::MethodCallData(_) => { /*self.fmt.meth_call_str(path.span, Some(mcd.span), mcd.ref_id, mcd.decl_id, mcd.scope);*/ } - Data::FunctionCallData(fcd) => { + Data::FunctionCallData(_) => { /*self.fmt.fn_call_str(path.span, Some(fcd.span), fcd.ref_id, fcd.scope);*/ } _ => { - self.sess.span_bug(path.span, + self.tcx.sess.span_bug(path.span, &format!("Unexpected data: {:?}", path_data)); } } @@ -158,34 +154,31 @@ impl <'l, 'tcx> InlineFolder<'l, 'tcx> { false } - fn front_to_ast(&self, input: &Path) -> syntax::ast::Path { - let ps = &self.sess.parse_sess; + fn front_to_ast(&self, input: &hir::Path) -> ast::Path { + let ps = &self.tcx.sess.parse_sess; let mut tmp = vec![]; - let cx = base::ExtCtxt::new(ps, Vec::new(),//krate.config.clone(), + let cx = base::ExtCtxt::new(ps, Vec::new(), expand::ExpansionConfig::default("".to_string()), &mut tmp); cx.path_ident(input.span.clone(), input.segments[0].identifier) } - -//pub fn noop_fold_expr(Expr {id, node, span}: Expr, folder: &mut T) -> Expr {} - } -impl <'l, 'tcx> Folder for InlineFolder<'l, 'tcx> { - fn fold_decl(&mut self, d: P) -> SmallVector> { +impl <'l, 'tcx, 'lcx> Folder for InlineFolder<'l, 'tcx, 'lcx> { + fn fold_decl(&mut self, d: P) -> P { self.noop_fold_decl(d) } - fn fold_expr(&mut self, e: P) -> P { + fn fold_expr(&mut self, e: P) -> P { debug!("{:?}", e); e.map(|e| { match e.node { - ExprPath(ref q, ref path) => { + hir::ExprPath(_, ref path) => { if self.process_path(e.id, path, None) { let node_to_find = e.id; let s_ctx = path.segments[0].clone().identifier.ctxt; - let mut resolver = resolve::create_resolver(&self.sess, &self.tcx.map, + let mut resolver = resolve::create_resolver(&self.tcx.sess, &self.tcx.map, &self.tcx.map.krate(), resolve::MakeGlobMap::No, Some(Box::new(move |node: ast_map::Node, resolved: &mut bool| { @@ -214,8 +207,6 @@ impl <'l, 'tcx> Folder for InlineFolder<'l, 'tcx> { // Fix for the current simple variable case if path.1 == Namespace::ValueNS && path.0.segments.len() == 1 { let mut t = path.0.segments[0].clone().identifier; - let krate = self.tcx.map.krate(); - let ps = &self.sess.parse_sess; t.ctxt = s_ctx; let path = build_path(DUMMY_SP, vec![t]); @@ -224,10 +215,9 @@ impl <'l, 'tcx> Folder for InlineFolder<'l, 'tcx> { } else { resolution = resolver.resolve_path(self.node_to_find, &path.0, 0, path.1, true); } - if let Some(resolution) = resolution { - let PathResolution {base_def, ..} = resolution; - debug!("BASEDEF {:?}", base_def); - if base_def != *def { + if let Some(res) = resolution { + debug!("BASEDEF {:?}", res.base_def); + if res.base_def != *def { debug!("OH DEAR, DEF IS NOW DIFFERENT"); self.changed_paths = true; } @@ -246,15 +236,15 @@ impl <'l, 'tcx> Folder for InlineFolder<'l, 'tcx> { _ => {} } - noop_fold_expr(e, self) + fold::noop_fold_expr(e, self) }) } } -impl<'l, 'tcx, 'v> Visitor<'v> for InlineFolder<'l, 'tcx> { +impl<'l, 'tcx, 'lcx, 'v> Visitor<'v> for InlineFolder<'l, 'tcx, 'lcx> { fn visit_expr(&mut self, ex: &hir::Expr) { let node_to_find = self.node_to_find; - let mut resolver = resolve::create_resolver(&self.sess, &self.tcx.map, + let mut resolver = resolve::create_resolver(&self.tcx.sess, &self.tcx.map, &self.tcx.map.krate(), resolve::MakeGlobMap::No, Some(Box::new(move |node: ast_map::Node, resolved: &mut bool| { @@ -305,35 +295,35 @@ impl<'l, 'tcx, 'v> Visitor<'v> for InlineFolder<'l, 'tcx> { // Fold lifetimes so they are all removed. pub struct LifetimeFolder { pub has_bounds: bool, - pub expl_self: Name, + pub expl_self: ast::Name, } impl Folder for LifetimeFolder { - fn fold_opt_lifetime(&mut self, o_lt: Option) -> Option { + fn fold_opt_lifetime(&mut self, _: Option) -> Option { None } - fn fold_generics(&mut self, Generics {ty_params, lifetimes, where_clause}: Generics) -> Generics { + fn fold_generics(&mut self, hir::Generics {ty_params, lifetimes, where_clause}: hir::Generics) -> hir::Generics { for lifetime in lifetimes.iter() { if lifetime.bounds.len() > 0 { self.has_bounds = true; } } - Generics { + hir::Generics { ty_params: self.fold_ty_params(ty_params), lifetimes: Vec::new(), where_clause: self.fold_where_clause(where_clause), } } - fn fold_explicit_self_underscore(&mut self, es: ExplicitSelf_) -> ExplicitSelf_ { + fn fold_explicit_self_underscore(&mut self, es: hir::ExplicitSelf_) -> hir::ExplicitSelf_ { match es { - SelfRegion(Some(lifetime), m, ident) => { + hir::SelfRegion(Some(lifetime), _, _) => { self.expl_self = lifetime.name; } _ => () } - noop_fold_explicit_self_underscore(es, self) + fold::noop_fold_explicit_self_underscore(es, self) } } diff --git a/src/lifetime_walker.rs b/src/compiler/lifetime_walker.rs similarity index 88% rename from src/lifetime_walker.rs rename to src/compiler/lifetime_walker.rs index 1251d66..93ff24d 100644 --- a/src/lifetime_walker.rs +++ b/src/compiler/lifetime_walker.rs @@ -1,11 +1,8 @@ use syntax::ast::Name; use std::collections::HashSet; -//use syntax::ast::*; -//use syntax::visit::{self, Visitor}; use rustc_front::hir::*; -use rustc_front::visit::{self, Visitor}; -use syntax::codemap::Span; +use rustc_front::intravisit::{self as visit, Visitor}; pub struct LifetimeWalker { pub anon: u32, @@ -27,7 +24,7 @@ impl LifetimeWalker { // Walk the AST for lifetimes and count them. impl<'v> Visitor<'v> for LifetimeWalker { - +/* FIXME! fn visit_opt_lifetime_ref(&mut self, _span: Span, opt_lifetime: &'v Option) { @@ -40,6 +37,7 @@ impl<'v> Visitor<'v> for LifetimeWalker { None => self.anon += 1 } } + */ fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { self.expl_self = self.anon; diff --git a/src/loader.rs b/src/compiler/loader.rs similarity index 83% rename from src/loader.rs rename to src/compiler/loader.rs index 5617334..d9d11a2 100644 --- a/src/loader.rs +++ b/src/compiler/loader.rs @@ -1,10 +1,8 @@ - use std::collections::HashMap; -use std::path::Path; -use std::fs; +use std::fs::{self, File}; use std::io::{self, Read}; -use syntax::codemap::FileLoader; -use syntax::codemap::FileName; +use std::path::Path; +use syntax::codemap::{FileLoader, FileName}; pub struct ReplaceLoader { files: HashMap, @@ -23,8 +21,7 @@ impl FileLoader for ReplaceLoader { } let mut src = String::new(); - try!(try!(fs::File::open(path)).read_to_string(&mut src)); - Ok(src) + try!(File::open(path)).read_to_string(&mut src).map(move |_| src) } } diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs new file mode 100644 index 0000000..383dd97 --- /dev/null +++ b/src/compiler/mod.rs @@ -0,0 +1,140 @@ +mod folder; +mod lifetime_walker; +mod loader; +mod refactor_calls; +mod util; + +use std::{env, thread}; + +use rustc::lint; +use rustc::session::{self, config}; +use rustc_driver::{CompilerCalls, Compilation, diagnostics_registry, driver, + handle_options, monitor}; +use rustc_lint; +use syntax::diagnostic; +use syntax::ast::NodeId; +use syntax::codemap::{self, FileLoader}; + +use self::loader::ReplaceLoader; +use self::refactor_calls::RefactorCalls; +use self::util::{make_input, make_output}; +use refactor::{RefactorType, Response}; + +// Used to check same-block conflicts in modules (since name resolution doesn't seem to). +pub fn check_reduced_graph(root: String, + files: Vec<(String, String)>, + new_name: String, + node: NodeId) + -> Result<(), Response> { + match run_resolution(root, Some(files), None, RefactorType::Reduced, new_name, node, false) { + Ok(()) => Ok(()), + Err(_) => Err(Response::Conflict) + } +} + +// What does this do? +pub fn run_resolution(root: String, + file_override: Option>, + working_file: Option, + kind: RefactorType, + new_name: String, + node: NodeId, + full: bool) + -> Result<(), (usize, usize, String, i32)> { + let key = "RUST_FOLDER"; + let mut path = String::new(); + let args = match env::var(key) { + Ok(val) => { + path.push_str("-L"); + path.push_str(&val[..]); + vec!["refactor".to_owned(), + path, + "-Z".to_owned(), "keep_mtwt_tables".to_owned(), + //"--crate-type", "lib", + root] + } + Err(_) => vec!["refactor".to_owned(), root], + }; + + let mut loader = ReplaceLoader::new(); + match file_override.as_ref() { + Some(input) => { + for file in input.iter() { + loader.add_file(file.0.clone(), file.1.clone()); + } + }, + None => () + } + + thread::catch_panic(move || { + let mut call_ctxt = RefactorCalls::new(kind, new_name, node, file_override, + working_file, full); + // Calling monitor fixes a bug where this process is put into an + // invalid (logging) state. + match kind { + RefactorType::InlineLocal | + RefactorType::ReifyLifetime | + RefactorType::ElideLifetime => run_compiler(&args, &mut call_ctxt, Box::new(loader)), + _ => monitor(move || run_compiler(&args, &mut call_ctxt, Box::new(loader))) + } + }).map_err(|any| + *any.downcast().ok().unwrap_or_default() + ) +} + +// Basically a clone of the function librustc_driver +fn run_compiler<'a, T: CompilerCalls<'a>>(args: &[String], callbacks: &mut T, loader: Box) { + macro_rules! do_or_return {($expr: expr) => { + match $expr { + Compilation::Stop => return, + Compilation::Continue => {} + } + }} + + let matches = match handle_options(args.to_vec()) { + Some(matches) => matches, + None => return + }; + + let sopts = config::build_session_options(&matches); + + let descriptions = diagnostics_registry(); + + do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color)); + + let (odir, ofile) = make_output(&matches); + let (input, input_file_path) = match make_input(&matches.free) { + Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), + None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) { + Some((input, input_file_path)) => (input, input_file_path), + None => return + } + }; + + let can_print_warnings = sopts.lint_opts + .iter() + .filter(|&&(ref key, _)| *key == "warnings") + .map(|&(_, ref level)| *level != lint::Allow) + .last() + .unwrap_or(true); + + + let codemap = codemap::CodeMap::with_file_loader(loader); + let diagnostic_handler = + diagnostic::Handler::new(sopts.color, Some(descriptions), can_print_warnings); + let span_diagnostic_handler = + diagnostic::SpanHandler::new(diagnostic_handler, codemap); + + let mut sess = session::build_session_(sopts, input_file_path, span_diagnostic_handler); + rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + if sess.unstable_options() { + sess.opts.show_span = matches.opt_str("show-span"); + } + let cfg = config::build_configuration(&sess); + + do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); + + let plugins = sess.opts.debugging_opts.extra_plugins.clone(); + let control = callbacks.build_controller(&sess); + driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control); +} diff --git a/src/compiler/refactor_calls.rs b/src/compiler/refactor_calls.rs new file mode 100644 index 0000000..bab4b08 --- /dev/null +++ b/src/compiler/refactor_calls.rs @@ -0,0 +1,704 @@ +use std::collections::{HashMap, HashSet}; +use std::io::Write; +use std::path::PathBuf; + +use rustc::front::map::{self as ast_map, Node}; +use rustc::session::Session; +use rustc::session::config::{self, Input}; +use rustc::metadata::creader::LocalCrateReader; +use rustc_driver::{CompilerCalls, Compilation, driver, RustcDefaultCalls}; +use rustc_front::fold::Folder; +use rustc_front::hir; +use rustc_front::hir::Item_::{ItemImpl, ItemStruct}; +use rustc_front::intravisit as visit; +use rustc_front::print::pprust::{self, State}; +use rustc_resolve as resolve; +use rustc::middle::def_id::{DefId, DefIndex}; +use rustc::middle::lang_items; +use rustc::middle::infer::region_inference::SameRegions; +use rustc::middle::ty::BoundRegion::*; +use syntax::{attr, diagnostics}; +use syntax::ast::{self, Name, NodeId}; +use syntax::codemap::{DUMMY_SP, Pos, Spanned}; +use syntax::ext::build::AstBuilder; +use syntax::ext::mtwt; +use syntax::parse::token; +use syntax::print::pp::eof; +use syntax::ptr::P; + +use getopts; + +use super::folder::{InlineFolder, LifetimeFolder}; +use super::lifetime_walker::LifetimeWalker; +use super::util::{build_path, lifetimes_in_scope}; +use rebuilder::{Rebuilder, LifeGiver}; +use refactor::RefactorType; + +fn default_defid() -> DefId { + DefId { + krate: 0, + index: DefIndex::new(0) + } +} + +pub struct RefactorCalls { + r_type: RefactorType, + new_name: String, + node_to_find: NodeId, + input: Option>, + working_file: Option, + is_full: bool, +} + +impl RefactorCalls { + pub fn new(t: RefactorType, + new_name: String, + node: NodeId, + new_file: Option>, + working_file: Option, + is_full: bool) + -> RefactorCalls + { + RefactorCalls { + r_type: t, + new_name: new_name, + node_to_find: node, + input: new_file, + working_file: working_file, + is_full: is_full, + } + } +} + +impl<'a> CompilerCalls<'a> for RefactorCalls { + fn late_callback(&mut self, + m: &getopts::Matches, + s: &Session, + i: &Input, + odir: &Option, + ofile: &Option) + -> Compilation { + RustcDefaultCalls.late_callback(m, s, i, odir, ofile); + + // FIXME: We ignore the result of late_callback... Why? + Compilation::Continue + } + + fn no_input(&mut self, + m: &getopts::Matches, + o: &config::Options, + odir: &Option, + ofile: &Option, + r: &diagnostics::registry::Registry) + -> Option<(Input, Option)> { + RustcDefaultCalls.no_input(m, o, odir, ofile, r); + + // FIXME: This is not optimal error handling. + panic!("No input supplied"); + } + + fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> { + let r_type = self.r_type; + let is_full = self.is_full; + let node_to_find = self.node_to_find; + let input = self.working_file.clone().unwrap_or_default(); + + // FIXME: I migrated a lot of stuff to use the HIR just to appease the compiler... Is this ok? + let mut control = driver::CompileController::basic(); + if is_full { + control.after_analysis.stop = Compilation::Stop; + control.after_analysis.callback = Box::new(move |state| { + let tcx = state.tcx.unwrap(); + let lcx = state.lcx.unwrap(); + + // FIXME: doest his work properly? + // Old code: + // let mut new_for = Forest::new(krate.clone()); + // let ast_map_original = map_crate(&mut new_for); + // New code: + let ast_map_original = state.ast_map.unwrap().clone(); + let ast_map = &tcx.map; + if r_type == RefactorType::InlineLocal { + + debug!("{:?}", ast_map.get(ast_map.get_parent(node_to_find))); + debug!("{:?}", ast_map.get(node_to_find)); + + match ast_map.get(node_to_find) { + Node::NodeLocal(_) => { }, + _ => { panic!(); } + } + + let mut parent = None; + let mut other = None; + match ast_map_original.get(ast_map.get_parent(node_to_find)) { + Node::NodeItem(item) => { + parent = Some(P((*item).clone())); + other = Some((*item).clone()); + debug!("{:?}", pprust::item_to_string(item)); + }, + _ => {} + } + + let src; + src = state.session.codemap().get_filemap(&input[..]) + .src + .as_ref() + .unwrap() + .as_bytes() + .to_vec(); + // need to distinguish internal errors + + let mut rdr = &src[..]; + let mut out = Vec::new(); + let ann = pprust::NoAnn; + { + let out_borrow: &mut Write = &mut out; + // FIXME: the last argument was added just to make this compile... Should it be changed to something else? + let mut pp_state = State::new_from_input(state.session.codemap(), state.session.diagnostic(), input.clone(), &mut rdr, Box::new(out_borrow), &ann, true, None); + + if let Some(other) = other { + let _ = pp_state.print_item(&other); + //debug!("{:?}", v); + //pp_state.print_mod(&krate.module, &krate.attrs); + } + let _ = eof(&mut pp_state.s); + } + let _ = out.flush(); + + // Build save walker + let src2; + src2 = state.session.codemap().get_filemap(&input[..]) + .src + .as_ref() + .unwrap() + .as_bytes() + .to_vec(); + let mut rdr2 = &src2[..]; + + if let Some(par) = parent { + let outer_span = par.span; + //let mut visitor = DumpCsvVisitor::new(tcx, anal, output_file); + let mut folder = InlineFolder::new(tcx, lcx, node_to_find); + debug!("{:?}", folder.fold_item((*par).clone())); + debug!("Number of usages: {}", folder.usages); + + // First we want to ignore destructuring locals, this has issues with lifetimes + type info. + // It should also actually BE a local, not just some variable-like item. + // TODO + // What about sensible destructors, operator overloading? + // BUT if we get a 'consider using a let binding error', then, we cannot inline. + if folder.usages <= 1 { + // This is generally OK, unless the expression contains an impure function/constructor + // e.g. let a = + // + // Now if we move the first change after the second change, behaviour might change. + // If doesn't matter here if we have copy, move, borrow etc. + // + // Due to uniqueness constraints in Rust, if there is just a single usage, there really + // is just a single usage without any aliases. + + // If any variables composing the initializer were redeclared in the meantime, return + if folder.changed_paths { + return; + } + + + } else { + // Otherwise, multiple references: + + // Mutable case: + // If the variable is mutable, inlining is a bad idea!!! + // e.g. let mut a = 2; + // a = 3; // Now the expression is made the lvalue, but this holds no meaning + // Same again with *&mut a modifying the internal value. + let used_mutables = tcx.used_mut_nodes.borrow(); + // CAVEAT: + // If the mutable was never used, then it should be considered mutable. + if folder.mutable && used_mutables.contains(&node_to_find) { + debug!("IS MUTABLE"); + return; + } + // CAVEAT: + // If there is a refcell, or interior mutability, then it really is mutable. + let ty_cache = tcx.ast_ty_to_ty_cache.borrow(); + let interior_unsafe = 0b0000_0000__0000_0000__0010; + if let Some(node_ctx) = ty_cache.get(&folder.type_node_id) { + debug!("BITS: {:?}", node_ctx.type_contents(tcx).bits); + if node_ctx.type_contents(tcx).bits & interior_unsafe != 0 { + debug!("IS MUTABLE (REFCELL)"); + return; + } + } + + // If the variable is a direct alias, then it might be alright. + // In this case, movements or borrows are irrelevant. + // e.g. let a = 2; + // let b = a; // copy, but memory shouldn't mutate underneath + // or let a = &2; + // let b = a; // this duplicates the reference + // or let a = &mut 2; + // let b = a; // this moves &mut into b + // or let a = vec![0]; + // let b = a; // this moves a into b + // Whether or not a is inlined, it must follow the normal lifetime rules. + // Whatever a refers to must exists for the right scopes. + // However, you must check no one redeclares a in the meantime! + if let Some(ref to_replace) = folder.to_replace { + match (**to_replace).node { + hir::ExprPath(..) => { + // Alias case: + }, + _ => { + } + } + } + + + debug!("IS NOT MUTABLE"); + // Immutable case: + // Check which paths compose the initializer and ensure they resolve + // to the same item at the new call site. + // e.g. b = 2; + // let a = b + c + // let b = 3; + // println!("{}", a); + + // If any variables composing the initializer were redeclared in the meantime, return + if folder.changed_paths { + return; + } + + // If any variables composing the initializer mutated in the meantime, return + // TODO + + } + + let mut out = Vec::new(); + { + let out_borrow: &mut Write = &mut out; + // FIXME: can the last argument be None? + let mut pp_state = State::new_from_input(state.session.codemap(), state.session.diagnostic(), input.clone(), &mut rdr2, Box::new(out_borrow), &ann, true, None); + + let _ = pp_state.print_item(&folder.fold_item((*par).clone())); + //debug!("{:?}", v); + //pp_state.print_mod(&krate.module, &krate.attrs); + //pp_state.print_remaining_comments(); + let _ = eof(&mut pp_state.s); + } + let _ = out.flush(); + debug!("{:?}", out); + let hi_pos = state.session.codemap().lookup_byte_offset(outer_span.hi).pos.to_usize(); + let lo_pos = state.session.codemap().lookup_byte_offset(outer_span.lo).pos.to_usize(); + panic!((lo_pos, hi_pos, String::from_utf8(out).ok().expect("Pretty printer didn't output UTF-8"), 0)); + //pprust::item_to_string(folder.fold_item(par).get(0)) + //visit::walk_crate(&mut visitor, &krate); + } + } else if r_type == RefactorType::ReifyLifetime || r_type == RefactorType::ElideLifetime { + debug!("{:?}", ast_map.get(node_to_find)); + + let taken = lifetimes_in_scope(&tcx.map, node_to_find); + let life_giver = LifeGiver::with_taken(&taken[..]); + let node_inner = match ast_map_original.find(node_to_find) { + Some(ref node) => match *node { + Node::NodeItem(ref item) => { + match item.node { + hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, ref body) => { + Some((fn_decl, gen, unsafety, constness, + item.name, None, item.span, body.span)) + }, + _ => None + } + } + Node::NodeImplItem(item) => { + match item.node { + hir::ImplItemKind::Method(ref sig, ref body) => { + Some((&sig.decl, + &sig.generics, + sig.unsafety, + sig.constness, + item.name, + Some(&sig.explicit_self.node), + item.span, body.span)) + } + //ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"), + _ => None, + } + }, + Node::NodeTraitItem(item) => { + match item.node { + hir::MethodTraitItem(ref sig, Some(ref body)) => { + Some((&sig.decl, + &sig.generics, + sig.unsafety, + sig.constness, + item.name, + Some(&sig.explicit_self.node), + item.span, body.span)) + } + _ => None + } + } + _ => None + }, + None => None + }; + let mut a = Vec::new(); + let (fn_decl, generics, unsafety, constness, ident, expl_self, span, body_span) + = node_inner.expect("expect item fn"); + + let mut folder = LifetimeFolder{ has_bounds: false, expl_self: Name(0) }; + let elided_fn_decl = folder.fold_fn_decl(fn_decl.clone()); + let elided_expl_self_tmp; + let mut elided_expl_self = None; + + // Count input lifetimes and count output lifetimes. + let mut in_walker = LifetimeWalker::new(); + let mut out_walker = LifetimeWalker::new(); + + if let Some(expl_self) = expl_self { + visit::walk_explicit_self(&mut in_walker, &Spanned {node: expl_self.clone(), span: DUMMY_SP}); + elided_expl_self_tmp = folder.fold_explicit_self(Spanned {node: expl_self.clone(), span: DUMMY_SP}); + elided_expl_self = Some(&elided_expl_self_tmp.node); + } + + for argument in fn_decl.inputs.iter() { + debug!("FN DECL: {:?}", argument); + visit::walk_ty(&mut in_walker, &*argument.ty); + } + + visit::walk_fn_ret_ty(&mut out_walker, &fn_decl.output); + + if r_type == RefactorType::ElideLifetime { + let elided_generics = folder.fold_generics(generics.clone()); + let mut parameterized = HashSet::new(); + for lifetimes in generics.lifetimes.iter() { + parameterized.insert(lifetimes.lifetime.name); + } + + // Can't elide if returning multiple lifetimes + if out_walker.names.len() > 1 { + return; + } + + // Don't elide if return doesn't appear in generics (trait lifetime?) + let intersect: HashSet<_> = out_walker.names.intersection(¶meterized).cloned().collect(); + if out_walker.names.len() > 0 && intersect.len() == 0 { + return; + } + + // Make sure that each input lifetime is never used more than once + if in_walker.names.len() as u32 + in_walker.anon != in_walker.total { + return; + } + + // If you have a return, either it has the same name as the only input, or that of self + let intersect: HashSet<_> = out_walker.names.intersection(&in_walker.names).cloned().collect(); + if out_walker.names.len() > 0 && !out_walker.names.contains(&folder.expl_self) + && (in_walker.names.len() > 1 || intersect.len() == 0) { + return; + } + + // Make sure that input lifetimes are all parameterized + // TODO delete only unparameterized? + if !in_walker.names.is_subset(¶meterized) { + return; + } + + // TODO move has_bounds out of the folder + if folder.has_bounds { + return; + } + + let mut answer = pprust::fun_to_string(&elided_fn_decl, unsafety, constness, ident, elided_expl_self, &elided_generics); + + // Add some likely spacing + answer.push_str(" "); + + let hi_pos = state.session.codemap().lookup_byte_offset(body_span.lo).pos.to_usize(); + let lo_pos = state.session.codemap().lookup_byte_offset(span.lo).pos.to_usize(); + panic!((lo_pos, hi_pos, answer, 0)); + } + + // Count anonymous and count total. + // CASE 1: fn <'a> (x: &'a) -> &out + // CASE 2: fn (x: &a) -> &out + // If there is exactly 1 input lifetime, then reuse that lifetime for output (possibly multiple). + if in_walker.total == 1 { + let mut regions = Vec::new(); + if in_walker.anon == 0 { + // CASE 1 + regions.push(BrNamed(default_defid(), generics.lifetimes.get(0).unwrap().lifetime.name)); + for x in 0..out_walker.anon { + regions.push(BrAnon(x)); + } + } else { + // CASE 2 + regions.push(BrAnon(0)); + for x in 0..out_walker.anon { + regions.push(BrAnon(x+1)); + } + } + a.push(SameRegions{scope_id: 0, regions: regions}); + + } else if in_walker.total > 1 { + // If there is more than one lifetime, then: + // fn <'a, 'b> (x: &'a, y: &'b, z: &) -> &'a out + // We can make concrete the anonymous input lifetimes but not the output. + for x in 0..in_walker.anon { + a.push(SameRegions{scope_id: 0, regions: vec![BrAnon(x)]}); + } + + // Unless, there is a self lifetime, then: + // fn <'a, 'b> (self: &'a, ...) -> &out + // We can make concrete the output lifetime as well (which may be multiple). + if let Some(expl_self) = expl_self { + match *expl_self { + hir::SelfRegion(ref life, _, _) => { + if life.is_some() { + // self has a named lifetime + let mut regions = Vec::new(); + regions.push(BrNamed(default_defid(), life.unwrap().name)); + for x in 0..out_walker.anon { + regions.push(BrAnon(in_walker.anon + x)); + } + a.push(SameRegions{scope_id: 0, regions: regions}); + } else { + // self is anonymous + // TODO remove expl_self + let mut regions = &mut a.get_mut(in_walker.expl_self as usize).expect("Missing expl self").regions; + for x in 0..out_walker.anon { + regions.push(BrAnon(in_walker.anon + x)); + } + } + } + _ => () + } + } + + } + + let rebuilder = Rebuilder::new(tcx, &*fn_decl, expl_self, + generics, &a/*same_regions*/, &life_giver); + let (fn_decl, expl_self, generics) = rebuilder.rebuild(); + //self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident, + // expl_self.as_ref(), &generics, span); + debug!("{}", pprust::fun_to_string(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics)); + println!("{}", pprust::fun_to_string(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics)); + //debug!("{:?}", tcx.region_maps); + debug!("{:?}", tcx.named_region_map); + //debug!("{:?}", tcx.free_region_maps.borrow()); + let mut answer = pprust::fun_to_string(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics); + + // Add some likely spacing + answer.push_str(" "); + + let hi_pos = state.session.codemap().lookup_byte_offset(body_span.lo).pos.to_usize(); + let lo_pos = state.session.codemap().lookup_byte_offset(span.lo).pos.to_usize(); + panic!((lo_pos, hi_pos, answer, 0)); + } + }); + + return control; + } + + let new_name = self.new_name.clone(); + + control.after_write_deps.stop = Compilation::Stop; + control.after_write_deps.callback = Box::new(move |state| { + //let krate = state.krate.unwrap().clone(); + let ast_map = state.ast_map.unwrap(); + let krate = ast_map.krate(); + LocalCrateReader::new(&state.session, &ast_map).read_crates(krate); + let _ = lang_items::collect_language_items(&state.session, &ast_map); + + // According to some condition ! + //let ps = syntax::parse::ParseSess::new(); + //let ps = &state.session.parse_sess; + let cratename = match attr::find_crate_name(&krate.attrs[..]) { + Some(name) => name.to_string(), + None => String::from("unknown_crate"), + }; + debug!("{}", cratename); + + debug!("{:?}", token::str_to_ident(&new_name[..])); + debug!("{}", node_to_find); + let ast_node = ast_map.find(node_to_find); + debug!("{:?}", ast_node); + debug!("{:?}", token::str_to_ident(&new_name[..])); + + // find current path and syntax context + let mut syntax_ctx = ast::SyntaxContext(0); + // If None, then it is probably a field. + // TODO fields have no super/sub-block conflict + // Can we remove the compiler runs afterwards? + if let Some(ast_node) = ast_node { + match ast_node { + Node::NodeLocal(pat) => { + match pat.node { + hir::PatIdent(_, path, _) => { + syntax_ctx = path.node.ctxt; + }, + _ => {} + } + }, + + _ => {} + } + } + + let path = build_path(DUMMY_SP, vec![token::str_to_ident(&new_name)]); + // create resolver + let mut resolver = resolve::create_resolver(&state.session, &ast_map, krate, resolve::MakeGlobMap::No, + Some(Box::new(move |node: ast_map::Node, resolved: &mut bool| { + if *resolved { + return true; + } + //debug!("Entered resolver callback"); + match node { + Node::NodeLocal(pat) => { + if pat.id == node_to_find { + debug!("Found node"); + *resolved = true; + return true; + } + }, + Node::NodeItem(item) => { + match item.node { + ItemImpl(_, _, _, _, _, ref impls) => { + for i in impls.iter() { + if i.id == node_to_find { + debug!("{:?}", i); + debug!("Found node"); + *resolved = true; + return true; + } + } + }, + ItemStruct(hir::VariantData::Struct(ref fields, _), _) + | ItemStruct(hir::VariantData::Tuple(ref fields, _), _) => { + for field in fields.iter() { + if field.node.id == node_to_find { + *resolved = true; + return true; + } + } + }, + _ => {} + + } + if item.id == node_to_find { + debug!("Found node"); + debug!("{:?}", item); + *resolved = true; + return true; + } + }, + _ => {} + } + + false + }))); + + match r_type { + RefactorType::Type => { + let mut h = HashMap::new(); + h.insert(String::new(), String::new()); + debug!("{:?}", token::str_to_ident(&new_name[..])); + + let mut idens = ast_map.with_path(node_to_find, |path| { + let itr = token::get_ident_interner(); + + path.fold(Vec::new(), |mut s, e| { + let e = itr.get(e.name()); + s.push(token::str_to_ident(&e[..])); + s }) + //ast_map::path_to_string(path) + }); + + + visit::walk_crate(&mut resolver, krate); + + let new_iden = token::str_to_ident(&new_name[..]); + idens.pop(); + idens.push(new_iden); + + token::str_to_ident(&new_name[..]); + let path = build_path(DUMMY_SP, idens); + + // resolver resolve node id + println!("{:?}", path); + if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::TypeNS, true).is_some() { + // unwind at this location + panic!(h); + } + }, + RefactorType::Variable => { + let mut t = token::str_to_ident(&new_name[..]); + t.ctxt = syntax_ctx; + debug!("{:?}", mtwt::resolve(t)); + let path = build_path(DUMMY_SP, vec![t]); + + visit::walk_crate(&mut resolver, krate); + + let mut h = HashMap::new(); + h.insert(String::new(), String::new()); + debug!("{:?}", token::str_to_ident(&new_name[..])); + + // resolver resolve node id + //if resolver.resolve_path(node_to_find, &path) { + if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::ValueNS, true).is_some() { + // unwind at this location + panic!(h); + } + //println!("{:?}", mtwt::resolve( token::str_to_ident(&new_name[..]))); + + }, + RefactorType::Function => { + let mut idens = ast_map.with_path(node_to_find, |path| { + let itr = token::get_ident_interner(); + + path.fold(Vec::new(), |mut s, e| { + let e = itr.get(e.name()); + s.push(token::str_to_ident(&e[..])); + s + }) + //ast_map::path_to_string(path) + + }); + + let new_iden = token::str_to_ident(&new_name[..]); + idens.pop(); + idens.push(new_iden); + + visit::walk_crate(&mut resolver, krate); + + let mut h = HashMap::new(); + h.insert(String::new(), String::new()); + debug!("{:?}", token::str_to_ident(&new_name[..])); + + // TODO + // let path = cx.path(DUMMY_SP, idens); + // resolver resolve node id + //if resolver.resolve_path(node_to_find, &path) { + if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::ValueNS, true).is_some() { + // unwind at this location + debug!("BAD ValueNS"); + panic!(h); + } + + // Is it possible for type namespace to ever conflict with functions? + /*if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::TypeNS, true).is_some() { + // unwind at this location + debug!("BAD TypeNS"); + panic!(h); + }*/ + + //println!("{:?}", mtwt::resolve( token::str_to_ident(&new_name[..]))); + }, + _ => { /* Reduced graph check falls here */ } + } + }); + + control + } +} diff --git a/src/compiler/util.rs b/src/compiler/util.rs new file mode 100644 index 0000000..7f70590 --- /dev/null +++ b/src/compiler/util.rs @@ -0,0 +1,127 @@ +use std::io::{self, Read}; +use std::path::PathBuf; + +use rustc::front::map as ast_map; +use rustc::session::config::Input; +use rustc_front::hir as ast; +use syntax::ast::{Ident, NodeId}; +use syntax::codemap::Span; +use syntax::owned_slice::OwnedSlice; +use syntax::ptr::P; + +use getopts; + +// The functions below have been copied from librustc_driver/lib.rs + +// Extract output directory and file from matches. +pub fn make_output(matches: &getopts::Matches) -> (Option, Option) { + let odir = matches.opt_str("out-dir").map(PathBuf::from); + let ofile = matches.opt_str("o").map(PathBuf::from); + (odir, ofile) +} + +// Extract input (string or file and optional path) from matches. +pub fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { + if free_matches.len() == 1 { + let ifile = &free_matches[0][..]; + if ifile == "-" { + let mut src = String::new(); + io::stdin().read_to_string(&mut src).unwrap(); + Some((Input::Str(src), None)) + } else { + Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))) + } + } else { + None + } +} + +// The functions below are needed because of HIR lowering +pub fn build_path(span: Span, strs: Vec ) -> ast::Path { + path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new()) +} + +pub fn build_path_ident(span: Span, id: Ident) -> ast::Path { + build_path(span, vec!(id)) +} + +pub fn build_path_global(span: Span, strs: Vec ) -> ast::Path { + path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new()) +} + +fn path_all(sp: Span, + global: bool, + mut idents: Vec , + lifetimes: Vec, + types: Vec>, + bindings: Vec> ) + -> ast::Path { + let last_identifier = idents.pop().unwrap(); + let mut segments: Vec = idents.into_iter() + .map(|ident| { + ast::PathSegment { + identifier: ident, + parameters: ast::PathParameters::none(), + } + }).collect(); + segments.push(ast::PathSegment { + identifier: last_identifier, + parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + bindings: OwnedSlice::from_vec(bindings), + }) + }); + ast::Path { + span: sp, + global: global, + segments: segments, + } +} + +// Identifies the current lifetimes in scope for finding an unused lifetime. +pub fn lifetimes_in_scope(map: &ast_map::Map, + scope_id: NodeId) + -> Vec { + let mut taken = Vec::new(); + let method_id_opt = match map.find(scope_id) { + Some(node) => match node { + ast_map::NodeItem(item) => match item.node { + ast::ItemFn(_, _, _, _, ref gen, _) => { + taken.push_all(&gen.lifetimes); + None + }, + _ => None + }, + ast_map::NodeImplItem(ii) => { + match ii.node { + ast::ImplItemKind::Method(ref sig, _) => { + taken.push_all(&sig.generics.lifetimes); + Some(ii.id) + } + //ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"), + _ => None, + } + } + _ => None + }, + None => None + }; + if method_id_opt.is_some() { + let method_id = method_id_opt.unwrap(); + let parent = map.get_parent(method_id); + match map.find(parent) { + Some(node) => match node { + ast_map::NodeItem(item) => match item.node { + ast::ItemImpl(_, _, ref gen, _, _, _) => { + taken.push_all(&gen.lifetimes); + } + _ => () + }, + _ => () + }, + None => () + } + } + return taken; +} diff --git a/src/lib.rs b/src/lib.rs index 203d8ae..3555f01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,27 +1,41 @@ -#![feature(box_syntax)] -#![feature(box_patterns)] -#![feature(catch_panic)] #![feature(rustc_private)] -#![feature(slice_splits)] #![feature(vec_push_all)] +#![feature(catch_panic)] -#[macro_use] -extern crate log; - -extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_front; extern crate rustc_lint; extern crate rustc_resolve; -extern crate rustc_trans as trans; +extern crate rustc_trans; extern crate syntax; +extern crate csv; +extern crate getopts; +#[macro_use] +extern crate log; extern crate strings; -pub mod folder; -pub mod lifetime_walker; -pub mod loader; -pub mod rebuilder; +pub mod analysis; +mod compiler; +mod rebuilder; pub mod refactor; -pub mod ast_map; +pub mod util; + +pub use analysis::{ + AnalysisData +}; + +pub use refactor::{ + Response, + elide_fn_lifetime, + inline_local, + rename_function, + rename_type, + rename_variable, + restore_fn_lifetime +}; + +pub use util::{ + identify_id +}; diff --git a/src/main.rs b/src/main.rs index b3cc2fd..f7ff8d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,7 @@ -#![feature(io)] -#![feature(box_syntax)] -#![feature(box_patterns)] -#![feature(collections)] #![feature(rustc_private)] -#![feature(core)] -#![feature(path)] #[macro_use] extern crate log; - extern crate refactor; use std::env; @@ -17,13 +10,12 @@ use std::io::prelude::*; use std::path::Path; use std::collections::HashMap; -use refactor::refactor::init; +use refactor::analysis::AnalysisData; // Simple command line interface to the library. // Should probably use the actual getopt to be more practical. fn main() { - let args = env::args(); - let args: Vec<_> = args.collect(); + let args: Vec<_> = env::args().collect(); if args.len() < 5 { let _ = writeln!(&mut std::io::stderr(), "Not enough args: []"); @@ -47,12 +39,12 @@ fn main() { }; let mut analysis_str = String::new(); let _ = analysis.read_to_string(&mut analysis_str); - let analysis_data = init(&analysis_str); + let analysis_data = AnalysisData::new(&analysis_str); let v: Vec<_> = args[4].split(":").collect(); if v.len() == 3 { - input_id = refactor::refactor::identify_id(path.file_name().unwrap().to_str().unwrap(), &analysis_data, + input_id = refactor::identify_id(path.file_name().unwrap().to_str().unwrap(), &analysis_data, v[0], v[1].parse().unwrap(), v[2].parse().unwrap(), None); let _ = writeln!(&mut std::io::stderr(), "NODE ID: {}", input_id); @@ -61,42 +53,42 @@ fn main() { match &*args[1] { "var" => { - let result = refactor::refactor::rename_variable(&args[3], &analysis_data, &args[5], rename_var); + let result = refactor::rename_variable(&args[3], &analysis_data, &args[5], rename_var); match result { Ok(x) => println!("{}", better_string(x)), Err(x) => println!("{:?}", x) } }, "type" => { - let result = refactor::refactor::rename_type(&args[3], &analysis_data, &args[5], rename_var); + let result = refactor::rename_type(&args[3], &analysis_data, &args[5], rename_var); match result { Ok(x) => println!("{}", better_string(x)), Err(x) => println!("{:?}", x) } }, "fn" => { - let result = refactor::refactor::rename_function(&args[3], &analysis_data, &args[5], rename_var); + let result = refactor::rename_function(&args[3], &analysis_data, &args[5], rename_var); match result { Ok(x) => println!("{}", better_string(x)), Err(x) => println!("{:?}", x) } }, "inline" => { - let result = refactor::refactor::inline_local(&args[3], &analysis_data, rename_var); + let result = refactor::inline_local(&args[3], &analysis_data, rename_var); match result { Ok(x) => println!("{}", better_string(x)), Err(x) => println!("{:?}", x) } }, "reify" => { - let result = refactor::refactor::restore_fn_lifetime(&args[3], &analysis_data, rename_var); + let result = refactor::restore_fn_lifetime(&args[3], &analysis_data, rename_var); match result { Ok(x) => println!("{}", better_string(x)), Err(x) => println!("{:?}", x) } }, "elide" => { - let result = refactor::refactor::elide_fn_lifetime(&args[3], &analysis_data, rename_var); + let result = refactor::elide_fn_lifetime(&args[3], &analysis_data, rename_var); match result { Ok(x) => println!("{}", better_string(x)), Err(x) => println!("{:?}", x) diff --git a/src/rebuilder.rs b/src/rebuilder.rs index 49f77f5..ecc2c87 100644 --- a/src/rebuilder.rs +++ b/src/rebuilder.rs @@ -13,26 +13,22 @@ use self::FreshOrKept::*; use rustc_front::hir; -use rustc::front::map as ast_map; use rustc::middle::def; -use rustc::middle::infer::{self, InferCtxt}; +use rustc::middle::infer::InferCtxt; use rustc::middle::infer::region_inference::SameRegions; -use rustc::middle::ty::{self, Ty, HasTypeFlags}; -use rustc::middle::ty::error::TypeError; +use rustc::middle::ty::{self, Ty}; use rustc::middle::subst; use std::cell::{Cell, RefCell}; use std::char::from_u32; use std::collections::HashSet; use syntax::{codemap}; -use syntax::ast::{DUMMY_NODE_ID, Name, NodeId}; -use syntax::ast; -//use rustc_front::hir as ast; +use syntax::ast::{DUMMY_NODE_ID, Name}; use syntax::owned_slice::OwnedSlice; use syntax::parse::token; use syntax::ptr::P; struct RebuildPathInfo<'a> { - path: &'a ast::Path, + path: &'a hir::Path, // indexes to insert lifetime on path.lifetimes indexes: Vec, // number of lifetimes we expect to see on the type referred by `path` @@ -44,9 +40,9 @@ struct RebuildPathInfo<'a> { pub struct Rebuilder<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - fn_decl: &'a ast::FnDecl, - expl_self_opt: Option<&'a ast::ExplicitSelf_>, - generics: &'a ast::Generics, + fn_decl: &'a hir::FnDecl, + expl_self_opt: Option<&'a hir::ExplicitSelf_>, + generics: &'a hir::Generics, same_regions: &'a [SameRegions], life_giver: &'a LifeGiver, cur_anon: Cell, @@ -60,9 +56,9 @@ enum FreshOrKept { impl<'a, 'tcx> Rebuilder<'a, 'tcx> { pub fn new(tcx: &'a ty::ctxt<'tcx>, - fn_decl: &'a ast::FnDecl, - expl_self_opt: Option<&'a ast::ExplicitSelf_>, - generics: &'a ast::Generics, + fn_decl: &'a hir::FnDecl, + expl_self_opt: Option<&'a hir::ExplicitSelf_>, + generics: &'a hir::Generics, same_regions: &'a [SameRegions], life_giver: &'a LifeGiver) -> Rebuilder<'a, 'tcx> { @@ -79,7 +75,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } pub fn rebuild(&self) - -> (ast::FnDecl, Option, ast::Generics) { + -> (hir::FnDecl, Option, hir::Generics) { let mut expl_self_opt = self.expl_self_opt.cloned(); let mut inputs = self.fn_decl.inputs.clone(); let mut output = self.fn_decl.output.clone(); @@ -112,7 +108,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { &all_region_names, ty_params, where_clause); - let new_fn_decl = ast::FnDecl { + let new_fn_decl = hir::FnDecl { inputs: inputs, output: output, variadic: self.fn_decl.variadic @@ -122,7 +118,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { fn pick_lifetime(&self, region_names: &HashSet) - -> (ast::Lifetime, FreshOrKept) { + -> (hir::Lifetime, FreshOrKept) { if !region_names.is_empty() { // It's not necessary to convert the set of region names to a // vector of string and then sort them. However, it makes the @@ -195,16 +191,16 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } fn rebuild_ty_params(&self, - ty_params: OwnedSlice, - lifetime: ast::Lifetime, + ty_params: OwnedSlice, + lifetime: hir::Lifetime, region_names: &HashSet) - -> OwnedSlice { + -> OwnedSlice { ty_params.map(|ty_param| { let bounds = self.rebuild_ty_param_bounds(ty_param.bounds.clone(), lifetime, region_names); - ast::TyParam { - ident: ty_param.ident, + hir::TyParam { + name: ty_param.name, id: ty_param.id, bounds: bounds, default: ty_param.default.clone(), @@ -214,19 +210,19 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } fn rebuild_ty_param_bounds(&self, - ty_param_bounds: OwnedSlice, - lifetime: ast::Lifetime, + ty_param_bounds: OwnedSlice, + lifetime: hir::Lifetime, region_names: &HashSet) - -> OwnedSlice { + -> OwnedSlice { ty_param_bounds.map(|tpb| { match tpb { - &ast::RegionTyParamBound(lt) => { + &hir::RegionTyParamBound(lt) => { // FIXME -- it's unclear whether I'm supposed to // substitute lifetime here. I suspect we need to // be passing down a map. - ast::RegionTyParamBound(lt) + hir::RegionTyParamBound(lt) } - &ast::TraitTyParamBound(ref poly_tr, modifier) => { + &hir::TraitTyParamBound(ref poly_tr, modifier) => { let tr = &poly_tr.trait_ref; let last_seg = tr.path.segments.last().unwrap(); let mut insert = Vec::new(); @@ -244,9 +240,9 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { region_names: region_names }; let new_path = self.rebuild_path(rebuild_info, lifetime); - ast::TraitTyParamBound(ast::PolyTraitRef { + hir::TraitTyParamBound(hir::PolyTraitRef { bound_lifetimes: poly_tr.bound_lifetimes.clone(), - trait_ref: ast::TraitRef { + trait_ref: hir::TraitRef { path: new_path, ref_id: tr.ref_id, }, @@ -258,23 +254,23 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } fn rebuild_expl_self(&self, - expl_self_opt: Option, - lifetime: ast::Lifetime, + expl_self_opt: Option, + lifetime: hir::Lifetime, anon_nums: &HashSet, region_names: &HashSet) - -> Option { + -> Option { match expl_self_opt { Some(ref expl_self) => match *expl_self { - ast::SelfRegion(lt_opt, muta, id) => match lt_opt { + hir::SelfRegion(lt_opt, muta, id) => match lt_opt { Some(lt) => if region_names.contains(<.name) { - return Some(ast::SelfRegion(Some(lifetime), muta, id)); + return Some(hir::SelfRegion(Some(lifetime), muta, id)); }, None => { let anon = self.cur_anon.get(); self.inc_and_offset_cur_anon(1); if anon_nums.contains(&anon) { self.track_anon(anon); - return Some(ast::SelfRegion(Some(lifetime), muta, id)); + return Some(hir::SelfRegion(Some(lifetime), muta, id)); } } }, @@ -286,16 +282,16 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } fn rebuild_generics(&self, - generics: &ast::Generics, - add: &Vec, + generics: &hir::Generics, + add: &Vec, keep: &HashSet, remove: &HashSet, - ty_params: OwnedSlice, - where_clause: ast::WhereClause) - -> ast::Generics { + ty_params: OwnedSlice, + where_clause: hir::WhereClause) + -> hir::Generics { let mut lifetimes = Vec::new(); for lt in add { - lifetimes.push(ast::LifetimeDef { lifetime: *lt, + lifetimes.push(hir::LifetimeDef { lifetime: *lt, bounds: Vec::new() }); } for lt in &generics.lifetimes { @@ -304,7 +300,7 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { lifetimes.push((*lt).clone()); } } - ast::Generics { + hir::Generics { lifetimes: lifetimes, ty_params: ty_params, where_clause: where_clause, @@ -312,16 +308,16 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } fn rebuild_args_ty(&self, - inputs: &[ast::Arg], - lifetime: ast::Lifetime, + inputs: &[hir::Arg], + lifetime: hir::Lifetime, anon_nums: &HashSet, region_names: &HashSet) - -> Vec { + -> Vec { let mut new_inputs = Vec::new(); for arg in inputs { let new_ty = self.rebuild_arg_ty_or_output(&*arg.ty, lifetime, anon_nums, region_names); - let possibly_new_arg = ast::Arg { + let possibly_new_arg = hir::Arg { ty: new_ty, pat: arg.pat.clone(), id: arg.id @@ -331,31 +327,31 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { new_inputs } - fn rebuild_output(&self, ty: &ast::FunctionRetTy, - lifetime: ast::Lifetime, + fn rebuild_output(&self, ty: &hir::FunctionRetTy, + lifetime: hir::Lifetime, anon_nums: &HashSet, - region_names: &HashSet) -> ast::FunctionRetTy { + region_names: &HashSet) -> hir::FunctionRetTy { match *ty { - ast::Return(ref ret_ty) => ast::Return( + hir::Return(ref ret_ty) => hir::Return( self.rebuild_arg_ty_or_output(&**ret_ty, lifetime, anon_nums, region_names) ), - ast::DefaultReturn(span) => ast::DefaultReturn(span), - ast::NoReturn(span) => ast::NoReturn(span) + hir::DefaultReturn(span) => hir::DefaultReturn(span), + hir::NoReturn(span) => hir::NoReturn(span) } } fn rebuild_arg_ty_or_output(&self, - ty: &ast::Ty, - lifetime: ast::Lifetime, + ty: &hir::Ty, + lifetime: hir::Lifetime, anon_nums: &HashSet, region_names: &HashSet) - -> P { + -> P { let mut new_ty = P(ty.clone()); let mut ty_queue = vec!(ty); while !ty_queue.is_empty() { let cur_ty = ty_queue.remove(0); match cur_ty.node { - ast::TyRptr(lt_opt, ref mut_ty) => { + hir::TyRptr(lt_opt, ref mut_ty) => { let rebuild = match lt_opt { Some(lt) => region_names.contains(<.name), None => { @@ -369,16 +365,16 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } }; if rebuild { - let to = ast::Ty { + let to = hir::Ty { id: cur_ty.id, - node: ast::TyRptr(Some(lifetime), mut_ty.clone()), + node: hir::TyRptr(Some(lifetime), mut_ty.clone()), span: cur_ty.span }; new_ty = self.rebuild_ty(new_ty, P(to)); } ty_queue.push(&*mut_ty.ty); } - ast::TyPath(ref maybe_qself, ref path) => { + hir::TyPath(ref maybe_qself, ref path) => { let a_def = match self.tcx.def_map.borrow().get(&cur_ty.id) { None => { self.tcx @@ -421,15 +417,15 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { }; let new_path = self.rebuild_path(rebuild_info, lifetime); let qself = maybe_qself.as_ref().map(|qself| { - ast::QSelf { + hir::QSelf { ty: self.rebuild_arg_ty_or_output(&qself.ty, lifetime, anon_nums, region_names), position: qself.position } }); - let to = ast::Ty { + let to = hir::Ty { id: cur_ty.id, - node: ast::TyPath(qself, new_path), + node: hir::TyPath(qself, new_path), span: cur_ty.span }; new_ty = self.rebuild_ty(new_ty, P(to)); @@ -439,14 +435,14 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } - ast::TyPtr(ref mut_ty) => { + hir::TyPtr(ref mut_ty) => { ty_queue.push(&*mut_ty.ty); } - ast::TyVec(ref ty) | - ast::TyFixedLengthVec(ref ty, _) => { + hir::TyVec(ref ty) | + hir::TyFixedLengthVec(ref ty, _) => { ty_queue.push(&**ty); } - ast::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), + hir::TyTup(ref tys) => ty_queue.extend(tys.iter().map(|ty| &**ty)), _ => {} } } @@ -454,41 +450,40 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { } fn rebuild_ty(&self, - from: P, - to: P) - -> P { + from: P, + to: P) + -> P { - fn build_to(from: P, - to: &mut Option>) - -> P { + fn build_to(from: P, + to: &mut Option>) + -> P { if Some(from.id) == to.as_ref().map(|ty| ty.id) { return to.take().expect("`to` type found more than once during rebuild"); } - from.map(|ast::Ty {id, node, span}| { + from.map(|hir::Ty {id, node, span}| { let new_node = match node { - ast::TyRptr(lifetime, mut_ty) => { - ast::TyRptr(lifetime, ast::MutTy { + hir::TyRptr(lifetime, mut_ty) => { + hir::TyRptr(lifetime, hir::MutTy { mutbl: mut_ty.mutbl, ty: build_to(mut_ty.ty, to), }) } - ast::TyPtr(mut_ty) => { - ast::TyPtr(ast::MutTy { + hir::TyPtr(mut_ty) => { + hir::TyPtr(hir::MutTy { mutbl: mut_ty.mutbl, ty: build_to(mut_ty.ty, to), }) } - ast::TyVec(ty) => ast::TyVec(build_to(ty, to)), - ast::TyFixedLengthVec(ty, e) => { - ast::TyFixedLengthVec(build_to(ty, to), e) + hir::TyVec(ty) => hir::TyVec(build_to(ty, to)), + hir::TyFixedLengthVec(ty, e) => { + hir::TyFixedLengthVec(build_to(ty, to), e) } - ast::TyTup(tys) => { - ast::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) + hir::TyTup(tys) => { + hir::TyTup(tys.into_iter().map(|ty| build_to(ty, to)).collect()) } - ast::TyParen(typ) => ast::TyParen(build_to(typ, to)), other => other }; - ast::Ty { id: id, node: new_node, span: span } + hir::Ty { id: id, node: new_node, span: span } }) } @@ -497,8 +492,8 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { fn rebuild_path(&self, rebuild_info: RebuildPathInfo, - lifetime: ast::Lifetime) - -> ast::Path + lifetime: hir::Lifetime) + -> hir::Path { let RebuildPathInfo { path, @@ -510,11 +505,11 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { let last_seg = path.segments.last().unwrap(); let new_parameters = match last_seg.parameters { - ast::ParenthesizedParameters(..) => { + hir::ParenthesizedParameters(..) => { last_seg.parameters.clone() } - ast::AngleBracketedParameters(ref data) => { + hir::AngleBracketedParameters(ref data) => { let mut new_lts = Vec::new(); if data.lifetimes.is_empty() { // traverse once to see if there's a need to insert lifetime @@ -543,9 +538,9 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names) }); let new_bindings = data.bindings.map(|b| { - P(ast::TypeBinding { + P(hir::TypeBinding { id: b.id, - ident: b.ident, + name: b.name, ty: self.rebuild_arg_ty_or_output(&*b.ty, lifetime, anon_nums, @@ -553,21 +548,20 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> { span: b.span }) }); - ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + hir::AngleBracketedParameters(hir::AngleBracketedParameterData { lifetimes: new_lts, types: new_types, bindings: new_bindings, }) } }; - let new_seg = ast::PathSegment { + let new_seg = hir::PathSegment { identifier: last_seg.identifier, parameters: new_parameters }; - let mut new_segs = Vec::new(); - new_segs.push_all(path.segments.split_last().unwrap().1); + let mut new_segs = path.segments.split_last().unwrap().1.to_owned(); new_segs.push(new_seg); - ast::Path { + hir::Path { span: path.span, global: path.global, segments: new_segs @@ -603,7 +597,7 @@ impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { /*fn lifetimes_in_scope(tcx: &ty::ctxt, scope_id: NodeId) - -> Vec { + -> Vec { let mut taken = Vec::new(); let parent = tcx.map.get_parent(scope_id); let method_id_opt = match tcx.map.find(parent) { @@ -651,7 +645,7 @@ impl<'tcx> Resolvable<'tcx> for ty::PolyTraitRef<'tcx> { pub struct LifeGiver { taken: HashSet, counter: Cell, - generated: RefCell>, + generated: RefCell>, } impl LifeGiver { @@ -673,7 +667,7 @@ impl LifeGiver { self.counter.set(c+1); } - fn give_lifetime(&self) -> ast::Lifetime { + fn give_lifetime(&self) -> hir::Lifetime { let lifetime; loop { let mut s = String::from("'"); @@ -701,13 +695,13 @@ impl LifeGiver { } } - pub fn get_generated_lifetimes(&self) -> Vec { + pub fn get_generated_lifetimes(&self) -> Vec { self.generated.borrow().clone() } } -fn name_to_dummy_lifetime(name: Name) -> ast::Lifetime { - ast::Lifetime { id: DUMMY_NODE_ID, +fn name_to_dummy_lifetime(name: Name) -> hir::Lifetime { + hir::Lifetime { id: DUMMY_NODE_ID, span: codemap::DUMMY_SP, name: name } } diff --git a/src/refactor.rs b/src/refactor.rs deleted file mode 100644 index 8230d29..0000000 --- a/src/refactor.rs +++ /dev/null @@ -1,1737 +0,0 @@ - -extern crate csv; - -use getopts; -use rustc_front::lowering; -use rustc::front::map as ast_map; -use rustc::front::map::Node; -use rustc::front::map::Node::*; -use rustc::session::{self, Session}; -use rustc::session::config::{self, Input}; -use rustc_driver::{CompilerCalls, Compilation, diagnostics_registry, driver, - handle_options, monitor, RustcDefaultCalls}; -use rustc::metadata::creader::LocalCrateReader; -use rustc_resolve as resolve; -use rustc::lint; -use rustc_lint; -use rustc::middle::def_id::DefId; -use rustc::middle::lang_items; -use rustc::middle::infer::region_inference::SameRegions; -use rustc::middle::ty::BoundRegion::*; -use syntax::{self, attr, diagnostic, diagnostics}; -use syntax::fold::Folder; -use rustc_front::visit; -use rustc_front::hir as ast; -use rustc_front::hir::Item_::{ItemImpl, ItemStruct}; -use syntax::ast::{Name, NodeId, Ident}; -use syntax::codemap::{self, DUMMY_SP, FileLoader, Pos, Span, Spanned}; -use syntax::ext::build::AstBuilder; -use syntax::ext::mtwt; -use syntax::owned_slice::OwnedSlice; -use syntax::parse::token; -use syntax::print::pprust::{self, State}; -use syntax::print::pp::eof; -use syntax::ptr::P; -use std::collections::{HashMap, HashSet}; -use std::env; -use std::io; -use std::io::prelude::*; -use std::io::stderr; -use std::iter::FromIterator; -use std::path::PathBuf; -use std::path::Path; -use std::fs::File; -use std::thread; - -use strings::src_rope::Rope; - -use folder::{InlineFolder, LifetimeFolder}; -use loader::ReplaceLoader; -use rebuilder::{Rebuilder, LifeGiver}; -use lifetime_walker::LifetimeWalker; -use ast_map::{Forest, map_crate}; -use ast_map as custom_map; - -// The general idea is to expand the variants to be more fine-grained. -#[derive(Debug, PartialEq)] -pub enum Response { - Error, - Conflict, - Possible, -} - -type ErrorCode = i32; - -// Renames a variable (or variable-like construct). -// This includes constants, fields, and function parameters. -pub fn rename_variable(input_file: &str, - analyzed_data: &AnalysisData, - new_name: &str, - rename_var: &str) - -> Result, Response> { - //for (key, value) in analyzed_data.type_map.iter() { - // println!("{}: \"{}\"", *key, value.get("id").unwrap()); - //} - - //for (key, value) in analyzed_data.type_ref_map.iter() { - // println!("{}: \"{:?}\"", *key, value); - //} - - let dec_map = &analyzed_data.var_map; - let ref_map = &analyzed_data.var_ref_map; - - let input_file_str = String::from(input_file); - let mut filename = String::from(input_file); - if let Some(decl) = dec_map.get(rename_var) { - if let Some(file) = decl.get("file_name") { - filename = file.clone(); - } - } - let filename = filename; - - // Check if renaming will cause conflicts - let node: NodeId = rename_var.parse().unwrap(); - - match run_compiler_resolution(String::from(input_file), None, //Some(filename, String::from(input)), - None, RefactorType::Variable, String::from(new_name), - node, false) { - Ok(()) => { - debug!("GOOD"); - }, - Err(x) => { debug!("BAD"); return Err(Response::Conflict); } - } - match dec_map.get(rename_var) { - Some(x) => { - for (key, value) in dec_map.iter() { - let name = value.get("name").unwrap(); - if (x.get("scopeid") == value.get("scopeid") && - name == &new_name) { - // Conflict present: - // May still be ok if there is no references to it - // However, standalone blocks won't be detected + macros - // Will also restrict if reference is on same line as renaming - - if let Some(references) = ref_map.get(rename_var) { - for map in references.iter() { - let filename = map.get("file_name").unwrap(); - - let mut file = match File::open(&Path::new(filename)) { - Err(why) => panic!("couldn't open file {}", why), - Ok(file) => file, - }; - let mut file_str = String::new(); - let _ = file.read_to_string(&mut file_str); - let file_str = &file_str[..]; - let mut ropes: Vec = file_str.lines().map(|x| Rope::from_string(String::from(x))).collect(); - let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); - let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); - let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); - let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); - - //let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); - rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); - let mut answer = String::new(); - let mut count = ropes.len(); - for rope in &ropes { - answer.push_str(&rope.to_string()); - if count > 1 { - answer.push_str("\n"); - count -= 1; - } - } - - match run_compiler_resolution(String::from(input_file), Some(vec![(String::from(filename.clone()), answer)]), - None, RefactorType::Variable, String::from(new_name), - node, true) { - Ok(()) => { - debug!("Unexpected success!"); - // Check for conflicts - return Err(Response::Conflict); - }, - Err(x) => { debug!("Expected failure!");} - } - } - } - - /*let id = value.get("id").unwrap(); - let line_no: i32 = value.get("file_line").unwrap().parse().unwrap(); - if let Some(refs) = ref_map.get(id) { - for record in refs.iter() { - let line: i32 = record.get("file_line").unwrap().parse().unwrap(); - if line >= line_no { - // Affected reference - return Err(Response::Conflict); //input.to_string(); - } - } - }*/ - } - } - }, - _ => { return Err(Response::Conflict); } //input.to_string(); } - } - - let output = rename_dec_and_ref(new_name, rename_var, dec_map, ref_map); - - try!(check_reduced_graph(String::from(input_file), - output.iter().map(|(x,y)| - (x.clone(), y.clone())).collect(), - String::from(new_name), node)); - - Ok(output) -} - -// Rename concrete types (structs, enums and struct enums). -pub fn rename_type(input_file: &str, - analyzed_data: &AnalysisData, - new_name: &str, - rename_var: &str) - -> Result, Response> { - //for (key, value) in analyzed_data.type_map.iter() { - // println!("{}: \"{:?}\"", *key, value); - //} - - let dec_map = &analyzed_data.type_map; - let ref_map = &analyzed_data.type_ref_map; - let node: NodeId = rename_var.parse().unwrap(); - - let input_file_str = String::from(input_file); - let mut filename = String::from(input_file); - if let Some(decl) = dec_map.get(rename_var) { - if let Some(file) = decl.get("file_name") { - filename = file.clone(); - } - } - let filename = filename; - match run_compiler_resolution(input_file_str, None, None, RefactorType::Type, - String::from(new_name), node, false) { - Ok(()) => {}, - Err(x) => { debug!("Unexpected failure!"); return Err(Response::Conflict) } - } - - if let Some(references) = ref_map.get(rename_var) { - for map in references.iter() { - let filename = map.get("file_name").unwrap(); - - let mut file = match File::open(&Path::new(filename)) { - Err(why) => panic!("couldn't open file {}", why), - Ok(file) => file, - }; - let mut file_str = String::new(); - let _ = file.read_to_string(&mut file_str); - let file_str = &file_str[..]; - let mut ropes: Vec = file_str.lines().map(|x| Rope::from_string(String::from(x))).collect(); - let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); - let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); - let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); - let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); - - //let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); - rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); - let mut answer = String::new(); - let mut count = ropes.len(); - for rope in &ropes { - answer.push_str(&rope.to_string()); - if count > 1 { - answer.push_str("\n"); - count -= 1; - } - } - - match run_compiler_resolution(String::from(input_file), Some(vec![(String::from(filename.clone()), answer)]), - None, RefactorType::Variable, String::from(new_name), - node, true) { - Ok(()) => { - debug!("Unexpected success!"); - // Check for conflicts - return Err(Response::Conflict); - }, - Err(x) => { debug!("Expected failure!");} - } - } - } - - Ok(rename_dec_and_ref(new_name, rename_var, dec_map, ref_map)) -} - -// Rename functions and methods. -pub fn rename_function(input_file: &str, - analyzed_data: &AnalysisData, - new_name: &str, - rename_var: &str) - -> Result, Response> { - // method calls refer to top level trait function in declid - - // rename original function - - // then rename all statically dispatched with refid = id - // then rename all dynamically dispatched with declid = id - // then rename all functions with declid = id - // assuming mutual exclusion, these should all be covered in func_ref_map - - let dec_map = &analyzed_data.func_map; - let ref_map = &analyzed_data.func_ref_map; - let node: NodeId = rename_var.parse().unwrap(); - - let input_file_str = String::from(input_file); - - let mut filename = String::from(input_file); - if let Some(decl) = dec_map.get(rename_var) { - if let Some(file) = decl.get("file_name") { - filename = file.clone(); - } - } - let filename = filename; - match run_compiler_resolution(input_file_str, None, None, RefactorType::Function, - String::from(new_name), node, false) { - Ok(()) => {}, - Err(x) => { debug!("Unexpected failure!"); return Err(Response::Conflict) } - } - - if let Some(references) = ref_map.get(rename_var) { - for map in references.iter() { - let filename = map.get("file_name").unwrap(); - - let mut file = match File::open(&Path::new(filename)) { - Err(why) => panic!("couldn't open file {}", why), - Ok(file) => file, - }; - let mut file_str = String::new(); - let _ = file.read_to_string(&mut file_str); - let file_str = &file_str[..]; - - let mut ropes: Vec = file_str.lines().map(|x| Rope::from_string(String::from(x))).collect(); - let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); - let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); - let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); - let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); - - //let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); - rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); - let mut answer = String::new(); - let mut count = ropes.len(); - for rope in &ropes { - answer.push_str(&rope.to_string()); - if count > 1 { - answer.push_str("\n"); - count -= 1; - } - } - - match run_compiler_resolution(String::from(input_file), Some(vec![(String::from(filename.clone()), answer)]), - None, RefactorType::Variable, String::from(new_name), - node, true) { - Ok(()) => { - debug!("Unexpected success!"); - // Check for conflicts - return Err(Response::Conflict); - }, - Err(x) => { debug!("Expected failure!");} - } - } - } - - let output = rename_dec_and_ref(new_name, rename_var, dec_map, ref_map); - - //println!("{:?}", output); - try!(check_reduced_graph(String::from(input_file), - output.iter().map(|(x,y)| - (x.clone(), y.clone())).collect(), - String::from(new_name), node)); - - Ok(output) -} - -// Identifies the current lifetimes in scope for finding an unused lifetime. -fn lifetimes_in_scope(map: &ast_map::Map, - scope_id: NodeId) - -> Vec { - let mut taken = Vec::new(); - let method_id_opt = match map.find(scope_id) { - Some(node) => match node { - ast_map::NodeItem(item) => match item.node { - ast::ItemFn(_, _, _, _, ref gen, _) => { - taken.push_all(&gen.lifetimes); - None - }, - _ => None - }, - ast_map::NodeImplItem(ii) => { - match ii.node { - ast::MethodImplItem(ref sig, _) => { - taken.push_all(&sig.generics.lifetimes); - Some(ii.id) - } - //ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"), - _ => None, - } - } - _ => None - }, - None => None - }; - if method_id_opt.is_some() { - let method_id = method_id_opt.unwrap(); - let parent = map.get_parent(method_id); - match map.find(parent) { - Some(node) => match node { - ast_map::NodeItem(item) => match item.node { - ast::ItemImpl(_, _, ref gen, _, _, _) => { - taken.push_all(&gen.lifetimes); - } - _ => () - }, - _ => () - }, - None => () - } - } - return taken; -} - -// Reify the lifetimes in a signature -pub fn restore_fn_lifetime(input_file: &str, - analyzed_data: &AnalysisData, - rename_var: &str) - -> Result, Response> { - let dec_map = &analyzed_data.func_map; - let ref_map = &analyzed_data.func_ref_map; - - let node: NodeId = rename_var.parse().unwrap(); - - let input_file_str = String::from(input_file); - - let mut filename = String::from(input_file); - if let Some(decl) = dec_map.get(rename_var) { - if let Some(file) = decl.get("file_name") { - filename = file.clone(); - } - } - let filename = filename; - debug!("{}", filename); - let (x,y,z,_) = match run_compiler_resolution(input_file_str, None, Some(filename.clone()), RefactorType::ReifyLifetime, - String::from(rename_var), node, true) { - Ok(()) => { debug!("Unexpected success!"); return Err(Response::Conflict) }, - Err(x) => { println!("{:?}", x); x } - }; - - let mut new_file = String::new(); - File::open(&filename).expect("Missing file").read_to_string(&mut new_file); - let mut rope = Rope::from_string(new_file); - - debug!("{}", filename); - debug!("{}", rope.to_string()); - rope.src_remove(x, y); - rope.src_insert(x, z); - - let mut output = HashMap::new(); - output.insert(filename, rope.to_string()); - debug!("{}", rope.to_string()); - Ok(output) -} - -// Elide the lifetimes in a signature -pub fn elide_fn_lifetime(input_file: &str, - analyzed_data: &AnalysisData, - rename_var: &str) - -> Result, Response> { - let dec_map = &analyzed_data.func_map; - //let ref_map = &analyzed_data.func_ref_map; - - let node: NodeId = rename_var.parse().unwrap(); - - let input_file_str = String::from(input_file); - - let mut filename = String::from(input_file); - if let Some(decl) = dec_map.get(rename_var) { - if let Some(file) = decl.get("file_name") { - filename = file.clone(); - } - } - let filename = filename; - debug!("{}", filename); - let (x,y,z,_) = match run_compiler_resolution(input_file_str, None, Some(filename.clone()), RefactorType::ElideLifetime, - String::from(rename_var), node, true) { - Ok(()) => { debug!("Unexpected success!"); return Err(Response::Conflict) }, - Err(x) => { println!("{:?}", x); x } - }; - - let mut new_file = String::new(); - File::open(&filename).expect("Missing file").read_to_string(&mut new_file); - let mut rope = Rope::from_string(new_file); - - debug!("{}", filename); - debug!("{}", rope.to_string()); - rope.src_remove(x, y); - rope.src_insert(x, z); - - let mut output = HashMap::new(); - output.insert(filename, rope.to_string()); - debug!("{}", rope.to_string()); - Ok(output) -} - - -// Inline a local variable -pub fn inline_local(input_file: &str, - analyzed_data: &AnalysisData, - rename_var: &str) - -> Result, Response> { - let dec_map = &analyzed_data.var_map; - //let ref_map = &analyzed_data.var_ref_map; - let node: NodeId = rename_var.parse().unwrap(); - - let input_file_str = String::from(input_file); - - let mut filename = String::from(input_file); - if let Some(decl) = dec_map.get(rename_var) { - if let Some(file) = decl.get("file_name") { - filename = file.clone(); - } - } - let filename = filename; - let (x,y,z,_) = match run_compiler_resolution(input_file_str, None, Some(filename.clone()), RefactorType::InlineLocal, - String::from(rename_var), node, true) { - Ok(()) => { debug!("Unexpected success!"); return Err(Response::Conflict) }, - Err(x) => { println!("{:?}", x); x } - }; - - let mut new_file = String::new(); - File::open(&filename).expect("Missing file").read_to_string(&mut new_file); - let mut rope = Rope::from_string(new_file); - - rope.src_remove(x, y); - rope.src_insert(x, z); - - let mut output = HashMap::new(); - output.insert(filename, rope.to_string()); - Ok(output) -} - -// Used to check same-block conflicts in modules (since name resolution doesn't seem to). -fn check_reduced_graph(root: String, - files: Vec<(String, String)>, - new_name: String, - node: NodeId) - -> Result<(), Response> { - - match run_compiler_resolution(root, Some(files), None, RefactorType::Reduced, new_name, node, false) { - Ok(()) => Ok(()), - Err(x) => Err(Response::Conflict) - - } -} - -fn run_compiler_resolution(root: String, - file_override: Option>, - working_file: Option, - kind: RefactorType, - new_name: String, - node: NodeId, - full: bool) - -> Result<(), (usize, usize, String, ErrorCode)> { - let key = "RUST_FOLDER"; - let mut path = String::new(); - let args = match env::var(key) { - Ok(val) => { - path.push_str("-L"); - path.push_str(&val[..]); - vec!["refactor".to_owned(), - path, - "-Z".to_owned(), "keep_mtwt_tables".to_owned(), - //"--crate-type", "lib", - root] - } - Err(e) => {vec!["refactor".to_owned(), root]}, - }; - - let mut loader = ReplaceLoader::new(); - match file_override.as_ref() { - Some(input) => { - for file in input.iter() { - loader.add_file(file.0.clone(), file.1.clone()); - } - }, - None => () - } - - thread::catch_panic(move || { - let mut call_ctxt = RefactorCalls::new(kind, new_name, node, file_override, - working_file, full); - // Calling monitor fixes a bug where this process is put into an - // invalid (logging) state. - match kind { - RefactorType::InlineLocal | - RefactorType::ReifyLifetime | - RefactorType::ElideLifetime => run_compiler(&args, &mut call_ctxt, Box::new(loader)), - _ => monitor(move || run_compiler(&args, &mut call_ctxt, Box::new(loader))) - } - }).map_err(|any| - *any.downcast().ok().unwrap_or_default() - ) -} - -// Basically a clone of the function librustc_driver -fn run_compiler<'a>(args: &[String], callbacks: &mut CompilerCalls<'a>, loader: Box) { - macro_rules! do_or_return {($expr: expr) => { - match $expr { - Compilation::Stop => return, - Compilation::Continue => {} - } - }} - - let matches = match handle_options(args.to_vec()) { - Some(matches) => matches, - None => return - }; - - let sopts = config::build_session_options(&matches); - - let descriptions = diagnostics_registry(); - - do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color)); - - let (odir, ofile) = make_output(&matches); - let (input, input_file_path) = match make_input(&matches.free) { - Some((input, input_file_path)) => callbacks.some_input(input, input_file_path), - None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) { - Some((input, input_file_path)) => (input, input_file_path), - None => return - } - }; - - let can_print_warnings = sopts.lint_opts - .iter() - .filter(|&&(ref key, _)| *key == "warnings") - .map(|&(_, ref level)| *level != lint::Allow) - .last() - .unwrap_or(true); - - - let codemap = codemap::CodeMap::with_file_loader(loader); - let diagnostic_handler = - diagnostic::Handler::new(sopts.color, Some(descriptions), can_print_warnings); - let span_diagnostic_handler = - diagnostic::SpanHandler::new(diagnostic_handler, codemap); - - let mut sess = session::build_session_(sopts, input_file_path, span_diagnostic_handler); - rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); - if sess.unstable_options() { - sess.opts.show_span = matches.opt_str("show-span"); - } - let cfg = config::build_configuration(&sess); - - do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile)); - - let plugins = sess.opts.debugging_opts.extra_plugins.clone(); - let control = callbacks.build_controller(&sess); - driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control); -} - -// Essentially the CSV file in a more accessible manner. -pub struct AnalysisData { - var_map: HashMap>, - var_ref_map: HashMap>>, - type_map: HashMap>, - type_ref_map: HashMap>>, - func_map: HashMap>, - func_ref_map: HashMap>>, -} - -pub fn init(analysis: &str) -> AnalysisData { - let mut var_map = HashMap::new(); - let mut var_ref_map = HashMap::new(); - let mut type_map = HashMap::new(); - let mut type_ref_map = HashMap::new(); - let mut ctor_map = HashMap::new(); - let mut qual_type_map = HashMap::new(); - let mut func_map = HashMap::new(); - let mut func_ref_map = HashMap::new(); - - for line in analysis.lines() { - //println!("{}", line); - let mut rdr = csv::Reader::from_string(line).has_headers(false); - for row in rdr.records() { - let row = row.unwrap(); - let mut map_record = HashMap::new(); - //println!("{:?}", row); - - let mut it = row.iter(); - it.next(); // discard first value - while let Some(key) = it.next() { - if let Some(val) = it.next() { - // has pair of values as expected - if key.to_string() == "qualname" { - let new_val = val.trim_left_matches(':'); - map_record.insert(key.clone(), new_val.to_string()); - if !map_record.contains_key("name") { - let name: Vec<&str> = new_val.split("::").collect(); - map_record.insert("name".to_string(), name[name.len()-1].to_string()); - } - } else { - map_record.insert(key.clone(), val.clone()); - } - } else { - break; - } - } - - match &row[0][..] { - "crate" => {}, - "external_crate" => {}, - "end_external_crates" => {}, - "function" | "function_impl" | "method_decl" => { - let rec = map_record.clone(); - let copy = map_record.clone(); - let key = rec.get("id").unwrap(); - func_map.insert(key.clone(), map_record); - - // Treat method impl as a function ref - let declid = rec.get("declid"); - match declid { - Some(x) if *x != "" => { - if !func_ref_map.contains_key(x) { - let v = vec![copy]; - func_ref_map.insert(x.clone(), v); - } else { - let vec = func_ref_map.get_mut(x); - vec.unwrap().push(copy); - } - }, - _ => {} - } - }, - "fn_ref" | "fn_call" | "method_call" => { - let rec = map_record.clone(); - let refid = rec.get("refid"); - let declid = rec.get("declid"); - let mut key = "".to_string(); - - match refid { - Some(x) if *x != "" && *x != "0" => { - key = x.clone(); - }, - _ => { - match declid { - Some(x) if *x != "" => { - key = x.clone(); - }, - None | _ => {} - } - } - } - - if !func_ref_map.contains_key(&key) { - let v = vec![map_record]; - func_ref_map.insert(key, v); - } else { - let vec = func_ref_map.get_mut(&key); - vec.unwrap().push(map_record); - - } - }, - "variable" => { - let key = map_record.get("id").unwrap().clone(); - var_map.insert(key, map_record); - }, - "var_ref" => { - let key = map_record.get("refid").unwrap().clone(); - - if !var_ref_map.contains_key(&key) { - let v = vec![map_record]; - var_ref_map.insert(key, v); - } else { - let vec = var_ref_map.get_mut(&key); - vec.unwrap().push(map_record); - - } - }, - "enum" => { - let rec = map_record.clone(); - let key = rec.get("id").unwrap(); - let q_key = rec.get("qualname").unwrap(); - type_map.insert(key.clone(), map_record); - qual_type_map.insert(q_key.clone(), key.clone()); - }, - "struct" => { - let rec = map_record.clone(); - let key = rec.get("id").unwrap(); - let c_key = rec.get("ctor_id").unwrap(); - let q_key = rec.get("qualname").unwrap(); - type_map.insert(key.clone(), map_record); - ctor_map.insert(c_key.clone(), key.clone()); - qual_type_map.insert(q_key.clone(), key.clone()); - }, - "type_ref" | "struct_ref" | "mod_ref" => { - let key = map_record.get("refid").unwrap().clone(); - - if !type_ref_map.contains_key(&key) { - let v = vec![map_record]; - type_ref_map.insert(key, v); - } else { - let vec = type_ref_map.get_mut(&key); - vec.unwrap().push(map_record); - - } - }, - "module" => {}, - "module_alias" => {}, - "unknown_ref" => {}, - _ => {} - } - } - - } - - // Fixup type_refs with refid = 0 and ctor_id references - let mut to_add = Vec::new(); - for (key, value) in type_ref_map.iter() { - if *key == "0" { - for i in value.iter() { - // must check qualname - let name = i.get("qualname").unwrap(); - if qual_type_map.contains_key(name) { - let mut modified = i.clone(); - modified.insert("refid".to_string(), qual_type_map.get(name).unwrap().clone()); - to_add.push(modified); - } - } - } else if let Some(ctor) = ctor_map.get(key) { - for i in value.iter() { - let mut modified = i.clone(); - modified.insert("refid".to_string(), ctor.clone()); - to_add.push(modified); - } - } - } - - for add in to_add.iter() { - let key = add.get("refid").unwrap().clone(); - if !type_ref_map.contains_key(&key) { - let v = vec![add.clone()]; - type_ref_map.insert(key, v); - } else { - let vec = type_ref_map.get_mut(&key); - vec.unwrap().push(add.clone()); - - } - } - - AnalysisData{ var_map: var_map, var_ref_map: var_ref_map, type_map: type_map, - type_ref_map: type_ref_map, func_map: func_map, func_ref_map: func_ref_map } -} - -// Convenience function for replacing the declaration and all references. -fn rename_dec_and_ref(new_name: &str, - rename_var: &str, - dec_map: &HashMap>, - ref_map: &HashMap>>) - -> HashMap { - let mut output = HashMap::new(); - - // TODO Failed an attempt to chain the declaration to the other iterator... - let map = dec_map.get(rename_var).unwrap(); - let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); - let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); - let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); - let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); - let filename = map.get("file_name").unwrap(); - - let mut new_file = String::new(); - File::open(&filename).expect("Missing file").read_to_string(&mut new_file); - - let mut ropes: Vec = new_file.lines().map(|x| Rope::from_string(String::from(x))).collect(); - rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); - - output.insert(filename.clone(), ropes); - - if let Some(references) = ref_map.get(rename_var) { - for map in references.iter() { - let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); - let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); - let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); - let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); - let filename = map.get("file_name").unwrap(); - if let Some(ref mut ropes) = output.get_mut(filename) { - rename(ropes, file_col, file_line, file_col_end, file_line_end, new_name); - continue; - } - let mut new_file = String::new(); - File::open(&filename).expect("Missing file").read_to_string(&mut new_file); - let mut ropes: Vec = new_file.lines().map(|x| Rope::from_string(String::from(x))).collect(); - rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); - output.insert(filename.clone(), ropes); - - - // let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); - } - } - - let mut outmap = HashMap::new(); - for (key, ropes) in output.iter() { - let mut answer = String::new(); - let mut count = ropes.len(); - for rope in ropes { - answer.push_str(&rope.to_string()); - if count > 1 { - answer.push_str("\n"); - count -= 1; - } - } - - outmap.insert(key.clone(), answer); - } - - outmap -} - -fn rename(ropes: &mut Vec, - file_col: usize, - file_line: usize, - file_col_end: usize, - file_line_end: usize, - new_name: &str) { - let to_change = &mut ropes[file_line-1..file_line_end]; - let length = to_change.len(); - - if file_line == file_line_end { - to_change[0].src_remove(file_col, file_col_end); - } else { - for i in 0..length { - let len = to_change[i].len(); - let line = &mut to_change[i]; - match i { - 0 => line.src_remove(file_col, len), - x if x == length => line.src_remove(0, file_col_end), - _ => line.src_remove(0, len) - } - } - } - - to_change[0].src_insert(file_col, new_name.to_string()); -} - -// Find the id associated with the row and column given -// (or a -1 wildcard is given and any with a matching name will be returned). -// TODO more efficient, perhaps better indexed and given type of node as arg -pub fn identify_id(input_filename: &str, - analyzed_data: &AnalysisData, - rename_var: &str, - row: i32, - col: i32, - file: Option<&str>) - -> String { - let _ = writeln!(&mut stderr(), "{} {} {}", rename_var, row, col); - for (key, value) in &analyzed_data.var_map { - if check_match(rename_var, input_filename, row, col, value, file) { - return key.clone(); - } - } - - for (key, value) in &analyzed_data.type_map { - if check_match(rename_var, input_filename, row, col, value, file) { - return key.clone(); - } - } - - for (key, value) in &analyzed_data.func_map { - if check_match(rename_var, input_filename, row, col, value, file) { - return key.clone(); - } - } - - "".to_string() -} - -fn check_match(name: &str, - input_filename: &str, - row: i32, - col: i32, - record: &HashMap, - file: Option<&str>) - -> bool { - - let c: i32 = record.get("file_col").unwrap().parse().unwrap(); - let r: i32 = record.get("file_line").unwrap().parse().unwrap(); - let r_end: i32 = record.get("file_line_end").unwrap().parse().unwrap(); - let c_end: i32 = record.get("file_col_end").unwrap().parse().unwrap(); - let filename = record.get("file_name").unwrap(); - let n = record.get("name").unwrap(); - - if &name == n && (!file.is_some() || filename == file.unwrap()) { - if !(row < 0) { - if row >= r && row <= r_end { - if !(col < 0) { - if col >= c && col < c_end { - return true; - } - } else { - return true; - } - } - } else { - return true; - } - } - - false -} - -#[derive(Copy, Clone, PartialEq)] -pub enum RefactorType { - Variable, - Function, - Type, - InlineLocal, - Reduced, - ReifyLifetime, - ElideLifetime, - Nil, -} - -struct RefactorCalls { - default_calls: RustcDefaultCalls, - r_type: RefactorType, - new_name: String, - node_to_find: NodeId, - input: Option>, - working_file: Option, - is_full: bool, -} - -impl RefactorCalls { - fn new(t: RefactorType, - new_name: String, - node: NodeId, - new_file: Option>, - working_file: Option, - is_full: bool) - -> RefactorCalls { - RefactorCalls { - default_calls: RustcDefaultCalls, - r_type: t, - new_name: new_name, - node_to_find: node, - input: new_file, - working_file: working_file, - is_full: is_full, - } - } -} - -impl<'a> CompilerCalls<'a> for RefactorCalls { - fn late_callback(&mut self, - m: &getopts::Matches, - s: &Session, - i: &Input, - odir: &Option, - ofile: &Option) - -> Compilation { - self.default_calls.late_callback(m, s, i, odir, ofile); - Compilation::Continue - } - - fn some_input(&mut self, - input: Input, - input_path: Option) - -> (Input, Option) { - (input, input_path) - } - - fn no_input(&mut self, - m: &getopts::Matches, - o: &config::Options, - odir: &Option, - ofile: &Option, - r: &diagnostics::registry::Registry) - -> Option<(Input, Option)> { - self.default_calls.no_input(m, o, odir, ofile, r); - // This is not optimal error handling. - panic!("No input supplied"); - } - - fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> { - let r_type = self.r_type; - let is_full = self.is_full; - let node_to_find = self.node_to_find; - let input = self.working_file.clone().unwrap_or_default(); - - let mut control = driver::CompileController::basic(); - if is_full { - control.after_analysis.stop = Compilation::Stop; - control.after_analysis.callback = box move |state| { - let krate = state.krate.unwrap().clone(); - let tcx = state.tcx.unwrap(); - let anal = state.analysis.unwrap(); - let mut new_for = Forest::new(krate.clone()); - let ast_map_original = map_crate(&mut new_for); - let ast_map = &tcx.map; - if r_type == RefactorType::InlineLocal { - - debug!("{:?}", ast_map.get(ast_map.get_parent(node_to_find))); - debug!("{:?}", ast_map.get(node_to_find)); - - match ast_map.get(node_to_find) { - NodeLocal(ref pat) => { - }, - _ => { panic!(); } - } - - let mut parent = None; - let mut other = None; - match ast_map_original.get(ast_map.get_parent(node_to_find)) { - custom_map::NodeItem(ref item) => { - parent = Some(P((*item).clone())); - other = Some((*item).clone()); - debug!("{:?}", pprust::item_to_string(item)); - }, - _ => {} - } - - let src; - src = state.session.codemap().get_filemap(&input[..]) - .src - .as_ref() - .unwrap() - .as_bytes() - .to_vec(); - // need to distinguish internal errors - - let mut rdr = &src[..]; - let mut out = Vec::new(); - let ann = pprust::NoAnn; - { - let out_borrow: &mut Write = &mut out; - let mut pp_state = State::new_from_input(state.session.codemap(), state.session.diagnostic(), input.clone(), &mut rdr, box out_borrow, &ann, true); - - if let Some(other) = other { - let _ = pp_state.print_item(&other); - //debug!("{:?}", v); - //pp_state.print_mod(&krate.module, &krate.attrs); - } - let _ = eof(&mut pp_state.s); - } - let _ = out.flush(); - debug!("{:?}", out); - /*{ - let mut out_borrow: &mut Write = &mut out; - let ann = pprust::NoAnn; - pprust::print_crate(state.session.codemap(), state.session.diagnostic(), &krate, input.clone(), &mut rdr, box out_borrow, &ann, true); - } - debug!("{:?}", out);*/ - - // Build save walker - let src2; - src2 = state.session.codemap().get_filemap(&input[..]) - .src - .as_ref() - .unwrap() - .as_bytes() - .to_vec(); - let mut rdr2 = &src2[..]; - - if let Some(par) = parent { - let outer_span = par.span; - //let mut visitor = DumpCsvVisitor::new(tcx, anal, output_file); - let mut folder = InlineFolder::new(tcx, anal, node_to_find); - debug!("{:?}", Vec::from_iter(folder.fold_item(par.clone()).into_iter())); - debug!("Number of usages: {}", folder.usages); - - // First we want to ignore destructuring locals, this has issues with lifetimes + type info. - // It should also actually BE a local, not just some variable-like item. - // TODO - // What about sensible destructors, operator overloading? - // BUT if we get a 'consider using a let binding error', then, we cannot inline. - if folder.usages <= 1 { - // This is generally OK, unless the expression contains an impure function/constructor - // e.g. let a = - // - // Now if we move the first change after the second change, behaviour might change. - // If doesn't matter here if we have copy, move, borrow etc. - // - // Due to uniqueness constraints in Rust, if there is just a single usage, there really - // is just a single usage without any aliases. - - // If any variables composing the initializer were redeclared in the meantime, return - if folder.changed_paths { - return; - } - - - } else { - // Otherwise, multiple references: - - // Mutable case: - // If the variable is mutable, inlining is a bad idea!!! - // e.g. let mut a = 2; - // a = 3; // Now the expression is made the lvalue, but this holds no meaning - // Same again with *&mut a modifying the internal value. - let used_mutables = tcx.used_mut_nodes.borrow(); - // CAVEAT: - // If the mutable was never used, then it should be considered mutable. - if folder.mutable && used_mutables.contains(&node_to_find) { - debug!("IS MUTABLE"); - return; - } - // CAVEAT: - // If there is a refcell, or interior mutability, then it really is mutable. - let ty_cache = tcx.ast_ty_to_ty_cache.borrow(); - let interior_unsafe = 0b0000_0000__0000_0000__0010; - if let Some(node_ctx) = ty_cache.get(&folder.type_node_id) { - debug!("BITS: {:?}", node_ctx.type_contents(tcx).bits); - if node_ctx.type_contents(tcx).bits & interior_unsafe != 0 { - debug!("IS MUTABLE (REFCELL)"); - return; - } - } - - // If the variable is a direct alias, then it might be alright. - // In this case, movements or borrows are irrelevant. - // e.g. let a = 2; - // let b = a; // copy, but memory shouldn't mutate underneath - // or let a = &2; - // let b = a; // this duplicates the reference - // or let a = &mut 2; - // let b = a; // this moves &mut into b - // or let a = vec![0]; - // let b = a; // this moves a into b - // Whether or not a is inlined, it must follow the normal lifetime rules. - // Whatever a refers to must exists for the right scopes. - // However, you must check no one redeclares a in the meantime! - if let Some(ref to_replace) = folder.to_replace { - match (**to_replace).node { - syntax::ast::ExprPath(..) => { - // Alias case: - }, - _ => { - } - } - } - - - debug!("IS NOT MUTABLE"); - // Immutable case: - // Check which paths compose the initializer and ensure they resolve - // to the same item at the new call site. - // e.g. b = 2; - // let a = b + c - // let b = 3; - // println!("{}", a); - - // If any variables composing the initializer were redeclared in the meantime, return - if folder.changed_paths { - return; - } - - // If any variables composing the initializer mutated in the meantime, return - // TODO - - } - - let mut out = Vec::new(); - { - let out_borrow: &mut Write = &mut out; - let mut pp_state = State::new_from_input(state.session.codemap(), state.session.diagnostic(), input.clone(), &mut rdr2, box out_borrow, &ann, true); - - let _ = pp_state.print_item(&folder.fold_item(par).get(0)); - //debug!("{:?}", v); - //pp_state.print_mod(&krate.module, &krate.attrs); - //pp_state.print_remaining_comments(); - let _ = eof(&mut pp_state.s); - } - let _ = out.flush(); - debug!("{:?}", out); - let hi_pos = state.session.codemap().lookup_byte_offset(outer_span.hi).pos.to_usize(); - let lo_pos = state.session.codemap().lookup_byte_offset(outer_span.lo).pos.to_usize(); - panic!((lo_pos, hi_pos, String::from_utf8(out).ok().expect("Pretty printer didn't output UTF-8"), 0)); - //pprust::item_to_string(folder.fold_item(par).get(0)) - //visit::walk_crate(&mut visitor, &krate); - } - } else if r_type == RefactorType::ReifyLifetime || r_type == RefactorType::ElideLifetime { - debug!("{:?}", ast_map.get(node_to_find)); - - let taken = lifetimes_in_scope(&tcx.map, node_to_find); - let life_giver = LifeGiver::with_taken(&taken[..]); - let node_inner = match ast_map_original.find(node_to_find) { - Some(ref node) => match *node { - custom_map::NodeItem(ref item) => { - match item.node { - syntax::ast::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, ref body) => { - Some((fn_decl, gen, unsafety, constness, - item.ident, None, item.span, body.span)) - }, - _ => None - } - } - custom_map::NodeImplItem(item) => { - match item.node { - syntax::ast::MethodImplItem(ref sig, ref body) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.ident, - Some(&sig.explicit_self.node), - item.span, body.span)) - } - //ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"), - _ => None, - } - }, - custom_map::NodeTraitItem(item) => { - match item.node { - syntax::ast::MethodTraitItem(ref sig, Some(ref body)) => { - Some((&sig.decl, - &sig.generics, - sig.unsafety, - sig.constness, - item.ident, - Some(&sig.explicit_self.node), - item.span, body.span)) - } - _ => None - } - } - _ => None - }, - None => None - }; - let mut a = Vec::new(); - let (fn_decl, generics, unsafety, constness, ident, expl_self, span, body_span) - = node_inner.expect("expect item fn"); - - let mut folder = LifetimeFolder{ has_bounds: false, expl_self: Name(0) }; - let elided_fn_decl = folder.fold_fn_decl(fn_decl.clone()); - let elided_expl_self_tmp; - let mut elided_expl_self = None; - - // Count input lifetimes and count output lifetimes. - let mut in_walker = LifetimeWalker::new(); - let mut out_walker = LifetimeWalker::new(); - - if let Some(expl_self) = expl_self { - visit::walk_explicit_self(&mut in_walker, - &Spanned {node: lowering::lower_explicit_self_underscore(expl_self), span: DUMMY_SP}); - elided_expl_self_tmp = folder.fold_explicit_self(Spanned {node: expl_self.clone(), span: DUMMY_SP}); - elided_expl_self = Some(&elided_expl_self_tmp.node); - } - - for argument in fn_decl.inputs.iter() { - debug!("FN DECL: {:?}", argument); - visit::walk_ty(&mut in_walker, &lowering::lower_ty(&*argument.ty)); - } - - let lowered_fn = lowering::lower_fn_decl(&fn_decl); - visit::walk_fn_ret_ty(&mut out_walker, &lowered_fn.output); - - if r_type == RefactorType::ElideLifetime { - let elided_generics = folder.fold_generics(generics.clone()); - let mut parameterized = HashSet::new(); - for lifetimes in generics.lifetimes.iter() { - parameterized.insert(lifetimes.lifetime.name); - } - - // Can't elide if returning multiple lifetimes - if out_walker.names.len() > 1 { - return; - } - - // Don't elide if return doesn't appear in generics (trait lifetime?) - let intersect: HashSet<_> = out_walker.names.intersection(¶meterized).cloned().collect(); - if out_walker.names.len() > 0 && intersect.len() == 0 { - return; - } - - // Make sure that each input lifetime is never used more than once - if in_walker.names.len() as u32 + in_walker.anon != in_walker.total { - return; - } - - // If you have a return, either it has the same name as the only input, or that of self - let intersect: HashSet<_> = out_walker.names.intersection(&in_walker.names).cloned().collect(); - if out_walker.names.len() > 0 && !out_walker.names.contains(&folder.expl_self) - && (in_walker.names.len() > 1 || intersect.len() == 0) { - return; - } - - // Make sure that input lifetimes are all parameterized - // TODO delete only unparameterized? - if !in_walker.names.is_subset(¶meterized) { - return; - } - - // TODO move has_bounds out of the folder - if folder.has_bounds { - return; - } - - let mut answer = pprust::fun_to_string(&elided_fn_decl, unsafety, constness, ident, elided_expl_self, &elided_generics); - - // Add some likely spacing - answer.push_str(" "); - - let hi_pos = state.session.codemap().lookup_byte_offset(body_span.lo).pos.to_usize(); - let lo_pos = state.session.codemap().lookup_byte_offset(span.lo).pos.to_usize(); - panic!((lo_pos, hi_pos, answer, 0)); - } - - // Count anonymous and count total. - // CASE 1: fn <'a> (x: &'a) -> &out - // CASE 2: fn (x: &a) -> &out - // If there is exactly 1 input lifetime, then reuse that lifetime for output (possibly multiple). - if in_walker.total == 1 { - let mut regions = Vec::new(); - if in_walker.anon == 0 { - // CASE 1 - regions.push(BrNamed(DefId{krate: 0, node: 0}, generics.lifetimes.get(0).unwrap().lifetime.name)); - for x in 0..out_walker.anon { - regions.push(BrAnon(x)); - } - } else { - // CASE 2 - regions.push(BrAnon(0)); - for x in 0..out_walker.anon { - regions.push(BrAnon(x+1)); - } - } - a.push(SameRegions{scope_id: 0, regions: regions}); - - } else if in_walker.total > 1 { - // If there is more than one lifetime, then: - // fn <'a, 'b> (x: &'a, y: &'b, z: &) -> &'a out - // We can make concrete the anonymous input lifetimes but not the output. - for x in 0..in_walker.anon { - a.push(SameRegions{scope_id: 0, regions: vec![BrAnon(x)]}); - } - - // Unless, there is a self lifetime, then: - // fn <'a, 'b> (self: &'a, ...) -> &out - // We can make concrete the output lifetime as well (which may be multiple). - if let Some(expl_self) = expl_self { - match *expl_self { - syntax::ast::SelfRegion(ref life, _, _) => { - if life.is_some() { - // self has a named lifetime - let mut regions = Vec::new(); - regions.push(BrNamed(DefId{krate: 0, node: 0}, life.unwrap().name)); - for x in 0..out_walker.anon { - regions.push(BrAnon(in_walker.anon + x)); - } - a.push(SameRegions{scope_id: 0, regions: regions}); - } else { - // self is anonymous - // TODO remove expl_self - let mut regions = &mut a.get_mut(in_walker.expl_self as usize).expect("Missing expl self").regions; - for x in 0..out_walker.anon { - regions.push(BrAnon(in_walker.anon + x)); - } - } - } - _ => () - } - } - - } - - let rebuilder = Rebuilder::new(tcx, fn_decl, expl_self, - generics, &a/*same_regions*/, &life_giver); - let (fn_decl, expl_self, generics) = rebuilder.rebuild(); - //self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident, - // expl_self.as_ref(), &generics, span); - debug!("{}", pprust::fun_to_string(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics)); - println!("{}", pprust::fun_to_string(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics)); - //debug!("{:?}", tcx.region_maps); - debug!("{:?}", tcx.named_region_map); - //debug!("{:?}", tcx.free_region_maps.borrow()); - let mut answer = pprust::fun_to_string(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics); - - // Add some likely spacing - answer.push_str(" "); - - let hi_pos = state.session.codemap().lookup_byte_offset(body_span.lo).pos.to_usize(); - let lo_pos = state.session.codemap().lookup_byte_offset(span.lo).pos.to_usize(); - panic!((lo_pos, hi_pos, answer, 0)); - } - }; - - return control; - } - - let new_name = self.new_name.clone(); - - control.after_write_deps.stop = Compilation::Stop; - control.after_write_deps.callback = box move |state| { - //let krate = state.krate.unwrap().clone(); - let ast_map = state.ast_map.unwrap(); - let krate = ast_map.krate(); - LocalCrateReader::new(&state.session, &ast_map).read_crates(krate); - let _ = lang_items::collect_language_items(krate, &state.session); - /*let resolve::CrateMap { - def_map, - freevars, - export_map, - trait_map, - external_exports, - glob_map, - } = resolve::resolve_crate(&state.session, &ast_map, resolve::MakeGlobMap::No); - debug!("{:?}", def_map);*/ - - // According to some condition ! - //let ps = syntax::parse::ParseSess::new(); - //let ps = &state.session.parse_sess; - let cratename = match attr::find_crate_name(&krate.attrs[..]) { - Some(name) => name.to_string(), - None => String::from("unknown_crate"), - }; - debug!("{}", cratename); - - debug!("{:?}", token::str_to_ident(&new_name[..])); - debug!("{:?}", token::str_to_ident(&new_name[..])); - //let ast_node = ast_map.get(ast_map.get_parent(node_to_find)); - //println!("{:?}", ast_node); - debug!("{}", node_to_find); - let ast_node = ast_map.find(node_to_find); - debug!("{:?}", ast_node); - debug!("{:?}", token::str_to_ident(&new_name[..])); - - // find current path and syntax context - let mut syntax_ctx = 0; - // If None, then it is probably a field. - // TODO fields have no super/sub-block conflict - // Can we remove the compiler runs afterwards? - if let Some(ast_node) = ast_node { - match ast_node { - NodeLocal(pat) => { - match pat.node { - ast::PatIdent(_, path, _) => { - syntax_ctx = path.node.ctxt; - }, - _ => {} - } - }, - - _ => {} - } - } - - let path = build_path(DUMMY_SP, vec![token::str_to_ident(&new_name)]); - // create resolver - let mut resolver = resolve::create_resolver(&state.session, &ast_map, krate, resolve::MakeGlobMap::No, - Some(Box::new(move |node: ast_map::Node, resolved: &mut bool| { - if *resolved { - return true; - } - //debug!("Entered resolver callback"); - match node { - NodeLocal(pat) => { - if pat.id == node_to_find { - debug!("Found node"); - *resolved = true; - return true; - } - }, - NodeItem(item) => { - match item.node { - ItemImpl(_, _, _, _, _, ref impls) => { - for i in impls.iter() { - if i.id == node_to_find { - debug!("{:?}", i); - debug!("Found node"); - *resolved = true; - return true; - } - } - }, - ItemStruct(ref def, _) => { - for field in def.fields.iter() { - if field.node.id == node_to_find { - *resolved = true; - return true; - } - } - }, - _ => {} - - } - if item.id == node_to_find { - debug!("Found node"); - debug!("{:?}", item); - *resolved = true; - return true; - } - }, - _ => {} - } - - false - }))); - - match r_type { - RefactorType::Type => { - let mut h = HashMap::new(); - h.insert(String::new(), String::new()); - debug!("{:?}", token::str_to_ident(&new_name[..])); - - let mut idens = ast_map.with_path(node_to_find, |path| { - let itr = token::get_ident_interner(); - - path.fold(Vec::new(), |mut s, e| { - let e = itr.get(e.name()); - s.push(token::str_to_ident(&e[..])); - s }) - //ast_map::path_to_string(path) - }); - - - visit::walk_crate(&mut resolver, krate); - - let new_iden = token::str_to_ident(&new_name[..]); - idens.pop(); - idens.push(new_iden); - - token::str_to_ident(&new_name[..]); - let path = build_path(DUMMY_SP, idens); - - // resolver resolve node id - println!("{:?}", path); - if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::TypeNS, true).is_some() { - // unwind at this location - panic!(h); - } - }, - RefactorType::Variable => { - let mut t = token::str_to_ident(&new_name[..]); - t.ctxt = syntax_ctx; - debug!("{:?}", mtwt::resolve(t)); - let path = build_path(DUMMY_SP, vec![t]); - - visit::walk_crate(&mut resolver, krate); - - let mut h = HashMap::new(); - h.insert(String::new(), String::new()); - debug!("{:?}", token::str_to_ident(&new_name[..])); - - // resolver resolve node id - //if resolver.resolve_path(node_to_find, &path) { - if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::ValueNS, true).is_some() { - // unwind at this location - panic!(h); - } - //println!("{:?}", mtwt::resolve( token::str_to_ident(&new_name[..]))); - - }, - RefactorType::Function => { - let mut idens = ast_map.with_path(node_to_find, |path| { - let itr = token::get_ident_interner(); - - path.fold(Vec::new(), |mut s, e| { - let e = itr.get(e.name()); - s.push(token::str_to_ident(&e[..])); - s - }) - //ast_map::path_to_string(path) - - }); - - let new_iden = token::str_to_ident(&new_name[..]); - idens.pop(); - idens.push(new_iden); - - visit::walk_crate(&mut resolver, krate); - - let mut h = HashMap::new(); - h.insert(String::new(), String::new()); - debug!("{:?}", token::str_to_ident(&new_name[..])); - - // TODO - // let path = cx.path(DUMMY_SP, idens); - // resolver resolve node id - //if resolver.resolve_path(node_to_find, &path) { - if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::ValueNS, true).is_some() { - // unwind at this location - debug!("BAD ValueNS"); - panic!(h); - } - - // Is it possible for type namespace to ever conflict with functions? - /*if resolver.resolve_path(node_to_find, &path, 0, resolve::Namespace::TypeNS, true).is_some() { - // unwind at this location - debug!("BAD TypeNS"); - panic!(h); - }*/ - - debug!("OK"); - //println!("{:?}", mtwt::resolve( token::str_to_ident(&new_name[..]))); - }, - _ => { debug!("HERE"); /* Reduced graph check falls here */ } - } - }; - - control - } -} - -// Extract output directory and file from matches. -fn make_output(matches: &getopts::Matches) -> (Option, Option) { - let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o)); - let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o)); - (odir, ofile) -} - -// Extract input (string or file and optional path) from matches. -fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { - if free_matches.len() == 1 { - let ifile = &free_matches[0][..]; - if ifile == "-" { - let mut src = String::new(); - io::stdin().read_to_string(&mut src).unwrap(); - Some((Input::Str(src), None)) - } else { - Some((Input::File(PathBuf::from(ifile)), Some(PathBuf::from(ifile)))) - } - } else { - None - } -} - -// Path functions duplicated due to HIR lowering -pub fn build_path(span: Span, strs: Vec ) -> ast::Path { - path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new()) -} - -pub fn build_path_ident(span: Span, id: Ident) -> ast::Path { - build_path(span, vec!(id)) -} - -pub fn build_path_global(span: Span, strs: Vec ) -> ast::Path { - path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new()) -} - -fn path_all(sp: Span, - global: bool, - mut idents: Vec , - lifetimes: Vec, - types: Vec>, - bindings: Vec> ) - -> ast::Path { - let last_identifier = idents.pop().unwrap(); - let mut segments: Vec = idents.into_iter() - .map(|ident| { - ast::PathSegment { - identifier: ident, - parameters: ast::PathParameters::none(), - } - }).collect(); - segments.push(ast::PathSegment { - identifier: last_identifier, - parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), - }) - }); - ast::Path { - span: sp, - global: global, - segments: segments, - } -} diff --git a/src/refactor/error.rs b/src/refactor/error.rs new file mode 100644 index 0000000..6294e45 --- /dev/null +++ b/src/refactor/error.rs @@ -0,0 +1,7 @@ +// The general idea is to expand the variants to be more fine-grained. +#[derive(Debug, PartialEq)] +pub enum Response { + Error, + Conflict, + Possible, +} \ No newline at end of file diff --git a/src/refactor/inline_local.rs b/src/refactor/inline_local.rs new file mode 100644 index 0000000..c7e5842 --- /dev/null +++ b/src/refactor/inline_local.rs @@ -0,0 +1,47 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use syntax::ast::NodeId; +use super::{RefactorType, Response}; + +use strings::src_rope::Rope; + +use analysis::AnalysisData; +use compiler; + +// Inline a local variable +pub fn inline_local(input_file: &str, + analyzed_data: &AnalysisData, + rename_var: &str) + -> Result, Response> { + let dec_map = &analyzed_data.var_map; + //let ref_map = &analyzed_data.var_ref_map; + let node: NodeId = rename_var.parse().unwrap(); + + let input_file_str = String::from(input_file); + + let mut filename = String::from(input_file); + if let Some(decl) = dec_map.get(rename_var) { + if let Some(file) = decl.get("file_name") { + filename = file.clone(); + } + } + let filename = filename; + let (x,y,z,_) = match compiler::run_resolution(input_file_str, None, Some(filename.clone()), RefactorType::InlineLocal, + String::from(rename_var), node, true) { + Ok(()) => { debug!("Unexpected success!"); return Err(Response::Conflict) }, + Err(x) => { println!("{:?}", x); x } + }; + + let mut new_file = String::new(); + File::open(&filename).expect("Missing file").read_to_string(&mut new_file).unwrap(); + let mut rope = Rope::from_string(new_file); + + rope.src_remove(x, y); + rope.src_insert(x, z); + + let mut output = HashMap::new(); + output.insert(filename, rope.to_string()); + Ok(output) +} diff --git a/src/refactor/lifetimes.rs b/src/refactor/lifetimes.rs new file mode 100644 index 0000000..80a2109 --- /dev/null +++ b/src/refactor/lifetimes.rs @@ -0,0 +1,89 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use syntax::ast::NodeId; +use super::{RefactorType, Response}; + +use strings::src_rope::Rope; + +use analysis::AnalysisData; +use compiler; + +// Reify the lifetimes in a signature +pub fn restore_fn_lifetime(input_file: &str, + analyzed_data: &AnalysisData, + rename_var: &str) + -> Result, Response> { + let dec_map = &analyzed_data.func_map; + + let node: NodeId = rename_var.parse().unwrap(); + + let input_file_str = String::from(input_file); + + let mut filename = String::from(input_file); + if let Some(decl) = dec_map.get(rename_var) { + if let Some(file) = decl.get("file_name") { + filename = file.clone(); + } + } + let (x,y,z,_) = match compiler::run_resolution(input_file_str, None, Some(filename.clone()), RefactorType::ReifyLifetime, + String::from(rename_var), node, true) { + Ok(()) => { debug!("Unexpected success!"); return Err(Response::Conflict) }, + Err(x) => { println!("{:?}", x); x } + }; + + let mut new_file = String::new(); + File::open(&filename).expect("Missing file").read_to_string(&mut new_file).unwrap(); + let mut rope = Rope::from_string(new_file); + + debug!("{}", filename); + debug!("{}", rope.to_string()); + rope.src_remove(x, y); + rope.src_insert(x, z); + + let mut output = HashMap::new(); + output.insert(filename, rope.to_string()); + debug!("{}", rope.to_string()); + Ok(output) +} + +// Elide the lifetimes in a signature +pub fn elide_fn_lifetime(input_file: &str, + analyzed_data: &AnalysisData, + rename_var: &str) + -> Result, Response> { + let dec_map = &analyzed_data.func_map; + + let node: NodeId = rename_var.parse().unwrap(); + + let input_file_str = String::from(input_file); + + let mut filename = String::from(input_file); + if let Some(decl) = dec_map.get(rename_var) { + if let Some(file) = decl.get("file_name") { + filename = file.clone(); + } + } + let filename = filename; + debug!("{}", filename); + let (x,y,z,_) = match compiler::run_resolution(input_file_str, None, Some(filename.clone()), RefactorType::ElideLifetime, + String::from(rename_var), node, true) { + Ok(()) => { debug!("Unexpected success!"); return Err(Response::Conflict) }, + Err(x) => { println!("{:?}", x); x } + }; + + let mut new_file = String::new(); + File::open(&filename).expect("Missing file").read_to_string(&mut new_file).unwrap(); + let mut rope = Rope::from_string(new_file); + + debug!("{}", filename); + debug!("{}", rope.to_string()); + rope.src_remove(x, y); + rope.src_insert(x, z); + + let mut output = HashMap::new(); + output.insert(filename, rope.to_string()); + debug!("{}", rope.to_string()); + Ok(output) +} diff --git a/src/refactor/mod.rs b/src/refactor/mod.rs new file mode 100644 index 0000000..f63026b --- /dev/null +++ b/src/refactor/mod.rs @@ -0,0 +1,27 @@ +mod error; +pub mod inline_local; +pub mod lifetimes; +mod rename; +pub mod rename_function; +pub mod rename_type; +pub mod rename_variable; + +pub use self::error::Response; +pub use self::inline_local::inline_local; +pub use self::lifetimes::{elide_fn_lifetime, restore_fn_lifetime}; +pub use self::rename::{rename, rename_dec_and_ref}; +pub use self::rename_function::rename_function; +pub use self::rename_type::rename_type; +pub use self::rename_variable::rename_variable; + +#[derive(Copy, Clone, PartialEq)] +pub enum RefactorType { + Variable, + Function, + Type, + InlineLocal, + Reduced, + ReifyLifetime, + ElideLifetime, + Nil, +} diff --git a/src/refactor/rename.rs b/src/refactor/rename.rs new file mode 100644 index 0000000..21a40c8 --- /dev/null +++ b/src/refactor/rename.rs @@ -0,0 +1,95 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use strings::src_rope::Rope; + +// Convenience function for replacing the declaration and all references. +pub fn rename_dec_and_ref(new_name: &str, + rename_var: &str, + dec_map: &HashMap>, + ref_map: &HashMap>>) + -> HashMap { + let mut output = HashMap::new(); + + // TODO Failed an attempt to chain the declaration to the other iterator... + let map = dec_map.get(rename_var).unwrap(); + let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); + let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); + let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); + let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); + let filename = map.get("file_name").unwrap(); + + let mut new_file = String::new(); + File::open(&filename).expect("Missing file").read_to_string(&mut new_file).unwrap(); + + let mut ropes: Vec = new_file.lines().map(|x| Rope::from_string(String::from(x))).collect(); + rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); + + output.insert(filename.clone(), ropes); + + if let Some(references) = ref_map.get(rename_var) { + for map in references.iter() { + let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); + let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); + let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); + let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); + let filename = map.get("file_name").unwrap(); + if let Some(ref mut ropes) = output.get_mut(filename) { + rename(ropes, file_col, file_line, file_col_end, file_line_end, new_name); + continue; + } + let mut new_file = String::new(); + File::open(&filename).expect("Missing file").read_to_string(&mut new_file).unwrap(); + let mut ropes: Vec = new_file.lines().map(|x| Rope::from_string(String::from(x))).collect(); + rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); + output.insert(filename.clone(), ropes); + + + // let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); + } + } + + let mut outmap = HashMap::new(); + for (key, ropes) in output.iter() { + let mut answer = String::new(); + let mut count = ropes.len(); + for rope in ropes { + answer.push_str(&rope.to_string()); + if count > 1 { + answer.push_str("\n"); + count -= 1; + } + } + + outmap.insert(key.clone(), answer); + } + + outmap +} + +pub fn rename(ropes: &mut Vec, + file_col: usize, + file_line: usize, + file_col_end: usize, + file_line_end: usize, + new_name: &str) { + let to_change = &mut ropes[file_line-1..file_line_end]; + let length = to_change.len(); + + if file_line == file_line_end { + to_change[0].src_remove(file_col, file_col_end); + } else { + for i in 0..length { + let len = to_change[i].len(); + let line = &mut to_change[i]; + match i { + 0 => line.src_remove(file_col, len), + x if x == length => line.src_remove(0, file_col_end), + _ => line.src_remove(0, len) + } + } + } + + to_change[0].src_insert(file_col, new_name.to_string()); +} diff --git a/src/refactor/rename_function.rs b/src/refactor/rename_function.rs new file mode 100644 index 0000000..605343d --- /dev/null +++ b/src/refactor/rename_function.rs @@ -0,0 +1,98 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use syntax::ast::NodeId; + +use strings::src_rope::Rope; + +use super::{RefactorType, Response}; +use analysis::AnalysisData; +use compiler; +use refactor; + +// Rename functions and methods. +pub fn rename_function(input_file: &str, + analyzed_data: &AnalysisData, + new_name: &str, + rename_var: &str) + -> Result, Response> { + // method calls refer to top level trait function in declid + + // rename original function + + // then rename all statically dispatched with refid = id + // then rename all dynamically dispatched with declid = id + // then rename all functions with declid = id + // assuming mutual exclusion, these should all be covered in func_ref_map + + let dec_map = &analyzed_data.func_map; + let ref_map = &analyzed_data.func_ref_map; + let node: NodeId = rename_var.parse().unwrap(); + + let mut filename = String::from(input_file); + if let Some(decl) = dec_map.get(rename_var) { + if let Some(file) = decl.get("file_name") { + // FIXME: what's the point of this? We never use this value... + filename = file.clone(); + } + } + + match compiler::run_resolution(input_file.to_owned(), None, None, RefactorType::Function, + String::from(new_name), node, false) { + Ok(()) => {}, + Err(_) => { debug!("Unexpected failure!"); return Err(Response::Conflict) } + } + + if let Some(references) = ref_map.get(rename_var) { + for map in references.iter() { + let filename = map.get("file_name").unwrap(); + + let mut file = match File::open(&filename) { + Err(why) => panic!("couldn't open file {}", why), + Ok(file) => file, + }; + let mut file_str = String::new(); + let _ = file.read_to_string(&mut file_str); + let file_str = &file_str[..]; + + let mut ropes: Vec = file_str.lines().map(|x| Rope::from_string(String::from(x))).collect(); + let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); + let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); + let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); + let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); + + refactor::rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); + let mut answer = String::new(); + let mut count = ropes.len(); + for rope in &ropes { + answer.push_str(&rope.to_string()); + if count > 1 { + answer.push_str("\n"); + count -= 1; + } + } + + match compiler::run_resolution(String::from(input_file), Some(vec![(String::from(filename.clone()), answer)]), + None, RefactorType::Variable, String::from(new_name), + node, true) { + Ok(()) => { + debug!("Unexpected success!"); + // Check for conflicts + return Err(Response::Conflict); + }, + Err(_) => { debug!("Expected failure!");} + } + } + } + + let output = refactor::rename_dec_and_ref(new_name, rename_var, dec_map, ref_map); + + //println!("{:?}", output); + try!(compiler::check_reduced_graph(String::from(input_file), + output.iter().map(|(x,y)| + (x.clone(), y.clone())).collect(), + String::from(new_name), node)); + + Ok(output) +} diff --git a/src/refactor/rename_type.rs b/src/refactor/rename_type.rs new file mode 100644 index 0000000..f8d1b5a --- /dev/null +++ b/src/refactor/rename_type.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use syntax::ast::NodeId;use super::{RefactorType, Response}; + +use strings::src_rope::Rope; + +use analysis::AnalysisData; +use compiler; +use refactor; + +// Rename concrete types (structs, enums and struct enums). +pub fn rename_type(input_file: &str, + analyzed_data: &AnalysisData, + new_name: &str, + rename_var: &str) + -> Result, Response> { + + let dec_map = &analyzed_data.type_map; + let ref_map = &analyzed_data.type_ref_map; + let node: NodeId = rename_var.parse().unwrap(); + + let input_file_str = String::from(input_file); + let mut filename = String::from(input_file); + if let Some(decl) = dec_map.get(rename_var) { + if let Some(file) = decl.get("file_name") { + // FIXME: what's the point of this? We never use this value... + filename = file.clone(); + } + } + + match compiler::run_resolution(input_file_str, None, None, RefactorType::Type, + String::from(new_name), node, false) { + Ok(()) => {}, + Err(_) => { debug!("Unexpected failure!"); return Err(Response::Conflict) } + } + + if let Some(references) = ref_map.get(rename_var) { + for map in references.iter() { + let filename = map.get("file_name").unwrap(); + + let mut file = match File::open(&filename) { + Err(why) => panic!("couldn't open file {}", why), + Ok(file) => file, + }; + let mut file_str = String::new(); + let _ = file.read_to_string(&mut file_str); + let file_str = &file_str[..]; + let mut ropes: Vec = file_str.lines().map(|x| Rope::from_string(String::from(x))).collect(); + let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); + let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); + let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); + let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); + + //let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); + refactor::rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); + let mut answer = String::new(); + let mut count = ropes.len(); + for rope in &ropes { + answer.push_str(&rope.to_string()); + if count > 1 { + answer.push_str("\n"); + count -= 1; + } + } + + match compiler::run_resolution(String::from(input_file), Some(vec![(String::from(filename.clone()), answer)]), + None, RefactorType::Variable, String::from(new_name), + node, true) { + Ok(()) => { + debug!("Unexpected success!"); + // Check for conflicts + return Err(Response::Conflict); + }, + Err(_) => { debug!("Expected failure!");} + } + } + } + + Ok(refactor::rename_dec_and_ref(new_name, rename_var, dec_map, ref_map)) +} \ No newline at end of file diff --git a/src/refactor/rename_variable.rs b/src/refactor/rename_variable.rs new file mode 100644 index 0000000..37f5c9a --- /dev/null +++ b/src/refactor/rename_variable.rs @@ -0,0 +1,120 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use syntax::ast::NodeId;use super::{RefactorType, Response}; + +use strings::src_rope::Rope; + +use analysis::AnalysisData; +use compiler; +use refactor; + +// Renames a variable (or variable-like construct). +// This includes constants, fields, and function parameters. +pub fn rename_variable(input_file: &str, + analyzed_data: &AnalysisData, + new_name: &str, + rename_var: &str) + -> Result, Response> { + let dec_map = &analyzed_data.var_map; + let ref_map = &analyzed_data.var_ref_map; + + let mut filename = String::from(input_file); + if let Some(decl) = dec_map.get(rename_var) { + if let Some(file) = decl.get("file_name") { + // FIXME: what's the point of this? We never use this value... + filename = file.clone(); + } + } + + // Check if renaming will cause conflicts + let node: NodeId = rename_var.parse().unwrap(); + + match compiler::run_resolution(String::from(input_file), None, + None, RefactorType::Variable, String::from(new_name), node, false) + { + Ok(()) => { + debug!("GOOD"); + }, + Err(_) => { debug!("BAD"); return Err(Response::Conflict); } + } + match dec_map.get(rename_var) { + Some(x) => { + for (_, value) in dec_map.iter() { + let name = value.get("name").unwrap(); + if x.get("scopeid") == value.get("scopeid") && + name == &new_name { + // Conflict present: + // May still be ok if there is no references to it + // However, standalone blocks won't be detected + macros + // Will also restrict if reference is on same line as renaming + + if let Some(references) = ref_map.get(rename_var) { + for map in references.iter() { + let filename = map.get("file_name").unwrap(); + + let mut file = match File::open(&filename) { + Err(why) => panic!("couldn't open file {}", why), + Ok(file) => file, + }; + let mut file_str = String::new(); + let _ = file.read_to_string(&mut file_str); + let file_str = &file_str[..]; + let mut ropes: Vec = file_str.lines().map(|x| Rope::from_string(String::from(x))).collect(); + let file_col: usize = map.get("file_col").unwrap().parse().unwrap(); + let file_line: usize = map.get("file_line").unwrap().parse().unwrap(); + let file_col_end: usize = map.get("file_col_end").unwrap().parse().unwrap(); + let file_line_end: usize = map.get("file_line_end").unwrap().parse().unwrap(); + + //let _ = writeln!(&mut stderr(), "{} {} {} {}", file_col, file_line, file_col_end, file_line_end); + refactor::rename(&mut ropes, file_col, file_line, file_col_end, file_line_end, new_name); + let mut answer = String::new(); + let mut count = ropes.len(); + for rope in &ropes { + answer.push_str(&rope.to_string()); + if count > 1 { + answer.push_str("\n"); + count -= 1; + } + } + + match compiler::run_resolution(String::from(input_file), Some(vec![(String::from(filename.clone()), answer)]), + None, RefactorType::Variable, String::from(new_name), + node, true) { + Ok(()) => { + debug!("Unexpected success!"); + // Check for conflicts + return Err(Response::Conflict); + }, + Err(_) => { debug!("Expected failure!");} + } + } + } + + /*let id = value.get("id").unwrap(); + let line_no: i32 = value.get("file_line").unwrap().parse().unwrap(); + if let Some(refs) = ref_map.get(id) { + for record in refs.iter() { + let line: i32 = record.get("file_line").unwrap().parse().unwrap(); + if line >= line_no { + // Affected reference + return Err(Response::Conflict); //input.to_string(); + } + } + }*/ + } + } + }, + _ => { return Err(Response::Conflict); } //input.to_string(); } + } + + let output = refactor::rename_dec_and_ref(new_name, rename_var, dec_map, ref_map); + + try!(compiler::check_reduced_graph(String::from(input_file), + output.iter().map(|(x,y)| + (x.clone(), y.clone())).collect(), + String::from(new_name), node)); + + Ok(output) +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..a3c95fb --- /dev/null +++ b/src/util.rs @@ -0,0 +1,69 @@ +use std::collections::HashMap; +use std::io::{self, Write}; +use analysis::AnalysisData; + +// Find the id associated with the row and column given +// (or a -1 wildcard is given and any with a matching name will be returned). +// TODO more efficient, perhaps better indexed and given type of node as arg +pub fn identify_id(input_filename: &str, + analyzed_data: &AnalysisData, + rename_var: &str, + row: i32, + col: i32, + file: Option<&str>) + -> String { + let _ = writeln!(&mut io::stderr(), "{} {} {}", rename_var, row, col); + for (key, value) in &analyzed_data.var_map { + if check_match(rename_var, input_filename, row, col, value, file) { + return key.clone(); + } + } + + for (key, value) in &analyzed_data.type_map { + if check_match(rename_var, input_filename, row, col, value, file) { + return key.clone(); + } + } + + for (key, value) in &analyzed_data.func_map { + if check_match(rename_var, input_filename, row, col, value, file) { + return key.clone(); + } + } + + "".to_string() +} + +fn check_match(name: &str, + _input_filename: &str, + row: i32, + col: i32, + record: &HashMap, + file: Option<&str>) + -> bool { + + let c: i32 = record.get("file_col").unwrap().parse().unwrap(); + let r: i32 = record.get("file_line").unwrap().parse().unwrap(); + let r_end: i32 = record.get("file_line_end").unwrap().parse().unwrap(); + let c_end: i32 = record.get("file_col_end").unwrap().parse().unwrap(); + let filename = record.get("file_name").unwrap(); + let n = record.get("name").unwrap(); + + if &name == n && (!file.is_some() || filename == file.unwrap()) { + if !(row < 0) { + if row >= r && row <= r_end { + if !(col < 0) { + if col >= c && col < c_end { + return true; + } + } else { + return true; + } + } + } else { + return true; + } + } + + false +} diff --git a/tests/lib.rs b/tests/lib.rs index f4e4e7c..1e99ae9 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -2,8 +2,8 @@ extern crate refactor; use std::fs::File; -use std::io::prelude::*; -use refactor::refactor::Response; +use std::io::Read; +use refactor::{AnalysisData, Response}; fn read_to_string(filename: &str) -> String { let mut file = match File::open(filename) { @@ -12,13 +12,13 @@ fn read_to_string(filename: &str) -> String { }; let mut output = String::new(); - let _ = file.read_to_string(&mut output); + file.read_to_string(&mut output).unwrap(); return output; } -fn read_analysis(filename: &str) -> refactor::refactor::AnalysisData { - refactor::refactor::init(&read_to_string(filename)) +fn read_analysis(filename: &str) -> AnalysisData { + AnalysisData::new(&read_to_string(filename)) } #[test] @@ -27,7 +27,7 @@ fn working_variable_1() { let output = read_to_string("tests/variable/working_rename_1_out.rs"); let analysis = read_analysis("tests/variable/basic_rename.csv"); - match refactor::refactor::rename_variable(&"tests/variable/basic_rename.rs", &analysis, "hello", "9") { + match refactor::rename_variable(&"tests/variable/basic_rename.rs", &analysis, "hello", "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -39,7 +39,7 @@ fn working_variable_2() { let output = read_to_string("tests/variable/working_rename_2_out.rs"); let analysis = read_analysis("tests/variable/basic_rename.csv"); - match refactor::refactor::rename_variable(&"tests/variable/basic_rename.rs", &analysis, "hello", "17") { + match refactor::rename_variable(&"tests/variable/basic_rename.rs", &analysis, "hello", "17") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -51,7 +51,7 @@ fn working_variable_3() { let output = read_to_string("tests/variable/alex_var_test_out.rs"); let analysis = read_analysis("tests/variable/alex_var_test.csv"); - match refactor::refactor::rename_variable(&"tests/variable/alex_var_test.rs", &analysis, "bar", "14") { + match refactor::rename_variable(&"tests/variable/alex_var_test.rs", &analysis, "bar", "14") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -63,7 +63,7 @@ fn working_variable_4() { let output = read_to_string("tests/variable/alex_var_test_out2.rs"); let analysis = read_analysis("tests/variable/alex_var_test.csv"); - match refactor::refactor::rename_variable(&"tests/variable/alex_var_test.rs", &analysis, "bar", "4") { + match refactor::rename_variable(&"tests/variable/alex_var_test.rs", &analysis, "bar", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -75,7 +75,7 @@ fn working_variable_5() { let output = read_to_string("tests/variable/const_rename_out.rs"); let analysis = read_analysis("tests/variable/const_rename.csv"); - match refactor::refactor::rename_variable(&"tests/variable/const_rename.rs", &analysis, "BAZ", "8") { + match refactor::rename_variable(&"tests/variable/const_rename.rs", &analysis, "BAZ", "8") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -87,7 +87,7 @@ fn working_variable_6() { let output = read_to_string("tests/variable/working_fn_local_out.rs"); let analysis = read_analysis("tests/variable/working_fn_local.csv"); - match refactor::refactor::rename_variable(&"tests/variable/working_fn_local.rs", &analysis, "Foo", "9") { + match refactor::rename_variable(&"tests/variable/working_fn_local.rs", &analysis, "Foo", "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -99,7 +99,7 @@ fn working_variable_7() { let output = read_to_string("tests/variable/working_nested_out.rs"); let analysis = read_analysis("tests/variable/working_nested.csv"); - match refactor::refactor::rename_variable(&"tests/variable/working_nested.rs", &analysis, "b", "16") { + match refactor::rename_variable(&"tests/variable/working_nested.rs", &analysis, "b", "16") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -111,7 +111,7 @@ fn working_variable_8() { let output = read_to_string("tests/variable/working_tuple_let_out.rs"); let analysis = read_analysis("tests/variable/working_tuple_let.csv"); - match refactor::refactor::rename_variable(file, &analysis, "x", "10") { + match refactor::rename_variable(file, &analysis, "x", "10") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -123,7 +123,7 @@ fn working_variable_9() { let output = read_to_string("tests/variable/working_mut_tuple_let_out.rs"); let analysis = read_analysis("tests/variable/working_mut_tuple_let.csv"); - match refactor::refactor::rename_variable(file, &analysis, "x", "10") { + match refactor::rename_variable(file, &analysis, "x", "10") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -135,7 +135,7 @@ fn working_variable_10() { let output = read_to_string("tests/variable/working_mut_tuple_let2_out.rs"); let analysis = read_analysis("tests/variable/working_mut_tuple_let2.csv"); - match refactor::refactor::rename_variable(file, &analysis, "x", "11") { + match refactor::rename_variable(file, &analysis, "x", "11") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -147,7 +147,7 @@ fn working_variable_11() { let output = read_to_string("tests/variable/working_mut_tuple_let3_out.rs"); let analysis = read_analysis("tests/variable/working_mut_tuple_let3.csv"); - match refactor::refactor::rename_variable(file, &analysis, "x", "11") { + match refactor::rename_variable(file, &analysis, "x", "11") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -159,7 +159,7 @@ fn working_variable_12() { let output = read_to_string("tests/variable/conflict_var_use_mod_out.rs"); let analysis = read_analysis("tests/variable/conflict_var_use_mod.csv"); - match refactor::refactor::rename_variable(file, &analysis, "BIT3", "6") { + match refactor::rename_variable(file, &analysis, "BIT3", "6") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -170,7 +170,7 @@ fn prevented_variable_1() { let file = "tests/variable/basic_rename.rs"; let analysis = read_analysis("tests/variable/basic_rename.csv"); - match refactor::refactor::rename_variable(&file, &analysis, "j", "36") { + match refactor::rename_variable(&file, &analysis, "j", "36") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -181,7 +181,7 @@ fn prevented_variable_2() { let file = "tests/variable/basic_rename.rs"; let analysis = read_analysis("tests/variable/basic_rename.csv"); - match refactor::refactor::rename_variable(&file, &analysis, "x", "36") { + match refactor::rename_variable(&file, &analysis, "x", "36") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -192,7 +192,7 @@ fn prevented_variable_3() { let file = "tests/variable/override.rs"; let analysis = read_analysis("tests/variable/override.csv"); - match refactor::refactor::rename_variable(&file, &analysis, "v", "9") { + match refactor::rename_variable(&file, &analysis, "v", "9") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -202,7 +202,7 @@ fn prevented_variable_3() { fn prevented_variable_4() { let file = "tests/variable/name_conflict_method.rs"; let analysis = read_analysis("tests/variable/name_conflict_method.csv"); - match refactor::refactor::rename_variable(file, &analysis, "foo", "12") { + match refactor::rename_variable(file, &analysis, "foo", "12") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -212,7 +212,7 @@ fn prevented_variable_4() { fn prevented_variable_5() { let file = "tests/variable/name_conflict_type.rs"; let analysis = read_analysis("tests/variable/name_conflict_type.csv"); - match refactor::refactor::rename_variable(file, &analysis, "Foo", "12") { + match refactor::rename_variable(file, &analysis, "Foo", "12") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -222,7 +222,7 @@ fn prevented_variable_5() { fn prevented_variable_6() { let file = "tests/variable/name_conflict_type_local.rs"; let analysis = read_analysis("tests/variable/name_conflict_type_local.csv"); - match refactor::refactor::rename_variable(file, &analysis, "Foo", "13") { + match refactor::rename_variable(file, &analysis, "Foo", "13") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -232,7 +232,7 @@ fn prevented_variable_6() { fn prevented_variable_7() { let file = "tests/variable/name_conflict_type_local2.rs"; let analysis = read_analysis("tests/variable/name_conflict_type_local2.csv"); - match refactor::refactor::rename_variable(file, &analysis, "Foo", "9") { + match refactor::rename_variable(file, &analysis, "Foo", "9") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -242,7 +242,7 @@ fn prevented_variable_7() { fn prevented_variable_8() { let file = "tests/variable/name_conflict_method_local.rs"; let analysis = read_analysis("tests/variable/name_conflict_method_local.csv"); - match refactor::refactor::rename_variable(file, &analysis, "foo", "13") { + match refactor::rename_variable(file, &analysis, "foo", "13") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -252,7 +252,7 @@ fn prevented_variable_8() { fn prevented_variable_9() { let file = "tests/variable/name_conflict_method_local2.rs"; let analysis = read_analysis("tests/variable/name_conflict_method_local2.csv"); - match refactor::refactor::rename_variable(file, &analysis, "Foo", "9") { + match refactor::rename_variable(file, &analysis, "Foo", "9") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -273,7 +273,7 @@ fn prevented_variable_9() { fn prevented_variable_10() { let file = "tests/variable/name_conflict_global.rs"; let analysis = read_analysis("tests/variable/name_conflict_global.csv"); - match refactor::refactor::rename_variable(file, &analysis, "FOO", "12") { + match refactor::rename_variable(file, &analysis, "FOO", "12") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -283,7 +283,7 @@ fn prevented_variable_10() { fn prevented_variable_11() { let file = "tests/variable/name_conflict_type_global.rs"; let analysis = read_analysis("tests/variable/name_conflict_type_global.csv"); - match refactor::refactor::rename_variable(file, &analysis, "Foo", "7") { + match refactor::rename_variable(file, &analysis, "Foo", "7") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -293,7 +293,7 @@ fn prevented_variable_11() { fn prevented_variable_12() { let file = "tests/variable/name_conflict_method_global.rs"; let analysis = read_analysis("tests/variable/name_conflict_method_global.csv"); - match refactor::refactor::rename_variable(file, &analysis, "foo", "4") { + match refactor::rename_variable(file, &analysis, "foo", "4") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -306,7 +306,7 @@ fn prevented_variable_13() { // => Point {foo, y} = Point{x:1, x:2} let file = "tests/variable/destructure_conflict.rs"; let analysis = read_analysis("tests/variable/destructure_conflict.csv"); - match refactor::refactor::rename_variable(file, &analysis, "bar", "16") { + match refactor::rename_variable(file, &analysis, "bar", "16") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -316,7 +316,7 @@ fn prevented_variable_13() { fn prevented_variable_14() { let file = "tests/variable/conflict_var_use_mod.rs"; let analysis = read_analysis("tests/variable/conflict_var_use_mod.csv"); - match refactor::refactor::rename_variable(file, &analysis, "BIT2", "6") { + match refactor::rename_variable(file, &analysis, "BIT2", "6") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -326,7 +326,7 @@ fn prevented_variable_14() { fn prevented_variable_15() { let file = "tests/variable/conflict_var_use_mod.rs"; let analysis = read_analysis("tests/variable/conflict_var_use_mod.csv"); - match refactor::refactor::rename_variable(file, &analysis, "BIT1", "11") { + match refactor::rename_variable(file, &analysis, "BIT1", "11") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -337,7 +337,7 @@ fn working_argument_1() { let file = "tests/variable/fn_args_1.rs"; let output = read_to_string("tests/variable/fn_args_1_out.rs"); let analysis = read_analysis("tests/variable/fn_args_1.csv"); - match refactor::refactor::rename_variable(file, &analysis, "z", "6") { + match refactor::rename_variable(file, &analysis, "z", "6") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -348,7 +348,7 @@ fn working_argument_2() { let file = "tests/variable/fn_args_2.rs"; let output = read_to_string("tests/variable/fn_args_2_1_out.rs"); let analysis = read_analysis("tests/variable/fn_args_2.csv"); - match refactor::refactor::rename_variable(file, &analysis, "z", "10") { + match refactor::rename_variable(file, &analysis, "z", "10") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -359,7 +359,7 @@ fn working_argument_3() { let file = "tests/variable/fn_args_2.rs"; let output = read_to_string("tests/variable/fn_args_2_2_out.rs"); let analysis = read_analysis("tests/variable/fn_args_2.csv"); - match refactor::refactor::rename_variable(file, &analysis, "z", "15") { + match refactor::rename_variable(file, &analysis, "z", "15") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -369,7 +369,7 @@ fn working_argument_3() { fn prevented_argument_1() { let file = "tests/variable/fn_args_1.rs"; let analysis = read_analysis("tests/variable/fn_args_1.csv"); - match refactor::refactor::rename_variable(file, &analysis, "c", "6") { + match refactor::rename_variable(file, &analysis, "c", "6") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -379,7 +379,7 @@ fn prevented_argument_1() { fn prevented_argument_2() { let file = "tests/variable/fn_args_1.rs"; let analysis = read_analysis("tests/variable/fn_args_1.csv"); - match refactor::refactor::rename_variable(file, &analysis, "foo", "6") { + match refactor::rename_variable(file, &analysis, "foo", "6") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -391,7 +391,7 @@ fn working_struct_1() { let output = read_to_string("tests/type/working_struct_1_out.rs"); let analysis = read_analysis("tests/type/basic_struct.csv"); - match refactor::refactor::rename_type(&"tests/type/basic_struct.rs", &analysis, "Pointer", "4") { + match refactor::rename_type(&"tests/type/basic_struct.rs", &analysis, "Pointer", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -404,7 +404,7 @@ fn working_struct_2() { let output = read_to_string("tests/type/working_struct_1_out.rs"); let analysis = read_analysis("tests/type/scoped_struct.csv"); - match refactor::refactor::rename_type(&"tests/type/basic_struct.rs", &analysis, "Pointer", "4") { + match refactor::rename_type(&"tests/type/basic_struct.rs", &analysis, "Pointer", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -417,7 +417,7 @@ fn working_struct_3() { let output = read_to_string("tests/type/tuple_struct_out.rs"); let analysis = read_analysis("tests/type/tuple_struct.csv"); - match refactor::refactor::rename_type(&file, &analysis, "Pointer", "4") { + match refactor::rename_type(&file, &analysis, "Pointer", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -429,7 +429,7 @@ fn working_enum_1() { let output = read_to_string("tests/type/working_enum_1_out.rs"); let analysis = read_analysis("tests/type/basic_enum.csv"); - match refactor::refactor::rename_type(&"tests/type/basic_enum.rs", &analysis, "YesNo", "4") { + match refactor::rename_type(&"tests/type/basic_enum.rs", &analysis, "YesNo", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -441,7 +441,7 @@ fn working_enum_2() { let output = read_to_string("tests/type/working_enum_2_out.rs"); let analysis = read_analysis("tests/type/modref_enum.csv"); - match refactor::refactor::rename_type(&"tests/type/modref_enum.rs", &analysis, "YesNo", "7") { + match refactor::rename_type(&"tests/type/modref_enum.rs", &analysis, "YesNo", "7") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -452,7 +452,7 @@ fn prevented_struct_1() { let file = "tests/type/conflict_struct.rs"; let analysis = read_analysis("tests/type/conflict_struct.csv"); - match refactor::refactor::rename_type(&file, &analysis, "P", "4") { + match refactor::rename_type(&file, &analysis, "P", "4") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -463,7 +463,7 @@ fn prevented_struct_2() { let file = "tests/type/conflict_mod_struct.rs"; let analysis = read_analysis("tests/type/conflict_mod_struct.csv"); - match refactor::refactor::rename_type(&file, &analysis, "B", "6") { + match refactor::rename_type(&file, &analysis, "B", "6") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -474,7 +474,7 @@ fn prevented_struct_3() { let file = "tests/type/conflict_use_mod_struct.rs"; let analysis = read_analysis("tests/type/conflict_use_mod_struct.csv"); - match refactor::refactor::rename_type(&file, &analysis, "B", "6") { + match refactor::rename_type(&file, &analysis, "B", "6") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -486,7 +486,7 @@ fn working_method_1() { let output = read_to_string("tests/function/working_method_1_out.rs"); let analysis = read_analysis("tests/function/basic_default_method.csv"); - match refactor::refactor::rename_function(&file, &analysis, "func", "5") { + match refactor::rename_function(&file, &analysis, "func", "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -498,7 +498,7 @@ fn working_method_2() { let output = read_to_string("tests/function/working_method_2_out.rs"); let analysis = read_analysis("tests/function/impl_override_method.csv"); - match refactor::refactor::rename_function(&file, &analysis, "func", "5") { + match refactor::rename_function(&file, &analysis, "func", "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -510,7 +510,7 @@ fn working_method_3() { let output = read_to_string("tests/function/alex_override_method_out2.rs"); let analysis = read_analysis("tests/function/alex_override_method.csv"); - match refactor::refactor::rename_function(&file, &analysis, "grue", "74") { + match refactor::rename_function(&file, &analysis, "grue", "74") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -521,7 +521,7 @@ fn not_working_method_1() { let file = "tests/function/alex_override_method.rs"; let analysis = read_analysis("tests/function/alex_override_method.csv"); - match refactor::refactor::rename_function(&file, &analysis, "foo", "74") { + match refactor::rename_function(&file, &analysis, "foo", "74") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -533,7 +533,7 @@ fn working_fn_1() { let output = read_to_string("tests/function/basic_function_out.rs"); let analysis = read_analysis("tests/function/basic_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "4") { + match refactor::rename_function(&file, &analysis, "bar", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -545,7 +545,7 @@ fn working_fn_2() { let output = read_to_string("tests/function/basic_module_function_out.rs"); let analysis = read_analysis("tests/function/basic_module_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "6") { + match refactor::rename_function(&file, &analysis, "bar", "6") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -557,7 +557,7 @@ fn working_fn_3() { let output = read_to_string("tests/function/basic_generic_function_out.rs"); let analysis = read_analysis("tests/function/basic_generic_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "5") { + match refactor::rename_function(&file, &analysis, "bar", "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -569,7 +569,7 @@ fn working_fn_4() { let output = read_to_string("tests/function/basic_trait_function_out.rs"); let analysis = read_analysis("tests/function/basic_trait_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "5") { + match refactor::rename_function(&file, &analysis, "bar", "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -581,7 +581,7 @@ fn working_fn_5() { let output = read_to_string("tests/function/basic_use_function_out.rs"); let analysis = read_analysis("tests/function/basic_use_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "6") { + match refactor::rename_function(&file, &analysis, "bar", "6") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -593,7 +593,7 @@ fn working_fn_6() { let output = read_to_string("tests/function/extern_function_out.rs"); let analysis = read_analysis("tests/function/extern_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "4") { + match refactor::rename_function(&file, &analysis, "bar", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -605,7 +605,7 @@ fn working_fn_7() { let output = read_to_string("tests/function/extern_stdcall_function_out.rs"); let analysis = read_analysis("tests/function/extern_stdcall_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "4") { + match refactor::rename_function(&file, &analysis, "bar", "4") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -617,7 +617,7 @@ fn working_fn_8() { let output = read_to_string("tests/function/fn_local_mod_out.rs"); let analysis = read_analysis("tests/function/fn_local_mod.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "10") { + match refactor::rename_function(&file, &analysis, "bar", "10") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -629,7 +629,7 @@ fn working_fn_9() { let output = read_to_string("tests/function/fn_local_mod_after_out.rs"); let analysis = read_analysis("tests/function/fn_local_mod_after.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "13") { + match refactor::rename_function(&file, &analysis, "bar", "13") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -639,7 +639,7 @@ fn working_fn_9() { fn not_working_fn_1() { let file = "tests/function/basic_function.rs"; let analysis = read_analysis("tests/function/basic_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "main", "4") { + match refactor::rename_function(&file, &analysis, "main", "4") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -649,7 +649,7 @@ fn not_working_fn_1() { fn not_working_fn_2() { let file = "tests/function/conflict_module_function.rs"; let analysis = read_analysis("tests/function/conflict_module_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "foo", "9") { + match refactor::rename_function(&file, &analysis, "foo", "9") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -659,7 +659,7 @@ fn not_working_fn_2() { fn not_working_fn_3() { let file = "tests/function/conflict_module_function.rs"; let analysis = read_analysis("tests/function/conflict_module_function.csv"); - match refactor::refactor::rename_function(&file, &analysis, "bar", "6") { + match refactor::rename_function(&file, &analysis, "bar", "6") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -669,7 +669,7 @@ fn not_working_fn_3() { fn not_working_fn_4() { let file = "tests/function/conflict_fn_with_var.rs"; let analysis = read_analysis("tests/function/conflict_fn_with_var.csv"); - match refactor::refactor::rename_function(&file, &analysis, "a", "8") { + match refactor::rename_function(&file, &analysis, "a", "8") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -684,7 +684,7 @@ fn multi_file_1() { let output2 = read_to_string("tests/multi-file/simple_function_1/foo_out.rs"); let analysis = read_analysis("tests/multi-file/simple_function_1/main.csv"); - match refactor::refactor::rename_function(&file, &analysis, "boo", "6") { + match refactor::rename_function(&file, &analysis, "boo", "6") { Ok(x) => { assert_eq!(output1.trim(), x.get(changed1).unwrap().trim()); assert_eq!(output2.trim(), x.get(changed2).unwrap().trim()); @@ -703,7 +703,7 @@ fn multi_file_2() { let output2 = read_to_string("tests/multi-file/simple_function_2/foo/mod_out.rs"); let analysis = read_analysis("tests/multi-file/simple_function_2/main.csv"); - match refactor::refactor::rename_function(&file, &analysis, "boo", "6") { + match refactor::rename_function(&file, &analysis, "boo", "6") { Ok(x) => { assert_eq!(output1.trim(), x.get(changed1).unwrap().trim()); assert_eq!(output2.trim(), x.get(changed2).unwrap().trim()); @@ -719,7 +719,7 @@ fn working_inline_1() { let output = read_to_string("tests/inline/inline_single_out.rs"); let analysis = read_analysis("tests/inline/inline_single.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -731,7 +731,7 @@ fn working_inline_2() { let output = read_to_string("tests/inline/inline3_out.rs"); let analysis = read_analysis("tests/inline/inline3.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -743,7 +743,7 @@ fn working_inline_3() { let output = read_to_string("tests/inline/inline4_out.rs"); let analysis = read_analysis("tests/inline/inline4.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -755,7 +755,7 @@ fn working_inline_4() { let output = read_to_string("tests/inline/inline5_out.rs"); let analysis = read_analysis("tests/inline/inline5.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -767,7 +767,7 @@ fn working_inline_5() { let output = read_to_string("tests/inline/inline6_out.rs"); let analysis = read_analysis("tests/inline/inline6.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -779,7 +779,7 @@ fn working_inline_6() { let output = read_to_string("tests/inline/inline7_out.rs"); let analysis = read_analysis("tests/inline/inline7.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -791,7 +791,7 @@ fn working_inline_7() { let output = read_to_string("tests/inline/inline8_out.rs"); let analysis = read_analysis("tests/inline/inline8.csv"); - match refactor::refactor::inline_local(&file, &analysis, "9") { + match refactor::inline_local(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -805,7 +805,7 @@ fn working_inline_8() { let output = read_to_string("tests/multi-file/simple_inline_1/foo_out.rs"); let analysis = read_analysis("tests/multi-file/simple_inline_1/main.csv"); - match refactor::refactor::inline_local(&file, &analysis, "11") { + match refactor::inline_local(&file, &analysis, "11") { Ok(x) => { assert_eq!(output.trim(), x.get(changed).unwrap().trim()); }, @@ -820,7 +820,7 @@ fn working_field_1() { let output = read_to_string("tests/field/simple_field_out.rs"); let analysis = read_analysis("tests/field/simple_field.csv"); - match refactor::refactor::rename_variable(&file, &analysis, "z", "5") { + match refactor::rename_variable(&file, &analysis, "z", "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -831,7 +831,7 @@ fn prevented_field_1() { let file = "tests/field/simple_field.rs"; let analysis = read_analysis("tests/field/simple_field.csv"); - match refactor::refactor::rename_variable(&file, &analysis, "y", "5") { + match refactor::rename_variable(&file, &analysis, "y", "5") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -843,7 +843,7 @@ fn working_reify_1() { let output = read_to_string("tests/lifetime/reify_single_in_out.rs"); let analysis = read_analysis("tests/lifetime/reify_single_in.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "5") { + match refactor::restore_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -855,7 +855,7 @@ fn working_reify_2() { let output = read_to_string("tests/lifetime/reify_single_in_ret_out.rs"); let analysis = read_analysis("tests/lifetime/reify_single_in_ret.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "5") { + match refactor::restore_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -867,7 +867,7 @@ fn working_reify_3() { let output = read_to_string("tests/lifetime/reify_single_in_anon_ret_out.rs"); let analysis = read_analysis("tests/lifetime/reify_single_in_anon_ret.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "5") { + match refactor::restore_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -879,7 +879,7 @@ fn working_reify_4() { let output = read_to_string("tests/lifetime/reify_multi_in_out.rs"); let analysis = read_analysis("tests/lifetime/reify_multi_in.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "5") { + match refactor::restore_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -891,7 +891,7 @@ fn working_reify_5() { let output = read_to_string("tests/lifetime/reify_multi_named_in_out.rs"); let analysis = read_analysis("tests/lifetime/reify_multi_named_in.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "5") { + match refactor::restore_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -903,7 +903,7 @@ fn working_reify_6() { let output = read_to_string("tests/lifetime/reify_multi_named_self_ret_out.rs"); let analysis = read_analysis("tests/lifetime/reify_multi_named_self_ret.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "9") { + match refactor::restore_fn_lifetime(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -915,7 +915,7 @@ fn working_reify_7() { let output = read_to_string("tests/lifetime/reify_multi_self_ret_out.rs"); let analysis = read_analysis("tests/lifetime/reify_multi_self_ret.csv"); - match refactor::refactor::restore_fn_lifetime(&file, &analysis, "9") { + match refactor::restore_fn_lifetime(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -927,7 +927,7 @@ fn working_elide_1() { let output = read_to_string("tests/lifetime/elide_single_in_out.rs"); let analysis = read_analysis("tests/lifetime/elide_single_in.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "5") { + match refactor::elide_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -939,7 +939,7 @@ fn working_elide_2() { let file = "tests/lifetime/elide_single_anon_static_ret.rs"; let analysis = read_analysis("tests/lifetime/elide_single_anon_static_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "5") { + match refactor::elide_fn_lifetime(&file, &analysis, "5") { Ok(_) => assert!(false), Err(x) => assert_eq!(Response::Conflict, x) } @@ -951,7 +951,7 @@ fn working_elide_3() { let output = read_to_string("tests/lifetime/elide_single_in_anon_ret_out.rs"); let analysis = read_analysis("tests/lifetime/elide_single_in_anon_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "5") { + match refactor::elide_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -963,7 +963,7 @@ fn working_elide_4() { let output = read_to_string("tests/lifetime/elide_single_in_ret_out.rs"); let analysis = read_analysis("tests/lifetime/elide_single_in_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "5") { + match refactor::elide_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -977,7 +977,7 @@ fn working_elide_5() { let output = read_to_string("tests/lifetime/elide_single_static_ret_out.rs"); let analysis = read_analysis("tests/lifetime/elide_single_static_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "5") { + match refactor::elide_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -989,7 +989,7 @@ fn working_elide_6() { let output = read_to_string("tests/lifetime/elide_multi_in_out.rs"); let analysis = read_analysis("tests/lifetime/elide_multi_in.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "5") { + match refactor::elide_fn_lifetime(&file, &analysis, "5") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -1001,7 +1001,7 @@ fn working_elide_7() { let output = read_to_string("tests/lifetime/elide_multi_named_self_ret_out.rs"); let analysis = read_analysis("tests/lifetime/elide_multi_named_self_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "9") { + match refactor::elide_fn_lifetime(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -1013,7 +1013,7 @@ fn working_elide_8() { let output = read_to_string("tests/lifetime/elide_multi_anon_self_ret_out.rs"); let analysis = read_analysis("tests/lifetime/elide_multi_anon_self_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "9") { + match refactor::elide_fn_lifetime(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) } @@ -1028,7 +1028,7 @@ fn working_elide_9() { let output = read_to_string("tests/lifetime/elide_multi_static_self_ret_out.rs"); let analysis = read_analysis("tests/lifetime/elide_multi_static_self_ret.csv"); - match refactor::refactor::elide_fn_lifetime(&file, &analysis, "9") { + match refactor::elide_fn_lifetime(&file, &analysis, "9") { Ok(x) => assert_eq!(output.trim(), x.get(file).unwrap().trim()), Err(_) => assert!(false) }