Skip to content

Commit 0159b7c

Browse files
committed
Auto merge of rust-lang#17083 - matklad:matklad/test-search, r=lnicola
ide: improve ReferenceCategoryType It is bitset semantically --- many categorical things can be true about a reference at the same time. In parciular, a reference can be a "test" and a "write" at the same time.
2 parents 58eb1f0 + f67a70d commit 0159b7c

File tree

9 files changed

+188
-132
lines changed

9 files changed

+188
-132
lines changed

src/tools/rust-analyzer/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1149,8 +1149,14 @@ fn reference_is_exclusive(
11491149
node: &dyn HasTokenAtOffset,
11501150
ctx: &AssistContext<'_>,
11511151
) -> bool {
1152+
// FIXME: this quite an incorrect way to go about doing this :-)
1153+
// `FileReference` is an IDE-type --- it encapsulates data communicated to the human,
1154+
// but doesn't necessary fully reflect all the intricacies of the underlying language semantics
1155+
// The correct approach here would be to expose this entire analysis as a method on some hir
1156+
// type. Something like `body.free_variables(statement_range)`.
1157+
11521158
// we directly modify variable with set: `n = 0`, `n += 1`
1153-
if reference.category == Some(ReferenceCategory::Write) {
1159+
if reference.category.contains(ReferenceCategory::WRITE) {
11541160
return true;
11551161
}
11561162

src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ fn used_once_in_scope(ctx: &AssistContext<'_>, def: Definition, scopes: &Vec<Sea
145145
for scope in scopes {
146146
let mut search_non_import = |_, r: FileReference| {
147147
// The import itself is a use; we must skip that.
148-
if r.category != Some(ReferenceCategory::Import) {
148+
if !r.category.contains(ReferenceCategory::IMPORT) {
149149
found = true;
150150
true
151151
} else {

src/tools/rust-analyzer/crates/ide-db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ indexmap.workspace = true
2626
memchr = "2.6.4"
2727
triomphe.workspace = true
2828
nohash-hasher.workspace = true
29+
bitflags.workspace = true
2930

3031
# local deps
3132
base-db.workspace = true

src/tools/rust-analyzer/crates/ide-db/src/search.rs

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub struct FileReference {
6464
pub range: TextRange,
6565
/// The node of the reference in the (macro-)file
6666
pub name: FileReferenceNode,
67-
pub category: Option<ReferenceCategory>,
67+
pub category: ReferenceCategory,
6868
}
6969

7070
#[derive(Debug, Clone)]
@@ -124,17 +124,16 @@ impl FileReferenceNode {
124124
}
125125
}
126126

127-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
128-
pub enum ReferenceCategory {
129-
// FIXME: Add this variant and delete the `retain_adt_literal_usages` function.
130-
// Create
131-
Write,
132-
Read,
133-
Import,
134-
// FIXME: Some day should be able to search in doc comments. Would probably
135-
// need to switch from enum to bitflags then?
136-
// DocComment
137-
Test,
127+
bitflags::bitflags! {
128+
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, Debug)]
129+
pub struct ReferenceCategory: u8 {
130+
// FIXME: Add this variant and delete the `retain_adt_literal_usages` function.
131+
// const CREATE = 1 << 0;
132+
const WRITE = 1 << 0;
133+
const READ = 1 << 1;
134+
const IMPORT = 1 << 2;
135+
const TEST = 1 << 3;
136+
}
138137
}
139138

140139
/// Generally, `search_scope` returns files that might contain references for the element.
@@ -660,7 +659,7 @@ impl<'a> FindUsages<'a> {
660659
let reference = FileReference {
661660
range,
662661
name: FileReferenceNode::NameRef(name_ref.clone()),
663-
category: None,
662+
category: ReferenceCategory::empty(),
664663
};
665664
sink(file_id, reference)
666665
}
@@ -676,10 +675,15 @@ impl<'a> FindUsages<'a> {
676675
match NameRefClass::classify(self.sema, name_ref) {
677676
Some(NameRefClass::Definition(def @ Definition::Module(_))) if def == self.def => {
678677
let FileRange { file_id, range } = self.sema.original_range(name_ref.syntax());
678+
let category = if is_name_ref_in_import(name_ref) {
679+
ReferenceCategory::IMPORT
680+
} else {
681+
ReferenceCategory::empty()
682+
};
679683
let reference = FileReference {
680684
range,
681685
name: FileReferenceNode::NameRef(name_ref.clone()),
682-
category: is_name_ref_in_import(name_ref).then_some(ReferenceCategory::Import),
686+
category,
683687
};
684688
sink(file_id, reference)
685689
}
@@ -700,7 +704,7 @@ impl<'a> FindUsages<'a> {
700704
let reference = FileReference {
701705
range,
702706
name: FileReferenceNode::FormatStringEntry(token, range),
703-
category: Some(ReferenceCategory::Read),
707+
category: ReferenceCategory::READ,
704708
};
705709
sink(file_id, reference)
706710
}
@@ -719,7 +723,7 @@ impl<'a> FindUsages<'a> {
719723
let reference = FileReference {
720724
range,
721725
name: FileReferenceNode::Lifetime(lifetime.clone()),
722-
category: None,
726+
category: ReferenceCategory::empty(),
723727
};
724728
sink(file_id, reference)
725729
}
@@ -817,7 +821,7 @@ impl<'a> FindUsages<'a> {
817821
range,
818822
name: FileReferenceNode::Name(name.clone()),
819823
// FIXME: mutable patterns should have `Write` access
820-
category: Some(ReferenceCategory::Read),
824+
category: ReferenceCategory::READ,
821825
};
822826
sink(file_id, reference)
823827
}
@@ -826,7 +830,7 @@ impl<'a> FindUsages<'a> {
826830
let reference = FileReference {
827831
range,
828832
name: FileReferenceNode::Name(name.clone()),
829-
category: None,
833+
category: ReferenceCategory::empty(),
830834
};
831835
sink(file_id, reference)
832836
}
@@ -851,7 +855,7 @@ impl<'a> FindUsages<'a> {
851855
let reference = FileReference {
852856
range,
853857
name: FileReferenceNode::Name(name.clone()),
854-
category: None,
858+
category: ReferenceCategory::empty(),
855859
};
856860
sink(file_id, reference)
857861
}
@@ -875,38 +879,41 @@ impl ReferenceCategory {
875879
sema: &Semantics<'_, RootDatabase>,
876880
def: &Definition,
877881
r: &ast::NameRef,
878-
) -> Option<ReferenceCategory> {
882+
) -> ReferenceCategory {
883+
let mut result = ReferenceCategory::empty();
879884
if is_name_ref_in_test(sema, r) {
880-
return Some(ReferenceCategory::Test);
885+
result |= ReferenceCategory::TEST;
881886
}
882887

883888
// Only Locals and Fields have accesses for now.
884889
if !matches!(def, Definition::Local(_) | Definition::Field(_)) {
885-
return is_name_ref_in_import(r).then_some(ReferenceCategory::Import);
890+
if is_name_ref_in_import(r) {
891+
result |= ReferenceCategory::IMPORT;
892+
}
893+
return result;
886894
}
887895

888896
let mode = r.syntax().ancestors().find_map(|node| {
889-
match_ast! {
890-
match node {
891-
ast::BinExpr(expr) => {
892-
if matches!(expr.op_kind()?, ast::BinaryOp::Assignment { .. }) {
893-
// If the variable or field ends on the LHS's end then it's a Write (covers fields and locals).
894-
// FIXME: This is not terribly accurate.
895-
if let Some(lhs) = expr.lhs() {
896-
if lhs.syntax().text_range().end() == r.syntax().text_range().end() {
897-
return Some(ReferenceCategory::Write);
897+
match_ast! {
898+
match node {
899+
ast::BinExpr(expr) => {
900+
if matches!(expr.op_kind()?, ast::BinaryOp::Assignment { .. }) {
901+
// If the variable or field ends on the LHS's end then it's a Write
902+
// (covers fields and locals). FIXME: This is not terribly accurate.
903+
if let Some(lhs) = expr.lhs() {
904+
if lhs.syntax().text_range().end() == r.syntax().text_range().end() {
905+
return Some(ReferenceCategory::WRITE)
906+
}
898907
}
899908
}
900-
}
901-
Some(ReferenceCategory::Read)
902-
},
903-
_ => None
909+
Some(ReferenceCategory::READ)
910+
},
911+
_ => None,
912+
}
904913
}
905-
}
906-
});
914+
}).unwrap_or(ReferenceCategory::READ);
907915

908-
// Default Locals and Fields to read
909-
mode.or(Some(ReferenceCategory::Read))
916+
result | mode
910917
}
911918
}
912919

0 commit comments

Comments
 (0)