From 34e3ef61bd25c635721066c1f881d7f041366a0a Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Mon, 24 Feb 2020 16:38:59 +0000
Subject: Initial debugging code

---
 crates/ra_project_model/src/lib.rs | 47 ++++++++++++++++++++++++++++++++++----
 1 file changed, 42 insertions(+), 5 deletions(-)

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 9df6a0e07..a8594a697 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -7,6 +7,7 @@ mod sysroot;
 use std::{
     error::Error,
     fs::File,
+    fs::read_dir,
     io::BufReader,
     path::{Path, PathBuf},
     process::Command,
@@ -406,18 +407,54 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
     None
 }
 
-fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
-    if path.ends_with("Cargo.toml") {
-        return Ok(path.to_path_buf());
-    }
+fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> {
     let mut curr = Some(path);
     while let Some(path) = curr {
         let candidate = path.join("Cargo.toml");
         if candidate.exists() {
-            return Ok(candidate);
+            return Some(candidate);
         }
         curr = path.parent();
     }
+    
+    None
+}
+
+fn find_cargo_toml_up_the_fs(path: &Path) -> Option<PathBuf> {
+    log::info!("find_cargo_toml_up_the_fs()");
+    let entities = match read_dir(path) {
+        Ok(entities) => entities,
+        Err(e) => {
+            log::info!("err {}", e);
+            return None
+        }
+    };
+
+    log::info!("entities: {:?}", entities);
+    for entity in entities.filter_map(Result::ok) {
+        let candidate = entity.path().join("Cargo.toml");
+        log::info!("candidate: {:?}, exists: {}", candidate, candidate.exists());
+        if candidate.exists() {
+            return Some(candidate);
+        }
+    }
+
+    None
+}
+
+fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
+    if path.ends_with("Cargo.toml") {
+        return Ok(path.to_path_buf());
+    }
+
+    if let Some(p) = find_cargo_toml_down_the_fs(path) {
+        return Ok(p)
+    }
+
+    if let Some(p) = find_cargo_toml_up_the_fs(path) {
+        return Ok(p)
+    }
+
     Err(CargoTomlNotFoundError(path.to_path_buf()).into())
 }
 
-- 
cgit v1.2.3


From f1b7349e7a929cd55f916fc6cdfa171467ac897d Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Tue, 25 Feb 2020 20:56:24 +0000
Subject: clean up

