test: add rename testing (#448)

This commit is contained in:
Myriad-Dreamin 2024-07-22 14:29:53 +08:00 committed by GitHub
parent ede592796d
commit 1bbf800643
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 196 additions and 60 deletions

View file

@ -0,0 +1,5 @@
// path: user.typ
#let f() = 1;
-----
#import "user.typ": f
#(/* position after */ f);

View file

@ -1,6 +1,6 @@
---
source: crates/tinymist-query/src/prepare_rename.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/prepare_rename/builtin.typ
input_file: crates/tinymist-query/src/fixtures/rename/builtin.typ
---
null

View file

@ -0,0 +1,9 @@
---
source: crates/tinymist-query/src/prepare_rename.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/rename/cross-module.typ
---
{
"placeholder": "f",
"range": "1:23:1:24"
}

View file

@ -1,7 +1,7 @@
---
source: crates/tinymist-query/src/prepare_rename.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/prepare_rename/user.typ
input_file: crates/tinymist-query/src/fixtures/rename/user.typ
---
{
"placeholder": "f",

View file

@ -0,0 +1,6 @@
---
source: crates/tinymist-query/src/rename.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/rename/builtin.typ
---
null

View file

@ -0,0 +1,25 @@
---
source: crates/tinymist-query/src/rename.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/rename/cross-module.typ
---
{
"changes": {
"s1.typ": [
{
"newText": "new_name",
"range": "0:20:0:21"
},
{
"newText": "new_name",
"range": "1:23:1:24"
}
],
"user.typ": [
{
"newText": "new_name",
"range": "0:5:0:6"
}
]
}
}

View file

@ -0,0 +1,19 @@
---
source: crates/tinymist-query/src/rename.rs
expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
input_file: crates/tinymist-query/src/fixtures/rename/user.typ
---
{
"changes": {
"s0.typ": [
{
"newText": "new_name",
"range": "1:5:1:6"
},
{
"newText": "new_name",
"range": "3:20:3:21"
}
]
}
}

View file

@ -50,7 +50,7 @@ impl StatefulRequest for GotoDefinitionRequest {
target_selection_range: range,
}]));
log::info!("goto_definition: {fid:?} {res:?}");
log::debug!("goto_definition: {fid:?} {res:?}");
res
}
}

View file

