Qodana 2025.1 Help

C / C++

The C/C++ family of linters lets you analyze C and C++ projects that support any common build system like CMake or provide a compile_commands.json file. There are two different linters that provide this functionality:

Linter

Linter name

Available under licenses

Supports

Qodana Community for C/C++

jetbrains/qodana-clang:2024.3-eap

Community license

Clang-Tidy-based inspections

Qodana for C/C++

jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged>*

Ultimate and Ultimate Plus licenses

The full set of inspections provided by CLion:

  • Clang-Tidy inspections supported by the Qodana Community for C/C++ linter

  • MISRA inspections

  • Inspections based on dataflow analysis

* You can run the Qodana for C/C++ linter in the privileged mode to execute commands that need root access because in this case Qodana comes with a default qodana user that possesses root privileges and does not require a password. To do it, in the -clangXX tag specify the Clang-Tidy version from 15 to 18, and also specify the -privileged tag.

Both linters support AMD64 and ARM64 architectures.

To see the list of supported features, navigate to the Supported features section.

Implementation details

The Docker image of Qodana Community for C/C++ employs Clang 16. You can see the Dockerfile for the detailed description of all software used by the linter.

Qodana Community for C/C++ searches for compile commands in the build/compile_commands.json file of the project directory. This file is usually generated by your build system. After reading the compile_commands.json file, the linter analyzes the project, generates analysis reports and saves them locally or uploads to Qodana Cloud.

Before you start

Prepare your project

  1. You can configure Clang-Tidy-based inspections in the .clang-tidy file, see the configuration example on the GitHub website. After configuring, save this file under the project root.

  2. Open the .clang-tidy file and configure the list of files and paths that will be analyzed by Qodana.

  3. For Qodana Community for C/C++, you need to generate compile_commands.json as explained in the CLion documentation portal, and save it to the build directory under the project root.

    If you use CMake, you can also generate a compilation database by specifying the following bootstrap option in the qodana.yaml file, for example:

    bootstrap: |   set -eux   cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

    You can skip this step for the Qodana for C/C++ linter. Assuming that you have a build system supported by CLion, the project will be configured automatically. This includes compile_commands.json files placed at the project root, not in the build/ directory.

  4. If your project requires specific packages not previously mentioned in the Dockerfile, add the following bootstrap command to your qodana.yaml file to install the required packages:

    bootstrap: |   set -eux   sudo apt-get update   sudo apt-get install -y <required-packages>   cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
  5. To modify analysis paths in the compile_commands.json file while running the Qodana Community for C/C++ linter or the Qodana for C/C++ linter using the raw compile_commands.json file, follow the instructions from the Modifying paths for analysis section.

Qodana Cloud

Because the Qodana for C/C++ linter requires a Qodana Cloud project token for identifying and verifying a license, follow these steps to get it:

  1. Navigate to Qodana Cloud and create an account there.

  2. In Qodana Cloud, create an organization, a team, and a project.

  3. On the project card, you can find the project token that you will be using further in this section.

Prepare your software

On the Settings tab of the GitHub UI, create the QODANA_TOKEN encrypted secret and save the project token as its value.

  1. In Jenkins, make sure that these plugins are up and running:

    Make sure that Docker is installed and accessible to Jenkins.

    If applicable, make sure that Docker is accessible to the jenkins user as described in the Manage Docker as a non-root user section of the Docker documentation.

  2. In Jenkins, create the qodana-token credential and save the project token as its value.

  3. In Jenkins, create a Multibranch Pipeline project as described on the Jenkins documentation portal.

  1. Make sure that your project repository is accessible to GitLab CI/CD.

  2. In GitLab CI/CD, create the QODANA_TOKEN variable and save the project token as its value.

In TeamCity, Create a project and a build configuration.

Install Docker on the machine you are going to run Qodana.

If you are using Linux, you should be able to run Docker under your current non-root user.

Follow the instructions from the Qodana CLI page on GitHub.

Run this command to pull the Docker image of Qodana:

docker pull jetbrains/qodana-<cpp|clang>:2025.1|2024.3-eap<-clangXX><-privileged>

Run Qodana

To analyze the main branch, release branches and the pull requests coming to your repository, save this workflow configuration to the .github/workflows/code_quality.yml file:

