save-analysis: emit names of items that a glob import actually imports.

There is also some work here to make resolve a bit more stable - it no longer overwrites a specific import with a glob import.

[breaking-change]

Import shadowing of single/list imports by globs is now forbidden. An interesting case is where a glob import imports a re-export (`pub use`) of a single import. This still counts as a single import for the purposes of shadowing .You can usually fix any bustage by re-ordering such imports. A single import may still shadow (override) a glob import or the prelude.
This commit is contained in:
Nick Cameron 2014-11-23 22:29:41 +13:00
parent bd3cf4c05f
commit df0c6d9385
11 changed files with 270 additions and 63 deletions

View File

@ -146,6 +146,13 @@ pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
tcx)
}
pub fn get_trait_name(cstore: &cstore::CStore, def: ast::DefId) -> ast::Name {
let cdata = cstore.get_crate_data(def.krate);
decoder::get_trait_name(cstore.intr.clone(),
&*cdata,
def.node)
}
pub fn get_trait_item_name_and_kind(cstore: &cstore::CStore, def: ast::DefId)
-> (ast::Name, def::TraitItemKind) {
let cdata = cstore.get_crate_data(def.krate);

View File

@ -781,6 +781,14 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
impl_items
}
pub fn get_trait_name(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId)
-> ast::Name {
let doc = lookup_item(id, cdata.data());
item_name(&*intr, doc)
}
pub fn get_trait_item_name_and_kind(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId)

View File

@ -105,6 +105,7 @@ pub struct CrateAnalysis<'tcx> {
pub ty_cx: ty::ctxt<'tcx>,
pub reachable: NodeSet,
pub name: String,
pub glob_map: Option<middle::resolve::GlobMap>,
}
#[deriving(Copy, PartialEq, Eq, Hash)]

View File

