Skip to content

Commit 49ec264

Browse files
committed
Introduce ProjectModelProvider
This is mainly for RLS which would love to be a single source of truth for project info, and which would rather link to a single copy of Cargo. However, it might also be possible to use other things as sources of project information, for example, `cargo metadata` or Bazel/Buck build rules.
1 parent 5aab964 commit 49ec264

File tree

6 files changed

+247
-199
lines changed

6 files changed

+247
-199
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ path = "src/racer/lib.rs"
1515
name = "racer"
1616
path = "src/bin/main.rs"
1717
doc = false
18+
required-features = ["cargo"]
1819

1920
[profile.release]
2021
debug = true
2122

2223
[dependencies]
2324
bitflags = "1.0"
24-
cargo = "0.28"
25+
cargo = { version = "0.28", optional = true }
2526
log = "0.4"
2627
rustc-ap-syntax = "209.0.0"
2728
env_logger = "0.5"
@@ -37,6 +38,7 @@ path = "testutils"
3738

3839

3940
[features]
41+
default = ["cargo"]
4042
nightly = []
4143

4244
[workspace]

src/bin/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ impl Interface {
271271
},
272272
Message::Point(point) => println!("POINT{}{}", self.leading_space(), point),
273273
Message::Coords(coord) => {
274-
println!("COORD{lead}{}{field}{}",
274+
println!("COORD{lead}{}{field}{}",
275275
coord.row.0,
276276
coord.col.0,
277277
lead = self.leading_space(),

src/racer/core.rs

Lines changed: 18 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use cargo::core::Resolve;
21
use rls_span;
32
use syntax::codemap;
43
use std::fs::File;
@@ -7,14 +6,15 @@ use std::{vec, fmt};
76
use std::{str, path};
87
use std::io;
98
use std::cell::RefCell;
10-
use std::collections::{hash_map, HashMap};
9+
use std::collections::HashMap;
1110
use std::ops::{Deref, Range};
1211
use std::slice;
1312
use std::cmp::{min, max, Ordering};
1413
use std::iter::{Fuse, Iterator};
1514
use std::rc::Rc;
1615
use codeiter::StmtIndicesIter;
1716
use matchers::ImportInfo;
17+
use project_model::ProjectModelProvider;
1818

1919
use scopes;
2020
use nameres;
@@ -261,7 +261,7 @@ impl Match {
261261
/// but in the interest of minimizing the crate's public API surface it's exposed
262262
/// as a private method for now.
263263
fn is_same_as(&self, other: &Match) -> bool {
264-
self.point == other.point
264+
self.point == other.point
265265
&& self.matchstr == other.matchstr
266266
&& self.filepath == other.filepath
267267
}
@@ -560,7 +560,7 @@ impl IndexedSource {
560560
lines: RefCell::new(Vec::new())
561561
}
562562
}
563-
563+
564564
pub fn with_src(&self, new_src: String) -> IndexedSource {
565565
IndexedSource {
566566
code: new_src,
@@ -704,7 +704,7 @@ impl<'c> Src<'c> {
704704
pub fn end(&self) -> BytePos {
705705
self.range.end
706706
}
707-
707+
708708
pub fn iter_stmts(&self) -> Fuse<StmtIndicesIter<CodeChunkIter>> {
709709
StmtIndicesIter::from_parts(self, self.chunk_indices())
710710
}
@@ -796,7 +796,7 @@ pub struct FileCache {
796796
masked_map: RefCell<HashMap<path::PathBuf, Rc<IndexedSource>>>,
797797

798798
/// The file loader
799-
loader: Box<FileLoader>,
799+
pub(crate) loader: Box<FileLoader>,
800800
}
801801

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

923-
/// dependencies info of a package
924-
#[derive(Clone, Debug, Default)]
925-
pub struct Dependencies {
926-
/// dependencies of a package(library name -> src_path)
927-
inner: HashMap<String, path::PathBuf>,
928-
}
929-
930-
impl Dependencies {
931-
/// Get src path from a library name.
932-
/// e.g. from query string `bit_set` it returns
933-
/// `~/.cargo/registry/src/github.1485827954.workers.dev-1ecc6299db9ec823/bit-set-0.4.0`
934-
pub fn get_src_path(&self, query: &str) -> Option<path::PathBuf> {
935-
let p = self.inner.get(query)?;
936-
Some(p.to_owned())
937-
}
938-
}
939-
940923
/// Context for a Racer operation
941924
pub struct Session<'c> {
942925
/// Cache for files
@@ -948,10 +931,7 @@ pub struct Session<'c> {
948931
pub generic_impls: RefCell<HashMap<(path::PathBuf, BytePos),
949932
Rc<Vec<(BytePos, String,
950933
ast::GenericsArgs, ast::ImplVisitor)>>>>,
951-
/// Cached dependencie (path to Cargo.toml -> Depedencies)
952-
cached_deps: RefCell<HashMap<path::PathBuf, Rc<Dependencies>>>,
953-
/// Cached lockfiles (path to Cargo.lock -> Resolve)
954-
cached_lockfile: RefCell<HashMap<path::PathBuf, Rc<Resolve>>>,
934+
pub project_model: Box<ProjectModelProvider + 'c>,
955935
}
956936

957937
impl<'c> fmt::Debug for Session<'c> {
@@ -976,15 +956,19 @@ impl<'c> Session<'c> {
976956
/// ```
977957
///
978958
/// [`FileCache`]: struct.FileCache.html
959+
#[cfg(feature = "cargo")]
979960
pub fn new(cache: &'c FileCache) -> Session<'c> {
961+
let project_model = ::project_model::cargo::cargo_project_model(cache);
962+
Session::with_project_model(cache, project_model)
963+
}
964+
965+
pub fn with_project_model(cache: &'c FileCache, project_model: Box<ProjectModelProvider + 'c>) -> Session<'c> {
980966
Session {
981967
cache,
982968
generic_impls: Default::default(),
983-
cached_deps: Default::default(),
984-
cached_lockfile: Default::default(),
969+
project_model,
985970
}
986971
}
987-
988972
/// Specify the contents of a file to be used in completion operations
989973
///
990974
/// The path to the file and the file's contents must both be specified.
@@ -1012,54 +996,6 @@ impl<'c> Session<'c> {
1012996
let masked = self.cache.masked_map.borrow();
1013997
raw.contains_key(path) && masked.contains_key(path)
1014998
}
1015-
1016-
/// Get cached dependencies from manifest path(abs path of Cargo.toml) if they exist.
1017-
pub(crate) fn get_deps<P: AsRef<path::Path>>(&self, manifest: P) -> Option<Rc<Dependencies>> {
1018-
let manifest = manifest.as_ref();
1019-
let deps = self.cached_deps.borrow();
1020-
deps.get(manifest).map(|rc| Rc::clone(&rc))
1021-
}
1022-
1023-
/// Cache dependencies into session.
1024-
pub(crate) fn cache_deps<P: AsRef<path::Path>>(
1025-
&self,
1026-
manifest: P,
1027-
cache: HashMap<String, path::PathBuf>,
1028-
) {
1029-
let manifest = manifest.as_ref().to_owned();
1030-
let deps = Dependencies {
1031-
inner: cache,
1032-
};
1033-
self.cached_deps.borrow_mut().insert(manifest, Rc::new(deps));
1034-
}
1035-
1036-
/// load `Cargo.lock` file using fileloader
1037-
// TODO: use result
1038-
pub(crate) fn load_lockfile<P, F>(&self, path: P, resolver: F) -> Option<Rc<Resolve>>
1039-
where
1040-
P: AsRef<path::Path>,
1041-
F: FnOnce(&str) -> Option<Resolve>
1042-
{
1043-
let pathbuf = path.as_ref().to_owned();
1044-
match self.cached_lockfile.borrow_mut().entry(pathbuf) {
1045-
hash_map::Entry::Occupied(occupied) => Some(Rc::clone(occupied.get())),
1046-
hash_map::Entry::Vacant(vacant) => {
1047-
let contents = match self.cache.loader.load_file(path.as_ref()) {
1048-
Ok(f) => f,
1049-
Err(e) => {
1050-
debug!(
1051-
"[Session::load_lock_file] Failed to load {:?}: {}",
1052-
path.as_ref(),
1053-
e
1054-
);
1055-
return None;
1056-
}
1057-
};
1058-
resolver(&contents)
1059-
.map(|res| Rc::clone(vacant.insert(Rc::new(res))))
1060-
}
1061-
}
1062-
}
1063999
}
10641000

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

12591195
return nameres::resolve_method(
1260-
pos,
1261-
src.as_src(),
1262-
expr,
1263-
filepath,
1196+
pos,
1197+
src.as_src(),
1198+
expr,
1199+
filepath,
12641200
SearchType::StartsWith,
12651201
session,
12661202
&ImportInfo::default(),

src/racer/fileres.rs

Lines changed: 2 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
1-
use cargo::core::{
2-
PackageSet, PackageId, registry::PackageRegistry,
3-
resolver::{EncodableResolve, Method, Resolve}, Workspace
4-
};
5-
use cargo::ops;
6-
use cargo::util::{errors::CargoResult, important_paths::find_root_manifest_for_wd, toml};
7-
use cargo::Config;
81
use core::Session;
92
use nameres::RUST_SRC_PATH;
10-
use std::collections::HashSet;
113
use std::path::{Path, PathBuf};
124

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

57-
macro_rules! cargo_try {
58-
($r:expr) => {
59-
match $r {
60-
Ok(val) => val,
61-
Err(err) => {
62-
warn!("Error in cargo: {}", err);
63-
return None;
64-
}
65-
}
66-
};
67-
}
68-
6949
/// try to get outer crates
7050
/// if we have dependencies in cache, use it.
7151
/// else, call cargo's function to resolve depndencies.
@@ -75,98 +55,6 @@ fn get_outer_crates(libname: &str, from_path: &Path, session: &Session) -> Optio
7555
libname, from_path
7656
);
7757

78-
let manifest = cargo_try!(find_root_manifest_for_wd(from_path));
79-
if let Some(deps_info) = session.get_deps(&manifest) {
80-
// cache exists
81-
debug!("[get_outer_crates] cache exists for manifest",);
82-
deps_info.get_src_path(libname)
83-
} else {
84-
// cache doesn't exist
85-
let manifest = cargo_try!(find_root_manifest_for_wd(from_path));
86-
// calucurating depedencies can be bottleneck we use info! here(kngwyu)
87-
info!("[get_outer_crates] cache doesn't exist");
88-
resolve_dependencies(&manifest, session, libname)
89-
}
90-
}
91-
92-
fn resolve_dependencies(manifest: &Path, session: &Session, libname: &str) -> Option<PathBuf> {
93-
let mut config = cargo_try!(Config::default());
94-
// frozen=true, locked=true
95-
config.configure(0, Some(true), &None, true, true, &None, &[]).ok()?;
96-
let ws = cargo_try!(Workspace::new(&manifest, &config));
97-
// get resolve from lock file
98-
let lock_path = ws.root().to_owned().join("Cargo.lock");
99-
let lock_file = session.load_lockfile(&lock_path, |lockfile| {
100-
let resolve = cargo_try!(toml::parse(&lockfile, &lock_path, ws.config()));
101-
let v: EncodableResolve = cargo_try!(resolve.try_into());
102-
Some(cargo_try!(v.into_resolve(&ws)))
103-
});
104-
// then resolve precisely and add overrides
105-
let mut registry = cargo_try!(PackageRegistry::new(ws.config()));
106-
let resolve = cargo_try!(match lock_file {
107-
Some(prev) => resolve_with_prev(&mut registry, &ws, Some(&*prev)),
108-
None => resolve_with_prev(&mut registry, &ws, None),
109-
});
110-
let packages = get_resolved_packages(&resolve, registry);
111-
let mut res = None;
112-
// we have caches for each crates, so only need depth1 depedencies(= dependencies in Cargo.toml)
113-
let depth1_dependencies = match ws.current_opt() {
114-
Some(cur) => cur.dependencies().iter().map(|p| p.name()).collect(),
115-
None => HashSet::new(),
116-
};
117-
let current_pkg = ws.current().map(|pkg| pkg.name());
118-
let is_current_pkg = |name| {
119-
if let Ok(n) = current_pkg {
120-
n == name
121-
} else {
122-
false
123-
}
124-
};
125-
let deps_map = packages
126-
.package_ids()
127-
.filter_map(|package_id| {
128-
let pkg = packages.get(package_id).ok()?;
129-
let pkg_name = pkg.name();
130-
// for examples/ or tests/ dir, we have to handle current package specially
131-
if !is_current_pkg(pkg_name) && !depth1_dependencies.contains(&pkg.name()) {
132-
return None;
133-
}
134-
let targets = pkg.manifest().targets();
135-
// we only need library target
136-
let lib_target = targets.into_iter().find(|target| target.is_lib())?;
137-
// crate_name returns target.name.replace("-", "_")
138-
let crate_name = lib_target.crate_name();
139-
let src_path = lib_target.src_path().to_owned();
140-
if crate_name == libname {
141-
res = Some(src_path.clone());
142-
}
143-
Some((crate_name, src_path))
144-
})
145-
.collect();
146-
session.cache_deps(manifest, deps_map);
147-
res
148-
}
149-
150-
// wrapper of resolve_with_previous
151-
fn resolve_with_prev<'cfg>(
152-
registry: &mut PackageRegistry<'cfg>,
153-
ws: &Workspace<'cfg>,
154-
prev: Option<&Resolve>,
155-
) -> CargoResult<Resolve> {
156-
ops::resolve_with_previous(
157-
registry,
158-
ws,
159-
Method::Everything,
160-
prev,
161-
None,
162-
&[],
163-
true,
164-
false,
165-
)
166-
}
167-
168-
// until cargo 0.30 is released
169-
fn get_resolved_packages<'a>(resolve: &Resolve, registry: PackageRegistry<'a>) -> PackageSet<'a> {
170-
let ids: Vec<PackageId> = resolve.iter().cloned().collect();
171-
registry.get(&ids)
58+
let manifest = session.project_model.discover_project_manifest(from_path)?;
59+
session.project_model.resolve_dependency(&manifest, libname)
17260
}

src/racer/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ extern crate lazy_static;
99
#[macro_use]
1010
extern crate bitflags;
1111

12-
extern crate cargo;
1312
extern crate syntax;
1413
#[macro_use]
1514
extern crate derive_more;
@@ -29,12 +28,14 @@ mod codecleaner;
2928
mod matchers;
3029
mod snippets;
3130
mod fileres;
31+
mod project_model;
3232

3333
pub use core::{find_definition, complete_from_file, complete_fully_qualified_name, to_point, to_coords};
3434
pub use snippets::snippet_for_match;
3535
pub use core::{Match, MatchType, PathSearch};
3636
pub use core::{FileCache, Session, Coordinate, Location, FileLoader, BytePos, ByteRange};
3737
pub use util::expand_ident;
38+
pub use project_model::ProjectModelProvider;
3839

3940
pub use util::{RustSrcPathError, get_rust_src_path};
4041

0 commit comments

Comments
 (0)