autosar-calltree 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -203,7 +203,10 @@ class CallTreeBuilder:
203
203
  # Build children nodes
204
204
  children = []
205
205
 
206
- for called_func_name in func_info.calls:
206
+ for func_call in func_info.calls:
207
+ called_func_name = func_call.name
208
+ is_conditional = func_call.is_conditional
209
+
207
210
  # Lookup called function
208
211
  called_funcs = self.function_db.lookup_function(
209
212
  called_func_name, context_file=str(func_info.file_path)
@@ -228,6 +231,11 @@ class CallTreeBuilder:
228
231
  verbose=verbose,
229
232
  )
230
233
 
234
+ # Mark as optional if it's conditional
235
+ if is_conditional:
236
+ child_node.is_optional = True
237
+ child_node.condition = func_call.condition
238
+
231
239
  children.append(child_node)
232
240
 
233
241
  # Remove from call stack
@@ -234,7 +234,9 @@ def cli(
234
234
 
235
235
  builder = CallTreeBuilder(db)
236
236
  result = builder.build_tree(
237
- start_function=start_function, max_depth=max_depth, verbose=verbose
237
+ start_function=start_function,
238
+ max_depth=max_depth,
239
+ verbose=verbose,
238
240
  )
239
241
 
240
242
  progress.update(task, completed=True)
@@ -22,6 +22,22 @@ class FunctionType(Enum):
22
22
  UNKNOWN = "unknown"
23
23
 
24
24
 
25
+ @dataclass
26
+ class FunctionCall:
27
+ """Represents a function call with its conditional status."""
28
+
29
+ name: str # Name of the called function
30
+ is_conditional: bool = False # True if called inside if/else block
31
+ condition: Optional[str] = None # The if/else condition (e.g., "update_mode == 0x05")
32
+
33
+ def __str__(self) -> str:
34
+ """String representation."""
35
+ if self.condition:
36
+ return f"{self.name} [{self.condition}]"
37
+ conditional_str = " [conditional]" if self.is_conditional else ""
38
+ return f"{self.name}{conditional_str}"
39
+
40
+
25
41
  @dataclass
26
42
  class Parameter:
27
43
  """Function parameter information."""
@@ -53,7 +69,7 @@ class FunctionInfo:
53
69
  function_type: FunctionType
54
70
  memory_class: Optional[str] = None # AUTOSAR memory class (RTE_CODE, etc.)
55
71
  parameters: List[Parameter] = field(default_factory=list)
56
- calls: List[str] = field(default_factory=list) # Functions called within
72
+ calls: List[FunctionCall] = field(default_factory=list) # Functions called within
57
73
  called_by: Set[str] = field(default_factory=set) # Functions that call this
58
74
 
59
75
  # AUTOSAR specific
@@ -102,6 +118,8 @@ class CallTreeNode:
102
118
  is_recursive: bool = False # True if function already in call stack
103
119
  is_truncated: bool = False # True if depth limit reached
104
120
  call_count: int = 1 # Number of times this function is called
121
+ is_optional: bool = False # True if this call is conditional (for opt blocks)
122
+ condition: Optional[str] = None # The if/else condition (e.g., "update_mode == 0x05")
105
123
 
106
124
  def add_child(self, child: "CallTreeNode") -> None:
107
125
  """Add a child node."""
@@ -231,8 +231,17 @@ class MermaidGenerator:
231
231
 
232
232
  # Generate calls to children
233
233
  for child in node.children:
234
+ # Start opt block for optional calls
235
+ if child.is_optional:
236
+ condition_text = child.condition if child.condition else "Optional call"
237
+ lines.append(f" opt {condition_text}")
238
+
234
239
  self._generate_sequence_calls(child, lines, current_participant)
235
240
 
241
+ # End opt block for optional calls
242
+ if child.is_optional:
243
+ lines.append(" end")
244
+
236
245
  # Generate return from current to caller (only if include_returns is True)
237
246
  if caller and not node.is_recursive and self.include_returns:
238
247
  lines.append(f" {current_participant}-->>{caller}: return")
@@ -8,6 +8,7 @@ into UML tools like Enterprise Architect, Visual Paradigm, etc.
8
8
  Requirements:
9
9
  - SWR_XMI_00001: XMI 2.5 Compliance
10
10
  - SWR_XMI_00002: Sequence Diagram Representation
11
+ - SWR_XMI_00003: Opt Block Support (Combined Fragments)
11
12
  """
12
13
 
13
14
  from pathlib import Path
@@ -111,7 +112,7 @@ class XmiGenerator:
111
112
  participants = self._collect_participants(call_tree)
112
113
  lifeline_elements = self._create_lifelines(interaction, participants)
113
114
 
114
- # Create messages (function calls)
115
+ # Create messages (function calls) with opt block support
115
116
  self._create_messages(call_tree, lifeline_elements, interaction)
116
117
 
117
118
  return root
@@ -218,7 +219,7 @@ class XmiGenerator:
218
219
  interaction: Element,
219
220
  ) -> None:
220
221
  """
221
- Create UML messages (function calls) between lifelines.
222
+ Create UML messages (function calls) between lifelines with opt block support.
222
223
 
223
224
  Args:
224
225
  root: Root node of call tree
@@ -275,9 +276,67 @@ class XmiGenerator:
275
276
  if node.is_recursive:
276
277
  message.set("messageSort", "reply")
277
278
 
278
- # Traverse children
279
+ # Traverse children with opt block support
279
280
  for child in node.children:
280
- traverse(child, current_participant)
281
+ if child.is_optional:
282
+ # Create UML combined fragment for opt block
283
+ combined_fragment = SubElement(interaction, f"{{{self.UML_NAMESPACE}}}fragment")
284
+ combined_fragment.set(f"{{{self.XMI_NAMESPACE}}}id", self._generate_id())
285
+ combined_fragment.set("name", "opt")
286
+ combined_fragment.set("visibility", "public")
287
+ combined_fragment.set("interactionOperator", "opt")
288
+
289
+ # Add interaction operand
290
+ operand = SubElement(combined_fragment, f"{{{self.UML_NAMESPACE}}}operand")
291
+ operand.set(f"{{{self.XMI_NAMESPACE}}}id", self._generate_id())
292
+ operand.set("name", child.condition or "condition")
293
+ operand.set("visibility", "public")
294
+
295
+ # Traverse children inside the opt block
296
+ def traverse_opt(opt_node: CallTreeNode, opt_parent: Optional[str] = None):
297
+ nonlocal message_counter
298
+
299
+ if self.use_module_names:
300
+ opt_participant = (
301
+ opt_node.function_info.sw_module
302
+ or Path(opt_node.function_info.file_path).stem
303
+ )
304
+ else:
305
+ opt_participant = opt_node.function_info.name
306
+
307
+ if opt_parent:
308
+ opt_message = SubElement(operand, f"{{{self.UML_NAMESPACE}}}message")
309
+ opt_message.set(f"{{{self.XMI_NAMESPACE}}}id", self._generate_id())
310
+ opt_message.set("name", opt_node.function_info.name)
311
+ opt_message.set("visibility", "public")
312
+ opt_message.set("messageSort", "synchCall")
313
+
314
+ opt_signature = self._format_message_signature(opt_node)
315
+ opt_message.set("signature", opt_signature)
316
+
317
+ opt_send_event = SubElement(opt_message, f"{{{self.UML_NAMESPACE}}}sendEvent")
318
+ opt_send_event.set(f"{{{self.XMI_NAMESPACE}}}id", self._generate_id())
319
+
320
+ opt_receive_event = SubElement(opt_message, f"{{{self.UML_NAMESPACE}}}receiveEvent")
321
+ opt_receive_event.set(f"{{{self.XMI_NAMESPACE}}}id", self._generate_id())
322
+
323
+ opt_message.set(
324
+ "sendEvent",
325
+ f"{{{self.XMI_NAMESPACE}}}{self.participant_map.get(opt_parent, '')}"
326
+ )
327
+ opt_message.set(
328
+ "receiveEvent",
329
+ f"{{{self.XMI_NAMESPACE}}}{self.participant_map.get(opt_participant, '')}"
330
+ )
331
+
332
+ message_counter += 1
333
+
334
+ for opt_child in opt_node.children:
335
+ traverse_opt(opt_child, opt_participant)
336
+
337
+ traverse_opt(child, current_participant)
338
+ else:
339
+ traverse(child, current_participant)
281
340
 
282
341
  # Start traversal from root's children
283
342
  for child in root.children:
@@ -9,7 +9,7 @@ import re
9
9
  from pathlib import Path
10
10
  from typing import List, Optional
11
11
 
12
- from ..database.models import FunctionInfo, FunctionType, Parameter
12
+ from ..database.models import FunctionCall, FunctionInfo, FunctionType, Parameter
13
13
 
14
14
 
15
15
  class CParser:
@@ -429,7 +429,7 @@ class CParser:
429
429
 
430
430
  return None
431
431
 
432
- def _extract_function_calls(self, function_body: str) -> List[str]:
432
+ def _extract_function_calls(self, function_body: str) -> List[FunctionCall]:
433
433
  """
434
434
  Extract function calls from a function body.
435
435
 
@@ -437,30 +437,117 @@ class CParser:
437
437
  function_body: Function body text
438
438
 
439
439
  Returns:
440
- List of called function names
440
+ List of FunctionCall objects with conditional status and condition text
441
441
  """
442
- called_functions = set()
443
-
444
- # Find all potential function calls
445
- for match in self.function_call_pattern.finditer(function_body):
446
- function_name = match.group(1)
447
-
448
- # Skip C keywords
449
- if function_name in self.C_KEYWORDS:
450
- continue
451
-
452
- # Skip AUTOSAR types (might be casts)
453
- if function_name in self.AUTOSAR_TYPES:
454
- continue
442
+ called_functions: List[FunctionCall] = []
443
+
444
+ # Analyze function body to track if/else context
445
+ # We'll parse line by line to detect if/else blocks
446
+ lines = function_body.split("\n")
447
+ in_if_block = False
448
+ in_else_block = False
449
+ current_condition = None
450
+ brace_depth = 0
451
+
452
+ for line in lines:
453
+ stripped = line.strip()
454
+
455
+ # Track if/else block entry and extract condition
456
+ if stripped.startswith("if ") or stripped.startswith("if("):
457
+ in_if_block = True
458
+ # Extract condition from if statement
459
+ # Handle both "if (condition)" and "if(condition)" formats
460
+ if_match = re.match(r'if\s*\(\s*(.+?)\s*\)', stripped)
461
+ if if_match:
462
+ current_condition = if_match.group(1).strip()
463
+ else:
464
+ # Fallback: try to extract everything between "if" and the first '{'
465
+ if_start = stripped.find("if")
466
+ brace_pos = stripped.find("{")
467
+ if brace_pos != -1:
468
+ condition_part = stripped[if_start+2:brace_pos].strip()
469
+ # Remove leading/trailing parentheses
470
+ condition_part = condition_part.lstrip("(").rstrip(")").strip()
471
+ current_condition = condition_part
472
+ else:
473
+ current_condition = "condition"
474
+ elif stripped.startswith("else if") or stripped.startswith("else if("):
475
+ in_if_block = True
476
+ # Extract condition from else if statement
477
+ elif_match = re.match(r'else\s+if\s*\(\s*(.+?)\s*\)', stripped)
478
+ if elif_match:
479
+ current_condition = f"else if {elif_match.group(1).strip()}"
480
+ else:
481
+ current_condition = "else if condition"
482
+ elif stripped.startswith("else") and not stripped.startswith("else if"):
483
+ in_else_block = True
484
+ current_condition = "else"
485
+
486
+ # Track brace depth for nested blocks
487
+ brace_depth += stripped.count("{")
488
+ brace_depth -= stripped.count("}")
489
+
490
+ # Find function calls in this line
491
+ for match in self.function_call_pattern.finditer(line):
492
+ function_name = match.group(1)
493
+
494
+ # Skip C keywords
495
+ if function_name in self.C_KEYWORDS:
496
+ continue
497
+
498
+ # Skip AUTOSAR types (might be casts)
499
+ if function_name in self.AUTOSAR_TYPES:
500
+ continue
501
+
502
+ # Check if this call is inside an if/else block
503
+ is_conditional = (in_if_block or in_else_block) and brace_depth > 0
504
+
505
+ # Add to called functions if not already present
506
+ existing = next((fc for fc in called_functions if fc.name == function_name), None)
507
+ if existing:
508
+ # Update conditional status if this occurrence is conditional
509
+ if is_conditional:
510
+ existing.is_conditional = True
511
+ if current_condition and not existing.condition:
512
+ existing.condition = current_condition
513
+ else:
514
+ called_functions.append(
515
+ FunctionCall(
516
+ name=function_name,
517
+ is_conditional=is_conditional,
518
+ condition=current_condition if is_conditional else None
519
+ )
520
+ )
455
521
 
456
- called_functions.add(function_name)
522
+ # Also extract RTE calls explicitly
523
+ for match in self.rte_call_pattern.finditer(line):
524
+ rte_function = match.group(0).rstrip("(").strip()
525
+
526
+ is_conditional = (in_if_block or in_else_block) and brace_depth > 0
527
+
528
+ existing = next((fc for fc in called_functions if fc.name == rte_function), None)
529
+ if existing:
530
+ if is_conditional:
531
+ existing.is_conditional = True
532
+ if current_condition and not existing.condition:
533
+ existing.condition = current_condition
534
+ else:
535
+ called_functions.append(
536
+ FunctionCall(
537
+ name=rte_function,
538
+ is_conditional=is_conditional,
539
+ condition=current_condition if is_conditional else None
540
+ )
541
+ )
457
542
 
458
- # Also extract RTE calls explicitly
459
- for match in self.rte_call_pattern.finditer(function_body):
460
- rte_function = match.group(0).rstrip("(").strip()
461
- called_functions.add(rte_function)
543
+ # Exit if/else block when we close the brace
544
+ if brace_depth == 0:
545
+ in_if_block = False
546
+ in_else_block = False
547
+ current_condition = None
462
548
 
463
- return sorted(list(called_functions))
549
+ # Sort by name for consistent output
550
+ return sorted(called_functions, key=lambda fc: fc.name)
464
551
 
465
552
  def parse_function_declaration(self, declaration: str) -> Optional[FunctionInfo]:
466
553
  """
@@ -1,5 +1,5 @@
1
1
  """Version information for autosar-calltree package."""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.5.0"
4
4
  __author__ = "melodypapa"
5
5
  __email__ = "melodypapa@outlook.com"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autosar-calltree
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: A Python tool to analyze C/AUTOSAR codebases and generate function call trees with Mermaid and XMI output
5
5
  Author-email: melodypapa <melodypapa@outlook.com>
6
6
  Maintainer-email: melodypapa <melodypapa@outlook.com>
@@ -58,17 +58,181 @@ A powerful Python package to analyze C/AUTOSAR codebases and generate function c
58
58
  - 🔍 **Static Analysis**: Analyzes C source code without compilation
59
59
  - 📊 **Multiple Output Formats**:
60
60
  - Mermaid sequence diagrams (Markdown)
61
- - XMI/UML 2.5 (importable to Enterprise Architect, MagicDraw, etc.) - *planned*
61
+ - XMI/UML 2.5 (importable to Enterprise Architect, Visual Paradigm, etc.)
62
62
  - JSON (for custom processing) - *planned*
63
63
  - 🏗️ **SW Module Support**: Map C files to SW modules via YAML configuration for architecture-level diagrams
64
64
  - 📈 **Module-Aware Diagrams**: Generate diagrams with SW module names as participants
65
65
  - 🎯 **Parameter Display**: Function parameters shown in sequence diagram calls for better visibility
66
+ - 🔄 **Automatic Conditional Detection**: Automatically detects `if`/`else` statements and generates `opt` blocks with actual conditions (Mermaid and XMI)
66
67
  - 🚀 **Performance**: Intelligent caching for fast repeated analysis with file-by-file progress reporting
67
68
  - 🎯 **Depth Control**: Configurable call tree depth
68
69
  - 🔄 **Circular Dependency Detection**: Identifies recursive calls and cycles
69
70
  - 📊 **Statistics**: Detailed analysis statistics including module distribution
70
71
  - 📝 **Clean Diagrams**: Return statements omitted by default for cleaner sequence diagrams (configurable)
71
72
 
73
+ ## What's New
74
+
75
+ ### Version 0.5.0 (2026-02-04)
76
+
77
+ **🎉 Major Feature: Automatic Conditional Call Detection with Opt/Alt/Else Blocks**
78
+
79
+ This release adds intelligent parsing of conditional function calls, automatically detecting `if`/`else` blocks in your C code and representing them as `opt`/`alt`/`else` blocks in both Mermaid and XMI output formats.
80
+
81
+ **Mermaid Example**:
82
+
83
+ **Source Code**:
84
+ ```c
85
+ FUNC(void, RTE_CODE) Demo_Update(VAR(uint32, AUTOMATIC) update_mode)
86
+ {
87
+ SW_UpdateState(update_mode);
88
+
89
+ if (update_mode == 0x05) {
90
+ COM_SendLINMessage(0x456, (uint8*)0x20003000);
91
+ }
92
+ }
93
+ ```
94
+
95
+ **Generated Mermaid Diagram**:
96
+ ```mermaid
97
+ sequenceDiagram
98
+ participant Demo_Update
99
+ participant COM_SendLINMessage
100
+ participant SW_UpdateState
101
+
102
+ Demo_Update->>SW_UpdateState: call(new_state)
103
+ opt update_mode == 0x05
104
+ Demo_Update->>COM_SendLINMessage: call(msg_id, data)
105
+ end
106
+ ```
107
+
108
+ **XMI Example**:
109
+ ```xml
110
+ <uml:fragment name="opt" interactionOperator="opt">
111
+ <uml:operand name="update_mode == 0x05">
112
+ <uml:message name="COM_SendLINMessage" signature="COM_SendLINMessage(msg_id, data)">
113
+ <!-- message events -->
114
+ </uml:message>
115
+ </uml:operand>
116
+ </uml:fragment>
117
+ ```
118
+
119
+ **Benefits**:
120
+ - ✅ No manual configuration required - automatic detection
121
+ - ✅ Shows actual condition text for better understanding
122
+ - ✅ Supports nested conditionals
123
+ - ✅ Handles `if`, `else if`, and `else` statements
124
+ - ✅ Works with both Mermaid and XMI output formats
125
+ - ✅ XMI uses UML combined fragments (standard UML 2.5 representation)
126
+
127
+ **Technical Changes**:
128
+ - `FunctionCall` model extended with `is_conditional` and `condition` fields
129
+ - `CallTreeNode` extended with `is_optional` and `condition` fields
130
+ - `CParser` enhanced with line-by-line conditional context tracking
131
+ - `MermaidGenerator` supports `opt`, `alt`, and `else` blocks
132
+ - `XMIGenerator` supports UML combined fragments
133
+ - 298 tests passing with 89% code coverage
134
+
135
+ ## Changelog
136
+
137
+ ### [0.5.0] - 2026-02-04
138
+
139
+ #### Added
140
+ - **Conditional function call tracking**: Automatic detection of `if`/`else` blocks with condition text extraction
141
+ - **Mermaid opt/alt/else blocks**: Generate `opt`, `alt`, and `else` blocks for conditional calls
142
+ - **XMI combined fragments**: UML 2.5 compliant `opt`/`alt`/`else` fragment generation
143
+ - **FunctionCall model**: Extended with `is_conditional` and `condition` fields
144
+ - **CallTreeNode model**: Extended with `is_optional` and `condition` fields
145
+ - **CParser enhancements**: Line-by-line parsing to track conditional context
146
+ - Requirements documentation for conditional call tracking (SWR_MODEL_00026-00028)
147
+
148
+ #### Fixed
149
+ - Linting errors (flake8 W292, W391) for proper file endings
150
+ - Type annotations in `c_parser.py:442` for mypy compliance
151
+
152
+ #### Technical
153
+ - 298 tests passing, 89% code coverage
154
+ - All CI quality checks passing (ruff, isort, flake8, mypy)
155
+ - Python 3.8-3.12 test matrix
156
+
157
+ ---
158
+
159
+ ### [0.4.0] - 2026-02-03
160
+
161
+ #### Added
162
+ - **XMI/UML 2.5 output format**: Complete XMI generation with UML 2.5 compliance
163
+ - **XMIGenerator**: New generator class for XMI document creation
164
+ - **CLI `--format xmi` option**: Support for XMI output format
165
+ - **CLI `--format both` option**: Generate both Mermaid and XMI simultaneously
166
+ - **XMI requirements documentation**: `docs/requirements/requirements_xmi.md`
167
+ - **UML combined fragments**: Support for `opt`, `alt`, `else` interactions
168
+ - **XMI demo output**: `demo/demo_main.xmi` example file
169
+
170
+ #### Technical
171
+ - XMI documents importable into Enterprise Architect, Visual Paradigm, MagicDraw
172
+ - Proper XML namespaces and structure (UML 2.5, XMI 2.5)
173
+ - Message events with sendEvent and receiveEvent elements
174
+
175
+ ---
176
+
177
+ ### [0.3.3] - 2026-02-02
178
+
179
+ #### Fixed
180
+ - **AUTOSAR macro false positives**: Performance degradation caused by incorrect macro matching
181
+ - Parser optimization to reduce false positive detections
182
+ - Improved AUTOSAR pattern matching accuracy
183
+
184
+ ---
185
+
186
+ ### [0.3.2] - 2026-02-01
187
+
188
+ #### Added
189
+ - **File size display**: Show file sizes during processing in verbose mode
190
+ - Enhanced progress reporting with line counts and file sizes
191
+ - Improved user feedback for large file processing
192
+
193
+ ---
194
+
195
+ ### [0.3.1] - 2026-01-31
196
+
197
+ #### Added
198
+ - **Verbose file progress**: File-by-file progress display during database building
199
+ - **Line count reporting**: Show number of lines processed per file
200
+ - **Enhanced cache loading**: File-by-file progress when loading from cache
201
+ - **C parser line-by-line tests**: Comprehensive testing for line-by-line processing
202
+
203
+ #### Fixed
204
+ - Import sorting to pass isort checks
205
+ - Minor documentation updates
206
+
207
+ ---
208
+
209
+ ### [0.3.0] - 2026-01-30
210
+
211
+ #### Added
212
+ - **SW Module Configuration System**: YAML-based file-to-module mapping
213
+ - **Module-aware diagrams**: Generate diagrams with SW module names as participants
214
+ - **Comprehensive test suite**: 298 tests across all modules (89% coverage)
215
+ - **Requirements traceability**: Complete traceability matrix between requirements and tests
216
+ - **Integration tests**: End-to-end CLI testing
217
+ - **PyPI publishing workflow**: Automated PyPI releases with OIDC trusted publishing
218
+ - **ModuleConfig class**: Load, validate, and perform module lookups
219
+ - **Module assignment**: Functions tagged with SW module information
220
+ - **FunctionDatabase integration**: Module assignments preserved in cache
221
+ - **CLI `--use-module-names` option**: Enable module-level diagrams
222
+ - **CLI `--module-config` option**: Specify module mapping YAML file
223
+
224
+ #### Technical
225
+ - Glob pattern support for file mappings (e.g., `hw_*.c`)
226
+ - Default module fallback for unmapped files
227
+ - Module lookup caching for performance
228
+ - Cache preserves module assignments across runs
229
+
230
+ ---
231
+
232
+ ### Earlier Versions
233
+
234
+ **0.2.x** - Initial development releases with basic AUTOSAR parsing and Mermaid output
235
+
72
236
  ## Installation
73
237
 
74
238
  ```bash
@@ -97,6 +261,9 @@ calltree --start-function Demo_Init --source-dir demo --module-config demo/modul
97
261
  # Specify depth and output
98
262
  calltree --start-function Demo_Init --max-depth 2 -o output.md
99
263
 
264
+ # Generate XMI format (with opt block support)
265
+ calltree --start-function Demo_MainFunction --source-dir demo --format xmi --output demo/demo.xmi
266
+
100
267
  # Verbose mode with detailed statistics and cache progress
101
268
  calltree --start-function Demo_Init --verbose
102
269
  ```
@@ -158,7 +325,7 @@ Options:
158
325
 
159
326
  ## Output Examples
160
327
 
161
- ### Mermaid Sequence Diagram
328
+ ### Mermaid Sequence Diagram with Opt Blocks
162
329
 
163
330
  ```mermaid
164
331
  sequenceDiagram
@@ -168,31 +335,55 @@ sequenceDiagram
168
335
  participant SoftwareModule
169
336
 
170
337
  DemoModule->>CommunicationModule: COM_InitCommunication(baud_rate, buffer_size)
171
- CommunicationModule->>CommunicationModule: COM_InitCAN
172
- CommunicationModule->>CommunicationModule: COM_InitEthernet
173
- CommunicationModule->>CommunicationModule: COM_InitLIN
174
- DemoModule->>DemoModule: Demo_InitVariables(config_mode)
175
- DemoModule->>HardwareModule: HW_InitHardware(clock_freq, gpio_mask)
176
- HardwareModule->>HardwareModule: HW_InitADC
177
- HardwareModule->>HardwareModule: HW_InitClock
178
- HardwareModule->>HardwareModule: HW_InitGPIO
179
- HardwareModule->>HardwareModule: HW_InitPWM
180
- DemoModule->>SoftwareModule: SW_InitSoftware(state, config)
181
- SoftwareModule->>SoftwareModule: SW_InitConfig
182
- SoftwareModule->>SoftwareModule: SW_InitState
338
+ opt mode > 0x00
339
+ DemoModule->>DemoModule: Demo_Update(mode)
340
+ opt mode == 0x05
341
+ DemoModule->>CommunicationModule: COM_SendLINMessage(msg_id, data)
342
+ end
343
+ DemoModule->>SoftwareModule: SW_UpdateState(new_state)
344
+ end
345
+ DemoModule->>HardwareModule: HW_ReadSensor(sensor_id)
346
+ DemoModule->>SoftwareModule: SW_ProcessData(data, length)
183
347
  ```
184
348
 
185
349
  **Key Features**:
186
- - Participants appear in the order they are first encountered in the call tree
187
- - Function parameters are displayed in the call arrows (e.g., `COM_InitCommunication(baud_rate, buffer_size)`)
350
+ - Conditional calls are automatically wrapped in `opt` blocks
351
+ - Shows actual condition text from source code (e.g., `mode > 0x00`, `mode == 0x05`)
352
+ - Supports nested conditionals
353
+ - Participants appear in the order they are first encountered
354
+ - Function parameters are displayed in the call arrows
188
355
  - Return statements are omitted by default for cleaner visualization
189
356
  - Module names are used as participants when `--use-module-names` is enabled
190
357
 
358
+ ### XMI Output with Opt Blocks
359
+
360
+ The XMI output also supports opt blocks using UML combined fragments:
361
+
362
+ ```xml
363
+ <uml:fragment name="opt" interactionOperator="opt">
364
+ <uml:operand name="update_mode == 0x05">
365
+ <uml:message name="COM_SendLINMessage"
366
+ signature="COM_SendLINMessage(msg_id, data)"
367
+ messageSort="synchCall">
368
+ <uml:sendEvent xmi:id="calltree_22"/>
369
+ <uml:receiveEvent xmi:id="calltree_23"/>
370
+ </uml:message>
371
+ </uml:operand>
372
+ </uml:fragment>
373
+ ```
374
+
375
+ **XMI Features**:
376
+ - UML 2.5 compliant XMI documents
377
+ - Combined fragments with `opt` interaction operator
378
+ - Operand elements display the condition text
379
+ - Can be imported into UML tools like Enterprise Architect, Visual Paradigm, MagicDraw
380
+ - Proper XML structure with correct namespaces
381
+
191
382
  ### Generated Markdown Structure
192
383
 
193
384
  The tool generates comprehensive Markdown files with:
194
385
  - Metadata header (timestamp, settings, statistics)
195
- - Mermaid sequence diagram with function parameters
386
+ - Mermaid sequence diagram with function parameters and opt blocks
196
387
  - Function details table with parameter information
197
388
  - Text-based call tree
198
389
  - Circular dependency warnings
@@ -261,6 +452,7 @@ calltree --start-function Demo_Init --module-config demo/module_mapping.yaml --u
261
452
  This generates diagrams with:
262
453
  - **Participants**: SW module names (HardwareModule, SoftwareModule, etc.) in the order they are first encountered
263
454
  - **Arrows**: Function names with parameters being called between modules
455
+ - **Opt Blocks**: Conditional calls wrapped with actual condition text
264
456
  - **Function Table**: Includes module column showing each function's SW module
265
457
  - **Clean Visualization**: Return statements omitted by default
266
458
 
@@ -284,7 +476,7 @@ autosar-calltree/
284
476
  │ ├── parsers/ # Code parsers (AUTOSAR, C)
285
477
  │ ├── analyzers/ # Analysis logic (call tree, dependencies)
286
478
  │ ├── database/ # Data models and caching
287
- │ ├── generators/ # Output generators (Mermaid)
479
+ │ ├── generators/ # Output generators (Mermaid, XMI)
288
480
  │ └── utils/ # Utilities (empty, for future use)
289
481
  ├── test_demo/ # Demo AUTOSAR C files for testing
290
482
  │ ├── demo.c
@@ -302,7 +494,7 @@ autosar-calltree/
302
494
 
303
495
  ### Running Tests
304
496
 
305
- The project has **comprehensive test coverage** with 278 tests across all modules:
497
+ The project has **comprehensive test coverage** with 298 tests across all modules:
306
498
 
307
499
  ```bash
308
500
  # Run all tests
@@ -336,20 +528,20 @@ pytest --cov=autosar_calltree --cov-report=html --cov-report=term --omit=tests/
336
528
 
337
529
  ### Test Coverage
338
530
 
339
- The project maintains **94% code coverage** across all modules:
531
+ The project maintains **89% code coverage** across all modules:
340
532
 
341
533
  | Module | Coverage | Tests |
342
534
  |--------|----------|-------|
343
- | Models | 100% | 25 |
535
+ | Models | 97% | 28 |
344
536
  | AUTOSAR Parser | 97% | 15 |
345
537
  | C Parser | 86% | 18 |
346
- | Database | 80% | 20 |
347
- | Analyzers | 94% | 20 |
538
+ | Database | 83% | 20 |
539
+ | Analyzers | 95% | 20 |
348
540
  | Config | 97% | 25 |
349
- | Generators | 96% | 31 |
350
- | CLI (Integration) | ~90% | 14 |
351
- | End-to-End | ~90% | 110 |
352
- | **Total** | **94%** | **278** |
541
+ | Generators | 89% | 45 |
542
+ | CLI (Integration) | 90% | 14 |
543
+ | End-to-End | ~90% | 120 |
544
+ | **Total** | **89%** | **298** |
353
545
 
354
546
  ### Code Quality
355
547
 
@@ -469,7 +661,8 @@ MIT License - see [LICENSE](LICENSE) file for details.
469
661
  - [ ] Multi-threading for large codebases
470
662
  - [ ] Function complexity metrics
471
663
  - [ ] Dead code detection
472
- - [ ] XMI/UML 2.5 output format
664
+ - [x] XMI/UML 2.5 output format with opt block support
665
+ - [x] Automatic conditional call detection with opt blocks
473
666
 
474
667
  ## Support
475
668
 
@@ -1,23 +1,23 @@
1
1
  autosar_calltree/__init__.py,sha256=WiP2aFfs0H3ze4X8tQg6ZiStdzgrp6uC8DPRUyGm_zg,660
2
- autosar_calltree/version.py,sha256=Nt6KvWNqsurDjWOhy4Xi-L1EtfOXOROb5rxxO8OE_bA,142
2
+ autosar_calltree/version.py,sha256=I6XTh66u90ab-PtD14KrayLlWv4ynW2h4Wmjq52IaW4,142
3
3
  autosar_calltree/analyzers/__init__.py,sha256=qUvB7CAa5xNcUYkhD7Rha-9quPG8yQJqg-GikHD41U0,119
4
- autosar_calltree/analyzers/call_tree_builder.py,sha256=tSsIj_BHzT4XQ-XsXXfyU-KyGK61p6O7nLBx1AiwxCA,11627
4
+ autosar_calltree/analyzers/call_tree_builder.py,sha256=hBiu6zM7agwLrAt7pWljYzW_Aur2zKuvJ_4cZrZlf50,11909
5
5
  autosar_calltree/cli/__init__.py,sha256=qwsSUuDyV6i1PYS7Mf6JBkBJKtcldxiIh5S0wOucWVY,76
6
- autosar_calltree/cli/main.py,sha256=f9awQW_1dKIc1IjhOp5_yx7f2CzRybNFKQt2tILwj1c,12676
6
+ autosar_calltree/cli/main.py,sha256=-E0JdU1NrHVrESDXA1L2lb_rNsaE9_WdXXSr8Kf3F04,12709
7
7
  autosar_calltree/config/__init__.py,sha256=mSrB2uvrax_MTgGynfPObXYUh6eCe5BZD21_cebfMQM,258
8
8
  autosar_calltree/config/module_config.py,sha256=--ptsY6drvVKn_HD5_JDEpCv9D1xI8kiJXi8bwrSFBI,6329
9
9
  autosar_calltree/database/__init__.py,sha256=qg0IfUGgkecJQXqe9lPrU0Xbu-hBZa8NOe8E8UZqC_s,405
10
10
  autosar_calltree/database/function_database.py,sha256=PJghwv2Duxx7vSIvApyVwg4N_bCTfnk85mtA89BpIuA,17561
11
- autosar_calltree/database/models.py,sha256=xo85zao2LDHJMR6FeMVxopPyXxEv7jQUzeh4fzHwNKo,6265
11
+ autosar_calltree/database/models.py,sha256=6f__e-oL14rrZyd1aDuPtzFnSZwzvZOxkUVvknJHwHw,7025
12
12
  autosar_calltree/generators/__init__.py,sha256=5gl3dF3imJIsvfmdg0bkZdnQ9vFWCTlpMWEhz6I_IZg,178
13
- autosar_calltree/generators/mermaid_generator.py,sha256=LcmWOACLAw3r7UQlnSlTM-_kpKQ6RGdgc6aNqXeMF7A,16191
14
- autosar_calltree/generators/xmi_generator.py,sha256=ndvDapHppOoDQ9q5Zu9b1AFbUKKc8q3copUti3UaFZM,12168
13
+ autosar_calltree/generators/mermaid_generator.py,sha256=K2Alg4_WvwJB5d8UpxyKt6Bv7JX0h-1oqVRuu7-hSoA,16544
14
+ autosar_calltree/generators/xmi_generator.py,sha256=gxwdErg-ahsWVsTOH1liBmrDqZfn1j_Qq6fnSHCNxJw,15482
15
15
  autosar_calltree/parsers/__init__.py,sha256=O0NTHrZqe6GXvU9_bLuAoAV_hxv7gHOgkH8KWSBmX1Y,151
16
16
  autosar_calltree/parsers/autosar_parser.py,sha256=iwF1VR4NceEfmc3gPP31CcVNPfRRVTj_aA6N94saXDA,10750
17
- autosar_calltree/parsers/c_parser.py,sha256=2LCDVZ8bcrBiQe9DK7kNMmvzhGegEDfd57KbI5JB43A,15846
18
- autosar_calltree-0.4.0.dist-info/licenses/LICENSE,sha256=Xy30Wm38nOLXLZZFgn9oD_3UcayYkm81xtn8IByrBlk,1067
19
- autosar_calltree-0.4.0.dist-info/METADATA,sha256=9O3LbtSX1byivDrDmCATcTSX5fT_Cxb-E6F0pyqhyIE,15566
20
- autosar_calltree-0.4.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
21
- autosar_calltree-0.4.0.dist-info/entry_points.txt,sha256=HfntIC1V_COOhGJ-OhtLKH_2vJ1jQy5Hlz8NmcJg4TQ,54
22
- autosar_calltree-0.4.0.dist-info/top_level.txt,sha256=eusKGYzQfbhwIFDsUYTby40SdMpe95Y9GtR0l1GVIDQ,17
23
- autosar_calltree-0.4.0.dist-info/RECORD,,
17
+ autosar_calltree/parsers/c_parser.py,sha256=87fn-97XZdlS6lbhzBT9q3Y25DwLWYiFN7tbYQxQaR0,20114
18
+ autosar_calltree-0.5.0.dist-info/licenses/LICENSE,sha256=Xy30Wm38nOLXLZZFgn9oD_3UcayYkm81xtn8IByrBlk,1067
19
+ autosar_calltree-0.5.0.dist-info/METADATA,sha256=8IuIEEw7VNmAb_Fr_lK9DvSvmvBR-6fsZ6dYrtjc9nM,22342
20
+ autosar_calltree-0.5.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
21
+ autosar_calltree-0.5.0.dist-info/entry_points.txt,sha256=HfntIC1V_COOhGJ-OhtLKH_2vJ1jQy5Hlz8NmcJg4TQ,54
22
+ autosar_calltree-0.5.0.dist-info/top_level.txt,sha256=eusKGYzQfbhwIFDsUYTby40SdMpe95Y9GtR0l1GVIDQ,17
23
+ autosar_calltree-0.5.0.dist-info/RECORD,,