Hello community,

here is the log from the commit of package racer for openSUSE:Factory checked 
in at 2017-05-04 15:05:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/racer (Old)
 and      /work/SRC/openSUSE:Factory/.racer.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "racer"

Thu May  4 15:05:23 2017 rev:3 rq:492762 version:2.0.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/racer/racer.changes      2017-02-16 
16:51:24.731775965 +0100
+++ /work/SRC/openSUSE:Factory/.racer.new/racer.changes 2017-05-04 
15:05:25.753762810 +0200
@@ -1,0 +2,6 @@
+Tue May  2 21:18:50 UTC 2017 - [email protected]
+
+- resolve Self (e.g. in-impl function calls like Self::myfunction())
+- Fix stack overflow issue on unresolvable imports
+
+-------------------------------------------------------------------

Old:
----
  racer-2.0.5.tar.gz

New:
----
  racer-2.0.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ racer.spec ++++++
--- /var/tmp/diff_new_pack.n51G2O/_old  2017-05-04 15:05:28.809331405 +0200
+++ /var/tmp/diff_new_pack.n51G2O/_new  2017-05-04 15:05:28.809331405 +0200
@@ -20,7 +20,7 @@
 
 
 Name:           racer
-Version:        2.0.5
+Version:        2.0.6
 Release:        0
 Summary:        Code completion for Rust
 License:        MIT
@@ -35,8 +35,8 @@
 
 BuildRequires:  cargo
 BuildRequires:  git
-BuildRequires:  rust >= 1.14.0
-BuildRequires:  rust-std >= 1.14.0
+BuildRequires:  rust
+BuildRequires:  rust-std
 
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 

++++++ racer-2.0.5.tar.gz -> racer-2.0.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/CHANGELOG.md new/racer-2.0.6/CHANGELOG.md
--- old/racer-2.0.5/CHANGELOG.md        2017-01-16 20:47:26.000000000 +0100
+++ new/racer-2.0.6/CHANGELOG.md        2017-02-17 17:32:13.000000000 +0100
@@ -4,6 +4,11 @@
 All notable changes to this project will be documented in this file. This
 project adheres to [Semantic Versioning](http://semver.org/).
 
+## 2.0.6
+
+- resolve Self (e.g. in-impl function calls like Self::myfunction())
+- Fix stack overflow issue on unresolvable imports :tada: #698
+
 ## 2.0.5
 
 - Chained completions on separate lines now work #686
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/Cargo.lock new/racer-2.0.6/Cargo.lock
--- old/racer-2.0.5/Cargo.lock  2017-01-16 20:47:26.000000000 +0100
+++ new/racer-2.0.6/Cargo.lock  2017-02-17 17:32:13.000000000 +0100
@@ -1,6 +1,6 @@
 [root]
 name = "racer"
-version = "2.0.5"
+version = "2.0.6"
 dependencies = [
  "clap 2.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/Cargo.toml new/racer-2.0.6/Cargo.toml
--- old/racer-2.0.5/Cargo.toml  2017-01-16 20:47:26.000000000 +0100
+++ new/racer-2.0.6/Cargo.toml  2017-02-17 17:32:13.000000000 +0100
@@ -1,7 +1,7 @@
 [package]
 
 name = "racer"
-version = "2.0.5"
+version = "2.0.6"
 license = "MIT"
 description = "Code completion for Rust"
 authors = ["Phil Dawes <[email protected]>"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/src/racer/core.rs 
new/racer-2.0.6/src/racer/core.rs
--- old/racer-2.0.5/src/racer/core.rs   2017-01-16 20:47:26.000000000 +0100
+++ new/racer-2.0.6/src/racer/core.rs   2017-02-17 17:32:13.000000000 +0100
@@ -11,6 +11,7 @@
 use std::iter::{Fuse, Iterator};
 use std::rc::Rc;
 use codeiter::StmtIndicesIter;
+use matchers::PendingImports;
 
 use scopes;
 use nameres;
@@ -947,8 +948,8 @@
 
             let path = Path::from_vec(is_global, v);
             for m in nameres::resolve_path(&path, filepath, pos,
-                                         SearchType::StartsWith, 
Namespace::Both,
-                                         session) {
+                                           SearchType::StartsWith, 
Namespace::Both,
+                                           session, &PendingImports::empty()) {
                 out.push(m);
             }
         },
@@ -1082,7 +1083,7 @@
 
             nameres::resolve_path(&path, filepath, pos,
                                   SearchType::ExactMatch, Namespace::Both,
-                                  session).nth(0)
+                                  session, &PendingImports::empty()).nth(0)
         },
         CompletionType::Field => {
             let context = ast::get_type_of(contextstr.to_owned(), filepath, 
pos, session);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/src/racer/matchers.rs 
new/racer-2.0.6/src/racer/matchers.rs
--- old/racer-2.0.5/src/racer/matchers.rs       2017-01-16 20:47:26.000000000 
+0100
+++ new/racer-2.0.6/src/racer/matchers.rs       2017-02-17 17:32:13.000000000 
+0100
@@ -1,15 +1,25 @@
 use {scopes, typeinf, ast};
 use core::{Match, PathSegment, Src, Session, Coordinate, SessionExt};
-use util::{symbol_matches, txt_matches, find_ident_end, is_ident_char, 
char_at};
+use util::{StackLinkedListNode, symbol_matches, txt_matches, find_ident_end, 
is_ident_char, char_at};
 use nameres::{get_module_file, get_crate_file, resolve_path};
 use core::SearchType::{self, StartsWith, ExactMatch};
 use core::MatchType::{self, Let, Module, Function, Struct, Type, Trait, Enum, 
EnumVariant,
                       Const, Static, IfLet, WhileLet, For, Macro};
 use core::Namespace;
-use std::cell::Cell;
 use std::path::Path;
 use std::{iter, option, str, vec};
 
+/// The location of an import (`use` item) currently being resolved.
+#[derive(PartialEq, Eq)]
+pub struct PendingImport<'fp> {
+    filepath: &'fp Path,
+    blobstart: usize,
+    blobend: usize,
+}
+
+/// A stack of imports (`use` items) currently being resolved.
+pub type PendingImports<'stack, 'fp> = StackLinkedListNode<'stack, 
PendingImport<'fp>>;
+
 pub type MIter = option::IntoIter<Match>;
 pub type MChain<T> = iter::Chain<T, MIter>;
 
