-
Notifications
You must be signed in to change notification settings - Fork 0
Coding and Style Guide
This document describes the coding guidelines which must be used when contributing to any of the NFs of the OAI CN. Some of them are enforced by the pipeline (such as formatting) and some are checked by the reviewers and maintainers. Don't worry if you do not follow them for your first MRs, we will help you adapt your code.
Each NF has a .clang-format file in the src folder. This file contains the format definitions. Ensure that you run:
clang-format-9 -i <changed_file>
before committing.
You can also use git pre-hooks or integrate clang-format-9 into your preferred IDE.
We recommend that you use a static code analyzer ("linter") to check your code. We recommend clang-tidy. It covers most rules described below.
It is enabled by default in the CLion IDE and can be enabled in VS Code.
Don't copy and paste code which only slightly differs. This is a common source for errors and it makes the code base complicated and unnecessarily large.
Instead, split your code into several functions, which are general enough that they can handle different cases (e.g. using parameters). Also ensure that your functions are not too general. They should cover exactly one well-defined functionality and should be small in size.
We recommend that you do that even if there is no other caller for now, as the code may be enhanced.
Every public or protected function in a base class shall be marked with the virtual decorator.
Every overriding function in a sub-class shall be marked with the override decorator. When a virtual function is overridden, use the override decorator instead of virtual.
Destructors shall be marked in the same style as above: Use virtual for base classes and override for sub-classes.
When you define a function where the return value must not be ignored, mark this function with [[nodiscard]].
This especially applies to:
- Getters
- Functions that return a status code indicating success or failure
Be careful that you do not use [[nodiscard]] per default. As a rule of thumb, only apply it to the two use cases mentioned above.
We never use raw pointers for dynamic memory management. We also never use new, delete, malloc or free (or other C-style memory management functions).
Instead, we always use smart pointers from <memory>.
We initialize the smart pointers using the functions std::make_shared or std::make_unique, we do not use the new keyword in combination with smart pointers.
Do use constant references wherever possible. For parameters, instead of writing: void function(TypeA obj) use: void function(const TypeA& obj).
Also, when you return an object, use constant references, e.g. for a getter: const TypeA& getA() const, except when the returned value is a temporary.
Exception to the use of const-references: for primitive types (int, float, char, raw pointers, ...), do not use const-references but pass parameters or return by value, as these types are the same size (or less) as references.
When the function does not change the state of an object, declare the function itself as const (see the getter above).
Usage of exceptions is preferred to the "C-style" return value based programming. (To be discussed with Team)