diff --git a/CHANGELOG.md b/CHANGELOG.md index d6947bec1..2b4cc1ac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixes +- **Code written without a space before a name resolves like spaced code.** Where one token ends exactly where the next begins, the resolver read the syntax at that point as the earlier token: in `x=1;local function helper()` it saw the `;`, so the Lua local read as global and calls from other files linked to it, and in `if ($x instanceof Foo)$x->bar();` it saw the `)`, so the PHP guard did not type `$x`. It now reads the token that starts there, the same way the TypeScript side already did. On json, jq and CPython the graph is unchanged. - **React Router's own `flatRoutes() satisfies RouteConfig` template now gets file routes, and RSC route modules link to their `ServerComponent`.** An `app/routes.ts` written as `export default flatRoutes() satisfies RouteConfig;` (or `as RouteConfig`), the form React Router's templates use, was taken for custom configuration, so the app got no file routes at all. In React Router's RSC framework mode a route module exports `ServerComponent` instead of a default component; such a page now gets its route and links to that component, both for files under `app/routes/` and for modules listed in `app/routes.ts`. A module that exports both keeps its default component. - **An inherited method no longer links to a same-named class in another package.** When a call on a `Child` reached `m()` through `Child extends Base`, the lookup past the first parent matched any class called `Base` in the project, so with an unrelated `Base` in another package the call could land on that package's `Base.m()`, or skip a grandparent's `m()` for it. The lookup now follows the parent the declaration names, for Java, Kotlin, C#, Scala and Swift, where a Java or Kotlin receiver comes from a factory call, or a C#, Scala or Swift receiver is typed. In Scala, a same-named object or a package block in the same file is told apart too; in Swift the other `Base` is one declared in another file, since modules are not modeled. Dart, TypeScript, Python and C++ are unchanged: their wrong links did not reproduce, or Dart's member lookup matches parents by name elsewhere. - **Python calls on a local built through a module, or through one of its fields, now resolve.** `bp = pkg.Blueprint()`, `c.Blueprint()` and `core.Blueprint()` type the local like a class imported by name, and `app.config.from_mapping()` resolves on the class the field holds, as `self.config.from_mapping()` already did. On Flask and requests this adds 98 and 103 call edges (almost all from tests, none removed); a 30-edge sample was all correct. diff --git a/__tests__/kernel-point-lookup-boundary.test.ts b/__tests__/kernel-point-lookup-boundary.test.ts new file mode 100644 index 000000000..bba56bad3 --- /dev/null +++ b/__tests__/kernel-point-lookup-boundary.test.ts @@ -0,0 +1,55 @@ +/** + * The kernel finds the syntax node at a reference or declaration's start + * position. Where the previous token ends exactly there (`x=1;local function`, + * `instanceof Foo)$x->bar()`), the node at that position is the token that + * starts there, not the `;` or `)` before it. Finding the earlier token made a + * Lua `local` function read as global and hid a PHP `instanceof` guard. + * The spaced forms are the controls: they resolved the same way before. + */ +import { describe, it, expect, afterAll } from 'vitest'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { CodeGraph } from '../src'; + +const roots: string[] = []; +afterAll(() => { + for (const r of roots.splice(0)) fs.rmSync(r, { recursive: true, force: true }); +}); + +async function callTargets(files: Record, from: string): Promise { + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-point-lookup-')); + roots.push(root); + for (const [rel, content] of Object.entries(files)) fs.writeFileSync(path.join(root, rel), content); + const cg = await CodeGraph.init(root, { index: true }); + try { + return cg + .getOutgoingEdgesFrom(cg.getNodesInFile(from).map((n) => n.id), ['calls']) + .map((e) => cg.getNode(e.target)!.qualifiedName) + .sort(); + } finally { + cg.close(); + } +} + +describe('point lookup at a token boundary', () => { + it('reads a Lua local function written right after `;` as local', async () => { + const files = { + 'a.lua': 'x=1;local function helper() return 1 end\nlocal y = 2; local function spaced() return 2 end\nreturn x\n', + 'b.lua': 'local function main()\n helper()\n spaced()\nend\nreturn main\n', + }; + expect(await callTargets(files, 'b.lua')).toEqual([]); + }); + + it('applies a PHP instanceof guard to a call written right after `)`', async () => { + const files = { + 'a.php': `bar(); } +function spaced($x) { if ($x instanceof Foo) $x->bar(); } +`, + }; + expect(await callTargets(files, 'a.php')).toEqual(['Foo::bar', 'Foo::bar']); + }); +}); diff --git a/codegraph-kernel/src/resolve/call_shape.rs b/codegraph-kernel/src/resolve/call_shape.rs index aaa03dcb6..cbc7f2b61 100644 --- a/codegraph-kernel/src/resolve/call_shape.rs +++ b/codegraph-kernel/src/resolve/call_shape.rs @@ -208,7 +208,7 @@ impl KernelResolver { let lines = self.read_file(&r.file_path)?; if r.language=="rust" && r.reference_kind=="calls" { if let Some(tree)=self.parsed_tree(&lines,r) { - let mut node=super::iteration::descendant_for_position(tree.root_node(),lines.text(),((r.line-1).max(0) as usize,r.column.max(0) as usize+1)); + let mut node=super::iteration::descendant_for_position(tree.root_node(),lines.text(),((r.line-1).max(0) as usize,r.column.max(0) as usize)); loop { if node.kind()=="field_expression" { if let (Some(field),Some(value))=(node.child_by_field_name("field"),node.child_by_field_name("value")) { diff --git a/codegraph-kernel/src/resolve/cpp_aliases.rs b/codegraph-kernel/src/resolve/cpp_aliases.rs index 7046a0aa7..03bd9762e 100644 --- a/codegraph-kernel/src/resolve/cpp_aliases.rs +++ b/codegraph-kernel/src/resolve/cpp_aliases.rs @@ -152,7 +152,7 @@ impl KernelResolver { let Some(tree) = self.parsed_tree(&source, r) else { continue; }; for keyword in re!(r"\b(?:using|typedef)\b").find_iter(line) { let column = line[..keyword.start()].encode_utf16().count(); - let mut node = super::iteration::descendant_for_position(tree.root_node(), source.text(), (i, column + 1)); + let mut node = super::iteration::descendant_for_position(tree.root_node(), source.text(), (i, column)); let mut code = true; loop { if matches!(node.kind(), "comment" | "string_literal" | "raw_string_literal" | "char_literal") { code = false; break; } @@ -312,7 +312,7 @@ impl KernelResolver { let Some(source) = self.read_file(&owner.file_path) else { return Ok(false); }; let site = r.clone().at(owner); let Some(tree) = self.parsed_tree(&source, &site) else { return Ok(false); }; - let mut node = super::iteration::descendant_for_position(tree.root_node(), source.text(), ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize + 1)); + let mut node = super::iteration::descendant_for_position(tree.root_node(), source.text(), ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize)); while let Some(parent) = node.parent() { if parent.kind() == "template_declaration" { return Ok(true); } node = parent; diff --git a/codegraph-kernel/src/resolve/cpp_range_for.rs b/codegraph-kernel/src/resolve/cpp_range_for.rs index 1a7dc5767..8d19c5f3f 100644 --- a/codegraph-kernel/src/resolve/cpp_range_for.rs +++ b/codegraph-kernel/src/resolve/cpp_range_for.rs @@ -174,7 +174,7 @@ impl KernelResolver { if r.language != "cpp" { return Ok(None); } let Some(source) = self.read_file(&r.file_path) else { return Ok(None) }; let Some(tree) = self.parsed_tree(&source, r) else { return Ok(None) }; - let mut at = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut at = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); while let Some(parent) = at.parent() { // A nearer declaration of the name, `{ Gadget* w = g; w->Self(); }` in the body, hides the loop's. if cpp_binding_type(parent, at, receiver, &source).is_some() { return Ok(None); } @@ -270,7 +270,7 @@ impl KernelResolver { let Some(source) = self.read_file(&function.file_path) else { return Ok(None) }; let site = site_at(r, function); let Some(tree) = self.parsed_tree(&source, &site) else { return Ok(None) }; - let mut node = descendant_for_position(tree.root_node(), source.text(), ((function.start_line - 1).max(0) as usize, function.start_column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), source.text(), ((function.start_line - 1).max(0) as usize, function.start_column.max(0) as usize)); let declaration = loop { match node.kind() { "function_definition" | "field_declaration" | "declaration" => break node, diff --git a/codegraph-kernel/src/resolve/cpp_receivers.rs b/codegraph-kernel/src/resolve/cpp_receivers.rs index ced94f9b0..f19303dac 100644 --- a/codegraph-kernel/src/resolve/cpp_receivers.rs +++ b/codegraph-kernel/src/resolve/cpp_receivers.rs @@ -10,7 +10,7 @@ impl KernelResolver { if !re!(r"^[A-Za-z_]\w*$").is_match(method) { return Ok(None); } let Some(source) = self.read_file(&r.file_path) else { return Ok(None) }; let Some(tree) = self.parsed_tree(&source, r) else { return Ok(None) }; - let mut at = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut at = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); while at.kind() != "call_expression" { let Some(parent) = at.parent() else { return Ok(None) }; at = parent; } @@ -149,7 +149,7 @@ impl KernelResolver { if r.language != "cpp" || r.reference_kind != "calls" || !re!(r"^[A-Za-z_]\w*$").is_match(&r.reference_name) { return Ok(None); } let Some(source) = self.read_file(&r.file_path) else { return Ok(None) }; let Some(tree) = self.parsed_tree(&source, r) else { return Ok(None) }; - let mut node = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); loop { if node.kind() == "call_expression" { if let Some(function) = node.child_by_field_name("function").filter(|n| n.kind() == "field_expression") { @@ -240,7 +240,7 @@ impl KernelResolver { let Some(source) = self.read_file(&method.file_path) else { return Ok(None) }; let mut site = r.clone().at(method); site.from_node_id = method.id.clone(); site.column = method.start_column; let Some(tree) = self.parsed_tree(&source, &site) else { return Ok(None) }; - let mut node = descendant_for_position(tree.root_node(), source.text(), ((method.start_line - 1).max(0) as usize, method.start_column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), source.text(), ((method.start_line - 1).max(0) as usize, method.start_column.max(0) as usize)); loop { if matches!(node.kind(), "function_definition" | "field_declaration" | "declaration") { return Ok(node.child_by_field_name("type").map(|ty| source.text()[ty.start_byte()..ty.end_byte()].to_string())); @@ -279,7 +279,7 @@ impl KernelResolver { let Some(source) = self.read_file(&owner.file_path) else { return Ok(None) }; let mut site = r.clone().at(owner); site.from_node_id = owner.id.clone(); site.column = owner.start_column; let Some(tree) = self.cpp_field_tree(&source, &site) else { return Ok(None) }; - let mut node = descendant_for_position(tree.root_node(), source.text(), ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), source.text(), ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize)); while !matches!(node.kind(), "class_specifier" | "struct_specifier" | "union_specifier") { let Some(parent) = node.parent() else { break }; node = parent; } @@ -313,7 +313,7 @@ impl KernelResolver { fn cpp_container_element(&mut self, name: &str, r: &ResolveRefIn) -> Res>> { let Some(source) = self.read_file(&r.file_path) else { return Ok(None) }; if let Some(tree) = self.parsed_tree(&source, r) { - let mut at = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut at = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); while let Some(parent) = at.parent() { if let Some(raw) = cpp_binding_type(parent, at, name, &source) { let Some(element) = cpp_element_type(&raw) else { return Ok(None) }; diff --git a/codegraph-kernel/src/resolve/cpp_types.rs b/codegraph-kernel/src/resolve/cpp_types.rs index 04d53a849..4d7b89c42 100644 --- a/codegraph-kernel/src/resolve/cpp_types.rs +++ b/codegraph-kernel/src/resolve/cpp_types.rs @@ -54,7 +54,7 @@ impl KernelResolver { let mut directives = Vec::new(); if let Some(tree) = self.parsed_tree(&lines, r) { let mut site = super::iteration::descendant_for_position(tree.root_node(), lines.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); let before = site.start_byte(); loop { if matches!(site.kind(), "translation_unit" | "declaration_list" | "field_declaration_list" | "compound_statement") { @@ -174,7 +174,7 @@ impl KernelResolver { let Some(source) = self.read_file(&owner.file_path) else { return Ok(false) }; let mut site = r.clone().at(owner); site.from_node_id = owner.id.clone(); site.column = owner.start_column; let Some(tree) = self.parsed_tree(&source, &site) else { return Ok(false) }; - let mut node = super::iteration::descendant_for_position(tree.root_node(), source.text(), ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize + 1)); + let mut node = super::iteration::descendant_for_position(tree.root_node(), source.text(), ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize)); while let Some(parent) = node.parent() { if parent.kind() == "template_declaration" { if let Some(parameters) = parent.child_by_field_name("parameters") { diff --git a/codegraph-kernel/src/resolve/fields.rs b/codegraph-kernel/src/resolve/fields.rs index 6e9f3aa67..b04d26d82 100644 --- a/codegraph-kernel/src/resolve/fields.rs +++ b/codegraph-kernel/src/resolve/fields.rs @@ -178,7 +178,7 @@ impl KernelResolver { let Some(tree) = self.parsed_tree(&source, &site) else { return Ok(false); }; let mut declaration = super::iteration::descendant_for_position( tree.root_node(), source.text(), - ((target.start_line - 1).max(0) as usize, target.start_column.max(0) as usize + 1), + ((target.start_line - 1).max(0) as usize, target.start_column.max(0) as usize), ); while !matches!(declaration.kind(), "type_spec" | "type_alias") { let Some(parent) = declaration.parent() else { return Ok(false); }; @@ -231,7 +231,7 @@ impl KernelResolver { if let Some(tree) = self.parsed_tree(&lines, &site) { let mut declaration = super::iteration::descendant_for_position( tree.root_node(), lines.text(), - ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize + 1), + ((owner.start_line - 1).max(0) as usize, owner.start_column.max(0) as usize), ); while !matches!(declaration.kind(), "type_alias" | "type_spec") { let Some(parent) = declaration.parent() else { break; }; diff --git a/codegraph-kernel/src/resolve/go_asserted.rs b/codegraph-kernel/src/resolve/go_asserted.rs index fe681c04e..5bb1e01aa 100644 --- a/codegraph-kernel/src/resolve/go_asserted.rs +++ b/codegraph-kernel/src/resolve/go_asserted.rs @@ -151,7 +151,7 @@ impl KernelResolver { if !text.contains(".(") { return None; } let tree = self.parsed_tree(&file, r)?; let site = super::iteration::descendant_for_position(tree.root_node(), text, - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); let at = site.start_byte(); let mut scope = Some(site); while let Some(node) = scope { diff --git a/codegraph-kernel/src/resolve/iteration.rs b/codegraph-kernel/src/resolve/iteration.rs index 3e6336b04..c2ccd91b0 100644 --- a/codegraph-kernel/src/resolve/iteration.rs +++ b/codegraph-kernel/src/resolve/iteration.rs @@ -27,7 +27,10 @@ fn before(a: (usize, usize), b: (usize, usize)) -> bool { } /// descendantForPosition (tree.ts): descend into the first child, named or -/// not, whose span contains the point, until none does. +/// not, whose span contains the point, until none does. A child must end +/// after the point, so where one token ends and the next begins (`)` then +/// `Foo` in `if(ok)Foo f;`) the next one is found: pass a token's start to +/// find that token. pub(super) fn descendant_for_position<'t>(root: TsNode<'t>, text: &str, at: (usize, usize)) -> TsNode<'t> { let mut node = root; 'down: loop { @@ -35,7 +38,7 @@ pub(super) fn descendant_for_position<'t>(root: TsNode<'t>, text: &str, at: (usi for c in node.children(&mut cursor) { let start = point16(text, c.start_byte(), c.start_position()); let end = point16(text, c.end_byte(), c.end_position()); - if before(start, at) && before(at, end) { + if before(start, at) && !before(end, at) { node = c; continue 'down; } @@ -266,7 +269,7 @@ impl KernelResolver { pub(super) fn kotlin_chain_receiver_call(&mut self, r: &ResolveRefIn) -> Option { let file = self.read_file(&r.file_path)?; let tree = self.parsed_tree(&file, r)?; - let mut node = descendant_for_position(tree.root_node(), file.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), file.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); if node.kind() != "simple_identifier" { return None; } while let Some(parent) = node.parent() { if parent.kind() == "navigation_expression" { @@ -753,6 +756,27 @@ impl KernelResolver { mod tests { use super::kotlin_takes_trailing_lambda as trailing; + /// The node `descendant_for_position` finds at (0, `column`) of `code`. + fn token_at(code: &str, language: &str, column: usize) -> (String, String) { + let mut parser = tree_sitter::Parser::new(); + parser.set_language(&crate::langs::grammar_for(language).unwrap()).unwrap(); + let tree = parser.parse(code, None).unwrap(); + let node = super::descendant_for_position(tree.root_node(), code, (0, column)); + (node.kind().to_string(), code[node.start_byte()..node.end_byte()].to_string()) + } + + #[test] + fn a_point_where_one_token_ends_and_the_next_begins_finds_the_next() { + // `)` ends where the name starts; the name is the token at that point. + let code = "void g(){if(ok)Foo f;}"; + assert_eq!(token_at(code, "cpp", code.find("Foo").unwrap()).1, "Foo"); + let code = "void g(){if(ok)target();}"; + assert_eq!(token_at(code, "cpp", code.find("target").unwrap()), ("identifier".into(), "target".into())); + // A one-character name followed by `(`: its start finds the name. + let code = "void g(){f(x);}"; + assert_eq!(token_at(code, "cpp", code.find("f(").unwrap()), ("identifier".into(), "f".into())); + } + #[test] fn a_trailing_lambda_needs_a_function_typed_last_parameter() { for sig in [ diff --git a/codegraph-kernel/src/resolve/kotlin_receiver.rs b/codegraph-kernel/src/resolve/kotlin_receiver.rs index b7ee487b9..99596c525 100644 --- a/codegraph-kernel/src/resolve/kotlin_receiver.rs +++ b/codegraph-kernel/src/resolve/kotlin_receiver.rs @@ -23,7 +23,7 @@ impl KernelResolver { if r.language != "kotlin" || r.reference_kind != "calls" { return Ok(None); } let Some(file) = self.read_file(&r.file_path) else { return Ok(None) }; let Some(tree) = self.parsed_tree(&file, r) else { return Ok(None) }; - let mut node = descendant_for_position(tree.root_node(), file.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), file.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); if node.kind() != "simple_identifier" { return Ok(None); } while let Some(parent) = node.parent() { if parent.kind() == "navigation_expression" { @@ -99,7 +99,7 @@ impl KernelResolver { fn kotlin_property_chain_receiver(&mut self,r:&ResolveRefIn)->bool { let Some(file)=self.read_file(&r.file_path) else {return false}; let Some(tree)=self.parsed_tree(&file,r) else {return false}; - let mut node=descendant_for_position(tree.root_node(),file.text(),((r.line-1).max(0) as usize,r.column.max(0) as usize+1)); + let mut node=descendant_for_position(tree.root_node(),file.text(),((r.line-1).max(0) as usize,r.column.max(0) as usize)); while let Some(parent)=node.parent() { if parent.kind()=="navigation_expression" { let Some(receiver)=parent.named_child(0) else {return false}; @@ -144,7 +144,7 @@ impl KernelResolver { } fn kotlin_decl_tree_node<'t>(tree: &'t tree_sitter::Tree, source: &str, decl: &KNode, kind: &str) -> Option> { - let mut node=descendant_for_position(tree.root_node(),source,((decl.start_line-1).max(0) as usize,decl.start_column.max(0) as usize+1)); + let mut node=descendant_for_position(tree.root_node(),source,((decl.start_line-1).max(0) as usize,decl.start_column.max(0) as usize)); while node.kind()!=kind {node=node.parent()?;} Some(node) } @@ -468,7 +468,7 @@ impl KernelResolver { let Some(file) = self.read_file(&decl.file_path) else { return Ok(None) }; let site = r.clone().at(decl); let Some(tree) = self.parsed_tree(&file, &site) else { return Ok(None) }; - let mut node = descendant_for_position(tree.root_node(), file.text(), ((decl.start_line - 1).max(0) as usize, decl.start_column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), file.text(), ((decl.start_line - 1).max(0) as usize, decl.start_column.max(0) as usize)); while node.kind() != "property_declaration" { let Some(parent) = node.parent() else { return Ok(None) }; node = parent; } @@ -481,7 +481,7 @@ impl KernelResolver { let Some(file) = self.read_file(&decl.file_path) else { return Ok(false) }; let site = r.clone().at(decl); let Some(tree) = self.parsed_tree(&file, &site) else { return Ok(false) }; - let mut node = descendant_for_position(tree.root_node(), file.text(), ((decl.start_line - 1).max(0) as usize, decl.start_column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), file.text(), ((decl.start_line - 1).max(0) as usize, decl.start_column.max(0) as usize)); while node.kind() != "function_declaration" { let Some(parent) = node.parent() else { return Ok(false) }; node = parent; } diff --git a/codegraph-kernel/src/resolve/kotlin_type_scope.rs b/codegraph-kernel/src/resolve/kotlin_type_scope.rs index 16f857fa8..7e5e6ce8a 100644 --- a/codegraph-kernel/src/resolve/kotlin_type_scope.rs +++ b/codegraph-kernel/src/resolve/kotlin_type_scope.rs @@ -77,7 +77,7 @@ impl KernelResolver { source.text(), ( (declaration.start_line - 1).max(0) as usize, - declaration.start_column.max(0) as usize + 1, + declaration.start_column.max(0) as usize, ), ); while node.kind() != "function_declaration" { diff --git a/codegraph-kernel/src/resolve/language_type_scope.rs b/codegraph-kernel/src/resolve/language_type_scope.rs index f7d323295..004cc0ab6 100644 --- a/codegraph-kernel/src/resolve/language_type_scope.rs +++ b/codegraph-kernel/src/resolve/language_type_scope.rs @@ -272,7 +272,7 @@ impl KernelResolver { source.text(), ( (n.start_line - 1).max(0) as usize, - n.start_column.max(0) as usize + 1, + n.start_column.max(0) as usize, ), ); loop { @@ -306,7 +306,7 @@ impl KernelResolver { let mut node = super::iteration::descendant_for_position( tree.root_node(), source.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1), + ((r.line - 1).max(0) as usize, r.column.max(0) as usize), ); let mut scopes = Vec::new(); loop { @@ -399,7 +399,7 @@ impl KernelResolver { let mut node = super::iteration::descendant_for_position( tree.root_node(), source.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1), + ((r.line - 1).max(0) as usize, r.column.max(0) as usize), ); let mut names = Vec::new(); loop { @@ -726,7 +726,7 @@ impl KernelResolver { source.text(), ( (n.start_line - 1).max(0) as usize, - n.start_column.max(0) as usize + 1, + n.start_column.max(0) as usize, ), ); while let Some(parent) = node.parent() { diff --git a/codegraph-kernel/src/resolve/lua_alias.rs b/codegraph-kernel/src/resolve/lua_alias.rs index 758d90df0..fddf67729 100644 --- a/codegraph-kernel/src/resolve/lua_alias.rs +++ b/codegraph-kernel/src/resolve/lua_alias.rs @@ -24,7 +24,7 @@ impl KernelResolver { let decl = self.lua_local_decl(&r.reference_name, r)?; if let Some(source) = self.read_file(&r.file_path) { if let Some(tree) = self.parsed_tree(&source, r) { - let mut node = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + let mut node = descendant_for_position(tree.root_node(), source.text(), ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); while let Some(parent) = node.parent() { if parent.kind() == "for_statement" && node.kind() == "block" { let clause = named_children(parent).into_iter().find(|n| matches!(n.kind(), "for_generic_clause" | "for_numeric_clause")); diff --git a/codegraph-kernel/src/resolve/names.rs b/codegraph-kernel/src/resolve/names.rs index b0acf4faf..5342c123b 100644 --- a/codegraph-kernel/src/resolve/names.rs +++ b/codegraph-kernel/src/resolve/names.rs @@ -1109,7 +1109,7 @@ impl KernelResolver { let Some(file) = self.read_file(&r.file_path) else { return Ok(None); }; let Some(tree) = self.parsed_tree(&file, r) else { return Ok(None); }; let mut node = super::iteration::descendant_for_position(tree.root_node(), file.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); let mut call = None; loop { if node.kind() == "call_expression" { @@ -1170,7 +1170,7 @@ impl KernelResolver { let file = self.read_file(&r.file_path)?; let tree = self.parsed_tree(&file, r)?; let mut node = super::iteration::descendant_for_position(tree.root_node(), file.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1)); + ((r.line - 1).max(0) as usize, r.column.max(0) as usize)); loop { if node.kind() == "call_expression" { if let Some(function) = node.child_by_field_name("function") { diff --git a/codegraph-kernel/src/resolve/overloads_upstream.rs b/codegraph-kernel/src/resolve/overloads_upstream.rs index 1b91795f3..aa109ab55 100644 --- a/codegraph-kernel/src/resolve/overloads_upstream.rs +++ b/codegraph-kernel/src/resolve/overloads_upstream.rs @@ -390,7 +390,7 @@ impl KernelResolver { declaration_source.text(), ( (method.start_line - 1).max(0) as usize, - method.start_column.max(0) as usize + 1, + method.start_column.max(0) as usize, ), ); loop { @@ -611,7 +611,7 @@ impl KernelResolver { let mut call = super::iteration::descendant_for_position( tree.root_node(), source.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1), + ((r.line - 1).max(0) as usize, r.column.max(0) as usize), ); let callee_pattern = Self::cached_regex(&format!( r"(?:^|[.:>])\s*{}(?:\s*<.*>)?\s*$", diff --git a/codegraph-kernel/src/resolve/receivers.rs b/codegraph-kernel/src/resolve/receivers.rs index 9067883f6..60726cecf 100644 --- a/codegraph-kernel/src/resolve/receivers.rs +++ b/codegraph-kernel/src/resolve/receivers.rs @@ -267,7 +267,7 @@ impl KernelResolver { let text = file.text(); let row = (site.line - 1).max(0) as usize; let column = site.column.max(0) as usize; - let call = descendant_for_position(tree.root_node(), text, (row, column + 1)); + let call = descendant_for_position(tree.root_node(), text, (row, column)); let contains_receiver = |pattern: tree_sitter::Node<'_>| { let mut pending = vec![pattern]; while let Some(name) = pending.pop() { diff --git a/codegraph-kernel/src/resolve/scala_type_scope.rs b/codegraph-kernel/src/resolve/scala_type_scope.rs index b1ecf78ed..2d25f770c 100644 --- a/codegraph-kernel/src/resolve/scala_type_scope.rs +++ b/codegraph-kernel/src/resolve/scala_type_scope.rs @@ -158,7 +158,7 @@ impl KernelResolver { let mut at = super::iteration::descendant_for_position( tree.root_node(), source.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1), + ((r.line - 1).max(0) as usize, r.column.max(0) as usize), ); let mut scopes = Vec::new(); loop { @@ -200,7 +200,7 @@ impl KernelResolver { super::iteration::descendant_for_position( tree.root_node(), source.text(), - ((r.line - 1).max(0) as usize, r.column.max(0) as usize + 1), + ((r.line - 1).max(0) as usize, r.column.max(0) as usize), ) .end_byte(), );