Coding Guidelines

General

openPASS (Open Source) is based on modern C++ (currently C++17). For coding guidelines, please refer to ISO C++ Core Guidelines.

Headers/Sources

  • Use *.h as file extension for header files

  • Use *.cpp as file extension for source files

Naming Conventions

Concise summarized Naming Conventions

#pragma once

namespace openpass::component::algorithm
{

/* fooBar.h */                                           // File: lowerCamelCase
class FooBar                                             // Class: UpperCamelCase
{
private:
    static constexpr int MAGIC_NUMBER {-999};            // Constants: UPPER_CASE
    int myMember;                                        // Members: lowerCamelCase
    FooBar();                                            // Ctor: UpperCamelCase

public:
    void Bar();                                          // Methods: UpperCamelCase
    void BarBar(bool flag, int counter);                  // Arguments: lowerCamelCase
    void YaaBar(); /// Yaa = Yet Another Abbreviation    // Abbreviations: UpperCamelCase
};

}

Namespaces

  1. Use lowercase for namespaces

  2. Use singular form for namespaces where appropriate

  3. Use base namespace openpass

  4. Core uses openpass::core::*

  5. Components use openpass::component::*

  6. Use the appropriate namespace for the type your component * openpass::component::algorithm * openpass::component::sensor * openpass::component::dynamics * openpass::component::driver * …

  7. Code with shared scope (e.g. common) namespaces are separated in

    • For everyone openpass::common e.g. openpass::common::XmlParser

    • Common for components openpass::component::common e.g. openpass::components::Ports

    • For the core only openpass::core::common e.g. openpass::core::common::Parameters

  8. Discussion: openpass::type::*

    Example: openpass::type::Vector2D, openpass::type::OpenDriveId

Interfaces

  1. Interfaces should be named descriptively according to the functionality they outline with an UpperCamelCase name

    Example: Interface for the world = class WorldInterface

  2. Interfaces are abstract classes, and as such provide pure virtual functions only, withtout any default implementation. For example:

    virtual double GetDistance() const = 0;

  3. Interface methods do not exibit default parameters.

  4. We excessively use gmock, so for every interface a fake interface should be provided

    Example: class FakeWorld : public WorldInterface {...};

    Note: Following *Roy Osherove*, we use Fake instead of Mock, whick allows to distinguish Mocks and Stubs more easily in the code

Classes

  1. Classes should be named descriptively according to the functionality they implement with an UpperCamelCase name

  2. A Class implementing an Interface should have the Interfaces name (see below), with the Interface portion removed. For example: .. code-block:

    class AgentBlueprint : public AgentBlueprintInterface {...};
    

Methods

  1. Methods should be descriptively named in UpperCamelCase

    Example: Method for retrieving the time of day should be named GetTimeOfDay()

Member Variables

  1. Member variables should be descriptively named in lowerCamelCase

  2. Normally, it is sufficient to use the classes name directly.

    Example: The member variable containing the AgentNetwork should be named agentNetwork

Input / Output Signal Naming

  1. Components use a special form of signal transmission. For easier use, the following abstraction is recommended: .. code-block:

    std::map<int, ComponentPort *> outputPorts;
    bool success = outputPorts.at(localLinkId)->SetSignalValue(data);
    
    std::map<int, ComponentPort *> inputPorts;
    bool success = inputPorts.at(localLinkId)->GetSignalValue(data);
    
  2. Discussion: Wrap in openpass::components::common::Port and further openpass::components::common::Ports

Additional Information

  1. Use UpperCamelCase for abbreviations used in files, classes, methods, or variables

  2. This does not apply if the abbreviation is the entire name or the beginning of the name - in such a case the name is written with the rules for the appropriate type

    • int ID→int id

    • class AgentID→ class AgentId

    • ADASDriver.cpp→adasDriver.cpp

  3. Avoid public class data members. If unavoidable, use lowerCamelCase

  4. Enums should be preferably defined as enum class; as such, enum names should be in UpperCamelCase

  5. Decorate container by type aliases and use UpperCamelCase. For example:

using FooParts = std::vector<FooPart>;

Avoid

  1. Do not use Hungarian notation for variables names (iCounter → counter)

  2. Do not specify the type of the underlying implementation (partMap→ parts)

  3. Do not use magic numbers in the code; explicitly define constants instead

  4. Do not use global variables

Exceptions

  1. Autogenerated code does not need to follow the coding conventions

    Example:: Signals/Slots (QT): void on_button_clicked();

