@@ -261,12 +261,12 @@ class CodeDocQLExecutor(
261261 *
262262 * Supports wildcard: $.code.class("*") returns all classes (equivalent to $.code.classes[*])
263263 *
264- * Matching priority:
265- * 1. Exact match: class name exactly equals the query (e.g., "CodingAgent" matches "class CodingAgent")
266- * 2. Partial match: class name contains the query (e.g., "Agent" matches "CodingAgent", "CodingAgentContext")
264+ * Matching behavior:
265+ * - Returns ONLY exact class name matches (e.g., "CodingAgent" matches "class CodingAgent" only)
266+ * - Does NOT return partial matches (e.g., "CodingAgent" does NOT match "CodingAgentContext")
267+ * - This is semantically correct: $.code.class("X") means "find the class named X", not "find classes containing X"
267268 *
268- * When exact match is found, only exact matches are returned.
269- * This prevents returning unrelated classes like "CodingAgentContext" when searching for "CodingAgent".
269+ * For partial/fuzzy matching, use $.code.classes[?(@.name contains "keyword")] instead.
270270 */
271271 private suspend fun executeCodeClassQuery (className : String ): DocQLResult {
272272 if (documentFile == null ) {
@@ -298,24 +298,19 @@ class CodeDocQLExecutor(
298298 return DocQLResult .Empty
299299 }
300300
301- // Prioritize exact matches over partial matches
302- // Extract class name from title (e.g., "class CodingAgent" -> "CodingAgent", "class Foo<T>" -> "Foo")
301+ // ONLY return exact matches - this is the correct semantic for $.code.class("Name")
302+ // For partial matching, users should use $.code.classes[?(@.name contains "keyword")]
303303 val exactMatches = classChunks.filter { chunk ->
304304 val extractedName = extractClassNameFromTitle(chunk.chapterTitle ? : " " )
305305 extractedName.equals(className, ignoreCase = true )
306306 }
307307
308308 return if (exactMatches.isNotEmpty()) {
309- // Return only exact matches - this prevents returning CodingAgentContext when searching for CodingAgent
310309 DocQLResult .Chunks (mapOf (documentFile.path to exactMatches))
311310 } else {
312- // No exact match - return partial matches sorted by relevance
313- // Sort: shorter names (more specific) come first
314- val sortedChunks = classChunks.sortedBy { chunk ->
315- val extractedName = extractClassNameFromTitle(chunk.chapterTitle ? : " " )
316- extractedName.length
317- }
318- DocQLResult .Chunks (mapOf (documentFile.path to sortedChunks))
311+ // No exact match in this file - return Empty
312+ // This prevents returning CodingAgentContext when searching for CodingAgent
313+ DocQLResult .Empty
319314 }
320315 }
321316
@@ -355,6 +350,8 @@ class CodeDocQLExecutor(
355350 * Execute $.code.function("functionName") - find specific function/method
356351 *
357352 * Supports wildcard: $.code.function("*") returns all functions (equivalent to $.code.functions[*])
353+ *
354+ * Returns ONLY exact function name matches. For partial matching, use $.code.query("keyword").
358355 */
359356 private suspend fun executeCodeFunctionQuery (functionName : String ): DocQLResult {
360357 if (documentFile == null ) {
@@ -366,7 +363,40 @@ class CodeDocQLExecutor(
366363 return executeCodeFunctionsQuery(emptyList())
367364 }
368365
369- return executeCodeCustomQuery(functionName)
366+ if (parserService == null ) {
367+ return DocQLResult .Error (" No parser service available" )
368+ }
369+
370+ // Use heading query to find the function
371+ val chunks = parserService.queryHeading(functionName)
372+
373+ if (chunks.isEmpty()) {
374+ return DocQLResult .Empty
375+ }
376+
377+ // Filter to function-level chunks and require EXACT name match
378+ val exactMatches = chunks.filter { chunk ->
379+ val title = chunk.chapterTitle ? : " "
380+ // Must be a function (not a class)
381+ val isFunction = title.contains(" fun " ) ||
382+ (! title.startsWith(" class " ) &&
383+ ! title.startsWith(" interface " ) &&
384+ ! title.startsWith(" enum " ) &&
385+ ! title.startsWith(" object " ) &&
386+ title.contains(" (" ))
387+
388+ if (! isFunction) return @filter false
389+
390+ val funcName = extractFunctionNameFromTitle(title)
391+ funcName.equals(functionName, ignoreCase = true )
392+ }
393+
394+ return if (exactMatches.isNotEmpty()) {
395+ DocQLResult .Chunks (mapOf (documentFile.path to exactMatches))
396+ } else {
397+ // No exact match - return Empty (for partial match, use $.code.query())
398+ DocQLResult .Empty
399+ }
370400 }
371401
372402 /* *
@@ -381,7 +411,8 @@ class CodeDocQLExecutor(
381411 *
382412 * Supports wildcard: $.code.query("*") returns all code chunks
383413 *
384- * For function queries, prioritizes exact name matches over partial matches.
414+ * Unlike $.code.function("name") which requires exact match, $.code.query() is for flexible search
415+ * and returns all matching code elements (functions, classes, etc.) sorted by relevance.
385416 */
386417 private suspend fun executeCodeCustomQuery (keyword : String ): DocQLResult {
387418 if (parserService == null || documentFile == null ) {
@@ -419,12 +450,13 @@ class CodeDocQLExecutor(
419450 return DocQLResult .Empty
420451 }
421452
422- // Prioritize exact function name matches over partial matches
453+ // For $.code.query(), prioritize exact matches but also include partial matches
454+ // This is different from $.code.function("name") which is exact-match only
423455 val exactMatches = chunks.filter { chunk ->
424456 val title = chunk.chapterTitle ? : " "
425- // Extract function name from title (e.g., "fun execute()" -> "execute")
426457 val funcName = extractFunctionNameFromTitle(title)
427- funcName.equals(keyword, ignoreCase = true )
458+ val className = extractClassNameFromTitle(title)
459+ funcName.equals(keyword, ignoreCase = true ) || className.equals(keyword, ignoreCase = true )
428460 }
429461
430462 return if (exactMatches.isNotEmpty()) {
0 commit comments