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:
parent
bd3cf4c05f
commit
df0c6d9385
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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)]
|
||||
|
@ -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|
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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 => {
|
||||
|
@ -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>,
|
||||
|
@ -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> {
|
||||
|
@ -69,4 +69,3 @@ pub struct CrateTranslation {
|
||||
pub crate_formats: dependency_format::Dependencies,
|
||||
pub no_builtins: bool,
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user