MuseScore coding rules
Note: This document is not valid anymore for the master branch (it still is for the 3.x branch though).
For the master branch coding style see https://github.com/musescore/MuseScore/wiki/CodeGuidelines
The coding rules aim to guide MuseScore developers in writing understandable and maintainable code, whilst minimizing confusion and surprise.
As usual, rules are not set in stone. If you have a good reason for breaking one, firstly, make sure that at least some other developers agree with you, especially if they are working on the same part of the codebase.
Submitting code
To submit code to MuseScore main repository, you need to sign the Contributor License Agreement. Your contribution can be a patch, or pull request, and should obey the following rules.
File format
- All code is UTF8, only ASCII to be used in C++ code for max. portability, UTF8 can be used in "
QString
"s though. - Use UNIX linefeed.
User visible texts
See Text style guide
Coding style
For historical reasons, MuseScore uses a special indenting scheme close to the Banner style. Take a closer look of the examples above to become familiar with it - particularly, the use of braces.
If you are using QtCreator, you can download and then import qt2-musescore.xml either locally for the mscore project via Projects > Code Style > Import... or globally via Tools > Settings > C++ > Code style to automate many of the behaviors described below.
Indentation & whitespaces
- Use six (6) spaces for indentation, no tabs.
- Use blank lines to group statements together where suited.
- Always use only one blank line.
- If a multiline conditional is required, use 3 spaces from the 2nd line on.
Pointers and references
For pointers or references, always use a single space after an asterisk (*) or an ampersand (&), but never before. Avoid C-style casts when possible:
char* blockOfMemory = reinterpret_cast<char*>(malloc(data.size())); -NOT- char *blockOfMemory = (char *) malloc(data.size());
Of course, in this particular case, using new
is the better choice. Avoid C++ functional style casts too:
return static_cast<int>(i); -NOT- return int(i);
Yes, these require more typing and yes they may look ugly, but that way they do stick out, are easier searchable and the compiler can detect errors in their use better. But see also below.
Returning pointers
Use C++'s "nullptr
" rather than "0
":
return nullptr; -NOT- return 0;
Operator names and parentheses
Do not use spaces between operator names and function names. The equation marks (==
) are a part of the function name, and therefore, spaces make the declaration look like an expression:
operator==(type) -NOT- operator == (type)
Binary operators
Use a space before and after every binary operator, except no spaces around "->", and only a space after ",":
for (int i = 0; i < firstScore->excerpts().count(); i++) -NOT- for (int i=0; i<firstScore->excerpts().count(); i++)
Expressions in parentheses
Do not put a space after opening parenthesis. Do not put a space before closing parenthesis:
(expression) -NOT- ( expression )
Function names and parentheses
Do not use spaces between function names and parentheses:
void mangle() -NOT- void mangle ()
Keywords
Always use a single space after a keyword, and before a curly brace:
if (foo) { } -NOT- if(foo){ }
Braces
As a base rule, place the left curly brace on the same line as the start of the statement and indent the closing one. This is know as Banner style indentation.
if (codec) { } -NOT- if (codec) { }
Exception: Function implementations always have the left brace on a new line and indented. Class declarations don't.
static void foo(int g) { qDebug("foo: %i", g); }
class Moo { };
Use curly braces when the body of a conditional statement contains more than one line, and also if a single line statement is somewhat complex. Otherwise, omit them:
if (address.isEmpty()) return false; for (int i = 0; i < 10; ++i) qDebug("%i", i); -NOT- if (address.isEmpty()) { return false; } for (int i = 0; i < 10; ++i) { qDebug("%i", i); }
Exception 1: Use braces also if the parent statement covers several lines or if it wraps:
if (address.isEmpty() || !isValid() || !codec) { return false; }
Exception 2: Use braces also in if-then-else blocks where either the if-code or the else-code covers several lines:
if (address.isEmpty()) { --it; } else { qDebug("%s", qPrintable(address)); ++it; } -NOT- if (address.isEmpty()) --it; else { qDebug("%s", qPrintable(address)); ++it; }
if (a) { if (b) ... else ... } -NOT- if (a) if (b) ... else ...
Use curly braces when the body of a conditional statement is empty:
while (a) {} -NOT- while (a);
Parentheses
Use parentheses to group expressions:
if ((a && b) || c) -NOT- if (a && b || c)
(a + b) & c -NOT- a + b & c
Class Scoping
All class scopes should be indented 3 spaces. This includes "slots" and "signals."
class Foo { public: Foo(); private: void bar(); } -NOT- class Foo { public: Foo(); private: void bar(); }
Names
Naming conventions are similar to Qt.
Names are of "camel" type, instead of "mops_klops
" write "mopsKlops
".
User defined types are capitalized. Start the names of non-type entities with lowercase. Preprocessor defines are all uppercase.
Do not encode type information in a name.
Typical prefixes
The prefix "r" like in Staff::rstaff()
means "relative" - in this example the returned staff index is relative to the part.
Casting
Safer conversion
(Introduced in MuseScore 3)
Use safer type conversion:
Chord* chord = toChord(e); -NOT- Chord* chord = static_cast<Chord*>(e);
Static casting
When possible, static_cast
is preferred over reinterpret_cast
:
Measure* m = static_cast<Measure*>(measureBase); -NOT- Measure* m = reinterpret_cast<Measure*>(measureBase);
Type checking
(Introduced in MuseScore 3)
Shorter and easier to read:
if (e->isChord()) -NOT- if (e->type() == Element::Type::Chord)
Primitive Types
unsigned ints
Use "unsigned" for unsigned ints:
unsigned i; -NOT- unsigned int i;
signed ints
Use "int" for signed ints:
int i; -NOT- signed i;
chars
Make sure to use signed char
or unsigned char
every time it matters whether it should be able to hold negative values or values greater than 127, respectively, do NOT use just plain char
in those cases. Whether an unqualified char is signed or unsigned is implementation defined and varies between the platforms MuseScore gets build for/on.
Loops
for
Use C++11's "for
" instead of Qt's "foreach
":
for (Element* e : m->el()) { -NOT- foreach (Element* e, m->el()) {
If you happen to be fixing some code and see a "foreach
", please change that loop into a "for
".
Pathnames
Use "/"
as the path separator, not QDir::separator()
, see #273963: QDir::separator() vs. "/"
Other MuseScore 3 style changes
MuseScore 3 programming style changes may be found here:
https://github.com/musescore/MuseScore/blob/master/mscore3.txt
Qt Debugging constructs
Q_ASSERT(bool test)
should be used for errors for which musescore can still continue on. Q_ASSERT
does nothing when built in release mode, but will halt execution with a diagnostic being printed when built in debug mode.
To avoid compiler warnings due to unused parameters, use Q_UNUSED(var)
rather than commenting out the variable name in the method definition. This also allows for conditional compiles, i.e. variables that are used in some setups but not others.
附加檔案 | 大小 |
---|---|
qt2-musescore.xml | 1.93 KB |