4.3. Cycles

4.3.1. Introduction

A cycle in software engineering refers to a circular dependency or repetitive invocation pattern where a sequence of function calls, method invocations, or component dependencies eventually return to an earlier point in the chain, creating a loop.

Cycles in the code or architecture of a software system can be the source of various problems, such as potential runtime crashes or bugs due to infinite call recursion, maintenance issues caused by cycles in the include graph or dependency graph. The Axivion Suite provides various analyses to detect cycles in different contexts, such as call cycles, include cycles, dependency cycles.

The basis for cycle detection is an abstraction of the program’s structure represented by a view in the RFG, the “base view”, usually the “Call” or “Include” view. For call cycle detection, we abstract to a graph that consists of nodes representing functions or methods and edges representing calls between them. For include cycle detection, the graph consists of nodes representing files and edges representing include relationships between them. This view is extracted from the source code by the language analysis front ends. The specifics of this extraction depend on the programming language and are described in Language Schema. This abstraction is available for all languages supported by the Axivion Suite.

4.3.2. Cycle Detection

The cycle detection mechanism can be applied to any view in the RFG. The Axivion Suite provides three different flavors of cycle detection rules:

  • Rules that run cycle detection on a specified view and report findings for detected cycles.

  • Rules that run cycle detection on a specified view and include the results in the RFG as “Cycle” view.

  • Metric rules that report the number of cycles or cycle violations in a project.

4.3.2.1. Cycle Detection Rules

Available rules

Common configuration options

All cycle detection rules share the following common configuration options:

  • Base view (base_view_name): The view on which cycle detection is performed. This can be the call graph, include graph, or any other relevant view depending on the context of the analysis.

  • Self loops (selfloops): Whether to consider self loops (dependency from the same element to the same element) as findings.

  • Violation previews (generate_violation_previews): Whether to provide SVG previews of the detected cycles in the dashboard.

  • Preview edge limit (preview_edge_limit): Maximum number of edges in a cycle for which a preview image should be generated.

  • Preview node limit (preview_node_limit): Maximum number of nodes in a cycle for which a preview image should be generated.

  • Pre-exclude filter (pre_excludes): A filter to exclude certain directories or filenames from the analysis before cycle detection is performed.

  • Exclude filter (excludes): A cycle produces multiple entries in the analysis results, one for each element in the cycle. This filter allows you to exclude individual entries from the results based on their filename or directory. This is applied after cycle detection is performed and can be used to exclude certain entries from the results of a cycle, while still reporting the cycle itself as a finding.

Differences between cycle detection rules

The rules in the CycleDetection rule group operate on the final RFG, whereas the Architecture-CycleDetection rule is part of the architecture analysis steps, which allows you to run cycle detection at an earlier stage of the analysis, before the final RFG is produced.

Another difference is that the CycleDetection rule group provides fewer configuration options. If you want to control, which edge types are not considered for cycle detection, you should use the Architecture-CycleDetection rule and exclude the respective edge types via the Architecture-CycleDetection/ignored_edge_types option.

Note

Dynamic calls are only included in the “Call” view, if StaticSemanticAnalysis is configured correctly. The CycleDetection-CallgraphCycles/consider_dynamic_calls option does not implicitly enable dynamic call analysis. Setting this option to false only excludes edges of type Dynamic_Call from cycle detection.

4.3.2.2. How To Configure Cycle Detection

This section walks through the most common cycle detection scenarios and how to configure the Axivion Suite for each.

Setting Up Callgraph Cycle Detection

  1. Open the configuration for the desired project in the axivion_config GUI.

  2. Enable CycleDetection-CallgraphCycles in the CycleDetection rule group. This detects cycles in the call graph and reports them as findings in the dashboard.

  3. Run the analysis and review the findings. Each cycle is reported as one finding per element in the cycle, so that every function or method involved is individually traceable.

  4. If necessary, use CycleDetection-CallgraphCycles/pre_excludes to exclude directories or files whose paths form part of a cycle you do not want to report at all. Use excludes if you want to suppress individual entries from a cycle while still reporting the cycle itself.

  5. (C/C++ only) If your project uses function pointers or virtual calls that should be considered during cycle detection, enable StaticSemanticAnalysis. The discovered dynamic calls are then automatically included unless you explicitly set CycleDetection-CallgraphCycles/consider_dynamic_calls to false.

Setting Up Include Cycle Detection

  1. Open the configuration for the desired project in the axivion_config GUI.

  2. Enable CycleDetection-IncludeCycles in the CycleDetection rule group. This detects cycles in the #include graph and reports them as findings in the dashboard.

  3. Run the analysis and review the findings. Each finding refers to a file that is part of an include cycle.

  4. Use CycleDetection-IncludeCycles/pre_excludes or excludes to suppress findings from third-party or generated headers that are not under your control.

Advanced: Using Architecture-CycleDetection

Use Architecture-CycleDetection instead of the CycleDetection rule group when you need finer control — for example, to run cycle detection on a custom view or to exclude specific edge types.

  1. Open the configuration for the desired project in the axivion_config GUI.

  2. Enable Architecture-CycleDetection in the Architecture rule group, by dragging it from the “Available rules” list to the list denoted by “Drag additional actions here…”.

  3. Set Architecture-CycleDetection/base_view_name to the name of the view you want to analyze (default: Call).

  4. If certain edge types should not contribute to cycle detection — for example, Dynamic_Call edges — add them to Architecture-CycleDetection/ignored_edge_types.

  5. Run the analysis and review the findings in the dashboard.

Note

Architecture-CycleDetection runs as part of the architecture analysis steps, before the final RFG is produced. It therefore has access to intermediate analysis state that the CycleDetection rules do not.

4.3.2.3. Cycles View in the RFG

The rules Architecture-CyclesView and Architecture-LiftedCyclesView perform cycle detection on the “base view”, but instead of producing analysis results entries in the dashboard, they include the detected cycles in the RFG as a separate Cycles view or Call Cycles in Level View view, respectively. In the latter case, the cycles are lifted to the level of the hierarchy defined by the Architecture-LiftedCyclesView/hierarchy_view_name and Architecture-LiftedCyclesView/hierarchy_node_predicate options. The name of the resulting view can be configured via the result_view_name option.

Adding a Cycles View to the RFG

If you want to inspect a cycle structure interactively in Gravis rather than through dashboard findings, you can use Editic_analysis Run Analysis... from the main menu and then select Find cycles.

If you want to have a persistent Cycles view in the RFG that is automatically updated with each analysis run, you can configure the following:

These rules do not produce findings in the dashboard. To also report cycles as findings, combine them with the CycleDetection rules or Architecture-CycleDetection.