mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-11-02 04:48:13 +00:00
Merge commit '37f84c101b' into sync-from-ra
This commit is contained in:
parent
6502421771
commit
4704881b64
311 changed files with 13700 additions and 9110 deletions
|
|
@ -21,7 +21,7 @@ once_cell = "1.17.0"
|
|||
either = "1.7.0"
|
||||
itertools = "0.10.5"
|
||||
arrayvec = "0.7.2"
|
||||
indexmap = "1.9.1"
|
||||
indexmap = "2.0.0"
|
||||
memchr = "2.5.0"
|
||||
triomphe.workspace = true
|
||||
nohash-hasher.workspace = true
|
||||
|
|
|
|||
|
|
@ -99,8 +99,8 @@ impl RootDatabase {
|
|||
hir::db::AstIdMapQuery
|
||||
hir::db::ParseMacroExpansionQuery
|
||||
hir::db::InternMacroCallQuery
|
||||
hir::db::MacroArgTextQuery
|
||||
hir::db::MacroDefQuery
|
||||
hir::db::MacroArgNodeQuery
|
||||
hir::db::DeclMacroExpanderQuery
|
||||
hir::db::MacroExpandQuery
|
||||
hir::db::ExpandProcMacroQuery
|
||||
hir::db::HygieneFrameQuery
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ use syntax::{
|
|||
AstToken, SyntaxKind, SyntaxToken, TokenAtOffset,
|
||||
};
|
||||
|
||||
use crate::{defs::Definition, generated, RootDatabase};
|
||||
use crate::{
|
||||
defs::{Definition, IdentClass},
|
||||
generated, RootDatabase,
|
||||
};
|
||||
|
||||
pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
|
||||
match item {
|
||||
|
|
@ -109,3 +112,16 @@ pub fn is_editable_crate(krate: Crate, db: &RootDatabase) -> bool {
|
|||
let source_root_id = db.file_source_root(root_file);
|
||||
!db.source_root(source_root_id).is_library
|
||||
}
|
||||
|
||||
pub fn get_definition(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
token: SyntaxToken,
|
||||
) -> Option<Definition> {
|
||||
for token in sema.descend_into_macros(token) {
|
||||
let def = IdentClass::classify_token(sema, &token).map(IdentClass::definitions_no_ops);
|
||||
if let Some(&[x]) = def.as_deref() {
|
||||
return Some(x);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use syntax::{
|
|||
|
||||
use crate::{
|
||||
helpers::item_name,
|
||||
items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT},
|
||||
items_locator::{self, AssocSearchMode, DEFAULT_QUERY_SEARCH_LIMIT},
|
||||
RootDatabase,
|
||||
};
|
||||
|
||||
|
|
@ -317,7 +317,7 @@ fn path_applicable_imports(
|
|||
// * improve the associated completion item matching and/or scoring to ensure no noisy completions appear
|
||||
//
|
||||
// see also an ignored test under FIXME comment in the qualify_path.rs module
|
||||
AssocItemSearch::Exclude,
|
||||
AssocSearchMode::Exclude,
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|item| {
|
||||
|
|
@ -334,7 +334,7 @@ fn path_applicable_imports(
|
|||
sema,
|
||||
current_crate,
|
||||
path_candidate.name.clone(),
|
||||
AssocItemSearch::Include,
|
||||
AssocSearchMode::Include,
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|item| {
|
||||
|
|
@ -483,7 +483,7 @@ fn trait_applicable_items(
|
|||
sema,
|
||||
current_crate,
|
||||
trait_candidate.assoc_item_name.clone(),
|
||||
AssocItemSearch::AssocItemsOnly,
|
||||
AssocSearchMode::AssocItemsOnly,
|
||||
Some(DEFAULT_QUERY_SEARCH_LIMIT.inner()),
|
||||
)
|
||||
.filter_map(|input| item_as_assoc(db, input))
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
//! The main reason for this module to exist is the fact that project's items and dependencies' items
|
||||
//! are located in different caches, with different APIs.
|
||||
use either::Either;
|
||||
use hir::{
|
||||
import_map::{self, ImportKind},
|
||||
AsAssocItem, Crate, ItemInNs, Semantics,
|
||||
};
|
||||
use hir::{import_map, AsAssocItem, Crate, ItemInNs, Semantics};
|
||||
use limit::Limit;
|
||||
|
||||
use crate::{imports::import_assets::NameToImport, symbol_index, RootDatabase};
|
||||
|
|
@ -14,23 +11,14 @@ use crate::{imports::import_assets::NameToImport, symbol_index, RootDatabase};
|
|||
/// A value to use, when uncertain which limit to pick.
|
||||
pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(40);
|
||||
|
||||
/// Three possible ways to search for the name in associated and/or other items.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AssocItemSearch {
|
||||
/// Search for the name in both associated and other items.
|
||||
Include,
|
||||
/// Search for the name in other items only.
|
||||
Exclude,
|
||||
/// Search for the name in the associated items only.
|
||||
AssocItemsOnly,
|
||||
}
|
||||
pub use import_map::AssocSearchMode;
|
||||
|
||||
/// Searches for importable items with the given name in the crate and its dependencies.
|
||||
pub fn items_with_name<'a>(
|
||||
sema: &'a Semantics<'_, RootDatabase>,
|
||||
krate: Crate,
|
||||
name: NameToImport,
|
||||
assoc_item_search: AssocItemSearch,
|
||||
assoc_item_search: AssocSearchMode,
|
||||
limit: Option<usize>,
|
||||
) -> impl Iterator<Item = ItemInNs> + 'a {
|
||||
let _p = profile::span("items_with_name").detail(|| {
|
||||
|
|
@ -48,9 +36,7 @@ pub fn items_with_name<'a>(
|
|||
let mut local_query = symbol_index::Query::new(exact_name.clone());
|
||||
local_query.exact();
|
||||
|
||||
let external_query = import_map::Query::new(exact_name)
|
||||
.name_only()
|
||||
.search_mode(import_map::SearchMode::Equals);
|
||||
let external_query = import_map::Query::new(exact_name);
|
||||
|
||||
(
|
||||
local_query,
|
||||
|
|
@ -61,17 +47,8 @@ pub fn items_with_name<'a>(
|
|||
let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone());
|
||||
|
||||
let mut external_query = import_map::Query::new(fuzzy_search_string.clone())
|
||||
.search_mode(import_map::SearchMode::Fuzzy)
|
||||
.name_only();
|
||||
match assoc_item_search {
|
||||
AssocItemSearch::Include => {}
|
||||
AssocItemSearch::Exclude => {
|
||||
external_query = external_query.exclude_import_kind(ImportKind::AssociatedItem);
|
||||
}
|
||||
AssocItemSearch::AssocItemsOnly => {
|
||||
external_query = external_query.assoc_items_only();
|
||||
}
|
||||
}
|
||||
.fuzzy()
|
||||
.assoc_search_mode(assoc_item_search);
|
||||
|
||||
if fuzzy_search_string.to_lowercase() != fuzzy_search_string {
|
||||
local_query.case_sensitive();
|
||||
|
|
@ -93,13 +70,15 @@ pub fn items_with_name<'a>(
|
|||
fn find_items<'a>(
|
||||
sema: &'a Semantics<'_, RootDatabase>,
|
||||
krate: Crate,
|
||||
assoc_item_search: AssocItemSearch,
|
||||
assoc_item_search: AssocSearchMode,
|
||||
local_query: symbol_index::Query,
|
||||
external_query: import_map::Query,
|
||||
) -> impl Iterator<Item = ItemInNs> + 'a {
|
||||
let _p = profile::span("find_items");
|
||||
let db = sema.db;
|
||||
|
||||
// NOTE: `external_query` includes `assoc_item_search`, so we don't need to
|
||||
// filter on our own.
|
||||
let external_importables =
|
||||
krate.query_external_importables(db, external_query).map(|external_importable| {
|
||||
match external_importable {
|
||||
|
|
@ -112,18 +91,15 @@ fn find_items<'a>(
|
|||
let local_results = local_query
|
||||
.search(&symbol_index::crate_symbols(db, krate))
|
||||
.into_iter()
|
||||
.filter_map(|local_candidate| match local_candidate.def {
|
||||
hir::ModuleDef::Macro(macro_def) => Some(ItemInNs::Macros(macro_def)),
|
||||
def => Some(ItemInNs::from(def)),
|
||||
.filter(move |candidate| match assoc_item_search {
|
||||
AssocSearchMode::Include => true,
|
||||
AssocSearchMode::Exclude => candidate.def.as_assoc_item(db).is_none(),
|
||||
AssocSearchMode::AssocItemsOnly => candidate.def.as_assoc_item(db).is_some(),
|
||||
})
|
||||
.map(|local_candidate| match local_candidate.def {
|
||||
hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def),
|
||||
def => ItemInNs::from(def),
|
||||
});
|
||||
|
||||
external_importables.chain(local_results).filter(move |&item| match assoc_item_search {
|
||||
AssocItemSearch::Include => true,
|
||||
AssocItemSearch::Exclude => !is_assoc_item(item, sema.db),
|
||||
AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db),
|
||||
})
|
||||
}
|
||||
|
||||
fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool {
|
||||
item.as_module_def().and_then(|module_def| module_def.as_assoc_item(db)).is_some()
|
||||
external_importables.chain(local_results)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,8 +200,8 @@ impl RootDatabase {
|
|||
hir_db::AstIdMapQuery
|
||||
// hir_db::ParseMacroExpansionQuery
|
||||
// hir_db::InternMacroCallQuery
|
||||
hir_db::MacroArgTextQuery
|
||||
hir_db::MacroDefQuery
|
||||
hir_db::MacroArgNodeQuery
|
||||
hir_db::DeclMacroExpanderQuery
|
||||
// hir_db::MacroExpandQuery
|
||||
hir_db::ExpandProcMacroQuery
|
||||
hir_db::HygieneFrameQuery
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ fn postorder(item: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> {
|
|||
})
|
||||
}
|
||||
|
||||
impl<'a> Ctx<'a> {
|
||||
impl Ctx<'_> {
|
||||
fn apply(&self, item: &SyntaxNode) {
|
||||
// `transform_path` may update a node's parent and that would break the
|
||||
// tree traversal. Thus all paths in the tree are collected into a vec
|
||||
|
|
|
|||
|
|
@ -149,10 +149,8 @@ impl SearchScope {
|
|||
|
||||
let mut to_visit: Vec<_> = module.children(db).collect();
|
||||
while let Some(module) = to_visit.pop() {
|
||||
if let InFile { file_id, value: ModuleSource::SourceFile(_) } =
|
||||
module.definition_source(db)
|
||||
{
|
||||
entries.insert(file_id.original_file(db), None);
|
||||
if let Some(file_id) = module.as_source_file_id(db) {
|
||||
entries.insert(file_id, None);
|
||||
}
|
||||
to_visit.extend(module.children(db));
|
||||
}
|
||||
|
|
@ -340,21 +338,21 @@ pub struct FindUsages<'a> {
|
|||
search_self_mod: bool,
|
||||
}
|
||||
|
||||
impl<'a> FindUsages<'a> {
|
||||
impl FindUsages<'_> {
|
||||
/// Enable searching for `Self` when the definition is a type or `self` for modules.
|
||||
pub fn include_self_refs(mut self) -> FindUsages<'a> {
|
||||
pub fn include_self_refs(mut self) -> Self {
|
||||
self.include_self_kw_refs = def_to_ty(self.sema, &self.def);
|
||||
self.search_self_mod = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Limit the search to a given [`SearchScope`].
|
||||
pub fn in_scope(self, scope: SearchScope) -> FindUsages<'a> {
|
||||
pub fn in_scope(self, scope: SearchScope) -> Self {
|
||||
self.set_scope(Some(scope))
|
||||
}
|
||||
|
||||
/// Limit the search to a given [`SearchScope`].
|
||||
pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
|
||||
pub fn set_scope(mut self, scope: Option<SearchScope>) -> Self {
|
||||
assert!(self.scope.is_none());
|
||||
self.scope = scope;
|
||||
self
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ use crate::SnippetCap;
|
|||
use base_db::{AnchoredPathBuf, FileId};
|
||||
use nohash_hasher::IntMap;
|
||||
use stdx::never;
|
||||
use syntax::{algo, ast, ted, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize};
|
||||
use syntax::{
|
||||
algo, ast, ted, AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange,
|
||||
TextSize,
|
||||
};
|
||||
use text_edit::{TextEdit, TextEditBuilder};
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
|
|
@ -237,19 +240,31 @@ impl SourceChangeBuilder {
|
|||
/// Adds a tabstop snippet to place the cursor before `node`
|
||||
pub fn add_tabstop_before(&mut self, _cap: SnippetCap, node: impl AstNode) {
|
||||
assert!(node.syntax().parent().is_some());
|
||||
self.add_snippet(PlaceSnippet::Before(node.syntax().clone()));
|
||||
self.add_snippet(PlaceSnippet::Before(node.syntax().clone().into()));
|
||||
}
|
||||
|
||||
/// Adds a tabstop snippet to place the cursor after `node`
|
||||
pub fn add_tabstop_after(&mut self, _cap: SnippetCap, node: impl AstNode) {
|
||||
assert!(node.syntax().parent().is_some());
|
||||
self.add_snippet(PlaceSnippet::After(node.syntax().clone()));
|
||||
self.add_snippet(PlaceSnippet::After(node.syntax().clone().into()));
|
||||
}
|
||||
|
||||
/// Adds a tabstop snippet to place the cursor before `token`
|
||||
pub fn add_tabstop_before_token(&mut self, _cap: SnippetCap, token: SyntaxToken) {
|
||||
assert!(token.parent().is_some());
|
||||
self.add_snippet(PlaceSnippet::Before(token.clone().into()));
|
||||
}
|
||||
|
||||
/// Adds a tabstop snippet to place the cursor after `token`
|
||||
pub fn add_tabstop_after_token(&mut self, _cap: SnippetCap, token: SyntaxToken) {
|
||||
assert!(token.parent().is_some());
|
||||
self.add_snippet(PlaceSnippet::After(token.clone().into()));
|
||||
}
|
||||
|
||||
/// Adds a snippet to move the cursor selected over `node`
|
||||
pub fn add_placeholder_snippet(&mut self, _cap: SnippetCap, node: impl AstNode) {
|
||||
assert!(node.syntax().parent().is_some());
|
||||
self.add_snippet(PlaceSnippet::Over(node.syntax().clone()))
|
||||
self.add_snippet(PlaceSnippet::Over(node.syntax().clone().into()))
|
||||
}
|
||||
|
||||
fn add_snippet(&mut self, snippet: PlaceSnippet) {
|
||||
|
|
@ -282,38 +297,40 @@ impl From<FileSystemEdit> for SourceChange {
|
|||
}
|
||||
|
||||
enum PlaceSnippet {
|
||||
/// Place a tabstop before a node
|
||||
Before(SyntaxNode),
|
||||
/// Place a tabstop before a node
|
||||
After(SyntaxNode),
|
||||
/// Place a placeholder snippet in place of the node
|
||||
Over(SyntaxNode),
|
||||
/// Place a tabstop before an element
|
||||
Before(SyntaxElement),
|
||||
/// Place a tabstop before an element
|
||||
After(SyntaxElement),
|
||||
/// Place a placeholder snippet in place of the element
|
||||
Over(SyntaxElement),
|
||||
}
|
||||
|
||||
impl PlaceSnippet {
|
||||
/// Places the snippet before or over a node with the given tab stop index
|
||||
/// Places the snippet before or over an element with the given tab stop index
|
||||
fn place(self, order: usize) {
|
||||
// ensure the target node is still attached
|
||||
// ensure the target element is still attached
|
||||
match &self {
|
||||
PlaceSnippet::Before(node) | PlaceSnippet::After(node) | PlaceSnippet::Over(node) => {
|
||||
// node should still be in the tree, but if it isn't
|
||||
PlaceSnippet::Before(element)
|
||||
| PlaceSnippet::After(element)
|
||||
| PlaceSnippet::Over(element) => {
|
||||
// element should still be in the tree, but if it isn't
|
||||
// then it's okay to just ignore this place
|
||||
if stdx::never!(node.parent().is_none()) {
|
||||
if stdx::never!(element.parent().is_none()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
PlaceSnippet::Before(node) => {
|
||||
ted::insert_raw(ted::Position::before(&node), Self::make_tab_stop(order));
|
||||
PlaceSnippet::Before(element) => {
|
||||
ted::insert_raw(ted::Position::before(&element), Self::make_tab_stop(order));
|
||||
}
|
||||
PlaceSnippet::After(node) => {
|
||||
ted::insert_raw(ted::Position::after(&node), Self::make_tab_stop(order));
|
||||
PlaceSnippet::After(element) => {
|
||||
ted::insert_raw(ted::Position::after(&element), Self::make_tab_stop(order));
|
||||
}
|
||||
PlaceSnippet::Over(node) => {
|
||||
let position = ted::Position::before(&node);
|
||||
node.detach();
|
||||
PlaceSnippet::Over(element) => {
|
||||
let position = ted::Position::before(&element);
|
||||
element.detach();
|
||||
|
||||
let snippet = ast::SourceFile::parse(&format!("${{{order}:_}}"))
|
||||
.syntax_node()
|
||||
|
|
@ -321,7 +338,7 @@ impl PlaceSnippet {
|
|||
|
||||
let placeholder =
|
||||
snippet.descendants().find_map(ast::UnderscoreExpr::cast).unwrap();
|
||||
ted::replace(placeholder.syntax(), node);
|
||||
ted::replace(placeholder.syntax(), element);
|
||||
|
||||
ted::insert_raw(position, snippet);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue