Merge #10841
10841: Emit moniker in lsif r=Veykril a=HKalbasi fix #10559 Co-authored-by: hkalbasi <hamidrezakalbasi@protonmail.com> Co-authored-by: HKalbasi <45197576+HKalbasi@users.noreply.github.com>
This commit is contained in:
commit
393cbd0982
@ -10,9 +10,10 @@
|
||||
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 @@ pub fn parse(ra_fixture: &str) -> 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 @@ pub fn parse(ra_fixture: &str) -> ChangeFixture {
|
||||
default_cfg,
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
} else {
|
||||
for (from, to, prelude) in crate_deps {
|
||||
@ -209,6 +212,7 @@ pub fn parse(ra_fixture: &str) -> ChangeFixture {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Vec::new(),
|
||||
CrateOrigin::Lang,
|
||||
);
|
||||
|
||||
for krate in all_crates {
|
||||
@ -243,6 +247,7 @@ pub fn parse(ra_fixture: &str) -> 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,
|
||||
|
@ -112,6 +112,24 @@ fn deref(&self) -> &str {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 @@ pub fn add_crate_root(
|
||||
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 @@ pub fn add_crate_root(
|
||||
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 @@ fn detect_cyclic_dependency_indirect() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@ -581,6 +603,7 @@ fn detect_cyclic_dependency_indirect() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate3 = graph.add_crate_root(
|
||||
FileId(3u32),
|
||||
@ -591,6 +614,7 @@ fn detect_cyclic_dependency_indirect() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||
@ -615,6 +639,7 @@ fn detect_cyclic_dependency_direct() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@ -625,6 +650,7 @@ fn detect_cyclic_dependency_direct() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||
@ -646,6 +672,7 @@ fn it_works() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@ -656,6 +683,7 @@ fn it_works() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate3 = graph.add_crate_root(
|
||||
FileId(3u32),
|
||||
@ -666,6 +694,7 @@ fn it_works() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
|
||||
@ -687,6 +716,7 @@ fn dashes_are_normalized() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
let crate2 = graph.add_crate_root(
|
||||
FileId(2u32),
|
||||
@ -697,6 +727,7 @@ fn dashes_are_normalized() {
|
||||
CfgOptions::default(),
|
||||
Env::default(),
|
||||
Default::default(),
|
||||
Default::default(),
|
||||
);
|
||||
assert!(graph
|
||||
.add_dep(
|
||||
|
@ -11,9 +11,9 @@
|
||||
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};
|
||||
|
@ -34,7 +34,7 @@
|
||||
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
|
||||
|
@ -41,6 +41,7 @@ macro_rules! eprintln {
|
||||
mod join_lines;
|
||||
mod markdown_remove;
|
||||
mod matching_brace;
|
||||
mod moniker;
|
||||
mod move_item;
|
||||
mod parent_module;
|
||||
mod references;
|
||||
@ -83,6 +84,7 @@ macro_rules! eprintln {
|
||||
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 @@ pub fn from_single_file(text: String) -> (Analysis, FileId) {
|
||||
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 @@ pub fn hover(
|
||||
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,
|
||||
|
233
crates/ide/src/moniker.rs
Normal file
233
crates/ide/src/moniker.rs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
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 @@ fn add_file(&mut self, file_id: FileId) {
|
||||
.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 @@ fn check_definitions(ra_fixture: &str) {
|
||||
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);
|
||||
}
|
||||
@ -262,6 +271,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(
|
||||
|
@ -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 @@ pub fn new(mut meta: cargo_metadata::Metadata) -> 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 @@ pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace {
|
||||
is_local,
|
||||
is_member,
|
||||
edition,
|
||||
repository: repository.clone(),
|
||||
dependencies: Vec::new(),
|
||||
features: meta_pkg.features.clone().into_iter().collect(),
|
||||
active_features: Vec::new(),
|
||||
|
@ -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 @@ pub fn new(base: &AbsPath, data: ProjectJsonData) -> 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)]
|
||||
|
@ -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,
|
||||
},
|
||||
},
|
||||
}"#]],
|
||||
|
@ -6,7 +6,8 @@
|
||||
|
||||
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))
|
||||
})
|
||||
|
@ -5,8 +5,8 @@
|
||||
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 @@ fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifMa
|
||||
token_map: HashMap::default(),
|
||||
range_map: HashMap::default(),
|
||||
file_map: HashMap::default(),
|
||||
package_map: HashMap::default(),
|
||||
analysis,
|
||||
db,
|
||||
vfs,
|
||||
@ -92,6 +94,28 @@ fn get_token_id(&mut self, id: TokenId) -> Id {
|
||||
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 @@ fn add_token(&mut self, id: TokenId, token: TokenStaticData) {
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user