GHA CI: only store cache for master branch
[qBittorrent.git] / CODING_GUIDELINES.md
blob4562dc84211c60c9b302d9cc8e4e9d6df1724823
1 # Coding Guidelines
3 All new code **must** follow the following coding guidelines.
5 If you make changes in a file that still uses another coding style, make sure that you follow these guidelines for your changes. \
6 For programming languages other than C++ (e.g. JavaScript) used in this repository and submodules, unless otherwise specified, coding guidelines listed here applies as much as possible.
8 **Note 1:** I will not take your head if you forget and use another style. However, most probably the request will be delayed until you fix your coding style. \
9 **Note 2:** You can use the `uncrustify` program/tool to clean up any source file. Use it with the `uncrustify.cfg` configuration file found in the root folder. \
10 **Note 3:** There is also a style for QtCreator but it doesn't cover all cases. In QtCreator `Tools->Options...->C++->Code Style->Import...` and choose the `codingStyleQtCreator.xml` file found in the root folder.
12 ## Table Of Contents
14 * [1. New lines & curly braces](#1-new-lines--curly-braces)
15   * [a. Function blocks, class/struct definitions, namespaces](#a-function-blocks-classstruct-definitions-namespaces)
16   * [b. Other code blocks](#b-other-code-blocks)
17   * [c. Blocks in switch's case labels](#c-blocks-in-switchs-case-labels)
18   * [d. If-else statements](#d-if-else-statements)
19   * [e. Single statement if blocks](#e-single-statement-if-blocks)
20   * [f. Acceptable conditions to omit braces](#f-acceptable-conditions-to-omit-braces)
21   * [g. Brace enclosed initializers](#g-brace-enclosed-initializers)
22 * [2. Indentation](#2-indentation)
23 * [3. File encoding and line endings](#3-file-encoding-and-line-endings)
24 * [4. Initialization lists](#4-initialization-lists)
25 * [5. Enums](#5-enums)
26 * [6. Names](#6-names)
27   * [a. Type names and namespaces](#a-type-names-and-namespaces)
28   * [b. Variable names](#b-variable-names)
29   * [c. Private member variable names](#c-private-member-variable-names)
30 * [7. Header inclusion order](#7-header-inclusion-order)
31 * [8. Include guard](#8-include-guard)
32 * [9. Misc](#9-misc)
33 * [10. Git commit message](#10-git-commit-message)
34 * [11. Not covered above](#11-not-covered-above)
36 ---
38 ## 1. New lines & curly braces
40 ### a. Function blocks, class/struct definitions, namespaces
42 ```c++
43 int myFunction(int a)
45     // code
48 void myFunction() {} // empty body
50 MyClass::MyClass(int *parent)
51     : m_parent {parent}
53     // initialize
56 int MyClass::myMethod(int a)
58     // code
61 class MyOtherClass
63 public:
64     // code
66 protected:
67     // code
69 private:
70     // code
73 namespace Name
75     // code
78 // Lambdas
79 [](int arg1, int arg2) -> bool { return arg1 < arg2; }
81 [this](int arg)
83     this->acc += arg;
85 ```
87 ### b. Other code blocks
89 ```c++
90 if (condition)
92     // code
95 for (int a = 0; a < b; ++b)
97     // code
100 switch (a)
102 case 1:
103     // blah
104 case 2:
105     // blah
106 default:
107     // blah
111     // code
115 ### c. Blocks in switch's case labels
117 ```c++
118 switch (var)
120 case 1:
121     {
122         // declare local variables
123         // code
124     }
125     break;
126 case 2:
127     {
128         // declare local variables
129         // code
130     }
131     break;
132 default:
133     // code
137 ### d. If-else statements
139 The `else if`/`else` must be on their own lines:
141 ```c++
142 if (condition)
144     // code
146 else if (condition)
148     // code
150 else
152     // code
156 ### e. Single statement if blocks
158 Most single statement if blocks should look like this:
160 ```c++
161 if (condition)
162     a = a + b;
165 One acceptable exception to this can be `return`, `break` or `continue` statements,
166 provided that the test condition isn't very long and its body statement occupies only one line.
167 However you can still choose to use the first rule.
169 ```c++
170 if (a > 0) return;
172 while (p)
174     // ...
175     if (!b) continue;
179 ### f. Acceptable conditions to omit braces
181 When the conditional statement in `if`/`else` has only one line and its body occupy only one line,
182 this also applies to loops statements. \
183 Notice that for a series of `if - else` branches, if one branch needs braces then all branches must add braces.
185 ```c++
186 if (a < b)  // conditional statement
187     do(a);  // body
189 if (a < b)
190     do(a);
191 else if (a > b)
192     do(b);
193 else
194     do(c);
196 if (a < b)
198     do(a);
200 else if (a > b)
202     // curly braces required here, then all branches should also add them
203     do(b);
204     do(d);
206 else
208     do(c);
212 ### g. Brace enclosed initializers
214 Unlike single-line functions, you must not insert spaces between the brackets and concluded expressions. \
215 But you must insert a space between the variable name and initializer.
217 ```c++
218 Class obj {}; // empty
219 Class obj {expr};
220 Class obj {expr1, /*...,*/ exprN};
221 QVariantMap map {{"key1", 5}, {"key2", 10}};
224 ## 2. Indentation
226 4 spaces.
228 ## 3. File encoding and line endings
230 UTF-8 and Unix-like line ending (LF). Unless some platform specific files need other encodings/line endings.
232 ## 4. Initialization lists
234 Initialization lists should be vertical. This will allow for more easily readable diffs. The initialization colon should be indented and in its own line along with first argument. The rest of the arguments should be indented too and have the comma prepended.
236 ```c++
237 myClass::myClass(int a, int b, int c, int d)
238     : m_a {a}
239     , m_b {b}
240     , m_c {c}
241     , m_d {d}
243     // code
247 ## 5. Enums
249 Enums should be vertical. This will allow for more easily readable diffs. The members should be indented.
251 ```c++
252 enum Days
254     Monday,
255     Tuesday,
256     Wednesday,
257     Thursday,
258     Friday,
259     Saturday,
260     Sunday
264 ## 6. Names
266 All names should be camelCased.
268 ### a. Type names and namespaces
270 Type names and namespaces start with Upper case letter (except POD types).
272 ```c++
273 class ClassName {};
275 struct StructName {};
277 enum EnumName {};
279 using SomeList = QList<ClassName>;
281 namespace NamespaceName
286 ### b. Variable names
288 Variable names start with lower case letter.
290 ```c++
291 int myVar;
294 ### c. Private member variable names
296 Private member variable names start with lower case letter and should have ```m_``` prefix.
298 ```c++
299 class MyClass
301     int m_myVar;
305 ## 7. Header inclusion order
307 The headers should be placed in the following group order:
309 1. Module header (in .cpp)
310 2. C++ Standard Library headers
311 3. System headers
312 4. Boost library headers
313 5. Libtorrent headers
314 6. Qt headers
315 7. qBittorrent's own headers, starting from the *base* headers.
317 The headers should be ordered alphabetically within each group. \
318 If there are conditionals for the same header group, then put them at the bottom of the respective group. \
319 If there are conditionals that contain headers from several different header groups, then put them above the "qBittorrent's own headers" group.
321 One exception is the header containing the library version (for example, QtVersionChecks), this particular header isn't constrained by the aforementioned order.
323 Example:
325 ```c++
326 // file: examplewidget.cpp
328 // Module header
329 #include "examplewidget.h"
331 // exceptions, headers containing version number
332 #include <boost/version.hpp>
333 #include <libtorrent/version.hpp>
334 #include <QtVersionChecks>
336 // C++ Standard Library headers
337 #include <cstdio>
339 #ifdef Q_OS_WIN  // conditional
340 #include <cmath>
341 #endif
343 // System headers
344 #ifdef Q_OS_WIN
345 #include <windows.h>
346 #endif
348 // Boost library headers
349 #include <boost/circular_buffer.hpp>
351 // Libtorrent headers
352 #include <libtorrent/session.hpp>
354 // Qt headers
355 #include <QString>
356 #include <QUrl>
358 #ifdef Q_OS_MACOS  // conditional
359 #include <QFont>
360 #endif
362 // conditional that contains headers from several different header groups
363 #if LIBTORRENT_VERSION_NUM >= 10100
364 #include <memory>
365 #include <QElapsedTimer>
366 #endif
368 // qBittorrent's own headers
369 #include "base/bittorrent/infohash.h"
370 #include "anothermodule.h"
371 #include "ui_examplewidget.h"
374 ## 8. Include guard
376 `#pragma once` must be used instead of a "classic include guard":
378 ```c++
379 // examplewidget.h
381 #pragma once
383 #include <QWidget>
385 class ExampleWidget : public QWidget
387     // (some code omitted)
392 ## 9. Misc
394 * Line breaks for long lines with operation:
396   ```c++
397   a += "b"
398     + "c"
399     + "d";
400   ```
402 * **auto** keyword
404   We allow the use of the **auto** keyword only where it is strictly necessary (for example, to declare a lambda object, etc.), or where it **enhances** the readability of the code. \
405   Declarations for which one can gather enough information about the object interface (type) from its name or the usage pattern (an iterator or a loop variable are good examples of clear patterns) or the right part of the expression nicely fit here.
407   When weighing whether to use an auto-typed variable please think about potential reviewers of your code, who will read it as a plain diff (on github.com, for instance). \
408   Please make sure that such reviewers can understand the code completely and without excessive effort.
410   Some valid use cases:
412   * Container iteration and casts:
414     ```c++
415     template <typename List>
416     void doSomethingWithList(const List &list)
417     {
418         foreach (const auto &item, list)
419         {
420             // we don't know item type here so we use 'auto' keyword
421             // do something with item
422         }
423     }
425     for (auto it = container.begin(), end = container.end(); it != end; ++it)
426     {
427         // we don't need to know the exact iterator type,
428         // because all iterators have the same interface
429     }
431     auto spinBox = static_cast<QSpinBox*>(sender());
432     // we know the variable type based on the right-hand expression
433     ```
435   * Notice the spaces in the following specific situations:
437     ```c++
438     // Before and after the assignment and other binary (and ternary) operators there should be a space
439     // There should not be a space between increment/decrement and its operand
440     a += 20;
441     a = (b <= MAX_B ? b : MAX_B);
442     ++a;
443     --b;
444     for (int a = 0; a < b; ++b)
445     {
446     }
447     // Range-based for loop, spaces before and after the colon
448     for (auto i : container)
449     {
450     }
451     // Derived class, spaces before and after the colon
452     class Derived : public Base
453     {
454     };
455     ```
457 * Prefer pre-increment, pre-decrement operators
459   ```c++
460   ++i, --j;  // yes
461   i++, j--;  // no
462   ```
464 * private/public/protected must not be indented
466 * Preprocessor commands must go at line start
468 * Method definitions aren't allowed in header files
470 ## 10. Git commit message
472 1. Limit the subject line to 50 characters. Subject should contain only the very essence of the changes (you should avoid extra details and internals)
473 2. Separate subject from body with a blank line
474 3. Capitalize the subject line
475 4. Do not end the subject line with a period
476 5. Use the imperative mood in the subject line (it's like you're ordering the program to do something (e.g. "Don't create temporary substrings")
477 6. Wrap the body at 72 characters
478 7. Use the body to explain what and why vs. how
479 8. If commit fixes a reported issue, mention it in the message body (e.g. `Closes #4134.`)
481 ## 11. Not covered above
483 If something isn't covered above, just follow the same style the file you are editing has. \
484 *This guide is not exhaustive and the style for a particular piece of code not specified here will be determined by project members on code review.*