MuseScore coding rules

Atjaunināts pirms 3 years

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.

upload
Attachment Size
qt2-musescore.xml 1.93 KB