Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/base_db/src/fixture.rs37
-rw-r--r--crates/base_db/src/input.rs31
-rw-r--r--crates/base_db/src/lib.rs6
-rw-r--r--crates/hir/src/lib.rs6
-rw-r--r--crates/ide/src/lib.rs11
-rw-r--r--crates/ide/src/moniker.rs233
-rw-r--r--crates/ide/src/static_index.rs31
-rw-r--r--crates/project_model/src/cargo_workspace.rs16
-rw-r--r--crates/project_model/src/project_json.rs4
-rw-r--r--crates/project_model/src/tests.rs95
-rw-r--r--crates/project_model/src/workspace.rs12
-rw-r--r--crates/rust-analyzer/src/cli/lsif.rs48
12 files changed, 511 insertions, 19 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 2b091f37a0..9baae92144 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -10,9 +10,10 @@ use tt::Subtree;
use vfs::{file_set::FileSet, VfsPath};
use crate::{
- input::CrateName, Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env,
- FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
- SourceDatabaseExt, SourceRoot, SourceRootId,
+ input::{CrateName, CrateOrigin},
+ Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition,
+ FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt,
+ SourceRoot, SourceRootId,
};
pub const WORKSPACE: SourceRootId = SourceRootId(0);
@@ -130,17 +131,18 @@ impl ChangeFixture {
current_source_root_kind = *kind;
}
- if let Some(krate) = meta.krate {
+ if let Some((krate, origin, version)) = meta.krate {
let crate_name = CrateName::normalize_dashes(&krate);
let crate_id = crate_graph.add_crate_root(
file_id,
meta.edition,
Some(crate_name.clone().into()),
- None,
+ version,
meta.cfg.clone(),
meta.cfg,
meta.env,
Default::default(),
+ origin,
);
let prev = crates.insert(crate_name.clone(), crate_id);
assert!(prev.is_none());
@@ -174,6 +176,7 @@ impl ChangeFixture {
default_cfg,
Env::default(),
Default::default(),
+ Default::default(),
);
} else {
for (from, to, prelude) in crate_deps {
@@ -209,6 +212,7 @@ impl ChangeFixture {
CfgOptions::default(),
Env::default(),
Vec::new(),
+ CrateOrigin::Lang,
);
for krate in all_crates {
@@ -243,6 +247,7 @@ impl ChangeFixture {
CfgOptions::default(),
Env::default(),
proc_macro,
+ CrateOrigin::Lang,
);
for krate in all_crates {
@@ -324,7 +329,7 @@ enum SourceRootKind {
#[derive(Debug)]
struct FileMeta {
path: String,
- krate: Option<String>,
+ krate: Option<(String, CrateOrigin, Option<String>)>,
deps: Vec<String>,
extern_prelude: Vec<String>,
cfg: CfgOptions,
@@ -333,16 +338,32 @@ struct FileMeta {
introduce_new_source_root: Option<SourceRootKind>,
}
+fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
+ if let Some((a, b)) = crate_str.split_once("@") {
+ let (version, origin) = match b.split_once(":") {
+ Some(("CratesIo", data)) => match data.split_once(",") {
+ Some((version, url)) => {
+ (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()) })
+ }
+ _ => panic!("Bad crates.io parameter: {}", data),
+ },
+ _ => panic!("Bad string for crate origin: {}", b),
+ };
+ (a.to_owned(), origin, Some(version.to_string()))
+ } else {
+ (crate_str, CrateOrigin::Unknown, None)
+ }
+}
+
impl From<Fixture> for FileMeta {
fn from(f: Fixture) -> FileMeta {
let mut cfg = CfgOptions::default();
f.cfg_atoms.iter().for_each(|it| cfg.insert_atom(it.into()));
f.cfg_key_values.iter().for_each(|(k, v)| cfg.insert_key_value(k.into(), v.into()));
-
let deps = f.deps;
FileMeta {
path: f.path,
- krate: f.krate,
+ krate: f.krate.map(parse_crate),
extern_prelude: f.extern_prelude.unwrap_or_else(|| deps.clone()),
deps,
cfg,
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 98533ca0a7..f182427e47 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -112,6 +112,24 @@ impl ops::Deref for CrateName {
}
}
+/// Origin of the crates. It is used in emitting monikers.
+#[derive(Debug, Clone)]
+pub enum CrateOrigin {
+ /// Crates that are from crates.io official registry,
+ CratesIo { repo: Option<String> },
+ /// Crates that are provided by the language, like std, core, proc-macro, ...
+ Lang,
+ /// Crates that we don't know their origin.
+ // Idealy this enum should cover all cases, and then we remove this variant.
+ Unknown,
+}
+
+impl Default for CrateOrigin {
+ fn default() -> Self {
+ Self::Unknown
+ }
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CrateDisplayName {
// The name we use to display various paths (with `_`).
@@ -205,6 +223,7 @@ pub struct CrateData {
pub env: Env,
pub dependencies: Vec<Dependency>,
pub proc_macro: Vec<ProcMacro>,
+ pub origin: CrateOrigin,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -256,6 +275,7 @@ impl CrateGraph {
potential_cfg_options: CfgOptions,
env: Env,
proc_macro: Vec<ProcMacro>,
+ origin: CrateOrigin,
) -> CrateId {
let data = CrateData {
root_file_id: file_id,
@@ -267,6 +287,7 @@ impl CrateGraph {
env,
proc_macro,
dependencies: Vec::new(),
+ origin,
};
let crate_id = CrateId(self.arena.len() as u32);
let prev = self.arena.insert(crate_id, data);
@@ -571,6 +592,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
@@ -581,6 +603,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
let crate3 = graph.add_crate_root(
FileId(3u32),
@@ -591,6 +614,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
assert!(graph
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -615,6 +639,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
@@ -625,6 +650,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
assert!(graph
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -646,6 +672,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
@@ -656,6 +683,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
let crate3 = graph.add_crate_root(
FileId(3u32),
@@ -666,6 +694,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
assert!(graph
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -687,6 +716,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
let crate2 = graph.add_crate_root(
FileId(2u32),
@@ -697,6 +727,7 @@ mod tests {
CfgOptions::default(),
Env::default(),
Default::default(),
+ Default::default(),
);
assert!(graph
.add_dep(
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index c34a329540..d4070457cd 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -11,9 +11,9 @@ use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
pub use crate::{
change::Change,
input::{
- CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env,
- ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroId, ProcMacroKind,
- SourceRoot, SourceRootId,
+ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
+ Edition, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroId,
+ ProcMacroKind, SourceRoot, SourceRootId,
},
};
pub use salsa::{self, Cancelled};
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 3946f51642..badd9ac589 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -34,7 +34,7 @@ mod display;
use std::{iter, ops::ControlFlow, sync::Arc};
use arrayvec::ArrayVec;
-use base_db::{CrateDisplayName, CrateId, Edition, FileId};
+use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId};
use either::Either;
use hir_def::{
adt::{ReprKind, VariantData},
@@ -144,6 +144,10 @@ pub struct CrateDependency {
}
impl Crate {
+ pub fn origin(self, db: &dyn HirDatabase) -> CrateOrigin {
+ db.crate_graph()[self.id].origin.clone()
+ }
+
pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
db.crate_graph()[self.id]
.dependencies
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 034a511793..121baa86f1 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -41,6 +41,7 @@ mod inlay_hints;
mod join_lines;
mod markdown_remove;
mod matching_brace;
+mod moniker;
mod move_item;
mod parent_module;
mod references;
@@ -83,6 +84,7 @@ pub use crate::{
inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
join_lines::JoinLinesConfig,
markup::Markup,
+ moniker::{MonikerKind, MonikerResult, PackageInformation},
move_item::Direction,
navigation_target::NavigationTarget,
prime_caches::PrimeCachesProgress,
@@ -225,6 +227,7 @@ impl Analysis {
cfg_options,
Env::default(),
Default::default(),
+ Default::default(),
);
change.change_file(file_id, Some(Arc::new(text)));
change.set_crate_graph(crate_graph);
@@ -425,6 +428,14 @@ impl Analysis {
self.with_db(|db| hover::hover(db, range, config))
}
+ /// Returns moniker of symbol at position.
+ pub fn moniker(
+ &self,
+ position: FilePosition,
+ ) -> Cancellable<Option<RangeInfo<Vec<moniker::MonikerResult>>>> {
+ self.with_db(|db| moniker::moniker(db, position))
+ }
+
/// Return URL(s) for the documentation of the symbol under the cursor.
pub fn external_docs(
&self,
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
new file mode 100644
index 0000000000..9d8c742fc4
--- /dev/null
+++ b/crates/ide/src/moniker.rs
@@ -0,0 +1,233 @@
+//! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
+//! for LSIF and LSP.
+
+use hir::{db::DefDatabase, Crate, Name, Semantics};
+use ide_db::{
+ base_db::{CrateOrigin, FileId, FileLoader, FilePosition},
+ defs::Definition,
+ helpers::pick_best_token,
+ RootDatabase,
+};
+use itertools::Itertools;
+use syntax::{AstNode, SyntaxKind::*, T};
+
+use crate::{doc_links::token_as_doc_comment, RangeInfo};
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct MonikerIdentifier {
+ crate_name: String,
+ path: Vec<Name>,
+}
+
+impl ToString for MonikerIdentifier {
+ fn to_string(&self) -> String {
+ match self {
+ MonikerIdentifier { path, crate_name } => {
+ format!("{}::{}", crate_name, path.iter().map(|x| x.to_string()).join("::"))
+ }
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum MonikerKind {
+ Import,
+ Export,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MonikerResult {
+ pub identifier: MonikerIdentifier,
+ pub kind: MonikerKind,
+ pub package_information: PackageInformation,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct PackageInformation {
+ pub name: String,
+ pub repo: String,
+ pub version: String,
+}
+
+pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option<Crate> {
+ for &krate in db.relevant_crates(file_id).iter() {
+ let crate_def_map = db.crate_def_map(krate);
+ for (_, data) in crate_def_map.modules() {
+ if data.origin.file_id() == Some(file_id) {
+ return Some(krate.into());
+ }
+ }
+ }
+ None
+}
+
+pub(crate) fn moniker(
+ db: &RootDatabase,
+ FilePosition { file_id, offset }: FilePosition,
+) -> Option<RangeInfo<Vec<MonikerResult>>> {
+ let sema = &Semantics::new(db);
+ let file = sema.parse(file_id).syntax().clone();
+ let current_crate = crate_for_file(db, file_id)?;
+ let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
+ IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] | COMMENT => 2,
+ kind if kind.is_trivia() => 0,
+ _ => 1,
+ })?;
+ if let Some(doc_comment) = token_as_doc_comment(&original_token) {
+ return doc_comment.get_definition_with_descend_at(sema, offset, |def, _, _| {
+ let m = def_to_moniker(db, def, current_crate)?;
+ Some(RangeInfo::new(original_token.text_range(), vec![m]))
+ });
+ }
+ let navs = sema
+ .descend_into_macros(original_token.clone())
+ .into_iter()
+ .map(|token| {
+ Definition::from_token(sema, &token)
+ .into_iter()
+ .flat_map(|def| def_to_moniker(sema.db, def, current_crate))
+ .collect::<Vec<_>>()
+ })
+ .flatten()
+ .unique()
+ .collect::<Vec<_>>();
+ Some(RangeInfo::new(original_token.text_range(), navs))
+}
+
+pub(crate) fn def_to_moniker(
+ db: &RootDatabase,
+ def: Definition,
+ from_crate: Crate,
+) -> Option<MonikerResult> {
+ if matches!(def, Definition::GenericParam(_) | Definition::SelfType(_) | Definition::Local(_)) {
+ return None;
+ }
+ let module = def.module(db)?;
+ let krate = module.krate();
+ let mut path = vec![];
+ path.extend(module.path_to_root(db).into_iter().filter_map(|x| x.name(db)));
+ if let Definition::Field(it) = def {
+ path.push(it.parent_def(db).name(db));
+ }
+ path.push(def.name(db)?);
+ Some(MonikerResult {
+ identifier: MonikerIdentifier {
+ crate_name: krate.display_name(db)?.crate_name().to_string(),
+ path,
+ },
+ kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import },
+ package_information: {
+ let name = krate.display_name(db)?.to_string();
+ let (repo, version) = match krate.origin(db) {
+ CrateOrigin::CratesIo { repo } => (repo?, krate.version(db)?),
+ CrateOrigin::Lang => (
+ "https://github.com/rust-lang/rust/".to_string(),
+ "compiler_version".to_string(),
+ ),
+ CrateOrigin::Unknown => return None,
+ };
+ PackageInformation { name, repo, version }
+ },
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::fixture;
+
+ use super::MonikerKind;
+
+ #[track_caller]
+ fn no_moniker(ra_fixture: &str) {
+ let (analysis, position) = fixture::position(ra_fixture);
+ if let Some(x) = analysis.moniker(position).unwrap() {
+ assert_eq!(x.info.len(), 0, "Moniker founded but no moniker expected: {:?}", x);
+ }
+ }
+
+ #[track_caller]
+ fn check_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) {
+ let (analysis, position) = fixture::position(ra_fixture);
+ let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
+ assert_eq!(x.len(), 1);
+ let x = x.into_iter().next().unwrap();
+ assert_eq!(identifier, x.identifier.to_string());
+ assert_eq!(package, format!("{:?}", x.package_information));
+ assert_eq!(kind, x.kind);
+ }
+
+ #[test]
+ fn basic() {
+ check_moniker(
+ r#"
+//- /lib.rs crate:main deps:foo
+use foo::module::func;
+fn main() {
+ func$0();
+}
+//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+pub mod module {
+ pub fn func() {}
+}
+"#,
+ "foo::module::func",
+ r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+ MonikerKind::Import,
+ );
+ check_moniker(
+ r#"
+//- /lib.rs crate:main deps:foo
+use foo::module::func;
+fn main() {
+ func();
+}
+//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+pub mod module {
+ pub fn func$0() {}
+}
+"#,
+ "foo::module::func",
+ r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+ MonikerKind::Export,
+ );
+ }
+
+ #[test]
+ fn moniker_for_field() {
+ check_moniker(
+ r#"
+//- /lib.rs crate:main deps:foo
+use foo::St;
+fn main() {
+ let x = St { a$0: 2 };
+}
+//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+pub struct St {
+ pub a: i32,
+}
+"#,
+ "foo::St::a",
+ r#"PackageInformation { name: "foo", repo: "https://a.b/foo.git", version: "0.1.0" }"#,
+ MonikerKind::Import,
+ );
+ }
+
+ #[test]
+ fn no_moniker_for_local() {
+ no_moniker(
+ r#"
+//- /lib.rs crate:main deps:foo
+use foo::module::func;
+fn main() {
+ func();
+}
+//- /foo/lib.rs crate:foo@CratesIo:0.1.0,https://a.b/foo.git
+pub mod module {
+ pub fn func() {
+ let x$0 = 2;
+ }
+}
+"#,
+ );
+ }
+}
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 29eef546ce..cf98bc32fa 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -12,6 +12,7 @@ use ide_db::{
use rustc_hash::FxHashSet;
use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
+use crate::moniker::{crate_for_file, def_to_moniker, MonikerResult};
use crate::{
hover::hover_for_definition, Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult,
InlayHint, InlayHintsConfig, TryToNav,
@@ -40,6 +41,7 @@ pub struct TokenStaticData {
pub hover: Option<HoverResult>,
pub definition: Option<FileRange>,
pub references: Vec<ReferenceData>,
+ pub moniker: Option<MonikerResult>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -97,6 +99,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
impl StaticIndex<'_> {
fn add_file(&mut self, file_id: FileId) {
+ let current_crate = crate_for_file(self.db, file_id);
let folds = self.analysis.folding_ranges(file_id).unwrap();
let inlay_hints = self
.analysis
@@ -143,6 +146,7 @@ impl StaticIndex<'_> {
.try_to_nav(self.db)
.map(|x| FileRange { file_id: x.file_id, range: x.focus_or_full_range() }),
references: vec![],
+ moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)),
});
self.def_map.insert(def, x);
x
@@ -206,6 +210,7 @@ mod tests {
use crate::{fixture, StaticIndex};
use ide_db::base_db::FileRange;
use std::collections::HashSet;
+ use syntax::TextSize;
fn check_all_ranges(ra_fixture: &str) {
let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
@@ -231,6 +236,10 @@ mod tests {
let mut range_set: HashSet<_> = ranges.iter().map(|x| x.0).collect();
for (_, t) in s.tokens.iter() {
if let Some(x) = t.definition {
+ if x.range.start() == TextSize::from(0) {
+ // ignore definitions that are whole of file
+ continue;
+ }
if !range_set.contains(&x) {
panic!("additional definition {:?}", x);
}
@@ -263,6 +272,28 @@ enum E { X(Foo) }
}
#[test]
+ fn multi_crate() {
+ check_definitions(
+ r#"
+//- /main.rs crate:main deps:foo
+
+
+use foo::func;
+
+fn main() {
+ //^^^^
+ func();
+}
+//- /foo/lib.rs crate:foo
+
+pub func() {
+
+}
+"#,
+ );
+ }
+
+ #[test]
fn derives() {
check_all_ranges(
r#"
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index 85123ed5c5..c2cf3c4ce3 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -130,6 +130,8 @@ pub struct PackageData {
pub version: semver::Version,
/// Name as given in the `Cargo.toml`
pub name: String,
+ /// Repository as given in the `Cargo.toml`
+ pub repository: Option<String>,
/// Path containing the `Cargo.toml`
pub manifest: ManifestPath,
/// Targets provided by the crate (lib, bin, example, test, ...)
@@ -146,9 +148,9 @@ pub struct PackageData {
pub features: FxHashMap<String, Vec<String>>,
/// List of features enabled on this package
pub active_features: Vec<String>,
- // String representation of package id
+ /// String representation of package id
pub id: String,
- // The contents of [package.metadata.rust-analyzer]
+ /// The contents of [package.metadata.rust-analyzer]
pub metadata: RustAnalyzerPackageMetaData,
}
@@ -302,7 +304,14 @@ impl CargoWorkspace {
meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
for meta_pkg in &meta.packages {
let cargo_metadata::Package {
- id, edition, name, manifest_path, version, metadata, ..
+ id,
+ edition,
+ name,
+ manifest_path,
+ version,
+ metadata,
+ repository,
+ ..
} = meta_pkg;
let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
let edition = edition.parse::<Edition>().unwrap_or_else(|err| {
@@ -323,6 +332,7 @@ impl CargoWorkspace {
is_local,
is_member,
edition,
+ repository: repository.clone(),
dependencies: Vec::new(),
features: meta_pkg.features.clone().into_iter().collect(),
active_features: Vec::new(),
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs
index d8d0d07aff..a3c5ac1674 100644
--- a/crates/project_model/src/project_json.rs
+++ b/crates/project_model/src/project_json.rs
@@ -39,6 +39,7 @@ pub struct Crate {
pub(crate) include: Vec<AbsPathBuf>,
pub(crate) exclude: Vec<AbsPathBuf>,
pub(crate) is_proc_macro: bool,
+ pub(crate) repository: Option<String>,
}
impl ProjectJson {
@@ -99,6 +100,7 @@ impl ProjectJson {
include,
exclude,
is_proc_macro: crate_data.is_proc_macro,
+ repository: crate_data.repository,
}
})
.collect::<Vec<_>>(),
@@ -142,6 +144,8 @@ struct CrateData {
source: Option<CrateSource>,
#[serde(default)]
is_proc_macro: bool,
+ #[serde(default)]
+ repository: Option<String>,
}
#[derive(Deserialize, Debug, Clone)]
diff --git a/crates/project_model/src/tests.rs b/crates/project_model/src/tests.rs
index 252acde14d..edf2673661 100644
--- a/crates/project_model/src/tests.rs
+++ b/crates/project_model/src/tests.rs
@@ -173,6 +173,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
5,
@@ -242,6 +245,11 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
2,
@@ -311,6 +319,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
4,
@@ -370,6 +381,11 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
dependencies: [],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
1,
@@ -439,6 +455,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
6,
@@ -498,6 +517,11 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
dependencies: [],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
3,
@@ -567,6 +591,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
},
}"#]],
@@ -651,6 +678,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
5,
@@ -720,6 +750,11 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
2,
@@ -791,6 +826,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
4,
@@ -850,6 +888,11 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
dependencies: [],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
1,
@@ -921,6 +964,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
6,
@@ -980,6 +1026,11 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
dependencies: [],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
3,
@@ -1051,6 +1102,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
},
}"#]],
@@ -1126,6 +1180,9 @@ fn cargo_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
5,
@@ -1197,6 +1254,11 @@ fn cargo_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
2,
@@ -1268,6 +1330,9 @@ fn cargo_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
4,
@@ -1329,6 +1394,11 @@ fn cargo_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
1,
@@ -1400,6 +1470,9 @@ fn cargo_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
6,
@@ -1461,6 +1534,11 @@ fn cargo_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: CratesIo {
+ repo: Some(
+ "https://github.com/rust-lang/libc",
+ ),
+ },
},
CrateId(
3,
@@ -1532,6 +1610,9 @@ fn cargo_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
},
}"#]],
@@ -1583,6 +1664,7 @@ fn rust_project_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: Lang,
},
CrateId(
10,
@@ -1611,6 +1693,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
7,
@@ -1639,6 +1722,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
4,
@@ -1677,6 +1761,7 @@ fn rust_project_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: Lang,
},
CrateId(
1,
@@ -1705,6 +1790,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
11,
@@ -1770,6 +1856,9 @@ fn rust_project_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: CratesIo {
+ repo: None,
+ },
},
CrateId(
8,
@@ -1798,6 +1887,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
5,
@@ -1826,6 +1916,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
2,
@@ -1854,6 +1945,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
9,
@@ -1882,6 +1974,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
CrateId(
6,
@@ -1992,6 +2085,7 @@ fn rust_project_hello_world_project_model() {
},
],
proc_macro: [],
+ origin: Lang,
},
CrateId(
3,
@@ -2020,6 +2114,7 @@ fn rust_project_hello_world_project_model() {
},
dependencies: [],
proc_macro: [],
+ origin: Lang,
},
},
}"#]],
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 2fc88bf505..0335f8b174 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -6,7 +6,8 @@ use std::{collections::VecDeque, fmt, fs, process::Command};
use anyhow::{format_err, Context, Result};
use base_db::{
- CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, FileId, ProcMacro,
+ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
+ FileId, ProcMacro,
};
use cfg::{CfgDiff, CfgOptions};
use paths::{AbsPath, AbsPathBuf};
@@ -473,6 +474,11 @@ fn project_json_to_crate_graph(
cfg_options,
env,
proc_macro.unwrap_or_default(),
+ if krate.display_name.is_some() {
+ CrateOrigin::CratesIo { repo: krate.repository.clone() }
+ } else {
+ CrateOrigin::Unknown
+ },
),
)
})
@@ -681,6 +687,7 @@ fn detached_files_to_crate_graph(
cfg_options.clone(),
Env::default(),
Vec::new(),
+ CrateOrigin::Unknown,
);
public_deps.add(detached_file_crate, &mut crate_graph);
@@ -821,7 +828,6 @@ fn add_target_crate_root(
.iter()
.map(|feat| CfgFlag::KeyValue { key: "feature".into(), value: feat.0.into() }),
);
-
crate_graph.add_crate_root(
file_id,
edition,
@@ -831,6 +837,7 @@ fn add_target_crate_root(
potential_cfg_options,
env,
proc_macro,
+ CrateOrigin::CratesIo { repo: pkg.repository.clone() },
)
}
@@ -874,6 +881,7 @@ fn sysroot_to_crate_graph(
cfg_options.clone(),
env,
proc_macro,
+ CrateOrigin::Lang,
);
Some((krate, crate_id))
})
diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs
index f108b694c0..b9bb335b05 100644
--- a/crates/rust-analyzer/src/cli/lsif.rs
+++ b/crates/rust-analyzer/src/cli/lsif.rs
@@ -5,8 +5,8 @@ use std::env;
use std::time::Instant;
use ide::{
- Analysis, FileId, FileRange, RootDatabase, StaticIndex, StaticIndexedFile, TokenId,
- TokenStaticData,
+ Analysis, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase, StaticIndex,
+ StaticIndexedFile, TokenId, TokenStaticData,
};
use ide_db::LineIndexDatabase;
@@ -36,6 +36,7 @@ struct LsifManager<'a> {
token_map: HashMap<TokenId, Id>,
range_map: HashMap<FileRange, Id>,
file_map: HashMap<FileId, Id>,
+ package_map: HashMap<PackageInformation, Id>,
analysis: &'a Analysis,
db: &'a RootDatabase,
vfs: &'a Vfs,
@@ -57,6 +58,7 @@ impl LsifManager<'_> {
token_map: HashMap::default(),
range_map: HashMap::default(),
file_map: HashMap::default(),
+ package_map: HashMap::default(),
analysis,
db,
vfs,
@@ -92,6 +94,28 @@ impl LsifManager<'_> {
result_set_id
}
+ fn get_package_id(&mut self, package_information: PackageInformation) -> Id {
+ if let Some(x) = self.package_map.get(&package_information) {
+ return *x;
+ }
+ let pi = package_information.clone();
+ let result_set_id =
+ self.add_vertex(lsif::Vertex::PackageInformation(lsif::PackageInformation {
+ name: pi.name,
+ manager: "cargo".to_string(),
+ uri: None,
+ content: None,
+ repository: Some(lsif::Repository {
+ url: pi.repo,
+ r#type: "git".to_string(),
+ commit_id: None,
+ }),
+ version: Some(pi.version),
+ }));
+ self.package_map.insert(package_information, result_set_id);
+ result_set_id
+ }
+
fn get_range_id(&mut self, id: FileRange) -> Id {
if let Some(x) = self.range_map.get(&id) {
return *x;
@@ -146,6 +170,26 @@ impl LsifManager<'_> {
out_v: result_set_id.into(),
}));
}
+ if let Some(moniker) = token.moniker {
+ let package_id = self.get_package_id(moniker.package_information);
+ let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker {
+ scheme: "rust-analyzer".to_string(),
+ identifier: moniker.identifier.to_string(),
+ unique: lsp_types::UniquenessLevel::Scheme,
+ kind: Some(match moniker.kind {
+ MonikerKind::Import => lsp_types::MonikerKind::Import,
+ MonikerKind::Export => lsp_types::MonikerKind::Export,
+ }),
+ }));
+ self.add_edge(lsif::Edge::PackageInformation(lsif::EdgeData {
+ in_v: package_id.into(),
+ out_v: moniker_id.into(),
+ }));
+ self.add_edge(lsif::Edge::Moniker(lsif::EdgeData {
+ in_v: moniker_id.into(),
+ out_v: result_set_id.into(),
+ }));
+ }
if let Some(def) = token.definition {
let result_id = self.add_vertex(lsif::Vertex::DefinitionResult);
let def_vertex = self.get_range_id(def);