From 4779d845712e4d071ff14f28d66e66f2ffca2cf7 Mon Sep 17 00:00:00 2001 From: arookieofc Date: Tue, 10 Nov 2026 22:49:39 +0800 Subject: [PATCH] feat(mybatis): navigate and complete @ResultMap ids (#2461) (#2533) * feat(mybatis): navigate and complete @ResultMap ids (#2461) @ResultMap on a method jumps to @Results(id) in the same file, else to the XML ; resultMap= on XML statements jumps to ; all three get gutter markers and @ResultMap( completes ids (annotation ids plus XML ids, merged). Unterminated strings now end at the newline and interface-level ; resyncs paren tracking, so typing half-written annotations no longer swallows the rest of the file. * chore(mybatis): retrigger CI after retargeting to main --- plugins/official/mybatis/Cargo.lock | 2 +- plugins/official/mybatis/Cargo.toml | 2 +- plugins/official/mybatis/dist/plugin.wasm | Bin 242292 -> 258999 bytes .../official/mybatis/dist/plugin.wasm.sources | 2 +- plugins/official/mybatis/plugin.toml | 4 +- plugins/official/mybatis/src/lib.rs | 427 ++++++++++++++++-- 6 files changed, 388 insertions(+), 49 deletions(-) diff --git a/plugins/official/mybatis/Cargo.lock b/plugins/official/mybatis/Cargo.lock index f16ab4da2..081926072 100644 --- a/plugins/official/mybatis/Cargo.lock +++ b/plugins/official/mybatis/Cargo.lock @@ -105,7 +105,7 @@ dependencies = [ [[package]] name = "openidea-plugin-openidea-mybatis" -version = "0.3.0" +version = "0.4.0" dependencies = [ "openidea-plugin", ] diff --git a/plugins/official/mybatis/Cargo.toml b/plugins/official/mybatis/Cargo.toml index eb3717b3e..4f5a3fcfe 100644 --- a/plugins/official/mybatis/Cargo.toml +++ b/plugins/official/mybatis/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openidea-plugin-openidea-mybatis" -version = "0.3.0" +version = "0.4.0" edition = "2024" publish = false diff --git a/plugins/official/mybatis/dist/plugin.wasm b/plugins/official/mybatis/dist/plugin.wasm index 6c301c1aea73001d777d65301f79bfb872b34b2e..3c710f8e8892a1725cad95b77483eadb01b5afed 100644 GIT binary patch delta 64002 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 Lo&}?feJ%eFNGj;s delta 49299 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, } +/// `@ResultMap("…")` on one method: `method` indexes `MapperJava::methods`, +/// `name` covers the id string (quotes excluded). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ResultMapRef { + pub method: usize, + pub name: Named, +} + /// A Java interface. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct MapperJava { @@ -69,6 +77,9 @@ pub struct MapperJava { pub decl: Option, pub methods: Vec<(Named, Vec)>, pub annotation_sql: Vec, + pub result_refs: Vec, + /// `@Results(id = "…")` definitions: method index and the id string. + pub result_ids: Vec<(usize, Named)>, } fn range_of(text: &str, start: usize, end: usize) -> Range { @@ -140,6 +151,10 @@ fn skip_string(bytes: &[u8], mut i: usize) -> usize { i += 1; while i < bytes.len() { match bytes[i] { + // Java string/char literals cannot span lines; an unterminated + // quote ends at the newline so one broken line cannot swallow + // the rest of the file (e.g. `@ResultMap("` while typing). + b'\n' | b'\r' => return i, b'\\' => i += 2, b if b == quote => return i + 1, _ => i += 1, @@ -341,12 +356,11 @@ const SQL_ANNOTATIONS: [&str; 4] = ["Select", "Insert", "Update", "Delete"]; /// A string literal's value with its byte offsets (quotes excluded). type LitSpan = (String, usize, usize); -/// The `#{…}` / `${…}` matches in one method's `@Select`/`@Insert`/`@Update`/ -/// `@Delete` SQL string literals: `(string start, string end, params)` with -/// offsets in `head` (the declaration's annotations and signature). Array -/// values (`@Select({…})`) and nested annotations in other arguments are -/// skipped over, never read as SQL. -fn annotation_sql_of(head: &str) -> Vec<(usize, usize, Vec)> { +/// Each `@Name(…)` in `head`: the simple annotation name and its arguments' +/// byte range (offsets in `head`), minding nesting, strings and comments. +/// Annotations nested inside another annotation's arguments are only reported +/// when the outer one has no argument list scanned here. +fn annotations_of(head: &str) -> Vec<(String, usize, usize)> { let bytes = head.as_bytes(); let mut out = Vec::new(); let mut i = 0; @@ -362,12 +376,12 @@ fn annotation_sql_of(head: &str) -> Vec<(usize, usize, Vec)> { while !head.is_char_boundary(j) { j -= 1; } - let simple = head[i + 1..j].rsplit('.').next().unwrap_or(""); + let simple = head[i + 1..j].rsplit('.').next().unwrap_or("").to_owned(); let mut k = j; while k < bytes.len() && bytes[k].is_ascii_whitespace() { k += 1; } - if SQL_ANNOTATIONS.contains(&simple) && bytes.get(k) == Some(&b'(') { + if bytes.get(k) == Some(&b'(') { // The annotation's arguments, minding nesting and strings. let (mut close, mut depth) = (k + 1, 1usize); while close < bytes.len() { @@ -391,27 +405,7 @@ fn annotation_sql_of(head: &str) -> Vec<(usize, usize, Vec)> { } } if depth == 0 { - let args = &head[k + 1..close]; - let mut s = 0; - while s < args.len() { - if args.as_bytes()[s] == b'"' { - let e = skip_string(args.as_bytes(), s); - // Without the quotes; skip_string stops just past `"`. - if e > s + 1 && args.as_bytes()[e - 1] == b'"' { - let (cs, ce) = (s + 1, e - 1); - let params = sql_params(&args[cs..ce]) - .into_iter() - .map(|(n, ps, pe)| (n, k + 1 + cs + ps, k + 1 + cs + pe)) - .collect(); - out.push((k + 1 + cs, k + 1 + ce, params)); - s = e; - } else { - s += 1; // unterminated: not a SQL string - } - } else { - s += 1; - } - } + out.push((simple, k + 1, close)); } i = close + 1; } else { @@ -424,6 +418,121 @@ fn annotation_sql_of(head: &str) -> Vec<(usize, usize, Vec)> { out } +/// The string literals in annotation `args`: `(value, value start, value end)` +/// with offsets in `args` (quotes excluded). Unterminated strings are skipped. +fn string_literals(args: &str) -> Vec<(String, usize, usize)> { + let bytes = args.as_bytes(); + let mut out = Vec::new(); + let mut s = 0; + while s < bytes.len() { + if bytes[s] == b'"' { + let e = skip_string(bytes, s); + // Without the quotes; skip_string stops just past `"`. + if e > s + 1 && bytes[e - 1] == b'"' { + out.push((args[s + 1..e - 1].to_owned(), s + 1, e - 1)); + s = e; + } else { + s += 1; // unterminated: not a string + } + } else { + s += 1; + } + } + out +} + +/// The value of `key = "…"`: the first string-valued `key` at nesting depth 0 +/// in annotation `args`, with offsets in `args`. Strings are skipped while +/// looking, so `property="id"` never matches `key = "id"`. +fn annotation_string_arg(args: &str, key: &str) -> Option<(String, usize, usize)> { + let bytes = args.as_bytes(); + let mut depth = 0usize; + let mut i = 0; + while i < bytes.len() { + match bytes[i] { + b'"' | b'\'' => i = skip_string(bytes, i), + b'/' if matches!(bytes.get(i + 1), Some(b'/' | b'*')) => i = skip_comment(bytes, i), + b'(' | b'{' | b'[' => { + depth += 1; + i += 1; + } + b')' | b'}' | b']' => { + depth = depth.saturating_sub(1); + i += 1; + } + _ if depth == 0 && ident(bytes[i] as char) => { + let mut j = i + 1; + while j < bytes.len() && ident(bytes[j] as char) { + j += 1; + } + if &args[i..j] == key { + let mut k = j; + while k < bytes.len() && bytes[k].is_ascii_whitespace() { + k += 1; + } + if bytes.get(k) == Some(&b'=') { + k += 1; + while k < bytes.len() && bytes[k].is_ascii_whitespace() { + k += 1; + } + if bytes.get(k) == Some(&b'"') { + let e = skip_string(bytes, k); + if e > k + 1 && bytes[e - 1] == b'"' { + return Some((args[k + 1..e - 1].to_owned(), k + 1, e - 1)); + } + } + i = k; + continue; + } + } + i = j; + } + _ => i += 1, + } + } + None +} + +/// The `#{…}` / `${…}` matches in one method's `@Select`/`@Insert`/`@Update`/ +/// `@Delete` SQL string literals: `(string start, string end, params)` with +/// offsets in `head` (the declaration's annotations and signature). Array +/// values (`@Select({…})`) and nested annotations in other arguments are +/// skipped over, never read as SQL. +fn annotation_sql_of(head: &str) -> Vec<(usize, usize, Vec)> { + let mut out = Vec::new(); + for (simple, a, b) in annotations_of(head) { + if !SQL_ANNOTATIONS.contains(&simple.as_str()) { + continue; + } + let args = &head[a..b]; + for (value, cs, ce) in string_literals(args) { + let params = sql_params(&value).into_iter().map(|(n, ps, pe)| (n, a + cs + ps, a + cs + pe)).collect(); + out.push((a + cs, a + ce, params)); + } + } + out +} + +/// `@ResultMap("…")` references and `@Results(id = "…")` definitions in one +/// method's head: `(id, id start, id end)` with offsets in `head` (quotes +/// excluded). Every `@ResultMap` string counts, so `@ResultMap({"a", "b"})` +/// yields both. +fn result_map_of(head: &str) -> (Vec, Vec) { + let mut refs = Vec::new(); + let mut defs = Vec::new(); + for (simple, a, b) in annotations_of(head) { + let args = &head[a..b]; + if simple == "ResultMap" { + refs.extend(string_literals(args).into_iter().map(|(v, s, e)| (v, a + s, a + e))); + } else if simple == "Results" + && let Some((v, s, e)) = annotation_string_arg(args, "id") + { + defs.push((v, a + s, a + e)); + } + } + (refs, defs) +} + /// The interface's name and methods (with their parameter names). pub fn parse_java(text: &str) -> MapperJava { let package = @@ -441,11 +550,15 @@ pub fn parse_java(text: &str) -> MapperJava { let body_start = text[i..].find('{').map_or(text.len(), |b| i + b + 1); let mut methods = Vec::new(); let mut annotation_sql = Vec::new(); + let mut result_refs = Vec::new(); + let mut result_ids = Vec::new(); let mut depth = 0; + let mut paren = 0usize; let mut stmt_start = body_start; - // Strings and comments may hold `{`, `}` or `;` (notably the `#{…}` - // braces in annotation SQL), so skip them: only structural braces and - // semicolons split statements. + // Strings and comments may hold `{`, `}`, `(`, `)` or `;` (notably the + // `#{…}` braces in annotation SQL), so skip them: braces inside + // parentheses (annotation arguments) are not structural, and only + // structural braces and semicolons split statements. let body = &text[body_start..]; let body_bytes = body.as_bytes(); let mut i = 0; @@ -454,16 +567,28 @@ pub fn parse_java(text: &str) -> MapperJava { match body_bytes[i] { b'"' | b'\'' => i = skip_string(body_bytes, i), b'/' if matches!(body_bytes.get(i + 1), Some(b'/' | b'*')) => i = skip_comment(body_bytes, i), - b'{' => { + b'(' => { + paren += 1; + i += 1; + } + b')' => { + paren = paren.saturating_sub(1); + i += 1; + } + b'{' if paren == 0 => { depth += 1; i += 1; } - b'}' if depth == 0 => break, - b'}' => { + b'}' if depth == 0 && paren == 0 => break, + b'}' if paren == 0 => { depth -= 1; stmt_start = k + 1; i += 1; } + // At interface level `;` always ends the statement: field and + // method declarations cannot hold one inside parentheses, so an + // unbalanced `(` from a broken line (e.g. `@ResultMap("` while + // typing) resyncs here instead of swallowing the rest of the file. b';' if depth == 0 => { let stmt = &text[stmt_start..k]; if let Some(decl) = scan_declaration(stmt) @@ -492,14 +617,23 @@ pub fn parse_java(text: &str) -> MapperJava { if !strings.is_empty() { annotation_sql.push(AnnotationSql { method, strings, params: sql_params }); } + let (refs, defs) = result_map_of(&stmt[..decl.parens.0]); + result_refs.extend(refs.into_iter().map(|(v, rs, re)| ResultMapRef { + method, + name: Named { name: v, range: range_of(text, stmt_start + rs, stmt_start + re) }, + })); + result_ids.extend(defs.into_iter().map(|(v, ds, de)| { + (method, Named { name: v, range: range_of(text, stmt_start + ds, stmt_start + de) }) + })); } stmt_start = k + 1; + paren = 0; i += 1; } _ => i += 1, } } - MapperJava { name, decl, methods, annotation_sql } + MapperJava { name, decl, methods, annotation_sql, result_refs, result_ids } } fn project_of(path: &str) -> Option { @@ -583,6 +717,52 @@ impl Navigator { pick(&other, path) } + /// Inside `@ResultMap("…")`: the known result-map ids — `@Results(id = + /// "…")` in this file, plus the XML mapper's `` ids. `None` + /// when the cursor is not on a `@ResultMap` id. + fn result_map_completion(&mut self, doc: &Document, at: Position) -> Option> { + let cursor = offset(&doc.text, at)?; + let before = &doc.text[..cursor]; + let java = parse_java(&doc.text); + // A closed string: the recorded id range. Otherwise (still typing) the + // `@ResultMap("` prefix on the cursor's line. + let typed: &str = if let Some(hit) = java.result_refs.iter().find(|r| contains(r.name.range, at)) { + &doc.text[offset(&doc.text, hit.name.range.start)?..cursor] + } else { + let line_start = before.rfind('\n').map_or(0, |i| i + 1); + let line = &before[line_start..]; + let rel = line.rfind("ResultMap(\"")?; + let prev = line[..rel].chars().next_back()?; + if prev != '@' && prev != '.' { + return None; + } + let typed = &line[rel + 11..]; + if !typed.chars().all(|c| ident(c) || c == '.' || c == '-') { + return None; + } + typed + }; + let start = Position::new(at.line, at.character - typed.encode_utf16().count() as u32); + let mut ids: Vec = java.result_ids.iter().map(|(_, d)| d.name.clone()).collect(); + if let Some(project) = project_of(&doc.path) + && let Some(name) = &java.name + && let Some((_, xml)) = self.xml_for(&project, name) + { + ids.extend(xml.result_maps.iter().map(|m| m.name.clone())); + } + ids.sort(); + ids.dedup(); + Some( + ids.into_iter() + .filter(|id| id.starts_with(typed)) + .map(|id| CompletionItem { + replace: Some(Range::new(start, at)), + ..CompletionItem::new(&id, CompletionKind::Value) + }) + .collect(), + ) + } + /// Pairs of (name in this document, target location) for `doc`. fn links(&mut self, doc: &Document) -> Vec<(Named, Location, String)> { let Some(project) = project_of(&doc.path) else { return Vec::new() }; @@ -622,16 +802,40 @@ impl Navigator { out } else { let java = parse_java(&doc.text); - let Some(name) = java.name else { return Vec::new() }; - let Some((path, xml)) = self.xml_for(&project, &name) else { return Vec::new() }; - let file = path.rsplit(['/', '\\']).next().unwrap_or(&path).to_owned(); - java.methods - .into_iter() - .filter_map(|(m, _)| { + let Some(name) = java.name.clone() else { return Vec::new() }; + let simple = name.rsplit('.').next().unwrap_or(&name).to_owned(); + // `@ResultMap("…")`: the `@Results(id = "…")` in this file when + // present, else the XML mapper's ``. Needs no XML for + // pure-annotation mappers. + let xml = self.xml_for(&project, &name); + let mut out: Vec<(Named, Location, String)> = Vec::new(); + for r in &java.result_refs { + if let Some((method, def)) = java.result_ids.iter().find(|(_, d)| d.name == r.name.name) { + let (m, _) = &java.methods[*method]; + out.push(( + r.name.clone(), + Location { path: doc.path.clone(), range: def.range }, + format!("{simple}.{}(): {}", m.name, def.name), + )); + } else if let Some((path, xml)) = &xml + && let Some(def) = xml.result_maps.iter().find(|m| m.name == r.name.name) + { + let file = path.rsplit(['/', '\\']).next().unwrap_or(path).to_owned(); + out.push(( + r.name.clone(), + Location { path: path.clone(), range: def.range }, + format!("{file}: {}", def.name), + )); + } + } + if let Some((path, xml)) = xml { + let file = path.rsplit(['/', '\\']).next().unwrap_or(&path).to_owned(); + out.extend(java.methods.into_iter().filter_map(|(m, _)| { let s = xml.statements.iter().find(|s| s.name == m.name)?; Some((m, Location { path: path.clone(), range: s.range }, format!("{file}: {}", s.name))) - }) - .collect() + })); + } + out } } } @@ -679,6 +883,9 @@ impl Providers for Navigator { fn completion(&mut self, doc: &Document, at: Position, _trigger: Option<&str>) -> Vec { if doc.language == "java" { + if let Some(items) = self.result_map_completion(doc, at) { + return items; + } return annotation_param_completion(doc, at); } if doc.language != "xml" { @@ -1107,4 +1314,136 @@ mod tests { let plain = n.completion(&doc, Position::new(5, 10), None); assert!(plain.is_empty()); } + + const RESULT_JAVA: &str = concat!( + "package com.acme;\n", + "import org.apache.ibatis.annotations.Result;\n", + "import org.apache.ibatis.annotations.ResultMap;\n", + "import org.apache.ibatis.annotations.Results;\n", + "import org.apache.ibatis.annotations.Select;\n", + "public interface UserMapper {\n", + " @Select(\"SELECT * FROM users WHERE id = #{id}\")\n", + " @ResultMap(\"userMap\")\n", + " User findById(Long id);\n", + "\n", + " @Results(\n", + " id = \"orderMap\",\n", + " value = {@Result(property = \"userName\", column = \"user_name\")}\n", + " )\n", + " @ResultMap(\"orderMap\")\n", + " Order findOrder(Long id);\n", + "}\n" + ); + + const RESULT_XML: &str = concat!( + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n" + ); + + fn result_setup() -> MockHost { + let host = MockHost::install(); + host.add_file("src/main/java/com/acme/UserMapper.java", RESULT_JAVA); + host.add_file("src/main/resources/mapper/UserMapper.xml", RESULT_XML); + host.add_file("pom.xml", ""); + host + } + + #[test] + fn parses_result_map_refs_and_ids() { + let java = parse_java(RESULT_JAVA); + let refs: Vec<_> = + java.result_refs.iter().map(|r| (java.methods[r.method].0.name.as_str(), r.name.name.as_str())).collect(); + assert_eq!(refs, [("findById", "userMap"), ("findOrder", "orderMap")]); + let ids: Vec<_> = + java.result_ids.iter().map(|(m, d)| (java.methods[*m].0.name.as_str(), d.name.as_str())).collect(); + assert_eq!(ids, [("findOrder", "orderMap")]); + let xml = parse_xml(RESULT_XML); + assert_eq!(xml.result_maps.iter().map(|m| m.name.as_str()).collect::>(), ["userMap", "extraMap"]); + assert_eq!(xml.result_map_refs.iter().map(|m| m.name.as_str()).collect::>(), ["userMap"]); + } + + /// `@ResultMap("…")` jumps to the XML ``, or to the + /// `@Results(id = "…")` in the same file; `resultMap="…"` in XML jumps to + /// the ``. All three get gutter markers. + #[test] + fn navigates_result_map_refs() { + let _host = result_setup(); + let mut n = Navigator::default(); + let java = doc("/project/src/main/java/com/acme/UserMapper.java", "java", RESULT_JAVA); + let xml = doc("/project/src/main/resources/mapper/UserMapper.xml", "xml", RESULT_XML); + + // `@ResultMap("userMap")` → the XML ``. + let line = RESULT_JAVA.lines().nth(7).unwrap(); + let col = line.find("\"userMap\"").unwrap() + 2; + let got = n.definition(&java, Position::new(7, col as u32)); + let want = parse_xml(RESULT_XML).result_maps[0].range; + assert_eq!(got, vec![Location { path: xml.path.clone(), range: want }]); + + // `@ResultMap("orderMap")` → the `@Results(id = "orderMap")` above. + let line = RESULT_JAVA.lines().nth(14).unwrap(); + let col = line.find("\"orderMap\"").unwrap() + 2; + let got = n.definition(&java, Position::new(14, col as u32)); + let want = parse_java(RESULT_JAVA).result_ids[0].1.range; + assert_eq!(got, vec![Location { path: java.path.clone(), range: want }]); + + // `resultMap="userMap"` in XML → the `` in the same file. + let line = RESULT_XML.lines().nth(6).unwrap(); + let col = line.find("resultMap=\"userMap\"").unwrap() + 12; + let got = n.definition(&xml, Position::new(6, col as u32)); + let want = parse_xml(RESULT_XML).result_maps[0].range; + assert_eq!(got, vec![Location { path: xml.path.clone(), range: want }]); + + let mut markers: Vec<_> = n.line_markers(&java).into_iter().map(|m| (m.line, m.tooltip)).collect(); + markers.sort(); + assert_eq!( + markers, + [ + (7, "Go to UserMapper.xml: userMap".to_owned()), + (8, "Go to UserMapper.xml: findById".to_owned()), + (14, "Go to UserMapper.findOrder(): orderMap".to_owned()) + ] + ); + let markers = n.line_markers(&xml); + assert_eq!( + markers.iter().map(|m| (m.line, m.tooltip.as_str())).collect::>(), + [(1, "Go to interface UserMapper"), (6, "Go to UserMapper.findById()"), (6, "Go to resultMap userMap")] + ); + } + + /// Inside `@ResultMap("…")`: annotation `@Results` ids and XML + /// `` ids, merged and sorted — even while the string is still + /// unterminated. + #[test] + fn completes_result_map_ids() { + let _host = result_setup(); + let mut n = Navigator::default(); + // Still typing: the string is unterminated. + let text = RESULT_JAVA.replace("@ResultMap(\"userMap\")", "@ResultMap(\"user"); + let typing = doc("/project/src/main/java/com/acme/UserMapper.java", "java", &text); + let line = text.lines().nth(7).unwrap(); + let col = line.find("\"user").unwrap() + 1 + 4; + let items = n.completion(&typing, Position::new(7, col as u32), None); + assert_eq!(items.iter().map(|c| c.label.as_str()).collect::>(), ["userMap"]); + // Just opened the string: every known id. + let text = RESULT_JAVA.replace("@ResultMap(\"userMap\")", "@ResultMap(\""); + let opened = doc("/project/src/main/java/com/acme/UserMapper.java", "java", &text); + let line = text.lines().nth(7).unwrap(); + let col = line.find("ResultMap(\"").unwrap() + 11; + let items = n.completion(&opened, Position::new(7, col as u32), None); + assert_eq!(items.iter().map(|c| c.label.as_str()).collect::>(), ["extraMap", "orderMap", "userMap"]); + // Closed string, cursor inside: the recorded range. + let closed = doc("/project/src/main/java/com/acme/UserMapper.java", "java", RESULT_JAVA); + let line = RESULT_JAVA.lines().nth(7).unwrap(); + let col = line.find("\"userMap\"").unwrap() + 1 + 2; + let items = n.completion(&closed, Position::new(7, col as u32), None); + assert_eq!(items.iter().map(|c| c.label.as_str()).collect::>(), ["userMap"]); + } }