@@ -17,14 +27,15 @@
 pub fn match_types(src: Src, blobstart: usize, blobend: usize,
                    searchstr: &str, filepath: &Path,
                    search_type: SearchType,
-                   local: bool, session: &Session) -> 
iter::Chain<MChain<MChain<MChain<MChain<MChain<MIter>>>>>, 
vec::IntoIter<Match>> {
+                   local: bool, session: &Session,
+                   pending_imports: &PendingImports) -> 
iter::Chain<MChain<MChain<MChain<MChain<MChain<MIter>>>>>, 
vec::IntoIter<Match>> {
     let it = match_extern_crate(&src, blobstart, blobend, searchstr, filepath, 
search_type, session).into_iter();
     let it = it.chain(match_mod(src, blobstart, blobend, searchstr, filepath, 
search_type, local, session).into_iter());
     let it = it.chain(match_struct(&src, blobstart, blobend, searchstr, 
filepath, search_type, local).into_iter());
     let it = it.chain(match_type(&src, blobstart, blobend, searchstr, 
filepath, search_type, local).into_iter());
     let it = it.chain(match_trait(&src, blobstart, blobend, searchstr, 
filepath, search_type, local).into_iter());
     let it = it.chain(match_enum(&src, blobstart, blobend, searchstr, 
filepath, search_type, local).into_iter());
-    it.chain(match_use(&src, blobstart, blobend, searchstr, filepath, 
search_type, local, session).into_iter())
+    it.chain(match_use(&src, blobstart, blobend, searchstr, filepath, 
search_type, local, session, pending_imports).into_iter())
 }
 
 pub fn match_values(src: Src, blobstart: usize, blobend: usize,
@@ -515,18 +526,30 @@
     }
 }
 