Documentation

  1. The following should be documented * Public functions and class methods * Classes * File headers * Constants * Private functions or methods with more than 3 arguments and/or complex functionality??

  2. Language

    • Document “what” it does rather than describing “why”

    • Third-person singular verbs should be used to describe what it does

  3. Use the below methods to comment in source code. The below 2 syntaxes must be placed just above an entity.

    Multi line comments

    //! … comments…
    //! … comments…
    //! … comments…
    

    Single line comments

    /// Comments.
    
  4. Use the following structural commands

    Syntax

    Definition

    @file

    The file name must be present in the file header

    @param[in/out]

    Parameter documentation for functions

    @page

    Markdown page name

  5. Use the following syntax for parameter description

    @param[in/out] <variable name> <variable description>
    
  6. All parameters description should be aligned as shown below to make them more readable.

    @param[in]  shortName    Description.
    @param[in]  longerName   Description.
    @param[out] veryLongName Description.
    
  7. Example

    /// @file main.c
    #include<stdio.h>
    
    /// Mathematical constant PI 
    #define PI       3.1415 
    
    /// Radius in meters  
    #define RADIUS_M 7.82
     
    //! Calculates the area of the circle.
    //! 
    //! @param[in]  radius Radius of the circle
    //! @param[out] area   Area of the circle
    float CalculateArea(float radius)
    {
        float area;
        area = PI * radius * radius;
        return area;
    }
    
  8. Do not comment on polymorph methods (virtual base → override), unless there is a severe change

End Of Line

  1. Native end of line (EOL) should be used in the working directory

  2. The .gitattributes configuration file provides correct EOL handling for git related commands and actions

  3. When editing files

    • Trim trailing whitespaces

    • Single EOL at end of files

    • Use spaces for tabs (use tab size according to coding guidelines or existing file contents)

See Example VSCode user settings.

ClangFormat

To ensure consistent and readable code across the project, ClangFormat is recommended.

Note

The following guidelines are based on ClangFormat version 15.0.7

Installing ClangFormat

To install ClangFormat 15.0.7, execute the following command depending on the operating system.

pacman -S mingw-w64-x86_64-clang

Configuring ClangFormat

To configure ClangFormat, create a .clang-format file in the root directory of your project. Below is the configuration used in openPASS (Open Source):

---
BasedOnStyle: Google
AccessModifierOffset: -2
AllowShortFunctionsOnASingleLine: Inline
AlignOperands: AlignAfterOperator
BinPackArguments: false
BinPackParameters: false
BreakBeforeBraces: Allman
BreakBeforeBinaryOperators: All
ColumnLimit: 120
SpacesInLineCommentPrefix:
  Minimum: 0
  Maximum: 1
CommentPragmas:  '^\\.+'
IncludeCategories:
  - Regex:           '^((<|")(gtest|gmock)/)'
    Priority:        -1
  - Regex:           '^<[^Q]'
    Priority:        1
  - Regex:           '^<Q'
    Priority:        2

Running ClangFormat

To format the code using ClangFormat, run the following command in the terminal:

clang-format -i [source_file(s)]

Replace [source_file(s)] with the path(s) to the file(s) to format. The -i option tells ClangFormat to modify the files in-place.

ClangTidy

Supported Version: 14.0.6

To ensure code quality and adherence to coding standards, ClangTidy is recommended.

The used checks are located in the .clang-tidy file, where lines starting with - are checks that have been deactivated. For more details, visit the ClangTidy official page.

Commit Message Guidelines

Overview

This section outlines the guidelines for writing commit messages in openPASS repository. Following these guidelines ensures that commit messages are clear, descriptive, and help facilitate collaboration among team members. This section uses excerpts from Conventional Commits licensed under CC BY 3.0 by it’s authors.

Commit Message Format

Each commit message should consist of a single short summary line (recommended, up to 50 characters) followed by a more detailed description (if necessary). The message should adhere to the following format:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]
  1. The <type> part represents the type of the commit, which helps in categorizing the nature of the changes. The following types are allowed:

    • feat: A new feature or enhancement.

    • fix: A bug fix.

    • docs: Documentation-related changes.

    • style: Code style changes (e.g., formatting, spacing).

    • refactor: Code refactoring without adding new features or fixing bugs.

    • test: Adding or improving tests.

    • chore: Maintenance tasks, build changes, or other non-functional modifications.

    • ci: Changes related to CI.

    • build: Modifications related to build step.

    • perf: Modifications related to performance improvements.

    • revert: Revert any code changes.

  2. The <optional scope> section is optional but is used to provide additional contextual information and is contained within parenthesis.

  3. The <description> is a brief description of the changes made in the commit. It should be concise yet informative and is recommended to not exceed 50 characters.

  4. The <optional body> section is optional but recommended, especially for complex changes or when further explanation is needed. This section should provide additional context, justification, and details about the changes made. Use bullet points for better readability when necessary.

  5. The <optional footer> section is also optional but can be used to provide supplementary information related to the commit.

Header File Inclusion

Overview

When working on a C/C++ project, it’s essential to include header files correctly. This documentation explains the various ways to include header files, depending on their source.

System Libraries

Header files from system libraries should be enclosed in angular brackets (< >). This syntax informs the compiler to search for the headers in the system’s standard include directories.

#include <stdio.h>
#include <stdlib.h>

Dependencies in CMAKE_PREFIX_PATH

If the header files are from dependencies that are part of the CMAKE_PREFIX_PATH, use angular brackets (< >) as well. This indicates to the compiler that the headers are part of external dependencies.

#include <dependency/header.h>

Repository Header Files

If the header files are from project’s repository then, use double quotes (” “”).

#include "my_component/header.h"