Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

#### Symbols, tests and the viewer

- Kotlin functions and methods now carry their signature — `(params): ReturnType` — in `codegraph_explore`, `node` and the viewer, instead of no signature at all. Re-index Kotlin projects after upgrading. (#1495)
- `codegraph affected` now finds Go, Python and JVM test files that previously went unreported, while preserving custom `--filter` behavior (thanks @danusha2345; #1507, #1688).

- Calls inside declaration initializers in Kotlin, Java, TypeScript, JavaScript, Scala, Rust and Python now appear under the declaration that owns them, making callers and impact results more accurate after re-indexing with `codegraph index -f` (thanks @danusha2345; #1510, #1511).
Expand Down
37 changes: 35 additions & 2 deletions codegraph-kernel/src/kotlin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,39 @@ impl<'t> Walker<'t> {
/// extractKotlinReturnType — positional: the first user_type/nullable_type
/// AFTER function_value_parameters; function_body/type_constraints first →
/// None; Unit/Nothing → None; `: T` generic params leak (preserve).
/// `(params): ReturnType` — the positional read TreeSitterExtractor's
/// kotlin getSignature does (#1495): the `function_value_parameters` child,
/// then the type node that follows it before the body. Verbatim source text,
/// so it round-trips through parity byte-for-byte.
fn signature_of(&self, node: Node) -> Option<String> {
let mut params: Option<Node> = None;
let mut return_type: Option<Node> = None;
for i in 0..node.named_child_count() {
let Some(child) = node.named_child(i) else { continue };
if child.kind() == "function_value_parameters" {
params = Some(child);
continue;
}
if params.is_none() {
continue;
}
if matches!(child.kind(), "function_body" | "type_constraints") {
break;
}
if matches!(child.kind(), "user_type" | "nullable_type" | "function_type") {
return_type = Some(child);
break;
}
}
let params = params?;
let mut sig = self.text(params).to_string();
if let Some(rt) = return_type {
sig.push_str(": ");
sig.push_str(self.text(rt));
}
Some(sig)
}

fn return_type_of(&self, node: Node) -> Option<String> {
let mut seen_params = false;
for i in 0..node.named_child_count() {
Expand Down Expand Up @@ -918,7 +951,7 @@ impl<'t> Walker<'t> {
}
let extra = Extra {
docstring: preceding_docstring(node, self.src),
signature: None, // dead hook (zero fields)
signature: self.signature_of(node),
visibility: Some(self.visibility_of(node)),
is_async: Some(self.is_async(node)),
is_static: Some(false), // kotlin isStatic is always false
Expand All @@ -943,7 +976,7 @@ impl<'t> Walker<'t> {
let qualified_override = receiver.as_ref().map(|r| format!("{r}::{name}"));
let extra = Extra {
docstring: preceding_docstring(node, self.src),
signature: None,
signature: self.signature_of(node),
visibility: Some(self.visibility_of(node)),
is_async: Some(self.is_async(node)),
is_static: Some(false),
Expand Down
25 changes: 21 additions & 4 deletions src/extraction/languages/kotlin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Node as SyntaxNode } from 'web-tree-sitter';
import { getNodeText, getChildByField } from '../tree-sitter-helpers';
import { getNodeText } from '../tree-sitter-helpers';
import type { LanguageExtractor } from '../tree-sitter-types';

/** Kotlin return types that can't be a chained-call receiver (no class to chain on). */
Expand Down Expand Up @@ -390,9 +390,26 @@ export const kotlinExtractor: LanguageExtractor = {
return undefined;
},
getSignature: (node, source) => {
// Kotlin function signature: fun name(params): ReturnType
const params = getChildByField(node, 'function_value_parameters');
const returnType = getChildByField(node, 'type');
// Kotlin function signature: fun name(params): ReturnType. tree-sitter-kotlin
// exposes no field names, so both parts are found positionally, the way
// extractKotlinReturnType does (#1495): the `function_value_parameters`
// child, then the type node that follows it before the body.
let params: SyntaxNode | null = null;
let returnType: SyntaxNode | null = null;
for (let i = 0; i < node.namedChildCount; i++) {
const child = node.namedChild(i);
if (!child) continue;
if (child.type === 'function_value_parameters') {
params = child;
continue;
}
if (!params) continue;
if (child.type === 'function_body' || child.type === 'type_constraints') break;
if (child.type === 'user_type' || child.type === 'nullable_type' || child.type === 'function_type') {
returnType = child;
break;
}
}
if (!params) return undefined;
let sig = getNodeText(params, source);
if (returnType) {
Expand Down