Difference between revisions of "Code Formatting Conventions"

From ScummVM :: Wiki
Jump to navigation Jump to search
m (Text replacement - "</source>" to "</syntaxhighlight>")
m (Text replacement - "<source lang=" to "<syntaxhighlight lang=")
 
Line 11: Line 11:
 
Braces in your code should look like the following example:
 
Braces in your code should look like the following example:
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
for (int i = 0; i < t; i++) {
 
for (int i = 0; i < t; i++) {
 
     [...]
 
     [...]
Line 39: Line 39:
 
'''Conventional operators surrounded by a space character'''
 
'''Conventional operators surrounded by a space character'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
a = (b + c) * d;
 
a = (b + c) * d;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 45: Line 45:
 
'''C++ reserved words separated from opening parentheses by a white space'''
 
'''C++ reserved words separated from opening parentheses by a white space'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
while (true) {
 
while (true) {
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 51: Line 51:
 
'''Commas followed by a white space'''
 
'''Commas followed by a white space'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
someFunction(a, b, c);
 
someFunction(a, b, c);
 
</syntaxhighlight>
 
</syntaxhighlight>
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
int d, e;
 
int d, e;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 60: Line 60:
 
'''Semicolons followed by a space character, if there is more on a line'''
 
'''Semicolons followed by a space character, if there is more on a line'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
for (int a = 0; b < c; d++)
 
for (int a = 0; b < c; d++)
 
</syntaxhighlight>
 
</syntaxhighlight>
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
doSomething(e); doSomething(f); // This is probably bad style anyway
 
doSomething(e); doSomething(f); // This is probably bad style anyway
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 69: Line 69:
 
'''Mandatory ''{}'' for empty ''for''/''while'' loops'''
 
'''Mandatory ''{}'' for empty ''for''/''while'' loops'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
while (i < length - 1 && array[++i] != item);  // bad
 
while (i < length - 1 && array[++i] != item);  // bad
 
while (i < length - 1 && array[++i] != item) {} // good
 
while (i < length - 1 && array[++i] != item) {} // good
Line 76: Line 76:
 
'''When declaring class inheritance and in a ? construct, colons should be surrounded by white space'''
 
'''When declaring class inheritance and in a ? construct, colons should be surrounded by white space'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
class BusWheel : public RubberInflatable {
 
class BusWheel : public RubberInflatable {
 
</syntaxhighlight>
 
</syntaxhighlight>
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
(isNight) ? colorMeDark() : colorMeBright();
 
(isNight) ? colorMeDark() : colorMeBright();
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 85: Line 85:
 
'''Indentation level is not increased after namespace clause'''
 
'''Indentation level is not increased after namespace clause'''
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
namespace Scumm {
 
namespace Scumm {
  
Line 98: Line 98:
  
 
'''Array delete operator has no whitespace before []'''
 
'''Array delete operator has no whitespace before []'''
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
delete[] foo;
 
delete[] foo;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 105: Line 105:
  
 
No whitespace between template keyword and <
 
No whitespace between template keyword and <
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
template<typename foo>
 
template<typename foo>
 
void myFunc(foo arg) {
 
void myFunc(foo arg) {
Line 115: Line 115:
  
 
Operator keyword is NOT separated from the name, except for type conversion operators where it is required.
 
Operator keyword is NOT separated from the name, except for type conversion operators where it is required.
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
struct Foo {
 
struct Foo {
 
     void operator()() {
 
     void operator()() {
Line 130: Line 130:
  
 
No whitespace after a cast; and in a pointer, we write a whitespace before the star but not after it.
 
No whitespace after a cast; and in a pointer, we write a whitespace before the star but not after it.
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
const char *ptr = (const char *)foobar;
 
const char *ptr = (const char *)foobar;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 137: Line 137:
  
 
We use the same rule for references as we do for pointers: use a whitespace before the "&" but not after it.
 
We use the same rule for references as we do for pointers: use a whitespace before the "&" but not after it.
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
int i = 0;
 
int i = 0;
 
int &ref = i;
 
int &ref = i;
Line 145: Line 145:
  
 
When it adds to readability, a vertical alignment by means of extra tabs or spaces is allowed. However, it is not advised to have the opening and closing brackets/braces to occupy a single line.
 
When it adds to readability, a vertical alignment by means of extra tabs or spaces is allowed. However, it is not advised to have the opening and closing brackets/braces to occupy a single line.
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
int foo    = 2;
 
int foo    = 2;
 
int morefoo = 3;
 
int morefoo = 3;
Line 157: Line 157:
 
== Switch/Case constructs ==
 
== Switch/Case constructs ==
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
switch (cmd) {
 
switch (cmd) {
 
case kSomeCmd:
 
case kSomeCmd:
Line 193: Line 193:
 
Camel case starting with upper case.
 
Camel case starting with upper case.
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
class MyClass { /* ... */ };
 
class MyClass { /* ... */ };
 
struct MyStruct { /* ... */ };
 
struct MyStruct { /* ... */ };
Line 203: Line 203:
 
Prefixed with '_' and in camel case (Yo! no underscore separators), starting with lowercase.
 
Prefixed with '_' and in camel case (Yo! no underscore separators), starting with lowercase.
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
char *_someVariableName;
 
char *_someVariableName;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 211: Line 211:
 
Camel case, starting with lowercase.
 
Camel case, starting with lowercase.
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
void thisIsMyFancyMethod();
 
void thisIsMyFancyMethod();
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 219: Line 219:
 
Use camel case (Yo! no underscore separators), starting with lowercase.
 
Use camel case (Yo! no underscore separators), starting with lowercase.
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
char *someVariableName;
 
char *someVariableName;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 229: Line 229:
 
In general you should avoid global variables, but if it can't be avoided, use 'g_' as prefix, camel case, and start with lowercase
 
In general you should avoid global variables, but if it can't be avoided, use 'g_' as prefix, camel case, and start with lowercase
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
int g_someGlobalVariable;
 
int g_someGlobalVariable;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 250: Line 250:
 
There are many ways to mark such comments, but developers are encouraged to use the JavaDoc style:
 
There are many ways to mark such comments, but developers are encouraged to use the JavaDoc style:
  
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
/**
 
/**
 
  * Move ("warp") the mouse cursor to the specified position in virtual
 
  * Move ("warp") the mouse cursor to the specified position in virtual
Line 264: Line 264:
  
 
If you want to add a brief explanation of a variable or function ''after'' its declaration, this is the correct syntax:
 
If you want to add a brief explanation of a variable or function ''after'' its declaration, this is the correct syntax:
<source lang="cpp">
+
<syntaxhighlight lang="cpp">
 
int16 x; ///< The horizontal part of the point
 
int16 x; ///< The horizontal part of the point
 
int16 y; ///< The vertical part of the point
 
int16 y; ///< The vertical part of the point

Latest revision as of 15:07, 25 October 2018

Use common sense

These are conventions which we try to follow when writing code for ScummVM. 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).

Hugging braces

Braces in your code should look like the following example:

for (int i = 0; i < t; i++) {
    [...]
}

if (j < k) {
    [...]
} else if (j > k) {
    [...]
} else {
    [...]
}

class Dummy {
    [...]
};

Did you see the {}'s on that?

Tab indents, with tabstop at four spaces

Says it all, really.

Whitespaces

Conventional operators surrounded by a space character

a = (b + c) * d;

C++ reserved words separated from opening parentheses by a white space

while (true) {

Commas followed by a white space

someFunction(a, b, c);
int d, e;

Semicolons followed by a space character, if there is more on a line

for (int a = 0; b < c; d++)
doSomething(e); doSomething(f);	// This is probably bad style anyway

Mandatory {} for empty for/while loops

while (i < length - 1 && array[++i] != item);   // bad
while (i < length - 1 && array[++i] != item) {} // good

When declaring class inheritance and in a ? construct, colons should be surrounded by white space

class BusWheel : public RubberInflatable {
(isNight) ? colorMeDark() : colorMeBright();

Indentation level is not increased after namespace clause

namespace Scumm {

byte Actor::kInvalidBox = 0;

void Actor::initActorClass(ScummEngine *scumm) {
    _vm = scumm;
}

} // End of namespace Scumm

Array delete operator has no whitespace before []

delete[] foo;

Template definitions

No whitespace between template keyword and <

template<typename foo>
void myFunc(foo arg) {
    // ...
}

Operator overloading

Operator keyword is NOT separated from the name, except for type conversion operators where it is required.

struct Foo {
    void operator()() {
        // ...
    }

    operator bool() {
        return true;
    }
};

Pointers and casts

No whitespace after a cast; and in a pointer, we write a whitespace before the star but not after it.

const char *ptr = (const char *)foobar;

References

We use the same rule for references as we do for pointers: use a whitespace before the "&" but not after it.

int i = 0;
int &ref = i;

Vertical alignment

When it adds to readability, a vertical alignment by means of extra tabs or spaces is allowed. However, it is not advised to have the opening and closing brackets/braces to occupy a single line.

int foo     = 2;
int morefoo = 3;

Common::Rect *r = new Common::Rect(x,
                                   y,
                                   x + w,
                                   y + h);

Switch/Case constructs

switch (cmd) {
case kSomeCmd:
    someCmd();
    // fall through
case kSomeVerySimilarCmd:
    someMoreCmd();
    break;
case kSaveCmd:
    save();
    break;
case kLoadCmd:
case kPlayCmd:
    close();
    break;
default:
    Dialog::handleCommand(sender, cmd, data);
}
  • Note comment on whether fall through is intentional. Use exactly this and not some variation both for consistency and so that the compiler will see it and suppress potential warnings.

Naming

Constants

Basically, you have two choices (this has historical reasons, and we probably should try to unify this one day):

  1. Camel case with prefix 'k':
     kSomeKludgyConstantName 
  2. All upper case, with words separated by underscores (no leading/trailing underscores):
    SOME_KLUDGY_CONSTANT_NAME

(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 const keyword.)

Type names

Camel case starting with upper case.

class MyClass { /* ... */ };
struct MyStruct { /* ... */ };
typedef int MyInt;

Class member variables

Prefixed with '_' and in camel case (Yo! no underscore separators), starting with lowercase.

char *_someVariableName;

Class methods

Camel case, starting with lowercase.

void thisIsMyFancyMethod();

Local variables

Use camel case (Yo! no underscore separators), starting with lowercase.

char *someVariableName;

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

int g_someGlobalVariable;

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

ScummVM uses the Doxygen software to generate HTML documentation for the codebase (available here).

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:

/**
 * 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;

(See here for the docs generated from this.)

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:

int16 x;	///< The horizontal part of the point
int16 y;	///< The vertical part of the point

(See here for the docs generated from this.)

For more information, visit the official documentation:

Automatically converting code to our conventions

The following settings for 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.

indent=tab=4
style=attach
pad-oper
pad-header
align-pointer=name
unpad-paren
indent-preprocessor
convert-tabs

Emacs style

Put the following in your .emacsrc file

(setq-default default-tab-width 4)
(setq-default c-basic-offset 4)
(setq-default indent-tabs-mode t)