name: Qodana on: workflow_dispatch: pull_request: push: branches: # Specify your branches here - main # The 'main' branch - 'releases/*' # The release branches jobs: qodana: runs-on: ubuntu-latest permissions: contents: write pull-requests: write checks: write steps: - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit fetch-depth: 0 # a full history is required for pull request analysis - name: 'Qodana Scan' uses: JetBrains/qodana-action@v2025.1 with: args: --linter,jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged> # args: --linter,jetbrains/qodana-clang:2024.3-eap # Community version env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

Here, fetch-depth: 0 is required for checkout in case Qodana works in pull request mode (reports issues that appeared only in that pull request).

To override the location of compile_commands.json (Qodana Community for C/C++ only), you can specify the location relative to the project root, so the configuration would look like:

name: Qodana on: workflow_dispatch: pull_request: push: branches: # Specify your branches here - main # The 'main' branch - 'releases/*' # The release branches jobs: qodana: runs-on: ubuntu-latest permissions: contents: write pull-requests: write checks: write steps: - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit fetch-depth: 0 # a full history is required for pull request analysis - name: 'Qodana Scan' uses: JetBrains/qodana-action@v2025.1 with: args: | --linter,jetbrains/qodana-clang:2024.3-eap, --compile-commands,<path-to-compile_commands.json> env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

More configuration examples are available in the GitHub Actions section.

Save this snippet to the Jenkinsfile:

