Qodana logo

Qodana

The code quality platform for teams

Tutorials

Fixing Unreal Engine Project Issues With Qodana

If you saw our blog post about using Qodana in Unity and .NET projects, you know that we’ve been striving to explore Qodana’s potential for game development. What’s our next stop on this mission? Seeing our code quality platform in action with Unreal Engine, one of the most popular engines for different types of projects – from virtual reality prototypes to triple-A games. 

In this post, we’ll demonstrate how we used our static analysis tool Qodana on Lyra Starter Game, a widely known sample project from Epic Games. We chose this project for its large codebase, which provides a wider range of potential issues to identify, analyze, and fix. 

The analysis and the resolution of issues were carried out by a junior developer. Our goal was to check how someone still building their game development knowledge can use Qodana to improve code and product quality. 

Running Qodana from the IDE

We started by running Qodana from an IDE (Rider) to see the initial results and set up filtering. As Qodana is integrated with the most popular JetBrains IDEs, it can be easily launched directly from the Tools menu. For a better team experience, we also recommend using the JetBrains CI/CD solution, TeamCity. After setting up we will switch that on as well to set up a seamless process and quality gate.

 Running Qodana in the IDE
 Running Qodana in the IDE

You can run Qodana in your IDE without a token, but we wanted our results to be accessible from Qodana Cloud, a cloud-based tool for Qodana reports. To upload a report to the cloud, you need a license token, which you can get from the Qodana Cloud project. We will also use the token to integrate our analysis into the CI/CD pipeline.

The qodana.yaml file is created automatically and shown in the popup below. 

The qodana.yaml popup
The qodana.yaml popup

You can modify this file directly in the popup window if you need to, and you can run inspections with the qodana.starter profile to check if there are any critical errors. Once you run it, the file will be saved in the project root. We wanted to use a custom profile, so we modified this file to reference the custom profile.yaml.

In the qodana.yaml file, we left a link to the profile. QDNET is a linter based on the Rider distribution and designed to work with Unreal Engine projects.

version: "1.0"

#Specify IDE code to run analysis without container (Applied in CI/CD pipeline)
ide: QDNET

#Specify inspection profile for code analysis
profile:
  path: profile.yaml

qodana.yaml

In the profile.yaml file, we changed the profile to the more extensive qodana.recommended and identified scope to be excluded from the analysis. We wanted to analyze only the project codebase, without Unreal Engine or plugin sources.

baseProfile: "qodana.recommended"
name: "UnrealEngine"

inspections:
  - group: ALL
    ignore:
      - "scope#!file:Source/LyraGame//*"

profile.yaml

These changes provided a relatively comprehensive analysis report.

 We then linked our project to Qodana Cloud. 

 Linking the project to Qodana Cloud
 Linking the project to Qodana Cloud

This will allow us to access future reports withinin the IDE and view problems locally.

The report in the IDE
The report in the IDE

Setting up the CI/CD pipeline

We already had a CI/CD pipeline in TeamCity, which we used to build the project every time we pushed changes to the main branch. There are several ways to complete the build. One such method is with the Unreal Engine plugin for TeamCity which can be downloaded from JetBrains Marketplace. You don’t have to run the build before running Qodana, but it is convenient to put it in the same pipeline. This allows TeamCity to mark the build as Failed if Qodana finds any issues.

To run the Qodana analysis, we added a PowerShell step that loaded and ran our Qodana CLI tool. We opted for the latest AMD64-compatible version and assets for our agents. If you are working with a different operating system and architecture, you will have to choose the assets designed for them. 

Before implementing this in any project, you should discuss the security implications with the people responsible for this in your organization. Downloading a third-party binary without checking its integrity and checksum can be risky. You may need to save a fixed version of the binary yourself or verify the checksum of the downloaded distribution. 

Invoke-WebRequest -Uri "https://github.com/JetBrains/qodana-cli/releases/download/%VERSION%/qodana_windows_x86_64.exe" -OutFile "qodana_windows_x86_64.exe" 

./qodana_windows_x86_64.exe scan --ide QDNET

PowerShell build step

The linter requires a Qodana token, a value from the project page on Qodana Cloud. To pass the token through the pipeline, we added the QODANA_TOKEN environment variable with the Password value type to ensure the token remains secure.

Then, in the same way, we added the desired version of Qodana CLI as a configuration parameter.

Fixing problems

For this Unreal Engine project, we were particularly interested in issues specific to projects created with the game engine. We used filters on Qodana Сloud to show only these problems.

Analyzing an Unreal Engine project
Unreal Engine problems

Qodana’s sunburst diagram provides a convenient visualization of the detected issues, as well as an easy way to navigate to them. In our case, we could see there were seven types of problems, some of which could be resolved using context actions:

  • BlueprintCallable function can be made const
  • BlueprintCallable function can be made static
  • Use of a class that has not been declared previously

To quickly navigate to these issues in the IDE, we can click on the Open file in Rider button.

Please note: to get this functionality to work you have to install JetBrains Toolbox on your computer.

Example of a problem in Qodana Cloud
Example of a problem in Qodana Cloud

After opening the file in the IDE, we resolved this problem using the relevant quick-fix with a context action.

Example of a problem in the IDE
Example of a problem in the IDE

You can also navigate by opening a report locally in the IDE and going through the list of problems grouped there by type, fixing them one by one. As you fix problems in the IDE, the number of issues detected will decrease.

We decided not to fix problems like BlueprintCallable function is never used in Blueprint or C++ code, as the Lyra project is considered learning material, and it’s actively maintained. The project contains methods that are not currently being used but may be in the future. 

