Skip to content

Pluggable project model #910

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ path = "src/racer/lib.rs"
name = "racer"
path = "src/bin/main.rs"
doc = false
required-features = ["cargo"]

[profile.release]
debug = true

[dependencies]
bitflags = "1.0"
cargo = "0.28"
cargo = { version = "0.28", optional = true }
log = "0.4"
rustc-ap-syntax = "209.0.0"
env_logger = "0.5"
Expand All @@ -37,6 +38,7 @@ path = "testutils"


[features]
default = ["cargo"]
nightly = []

[workspace]
Expand Down
2 changes: 1 addition & 1 deletion src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ impl Interface {
},
Message::Point(point) => println!("POINT{}{}", self.leading_space(), point),
Message::Coords(coord) => {
println!("COORD{lead}{}{field}{}",
println!("COORD{lead}{}{field}{}",
coord.row.0,
coord.col.0,
lead = self.leading_space(),
Expand Down
100 changes: 18 additions & 82 deletions src/racer/core.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use cargo::core::Resolve;
use rls_span;
use syntax::codemap;
use std::fs::File;
Expand All @@ -7,14 +6,15 @@ use std::{vec, fmt};
use std::{str, path};
use std::io;
use std::cell::RefCell;
use std::collections::{hash_map, HashMap};
use std::collections::HashMap;
use std::ops::{Deref, Range};
use std::slice;
use std::cmp::{min, max, Ordering};
use std::iter::{Fuse, Iterator};
use std::rc::Rc;
use codeiter::StmtIndicesIter;
use matchers::ImportInfo;
use project_model::ProjectModelProvider;

use scopes;
use nameres;
Expand Down Expand Up @@ -261,7 +261,7 @@ impl Match {
/// but in the interest of minimizing the crate's public API surface it's exposed
/// as a private method for now.
fn is_same_as(&self, other: &Match) -> bool {
self.point == other.point
self.point == other.point
&& self.matchstr == other.matchstr
&& self.filepath == other.filepath
}
Expand Down Expand Up @@ -560,7 +560,7 @@ impl IndexedSource {
lines: RefCell::new(Vec::new())
}
}

pub fn with_src(&self, new_src: String) -> IndexedSource {
IndexedSource {
code: new_src,
Expand Down Expand Up @@ -704,7 +704,7 @@ impl<'c> Src<'c> {
pub fn end(&self) -> BytePos {
self.range.end
}

pub fn iter_stmts(&self) -> Fuse<StmtIndicesIter<CodeChunkIter>> {
StmtIndicesIter::from_parts(self, self.chunk_indices())
}
Expand Down Expand Up @@ -796,7 +796,7 @@ pub struct FileCache {
masked_map: RefCell<HashMap<path::PathBuf, Rc<IndexedSource>>>,

/// The file loader
loader: Box<FileLoader>,
pub(crate) loader: Box<FileLoader>,
}

/// Used by the FileCache for loading files
Expand Down Expand Up @@ -920,23 +920,6 @@ pub trait SessionExt {
fn load_file_and_mask_comments(&self, &path::Path) -> Rc<IndexedSource>;
}

/// dependencies info of a package
#[derive(Clone, Debug, Default)]
pub struct Dependencies {
/// dependencies of a package(library name -> src_path)
inner: HashMap<String, path::PathBuf>,
}

impl Dependencies {
/// Get src path from a library name.
/// e.g. from query string `bit_set` it returns
/// `~/.cargo/registry/src/github.1485827954.workers.dev-1ecc6299db9ec823/bit-set-0.4.0`
pub fn get_src_path(&self, query: &str) -> Option<path::PathBuf> {
let p = self.inner.get(query)?;
Some(p.to_owned())
}
}

/// Context for a Racer operation
pub struct Session<'c> {
/// Cache for files
Expand All @@ -948,10 +931,7 @@ pub struct Session<'c> {
pub generic_impls: RefCell<HashMap<(path::PathBuf, BytePos),
Rc<Vec<(BytePos, String,
ast::GenericsArgs, ast::ImplVisitor)>>>>,
/// Cached dependencie (path to Cargo.toml -> Depedencies)
cached_deps: RefCell<HashMap<path::PathBuf, Rc<Dependencies>>>,
/// Cached lockfiles (path to Cargo.lock -> Resolve)
cached_lockfile: RefCell<HashMap<path::PathBuf, Rc<Resolve>>>,
pub project_model: Box<ProjectModelProvider + 'c>,
}

impl<'c> fmt::Debug for Session<'c> {
Expand All @@ -976,15 +956,19 @@ impl<'c> Session<'c> {
/// ```
///
/// [`FileCache`]: struct.FileCache.html
#[cfg(feature = "cargo")]
pub fn new(cache: &'c FileCache) -> Session<'c> {
let project_model = ::project_model::cargo::cargo_project_model(cache);
Session::with_project_model(cache, project_model)
}

pub fn with_project_model(cache: &'c FileCache, project_model: Box<ProjectModelProvider + 'c>) -> Session<'c> {
Session {
cache,
generic_impls: Default::default(),
cached_deps: Default::default(),
cached_lockfile: Default::default(),
project_model,
}
}

/// Specify the contents of a file to be used in completion operations
///
/// The path to the file and the file's contents must both be specified.
Expand Down Expand Up @@ -1012,54 +996,6 @@ impl<'c> Session<'c> {
let masked = self.cache.masked_map.borrow();
raw.contains_key(path) && masked.contains_key(path)
}

/// Get cached dependencies from manifest path(abs path of Cargo.toml) if they exist.
pub(crate) fn get_deps<P: AsRef<path::Path>>(&self, manifest: P) -> Option<Rc<Dependencies>> {
let manifest = manifest.as_ref();
let deps = self.cached_deps.borrow();
deps.get(manifest).map(|rc| Rc::clone(&rc))
}

/// Cache dependencies into session.
pub(crate) fn cache_deps<P: AsRef<path::Path>>(
&self,
manifest: P,
cache: HashMap<String, path::PathBuf>,
) {
let manifest = manifest.as_ref().to_owned();
let deps = Dependencies {
inner: cache,
};
self.cached_deps.borrow_mut().insert(manifest, Rc::new(deps));
}

/// load `Cargo.lock` file using fileloader
// TODO: use result
pub(crate) fn load_lockfile<P, F>(&self, path: P, resolver: F) -> Option<Rc<Resolve>>
where
P: AsRef<path::Path>,
F: FnOnce(&str) -> Option<Resolve>
{
let pathbuf = path.as_ref().to_owned();
match self.cached_lockfile.borrow_mut().entry(pathbuf) {
hash_map::Entry::Occupied(occupied) => Some(Rc::clone(occupied.get())),
hash_map::Entry::Vacant(vacant) => {
let contents = match self.cache.loader.load_file(path.as_ref()) {
Ok(f) => f,
Err(e) => {
debug!(
"[Session::load_lock_file] Failed to load {:?}: {}",
path.as_ref(),
e
);
return None;
}
};
resolver(&contents)
.map(|res| Rc::clone(vacant.insert(Rc::new(res))))
}
}
}
}

impl<'c> SessionExt for Session<'c> {
Expand Down Expand Up @@ -1257,10 +1193,10 @@ fn complete_from_file_(
trace!("Path is in fn declaration: `{}`", expr);

return nameres::resolve_method(
pos,
src.as_src(),
expr,
filepath,
pos,
src.as_src(),
expr,
filepath,
SearchType::StartsWith,
session,
&ImportInfo::default(),
Expand Down
116 changes: 2 additions & 114 deletions src/racer/fileres.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
use cargo::core::{
PackageSet, PackageId, registry::PackageRegistry,
resolver::{EncodableResolve, Method, Resolve}, Workspace
};
use cargo::ops;
use cargo::util::{errors::CargoResult, important_paths::find_root_manifest_for_wd, toml};
use cargo::Config;
use core::Session;
use nameres::RUST_SRC_PATH;
use std::collections::HashSet;
use std::path::{Path, PathBuf};

/// get crate file from current path & crate name
Expand Down Expand Up @@ -54,18 +46,6 @@ pub fn get_module_file(name: &str, parentdir: &Path, session: &Session) -> Optio
None
}

macro_rules! cargo_try {
($r:expr) => {
match $r {
Ok(val) => val,
Err(err) => {
warn!("Error in cargo: {}", err);
return None;
}
}
};
}

/// try to get outer crates
/// if we have dependencies in cache, use it.
/// else, call cargo's function to resolve depndencies.
Expand All @@ -75,98 +55,6 @@ fn get_outer_crates(libname: &str, from_path: &Path, session: &Session) -> Optio
libname, from_path
);

let manifest = cargo_try!(find_root_manifest_for_wd(from_path));
if let Some(deps_info) = session.get_deps(&manifest) {
// cache exists
debug!("[get_outer_crates] cache exists for manifest",);
deps_info.get_src_path(libname)
} else {
// cache doesn't exist
let manifest = cargo_try!(find_root_manifest_for_wd(from_path));
// calucurating depedencies can be bottleneck we use info! here(kngwyu)
info!("[get_outer_crates] cache doesn't exist");
resolve_dependencies(&manifest, session, libname)
}
}

fn resolve_dependencies(manifest: &Path, session: &Session, libname: &str) -> Option<PathBuf> {
let mut config = cargo_try!(Config::default());
// frozen=true, locked=true
config.configure(0, Some(true), &None, true, true, &None, &[]).ok()?;
let ws = cargo_try!(Workspace::new(&manifest, &config));
// get resolve from lock file
let lock_path = ws.root().to_owned().join("Cargo.lock");
let lock_file = session.load_lockfile(&lock_path, |lockfile| {
let resolve = cargo_try!(toml::parse(&lockfile, &lock_path, ws.config()));
let v: EncodableResolve = cargo_try!(resolve.try_into());
Some(cargo_try!(v.into_resolve(&ws)))
});
// then resolve precisely and add overrides
let mut registry = cargo_try!(PackageRegistry::new(ws.config()));
let resolve = cargo_try!(match lock_file {
Some(prev) => resolve_with_prev(&mut registry, &ws, Some(&*prev)),
None => resolve_with_prev(&mut registry, &ws, None),
});
let packages = get_resolved_packages(&resolve, registry);
let mut res = None;
// we have caches for each crates, so only need depth1 depedencies(= dependencies in Cargo.toml)
let depth1_dependencies = match ws.current_opt() {
Some(cur) => cur.dependencies().iter().map(|p| p.name()).collect(),
None => HashSet::new(),
};
let current_pkg = ws.current().map(|pkg| pkg.name());
let is_current_pkg = |name| {
if let Ok(n) = current_pkg {
n == name
} else {
false
}
};
let deps_map = packages
.package_ids()
.filter_map(|package_id| {
let pkg = packages.get(package_id).ok()?;
let pkg_name = pkg.name();
// for examples/ or tests/ dir, we have to handle current package specially
if !is_current_pkg(pkg_name) && !depth1_dependencies.contains(&pkg.name()) {
return None;
}
let targets = pkg.manifest().targets();
// we only need library target
let lib_target = targets.into_iter().find(|target| target.is_lib())?;
// crate_name returns target.name.replace("-", "_")
let crate_name = lib_target.crate_name();
let src_path = lib_target.src_path().to_owned();
if crate_name == libname {
res = Some(src_path.clone());
}
Some((crate_name, src_path))
})
.collect();
session.cache_deps(manifest, deps_map);
res
}

// wrapper of resolve_with_previous
fn resolve_with_prev<'cfg>(
registry: &mut PackageRegistry<'cfg>,
ws: &Workspace<'cfg>,
prev: Option<&Resolve>,
) -> CargoResult<Resolve> {
ops::resolve_with_previous(
registry,
ws,
Method::Everything,
prev,
None,
&[],
true,
false,
)
}

// until cargo 0.30 is released
fn get_resolved_packages<'a>(resolve: &Resolve, registry: PackageRegistry<'a>) -> PackageSet<'a> {
let ids: Vec<PackageId> = resolve.iter().cloned().collect();
registry.get(&ids)
let manifest = session.project_model.discover_project_manifest(from_path)?;
session.project_model.resolve_dependency(&manifest, libname)
}
3 changes: 2 additions & 1 deletion src/racer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ extern crate lazy_static;
#[macro_use]
extern crate bitflags;

extern crate cargo;
extern crate syntax;
#[macro_use]
extern crate derive_more;
Expand All @@ -29,12 +28,14 @@ mod codecleaner;
mod matchers;
mod snippets;
mod fileres;
mod project_model;

pub use core::{find_definition, complete_from_file, complete_fully_qualified_name, to_point, to_coords};
pub use snippets::snippet_for_match;
pub use core::{Match, MatchType, PathSearch};
pub use core::{FileCache, Session, Coordinate, Location, FileLoader, BytePos, ByteRange};
pub use util::expand_ident;
pub use project_model::ProjectModelProvider;

pub use util::{RustSrcPathError, get_rust_src_path};

Expand Down
Loading