Skip to content

Commit 17ab45f

Browse files
authored
Merge pull request #10 from gouthamgandhi/fix/c-codebase-leaf-node-detection
Fix: C codebase documentation generation finding 0 leaf nodes
2 parents 0a5fada + 4823675 commit 17ab45f

File tree

4 files changed

+54
-6
lines changed

4 files changed

+54
-6
lines changed

codewiki/src/be/dependency_analyzer/analyzers/c.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def _analyze(self):
6464
self._extract_relationships(root, top_level_nodes)
6565

6666
def _extract_nodes(self, node, top_level_nodes, lines):
67-
"""Recursively extract top-level nodes (functions and global variables)."""
67+
"""Recursively extract top-level nodes (functions, structs, and global variables)."""
6868
node_type = None
6969
node_name = None
7070

@@ -76,6 +76,24 @@ def _extract_nodes(self, node, top_level_nodes, lines):
7676
identifier = next((c for c in declarator.children if c.type == "identifier"), None)
7777
if identifier:
7878
node_name = identifier.text.decode()
79+
elif node.type == "struct_specifier":
80+
# Extract struct definitions: struct Name { ... }
81+
node_type = "struct"
82+
# Find type_identifier that represents the struct name
83+
for child in node.children:
84+
if child.type == "type_identifier":
85+
node_name = child.text.decode()
86+
break
87+
elif node.type == "type_definition":
88+
# Handle typedef struct definitions: typedef struct { ... } Name;
89+
# Check if this typedef contains a struct
90+
struct_spec = next((c for c in node.children if c.type == "struct_specifier"), None)
91+
if struct_spec:
92+
node_type = "struct"
93+
# The typedef name is the type_identifier at the end
94+
type_declarator = next((c for c in node.children if c.type == "type_identifier"), None)
95+
if type_declarator:
96+
node_name = type_declarator.text.decode()
7997
elif node.type == "declaration":
8098
if self._is_global_variable(node):
8199
node_type = "variable"
@@ -117,7 +135,7 @@ def _extract_nodes(self, node, top_level_nodes, lines):
117135
component_id=component_id
118136
)
119137

120-
if node_type == "function":
138+
if node_type in ["function", "struct"]:
121139
self.nodes.append(node_obj)
122140
top_level_nodes[node_name] = node_obj
123141

codewiki/src/be/dependency_analyzer/analyzers/python.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ast
22
import logging
3+
import warnings
34
from typing import List, Tuple, Optional
45
from pathlib import Path
56
import sys
@@ -227,7 +228,11 @@ def analyze(self):
227228
"""Analyze the Python file and extract functions and relationships."""
228229

229230
try:
230-
tree = ast.parse(self.content)
231+
# Suppress SyntaxWarnings about invalid escape sequences in source code
232+
# These warnings come from regex patterns like '\(' or '\.' in the analyzed files
233+
with warnings.catch_warnings():
234+
warnings.filterwarnings("ignore", category=SyntaxWarning)
235+
tree = ast.parse(self.content)
231236
self.visit(tree)
232237

233238
logger.debug(

codewiki/src/be/dependency_analyzer/dependency_graphs_builder.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,20 @@ def build_dependency_graph(self) -> tuple[Dict[str, Any], List[str]]:
6161
# Get leaf nodes
6262
leaf_nodes = get_leaf_nodes(graph, components)
6363

64-
# check if leaf_nodes are in components, only keep the ones that are in components and type is one of the following: class, interface, struct
64+
# check if leaf_nodes are in components, only keep the ones that are in components
65+
# and type is one of the following: class, interface, struct (or function for C-based projects)
66+
67+
# Determine if we should include functions based on available component types
68+
available_types = set()
69+
for comp in components.values():
70+
available_types.add(comp.component_type)
71+
72+
# Valid types for leaf nodes - include functions for C-based codebases
73+
valid_types = {"class", "interface", "struct"}
74+
# If no classes/interfaces/structs are found, include functions
75+
if not available_types.intersection(valid_types):
76+
valid_types.add("function")
77+
6578
keep_leaf_nodes = []
6679
for leaf_node in leaf_nodes:
6780
# Skip any leaf nodes that are clearly error strings or invalid identifiers
@@ -70,7 +83,7 @@ def build_dependency_graph(self) -> tuple[Dict[str, Any], List[str]]:
7083
continue
7184

7285
if leaf_node in components:
73-
if components[leaf_node].component_type in ["class", "interface", "struct"]:
86+
if components[leaf_node].component_type in valid_types:
7487
keep_leaf_nodes.append(leaf_node)
7588
else:
7689
# logger.debug(f"Leaf node {leaf_node} is a {components[leaf_node].component_type}, removing it")

codewiki/src/be/dependency_analyzer/topo_sort.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,18 @@ def concise_node(leaf_nodes: Set[str]) -> Set[str]:
302302
concise_leaf_nodes.add(node)
303303

304304
keep_leaf_nodes = []
305+
306+
# Determine if we should include functions based on available component types
307+
# For C-based projects, we need to include functions since they don't have classes
308+
available_types = set()
309+
for comp in components.values():
310+
available_types.add(comp.component_type)
311+
312+
# Valid types for leaf nodes - include functions for C-based codebases
313+
valid_types = {"class", "interface", "struct"}
314+
# If no classes/interfaces/structs are found, include functions
315+
if not available_types.intersection(valid_types):
316+
valid_types.add("function")
305317

306318
for leaf_node in leaf_nodes:
307319
# Skip any leaf nodes that are clearly error strings or invalid identifiers
@@ -310,7 +322,7 @@ def concise_node(leaf_nodes: Set[str]) -> Set[str]:
310322
continue
311323

312324
if leaf_node in components:
313-
if components[leaf_node].component_type in ["class", "interface", "struct"]:
325+
if components[leaf_node].component_type in valid_types:
314326
keep_leaf_nodes.append(leaf_node)
315327
else:
316328
# logger.debug(f"Leaf node {leaf_node} is a {components[leaf_node].component_type}, removing it")

0 commit comments

Comments
 (0)