Additionally, we decided not to fix inconsistent Unreal Engine naming problems because the project uses a different naming convention, where upper case is used for all abbreviations.

Example of a naming problem in the IDE
Example of a naming problem in the IDE

To deactivate these inspections, we added their inspection IDs to profile.yaml and set the enabled property to false, ensuring these types of problems will no longer be shown in reports. The problem ID can be found in the qodana.sarif.json file.

Next, we moved to C++ problems. We decided to only fix the problems that were categorized as higher than moderate severity, as most low-level issues could be fixed with quick-fixes. We excluded the non-critical issues by changing the profile.yaml file.

baseProfile: "qodana.recommended"
name: "UnrealEngine"

inspections:
 - group: ALL
   ignore:
     - "scope#!file:Source/LyraGame//*"
 - group: "severity:TYPO"
   enabled: false
 - inspection: "CppUE4CodingStandardNamingViolationWarning"
   enabled: false
 - inspection: "CppUEBlueprintCallableFunctionUnused"
   enabled: false

profile.yaml

This produced a report with less than a thousand problems. To experiment with different filtering strategies, we used separate branches for each YAML file. This allowed us to divide the problems into groups based on type, tackling each type in a separate branch with different settings and then merging the branches.

Low-severity C++ problems excluded
Low-severity C++ problems excluded

Even without the low-level results, we saw many types of problems that were not in the Unreal Engine category. 

In total, our team fixed 822 of 937 problems from the categories we examined next.

As you can see below, the most common problems fell into the Common Practices and Code Improvements category and included issues like variables that could be made const or static. We resolved most of them with quick-fixes. We left problems like Function is not implemented, as they could be fixed in future development. We decided not to fix some of the problems, as the changes required to mitigate them would make the project uncompilable and in need of further refactoring.

Problems classified as Common Practices and Code Improvements
Problems classified as Common Practices and Code Improvements

As a result, we were left with only 26 problems in the Common Practices and Code Improvements category, which we could deal with later. 

Remaining problems classified as Common Practices and Code Improvements
Remaining problems classified as Common Practices and Code Improvements

Up next were potential code quality issues. From this category, we fixed problems where we needed to remove unused declarators or directives. We then moved to redundancies in code, most of which were resolved easily with a quick-fix. We did not address any problems where developers left comments with their plans or TODOs because we assumed that these problems would be fixed with future changes.

Example of a TODO
Example of a TODO

Last but not least, the Syntax Style category contained only two types of problems, both of which concerned the use of virtual and override specifiers when overriding functions. We fixed all of them by adding the missing specifiers.

Syntax Style problems
Syntax Style problems

We were left with 123 unresolved problems, either due to ongoing development or the lack of a feasible solution. We moved these issues to the baseline. To apply the baseline, we downloaded the baseline file and stored it in the repository.

Selecting problems
Selecting problems
Downloading the baseline file
Downloading the baseline file

Then, by adding the –baseline parameter and path to the file, we adjusted the pipeline to include the baseline in future analyses.

Invoke-WebRequest -Uri "https://github.com/JetBrains/qodana-cli/releases/download/%VERSION%/qodana_windows_x86_64.exe" -OutFile "qodana_windows_x86_64.exe" 
./qodana_windows_x86_64.exe scan --ide QDNET --baseline qodana.sarif.json

PowerShell build step

And finally, we had a flawless report.

If our team decided to continue working on this project, we could fix new problems as they appeared or we could focus on eliminating problems from the baseline, depending on our priorities.

We set up a quality gate to enforce the standards we had achieved with these efforts, and we added a several failureConditions section to qodana.yaml to configure additional quality gates for the total number of problems, as well as the numbers of critical and high-severity issues. Going forward, if any of these limits are exceeded, the build will fail.

failureConditions:
  severityThresholds:
    any: 10 # Total problems
    critical: 0 # Critical and other severities
    high: 5

Added qodana.yaml configuration

We also adjusted the execution of qodana-cli to consider exit code, failing the build if the result fails the quality gates. By failing builds that don’t meet our quality criteria, we can identify and address issues immediately.

Invoke-WebRequest -Uri "https://github.com/JetBrains/qodana-cli/releases/download/%VERSION%/qodana_windows_x86_64.exe" -OutFile "qodana_windows_x86_64.exe" 
./qodana_windows_x86_64.exe scan --ide QDNET 

# Capture the exit code of the command
$exitCode = $LASTEXITCODE

# Print the exit code
Write-Output "Exit code: $exitCode"

# Exit the script with the same exit code
exit $exitCode

PowerShell build step

A failed build in TeamCity

Qodana’s Unreal Engine analysis summarized

We successfully analyzed the Lyra project, got a detailed report, and fixed more than 800 problems. While conducting professional reviews will likely require a deeper understanding of Unreal Engine, Qodana’s analysis still helped a single junior developer clean up the code and make it more concise. 

For large-scale projects like Lyra, Qodana can effectively highlight and prioritize critical code issues that may be overlooked in manual reviews.

Since Lyra is a private repo, we can’t share the outcome, but we hope we’ve shown you how this process could work for your team and what kind of results it can deliver.

If you’d like more information, visit our website, view Qodana’s features, or try it in your next game development project. 

Switch to Qodana for code analysis and get 25% off

Qodana gets better with every release and provides a cost-effective way for teams to build confidence in code quality. 

With this in mind, we’re offering you 25% off your first year of Qodana if you switch from a comparable commercial solution. Click on the button below to speak to our team. 

Switch To Qodana

Thank you to Software Developer Ekaterina Trukhan for her contribution to this analysis. 

image description