pipeline { environment { QODANA_TOKEN=credentials('qodana-token') } agent { docker { args ''' -v "${WORKSPACE}":/data/project --entrypoint="" ''' image 'jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged>' // image 'jetbrains/qodana-clang:2024.3-eap' # Community version } } stages { stage('Qodana') { steps { sh '''qodana''' } } } }

To override the location of compile_commands.json (Qodana Community for C/C++ only), you can specify the location relative to the project root, so the configuration would look like:

pipeline { environment { QODANA_TOKEN=credentials('qodana-token') } agent { docker { args ''' -v "${WORKSPACE}":/data/project --entrypoint="" ''' image 'jetbrains/qodana-clang:2024.3-eap' } } stages { stage('Qodana') { steps { sh ''' qodana \ --compile-commands <path-to-compile_commands.json> ''' } } } }

More configuration examples are available in the Jenkins section.

In the root directory of your project, save this snippet to the .gitlab-ci.yml file:

include: - component: $CI_SERVER_FQDN/qodana/qodana/qodana-gitlab-ci@v2025.1 args: --linter,jetbrains/qodana-<cpp|clang>:2025.1|2024.3-eap<-clangXX><-privileged>

To override the location of the compile_commands.json file for the Qodana Community for C/C++ linter, specify the location relative to the project root, so the configuration would look like:

include: - component: $CI_SERVER_FQDN/qodana/qodana/qodana-gitlab-ci@v2025.1 inputs: args: | --compile-commands,<path-to-compile_commands.json>, --linter,jetbrains/qodana-clang:2024.3-eap

More configuration examples are available in the GitLab CI/CD section.

  1. In the TeamCity UI, navigate to the configuration page of a build where you would like to run Qodana.

  2. On the Build Configuration Settings page, navigate to the Build steps page.

  3. On the Build steps page, click the Add build step button.

  4. On the page that opens, select the Qodana runner.

  5. On the New Build Step: Qodana page, click Show advanced options and configure the Qodana runner:

    • Step name uniquely identifies this step among other build steps.

    • Step ID uniquely identifies this step among other build steps.

    • Execute step configures the build condition that will trigger this build step.

    • Working directory sets the directory for the build process, see the TeamCity documentation for details. You can leave this field empty if the Checkout directory parameter is specified on the Version Control Settings tab.

    • Report ID uniquely identifies the report to let you distinguish between multiple reports when several analysis steps are configured within a single build.

    • The Forward reports to TeamCity tests checkbox configures Qodana report availability in the Test tab of the TeamCity UI. Using this option, you can view codebase problems along with other problems detected.

    • Linter configures the Qodana linter.

      Here, select Custom and in the field below specify the Qodana for C/C++ linter.

    • Version is by default set to Latest.

    • Inspection profile defines an inspection profile:

    • Cloud Token configures a project token generated in Qodana Cloud.

    • Additional Docker arguments configure the arguments accepted by a Docker image, see the Configuration options section for details.

    • Additional Qodana arguments let you extend the default Qodana functionality, see the Types of options section for details.

      To override the location of a compilation command database, specify the location relatively to the project root using the --compile-commands <path-to-compile_commands.json> command.

    • Qodana CLI version lets you specify the Qodana CLI version that you would like to use.

  6. Click the Save button.

More configuration examples are available in the TeamCity section.

Run this command:

docker run \    -v <source-directory>/:/data/project/ \    -v <output-directory>/:/data/results/ \    -e QODANA_TOKEN="<cloud-project-token>" \    jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged>    # jetbrains/qodana-clang:2024.3-eap # Community version

In this command, source-directory and output-directory are full local paths to the project source code directory and the analysis result directory, respectively. The QODANA_TOKEN variable refers to the project token required by the Ultimate and Ultimate Plus linters. If you omit the QODANA_TOKEN variable, the analysis results will be available in the qodana.sarif.json file saved in the output-directory of your project root.

To override the location of the compile_commands.json file for the Qodana Community for C/C++ linter, you can specify the location relative to the project root, so the configuration would look like:

docker run \    -v <source-directory>/:/data/project/ \    -v <output-directory>/:/data/results/ \    -e QODANA_TOKEN="<cloud-project-token>" \    jetbrains/qodana-clang:2024.3-eap \    --compile-commands <path-to-compile_commands.json>

In your browser, open Qodana Cloud to examine the analysis results and reconfigure the analysis. See the Analysis reports section of the documentation for full details.

If you run the analysis several times in a row, make sure you've cleaned the results directory before using it in docker run again.

Explore analysis results

Once Qodana analyzed your project and uploaded the analysis results to Qodana Cloud, you can navigate to your project Qodana Cloud and review the analysis results report.

Analysis report example

To learn more about Qodana report UI, see the Analysis reports section.

Extend Qodana configuration

Adjusting the scope of analysis

Qodana recognizes the qodana.yaml file for the analysis configuration, so that you don't need to pass any additional parameters. For the Qodana for C/C++ linter, you can configure:

Modifying paths for analysis

Recommendations from this section are applicable only to the Qodana Community for C/C++ linter and specific cases where the Qodana for C/C++ linter is analyzing a project configured with a raw compile_commands.json file.

To modify analysis paths in the compile_commands.json file contained in the Docker container of the linter, you can run a script during the bootstrap stage of analysis. For example, the Python scripts below use glob patterns and regular expressions that modify paths in the compile_commands.json file inside the Docker container of Qodana.

#!/usr/bin/env python3 import json from pathlib import Path   # Read existing compile_commands.json ------------------------------------------ REPO_ROOT = Path.cwd() COMPILE_COMMANDS_PATH = REPO_ROOT / "build/compile_commands.json"   with open(COMPILE_COMMANDS_PATH, "r", encoding="utf-8") as fd:     compile_commands = json.load(fd)   # Filter source files ---------------------------------------------------------- from itertools import chain   INCLUDE_GLOBS = [     "src/**/*",     "include/**/*", ] allowed_paths = (REPO_ROOT.glob(pattern) for pattern in INCLUDE_GLOBS) allowed_paths = set(chain.from_iterable(allowed_paths))   def keep_condition(cc_entry: dict):     path = Path(cc_entry["file"])     return path in allowed_paths   compile_commands = list(filter(keep_condition, compile_commands))   # Save the updated list of source files ---------------------------------------- COMPILE_COMMANDS_PATH.rename(COMPILE_COMMANDS_PATH.with_suffix(".old.json")) with open(COMPILE_COMMANDS_PATH, "w", encoding="utf-8") as fd:     json.dump(compile_commands, fd, ensure_ascii=False, indent="\t")
#!/usr/bin/env python3 import json from pathlib import Path   # Read existing compile_commands.json ------------------------------------------ REPO_ROOT = Path.cwd() COMPILE_COMMANDS_PATH = REPO_ROOT / "build/compile_commands.json"   with open(COMPILE_COMMANDS_PATH, "r", encoding="utf-8") as fd:     compile_commands = json.load(fd)   # Filter source files ---------------------------------------------------------- from itertools import chain   EXCLUDE_GLOBS = [     "src/**/*",     "include/**/*", ] allowed_paths = (REPO_ROOT.glob(pattern) for pattern in EXCLUDE_GLOBS) allowed_paths = set(chain.from_iterable(allowed_paths))   # Invert the list of paths ----------------------------------------------------- allowed_paths = set(REPO_ROOT.rglob("*")) - allowed_paths   def keep_condition(cc_entry: dict):     path = Path(cc_entry["file"])     return path in allowed_paths   compile_commands = list(filter(keep_condition, compile_commands))   # Save the updated list of source files ---------------------------------------- COMPILE_COMMANDS_PATH.rename(COMPILE_COMMANDS_PATH.with_suffix(".old.json")) with open(COMPILE_COMMANDS_PATH, "w", encoding="utf-8") as fd:     json.dump(compile_commands, fd, ensure_ascii=False, indent="\t")
#!/usr/bin/env python3 import json from pathlib import Path   # Read existing compile_commands.json ------------------------------------------ REPO_ROOT = Path.cwd() COMPILE_COMMANDS_PATH = REPO_ROOT / "build/compile_commands.json"   with open(COMPILE_COMMANDS_PATH, "r", encoding="utf-8") as fd:     compile_commands = json.load(fd)   # Filter source files using the regex ------------------------------------------ import re   INCLUDE_REGEX = re.compile(r"src\/(core|engine)\/.*$")   def keep_condition(cc_entry: dict):     path = cc_entry["file"]     return re.fullmatch(INCLUDE_REGEX, path)   compile_commands = list(filter(keep_condition, compile_commands))   # Save the updated list of source files ---------------------------------------- COMPILE_COMMANDS_PATH.rename(COMPILE_COMMANDS_PATH.with_suffix(".old.json")) with open(COMPILE_COMMANDS_PATH, "w", encoding="utf-8") as fd:     json.dump(compile_commands, fd, ensure_ascii=False, indent="\t")

To run a script, use the bootstrap section of the qodana.yaml file, for example:

bootstrap: | set -eux cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON python3 filter-script.py

Enabling the baseline feature

You can skip analysis for specific problems by using the baseline feature. Information about a baseline is contained in a SARIF-formatted file.

Save this snippet to the .github/workflows/code_quality.yml file:

name: Qodana on: workflow_dispatch: pull_request: push: branches: # Specify your branches here - main # The 'main' branch - master # The 'master' branch - 'releases/*' # The release branches jobs: qodana: runs-on: ubuntu-latest permissions: contents: write pull-requests: write checks: write steps: - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit fetch-depth: 0 # a full history is required for pull request analysis - name: 'Qodana Scan' uses: JetBrains/qodana-action@v2025.1 with: args: | --linter,jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged>, --baseline,<path/to/qodana.sarif.json> # args: --linter,jetbrains/qodana-clang:2024.3-eap,--baseline,<path/to/qodana.sarif.json> # Community version env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

This snippet has the args: --baseline,<path/to/qodana.sarif.json> line that specifies the path to the SARIF file containing a baseline.

The stages block contains the --baseline <path/to/qodana.sarif.json> line that specifies the path to the SARIF-formatted baseline file:

pipeline { environment { QODANA_TOKEN=credentials('qodana-token') } agent { docker { args ''' -v "${WORKSPACE}":/data/project --entrypoint="" ''' image 'jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged>' // image 'jetbrains/qodana-clang:2024.3-eap' // Community version } } stages { stage('Qodana') { steps { sh ''' qodana \ --baseline <path/to/qodana.sarif.json> ''' } } } }

The --baseline <path/to/qodana.sarif.json> line in the script block invokes the baseline feature.

include: - component: $CI_SERVER_FQDN/qodana/qodana/qodana-gitlab-ci@v2025.1 inputs: args: | --baseline,qodana.sarif.json, --fail-threshold,<number-of-accepted-problems>, --linter,jetbrains/qodana-<cpp|clang>:2025.1|2024.3-eap<-clangXX><-privileged>
  1. In the TeamCity UI, navigate to the configuration page of a build where you would like to run Qodana.

  2. On the Build Configuration Settings page, navigate to the Build steps page.

  3. On the Build steps page, click the Add build step button.

  4. On the page that opens, select the Qodana runner.

  5. On the New Build Step: Qodana page, click Show advanced options and configure the Qodana runner:

    • Step name uniquely identifies this step among other build steps.

    • Step ID uniquely identifies this step among other build steps.

    • Execute step configures the build condition that will trigger this build step.

    • Working directory sets the directory for the build process, see the TeamCity documentation for details. You can leave this field empty if the Checkout directory parameter is specified on the Version Control Settings tab.

    • Report ID uniquely identifies the report to let you distinguish between multiple reports when several analysis steps are configured within a single build.

    • The Forward reports to TeamCity tests checkbox configures Qodana report availability in the Test tab of the TeamCity UI. Using this option, you can view codebase problems along with other problems detected.

    • Linter configures the Qodana linter.

      Here, select Custom and in the field below specify the Qodana for C/C++ linter.

    • Version is by default set to Latest.

    • Inspection profile defines an inspection profile:

    • Cloud Token configures a project token generated in Qodana Cloud.

    • Additional Docker arguments configure the arguments accepted by a Docker image, see the Configuration options section for details.

    • Additional Qodana arguments let you extend the default Qodana functionality, see the Types of options section for details.

      In this field, specify the baseline feature using the --baseline <path/to/qodana.sarif.json> option.

    • Qodana CLI version lets you specify the Qodana CLI version that you would like to use.

  6. Click the Save button.

Run this command invoking the --baseline option:

docker run \ -v <source-directory>/:/data/project/ \ -v <path_to_baseline>:/data/base/ \ -e QODANA_TOKEN="<cloud-project-token>" \ jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged> \ --baseline /data/base/<path-relative-to-project-dir>/qodana.sarif.json # Replace image with jetbrains/qodana-clang:2024.3-eap for community version

Enabling the quality gate

You can configure quality gates for:

Save this snippet to the qodana.yaml file:

failureConditions: severityThresholds: any: 50 # Total number of problems in all severities critical: 1 # Severities high: 2 moderate: 3 low: 4 info: 5

Analyzing pull requests

You can analyze pull requests using the Qodana for C/C++ linter.

The Qodana Scan GitHub action automatically analyzes all pull requests, so you do not have to provide any additional configuration. Save this configuration to the .github/workflows/code_quality.yml file:

name: Qodana on: workflow_dispatch: pull_request: push: branches: # Specify your branches here - main # The 'main' branch - 'releases/*' # The release branches jobs: qodana: runs-on: ubuntu-latest permissions: contents: write pull-requests: write checks: write steps: - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit fetch-depth: 0 # a full history is required for pull request analysis - name: 'Qodana Scan' uses: JetBrains/qodana-action@v2025.1 with: args: --linter,jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged> env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }}

In the root directory of your project, save the .gitlab-ci.yml file containing the following snippet:

include: - component: $CI_SERVER_FQDN/qodana/qodana/qodana-gitlab-ci@v2025.1 inputs: args: --linter,jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged>

This configuration enables merge request analysis.

Information about configuring TeamCity for analyzing pull and merge requests is available on the TeamCity documentation portal.

To analyze changes in your code, employ the --diff-start option and specify a hash of the commit that will act as a base for comparison:

qodana scan \ -e QODANA_TOKEN="<cloud-project-token>" \ -l jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged> \ --diff-start=<GIT_START_HASH>
docker run \    -v $(pwd):/data/project/ \    -e QODANA_TOKEN="<cloud-project-token>" \    jetbrains/qodana-cpp:2025.1-eap<-clangXX><-privileged> \    --diff-start=<GIT_START_HASH>

Supported features

Both linters provide the following Qodana features:

Feature

Available under licenses

Baseline

Community, Ultimate and Ultimate Plus

Quality gate

Community, Ultimate and Ultimate Plus

Usage statistics

According to the JetBrains EAP user agreement, we can use third-party services to analyze the usage of our features to further improve the user experience. All data is collected anonymously. To disable the statistics, use the --no-statistics=true CLI option.

Last modified: 27 June 2025