---
 crates/ra_project_model/src/lib.rs | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index a8594a697..cfebf36f8 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -421,19 +421,14 @@ fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> {
 }
 
 fn find_cargo_toml_up_the_fs(path: &Path) -> Option<PathBuf> {
-    log::info!("find_cargo_toml_up_the_fs()");
     let entities = match read_dir(path) {
         Ok(entities) => entities,
-        Err(e) => {
-            log::info!("err {}", e);
-            return None
-        }
+        Err(_) => return None
     };
 
-    log::info!("entities: {:?}", entities);
+    // Only one level up to avoid cycles the easy way and stop a runaway scan with large projects
     for entity in entities.filter_map(Result::ok) {
         let candidate = entity.path().join("Cargo.toml");
-        log::info!("candidate: {:?}, exists: {}", candidate, candidate.exists());
         if candidate.exists() {
             return Some(candidate);
         }
-- 
cgit v1.2.3


From 9391b1c8ceb96e07e4553014cb3b543793ebf717 Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Thu, 27 Feb 2020 21:52:10 +0000
Subject: fixes and improvements

---
 crates/ra_project_model/src/lib.rs    | 72 ++++++++++++++++++++++++-----------
 crates/rust-analyzer/src/main_loop.rs |  2 +-
 2 files changed, 50 insertions(+), 24 deletions(-)

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index cfebf36f8..f678bf5d6 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -6,8 +6,7 @@ mod sysroot;
 
 use std::{
     error::Error,
-    fs::File,
-    fs::read_dir,
+    fs::{read_dir, File, ReadDir},
     io::BufReader,
     path::{Path, PathBuf},
     process::Command,
@@ -26,15 +25,35 @@ pub use crate::{
 };
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct CargoTomlNotFoundError(pub PathBuf);
+pub struct CargoTomlNoneFoundError(pub PathBuf);
 
-impl std::fmt::Display for CargoTomlNotFoundError {
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct CargoTomlMultipleValidFoundError(pub Vec<PathBuf>);
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct CargoTomlSearchFileSystemError(pub PathBuf, pub String);
+
+impl std::fmt::Display for CargoTomlNoneFoundError {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(fmt, "can't find Cargo.toml at {}", self.0.display())
     }
 }
 
-impl Error for CargoTomlNotFoundError {}
+impl std::fmt::Display for CargoTomlMultipleValidFoundError {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(fmt, "found multiple valid Cargo.toml files {:?}", self.0)
+    }
+}
+
+impl std::fmt::Display for CargoTomlSearchFileSystemError {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(fmt, "a filesystem error occurred while searching for Cargo.toml: {}", self.1)
+    }
+}
+
+impl Error for CargoTomlNoneFoundError {}
+impl Error for CargoTomlMultipleValidFoundError {}
+impl Error for CargoTomlSearchFileSystemError {}
 
 #[derive(Debug, Clone)]
 pub enum ProjectWorkspace {
@@ -407,7 +426,7 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
     None
 }
 
-fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> {
+fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> {
     let mut curr = Some(path);
     while let Some(path) = curr {
         let candidate = path.join("Cargo.toml");
@@ -416,41 +435,48 @@ fn find_cargo_toml_down_the_fs(path: &Path) -> Option<PathBuf> {
         }
         curr = path.parent();
     }
-    
+
     None
 }
 
-fn find_cargo_toml_up_the_fs(path: &Path) -> Option<PathBuf> {
-    let entities = match read_dir(path) {
-        Ok(entities) => entities,
-        Err(_) => return None
-    };
-
-    // Only one level up to avoid cycles the easy way and stop a runaway scan with large projects
+fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> {
+    // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
+    let mut valid_canditates = vec![];
     for entity in entities.filter_map(Result::ok) {
         let candidate = entity.path().join("Cargo.toml");
         if candidate.exists() {
-            return Some(candidate);
+            valid_canditates.push(candidate)
         }
     }
-
-    None
+    valid_canditates
 }
 
 fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
+    let path_as_buf = path.to_path_buf();
+
     if path.ends_with("Cargo.toml") {
         return Ok(path.to_path_buf());
     }
 
-    if let Some(p) = find_cargo_toml_down_the_fs(path) {
-        return Ok(p)
+    if let Some(p) = find_cargo_toml_in_parent_dir(path) {
+        return Ok(p);
     }
 
-    if let Some(p) = find_cargo_toml_up_the_fs(path) {
-        return Ok(p)
-    }
+    let entities = match read_dir(path.join("does_not_exist")) {
+        Ok(entities) => {
+            entities
+        },
+        Err(e) => {
+            return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into())
+        },
+    };
 
-    Err(CargoTomlNotFoundError(path.to_path_buf()).into())
+    let mut valid_canditates = find_cargo_toml_in_child_dir(entities);
+    match valid_canditates.len() {
+        1 => Ok(valid_canditates.remove(0)),
+        0 => Err(CargoTomlNoneFoundError(path_as_buf).into()),
+        _ => Err(CargoTomlMultipleValidFoundError(valid_canditates).into()),
+    }
 }
 
 pub fn get_rustc_cfg_options() -> CfgOptions {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 6e9e604a6..37a46cd65 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -115,7 +115,7 @@ pub fn main_loop(
                     Ok(workspace) => loaded_workspaces.push(workspace),
                     Err(e) => {
                         log::error!("loading workspace failed: {:?}", e);
-                        if let Some(ra_project_model::CargoTomlNotFoundError(_)) = e.downcast_ref()
+                        if let Some(ra_project_model::CargoTomlNoneFoundError(_)) = e.downcast_ref()
                         {
                             if !feature_flags.get("notifications.cargo-toml-not-found") {
                                 continue;
-- 
cgit v1.2.3


From f9f8edfb0602baa6d7fae0704f02aef15ea25dd1 Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Thu, 27 Feb 2020 22:03:29 +0000
Subject: fix unneeded body

---
 crates/ra_project_model/src/lib.rs | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index f678bf5d6..ec91abf85 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -463,12 +463,8 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
     }
 
     let entities = match read_dir(path.join("does_not_exist")) {
-        Ok(entities) => {
-            entities
-        },
-        Err(e) => {
-            return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into())
-        },
+        Ok(entities) => entities,
+        Err(e) => return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into()),
     };
 
     let mut valid_canditates = find_cargo_toml_in_child_dir(entities);
-- 
cgit v1.2.3


From 12b595e817b9cb47b3abb5ca4455e2ae9e95f58b Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Thu, 27 Feb 2020 22:06:51 +0000
Subject: remove code used for testing

---
 crates/ra_project_model/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index ec91abf85..c4d67d3dc 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -462,7 +462,7 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
         return Ok(p);
     }
 
-    let entities = match read_dir(path.join("does_not_exist")) {
+    let entities = match read_dir(path) {
         Ok(entities) => entities,
         Err(e) => return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into()),
     };
-- 
cgit v1.2.3


From e15424c1b7d5a82545fbb3744af3123a124053d5 Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Sat, 29 Feb 2020 13:05:10 +0000
Subject: keep one CargoTomlNotFoundError

---
 crates/ra_project_model/src/lib.rs    | 59 ++++++++++++++++++-----------------
 crates/rust-analyzer/src/main_loop.rs |  7 ++++-
 2 files changed, 37 insertions(+), 29 deletions(-)

diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index c4d67d3dc..bcf12460d 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -25,35 +25,23 @@ pub use crate::{
 };
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct CargoTomlNoneFoundError(pub PathBuf);
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct CargoTomlMultipleValidFoundError(pub Vec<PathBuf>);
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct CargoTomlSearchFileSystemError(pub PathBuf, pub String);
-
-impl std::fmt::Display for CargoTomlNoneFoundError {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(fmt, "can't find Cargo.toml at {}", self.0.display())
-    }
-}
-
-impl std::fmt::Display for CargoTomlMultipleValidFoundError {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(fmt, "found multiple valid Cargo.toml files {:?}", self.0)
-    }
+pub struct CargoTomlNotFoundError {
+    pub searched_at: PathBuf,
+    pub reason: String,
 }
 
-impl std::fmt::Display for CargoTomlSearchFileSystemError {
+impl std::fmt::Display for CargoTomlNotFoundError {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(fmt, "a filesystem error occurred while searching for Cargo.toml: {}", self.1)
+        write!(
+            fmt,
+            "can't find Cargo.toml at {}, due to {}",
+            self.searched_at.display(),
+            self.reason
+        )
     }
 }
 
-impl Error for CargoTomlNoneFoundError {}
-impl Error for CargoTomlMultipleValidFoundError {}
-impl Error for CargoTomlSearchFileSystemError {}
+impl Error for CargoTomlNotFoundError {}
 
 #[derive(Debug, Clone)]
 pub enum ProjectWorkspace {
@@ -452,8 +440,6 @@ fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> {
 }
 
 fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
-    let path_as_buf = path.to_path_buf();
-
     if path.ends_with("Cargo.toml") {
         return Ok(path.to_path_buf());
     }
@@ -464,14 +450,31 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
 
     let entities = match read_dir(path) {
         Ok(entities) => entities,
-        Err(e) => return Err(CargoTomlSearchFileSystemError(path_as_buf, e.to_string()).into()),
+        Err(e) => {
+            return Err(CargoTomlNotFoundError {
+                searched_at: path.to_path_buf(),
+                reason: format!("file system error: {}", e),
+            }
+            .into());
+        }
     };
 
     let mut valid_canditates = find_cargo_toml_in_child_dir(entities);
     match valid_canditates.len() {
         1 => Ok(valid_canditates.remove(0)),
-        0 => Err(CargoTomlNoneFoundError(path_as_buf).into()),
-        _ => Err(CargoTomlMultipleValidFoundError(valid_canditates).into()),
+        0 => Err(CargoTomlNotFoundError {
+            searched_at: path.to_path_buf(),
+            reason: "no Cargo.toml file found".to_string(),
+        }
+        .into()),
+        _ => Err(CargoTomlNotFoundError {
+            searched_at: path.to_path_buf(),
+            reason: format!(
+                "multiple equally valid Cargo.toml files found: {:?}",
+                valid_canditates
+            ),
+        }
+        .into()),
     }
 }
 
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 37a46cd65..bcfeb6442 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -115,12 +115,17 @@ pub fn main_loop(
                     Ok(workspace) => loaded_workspaces.push(workspace),
                     Err(e) => {
                         log::error!("loading workspace failed: {:?}", e);
-                        if let Some(ra_project_model::CargoTomlNoneFoundError(_)) = e.downcast_ref()
+
+                        if let Some(ra_project_model::CargoTomlNotFoundError {
+                            searched_at: _,
+                            reason: _,
+                        }) = e.downcast_ref()
                         {
                             if !feature_flags.get("notifications.cargo-toml-not-found") {
                                 continue;
                             }
                         }
+
                         show_message(
                             req::MessageType::Error,
                             format!("rust-analyzer failed to load workspace: {:?}", e),
-- 
cgit v1.2.3


From b9fbb3da1740ddef0ab5d9dcbb75e50b92ba0c09 Mon Sep 17 00:00:00 2001
From: nmio <kristo.koert@gmail.com>
Date: Sat, 29 Feb 2020 13:14:31 +0000
Subject: lint warn fix

---
 crates/rust-analyzer/src/main_loop.rs | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index bcfeb6442..3d147d449 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -116,10 +116,8 @@ pub fn main_loop(
                     Err(e) => {
                         log::error!("loading workspace failed: {:?}", e);
 
-                        if let Some(ra_project_model::CargoTomlNotFoundError {
-                            searched_at: _,
-                            reason: _,
-                        }) = e.downcast_ref()
+                        if let Some(ra_project_model::CargoTomlNotFoundError { .. }) =
+                            e.downcast_ref()
                         {
                             if !feature_flags.get("notifications.cargo-toml-not-found") {
                                 continue;
-- 
cgit v1.2.3