-
Notifications
You must be signed in to change notification settings - Fork 1
/
Code_Formatting_Conventions.mw
348 lines (251 loc) · 10.7 KB
/
Code_Formatting_Conventions.mw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
'''Note:''' These are mostly the [http://wiki.scummvm.org/index.php/Code_Formatting_Conventions ScummVM code formatting conventions], with some minor changes.
== Use common sense ==
These are conventions which we try to follow when writing code for xoreos. Sticking to a common set of formatting / indention rules makes it easier to read through our source base (which now exceed half a million lines of code by far, making this quite important). If you want to submit patches, please try to adhere to these rules.
We don't always follow these rules slavishly, in certain cases it is OK (and in fact might be favorable) to stray from them. Applying common sense, as usual, is a good idea.
In the following examples tabs are replaced by spaces for visual consistency with the Code Formatting Conventions. But in actual code, use tabs for indentations (our tabs are assumed to be 4 spaces wide).
== C++ Standard ==
Among the three main repositories, xoreos, xoreos-tools and Phaethon, we're following three different versions of the C++ standard.
* xoreos itself follows the oldest standard for now, C++03
* xoreos-tools follows the C++11 standard
* Phaethon follows the C++14 standard, due to the reliance on the relaxed constexpr rules in [https://woboq.com/blog/verdigris-qt-without-moc.html Verdigris]
With xoreos-tools, we're currently in a C++11 trial period. If everything goes well, we're opening xoreos for C++11 as well.
== Hugging braces ==
Braces in your code should look like the following example:
<syntaxhighlight lang="cpp">
for (int i = 0; i < t; i++) {
[...]
}
if (j < k) {
[...]
} else if (j > k) {
[...]
} else {
[...]
}
class Dummy {
[...]
};
</syntaxhighlight>
Did you see the {}'s on that?
== Tabs for indenting, spaces for alignment ==
Says it all, really.
== Whitespaces ==
'''Conventional operators surrounded by a space character'''
<syntaxhighlight lang="cpp">
a = (b + c) * d;
</syntaxhighlight>
'''C++ reserved words separated from opening parentheses by a white space'''
<syntaxhighlight lang="cpp">
while (true) {
</syntaxhighlight>
'''Commas followed by a white space'''
<syntaxhighlight lang="cpp">
someFunction(a, b, c);
</syntaxhighlight>
<syntaxhighlight lang="cpp">
int d, e;
</syntaxhighlight>
'''Semicolons followed by a space character, if there is more on a line'''
<syntaxhighlight lang="cpp">
for (int a = 0; b < c; d++)
</syntaxhighlight>
<syntaxhighlight lang="cpp">
doSomething(e); doSomething(f); // This is probably bad style anyway
</syntaxhighlight>
'''Semicolons preceded by a space character, if it ends an empty loop body'''
It should also contain a comment to make it clear that the loop is intentionally empty.
<syntaxhighlight lang="cpp">
while (i < length - 1 && array[++i] != item) ; // Look for index of item with an empty loop
</syntaxhighlight>
The following syntax is also acceptable:
<syntaxhighlight lang="cpp">
while (i < length - 1 && array[++i] != item)
; //this loop is intentionally empty
</syntaxhighlight>
'''When declaring class inheritance and in a ? construct, colons should be surrounded by white space'''
<syntaxhighlight lang="cpp">
class BusWheel : public RubberInflatable {
</syntaxhighlight>
<syntaxhighlight lang="cpp">
(isNight) ? colorMeDark() : colorMeBright();
</syntaxhighlight>
'''Indentation level is not increased after namespace clause'''
<syntaxhighlight lang="cpp">
namespace Scumm {
byte Actor::kInvalidBox = 0;
void Actor::initActorClass(ScummEngine *scumm) {
_vm = scumm;
}
} // End of namespace Scumm
</syntaxhighlight>
'''However, namespaces used solely for forward-declarations should indent'''
<syntaxhighlight lang="cpp">
namespace Aurora {
namespace NWScript {
class Object;
}
}
</syntaxhighlight>
'''Array delete operator has no whitespace before []'''
<syntaxhighlight lang="cpp">
delete[] foo;
</syntaxhighlight>
'''Template definitions'''
No whitespace between template keyword and <
<syntaxhighlight lang="cpp">
template<typename foo>
void myFunc(foo arg) {
// ...
}
</syntaxhighlight>
'''Operator overloading'''
Operator keyword is NOT separated from the name, except for type conversion operators where it is required.
<syntaxhighlight lang="cpp">
struct Foo {
void operator()() {
// ...
}
operator bool() {
return true;
}
};
</syntaxhighlight>
'''Pointers and casts'''
One whitespace after a cast.
<syntaxhighlight lang="cpp">
const char *ptr = (const char *) foobar;
</syntaxhighlight>
'''References'''
We use the same rule for references as we do for pointers: use a whitespace before the "&" but not after it.
<syntaxhighlight lang="cpp">
int i = 0;
int &ref = i;
</syntaxhighlight>
'''Trailing whitespace'''
No trailing whitespace, at all. This means that lines should never end with spaces or tabs. Remove them. Empty lines should be completely empty; not even indenting tabs should be there.
== Include order ==
Include directives should be grouped by subsystem, roughly ordered by specificity, from general to specific.
The group order is as follows:
* C++ versions of standard C headers
* Standard C++ headers
* Standard C headers
* Library includes
* src/common
* src/aurora
* src/graphics
* src/sound
* src/video
* src/events
* src/engines
Each group is separated by an empty line. The includes within each group are again ordered roughly by specificity, with includes used by other includes first. But in a .cpp file implementing an interface specified in a .h file, the .h file sits ontop of its group.
For example, these could be the include directives in src/engines/nwn/game.cpp:
<syntaxhighlight lang="cpp">
#include <cassert>
#include <list>
#include <map>
#include "src/common/util.h"
#include "src/common/ustring.h"
#include "src/common/filelist.h"
#include "src/aurora/types.h"
#include "src/aurora/talkman.h"
#include "src/engines/aurora/util.h"
#include "src/engines/nwn/game.h"
#include "src/engines/nwn/util.h"
#include "src/engines/nwn/nwn.h"
</syntaxhighlight>
== Switch/Case constructs ==
<syntaxhighlight lang="cpp">
switch (cmd) {
case kSomeCmd:
someCmd();
// Fall Through intended
case kSomeVerySimilarCmd:
someMoreCmd();
break;
case kSaveCmd:
save();
break;
case kLoadCmd:
case kPlayCmd:
close();
break;
default:
Dialog::handleCommand(sender, cmd, data);
}
</syntaxhighlight>
* Note comment on whether fall through is intentional.
== Naming ==
'''Constants'''
Basically, you have two choices (this has historical reasons, and we probably should try to unify this one day):
# Camel case with prefix 'k': <pre> kSomeKludgyConstantName </pre >
# All upper case, with words separated by underscores (no leading/trailing underscores): <pre>SOME_KLUDGY_CONSTANT_NAME</pre>
(As a side remark, we recommend avoiding #define for creating constants, because these can lead to weird and difficult to track down conflicts. Instead use enums or the <code>const</code> keyword.)
'''Type names'''
Camel case starting with upper case.
<syntaxhighlight lang="cpp">
class MyClass { /* ... */ };
struct MyStruct { /* ... */ };
typedef int MyInt;
</syntaxhighlight>
'''Class member variables'''
Prefixed with '_' and in camel case (Yo! no underscore separators), starting with lowercase.
<syntaxhighlight lang="cpp">
char *_someVariableName;
</syntaxhighlight>
'''Class methods'''
Camel case, starting with lowercase.
<syntaxhighlight lang="cpp">
void thisIsMyFancyMethod();
</syntaxhighlight>
'''Local variables'''
Use camel case (Yo! no underscore separators), starting with lowercase.
<syntaxhighlight lang="cpp">
char *someVariableName;
</syntaxhighlight>
Note that for POD structures it is fine to use this rule too.
'''Global variables'''
In general you should avoid global variables, but if it can't be avoided, use 'g_' as prefix, camel case, and start with lowercase
<syntaxhighlight lang="cpp">
int g_someGlobalVariable;
</syntaxhighlight>
== Special comments ==
=== Special Keywords ===
The following goes slightly beyond code formatting: We use certain keywords (together with an explanatory text) to mark certain sections of our code. In particular:
* '''FIXME''' marks code that contains hacks or bad temporary workarounds, things that really should be revised at a later point.
* '''TODO''' marks incomplete code, or things that could be done better but are left for the future.
* '''WORKAROUND''' marks code that works around bugs in the original game, like script bugs. Sometimes these bugs worked in the original due to bugs in the original engine, sometimes the bug was visible in the original, too. It's important that you explain here what exactly you work around, and if applicable, refer to relevant tracker items!
=== Doxygen documentation comments ===
xoreos uses the [http://www.doxygen.org/ Doxygen] software to generate HTML documentation for the codebase.
Doxygen supports ''documentation blocks''. These are specially-formatted comments that doxygen prints out in the generated documentation. They are similar in purpose to Java's JavaDoc or Python's docstrings.
There are many ways to mark such comments, but developers are encouraged to use the JavaDoc style:
<syntaxhighlight lang="cpp">
/** Move ("warp") the mouse cursor to the specified position in virtual
* screen coordinates.
*
* @param x the new x position of the mouse.
* @param y the new y position of the mouse.
*/
virtual void warpMouse(int x, int y) = 0;
</syntaxhighlight>
As shown in the example, documentation blocks also support several special commands such as '''param'''. Those are prefixed with either '''@''' or '''\''', but developers should always use '''@'''.
If you want to add a brief explanation of a variable or function ''after'' its declaration, this is the correct syntax:
<syntaxhighlight lang="cpp">
int16 x; ///< The horizontal part of the point.
int16 y; ///< The vertical part of the point.
</syntaxhighlight>
For more information, visit the official documentation:
* [http://www.stack.nl/~dimitri/doxygen/docblocks.html Documentation blocks].
* [http://www.stack.nl/~dimitri/doxygen/commands.html List of available commands].
== Automatically converting code to our conventions ==
The following settings for [http://astyle.sourceforge.net/ Artistic Style] (also known as astyle) approximate our code formatting conventions and can be used to quickly convert a big bunch of source files to our conventions. Note that you may still have to manually clean up some stuff afterwards.
<pre>
indent=tab=4
brackets=attach
pad-oper
pad-header
align-pointer=name
unpad-paren
indent-preprocessor
convert-tabs
</pre>
Alternatively, [https://github.com/xoreos/xoreos/blob/master/.uncrustifyrc this config file] for [http://uncrustify.sourceforge.net/ uncrustify] should also work as a starting point for our conventions. Again, you may still clean things up manually.