Skip to content

CXX-3061 Move coding guidelines into a separate document #1168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 28 additions & 176 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,199 +1,51 @@
# Contributing Guidelines

When contributing code, in addition to following the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines), please follow the same
[design guidelines](https://github.com/mongodb/mongo/wiki/Server-Design-Guidelines)
and [style guidelines](https://github.com/mongodb/mongo/wiki/Style-Guidelines)
as [mongodb/mongo.](https://github.com/mongodb/mongo) Additions and exceptions are listed
below.
Follow the [MongoDB C++ Driver Coding Guidelines](https://github.com/mongodb/mongo-cxx-driver/etc/coding_guidelines.md), ensure files are formatted properly, and follow guidelines for writing PR titles and commit messages.

For anything that isn't explicitly covered here, default to the
[Google C++ Style Guide.](https://google.github.io/styleguide/cppguide.html#Scoping)
Running [clang-format](https://clang.llvm.org/docs/ClangFormat.html) with our
configuration file,
[mongo-cxx-driver/.clang-format](https://github.com/mongodb/mongo-cxx-driver/blob/master/.clang-format),
will help ensure your code conforms to these standards.
All contributions must be made via a GitHub pull request (PR).

### Commit Messages
## Commit Messages

If a pull-request addresses a JIRA ticket, for a single-commit PR, prefix
the subject line with the ticket ID. (For a multi-commit PR, we will add
the ID later when we squash or merge it.)
Prefix the PR title with the relevant JIRA ticket number when applicable. When multiple JIRA tickets are related, they may be suffixed to the title or mentioned within the commit message instead.

> CXX-883 Add commit message conventions to CONTRIBUTING.md
Examples include:

Capitalize subject lines and don't use a trailing period. Keep the subject
at most 70 characters long. Use active voice! Imagine this preamble to get
your phrasing right:

> _If applied, this commit will..._ [your subject line]

See Chris Beams'
[How to write a git commit message](http://chris.beams.io/posts/git-commit/)
for more good guidelines to follow.

### Lifecycle Methods

- default-or-argument-bearing 'user' constructors

- declaration-or-deletion-of-move-constructor
- declaration-or-deletion-of-move-assignment-operator

- declaration-or-deletion-of-copy-constructor
- declaration-or-deletion-of-copy-assignment-operator

- declaration-of-dtor

### Headers

Public headers must have a ".hpp" suffix. Private headers must have a ".hh"
suffix.

General structure:

- License
- Include Guard (`#pragma once`)
- Header Prelude
- System Headers `<vector>` (alphabetical order)
- Driver Headers `<path/to/header.hpp>` (alphabetical order)
- Open Namespace mongocxx
- `inline namespace v_noabi {`
- Code
- `} // namespace v_noabi`
- Close Namespace mongocxx
- Header Postlude

Example:

```{.cpp}
// Copyright 2009-present MongoDB, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <driver/config/prelude.hpp>

#include <vector>

#include <driver/blah.hpp>

namespace mongocxx {
inline namespace v_noabi {

// Declarations

// Inline Implementations

} // namespace v_noabi
} // namespace mongocxx

#include <driver/config/postlude.hpp>
```

### Library Root Namespace

The library root namespace declares ABI namespaces (e.g. `mongocxx::v_noabi`, `mongocxx::v1`, etc.), within which symbols are declared according to their compatibility with an ABI version.

The library root namespace also redeclares ABI-specific entities without an ABI namespace qualifier (e.g. `mongocxx::v_noabi::document::view` as `mongocxx::document::view`) to allow users to automatically opt-into the latest supported ABI version of a given entity without requiring changes to source code. The root namespace redeclarations are intended to be the default method for using library entities. A user should only include the ABI namespace in a qualifier if they require compatibility with that specific ABI version.

To avoid being affected by changes to root namespace redeclarations, interfaces declared within an ABI namespace must not be written in terms of a root namespace redeclaration:

```cpp
namespace mongocxx {
namespace v_noabi {
namespace example {

struct type {}; // The type intended to be referenced below.

// Problem: when `mongocxx::example::type` is changed from `v_noabi` to `v1`,
// this parameter type will also (incorrectly) change from `v_noabi` to `v1`.
void fn(mongocxx::example::type param);

} // namespace example
} // namespace v_noabi
} // namespace mongocxx
CXX-XXXX Resolve an issue
```

References to ABI-specific entities in ABI namespaces must always be (un)qualified such that it is not affected by changes to root namespace redeclarations:

```cpp
namespace mongocxx {
namespace v_noabi {
namespace example {

struct type {}; // The type intended to be referenced below.

// OK: always resolves to `mongocxx::v_noabi::example::type`.
void fn(type param);

// Also OK: unambiguously refers to the ABI-specific type.
void fn(mongocxx::v_noabi::example::type param);

} // namespace example
} // namespace v_noabi
} // namespace mongocxx
```
Fix several related issues (CXX-AAAA, CXX-BBBB)

### Class Declarations

Guidelines:

- Blank line at beginning and end of class declaration
- Public section up top / private at bottom
- Lifecycle methods first (see rules above)
- Private Member Ordering
- Friendships
- Private Constructors
- Private Methods
- Private Variables

Example:

```{.cpp}
class foo {

public:
foo();

foo(foo&& other) noexcept;
foo& operator=(foo&& other) noexcept;

~foo();

private:
friend baz;

class MONGOCXX_PRIVATE impl;
std::unique_ptr<impl> _impl;
* Commit A description
* Commit B description
* Commit C description
```

};
```
CXX-XXXX Implement a feature resolving several related issues

### Inlines
* CXX-AAAA Commit A description
* CXX-BBBB Commit B description
* Additional commit description
```

- Define outside of class declaration
- Specify inline keyword in declaration and definition (for clarity)
Refer to Chris Beams' guidelines for
[How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/).

### Relational Operators
## Formatting

- Prefer to use free functions
Format files with [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) using the [etc/clang_format.py](https://github.com/mongodb/mongo-cxx-driver/blob/master/etc/clang_format.py) script.

### Formatting
The script must be run in the project root directory to ensure the [.clang-format](https://github.com/mongodb/mongo-cxx-driver/blob/master/.clang-format) configuration file is used properly.

The source includes a clang format definitions file (`.clang-format`) to enforce consistent style. Run clang-format (using 3.8) from the root of the repository or use the helper script included in the source:
```bash
# Allow the script to download the correct ClangFormat release version.
python2 ./etc/clang-format.py format

```
python ./etc/clang-format.py format
# Provide a path to an existing ClangFormat binary to use instead.
MONGO_CLANG_FORMAT="path/to/clang-format" python2 ./etc/clang-format.py format
```

Note, this script will automatically download clang-format 3.8 if it cannot detect it on your system.
> [!NOTE]
> ClangFormat results may differ across release versions. When using a preinstalled ClangFormat binary, its version must be consistent with the `CLANG_FORMAT_VERSION` variable defined in the `etc/clang_format.py` script.
146 changes: 146 additions & 0 deletions etc/coding_guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# MongoDB C++ Driver Coding Guidelines

For topics and situations not explicitly documented here, refer to the [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines).

## Headers

Public headers must have a ".hpp" suffix. Private headers must have a ".hh"
suffix.

General structure:

- License
- Include Guard (`#pragma once`)
- Include Directives
- Open Namespace mongocxx
- `inline namespace v_noabi {`
- Code
- `} // namespace v_noabi`
- Close Namespace mongocxx
- Header Postlude

Example:

```{.cpp}
// Copyright 2009-present MongoDB, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <driver/config/prelude.hpp>

#include <vector>

#include <driver/blah.hpp>

namespace mongocxx {
inline namespace v_noabi {

// Declarations

// Inline Implementations

} // namespace v_noabi
} // namespace mongocxx

#include <driver/config/postlude.hpp>
```

## Library Root Namespace

The library root namespace declares ABI namespaces (e.g. `mongocxx::v_noabi`, `mongocxx::v1`, etc.), within which symbols are declared according to their compatibility with an ABI version.

The library root namespace also redeclares ABI-specific entities without an ABI namespace qualifier (e.g. `mongocxx::v_noabi::document::view` as `mongocxx::document::view`) to allow users to automatically opt-into the latest supported ABI version of a given entity without requiring changes to source code. The root namespace redeclarations are intended to be the default method for using library entities. A user should only include the ABI namespace in a qualifier if they require compatibility with that specific ABI version.

To avoid being affected by changes to root namespace redeclarations, interfaces declared within an ABI namespace must not be written in terms of a root namespace redeclaration:

```cpp
namespace mongocxx {
namespace v_noabi {
namespace example {

struct type {}; // The type intended to be referenced below.

// Problem: when `mongocxx::example::type` is changed from `v_noabi` to `v1`,
// this parameter type will also (incorrectly) change from `v_noabi` to `v1`.
void fn(mongocxx::example::type param);

} // namespace example
} // namespace v_noabi
} // namespace mongocxx
```

References to ABI-specific entities in ABI namespaces must always be (un)qualified such that it is not affected by changes to root namespace redeclarations:

```cpp
namespace mongocxx {
namespace v_noabi {
namespace example {

struct type {}; // The type intended to be referenced below.

// OK: always resolves to `mongocxx::v_noabi::example::type`.
void fn(type param);

// Also OK: unambiguously refers to the ABI-specific type.
void fn(mongocxx::v_noabi::example::type param);

} // namespace example
} // namespace v_noabi
} // namespace mongocxx
```

## Class Declarations

Guidelines:

- Blank line at beginning and end of class declaration
- Public section up top / private at bottom
- Special Member Functions
- Private Member Ordering
- Friendships
- Private Constructors
- Private Methods
- Private Variables

Example:

```{.cpp}
class foo {

public:
foo();

foo(foo&& other) noexcept;
foo& operator=(foo&& other) noexcept;

~foo();

private:
friend baz;

class MONGOCXX_PRIVATE impl;
std::unique_ptr<impl> _impl;

};
```

## Inlines

- Define outside of class declaration
- Specify inline keyword in declaration and definition (for clarity)

## Relational Operators

- Prefer to use free functions