-// HACK: recursion protection. With 'use glob' statements it's easy to
-// get into a recursive loop and exchaust the stack. Currently we
-// avoid this by not following a glob if we're already searching
-// through one.
-thread_local!(static ALREADY_GLOBBING: Cell<Option<bool>> = Cell::new(None));
-
 pub fn match_use(msrc: &str, blobstart: usize, blobend: usize,
                  searchstr: &str, filepath: &Path, search_type: SearchType,
-                 local: bool, session: &Session) -> Vec<Match> {
-    let mut out = Vec::new();
+                 local: bool, session: &Session,
+                 pending_imports: &PendingImports) -> Vec<Match> {
+    let import = PendingImport {
+        filepath: &filepath,
+        blobstart: blobstart,
+        blobend: blobend,
+    };
+
     let blob = &msrc[blobstart..blobend];
 
+    // If we're trying to resolve the same import recursively,
+    // do not return any matches this time.
+    if pending_imports.contains(&import) {
+        debug!("import {} involved in a cycle; ignoring", blob);
+        return Vec::new();
+    }
+
+    // Push this import on the stack of pending imports.
+    let pending_imports = &pending_imports.push(import);
+
+    let mut out = Vec::new();
+
     if find_keyword(blob, "use", "", StartsWith, local).is_none() { return 
out; }
 
     if blob.contains('*') {
@@ -536,36 +559,17 @@
 
         if use_item.is_glob {
             let basepath = use_item.paths.into_iter().nth(0).unwrap();
-            let mut follow_glob = true;
-            {
-                // don't follow glob if we are already following one otherwise
-                // otherwise we get a recursive mess
-                follow_glob &= ALREADY_GLOBBING.with(|c| { c.get().is_none() 
});
-
-                // don't follow the glob if the path base is the searchstr
-                follow_glob &= !(basepath.segments[0].name == searchstr ||
-                    (basepath.segments[0].name == "self" && 
basepath.segments[1].name == searchstr));
-            }
-
-            if follow_glob {
-                ALREADY_GLOBBING.with(|c| { c.set(Some(true)) });
-
-                let seg = PathSegment{ name: searchstr.to_owned(), types: 
Vec::new() };
-                let mut path = basepath.clone();
-                path.segments.push(seg);
-                debug!("found a glob: now searching for {:?}", path);
-                let iter_path = resolve_path(&path, filepath, blobstart, 
search_type, Namespace::Both, session);
-                if let StartsWith = search_type {
-                       ALREADY_GLOBBING.with(|c| { c.set(None) });
-                    return iter_path.collect();
-                }
-                for m in iter_path {
-                    out.push(m);
-                    break;
-                }
-                ALREADY_GLOBBING.with(|c| { c.set(None) });
-            } else {
-                debug!("not following glob");
+            let seg = PathSegment{ name: searchstr.to_owned(), types: 
Vec::new() };
+            let mut path = basepath.clone();
+            path.segments.push(seg);
+            debug!("found a glob: now searching for {:?}", path);
+            let iter_path = resolve_path(&path, filepath, blobstart, 
search_type, Namespace::Both, session, pending_imports);
+            if let StartsWith = search_type {
+                return iter_path.collect();
+            }
+            for m in iter_path {
+                out.push(m);
+                break;
             }
         }
     } else if txt_matches(search_type, searchstr, blob) {
@@ -582,7 +586,7 @@
                     // Do nothing because this will be picked up by the module
                     // search in a bit.
                 } else {
-                    for m in resolve_path(&path, filepath, blobstart, 
ExactMatch, Namespace::Both, session) {
+                    for m in resolve_path(&path, filepath, blobstart, 
ExactMatch, Namespace::Both, session, pending_imports) {
                         out.push(m);
                         if let ExactMatch = search_type  {
                             return out;
@@ -614,7 +618,7 @@
                         if symbol_matches(search_type, searchstr, 
&path.segments.last().unwrap().name) {
                             // last path segment matches the path. find it!
                             for m in resolve_path(&path, filepath, blobstart,
-                                                  ExactMatch, Namespace::Both, 
session) {
+                                                  ExactMatch, Namespace::Both, 
session, pending_imports) {
                                 out.push(m);
                                 if let ExactMatch = search_type  {
                                     return out;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/src/racer/nameres.rs 
new/racer-2.0.6/src/racer/nameres.rs
--- old/racer-2.0.5/src/racer/nameres.rs        2017-01-16 20:47:26.000000000 
+0100
+++ new/racer-2.0.6/src/racer/nameres.rs        2017-02-17 17:32:13.000000000 
+0100
@@ -2,7 +2,7 @@
 
 use {core, ast, matchers, scopes, typeinf};
 use core::SearchType::{self, ExactMatch, StartsWith};
-use core::{Match, Src, Session, Coordinate, SessionExt};
+use core::{Match, Src, Session, Coordinate, SessionExt, Ty};
 use core::MatchType::{Module, Function, Struct, Enum, FnArg, Trait, 
StructField, Impl, TraitImpl, MatchArm, Builtin};
 use core::Namespace;
 use util::{symbol_matches, txt_matches, find_ident_end};
@@ -10,6 +10,7 @@
 use cargo;
 use std::path::{Path, PathBuf};
 use std::{self, vec};
+use matchers::PendingImports;
 
 #[cfg(unix)]
 pub const PATH_SEP: char = ':';
@@ -62,7 +63,7 @@
 
     let mut out = Vec::new();
 
-    for m in search_for_impls(point, implsearchstr, fpath, local, true, 
session) {
+    for m in search_for_impls(point, implsearchstr, fpath, local, true, 
session, &PendingImports::empty()) {
         debug!("found impl!! |{:?}| looking for methods", m);
 
         if m.matchstr == "Deref" {
@@ -228,7 +229,7 @@
 
 
 pub fn search_for_impls(pos: usize, searchstr: &str, filepath: &Path, local: 
bool, include_traits: bool,
-                        session: &Session) -> vec::IntoIter<Match> {
+                        session: &Session, pending_imports: &PendingImports) 
-> vec::IntoIter<Match> {
     debug!("search_for_impls {}, {}, {:?}", pos, searchstr, 
filepath.display());
     let s = session.load_file(filepath);
     let scope_start = scopes::scope_start(s.as_src(), pos);
@@ -274,8 +275,8 @@
                     if include_traits && is_trait_impl {
                         let trait_path = implres.trait_path.unwrap();
                         let mut m = resolve_path(&trait_path,
-                                             filepath, scope_start + start, 
ExactMatch, Namespace::Type,
-                                             session).nth(0);
+                                                 filepath, scope_start + 
start, ExactMatch, Namespace::Type,
+                                                 session, 
pending_imports).nth(0);
                         debug!("found trait |{:?}| {:?}", trait_path, m);
 
                         if let Some(ref mut m) = m {
@@ -364,8 +365,8 @@
 
 // scope headers include fn decls, if let, while let etc..
 fn search_scope_headers(point: usize, scopestart: usize, msrc: Src, searchstr: 
&str,
-                        filepath: &Path, search_type: SearchType, session: 
&Session)
-                         -> vec::IntoIter<Match> {
+                        filepath: &Path, search_type: SearchType, session: 
&Session,
+                        pending_imports: &PendingImports) -> 
vec::IntoIter<Match> {
     debug!("search_scope_headers for |{}| pt: {}", searchstr, scopestart);
     if let Some(stmtstart) = scopes::find_stmt_start(msrc, scopestart) {
         let preblock = &msrc[stmtstart..scopestart];
@@ -479,7 +480,8 @@
                                      stmtstart + n - 1,
                                      SearchType::ExactMatch,
                                      Namespace::Both,
-                                     session)
+                                     session,
+                                     pending_imports)
                     .filter(|m| m.mtype == Trait)
                     .nth(0);
                 if let Some(m) = m {
@@ -647,7 +649,7 @@
 
 pub fn search_crate_root(pathseg: &core::PathSegment, modfpath: &Path,
                          searchtype: SearchType, namespace: Namespace,
-                         session: &Session) -> vec::IntoIter<Match> {
+                         session: &Session, pending_imports: &PendingImports) 
-> vec::IntoIter<Match> {
     debug!("search_crate_root |{:?}| {:?}", pathseg, modfpath.display());
 
     let crateroots = 
find_possible_crate_root_modules(modfpath.parent().unwrap(), session);
@@ -657,7 +659,7 @@
             continue;
         }
         debug!("going to search for {:?} in crateroot {:?}", pathseg, 
crateroot.display());
-        for m in resolve_name(pathseg, &crateroot, 0, searchtype, namespace, 
session) {
+        for m in resolve_name(pathseg, &crateroot, 0, searchtype, namespace, 
session, pending_imports) {
             out.push(m);
             if let ExactMatch = searchtype {
                 break;
@@ -691,8 +693,8 @@
 
 pub fn search_next_scope(mut startpoint: usize, pathseg: &core::PathSegment,
                          filepath:&Path, search_type: SearchType, local: bool,
-                         namespace: Namespace,
-                         session: &Session) -> vec::IntoIter<Match> {
+                         namespace: Namespace, session: &Session,
+                         pending_imports: &PendingImports) -> 
vec::IntoIter<Match> {
     let filesrc = session.load_file(filepath);
     if startpoint != 0 {
         // is a scope inside the file. Point should point to the definition
@@ -704,7 +706,7 @@
             startpoint += n + 1;
         });
     }
-    search_scope(startpoint, startpoint, filesrc.as_src(), pathseg, filepath, 
search_type, local, namespace, session)
+    search_scope(startpoint, startpoint, filesrc.as_src(), pathseg, filepath, 
search_type, local, namespace, session, pending_imports)
 }
 
 pub fn get_crate_file(name: &str, from_path: &Path, session: &Session) -> 
Option<PathBuf> {
@@ -758,7 +760,8 @@
                     pathseg: &core::PathSegment,
                     filepath:&Path, search_type: SearchType, local: bool,
                     namespace: Namespace,
-                    session: &Session) -> vec::IntoIter<Match> {
+                    session: &Session,
+                    pending_imports: &PendingImports) -> vec::IntoIter<Match> {
     let searchstr = &pathseg.name;
     let mut out = Vec::new();
 
@@ -767,7 +770,8 @@
 
     let scopesrc = src.from(start);
     let mut skip_next_block = false;
-    let mut delayed_use_globs = Vec::new();
+    let mut delayed_single_imports = Vec::new();
+    let mut delayed_glob_imports = Vec::new();
     let mut codeit = scopesrc.iter_stmts();
     let mut v = Vec::new();
 
@@ -833,12 +837,31 @@
             continue;
         }
 
-        let is_a_use_glob = (blob.starts_with("use") || blob.starts_with("pub 
use"))
-              && blob.find("::*").is_some();
+        let is_an_import = blob.starts_with("use") || blob.starts_with("pub 
use");
+
+        if is_an_import {
+            // A `use` item can import a value
+            // with the same name as a "type" (type/module/etc.) in the same 
scope.
+            // However, that type might appear after the `use`,
+            // so we need to process the type first and the `use` later (if 
necessary).
+            // If we didn't delay imports,
+            // we'd try to resolve such a `use` item by recursing onto itself.
+
+            // Optimisation: if the search string is not in the blob and it is 
not
+            // a glob import, this cannot match so fail fast!
+            let is_glob_import = blob.contains("::*");
+            if !is_glob_import {
+                if !blob.contains(searchstr.trim_right_matches('!')) {
+                    continue;
+                }
+            }
+
+            if is_glob_import {
+                delayed_glob_imports.push((blobstart, blobend));
+            } else {
+                delayed_single_imports.push((blobstart, blobend));
+            }
 
-        if is_a_use_glob {
-            // globs are *really* expensive to process. delay them until later
-            delayed_use_globs.push((blobstart, blobend));
             continue;
         }
 
@@ -861,16 +884,16 @@
             });
         }
 
-        // Optimisation: if the search string is not in the blob and it is not
-        // a 'use glob', this cannot match so fail fast!
-        if blob.find(searchstr.trim_right_matches('!')).is_none() {
+        // Optimisation: if the search string is not in the blob,
+        // this cannot match so fail fast!
+        if !blob.contains(searchstr.trim_right_matches('!')) {
             continue;
         }
 
         // There's a good chance of a match. Run the matchers
         out.extend(run_matchers_on_blob(src, start+blobstart, start+blobend,
                                         searchstr,
-                                        filepath, search_type, local, 
namespace, session));
+                                        filepath, search_type, local, 
namespace, session, pending_imports));
         if let ExactMatch = search_type {
             if !out.is_empty() {
                 return out.into_iter();
@@ -878,12 +901,13 @@
         }
     }
 
-    // finally process any use-globs that we skipped before
-    for (blobstart, blobend) in delayed_use_globs {
+    // Finally, process the imports that we skipped before.
+    // Process single imports first, because they shadow glob imports.
+    for (blobstart, blobend) in 
delayed_single_imports.into_iter().chain(delayed_glob_imports) {
         // There's a good chance of a match. Run the matchers
         for m in run_matchers_on_blob(src, start+blobstart, start+blobend,
                                       searchstr, filepath, search_type,
-                                      local, namespace, session).into_iter() {
+                                      local, namespace, session, 
pending_imports).into_iter() {
             out.push(m);
             if let ExactMatch = search_type {
                 return out.into_iter();
@@ -896,14 +920,15 @@
 }
 
 fn run_matchers_on_blob(src: Src, start: usize, end: usize, searchstr: &str,
-                         filepath: &Path, search_type: SearchType, local: bool,
-                         namespace: Namespace, session: &Session) -> 
Vec<Match> {
+                        filepath: &Path, search_type: SearchType, local: bool,
+                        namespace: Namespace, session: &Session,
+                        pending_imports: &PendingImports) -> Vec<Match> {
     let mut out = Vec::new();
     match namespace {
         Namespace::Type =>
             for m in matchers::match_types(src, start,
                                            end, searchstr,
-                                           filepath, search_type, local, 
session) {
+                                           filepath, search_type, local, 
session, pending_imports) {
                 out.push(m);
                 if let ExactMatch = search_type {
                     return out;
@@ -921,7 +946,7 @@
         Namespace::Both => {
             for m in matchers::match_types(src, start,
                                            end, searchstr,
-                                           filepath, search_type, local, 
session) {
+                                           filepath, search_type, local, 
session, pending_imports) {
                 out.push(m);
                 if let ExactMatch = search_type {
                     return out;
@@ -942,21 +967,21 @@
 
 fn search_local_scopes(pathseg: &core::PathSegment, filepath: &Path,
                        msrc: Src, point: usize, search_type: SearchType,
-                       namespace: Namespace,
-                       session: &Session) -> vec::IntoIter<Match> {
+                       namespace: Namespace, session: &Session,
+                       pending_imports: &PendingImports) -> 
vec::IntoIter<Match> {
     debug!("search_local_scopes {:?} {:?} {} {:?} {:?}", pathseg, 
filepath.display(), point,
            search_type, namespace);
 
     if point == 0 {
         // search the whole file
-        search_scope(0, 0, msrc, pathseg, filepath, search_type, true, 
namespace, session)
+        search_scope(0, 0, msrc, pathseg, filepath, search_type, true, 
namespace, session, pending_imports)
     } else {
         let mut out = Vec::new();
         let mut start = point;
         // search each parent scope in turn
         while start > 0 {
             start = scopes::scope_start(msrc, start);
-            for m in search_scope(start, point, msrc, pathseg, filepath, 
search_type, true, namespace, session) {
+            for m in search_scope(start, point, msrc, pathseg, filepath, 
search_type, true, namespace, session, pending_imports) {
                 out.push(m);
                 if let ExactMatch = search_type {
                     return out.into_iter();
@@ -969,7 +994,7 @@
             let searchstr = &pathseg.name;
 
             // scope headers = fn decls, if let, match, etc..
-            for m in search_scope_headers(point, start, msrc, searchstr, 
filepath, search_type, session) {
+            for m in search_scope_headers(point, start, msrc, searchstr, 
filepath, search_type, session, pending_imports) {
                 out.push(m);
                 if let ExactMatch = search_type {
                     return out.into_iter();
@@ -981,7 +1006,8 @@
 }
 
 pub fn search_prelude_file(pathseg: &core::PathSegment, search_type: 
SearchType,
-                           namespace: Namespace, session: &Session) -> 
vec::IntoIter<Match> {
+                           namespace: Namespace, session: &Session,
+                           pending_imports: &PendingImports) -> 
vec::IntoIter<Match> {
     debug!("search_prelude file {:?} {:?} {:?}", pathseg, search_type, 
namespace);
     let mut out : Vec<Match> = Vec::new();
 
@@ -998,7 +1024,7 @@
         if filepath.exists() || session.contains_file(&filepath) {
             let msrc = session.load_file_and_mask_comments(&filepath);
             let is_local = true;
-            for m in search_scope(0, 0, msrc.as_src(), pathseg, &filepath, 
search_type, is_local, namespace, session) {
+            for m in search_scope(0, 0, msrc.as_src(), pathseg, &filepath, 
search_type, is_local, namespace, session, pending_imports) {
                 out.push(m);
             }
         }
@@ -1019,7 +1045,7 @@
 
         if let Some(module) = resolve_path(&core::Path::from_vec(true, 
vec!["std","str"]),
                                            filepath, pos, search_type, 
namespace,
-                                           session).nth(0) {
+                                           session, 
&PendingImports::empty()).nth(0) {
             out.push(Match {
                 matchstr: "str".into(),
                 filepath: module.filepath,
@@ -1036,7 +1062,7 @@
         }
 
     } else {
-        for m in resolve_path(path, filepath, pos, search_type, namespace, 
session) {
+        for m in resolve_path(path, filepath, pos, search_type, namespace, 
session, &PendingImports::empty()) {
             out.push(m);
             if let ExactMatch = search_type {
                 break;
@@ -1055,7 +1081,7 @@
 
 pub fn resolve_name(pathseg: &core::PathSegment, filepath: &Path, pos: usize,
                     search_type: SearchType, namespace: Namespace,
-                    session: &Session) -> vec::IntoIter<Match> {
+                    session: &Session, pending_imports: &PendingImports) -> 
vec::IntoIter<Match> {
     let mut out = Vec::new();
     let searchstr = &pathseg.name;
 
@@ -1064,6 +1090,12 @@
     let msrc = session.load_file(filepath);
     let is_exact_match = match search_type { ExactMatch => true, StartsWith => 
false };
 
+    if is_exact_match && &searchstr[..] == "Self" {
+        if let Some(Ty::Match(m)) = typeinf::get_type_of_self(pos, filepath, 
true, msrc.as_src(), session) {
+            out.push(m.clone());
+        }
+    }
+
     if (is_exact_match && &searchstr[..] == "std") ||
        (!is_exact_match && "std".starts_with(searchstr)) {
         get_crate_file("std", filepath, session).map(|cratepath| {
@@ -1089,7 +1121,7 @@
         }
     }
 
-    for m in search_local_scopes(pathseg, filepath, msrc.as_src(), pos, 
search_type, namespace, session) {
+    for m in search_local_scopes(pathseg, filepath, msrc.as_src(), pos, 
search_type, namespace, session, pending_imports) {
         out.push(m);
         if let ExactMatch = search_type {
             if !out.is_empty() {
@@ -1098,7 +1130,7 @@
         }
     }
 
-    for m in search_crate_root(pathseg, filepath, search_type, namespace, 
session) {
+    for m in search_crate_root(pathseg, filepath, search_type, namespace, 
session, pending_imports) {
         out.push(m);
         if let ExactMatch = search_type {
             if !out.is_empty() {
@@ -1107,7 +1139,7 @@
         }
     }
 
-    for m in search_prelude_file(pathseg, search_type, namespace, session) {
+    for m in search_prelude_file(pathseg, search_type, namespace, session, 
pending_imports) {
         out.push(m);
         if let ExactMatch = search_type {
             if !out.is_empty() {
@@ -1125,7 +1157,8 @@
 }
 
 // Get the scope corresponding to super::
-pub fn get_super_scope(filepath: &Path, pos: usize, session: &Session) -> 
Option<core::Scope> {
+pub fn get_super_scope(filepath: &Path, pos: usize, session: &Session,
+                       pending_imports: &PendingImports) -> 
Option<core::Scope> {
     let msrc = session.load_file_and_mask_comments(filepath);
     let mut path = scopes::get_local_module_path(msrc.as_src(), pos);
     debug!("get_super_scope: path: {:?} filepath: {:?} {} {:?}", path, 
filepath, pos, session);
@@ -1153,7 +1186,7 @@
         let path = core::Path::from_svec(false, path);
         debug!("get_super_scope looking for local scope {:?}", path);
         resolve_path(&path, filepath, 0, SearchType::ExactMatch,
-                            Namespace::Type, session).nth(0)
+                            Namespace::Type, session, pending_imports).nth(0)
             .and_then(|m| msrc[m.point..].find('{')
                       .map(|p| core::Scope{ filepath: filepath.to_path_buf(),
                                              point:m.point + p + 1 }))
@@ -1162,28 +1195,28 @@
 
 pub fn resolve_path(path: &core::Path, filepath: &Path, pos: usize,
                     search_type: SearchType, namespace: Namespace,
-                    session: &Session) -> vec::IntoIter<Match> {
+                    session: &Session, pending_imports: &PendingImports) -> 
vec::IntoIter<Match> {
     debug!("resolve_path {:?} {:?} {} {:?}", path, filepath.display(), pos, 
search_type);
     let len = path.segments.len();
     if len == 1 {
         let pathseg = &path.segments[0];
-        resolve_name(pathseg, filepath, pos, search_type, namespace, session)
+        resolve_name(pathseg, filepath, pos, search_type, namespace, session, 
pending_imports)
     } else if len != 0 {
         if path.segments[0].name == "self" {
             // just remove self
             let mut newpath: core::Path = path.clone();
             newpath.segments.remove(0);
-            return resolve_path(&newpath, filepath, pos, search_type, 
namespace, session);
+            return resolve_path(&newpath, filepath, pos, search_type, 
namespace, session, pending_imports);
         }
 
         if path.segments[0].name == "super" {
-            if let Some(scope) = get_super_scope(filepath, pos, session) {
+            if let Some(scope) = get_super_scope(filepath, pos, session, 
pending_imports) {
                 debug!("PHIL super scope is {:?}", scope);
 
                 let mut newpath: core::Path = path.clone();
                 newpath.segments.remove(0);
                 return resolve_path(&newpath, &scope.filepath,
-                                    scope.point, search_type, namespace, 
session);
+                                    scope.point, search_type, namespace, 
session, pending_imports);
             } else {
                 // can't find super scope. Return no matches
                 debug!("can't resolve path {:?}, returning no matches", path);
@@ -1194,7 +1227,7 @@
         let mut out = Vec::new();
         let mut parent_path: core::Path = path.clone();
         parent_path.segments.remove(len-1);
-        let context = resolve_path(&parent_path, filepath, pos, ExactMatch, 
Namespace::Type, session).nth(0);
+        let context = resolve_path(&parent_path, filepath, pos, ExactMatch, 
Namespace::Type, session, pending_imports).nth(0);
         context.map(|m| {
             match m.mtype {
                 Module => {
@@ -1207,7 +1240,7 @@
                     }
                     let pathseg = core::PathSegment{name: 
searchstr.to_owned(), types: Vec::new()};
                     debug!("searching a module '{}' for {} (whole path: 
{:?})", m.matchstr, pathseg.name, path);
-                    for m in search_next_scope(m.point, &pathseg, &m.filepath, 
search_type, false, namespace, session) {
+                    for m in search_next_scope(m.point, &pathseg, &m.filepath, 
search_type, false, namespace, session, pending_imports) {
                         out.push(m);
                     }
                 }
@@ -1230,14 +1263,14 @@
                 }
                 Struct => {
                     debug!("found a struct. Now need to look for impl");
-                    for m_impl in search_for_impls(m.point, &m.matchstr, 
&m.filepath, m.local, true, session) {
+                    for m_impl in search_for_impls(m.point, &m.matchstr, 
&m.filepath, m.local, true, session, pending_imports) {
                         debug!("found impl!! {:?}", m_impl);
                         let pathseg = &path.segments[len-1];
                         let src = session.load_file(&m_impl.filepath);
                         // find the opening brace and skip to it.
                         src[m_impl.point..].find('{').map(|n| {
                             let point = m_impl.point + n + 1;
-                            for m_impl in search_scope(point, point, 
src.as_src(), pathseg, &m_impl.filepath, search_type, m_impl.local, namespace, 
session) {
+                            for m_impl in search_scope(point, point, 
src.as_src(), pathseg, &m_impl.filepath, search_type, m_impl.local, namespace, 
session, pending_imports) {
                                 out.push(m_impl);
                             }
                         });
@@ -1248,7 +1281,7 @@
                             // find the opening brace and skip to it.
                             src[m_gen.point..].find('{').map(|n| {
                                 let point = m_gen.point + n + 1;
-                                for m_gen in search_scope(point, point, 
src.as_src(), pathseg, &m_gen.filepath, search_type, m_gen.local, namespace, 
session) {
+                                for m_gen in search_scope(point, point, 
src.as_src(), pathseg, &m_gen.filepath, search_type, m_gen.local, namespace, 
session, pending_imports) {
                                     out.push(m_gen);
                                 }
                             });
@@ -1277,7 +1310,7 @@
         let pathseg = core::PathSegment{name: searchstr.to_owned(),
                                          types: Vec::new()};
 
-        for m in search_next_scope(pos, &pathseg, filepath, search_type, 
false, namespace, session) {
+        for m in search_next_scope(pos, &pathseg, filepath, search_type, 
false, namespace, session, &PendingImports::empty()) {
             out.push(m);
         }
 
@@ -1300,6 +1333,7 @@
         let parent_path = &path[..(path.len()-1)];
         let context = do_external_search(parent_path, filepath, pos, 
ExactMatch, Namespace::Type, session).nth(0);
         context.map(|m| {
+            let pending_imports = &PendingImports::empty();
             match m.mtype {
                 Module => {
                     debug!("found an external module {}", m.matchstr);
@@ -1310,14 +1344,14 @@
                     };
                     let pathseg = core::PathSegment{name: searchstr.to_owned(),
                                          types: Vec::new()};
-                    for m in search_next_scope(m.point, &pathseg, &m.filepath, 
search_type, false, namespace, session) {
+                    for m in search_next_scope(m.point, &pathseg, &m.filepath, 
search_type, false, namespace, session, pending_imports) {
                         out.push(m);
                     }
                 }
 
                 Struct => {
                     debug!("found a pub struct. Now need to look for impl");
-                    for m in search_for_impls(m.point, &m.matchstr, 
&m.filepath, m.local, false, session) {
+                    for m in search_for_impls(m.point, &m.matchstr, 
&m.filepath, m.local, false, session, pending_imports) {
                         debug!("found  impl2!! {}", m.matchstr);
                         // deal with started with "{", so that "foo::{bar" 
will be same as "foo::bar"
                         let searchstr = match 
path[path.len()-1].chars().next() {
@@ -1327,7 +1361,7 @@
                         let pathseg = core::PathSegment{name: 
searchstr.to_owned(),
                                          types: Vec::new()};
                         debug!("about to search impl scope...");
-                        for m in search_next_scope(m.point, &pathseg, 
&m.filepath, search_type, m.local, namespace, session) {
+                        for m in search_next_scope(m.point, &pathseg, 
&m.filepath, search_type, m.local, namespace, session, pending_imports) {
                             out.push(m);
                         }
                     };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/src/racer/typeinf.rs 
new/racer-2.0.6/src/racer/typeinf.rs
--- old/racer-2.0.5/src/racer/typeinf.rs        2017-01-16 20:47:26.000000000 
+0100
+++ new/racer-2.0.6/src/racer/typeinf.rs        2017-02-17 17:32:13.000000000 
+0100
@@ -9,6 +9,7 @@
 use matchers;
 use core::SearchType::ExactMatch;
 use util::txt_matches;
+use std::path::Path;
 
 fn find_start_of_function_body(src: &str) -> usize {
     // TODO: this should ignore anything inside parens so as to skip the arg 
list
@@ -78,7 +79,11 @@
 
 fn get_type_of_self_arg(m: &Match, msrc: Src, session: &Session) -> 
Option<core::Ty> {
     debug!("get_type_of_self_arg {:?}", m);
-    scopes::find_impl_start(msrc, m.point, 0).and_then(|start| {
+    get_type_of_self(m.point, &m.filepath, m.local, msrc, session)
+}
+
+pub fn get_type_of_self(point: usize, filepath: &Path, local: bool, msrc: Src, 
session: &Session) -> Option<core::Ty> {
+    scopes::find_impl_start(msrc, point, 0).and_then(|start| {
         let decl = generate_skeleton_for_parsing(&msrc.from(start));
         debug!("get_type_of_self_arg impl skeleton |{}|", decl);
 
@@ -86,23 +91,23 @@
             let implres = ast::parse_impl(decl);
             debug!("get_type_of_self_arg implres |{:?}|", implres);
             resolve_path_with_str(&implres.name_path.expect("failed parsing 
impl name"),
-                                  &m.filepath, start,
+                                  filepath, start,
                                   ExactMatch, Namespace::Type,
                                   session).nth(0).map(core::Ty::Match)
         } else {
             // // must be a trait
             ast::parse_trait(decl).name.and_then(|name| {
                 Some(core::Ty::Match(Match {
-                           matchstr: name,
-                           filepath: m.filepath.clone(),
-                           point: start,
-                           coords: None,
-                           local: m.local,
-                           mtype: core::MatchType::Trait,
-                           contextstr: matchers::first_line(&msrc[start..]),
-                           generic_args: Vec::new(),
-                           generic_types: Vec::new(),
-                           docs: String::new(),
+                    matchstr: name,
+                    filepath: filepath.into(),
+                    point: start,
+                    coords: None,
+                    local: local,
+                    mtype: core::MatchType::Trait,
+                    contextstr: matchers::first_line(&msrc[start..]),
+                    generic_args: Vec::new(),
+                    generic_types: Vec::new(),
+                    docs: String::new(),
                 }))
             })
         }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/src/racer/util.rs 
new/racer-2.0.6/src/racer/util.rs
--- old/racer-2.0.5/src/racer/util.rs   2017-01-16 20:47:26.000000000 +0100
+++ new/racer-2.0.6/src/racer/util.rs   2017-02-17 17:32:13.000000000 +0100
@@ -346,3 +346,50 @@
         }
     }
 }
+
+/// An immutable stack implemented as a linked list backed by a thread's stack.
+pub struct StackLinkedListNode<'stack, 
T>(Option<StackLinkedListNodeData<'stack, T>>)
+    where T: 'stack;
+
+struct StackLinkedListNodeData<'stack, T>
+    where T: 'stack
+{
+    item: T,
+    previous: &'stack StackLinkedListNode<'stack, T>,
+}
+
+impl<'stack, T> StackLinkedListNode<'stack, T>
+    where T: 'stack
+{
+    /// Returns an empty node.
+    pub fn empty() -> Self {
+        StackLinkedListNode(None)
+    }
+
+    /// Pushes a new node on the stack. Returns the new node.
+    pub fn push(&'stack self, item: T) -> Self {
+        StackLinkedListNode(Some(StackLinkedListNodeData {
+            item: item,
+            previous: self,
+        }))
+    }
+}
+
+impl<'stack, T> StackLinkedListNode<'stack, T>
+    where T: 'stack + PartialEq
+{
+    /// Check if the stack contains the specified item.
+    /// Returns `true` if the item is found, or `false` if it's not found.
+    pub fn contains(&self, item: &T) -> bool {
+        let mut current = self;
+        while let &StackLinkedListNode(Some(StackLinkedListNodeData { item: 
ref current_item, previous })) = current {
+            if current_item == item {
+                return true;
+            }
+
+            current = previous;
+        }
+
+        false
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/racer-2.0.5/tests/system.rs 
new/racer-2.0.6/tests/system.rs
--- old/racer-2.0.5/tests/system.rs     2017-01-16 20:47:26.000000000 +0100
+++ new/racer-2.0.6/tests/system.rs     2017-02-17 17:32:13.000000000 +0100
@@ -954,6 +954,33 @@
 }
 
 #[test]
+fn single_import_shadows_glob_import() {
+    let _lock = sync!();
+
+    let src = "
+    use shadowed::*;
+    use shadower::Foo;
+
+    mod shadowed {
+        pub struct Foo;
+    }
+
+    mod shadower {
+        pub struct Foo;
+    }
+
+    fn main() {
+        Foo~;
+    }
+    ";
+    let got = get_definition(src, None);
+    assert_eq!(got.matchstr, "Foo");
+    println!("{}", got.filepath.display());
+    println!("{}", got.point);
+    assert_eq!(got.coords, Some(Coordinate { line: 10, column: 19 }));
+}
+
+#[test]
 fn follows_use_self() {
     let _lock = sync!();
 
@@ -986,6 +1013,84 @@
 }
 
 #[test]
+fn completes_out_of_order_mod_use_with_same_fn_name_as_mod() {
+    let _lock = sync!();
+
+    let src = "
+    use foo::foo;
+
+    mod foo {
+        pub fn foo() {}
+    }
+
+    fn main() {
+        f~
+    }";
+
+    let mut has_module = false;
+    let mut has_function = false;
+    let completions = get_all_completions(src, None);
+    for m in completions {
+        match (&*m.matchstr, m.mtype) {
+            ("foo", MatchType::Module) => has_module = true,
+            ("foo", MatchType::Function) => has_function = true,
+            _ => (),
+        }
+    }
+    assert!(has_module && has_function);
+}
+
+#[test]
+fn ignores_self_referential_unresolved_import() {
+    let _lock = sync!();
+
+    let src = "use foo::foo;f~";
+
+    let completions = get_all_completions(src, None);
+    assert!(!completions.iter().any(|m| m.matchstr == "foo"));
+}
+
+#[test]
+fn ignores_self_referential_unresolved_import_long() {
+    let _lock = sync!();
+
+    let src = "use foo::bar::foo;f~";
+
+    let completions = get_all_completions(src, None);
+    assert!(!completions.iter().any(|m| m.matchstr == "foo"));
+}
+
+#[test]
+fn ignores_self_referential_unresolved_imports() {
+    let _lock = sync!();
+
+    let src = "
+    use foo::bar;
+    use bar::baz;
+    use baz::foo;
+    f~";
+
+    let completions = get_all_completions(src, None);
+    assert!(!completions.iter().any(|m| m.matchstr == "foo"));
+}
+
+#[test]
+fn ignores_self_referential_unresolved_imports_across_modules() {
+    let _lock = sync!();
+
+    let src = "
+    use foo::bar;
+
+    mod foo {
+        pub use super::bar;
+    }
+    b~";
+
+    let completions = get_all_completions(src, None);
+    assert!(!completions.iter().any(|m| m.matchstr == "bar"));
+}
+
+#[test]
 fn finds_external_mod_docs() {
     let _lock = sync!();
 
@@ -1042,7 +1147,7 @@
     let src1 = "
     /// Orange
     /// juice
-    
+
     pub fn apple() {
         let x = 1;
     }";
@@ -1966,6 +2071,24 @@
 }
 
 #[test]
+fn finds_enum_variant_through_recursive_glob_imports() {
+    let _lock = sync!();
+
+    let src = "
+    use foo::*;
+    use Bar::*;
+
+    mod foo {
+        pub enum Bar { MyVariant, MyVariant2 }
+    }
+    MyVa~riant
+    ";
+
+    let got = get_definition(src, None);
+    assert_eq!("MyVariant", got.matchstr);
+}
+
+#[test]
 #[ignore]
 fn uses_generic_arg_to_resolve_trait_method() {
     let _lock = sync!();
@@ -2481,3 +2604,38 @@
     assert_eq!("same_name", got.matchstr);
     assert_eq!(MatchType::Function, got.mtype);
 }
+
+#[test]
+fn finds_self() {
+    let _lock = sync!();
+
+    let src = "
+    struct Foo;
+    impl Foo {
+        fn foo() {
+            Se~lf
+        }
+    }
+    ";
+
+    let got = get_definition(src, None);
+    assert_eq!("Foo", got.matchstr);
+}
+
+#[test]
+fn finds_self_referenced_functions() {
+    let _lock = sync!();
+
+    let src = "
+    struct Foo;
+    impl Foo {
+        fn foo() {
+            Self::myfun~ction
+        }
+        fn myfunction() {}
+    }
+    ";
+
+    let got = get_definition(src, None);
+    assert_eq!("myfunction", got.matchstr);
+}

++++++ vendor.tar.xz ++++++


Reply via email to