Repository: rust-analyzer/rust-analyzer (rust)

Issue:
Handle std and prelude in name resolution
With the name resolution getting better, it's now more obvious that `std` is missing completely :) I guess we need to get the path to the rustup-installed std source code somehow. Of course that will also mean we have to parse a lot more code.

Once we have `std`, we should also import (basically) `std::prelude::v1::*` in every module.

Pull request:
support std
closes #465 

Patch:
diff --git a/.travis.yml b/.travis.yml
index 789adcbe38..12e4da4a30 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ build: &rust_build
     rust: 1.31.1
     script:
         - rustup component add rustfmt
+        - rustup component add rust-src
         - cargo gen-tests --verify
         - cargo gen-syntax --verify
         - cargo test --no-run  # let's measure compile time separately
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs
index 43bfa925a7..d7d5d5265c 100644
--- a/crates/ra_arena/src/lib.rs
+++ b/crates/ra_arena/src/lib.rs
@@ -35,12 +35,21 @@ impl fmt::Display for RawId {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct Arena<ID: ArenaId, T> {
     data: Vec<T>,
     _ty: PhantomData<ID>,
 }
 
+impl<ID: ArenaId, T: fmt::Debug> fmt::Debug for Arena<ID, T> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt.debug_struct("Arena")
+            .field("len", &self.len())
+            .field("data", &self.data)
+            .finish()
+    }
+}
+
 #[macro_export]
 macro_rules! impl_arena_id {
     ($name:ident) => {
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 069e7f932d..0dda9548a9 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -347,11 +347,11 @@ pub fn handle_runnables(
                 .read()
                 .file2path(ra_vfs::VfsFile(file_id.0.into()));
             let res = world.workspaces.iter().find_map(|ws| {
-                let tgt = ws.target_by_root(&path)?;
+                let tgt = ws.cargo.target_by_root(&path)?;
                 let res = CargoTargetSpec {
-                    package: tgt.package(ws).name(ws).to_string(),
-                    target: tgt.name(ws).to_string(),
-                    target_kind: tgt.kind(ws),
+                    package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(),
+                    target: tgt.name(&ws.cargo).to_string(),
+                    target_kind: tgt.kind(&ws.cargo),
                 };
                 Some(res)
             });
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs
index 9f429c9a1c..fd5875a0ab 100644
--- a/crates/ra_lsp_server/src/project_model.rs
+++ b/crates/ra_lsp_server/src/project_model.rs
@@ -1,163 +1,46 @@
+mod cargo_workspace;
+mod sysroot;
+
 use std::path::{Path, PathBuf};
 
-use cargo_metadata::{metadata_run, CargoOpt};
-use ra_syntax::SmolStr;
-use ra_arena::{Arena, RawId, impl_arena_id};
-use rustc_hash::FxHashMap;
-use failure::{format_err, bail};
+use failure::bail;
 use thread_worker::{WorkerHandle, Worker};
 
 use crate::Result;
 
-/// `CargoWorksapce` represents the logical structure of, well, a Cargo
-/// workspace. It pretty closely mirrors `cargo metadata` output.
-///
-/// Note that internally, rust analyzer uses a differnet structure:
-/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
-/// while this knows about `Pacakges` & `Targets`: purely cargo-related
-/// concepts.
-#[derive(Debug, Clone)]
-pub struct CargoWorkspace {
-    packages: Arena<Package, PackageData>,
-    targets: Arena<Target, TargetData>,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct Package(RawId);
-impl_arena_id!(Package);
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct Target(RawId);
-impl_arena_id!(Target);
-
-#[derive(Debug, Clone)]
-struct PackageData {
-    name: SmolStr,
-    manifest: PathBuf,
-    targets: Vec<Target>,
-    is_member: bool,
-    dependencies: Vec<PackageDependency>,
-}
+pub use crate::project_model::{
+    cargo_workspace::{CargoWorkspace, Package, Target, TargetKind},
+    sysroot::Sysroot,
+};
 
 #[derive(Debug, Clone)]
-pub struct PackageDependency {
-    pub pkg: Package,
-    pub name: SmolStr,
+pub struct ProjectWorkspace {
+    pub(crate) cargo: CargoWorkspace,
+    pub(crate) sysroot: Sysroot,
 }
 
-#[derive(Debug, Clone)]
-struct TargetData {
-    pkg: Package,
-    name: SmolStr,
-    root: PathBuf,
-    kind: TargetKind,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum TargetKind {
-    Bin,
-    Lib,
-    Example,
-    Test,
-    Bench,
-    Other,
-}
-
-impl Package {
-    pub fn name(self, ws: &CargoWorkspace) -> &str {
-        ws.packages[self].name.as_str()
-    }
-    pub fn root(self, ws: &CargoWorkspace) -> &Path {
-        ws.packages[self].manifest.parent().unwrap()
-    }
-    pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
-        ws.packages[self].targets.iter().cloned()
-    }
-    #[allow(unused)]
-    pub fn is_member(self, ws: &CargoWorkspace) -> bool {
-        ws.packages[self].is_member
-    }
-    pub fn dependencies<'a>(
-        self,
-        ws: &'a CargoWorkspace,
-    ) -> impl Iterator<Item = &'a PackageDependency> + 'a {
-        ws.packages[self].dependencies.iter()
-    }
-}
-
-impl Target {
-    pub fn package(self, ws: &CargoWorkspace) -> Package {
-        ws.targets[self].pkg
-    }
-    pub fn name(self, ws: &CargoWorkspace) -> &str {
-        ws.targets[self].name.as_str()
-    }
-    pub fn root(self, ws: &CargoWorkspace) -> &Path {
-        ws.targets[self].root.as_path()
-    }
-    pub fn kind(self, ws: &CargoWorkspace) -> TargetKind {
-        ws.targets[self].kind
+impl ProjectWorkspace {
+    pub fn discover(path: &Path) -> Result<ProjectWorkspace> {
+        let cargo_toml = find_cargo_toml(path)?;
+        let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?;
+        let sysroot = Sysroot::discover(&cargo_toml)?;
+        let res = ProjectWorkspace { cargo, sysroot };
+        Ok(res)
     }
 }
 
-impl CargoWorkspace {
-    pub fn from_cargo_metadata(path: &Path) -> Result<CargoWorkspace> {
-        let cargo_toml = find_cargo_toml(path)?;
-        let meta = metadata_run(
-            Some(cargo_toml.as_path()),
-            true,
-            Some(CargoOpt::AllFeatures),
-        )
-        .map_err(|e| format_err!("cargo metadata failed: {}", e))?;
-        let mut pkg_by_id = FxHashMap::default();
-        let mut packages = Arena::default();
-        let mut targets = Arena::default();
-
-        let ws_members = &meta.workspace_members;
-
-        for meta_pkg in meta.packages {
-            let is_member = ws_members.contains(&meta_pkg.id);
-            let pkg = packages.alloc(PackageData {
-                name: meta_pkg.name.into(),
-                manifest: meta_pkg.manifest_path.clone(),
-                targets: Vec::new(),
-                is_member,
-                dependencies: Vec::new(),
-            });
-            let pkg_data = &mut packages[pkg];
-            pkg_by_id.insert(meta_pkg.id.clone(), pkg);
-            for meta_tgt in meta_pkg.targets {
-                let tgt = targets.alloc(TargetData {
-                    pkg,
-                    name: meta_tgt.name.into(),
-                    root: meta_tgt.src_path.clone(),
-                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
-                });
-                pkg_data.targets.push(tgt);
-            }
-        }
-        let resolve = meta.resolve.expect("metadata executed with deps");
-        for node in resolve.nodes {
-            let source = pkg_by_id[&node.id];
-            for dep_node in node.deps {
-                let dep = PackageDependency {
-                    name: dep_node.name.into(),
-                    pkg: pkg_by_id[&dep_node.pkg],
-                };
-                packages[source].dependencies.push(dep);
-            }
-        }
-
-        Ok(CargoWorkspace { packages, targets })
-    }
-    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a {
-        self.packages.iter().map(|(id, _pkg)| id)
-    }
-    pub fn target_by_root(&self, root: &Path) -> Option<Target> {
-        self.packages()
-            .filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
-            .next()
-    }
+pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) {
+    thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>(
+        "workspace loader",
+        1,
+        |input_receiver, output_sender| {
+            input_receiver
+                .into_iter()
+                .map(|path| ProjectWorkspace::discover(path.as_path()))
+                .try_for_each(|it| output_sender.send(it))
+                .unwrap()
+        },
+    )
 }
 
 fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
@@ -174,33 +57,3 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
     }
     bail!("can't find Cargo.toml at {}", path.display())
 }
-
-impl TargetKind {
-    fn new(kinds: &[String]) -> TargetKind {
-        for kind in kinds {
-            return match kind.as_str() {
-                "bin" => TargetKind::Bin,
-                "test" => TargetKind::Test,
-                "bench" => TargetKind::Bench,
-                "example" => TargetKind::Example,
-                _ if kind.contains("lib") => TargetKind::Lib,
-                _ => continue,
-            };
-        }
-        TargetKind::Other
-    }
-}
-
-pub fn workspace_loader() -> (Worker<PathBuf, Result<CargoWorkspace>>, WorkerHandle) {
-    thread_worker::spawn::<PathBuf, Result<CargoWorkspace>, _>(
-        "workspace loader",
-        1,
-        |input_receiver, output_sender| {
-            input_receiver
-                .into_iter()
-                .map(|path| CargoWorkspace::from_cargo_metadata(path.as_path()))
-                .try_for_each(|it| output_sender.send(it))
-                .unwrap()
-        },
-    )
-}
diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
new file mode 100644
index 0000000000..8f75188607
--- /dev/null
+++ b/crates/ra_lsp_server/src/project_model/cargo_workspace.rs
@@ -0,0 +1,171 @@
+use std::path::{Path, PathBuf};
+
+use cargo_metadata::{metadata_run, CargoOpt};
+use ra_syntax::SmolStr;
+use ra_arena::{Arena, RawId, impl_arena_id};
+use rustc_hash::FxHashMap;
+use failure::format_err;
+
+use crate::Result;
+
+/// `CargoWorksapce` represents the logical structure of, well, a Cargo
+/// workspace. It pretty closely mirrors `cargo metadata` output.
+///
+/// Note that internally, rust analyzer uses a differnet structure:
+/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
+/// while this knows about `Pacakges` & `Targets`: purely cargo-related
+/// concepts.
+#[derive(Debug, Clone)]
+pub struct CargoWorkspace {
+    packages: Arena<Package, PackageData>,
+    targets: Arena<Target, TargetData>,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct Package(RawId);
+impl_arena_id!(Package);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct Target(RawId);
+impl_arena_id!(Target);
+
+#[derive(Debug, Clone)]
+struct PackageData {
+    name: SmolStr,
+    manifest: PathBuf,
+    targets: Vec<Target>,
+    is_member: bool,
+    dependencies: Vec<PackageDependency>,
+}
+
+#[derive(Debug, Clone)]
+pub struct PackageDependency {
+    pub pkg: Package,
+    pub name: SmolStr,
+}
+
+#[derive(Debug, Clone)]
+struct TargetData {
+    pkg: Package,
+    name: SmolStr,
+    root: PathBuf,
+    kind: TargetKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum TargetKind {
+    Bin,
+    Lib,
+    Example,
+    Test,
+    Bench,
+    Other,
+}
+
+impl TargetKind {
+    fn new(kinds: &[String]) -> TargetKind {
+        for kind in kinds {
+            return match kind.as_str() {
+                "bin" => TargetKind::Bin,
+                "test" => TargetKind::Test,
+                "bench" => TargetKind::Bench,
+                "example" => TargetKind::Example,
+                _ if kind.contains("lib") => TargetKind::Lib,
+                _ => continue,
+            };
+        }
+        TargetKind::Other
+    }
+}
+
+impl Package {
+    pub fn name(self, ws: &CargoWorkspace) -> &str {
+        ws.packages[self].name.as_str()
+    }
+    pub fn root(self, ws: &CargoWorkspace) -> &Path {
+        ws.packages[self].manifest.parent().unwrap()
+    }
+    pub fn targets<'a>(self, ws: &'a CargoWorkspace) -> impl Iterator<Item = Target> + 'a {
+        ws.packages[self].targets.iter().cloned()
+    }
+    #[allow(unused)]
+    pub fn is_member(self, ws: &CargoWorkspace) -> bool {
+        ws.packages[self].is_member
+    }
+    pub fn dependencies<'a>(
+        self,
+        ws: &'a CargoWorkspace,
+    ) -> impl Iterator<Item = &'a PackageDependency> + 'a {
+        ws.packages[self].dependencies.iter()
+    }
+}
+
+impl Target {
+    pub fn package(self, ws: &CargoWorkspace) -> Package {
+        ws.targets[self].pkg
+    }
+    pub fn name(self, ws: &CargoWorkspace) -> &str {
+        ws.targets[self].name.as_str()
+    }
+    pub fn root(self, ws: &CargoWorkspace) -> &Path {
+        ws.targets[self].root.as_path()
+    }
+    pub fn kind(self, ws: &CargoWorkspace) -> TargetKind {
+        ws.targets[self].kind
+    }
+}
+
+impl CargoWorkspace {
+    pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> {
+        let meta = metadata_run(Some(cargo_toml), true, Some(CargoOpt::AllFeatures))
+            .map_err(|e| format_err!("cargo metadata failed: {}", e))?;
+        let mut pkg_by_id = FxHashMap::default();
+        let mut packages = Arena::default();
+        let mut targets = Arena::default();
+
+        let ws_members = &meta.workspace_members;
+
+        for meta_pkg in meta.packages {
+            let is_member = ws_members.contains(&meta_pkg.id);
+            let pkg = packages.alloc(PackageData {
+                name: meta_pkg.name.into(),
+                manifest: meta_pkg.manifest_path.clone(),
+                targets: Vec::new(),
+                is_member,
+                dependencies: Vec::new(),
+            });
+            let pkg_data = &mut packages[pkg];
+            pkg_by_id.insert(meta_pkg.id.clone(), pkg);
+            for meta_tgt in meta_pkg.targets {
+                let tgt = targets.alloc(TargetData {
+                    pkg,
+                    name: meta_tgt.name.into(),
+                    root: meta_tgt.src_path.clone(),
+                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
+                });
+                pkg_data.targets.push(tgt);
+            }
+        }
+        let resolve = meta.resolve.expect("metadata executed with deps");
+        for node in resolve.nodes {
+            let source = pkg_by_id[&node.id];
+            for dep_node in node.deps {
+                let dep = PackageDependency {
+                    name: dep_node.name.into(),
+                    pkg: pkg_by_id[&dep_node.pkg],
+                };
+                packages[source].dependencies.push(dep);
+            }
+        }
+
+        Ok(CargoWorkspace { packages, targets })
+    }
+    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a {
+        self.packages.iter().map(|(id, _pkg)| id)
+    }
+    pub fn target_by_root(&self, root: &Path) -> Option<Target> {
+        self.packages()
+            .filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root))
+            .next()
+    }
+}
diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs
new file mode 100644
index 0000000000..1dbab57f82
--- /dev/null
+++ b/crates/ra_lsp_server/src/project_model/sysroot.rs
@@ -0,0 +1,132 @@
+use std::{
+    path::{Path, PathBuf},
+    process::Command,
+};
+
+use ra_syntax::SmolStr;
+use ra_arena::{Arena, RawId, impl_arena_id};
+
+use crate::Result;
+
+#[derive(Debug, Clone)]
+pub struct Sysroot {
+    crates: Arena<SysrootCrate, SysrootCrateData>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SysrootCrate(RawId);
+impl_arena_id!(SysrootCrate);
+
+#[derive(Debug, Clone)]
+struct SysrootCrateData {
+    name: SmolStr,
+    root: PathBuf,
+    deps: Vec<SysrootCrate>,
+}
+
+impl Sysroot {
+    pub(crate) fn std(&self) -> Option<SysrootCrate> {
+        self.by_name("std")
+    }
+
+    pub(crate) fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a {
+        self.crates.iter().map(|(id, _data)| id)
+    }
+
+    pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> {
+        let rustc_output = Command::new("rustc")
+            .current_dir(cargo_toml.parent().unwrap())
+            .args(&["--print", "sysroot"])
+            .output()?;
+        if !rustc_output.status.success() {
+            failure::bail!("failed to locate sysroot")
+        }
+        let stdout = String::from_utf8(rustc_output.stdout)?;
+        let sysroot_path = Path::new(stdout.trim());
+        let src = sysroot_path.join("lib/rustlib/src/rust/src");
+
+        let mut sysroot = Sysroot {
+            crates: Arena::default(),
+        };
+        for name in SYSROOT_CRATES.trim().lines() {
+            let root = src.join(format!("lib{}", name)).join("lib.rs");
+            if root.exists() {
+                sysroot.crates.alloc(SysrootCrateData {
+                    name: name.into(),
+                    root,
+                    deps: Vec::new(),
+                });
+            }
+        }
+        if let Some(std) = sysroot.std() {
+            for dep in STD_DEPS.trim().lines() {
+                if let Some(dep) = sysroot.by_name(dep) {
+                    sysroot.crates[std].deps.push(dep)
+                }
+            }
+        }
+        Ok(sysroot)
+    }
+
+    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
+        self.crates
+            .iter()
+            .find(|(_id, data)| data.name == name)
+            .map(|(id, _data)| id)
+    }
+}
+
+impl SysrootCrate {
+    pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr {
+        &sysroot.crates[self].name
+    }
+    pub(crate) fn root(self, sysroot: &Sysroot) -> &Path {
+        sysroot.crates[self].root.as_path()
+    }
+    pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path {
+        self.root(sysroot).parent().unwrap()
+    }
+    pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a {
+        sysroot.crates[self].deps.iter().map(|&it| it)
+    }
+}
+
+const SYSROOT_CRATES: &str = "
+std
+core
+alloc
+collections
+libc
+panic_unwind
+proc_macro
+rustc_unicode
+std_unicode
+test
+alloc_jemalloc
+alloc_system
+compiler_builtins
+getopts
+panic_unwind
+panic_abort
+rand
+term
+unwind
+build_helper
+rustc_asan
+rustc_lsan
+rustc_msan
+rustc_tsan
+syntax";
+
+const STD_DEPS: &str = "
+alloc_jemalloc
+alloc_system
+panic_abort
+rand
+compiler_builtins
+unwind
+rustc_asan
+rustc_lsan
+rustc_msan
+rustc_tsan
+build_helper";
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index 76c76766d3..4f3c231d31 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -15,7 +15,7 @@ use parking_lot::RwLock;
 use failure::format_err;
 
 use crate::{
-    project_model::{CargoWorkspace, TargetKind},
+    project_model::{ProjectWorkspace, TargetKind},
     Result,
 };
 
@@ -23,28 +23,33 @@ use crate::{
 pub struct ServerWorldState {
     pub roots_to_scan: usize,
     pub root: PathBuf,
-    pub workspaces: Arc<Vec<CargoWorkspace>>,
+    pub workspaces: Arc<Vec<ProjectWorkspace>>,
     pub analysis_host: AnalysisHost,
     pub vfs: Arc<RwLock<Vfs>>,
 }
 
 pub struct ServerWorld {
-    pub workspaces: Arc<Vec<CargoWorkspace>>,
+    pub workspaces: Arc<Vec<ProjectWorkspace>>,
     pub analysis: Analysis,
     pub vfs: Arc<RwLock<Vfs>>,
 }
 
 impl ServerWorldState {
-    pub fn new(root: PathBuf, workspaces: Vec<CargoWorkspace>) -> ServerWorldState {
+    pub fn new(root: PathBuf, workspaces: Vec<ProjectWorkspace>) -> ServerWorldState {
         let mut change = AnalysisChange::new();
 
         let mut roots = Vec::new();
         roots.push(root.clone());
         for ws in workspaces.iter() {
-            for pkg in ws.packages() {
-                roots.push(pkg.root(&ws).to_path_buf());
+            for pkg in ws.cargo.packages() {
+                roots.push(pkg.root(&ws.cargo).to_path_buf());
+            }
+            for krate in ws.sysroot.crates() {
+                roots.push(krate.root_dir(&ws.sysroot).to_path_buf())
             }
         }
+        roots.sort();
+        roots.dedup();
         let roots_to_scan = roots.len();
         let (mut vfs, roots) = Vfs::new(roots);
         for r in roots {
@@ -53,16 +58,43 @@ impl ServerWorldState {
         }
 
         let mut crate_graph = CrateGraph::default();
-        let mut pkg_to_lib_crate = FxHashMap::default();
-        let mut pkg_crates = FxHashMap::default();
         for ws in workspaces.iter() {
-            for pkg in ws.packages() {
-                for tgt in pkg.targets(ws) {
-                    let root = tgt.root(ws);
+            // First, load std
+            let mut sysroot_crates = FxHashMap::default();
+            for krate in ws.sysroot.crates() {
+                if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) {
+                    let file_id = FileId(file_id.0.into());
+                    sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id));
+                }
+            }
+            for from in ws.sysroot.crates() {
+                for to in from.deps(&ws.sysroot) {
+                    let name = to.name(&ws.sysroot);
+                    if let (Some(&from), Some(&to)) =
+                        (sysroot_crates.get(&from), sysroot_crates.get(&to))
+                    {
+                        crate_graph.add_dep(from, name.clone(), to);
+                    }
+                }
+            }
+
+            let libstd = ws
+                .sysroot
+                .std()
+                .and_then(|it| sysroot_crates.get(&it).map(|&it| it));
+
+            let mut pkg_to_lib_crate = FxHashMap::default();
+            let mut pkg_crates = FxHashMap::default();
+            // Next, create crates for each package, target pair
+            for pkg in ws.cargo.packages() {
+                let mut lib_tgt = None;
+                for tgt in pkg.targets(&ws.cargo) {
+                    let root = tgt.root(&ws.cargo);
                     if let Some(file_id) = vfs.load(root) {
                         let file_id = FileId(file_id.0.into());
                         let crate_id = crate_graph.add_crate_root(file_id);
-                        if tgt.kind(ws) == TargetKind::Lib {
+                        if tgt.kind(&ws.cargo) == TargetKind::Lib {
+                            lib_tgt = Some(crate_id);
                             pkg_to_lib_crate.insert(pkg, crate_id);
                         }
                         pkg_crates
@@ -71,9 +103,24 @@ impl ServerWorldState {
                             .push(crate_id);
                     }
                 }
+
+                // Set deps to the std and to the lib target of the current package
+                for &from in pkg_crates.get(&pkg).into_iter().flatten() {
+                    if let Some(to) = lib_tgt {
+                        if to != from {
+                            crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to);
+                        }
+                    }
+                    if let Some(std) = libstd {
+                        crate_graph.add_dep(from, "std".into(), std);
+                    }
+                }
             }
-            for pkg in ws.packages() {
-                for dep in pkg.dependencies(ws) {
+
+            // Now add a dep ednge from all targets of upstream to the lib
+            // target of downstream.
+            for pkg in ws.cargo.packages() {
+                for dep in pkg.dependencies(&ws.cargo) {
                     if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
                         for &from in pkg_crates.get(&pkg).into_iter().flatten() {
                             crate_graph.add_dep(from, dep.name.clone(), to);


Test patch:
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 9eaf46ac87..02d62a2591 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -1,10 +1,15 @@
 mod support;
 
+use std::{
+    collections::HashMap,
+    time::Instant,
+};
+
 use languageserver_types::{
     CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range,
 };
 use ra_lsp_server::req::{
-    CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams,
+    CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion,
 };
 use serde_json::json;
 
@@ -12,6 +17,32 @@ use crate::support::project;
 
 const LOG: &'static str = "";
 
+#[test]
+fn completes_items_from_standard_library() {
+    let project_start = Instant::now();
+    let server = project(
+        r#"
+//- Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- src/lib.rs
+use std::collections::Spam;
+"#,
+    );
+    server.wait_for_feedback("workspace loaded");
+    eprintln!("loading took    {:?}", project_start.elapsed());
+    let completion_start = Instant::now();
+    let res = server.send_request::<Completion>(CompletionParams {
+        text_document: server.doc_id("src/lib.rs"),
+        context: None,
+        position: Position::new(0, 23),
+    });
+    assert!(format!("{}", res).contains("HashMap"));
+    eprintln!("completion took {:?}", completion_start.elapsed());
+}
+
 #[test]
 fn test_runnables_no_project() {
     let server = project(
@@ -122,7 +153,6 @@ fn test_eggs() {}
     );
 }
 
-use std::collections::HashMap;
 #[test]
 fn test_format_document() {
     let server = project(
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index 7db168b0f2..46107b6b60 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -93,9 +93,7 @@ impl Server {
         R: Request,
         R::Params: Serialize,
     {
-        let id = self.req_id.get();
-        self.req_id.set(id + 1);
-        let actual = self.send_request::<R>(id, params);
+        let actual = self.send_request::<R>(params);
         match find_mismatch(&expected_resp, &actual) {
             Some((expected_part, actual_part)) => panic!(
                 "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
@@ -108,11 +106,14 @@ impl Server {
         }
     }
 
-    fn send_request<R>(&self, id: u64, params: R::Params) -> Value
+    pub fn send_request<R>(&self, params: R::Params) -> Value
     where
         R: Request,
         R::Params: Serialize,
     {
+        let id = self.req_id.get();
+        self.req_id.set(id + 1);
+
         let r = RawRequest::new::<R>(id, &params);
         self.send_request_(r)
     }
@@ -178,7 +179,7 @@ impl Server {
 
 impl Drop for Server {
     fn drop(&mut self) {
-        self.send_request::<Shutdown>(666, ());
+        self.send_request::<Shutdown>(());
         let receiver = self.worker.take().unwrap().shutdown();
         while let Some(msg) = recv_timeout(&receiver) {
             drop(msg);
@@ -188,7 +189,7 @@ impl Drop for Server {
 }
 
 fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
-    let timeout = Duration::from_secs(5);
+    let timeout = Duration::from_secs(50);
     select! {
         recv(receiver) -> msg => msg.ok(),
         recv(after(timeout)) -> _ => panic!("timed out"),