Skip to content

Commit 1d86595

Browse files
ctothclaude
andcommitted
feat: add symbol-definitions search type to search_code_tool
- Add new search type "symbol-definitions" alongside existing "function-calls" - Support finding function, class, and variable definitions in Python/JS/TS - Include rich metadata with symbol_type classification - Enhance search_code_tool documentation with examples and use cases - Doubles search capability: find where symbols are DEFINED vs USED 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent af488c6 commit 1d86595

File tree

2 files changed

+161
-5
lines changed

2 files changed

+161
-5
lines changed

code_extractor/search_engine.py

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ def search_file(self, file_path: str, params: SearchParameters) -> List[SearchRe
4545
parser = get_parser(lang_name)
4646
tree = parser.parse(source_code.encode('utf-8'))
4747

48-
# For Phase 1, we'll hardcode the function-calls pattern
48+
# Route to appropriate search method
4949
if params.search_type == "function-calls":
5050
return self._search_function_calls(file_path, source_code, tree, params, lang_name)
51+
elif params.search_type == "symbol-definitions":
52+
return self._search_symbol_definitions(file_path, source_code, tree, params, lang_name)
5153

5254
return []
5355

@@ -189,6 +191,144 @@ def _search_function_calls(self, file_path: str, source_code: str, tree: Any,
189191

190192
return results
191193

194+
def _search_symbol_definitions(self, file_path: str, source_code: str, tree: Any,
195+
params: SearchParameters, lang_name: str) -> List[SearchResult]:
196+
"""Search for symbol definitions (classes, functions, variables) in the parsed tree."""
197+
results = []
198+
199+
# Define query patterns for different languages
200+
patterns = {
201+
'python': '''
202+
; Function definitions
203+
(function_definition
204+
name: (identifier) @function_name
205+
) @function_def
206+
207+
; Class definitions
208+
(class_definition
209+
name: (identifier) @class_name
210+
) @class_def
211+
212+
; Variable assignments
213+
(assignment
214+
left: (identifier) @variable_name
215+
) @variable_def
216+
''',
217+
'javascript': '''
218+
; Function declarations
219+
(function_declaration
220+
name: (identifier) @function_name
221+
) @function_def
222+
223+
; Class declarations
224+
(class_declaration
225+
name: (identifier) @class_name
226+
) @class_def
227+
228+
; Variable declarations
229+
(variable_declaration
230+
(variable_declarator
231+
name: (identifier) @variable_name
232+
)
233+
) @variable_def
234+
235+
; Const declarations
236+
(lexical_declaration
237+
(variable_declarator
238+
name: (identifier) @variable_name
239+
)
240+
) @const_def
241+
''',
242+
'typescript': '''
243+
; Function declarations
244+
(function_declaration
245+
name: (identifier) @function_name
246+
) @function_def
247+
248+
; Class declarations
249+
(class_declaration
250+
name: (identifier) @class_name
251+
) @class_def
252+
253+
; Interface declarations
254+
(interface_declaration
255+
name: (type_identifier) @interface_name
256+
) @interface_def
257+
258+
; Type alias declarations
259+
(type_alias_declaration
260+
name: (type_identifier) @type_name
261+
) @type_def
262+
263+
; Variable declarations
264+
(variable_declaration
265+
(variable_declarator
266+
name: (identifier) @variable_name
267+
)
268+
) @variable_def
269+
270+
; Const declarations
271+
(lexical_declaration
272+
(variable_declarator
273+
name: (identifier) @variable_name
274+
)
275+
) @const_def
276+
'''
277+
}
278+
279+
pattern = patterns.get(lang_name)
280+
if not pattern:
281+
return []
282+
283+
# Compile and execute query
284+
query = self._get_compiled_query(lang_name, pattern)
285+
captures = query.captures(tree.root_node)
286+
287+
source_lines = source_code.splitlines()
288+
289+
for node, capture_name in captures:
290+
if capture_name.endswith('_def'):
291+
# Check if this symbol name matches our target
292+
symbol_text = source_code[node.start_byte:node.end_byte]
293+
294+
# For symbol definitions, we want to check if the target appears in the symbol
295+
if params.target in symbol_text:
296+
start_line = node.start_point[0] + 1
297+
end_line = node.end_point[0] + 1
298+
299+
# Get context lines
300+
context_before = []
301+
context_after = []
302+
if params.include_context:
303+
start_ctx = max(0, start_line - 1 - params.context_lines)
304+
end_ctx = min(len(source_lines), end_line + params.context_lines)
305+
context_before = source_lines[start_ctx:start_line-1]
306+
context_after = source_lines[end_line:end_ctx]
307+
308+
# Determine symbol type from capture name
309+
symbol_type = capture_name.replace('_def', '').replace('_name', '')
310+
311+
result = SearchResult(
312+
file_path=file_path,
313+
start_line=start_line,
314+
end_line=end_line,
315+
match_text=symbol_text,
316+
context_before=context_before,
317+
context_after=context_after,
318+
metadata={
319+
"search_type": params.search_type,
320+
"target": params.target,
321+
"symbol_type": symbol_type
322+
},
323+
language=lang_name
324+
)
325+
results.append(result)
326+
327+
if len(results) >= params.max_results:
328+
break
329+
330+
return results
331+
192332
def _get_compiled_query(self, language: str, pattern: str) -> Query:
193333
"""Get or compile a tree-sitter query."""
194334
cache_key = f"{language}:{hash(pattern)}"

code_extractor/server.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -554,11 +554,23 @@ def search_code_tool(
554554
555555
Finds complex code patterns based on structure, not just text matching.
556556
Automatically detects whether scope is a file or directory and searches accordingly.
557-
Currently supports 'function-calls' search type.
557+
Supports 'function-calls' and 'symbol-definitions' search types.
558+
559+
Search Types:
560+
- "function-calls": Find where functions/methods are called or invoked
561+
- "symbol-definitions": Find where symbols (functions, classes, variables) are defined
562+
563+
Examples:
564+
- Find function calls: search_type="function-calls", target="requests.get"
565+
- Find function definitions: search_type="symbol-definitions", target="process_data"
566+
- Find class definitions: search_type="symbol-definitions", target="UserService"
567+
- Find variable definitions: search_type="symbol-definitions", target="API_KEY"
568+
569+
Supported Languages: Python, JavaScript, TypeScript (with fallback for others)
558570
559571
Args:
560-
search_type: Type of search ("function-calls")
561-
target: What to search for (e.g., "requests.get", "logger.error")
572+
search_type: Type of search ("function-calls", "symbol-definitions")
573+
target: What to search for (symbol name or call pattern)
562574
scope: File path, directory path, or URL to search in
563575
language: Programming language (auto-detected if not specified)
564576
git_revision: Optional git revision (commit, branch, tag) - not supported for URLs
@@ -568,10 +580,14 @@ def search_code_tool(
568580
exclude_patterns: File patterns to exclude (e.g., ["*.pyc", "node_modules/*"])
569581
max_files: Maximum number of files to search in directory mode
570582
follow_symlinks: Whether to follow symbolic links in directory search
583+
584+
Returns:
585+
List of search results with file paths, line numbers, matched text, context,
586+
and metadata including symbol_type for definitions.
571587
"""
572588
try:
573589
# Validate search type
574-
supported_types = ["function-calls"]
590+
supported_types = ["function-calls", "symbol-definitions"]
575591
if search_type not in supported_types:
576592
return [{"error": f"Unsupported search type '{search_type}'. Supported: {supported_types}"}]
577593

0 commit comments

Comments
 (0)