+ /// When name resolution fails, this method can be used to look up candidate
+ /// entities with the expected name. It allows filtering them using the
+ /// supplied predicate (which should be used to only accept the types of
+ /// definitions expected e.g. traits). The lookup spans across all crates.
+ ///
+ /// NOTE: The method does not look into imports, but this is not a problem,
+ /// since we report the definitions (thus, the de-aliased imports).
+ fn lookup_candidates<FilterFn>(&mut self,
+ lookup_name: Name,
+ namespace: Namespace,
+ filter_fn: FilterFn) -> SuggestedCandidates
+ where FilterFn: Fn(Def) -> bool {
+
+ let mut lookup_results = Vec::new();
+ let mut worklist = Vec::new();
+ worklist.push((self.graph_root, Vec::new(), false));
+
+ while let Some((in_module,
+ path_segments,
+ in_module_is_extern)) = worklist.pop() {
+ build_reduced_graph::populate_module_if_necessary(self, &in_module);
+
+ in_module.for_each_child(|name, ns, name_binding| {
+
+ // avoid imports entirely
+ if name_binding.is_import() { return; }
+
+ // collect results based on the filter function
+ if let Some(def) = name_binding.def() {
+ if name == lookup_name && ns == namespace && filter_fn(def) {
+ // create the path
+ let ident = hir::Ident::from_name(name);
+ let params = PathParameters::none();
+ let segment = PathSegment {
+ identifier: ident,
+ parameters: params,
+ };
+ let span = name_binding.span.unwrap_or(syntax::codemap::DUMMY_SP);
+ let mut segms = path_segments.clone();
+ segms.push(segment);
+ let segms = HirVec::from_vec(segms);
+ let path = Path {
+ span: span,
+ global: true,
+ segments: segms,
+ };
+ // the entity is accessible in the following cases:
+ // 1. if it's defined in the same crate, it's always
+ // accessible (since private entities can be made public)
+ // 2. if it's defined in another crate, it's accessible
+ // only if both the module is public and the entity is
+ // declared as public (due to pruning, we don't explore
+ // outside crate private modules => no need to check this)
+ if !in_module_is_extern || name_binding.is_public() {
+ lookup_results.push(path);
+ }
+ }
+ }
+
+ // collect submodules to explore
+ if let Some(module) = name_binding.module() {
+ // form the path
+ let path_segments = match module.parent_link {
+ NoParentLink => path_segments.clone(),
+ ModuleParentLink(_, name) => {
+ let mut paths = path_segments.clone();
+ let ident = hir::Ident::from_name(name);
+ let params = PathParameters::none();
+ let segm = PathSegment {
+ identifier: ident,
+ parameters: params,
+ };
+ paths.push(segm);
+ paths
+ }
+ _ => unreachable!(),
+ };
+
+ if !in_module_is_extern || name_binding.is_public() {
+ // add the module to the lookup
+ let is_extern = in_module_is_extern || module.is_extern_crate;
+ worklist.push((module, path_segments, is_extern));
+ }
+ }
+ })
+ }
+
+ SuggestedCandidates {
+ name: lookup_name.as_str().to_string(),
+ candidates: lookup_results,
+ }
+ }
+