@ -99,8 +99,8 @@ mod tests {
use crate::tests::*;
#[test]
fn test() {
snapshot_testing("prepare_rename", &|world, path| {
fn prepare() {
snapshot_testing("rename", &|world, path| {
let source = world.source_by_path(&path).unwrap();
let request = PrepareRenameRequest {

View file

@ -1,6 +1,7 @@
use log::debug;
use crate::{
analysis::SearchCtx,
prelude::*,
syntax::{DerefTarget, IdentRef},
SemanticRequest,
@ -27,7 +28,7 @@ impl SemanticRequest for ReferencesRequest {
let deref_target = ctx.deref_syntax_at(&source, self.position, 1)?;
let def_use = ctx.def_use(source.clone())?;
let locations = find_references(ctx, def_use, deref_target, ctx.position_encoding())?;
let locations = find_references(ctx, def_use, deref_target)?;
debug!("references: {locations:?}");
Some(locations)
@ -38,7 +39,6 @@ pub(crate) fn find_references(
ctx: &mut AnalysisContext<'_>,
def_use: Arc<crate::analysis::DefUseInfo>,
deref_target: DerefTarget<'_>,
position_encoding: PositionEncoding,
) -> Option<Vec<LspLocation>> {
let node = match deref_target {
DerefTarget::VarAccess(node) => node,
@ -95,71 +95,83 @@ pub(crate) fn find_references(
let root_def_use = ctx.def_use(def_source)?;
let root_def_id = root_def_use.get_def(def_fid, &def_ident)?.0;
find_references_root(
ctx,
root_def_use,
let worker = ReferencesWorker {
ctx: ctx.fork_for_search(),
references: vec![],
def_fid,
root_def_id,
def_ident,
position_encoding,
)
};
worker.root(root_def_use, root_def_id)
}
pub(crate) fn find_references_root(
ctx: &mut AnalysisContext<'_>,
def_use: Arc<crate::analysis::DefUseInfo>,
struct ReferencesWorker<'a, 'w> {
ctx: SearchCtx<'a, 'w>,
references: Vec<LspLocation>,
def_fid: TypstFileId,
def_id: DefId,
def_ident: IdentRef,
position_encoding: PositionEncoding,
) -> Option<Vec<LspLocation>> {
let def_source = ctx.source_by_id(def_fid).ok()?;
let uri = ctx.uri_for_id(def_fid).ok()?;
}
// todo: reuse uri, range to location
let mut references = def_use
.get_refs(def_id)
.map(|r| {
let range = typst_to_lsp::range(r.range.clone(), &def_source, position_encoding);
impl<'a, 'w> ReferencesWorker<'a, 'w> {
fn file(&mut self, ref_fid: TypstFileId) -> Option<()> {
log::debug!("references: file: {ref_fid:?}");
let ref_source = self.ctx.ctx.source_by_id(ref_fid).ok()?;
let def_use = self.ctx.ctx.def_use(ref_source.clone())?;
LspLocation {
uri: uri.clone(),
range,
}
})
.collect::<Vec<_>>();
let uri = self.ctx.ctx.uri_for_id(ref_fid).ok()?;
if def_use.is_exported(def_id) {
// Find dependents
let mut ctx = ctx.fork_for_search();
ctx.push_dependents(def_fid);
while let Some(ref_fid) = ctx.worklist.pop() {
let ref_source = ctx.ctx.source_by_id(ref_fid).ok()?;
let def_use = ctx.ctx.def_use(ref_source.clone())?;
let mut redefines = vec![];
if let Some((id, _def)) = def_use.get_def(self.def_fid, &self.def_ident) {
self.references.extend(def_use.get_refs(id).map(|r| {
log::debug!("references: at file: {ref_fid:?}, {r:?}");
let range = self.ctx.ctx.to_lsp_range(r.range.clone(), &ref_source);
let uri = ctx.ctx.uri_for_id(ref_fid).ok()?;
let mut redefines = vec![];
if let Some((id, _def)) = def_use.get_def(def_fid, &def_ident) {
references.extend(def_use.get_refs(id).map(|r| {
let range =
typst_to_lsp::range(r.range.clone(), &ref_source, position_encoding);
LspLocation {
uri: uri.clone(),
range,
}
}));
redefines.push(id);
if def_use.is_exported(id) {
ctx.push_dependents(ref_fid);
LspLocation {
uri: uri.clone(),
range,
}
};
}
}));
redefines.push(id);
if def_use.is_exported(id) {
self.ctx.push_dependents(ref_fid);
}
};
Some(())
}
Some(references)
fn root(
mut self,
def_use: Arc<crate::analysis::DefUseInfo>,
def_id: DefId,
) -> Option<Vec<LspLocation>> {
let def_source = self.ctx.ctx.source_by_id(self.def_fid).ok()?;
let uri = self.ctx.ctx.uri_for_id(self.def_fid).ok()?;
// todo: reuse uri, range to location
self.references = def_use
.get_refs(def_id)
.map(|r| {
let range = self.ctx.ctx.to_lsp_range(r.range.clone(), &def_source);
LspLocation {
uri: uri.clone(),
range,
}
})
.collect::<Vec<_>>();
if def_use.is_exported(def_id) {
// Find dependents
self.ctx.push_dependents(self.def_fid);
while let Some(ref_fid) = self.ctx.worklist.pop() {
self.file(ref_fid);
}
}
Some(self.references)
}
}
#[cfg(test)]

View file

@ -31,7 +31,7 @@ impl StatefulRequest for RenameRequest {
validate_renaming_definition(&lnk)?;
let def_use = ctx.def_use(source.clone())?;
let references = find_references(ctx, def_use, deref_target, ctx.position_encoding())?;
let references = find_references(ctx, def_use, deref_target)?;
let mut editions = HashMap::new();
@ -63,6 +63,8 @@ impl StatefulRequest for RenameRequest {
});
}
log::info!("rename editions: {editions:?}");
// todo: name conflict analysis
Some(WorkspaceEdit {
changes: Some(editions),
@ -70,3 +72,37 @@ impl StatefulRequest for RenameRequest {
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tests::*;
#[test]
fn test() {
snapshot_testing("rename", &|world, path| {
let source = world.source_by_path(&path).unwrap();
let request = RenameRequest {
path: path.clone(),
position: find_test_position(&source),
new_name: "new_name".to_string(),
};
let mut result = request.request(world, None);
// sort the edits to make the snapshot stable
if let Some(r) = result.as_mut().and_then(|r| r.changes.as_mut()) {
for edits in r.values_mut() {
edits.sort_by(|a, b| {
a.range
.start
.cmp(&b.range.start)
.then(a.range.end.cmp(&b.range.end))
});
}
};
assert_snapshot!(JsonRepr::new_redacted(result, &REDACT_LOC));
});
}
}

View file

@ -286,6 +286,7 @@ pub static REDACT_LOC: Lazy<RedactFields> = Lazy::new(|| {
"location",
"uri",
"range",
"changes",
"selectionRange",
"targetRange",
"targetSelectionRange",
@ -356,6 +357,29 @@ impl Redact for RedactFields {
};
match k {
"changes" => {
// object range => v
m.insert(
k.to_owned(),
Value::Object(
t.as_object()
.unwrap()
.iter()
.map(|(k, v)| {
(
Path::new(k)
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_owned(),
v.clone(),
)
})
.collect(),
),
);
}
"range"
| "selectionRange"
| "originSelectionRange"