[skip ci]
7.2 KiB
Coding Style
C++11 features
We make extensive use of new features in the C++ 11 standard. Developers must be familiar with the standard to be able to understand the code. Here are some of the features that are extensively used.
- Type inference (aka
auto
keyword). - Initializer lists.
- Lambda functions and expressions.
nullptr
constant.- Strongly typed enumerations.
- Right angle bracket.
- Thread local storage.
- Threading facilities.
- Tuple types.
Comments
The comments in the Lean codebase contain Doxygen commands. Doxygen is the de facto standard tool for generating documentation from annotated C++ sources.
Namespaces
All code is in the lean
namespace. Each frontend is stored in a
separate nested namespace. For example, the SMT 2.0 frontend is stored
in the lean::smt
namespace.
Exception: some debugging functions are stored outside of the lean
namespace. These functions are called print
and are meant to be used
when debugging Lean using gdb
.
Smart pointers
We only use std::shared_ptr
template for class C
only if we expect
to create only a few objects (< 1000) of class C
. Otherwise, we
implement our own intrusive smart pointer. For example, the class
expr
is an intrusive smart pointer to expr_cell
. We may have
millions of expr
objects. We say it is intrusive because the
reference counter is stored in expr_cell
.
We use std::unique_ptr
to make sure unique resources will be freed
correctly.
Template
We organize template source code using the approach described at http://www.codeproject.com/Articles/3515/How-To-Organize-Template-Source-Code
Idioms
We use some popular C++ idioms:
Formatting
-
We use 4 spaces for indentation.
-
Class, method, and function names are lower case We use
_
for composite names. Example:type_checker
. -
Class/struct fields should start with the prefix
m_
.
Example:
class point {
int m_x;
int m_y;
public:
...
};
-
We do not use the
#ifndef-#define-#endif
idiom for header files. Instead we use#pragma once
. -
We write
type const & v
instead ofconst type & v
. -
We use
const
extensively. -
if-then-else
The following forms are acceptable:
if (cond) {
...
} else {
...
}
and
if (cond)
statement1;
else
statement2;
In exceptional cases, we also use
if (cond) statement;
and
if (cond) statement1; else stament2;
if-then-else-if-else
The following forms are acceptable:
if (cond) {
...
} else if (cond) {
...
} else {
...
}
and
if (cond)
statement1;
else if (cond)
statement2;
else
statement3;
- We frequently format code using extra spaces
For example, we write
environment const & m_env;
cache m_cache;
normalizer m_normalizer;
volatile bool m_interrupted;
instead of
environment const & m_env;
cache m_cache;
normalizer m_normalizer;
volatile bool m_interrupted;
-
We use the macro
lean_assert
for assertions. The macrolean_assert
is extensively used when writing unit tests. -
Spaces in expressions We write
a == b
instead ofa==b
. Similarly, we writex < y + 1
instead ofx<y+1
.
Google's C++ Style Guide
We are using a modified version of Google's C++ Style Guide. We also have our version of Google's style checker cpplint.py. You can run the checker over the codebase by typing:
make style
If you use Ninja, you can check by ninja style
. It is also a part of testcases and can be run by
ctest -R style_check
Disabled Features:
- Namespace should be terminated with "namespace"
- At least two spaces is best between code and comments
- Do not use
dynamic_cast<>
. If you need to cast within a class hierarchy, usestatic_cast<>
to upcast. Google doesn't support RTTI. - "public:" should be preceded by a blank line
- Missing space before
{
- Found C system header after C++ system header. Should be: environment.h, c system, c++ system, other.
- Labels should always be indented at least one space. If this is a member-initializer list in a constructor or the base class list in a class definition, the colon should be on the following line.
- You don't need a
;
after a}
- No
#ifndef
header guard found - Streams are highly discouraged.
- Extra space before
(
in function call - Else clause should never be on same line as else
- Extra space before
)
- Is this a non-const reference? If so, make const or use a pointer.
- All parameters should be named in a function
Modified Features:
-
Add
#include <list>
forlist<>
=> Check
std::list
instead oflist
because we do have our ownlean::list
type. -
Add
#include <algorithm>
for copy=> Check
std::copy
instead ofcopy
because we do have our ownlean::copy
method. -
Do not use namespace using-directives. Use using-declarations instead.
=> Allow this if filename contains "tests/"
-
Small and focused functions are preferred: foo() has xxx non-comment lines (error triggered by exceeding 500 lines).
=> Allow this if filename contains "tests/"
-
Include the directory when naming .h files
=> Allow this if the included filename is "version.h" which is generated by cmake.
Git pre-push hook
Since git 1.8.2, git introduced pre-push hook which is executed before actual push operation is performed. Using this, we can automatically run the style checker over the changed files before we push commits to repositories. This is useful because it prevents us from accidentally pushing the commits which contain style problems.
- Create
<PROJECT_ROOT>/.git/hooks/pre-push
file with the following contents:
#!/usr/bin/env bash
IFS=' '
DIR="$( cd "$( dirname "$0" )" && pwd )"
CHECKER=$DIR/../../src/cmake/Modules/cpplint.py
while read local_ref local_sha remote_ref remote_sha;
do
CHANGED_FILES=`git diff --name-only $local_sha $remote_sha | grep '\(cpp\|h\)$'`
if [ ! -z "$CHANGED_FILES" -a "$CHANGED_FILES" != " " ]; then
echo $CHANGED_FILES | xargs $CHECKER
RET=$?
if [ $RET -ne 0 ]; then
echo "There is error(s) from style-check. Please fix them before push to the repo."
exit $RET
fi
fi
done
exit 0
- Give "exec" permission to the file
chmod +x <PROJECT_ROOT>/.git/hooks/pre-push
Note that you need to change CHECKER
variable if you want to use other
checkers.