Skip to main content
Prism Launcher follows specific code style conventions to maintain consistency across the codebase. All contributors must adhere to these guidelines.

Automatic Formatting

All C++ files are formatted with clang-format using the configuration in .clang-format.
Always run clang-format on changed files before committing!

Running clang-format

# Format a single file
clang-format -i path/to/file.cpp

# Format all modified files in git
git diff --name-only | grep -E '\.(cpp|h|cc|hpp)$' | xargs clang-format -i

# Check formatting without modifying files
clang-format --dry-run --Werror path/to/file.cpp

clang-format Configuration

The project uses a custom clang-format configuration based on Chromium style:
BasedOnStyle: Chromium
IndentWidth: 4
AllowShortIfStatementsOnASingleLine: false
ColumnLimit: 140
AccessModifierOffset: -1
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
Cpp11BracedListStyle: false
QualifierAlignment: Left
Key formatting rules:
  • Indent width: 4 spaces
  • Column limit: 140 characters
  • Braces: Functions have braces on a new line
  • Short statements: No single-line if statements

Naming Conventions

Classes and Types

Use PascalCase for class and type names:
class MyClass { };
struct Person { };
enum class PizzaToppings { };

Member Variables

Use camelCase with m_ prefix:
class ImportantClass {
   private:
    int m_counter;
    QString m_userName;
    std::vector<int> m_dataPoints;
};

Functions

Use camelCase for all function names:
class DataProcessor {
   public:
    void processData();
    int calculateSum(int a, int b);
    bool isValid() const;

   private:
    void initializeBuffers();
};

// Global functions also use camelCase
void globalFunction();
int computeHash(const QString& data);

Global Variables and Constants

// Non-const global variables: camelCase
int globalCounter = 0;
QString applicationPath;

// Const global variables and macros: SCREAMING_SNAKE_CASE
const int MAX_BUFFER_SIZE = 4096;
constexpr double PI = 3.14159;

#define AWESOMENESS 10
#define VERSION_STRING "1.0.0"

Enum Constants

Use PascalCase for enum values:
enum class PizzaToppings {
    HamAndPineapple,
    OreoAndKetchup,
    ClassicPepperoni
};

enum class HttpStatus {
    Ok,
    NotFound,
    InternalServerError
};

Complete Example

Here’s a comprehensive example showing all naming conventions:
#define AWESOMENESS 10

constexpr double PI = 3.14159;

enum class PizzaToppings { HamAndPineapple, OreoAndKetchup };

struct Person {
    QString name;
    QDateTime dateOfBirth;

    long daysOld() const { return dateOfBirth.daysTo(QDateTime::currentDateTime()); }
};

class ImportantClass {
   public:
    void incrementCounter()
    {
        if (m_counter + 1 > MAX_COUNTER_VALUE)
            throw std::runtime_error("Counter has reached limit!");

        ++m_counter;
    }

    int counter() const { return m_counter; }

   private:
    static constexpr int MAX_COUNTER_VALUE = 100;
    int m_counter;
};

ImportantClass importantClassInstance;

Best Practices

Avoid Abbreviations

Avoid inventing acronyms or abbreviations, especially for multi-word names.
// Bad: unclear abbreviation
TexturePack tp;
int cnt;

// Good: clear, full names
TexturePack texturePack;
int counter;

Use of [[nodiscard]]

Only use [[nodiscard]] when ignoring the return value is likely to cause a bug:
// Good: Memory allocation must be handled
[[nodiscard]] void* allocateMemory(size_t size);

// Good: Error status should be checked
[[nodiscard]] bool connectToServer(const QString& host);

// Good: Function might be mistaken for having side effects
[[nodiscard]] int calculate(int a, int b);

// Bad: Plain getter doesn't need [[nodiscard]]
int getCount() const;  // Not [[nodiscard]]
A plain getter is unlikely to cause confusion. Adding [[nodiscard]] to every getter creates clutter and inconsistency.

When to Rename

If you encounter names that don’t follow these conventions:
  • Preferred: Leave them as-is to minimize review complexity and merge conflicts
  • Acceptable: Rename them if you’re already refactoring the entire class
Unnecessary renames increase the number of changes, making reviews harder and increasing the likelihood of conflicts.

Static Analysis

clang-tidy

Most naming conventions are enforced by clang-tidy. Run it to check for violations:
clang-tidy path/to/file.cpp -- -I./include -I./src
The project includes a .clang-tidy configuration that checks:
  • Naming conventions
  • Code quality issues
  • Potential bugs
  • Performance problems

Running Checks in Nix

If using Nix, the project provides a formatting check:
nix flake check
This runs:
  • clang-format - C++ formatting
  • deadnix - Dead Nix code detection
  • nixfmt - Nix file formatting
  • statix - Nix static analysis
  • markdownlint - Markdown linting

Code Organization

Header Files

Use #pragma once for header guards:
#pragma once

#include <QString>

class MyClass {
    // ...
};

Brace Style

Functions have opening braces on a new line:
void myFunction()
{
    if (condition) {
        // if/else/for/while have braces on the same line
        doSomething();
    }
}

Constructor Initialization

Initializers break before the comma:
MyClass::MyClass(int value, QString name)
    : m_value(value)
    , m_name(std::move(name))
    , m_initialized(true)
{
    // Constructor body
}

Empty Functions and Records

Don’t split empty functions or records:
// Good
class Empty { };
void emptyFunction() { }

// Bad
class Empty {
};

Qt-Specific Guidelines

Q_DISABLE_COPY

For non-copyable classes:
class NonCopyable {
    Q_DISABLE_COPY(NonCopyable)
   public:
    NonCopyable() = default;
};

Signals and Slots

class MyWidget : public QWidget {
    Q_OBJECT

   public:
    explicit MyWidget(QWidget* parent = nullptr);

   signals:
    void dataChanged();
    void errorOccurred(const QString& error);

   private slots:
    void onButtonClicked();
    void handleTimeout();

   private:
    QPushButton* m_button;
};

Qt Deprecation Warnings

The project disables Qt deprecation warnings for APIs up to Qt 6.4:
// Set in CMakeLists.txt
-DQT_WARN_DEPRECATED_UP_TO=0x060400
-DQT_DISABLE_DEPRECATED_UP_TO=0x060400

Compiler Flags

Security

The build enables security features:
# All compilers
-fstack-protector-strong
--param=ssp-buffer-size=4

# Release builds
-D_FORTIFY_SOURCE=2

# Windows
-mguard=cf  # Control Flow Guard

Optimization

# Release builds
-O2
-ffunction-sections
-fdata-sections

Pre-commit Checklist

Before committing, ensure:
1

Format your code

clang-format -i $(git diff --name-only | grep -E '\.(cpp|h)$')
2

Run clang-tidy

clang-tidy path/to/modified/file.cpp
3

Build successfully

cd build && cmake --build .
4

Run tests

cd build && ctest

Further Reading