@ -342,17 +342,24 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
let lang_items = time(time_passes, "language item collection", (), |_|
middle::lang_items::collect_language_items(krate, &sess));
let resolve::CrateMap {
let make_glob_map = match save_analysis(&sess) {
true => middle::resolve::MakeGlobMap::Yes,
false => middle::resolve::MakeGlobMap::No,
};
def_map,
freevars,
capture_mode_map,
export_map,
trait_map,
external_exports,
last_private_map
last_private_map,
glob_map,
} =
time(time_passes, "resolution", (),
|_| resolve::resolve_crate(&sess, &lang_items, krate));
|_| resolve::resolve_crate(&sess,
&lang_items,
krate,
make_glob_map));
// Discard MTWT tables that aren't required past resolution.
syntax::ext::mtwt::clear_tables();
@ -454,14 +461,19 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
public_items: public_items,
reachable: reachable_map,
name: name,
glob_map: glob_map,
}
}
fn save_analysis(sess: &Session) -> bool {
(sess.opts.debugging_opts & config::SAVE_ANALYSIS) != 0
}
pub fn phase_save_analysis(sess: &Session,
krate: &ast::Crate,
analysis: &ty::CrateAnalysis,
odir: &Option<Path>) {
if (sess.opts.debugging_opts & config::SAVE_ANALYSIS) == 0 {
if !save_analysis(sess) {
return;
}
time(sess.time_passes(), "save analysis", krate, |krate|

View File

@ -123,7 +123,7 @@ fn test_env<F>(source_string: &str,
// run just enough stuff to build a tcx:
let lang_items = lang_items::collect_language_items(krate, &sess);
let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
resolve::resolve_crate(&sess, &lang_items, krate);
resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
let region_map = region::resolve_crate(&sess, krate);
let stability_index = stability::Index::build(krate);

View File

@ -28,19 +28,19 @@ use syntax::ast::{ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::codemap::{Span, DUMMY_SP};
use syntax::visit::{mod, Visitor};
struct UnusedImportCheckVisitor<'a, 'b:'a> {
resolver: &'a mut Resolver<'b>
struct UnusedImportCheckVisitor<'a, 'b:'a, 'tcx:'b> {
resolver: &'a mut Resolver<'b, 'tcx>
}
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
impl<'a, 'b> Deref<Resolver<'b>> for UnusedImportCheckVisitor<'a, 'b> {
fn deref<'c>(&'c self) -> &'c Resolver<'b> {
impl<'a, 'b, 'tcx> Deref<Resolver<'b, 'tcx>> for UnusedImportCheckVisitor<'a, 'b, 'tcx:'b> {
fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> {
&*self.resolver
}
}
impl<'a, 'b> DerefMut<Resolver<'b>> for UnusedImportCheckVisitor<'a, 'b> {
fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
impl<'a, 'b, 'tcx> DerefMut<Resolver<'b, 'tcx>> for UnusedImportCheckVisitor<'a, 'b, 'tcx:'b> {
fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> {
&mut *self.resolver
}
}
@ -104,7 +104,7 @@ impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
}
}
impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> {
impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
fn visit_view_item(&mut self, vi: &ViewItem) {
// Ignore is_public import statements because there's no way to be sure
// whether they're used or not. Also ignore imports with a dummy span

View File

@ -82,6 +82,7 @@ use syntax::ast::{Variant, ViewItem, ViewItemExternCrate};
use syntax::ast::{ViewItemUse, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::ast::{Visibility};
use syntax::ast;
use syntax::ast_map;
use syntax::ast_util::{mod, PostExpansionMethod, local_def, walk_pat};
use syntax::attr::AttrMetaMethods;
use syntax::ext::mtwt;
@ -109,6 +110,10 @@ struct BindingInfo {
// Map from the name in a pattern to its binding mode.
type BindingMap = HashMap<Name, BindingInfo>;
// Map from the NodeId of a glob import to a list of items which are actually
// imported.
pub type GlobMap = HashMap<NodeId, HashSet<Name>>;
#[deriving(Copy, PartialEq)]
enum PatternBindingMode {
RefutableMode,
@ -168,7 +173,7 @@ enum NameDefinition {
ImportNameDefinition(Def, LastPrivate) //< The name identifies an import.
}
impl<'a, 'v> Visitor<'v> for Resolver<'a> {
impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
fn visit_item(&mut self, item: &Item) {
self.resolve_item(item);
}
@ -340,6 +345,16 @@ impl Rib {
}
}
/// Whether an import can be shadowed by another import.
#[deriving(Show,PartialEq,Clone)]
enum Shadowable {
Always,
/// Means that the recorded import obeys the glob shadowing rules, i.e., can
/// only be shadowed by another glob import.
Glob,
Never
}
/// One import directive.
struct ImportDirective {
module_path: Vec<Name>,
@ -347,7 +362,7 @@ struct ImportDirective {
span: Span,
id: NodeId,
is_public: bool, // see note in ImportResolution about how to use this
shadowable: bool,
shadowable: Shadowable,
}
impl ImportDirective {
@ -356,7 +371,7 @@ impl ImportDirective {
span: Span,
id: NodeId,
is_public: bool,
shadowable: bool)
shadowable: Shadowable)
-> ImportDirective {
ImportDirective {
module_path: module_path,
@ -374,13 +389,13 @@ impl ImportDirective {
struct Target {
target_module: Rc<Module>,
bindings: Rc<NameBindings>,
shadowable: bool,
shadowable: Shadowable,
}
impl Target {
fn new(target_module: Rc<Module>,
bindings: Rc<NameBindings>,
shadowable: bool)
shadowable: Shadowable)
-> Target {
Target {
target_module: target_module,
@ -442,6 +457,15 @@ impl ImportResolution {
ValueNS => self.value_id,
}
}
fn shadowable(&self, namespace: Namespace) -> Shadowable {
let target = self.target_for_namespace(namespace);
if target.is_none() {
return Shadowable::Always;
}
target.unwrap().shadowable
}
}
/// The link from a module up to its nearest parent node.
@ -842,9 +866,11 @@ fn namespace_error_to_string(ns: NamespaceError) -> &'static str {
}
/// The main resolver class.
struct Resolver<'a> {
struct Resolver<'a, 'tcx:'a> {
session: &'a Session,
ast_map: &'a ast_map::Map<'tcx>,
graph_root: NameBindings,
trait_item_map: FnvHashMap<(Name, DefId), TraitItemKind>,
@ -895,16 +921,21 @@ struct Resolver<'a> {
// so as to avoid printing duplicate errors
emit_errors: bool,
make_glob_map: bool,
// Maps imports to the names of items actually imported (this actually maps
// all imports, but only glob imports are actually interesting).
glob_map: GlobMap,
used_imports: HashSet<(NodeId, Namespace)>,
used_crates: HashSet<CrateNum>,
}
struct BuildReducedGraphVisitor<'a, 'b:'a> {
resolver: &'a mut Resolver<'b>,
struct BuildReducedGraphVisitor<'a, 'b:'a, 'tcx:'b> {
resolver: &'a mut Resolver<'b, 'tcx>,
parent: ReducedGraphParent
}
impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
fn visit_item(&mut self, item: &Item) {
let p = self.resolver.build_reduced_graph_for_item(item, self.parent.clone());
@ -939,6 +970,20 @@ impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
}
<<<<<<< HEAD:src/librustc_resolve/lib.rs
=======
struct UnusedImportCheckVisitor<'a, 'b:'a, 'tcx:'b> {
resolver: &'a mut Resolver<'b, 'tcx>
}
impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
fn visit_view_item(&mut self, vi: &ViewItem) {
self.resolver.check_for_item_unused_imports(vi);
visit::walk_view_item(self, vi);
}
}
>>>>>>> save-analysis: emit names of items that a glob import actually imports.:src/librustc/middle/resolve.rs
#[deriving(PartialEq)]
enum FallbackChecks {
Everything,
@ -946,8 +991,11 @@ enum FallbackChecks {
}
impl<'a> Resolver<'a> {
fn new(session: &'a Session, crate_span: Span) -> Resolver<'a> {
impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn new(session: &'a Session,
ast_map: &'a ast_map::Map<'tcx>,
crate_span: Span,
make_glob_map: MakeGlobMap) -> Resolver<'a, 'tcx> {
let graph_root = NameBindings::new();
graph_root.define_module(NoParentLink,
@ -962,6 +1010,8 @@ impl<'a> Resolver<'a> {
Resolver {
session: session,
ast_map: ast_map,
// The outermost module has def ID 0; this is not reflected in the
// AST.
@ -997,6 +1047,8 @@ impl<'a> Resolver<'a> {
last_private: NodeMap::new(),
emit_errors: true,
make_glob_map: make_glob_map == MakeGlobMap::Yes,
glob_map: HashMap::new(),
}
}
@ -1610,6 +1662,11 @@ impl<'a> Resolver<'a> {
attr.name() == token::get_name(
special_idents::prelude_import.name)
});
let shadowable = if shadowable {
Shadowable::Always
} else {
Shadowable::Never
};
match view_path.node {
ViewPathSimple(binding, ref full_path, id) => {
@ -1680,7 +1737,11 @@ impl<'a> Resolver<'a> {
view_path.span,
id,
is_public,
shadowable);
if shadowable == Shadowable::Never {
Shadowable::Glob
} else {
shadowable
});
}
}
}
@ -2131,7 +2192,7 @@ impl<'a> Resolver<'a> {
span: Span,
id: NodeId,
is_public: bool,
shadowable: bool) {
shadowable: Shadowable) {
module_.imports.borrow_mut().push(ImportDirective::new(module_path,
subclass,
span,
@ -2326,6 +2387,29 @@ impl<'a> Resolver<'a> {
}
}
#[inline]
fn record_import_use(&mut self, import_id: NodeId, name: Name) {
if !self.make_glob_map {
return;
}
if self.glob_map.contains_key(&import_id) {
self.glob_map[import_id].insert(name);
return;
}
let mut new_set = HashSet::new();
new_set.insert(name);
self.glob_map.insert(import_id, new_set);
}
fn get_trait_name(&self, did: DefId) -> Name {
if did.krate == LOCAL_CRATE {
self.ast_map.expect_item(did.node).ident.name
} else {
csearch::get_trait_name(&self.session.cstore, did)
}
}
/// Attempts to resolve the given import. The return value indicates
/// failure if we're certain the name does not exist, indeterminate if we
/// don't know whether the name exists at the moment due to other
@ -2338,8 +2422,7 @@ impl<'a> Resolver<'a> {
let mut resolution_result = Failed(None);
let module_path = &import_directive.module_path;
debug!("(resolving import for module) resolving import `{}::...` in \
`{}`",
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
self.names_to_string(module_path[]),
self.module_to_string(&*module_));
@ -2526,7 +2609,8 @@ impl<'a> Resolver<'a> {
fn get_binding(this: &mut Resolver,
import_resolution: &ImportResolution,
namespace: Namespace)
namespace: Namespace,
source: &Name)
-> NamespaceResult {
// Import resolutions must be declared with "pub"
@ -2550,6 +2634,7 @@ impl<'a> Resolver<'a> {
let id = import_resolution.id(namespace);
// track used imports and extern crates as well
this.used_imports.insert((id, namespace));
this.record_import_use(id, *source);
match target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => {
this.used_crates.insert(kid);
@ -2564,13 +2649,17 @@ impl<'a> Resolver<'a> {
// The name is an import which has been fully
// resolved. We can, therefore, just follow it.
if value_result.is_unknown() {
value_result = get_binding(self, import_resolution,
ValueNS);
value_result = get_binding(self,
import_resolution,
ValueNS,
&source);
value_used_reexport = import_resolution.is_public;
}
if type_result.is_unknown() {
type_result = get_binding(self, import_resolution,
TypeNS);
type_result = get_binding(self,
import_resolution,
TypeNS,
&source);
type_used_reexport = import_resolution.is_public;
}
@ -2752,7 +2841,7 @@ impl<'a> Resolver<'a> {
return Success(());
}
// Resolves a glob import. Note that this function cannot panic; it either
// Resolves a glob import. Note that this function cannot fail; it either
// succeeds or bails out (as importing * from an empty module or a module
// that exports nothing is valid).
fn resolve_glob_import(&mut self,
@ -2883,7 +2972,9 @@ impl<'a> Resolver<'a> {
let mut import_resolutions = module_.import_resolutions.borrow_mut();
let dest_import_resolution = match import_resolutions.entry(name) {
Occupied(entry) => entry.into_mut(),
Occupied(entry) => {
entry.into_mut()
}
Vacant(entry) => {
// Create a new import resolution from this child.
entry.set(ImportResolution::new(id, is_public))
@ -2899,19 +2990,33 @@ impl<'a> Resolver<'a> {
// Merge the child item into the import resolution.
if name_bindings.defined_in_namespace_with(ValueNS, IMPORTABLE | PUBLIC) {
debug!("(resolving glob import) ... for value target");
dest_import_resolution.value_target =
Some(Target::new(containing_module.clone(),
name_bindings.clone(),
import_directive.shadowable));
dest_import_resolution.value_id = id;
if dest_import_resolution.shadowable(ValueNS) == Shadowable::Never {
let msg = format!("a value named `{}` has already been imported \
in this module",
token::get_name(name).get());
self.session.span_err(import_directive.span, msg.as_slice());
} else {
dest_import_resolution.value_target =
Some(Target::new(containing_module.clone(),
name_bindings.clone(),
import_directive.shadowable));
dest_import_resolution.value_id = id;
}
}
if name_bindings.defined_in_namespace_with(TypeNS, IMPORTABLE | PUBLIC) {
debug!("(resolving glob import) ... for type target");
dest_import_resolution.type_target =
Some(Target::new(containing_module,
name_bindings.clone(),
import_directive.shadowable));
dest_import_resolution.type_id = id;
if dest_import_resolution.shadowable(TypeNS) == Shadowable::Never {
let msg = format!("a type named `{}` has already been imported \
in this module",
token::get_name(name).get());
self.session.span_err(import_directive.span, msg.as_slice());
} else {
dest_import_resolution.type_target =
Some(Target::new(containing_module,
name_bindings.clone(),
import_directive.shadowable));
dest_import_resolution.type_id = id;
}
}
dest_import_resolution.is_public = is_public;
@ -2933,7 +3038,7 @@ impl<'a> Resolver<'a> {
}
match *target {
Some(ref target) if !target.shadowable => {
Some(ref target) if target.shadowable != Shadowable::Always => {
let msg = format!("a {} named `{}` has already been imported \
in this module",
match namespace {
@ -2976,7 +3081,7 @@ impl<'a> Resolver<'a> {
.borrow()
.contains_key(&name) {
match import_resolution.type_target {
Some(ref target) if !target.shadowable => {
Some(ref target) if target.shadowable != Shadowable::Always => {
let msg = format!("import `{0}` conflicts with imported \
crate in this module \
(maybe you meant `use {0}::*`?)",
@ -2998,7 +3103,7 @@ impl<'a> Resolver<'a> {
};
match import_resolution.value_target {
Some(ref target) if !target.shadowable => {
Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref value) = *name_bindings.value_def.borrow() {
let msg = format!("import `{}` conflicts with value \
in this module",
@ -3014,7 +3119,7 @@ impl<'a> Resolver<'a> {
}
match import_resolution.type_target {
Some(ref target) if !target.shadowable => {
Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref ty) = *name_bindings.type_def.borrow() {
match ty.module_def {
None => {
@ -3347,7 +3452,7 @@ impl<'a> Resolver<'a> {
debug!("top name bindings succeeded");
return Success((Target::new(module_.clone(),
name_bindings.clone(),
false),
Shadowable::Never),
false));
}
Some(_) | None => { /* Not found; continue. */ }
@ -3369,9 +3474,11 @@ impl<'a> Resolver<'a> {
debug!("(resolving item in lexical scope) using \
import resolution");
// track used imports and extern crates as well
self.used_imports.insert((import_resolution.id(namespace), namespace));
let id = import_resolution.id(namespace);
self.used_imports.insert((id, namespace));
self.record_import_use(id, name);
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
self.used_crates.insert(kid);
self.used_crates.insert(kid);
}
return Success((target, false));
}
@ -3384,7 +3491,9 @@ impl<'a> Resolver<'a> {
let name_bindings =
Rc::new(Resolver::create_name_bindings_from_module(module));
debug!("lower name bindings succeeded");
return Success((Target::new(module_, name_bindings, false),
return Success((Target::new(module_,
name_bindings,
Shadowable::Never),
false));
}
}
@ -3608,7 +3717,7 @@ impl<'a> Resolver<'a> {
debug!("(resolving name in module) found node as child");
return Success((Target::new(module_.clone(),
name_bindings.clone(),
false),
Shadowable::Never),
false));
}
Some(_) | None => {
@ -3645,7 +3754,9 @@ impl<'a> Resolver<'a> {
debug!("(resolving name in module) resolved to \
import");
// track used imports and extern crates as well
self.used_imports.insert((import_resolution.id(namespace), namespace));
let id = import_resolution.id(namespace);
self.used_imports.insert((id, namespace));
self.record_import_use(id, name);
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
self.used_crates.insert(kid);
}
@ -3661,7 +3772,9 @@ impl<'a> Resolver<'a> {
if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
let name_bindings =
Rc::new(Resolver::create_name_bindings_from_module(module));
return Success((Target::new(module_, name_bindings, false),
return Success((Target::new(module_,
name_bindings,
Shadowable::Never),
false));
}
}
@ -5171,6 +5284,7 @@ impl<'a> Resolver<'a> {
let id = import_resolution.id(namespace);
// track imports and extern crates as well
self.used_imports.insert((id, namespace));
self.record_import_use(id, name);
match target.target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => {
self.used_crates.insert(kid);
@ -5859,7 +5973,10 @@ impl<'a> Resolver<'a> {
};
if self.trait_item_map.contains_key(&(name, did)) {
add_trait_info(&mut found_traits, did, name);
self.used_imports.insert((import.type_id, TypeNS));
let id = import.type_id;
self.used_imports.insert((id, TypeNS));
let trait_name = self.get_trait_name(did);
self.record_import_use(id, trait_name);
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id.get() {
self.used_crates.insert(kid);
}
@ -5993,14 +6110,23 @@ pub struct CrateMap {
pub trait_map: TraitMap,
pub external_exports: ExternalExports,
pub last_private_map: LastPrivateMap,
pub glob_map: Option<GlobMap>
}
#[deriving(PartialEq)]
pub enum MakeGlobMap {
Yes,
No
}
/// Entry point to crate resolution.
pub fn resolve_crate(session: &Session,
_: &LanguageItems,
krate: &Crate)
-> CrateMap {
let mut resolver = Resolver::new(session, krate.span);
pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
ast_map: &'a ast_map::Map<'tcx>,
_: &LanguageItems,
krate: &Crate,
make_glob_map: MakeGlobMap)
-> CrateMap {
let mut resolver = Resolver::new(session, ast_map, krate.span, make_glob_map);
resolver.build_reduced_graph(krate);
session.abort_if_errors();
@ -6024,5 +6150,10 @@ pub fn resolve_crate(session: &Session,
trait_map: resolver.trait_map,
external_exports: resolver.external_exports,
last_private_map: resolver.last_private,
glob_map: if resolver.make_glob_map {
Some(resolver.glob_map)
} else {
None
},
}
}

View File

@ -1197,7 +1197,28 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
self.cur_scope);
self.write_sub_paths_truncated(path);
}
ast::ViewPathGlob(ref path, _) => {
ast::ViewPathGlob(ref path, id) => {
// Make a comma-separated list of names of imported modules.
let mut name_string = String::new();
let glob_map = &self.analysis.glob_map;
let glob_map = glob_map.as_ref().unwrap();
if glob_map.contains_key(&id) {
let names = glob_map.index(&id);
for n in names.iter() {
if name_string.len() > 0 {
name_string.push_str(", ");
}
name_string.push_str(n.as_str());
}
}
let sub_span = self.span.sub_span_of_token(path.span,
token::BinOp(token::Star));
self.fmt.use_glob_str(path.span,
sub_span,
id,
name_string.as_slice(),
self.cur_scope);
self.write_sub_paths(path);
}
ast::ViewPathList(ref path, ref list, _) => {
@ -1482,6 +1503,7 @@ pub fn process_crate(sess: &Session,
return;
}
assert!(analysis.glob_map.is_some());
let cratename = match attr::find_crate_name(krate.attrs[]) {
Some(name) => name.get().to_string(),
None => {

View File

@ -74,6 +74,7 @@ pub enum Row {
Impl,
Module,
UseAlias,
UseGlob,
ExternCrate,
Inheritance,
MethodCall,
@ -125,6 +126,7 @@ impl<'a> FmtStrs<'a> {
UseAlias => ("use_alias",
vec!("id","refid","refidcrate","name","scopeid"),
true, true),
UseGlob => ("use_glob", vec!("id","value","scopeid"), true, true),
ExternCrate => ("extern_crate",
vec!("id","name","location","crate","scopeid"),
true, true),
@ -480,6 +482,18 @@ impl<'a> FmtStrs<'a> {
svec!(id, mod_node, mod_crate, name, parent));
}
pub fn use_glob_str(&mut self,
span: Span,
sub_span: Option<Span>,
id: NodeId,
values: &str,
parent: NodeId) {
self.check_and_record(UseGlob,
span,
sub_span,
svec!(id, values, parent));
}
pub fn extern_crate_str(&mut self,
span: Span,
sub_span: Option<Span>,

View File

@ -280,6 +280,19 @@ impl<'a> SpanUtils<'a> {
}
}
pub fn sub_span_of_token(&self, span: Span, tok: Token) -> Option<Span> {
let mut toks = self.retokenise_span(span);
loop {
let next = toks.real_token();
if next.tok == token::Eof {
return None;
}
if next.tok == tok {
return self.make_sub_span(span, Some(next.sp));
}
}
}
pub fn sub_span_after_keyword(&self,
span: Span,
keyword: keywords::Keyword) -> Option<Span> {

View File

@ -69,4 +69,3 @@ pub struct CrateTranslation {
pub crate_formats: dependency_format::Dependencies,
pub no_builtins: bool,
}