doc: Add clang-tidy to "coding-style.rst"
This commit is contained in:
@@ -154,6 +154,138 @@ For quick-reference, the most used commands are listed below:
|
|||||||
# Individual file
|
# Individual file
|
||||||
/path/to/utils/check-style-clang-format.py [--fix] [--no-formatting] [--no-whitespace] [--no-tabs] absolute_or_relative/path/to/file
|
/path/to/utils/check-style-clang-format.py [--fix] [--no-formatting] [--no-whitespace] [--no-tabs] absolute_or_relative/path/to/file
|
||||||
|
|
||||||
|
|
||||||
|
Clang-tidy
|
||||||
|
**********
|
||||||
|
|
||||||
|
The |ns3| project uses `clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`_
|
||||||
|
to statically analyze (lint) C++ code and help developers write better code.
|
||||||
|
Clang-tidy can be easily integrated with modern IDEs or run manually on the command-line.
|
||||||
|
|
||||||
|
Clang-tidy installation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Clang-format can be installed using your OS's package manager. Please note that you
|
||||||
|
should install one of the supported versions of clang-format, which are listed in the
|
||||||
|
following section.
|
||||||
|
|
||||||
|
Minimum clang-tidy version
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Since clang-tidy is a linter that analyzes code and outputs errors found during
|
||||||
|
the analysis, developers can use different versions of clang-tidy on the workflow.
|
||||||
|
Newer versions of clang-tidy might produce better results than older versions.
|
||||||
|
Therefore, it is recommended to use the latest version available.
|
||||||
|
|
||||||
|
To ensure consistency among developers, |ns3| defines a minimum version of clang-tidy,
|
||||||
|
whose warnings must not be ignored. Therefore, developers should, at least, scan their
|
||||||
|
code with the minimum version of clang-tidy.
|
||||||
|
|
||||||
|
The minimum version is clang-tidy-14.
|
||||||
|
|
||||||
|
Integration with IDEs
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Clang-tidy automatically integrates with modern IDEs (e.g., VS Code) that read the
|
||||||
|
``.clang-tidy`` file and automatically checks the code of the currently open file.
|
||||||
|
|
||||||
|
Please refer to the documentation of your IDE for more information.
|
||||||
|
Some examples of IDE integration are provided in
|
||||||
|
`clang-tidy documentation <https://clang.llvm.org/extra/clang-tidy/Integrations.html>`_
|
||||||
|
|
||||||
|
Manual usage in the terminal
|
||||||
|
============================
|
||||||
|
|
||||||
|
In order to use clang-tidy on the terminal, |ns3| must first be configured by running
|
||||||
|
the following command on the terminal:
|
||||||
|
|
||||||
|
.. sourcecode:: console
|
||||||
|
|
||||||
|
./ns3 configure --enable-clang-tidy
|
||||||
|
|
||||||
|
Then, clang-tidy can be manually run on the terminal by applying the following commands
|
||||||
|
in the |ns3| root directory:
|
||||||
|
|
||||||
|
.. sourcecode:: console
|
||||||
|
|
||||||
|
# Analyze (and fix) single file with clang-tidy
|
||||||
|
clang-tidy -p cmake-cache/ [--fix] [--format-style=file] [--quiet] $FILE
|
||||||
|
|
||||||
|
# Analyze (and fix) multiple files in parallel
|
||||||
|
run-clang-tidy -p cmake-cache/ [-fix] [-format] [-quiet] $FILE1 $FILE2 ...
|
||||||
|
|
||||||
|
# Analyze (and fix) the entire ns-3 codebase in parallel
|
||||||
|
run-clang-tidy -p cmake-cache/ [-fix] [-format] [-quiet]
|
||||||
|
|
||||||
|
Please note that clang-tidy only analyzes implementation files (i.e., ``*.cc`` files).
|
||||||
|
Header files are analyzed when they are included by implementation files, using the
|
||||||
|
``#include "..."`` directive.
|
||||||
|
|
||||||
|
Integration with CMake
|
||||||
|
======================
|
||||||
|
|
||||||
|
CMake provides native integration for clang-tidy. This allows CMake to simultaneously
|
||||||
|
build |ns3| and scan the codebase with clang-tidy. To enable this process, please
|
||||||
|
use the following commands on the |ns3| root directory:
|
||||||
|
|
||||||
|
.. sourcecode:: console
|
||||||
|
|
||||||
|
./ns3 configure --enable-clang-tidy
|
||||||
|
./ns3 build
|
||||||
|
|
||||||
|
Please note that enabling clang-tidy scanning will add time to the build process
|
||||||
|
(in the order of minutes).
|
||||||
|
|
||||||
|
Disable analysis in specific lines
|
||||||
|
==================================
|
||||||
|
|
||||||
|
To disable clang-tidy analysis of a particular rule in a specific function,
|
||||||
|
specific clang-tidy comments have to be added to the corresponding function.
|
||||||
|
Please refer to the `official clang-tidy documentation <https://clang.llvm.org/extra/clang-tidy/#suppressing-undesired-diagnostics>`_
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
To disable ``modernize-use-override`` checking on ``func()`` only, use one of the
|
||||||
|
following two "special comment" syntaxes:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
//
|
||||||
|
// Syntax 1: Comment above the function
|
||||||
|
//
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(modernize-use-override)
|
||||||
|
void func();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Syntax 2: Trailing comment
|
||||||
|
//
|
||||||
|
|
||||||
|
void func(); // NOLINT(modernize-use-override)
|
||||||
|
|
||||||
|
To disable ``modernize-use-override`` checking on a block of code, use the
|
||||||
|
following "special comment" syntax:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
// NOLINTBEGIN(modernize-use-override)
|
||||||
|
void func1();
|
||||||
|
void func2();
|
||||||
|
// NOLINTEND(modernize-use-override)
|
||||||
|
|
||||||
|
|
||||||
|
To disable all clang-tidy checks on a block of code, use the following
|
||||||
|
"special comment" syntax:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
// NOLINTBEGIN
|
||||||
|
void func1();
|
||||||
|
void func2();
|
||||||
|
// NOLINTEND
|
||||||
|
|
||||||
|
To exclude the whole file from being formatted, surround the whole file with the
|
||||||
|
special comments.
|
||||||
|
|
||||||
Source code formatting
|
Source code formatting
|
||||||
**********************
|
**********************
|
||||||
|
|
||||||
@@ -804,6 +936,40 @@ The omission is preferred to commenting out unused parameters, such as:
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Unnecessary else after return
|
||||||
|
=============================
|
||||||
|
|
||||||
|
In order to increase readability and avoid deep code nests, consider not adding
|
||||||
|
an ``else`` block if the ``if`` block breaks the control flow (i.e., when using
|
||||||
|
``return``, ``break``, ``continue``, etc.).
|
||||||
|
|
||||||
|
For instance, the following code:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n += 3;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
can be rewritten as:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
n += 3;
|
||||||
|
return n;
|
||||||
|
|
||||||
Smart pointer boolean comparisons
|
Smart pointer boolean comparisons
|
||||||
=================================
|
=================================
|
||||||
|
|
||||||
@@ -905,3 +1071,77 @@ Miscellaneous items
|
|||||||
using the ``using`` directive; i.e., avoid ``using namespace std;``.
|
using the ``using`` directive; i.e., avoid ``using namespace std;``.
|
||||||
|
|
||||||
- Do not use the C++ ``goto`` statement.
|
- Do not use the C++ ``goto`` statement.
|
||||||
|
|
||||||
|
Clang-tidy rules
|
||||||
|
================
|
||||||
|
|
||||||
|
Please refer to the ``.clang-tidy`` file in the |ns3| root directory for the full list
|
||||||
|
of rules that should be observed while developing code.
|
||||||
|
|
||||||
|
- Explicitly mark inherited functions with the ``override`` specifier.
|
||||||
|
|
||||||
|
- Prefer to use ``.emplace_back()`` over ``.push_back()`` to optimize performance.
|
||||||
|
|
||||||
|
- When creating STL smart pointers, prefer to use ``std::make_shared`` or
|
||||||
|
``std::make_unique``, instead of creating the pointer with ``new``:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
auto node = std::make_shared<Node>(); // OK
|
||||||
|
auto node = std::shared_ptr<Node>(new Node()); // Avoid
|
||||||
|
|
||||||
|
- When looping through containers, prefer to use range-based for loops rather than
|
||||||
|
index-based loops:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
std::vector<int> myVector = {1, 2, 3};
|
||||||
|
|
||||||
|
for (const auto& v : myVector) { ... } // Prefer
|
||||||
|
for (int i = 0; i < myVector.size(); i++) { ... } // Avoid
|
||||||
|
|
||||||
|
- When looping through containers, prefer to use const-ref syntax over copying
|
||||||
|
elements:
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
std::vector<int> myVector = {1, 2, 3};
|
||||||
|
|
||||||
|
for (const auto& v : myVector) { ... } // OK
|
||||||
|
for (auto v : myVector) { ... } // Avoid
|
||||||
|
|
||||||
|
- When initializing ``std::vector`` containers with known size, reserve memory to
|
||||||
|
store all items, before pushing them in a loop.
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
int N_ITEMS = 5;
|
||||||
|
std::vector<int> myVector;
|
||||||
|
myVector.reserve(N_ITEMS); // Reserve memory required to store all items
|
||||||
|
for (int i = 0; i < N_ITEMS; i++)
|
||||||
|
{
|
||||||
|
myVector.emplace_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
- Prefer to initialize STL containers (e.g., ``std::vector``, ``std::map``, etc.)
|
||||||
|
directly with lists, instead of pushing elements one-by-one.
|
||||||
|
|
||||||
|
.. sourcecode:: cpp
|
||||||
|
|
||||||
|
// OK
|
||||||
|
std::vector<int> myVector = {1, 2, 3};
|
||||||
|
|
||||||
|
// Avoid
|
||||||
|
std::vector<int> myVector;
|
||||||
|
myVector.reserve(3);
|
||||||
|
myVector.emplace_back(1);
|
||||||
|
myVector.emplace_back(2);
|
||||||
|
myVector.emplace_back(3);
|
||||||
|
|
||||||
|
- Avoid unnecessary calls to the functions ``.c_str()`` and ``.data()`` of
|
||||||
|
``std::string``.
|
||||||
|
|
||||||
|
- Avoid declaring trivial destructors, to optimize performance.
|
||||||
|
|
||||||
|
- Prefer to use ``static_assert()`` over ``NS_ASSERT()`` when conditions can be
|
||||||
|
evaluated at compile-time.
|
||||||
|
|||||||
Reference in New Issue
Block a user