docs/source/contributing/code/development-guidelines.rst
.. note::
New to Cutter development? Check out our :doc:tutorial for new developers <getting-started>.
CutterCore Class
This is the main class where every link with Rizin is made. It is *unique*
across the whole process. To access it, simply call ``Core()``.
Example:
.. code:: cpp
Core()->getOffset();
Seek the Current File
To modify Rizin seek use CutterCore::seek(const RVA offset). This
is important because it will emit a
CutterCore::seekChanged(RVA offset) signal. Never ever call
cmd("s offset");
Example:
.. code:: cpp
Core()->seek(0x00C0FFEE);
.. note::
Cutter also supports a silent seek which doesn't trigger the seekChanged event and doesn't add new entries to the seek history.
Creating a Widget
Make sure to connect the ``CutterCore::seekChanged(RVA offset)`` signal
so your widget refreshes its output when Rizin seek is modified
(switching to another function, etc.).
Coding Style
------------
clang-format
~~~~~~~~~~~~
In general, we follow a slightly customized version of `the official Qt guidelines <https://wiki.qt.io/Qt_Coding_Style>`__
to format the code. Before sending a pull request, you will need to use `clang-format <https://clang.llvm.org/docs/ClangFormat.html>`__ (version 8 or newer)
to format the code. The command line for formatting the code according
to the style is:
.. code:: bash
clang-format -style=file -i src/filename.cpp
If your changes were done on many files across the codebase, you can use this oneliner to run ``clang-format`` on the entire ``src`` directory:
.. code:: bash
find ./src -regex '.*\.\(cpp\|h\)' -exec clang-format -style=file -i {} \;
clang-tidy
~~~~~~~~~~
Beyond formatting, we use `clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`__ (version 13 or newer) to catch potential style violations.
To run ``clang-tidy``, first configure your build to generate ``compile_commands.json`` and run the autogen tools:
.. code:: bash
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCUTTER_QT=6 -DCUTTER_USE_BUNDLED_RIZIN=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
cmake --build build --target Cutter_autogen
Run ``clang-tidy`` on modified files relative to the latest commit
.. code:: bash
git diff -U0 --no-color HEAD~1 | clang-tidy-diff.py -p1 -path build/
Similar to ``clang-format``, If your changes were done on many files across the codebase, you can use this oneliner to run ``clang-tidy`` on the entire 'src' directory. The following command excludes third-party and auto generated files:
.. code:: bash
run-clang-tidy -p build ".*src/(?!(themes|bindings|fonts|img|translations|Cutter_autogen)).*\.(cpp|h)$"
``clang-tidy`` can also attempt to fix style violations using the ``-fix`` flag. However these may not always be perfect. Make sure to verify the fixes before opening a pull request:
.. code:: bash
git diff -U0 --no-color HEAD~1 | clang-tidy-diff.py -fix -p1 -path build/
Python scripts
~~~~~~~~~~~~~~
If you don't want to run manual commands, cutter also provides scripts for running ``clang-format`` and ``clang-tidy`` in the ``scripts`` directory
.. code:: bash
python scripts/clang-format.py -h
usage: clang-format.py [-h] [-C CLANG_FORMAT] [-c] [-v] [-f FILE] [-d DIFF]
Clang format the cutter project
options:
-h, --help show this help message and exit
-C, --clang-format CLANG_FORMAT
path of clang-format
-c, --check enable the check mode
-v, --verbose use verbose output
-f, --file FILE formats (or checks) only the given file
-d, --diff DIFF format all modified file related to branch
.. code:: bash
usage: clang-tidy.py [-h] [-T RUN_CLANG_TIDY] [-p BUILD_PATH] [-j JOBS] [-r REGEX] [-i] [-q]
clang-tidy regex wrapper
options:
-h, --help show this help message and exit
-T, --run-clang-tidy RUN_CLANG_TIDY
Path of run-clang-tidy binary
-p, --build-path BUILD_PATH
Path to the build directory
-j, --jobs JOBS Number of parallel execution jobs
-r, --regex REGEX Regex pattern for filtering files
-i, --fix Apply fixes automatically
-q, --quiet Suppress configuration logs
Below are some of the low level coding conventions that we follow
Variables
~~~~~~~~~
Variable names start with a lowercase letter with each consecutive word starting with an uppercase letter. (**camelBack** case)
.. code:: cpp
int Height // Wrong
string name_of_widget // Wrong
int height; // Correct
string nameOfWidget // Correct
Avoid meaningless variable names
.. code:: cpp
int a, b; // Wrong
string c; // Wrong
int height, width; // Correct
string nameOfThis; // Correct
Object obj; // Also Correct
Only first letter of an acronym is uppercase
.. code:: cpp
CutterJsonWigdet cutterJSONWidget; // Wrong
CutterJsonWigdet cutterJsonWigdet; // Correct
Variable names don't use leading/trailing underscores, including prefixes like m\_
.. code:: cpp
class Example {
private:
int index_; // Wrong
int m_index; // Wrong
int index; // Correct
};
Global variables follow the same naming conventions
Anonymous Namespace
Global entities (variables, functions, structs...) private to a source file (internal linkage) are defined in an anonymous namespace
.. code:: cpp
namespace { int globalCounter = 0;
bool doSomething() {
...
return true;
}
};
Functions
Function names follow the same naming convention as `variables`_. (**camelBack** casing)
.. code:: cpp
void do_something() {} // Wrong
void DoSomething() {} // Wrong
void doSomething() {} // Correct
Unused parameters inside a function are omitted in the definition either by commenting out the parameter name or not writing the name at all.
Avoid using ``Q_UNUSED``
.. code:: cpp
// Bad
void doSomething(int one, int two) {
Q_UNUSED(one)
...
}
// Good
void doSomething(int /*one*/, int two) {
...
}
// Good
void doSomething(int, int two) {
...
}
Avoid the use of automatic name based connections. See `Connecting Qt Signals`_.
Classes
~~~~~~~~
First letter of each word is uppercased. (**CamelCase**)
.. code:: cpp
class memory_dock_widget; // Wrong
class memoryDockWidget; // Wrong
class MemoryDockWidget; // Correct
Only first letter of an acronym is uppercase
.. code:: cpp
class CutterJSONWidget // Wrong
class CutterJsonWidget // Correct
Member variables follow the same naming conventions defined in `variables`_ that means no leading/trailing underscores or m\_ prefixes
Casting
~~~~~~~
Avoid the use of C style casts, prefer C++ casts (``static_cast``, ``const_cast`` ...)
Use ``qobject_cast`` for ``QObjects``
Smart Pointers
Prefer the use of C++ smart pointers (unique_ptr, shared_ptr...)
.. code:: cpp
RegisterProfileDialog *ui; // Bad
std::unique_ptr<Ui::RegisterProfileDialog> ui; // Good
Braces
In contrast to the official guidelines of Qt, in Cutter we always use curly braces in conditional statements, even if the body of a conditional statement contains only one line.
.. code:: cpp
// Wrong
if (address.isEmpty())
return false;
// Correct
if (address.isEmpty()) {
return false;
}
// Wrong
for (int i = 0; i < 10; ++i)
qDebug("%i", i);
// Correct
for (int i = 0; i < 10; ++i) {
qDebug("%i", i);
}
Loops
~~~~~
We use the C++11 foreach loop style, which means any “foreach” loop should
look like:
.. code:: cpp
// Good - If a copy of each element is required
for (auto import : importsArray) {
doSomething(import);
}
// Good - If copy is not required
for (auto &import : importsArray) {
doSomething(import);
}
// Good - If no modification is required
for (const auto &import : importsArray) {
doSomething(import);
}
auto
~~~~
Prefer the use of ``auto`` keyword when working with the following:
.. code:: cpp
// Iterators
auto it = myMap.find(key);
for (const auto &import : importsArray) { ... }
// Lambdas
auto multiply = [](int a, int b) -> int { return a * b; };
// Casting
auto myFloat = static_cast<float>(myInt);
// Initializing using new
auto *item = new QListWidgetItem(text);
nullptr
Please do not use 0 nor Q_NULLPTR, only use nullptr.
Example:
.. code:: cpp
std::unique_ptr<QObject> obj = nullptr;
// Note that this is just an example, unique_ptr constructor initializes the internal pointer to nullptr by default
Connecting Qt Signals
Use one of the following methods for connecting signals to slots:
.. code:: cpp
// typically you will make connection in the constructor to a member of current class
connect(this->ui->button1, &QPushButton::clicked,
this, &MyObject::buttonClicked); // Good
// you can also connect directly other object slots
connect(checkbox, &QCheckBox::toggled, widget, &QWidget::setEnabled); // Good
// use lambda for passing extra arguments
connect(button1, &QPushButton::clicked, this, [this](){ foo(getBar()); }); // Good
This syntax performs compile-time type checks and allows the use of lambda
functions. Other approaches for connecting signals can silently break at runtime.
Don't use the older macro based syntax or automatic name based connections.
.. code:: cpp
// SIGNAL and SLOT macros
connect(sender, SIGNAL(clicked), this, SLOT(buttonClicked)); // BAD
// automatic name based connection
slot:
void on_actionNew_triggered(); // BAD
// 3 argument connect without receiver object
connect(sender, &SomeObject::signal, [this](){ this->foo(getBar()); }); // BAD
Includes
~~~~~~~~
Strive to include only **required** definitions inside header files.
This will avoid triggering additional unnecessary compilations.
If you only need to know that a class exists but don't need the prototype,
you can declare the class like this:
.. code:: cpp
class MyClassThatExists;
/** ... **/
private:
std::unqiue_ptr<MyClassThatExists> classInstance;
And then include the class header inside your .cpp so you can use that class.
If you need something in the source file (.cpp) that is not a class member,
then add the include in the source file.
The includes must be ordered from local to global. That is, first include
any local header file (with double quotes like `#include "common/Helpers.h"`.
Then, after an empty newline, include Qt definitions like
`#include <QShortcut>`.
Finally, include the standard C++ headers you need.
Includes must be sorted by alphabetical order.
This is automatically handled by running ``clang-format``
Docstrings
~~~~~~~~~~
Our API reference is generated using Doxygen, so when it comes to
function documentation, please use the following format:
.. code:: cpp
/**
* @brief Add new parameters to the accumulator
* @param params The parameters to add
* @return True if the parameters were added, false otherwise
*/
bool accumulate(RefreshDeferrerParams params) { ... };
Documenting every function is generally not required. Only document those functions whose purpose is not immediately understandable just by looking at the function name.
.. code:: cpp
// No need for docs
int getCount() const;
// Should provide docs
bool syncRemote();
It is preferred for classes to have documentation just above the definition, explaining their purpose.
.. code:: cpp
/**
* @brief A short description about SomeDialog
*/
class SomeDialog {
...
};
General Coding Advices
----------------------
Functions Documentation
You can find the class documentation in the API Reference <https://cutter.re/docs/api.html>__ menu item.
Updating the Git Submodules
Git submodules play a major part in Cutter. This, because Cutter is powered
by Rizin, its parent project, and it tries to stay up-to-date with its
recent version, which allows us to implement new features, and enjoy bug
fixes and performance improvements on Rizin. Often, we need to update
the Rizin submodule or the others, to push their most recent
version to Cutter.
You can view the list of all the submodules from the cutter root folder with:
.. code:: sh
git config --file .gitmodules --get-regexp path | awk '{ print $2 }'
To update all the submodules at once, run these commands from the
cutter root folder:
.. code:: sh
git submodule foreach git pull origin master
git add submodule_name_1 submodule_name_2
git commit -m "Update submodules"
More likely, you'll only need to update the *rizin* submodule.
In order to update one submodule individually, use the following code:
.. code:: sh
cd rizin
git checkout dev && git pull
cd ..
git add rizin
git commit -m "Update rizin submodule"
Useful Resources (Qt Development)
Signals & Slots <https://doc.qt.io/qt-6/signalsandslots.html>__Model/View Programming <https://doc.qt.io/qt-6/model-view-programming.html>__ - read this if you are going to work with a list or table-like widgetsQAction <https://doc.qt.io/qt-6/qaction.html#details>__