mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Correct the style of coding style
This commit is contained in:
parent
d577f06ad8
commit
ae834e3dbe
317
CODING_STYLE.md
317
CODING_STYLE.md
@ -1,35 +1,24 @@
|
|||||||
0. Formatting
|
## 0. Formatting
|
||||||
|
|
||||||
GOLDEN RULE: Follow the style of the existing code when you make changes.
|
**GOLDEN RULE**: Follow the style of the existing code when you make changes.
|
||||||
|
|
||||||
a. Use tabs for leading indentation
|
1. Use tabs for leading indentation:
|
||||||
- tab stops are every 4 characters (only relevant for line length).
|
- tab stops are every 4 characters (only relevant for line length).
|
||||||
- One indentation level -> exactly one byte (i.e. a tab character) in the source file.
|
- one indentation level -> exactly one byte (i.e. a tab character) in the source file.
|
||||||
b. Line widths:
|
2. Line widths:
|
||||||
- Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts.
|
- Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts.
|
||||||
- Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty.
|
- Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty.
|
||||||
c. Single-statement blocks should not have braces, unless required for clarity.
|
3. Single-statement blocks should not have braces, unless required for clarity.
|
||||||
d. Never place condition bodies on same line as condition.
|
4. Never place condition bodies on same line as condition.
|
||||||
e. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis.
|
5. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis.
|
||||||
f. No spaces for unary operators, `->` or `.`.
|
6. No spaces for unary operators, `->` or `.`.
|
||||||
g. No space before ':' but one after it, except in the ternary operator: one on both sides.
|
7. No space before `:` but one after it, except in the ternary operator: one on both sides.
|
||||||
h. Add spaces around all other operators.
|
8. Add spaces around all other operators.
|
||||||
i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.
|
9. Braces, when used, always have their own lines and are at same indentation level as "parent" scope.
|
||||||
j. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a
|
10. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a separator (of any kind) are formatted such that there is exactly one element per line, followed by the separator, the opening parenthesis is on the first line, followed by a line break and the closing parenthesis is on a line of its own unindented). See example below.
|
||||||
separator (of any kind) are formatted such that there is exactly one element per line, followed by
|
|
||||||
the separator, the opening parenthesis is on the first line, followed by a line break and the closing
|
|
||||||
parenthesis is on a line of its own (unindented). See example below.
|
|
||||||
|
|
||||||
(WRONG)
|
Yes:
|
||||||
if( a==b[ i ] ) { printf ("Hello\n"); }
|
```cpp
|
||||||
foo->bar(someLongVariableName,
|
|
||||||
anotherLongVariableName,
|
|
||||||
anotherLongVariableName,
|
|
||||||
anotherLongVariableName,
|
|
||||||
anotherLongVariableName);
|
|
||||||
cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl;
|
|
||||||
|
|
||||||
(RIGHT)
|
|
||||||
if (a == b[i])
|
if (a == b[i])
|
||||||
printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'.
|
printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'.
|
||||||
foo->bar(
|
foo->bar(
|
||||||
@ -44,99 +33,92 @@ cout <<
|
|||||||
"text that talks about this and that and contains the words " <<
|
"text that talks about this and that and contains the words " <<
|
||||||
"\"lorem\" and \"ipsum\"" <<
|
"\"lorem\" and \"ipsum\"" <<
|
||||||
endl;
|
endl;
|
||||||
|
```
|
||||||
|
|
||||||
|
No:
|
||||||
|
```cpp
|
||||||
|
if( a==b[ i ] ) { printf ("Hello\n"); }
|
||||||
|
foo->bar(someLongVariableName,
|
||||||
|
anotherLongVariableName,
|
||||||
|
anotherLongVariableName,
|
||||||
|
anotherLongVariableName,
|
||||||
|
anotherLongVariableName);
|
||||||
|
cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Namespaces
|
||||||
|
|
||||||
1. Namespaces;
|
1. No `using namespace` declarations in header files.
|
||||||
|
2. All symbols should be declared in a namespace except for final applications.
|
||||||
|
3. Use anonymous namespaces for helpers whose scope is a cpp file only.
|
||||||
|
4. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore.
|
||||||
|
|
||||||
a. No "using namespace" declarations in header files.
|
Yes:
|
||||||
b. All symbols should be declared in a namespace except for final applications.
|
```cpp
|
||||||
c. Use anonymous namespaces for helpers whose scope is a cpp file only.
|
#include <cassert>
|
||||||
d. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore.
|
std::tuple<float, float> meanAndSigma(std::vector<float> const& _v);
|
||||||
|
```
|
||||||
|
|
||||||
(WRONG)
|
No:
|
||||||
|
```cpp
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
tuple<float, float> meanAndSigma(vector<float> const& _v);
|
tuple<float, float> meanAndSigma(vector<float> const& _v);
|
||||||
|
```
|
||||||
|
|
||||||
(CORRECT)
|
## 2. Preprocessor
|
||||||
#include <cassert>
|
|
||||||
std::tuple<float, float> meanAndSigma(std::vector<float> const& _v);
|
|
||||||
|
|
||||||
|
1. File comment is always at top, and includes:
|
||||||
|
- Copyright
|
||||||
|
- License (e.g. see COPYING)
|
||||||
|
2. Never use `#ifdef`/`#define`/`#endif` file guards. Prefer `#pragma` once as first line below file comment.
|
||||||
|
3. Prefer static const variable to value macros.
|
||||||
|
4. Prefer inline constexpr functions to function macros.
|
||||||
|
5. Split complex macro on multiple lines with `\`.
|
||||||
|
|
||||||
|
## 3. Capitalization
|
||||||
|
|
||||||
2. Preprocessor;
|
**GOLDEN RULE**: Preprocessor: `ALL_CAPS`; C++: `camelCase`.
|
||||||
|
|
||||||
a. File comment is always at top, and includes:
|
|
||||||
- Copyright.
|
|
||||||
- License (e.g. see COPYING).
|
|
||||||
b. Never use #ifdef/#define/#endif file guards. Prefer #pragma once as first line below file comment.
|
|
||||||
c. Prefer static const variable to value macros.
|
|
||||||
d. Prefer inline constexpr functions to function macros.
|
|
||||||
e. Split complex macro on multiple lines with '\'.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3. Capitalization;
|
|
||||||
|
|
||||||
GOLDEN RULE: Preprocessor: ALL_CAPS; C++: camelCase.
|
|
||||||
|
|
||||||
a. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions.
|
|
||||||
b. The following entities' first alpha is upper case:
|
|
||||||
- Type names.
|
|
||||||
- Template parameters.
|
|
||||||
- Enum members.
|
|
||||||
- static const variables that form an external API.
|
|
||||||
c. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation.
|
|
||||||
|
|
||||||
|
1. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions.
|
||||||
|
2. The following entities' first alpha is upper case:
|
||||||
|
- Type names
|
||||||
|
- Template parameters
|
||||||
|
- Enum members
|
||||||
|
- static const variables that form an external API.
|
||||||
|
3. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation.
|
||||||
|
|
||||||
All other entities' first alpha is lower case.
|
All other entities' first alpha is lower case.
|
||||||
|
|
||||||
|
## 4. Variable prefixes
|
||||||
|
|
||||||
|
1. Leading underscore "_" to parameter names:
|
||||||
|
- Exception: "o_parameterName" when it is used exclusively for output. See 6(f).
|
||||||
|
- Exception: "io_parameterName" when it is used for both input and output. See 6(f).
|
||||||
|
2. Leading "g_" to global (non-const) variables.
|
||||||
|
3. Leading "s_" to static (non-const, non-global) variables.
|
||||||
|
|
||||||
4. Variable prefixes:
|
## 5. Assertions
|
||||||
|
|
||||||
a. Leading underscore "_" to parameter names.
|
Use `solAssert` and `solUnimplementedAssert` generously to check assumptions that span across different parts of the code base, for example before dereferencing a pointer.
|
||||||
- Exception: "o_parameterName" when it is used exclusively for output. See 6(f).
|
|
||||||
- Exception: "io_parameterName" when it is used for both input and output. See 6(f).
|
|
||||||
b. Leading "g_" to global (non-const) variables.
|
|
||||||
c. Leading "s_" to static (non-const, non-global) variables.
|
|
||||||
|
|
||||||
|
## 6. Declarations
|
||||||
|
|
||||||
|
1. {Typename} + {qualifiers} + {name}.
|
||||||
|
2. Only one per line.
|
||||||
|
3. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)).
|
||||||
|
4. Favour declarations close to use; don't habitually declare at top of scope ala C.
|
||||||
|
5. Pass non-trivial parameters as const reference, unless the data is to be copied into the function, then either pass by const reference or by value and use std::move.
|
||||||
|
6. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments.
|
||||||
|
7. Use parameters of pointer type only if ``nullptr`` is a valid argument, use references otherwise. Often, ``boost::optional`` is better suited than a raw pointer.
|
||||||
|
8. Never use a macro where adequate non-preprocessor C++ can be written.
|
||||||
|
9. Only use ``auto`` if the type is very long and rather irrelevant.
|
||||||
|
10. Do not pass bools: prefer enumerations instead.
|
||||||
|
11. Prefer enum class to straight enum.
|
||||||
|
12. Always initialize POD variables, even if their value is overwritten later.
|
||||||
|
|
||||||
5. Assertions:
|
Yes:
|
||||||
|
```cpp
|
||||||
- use `solAssert` and `solUnimplementedAssert` generously to check assumptions
|
|
||||||
that span across different parts of the code base, for example before dereferencing
|
|
||||||
a pointer.
|
|
||||||
|
|
||||||
|
|
||||||
6. Declarations:
|
|
||||||
|
|
||||||
a. {Typename} + {qualifiers} + {name}.
|
|
||||||
b. Only one per line.
|
|
||||||
c. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)).
|
|
||||||
d. Favour declarations close to use; don't habitually declare at top of scope ala C.
|
|
||||||
e. Pass non-trivial parameters as const reference, unless the data is to be copied into the function, then either pass by const reference or by value and use std::move.
|
|
||||||
f. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments.
|
|
||||||
g. Use parameters of pointer type only if ``nullptr`` is a valid argument, use references otherwise. Often, ``boost::optional`` is better suited than a raw pointer.
|
|
||||||
h. Never use a macro where adequate non-preprocessor C++ can be written.
|
|
||||||
i. Only use ``auto`` if the type is very long and rather irrelevant.
|
|
||||||
j. Do not pass bools: prefer enumerations instead.
|
|
||||||
k. Prefer enum class to straight enum.
|
|
||||||
l. Always initialize POD variables, even if their value is overwritten later.
|
|
||||||
|
|
||||||
|
|
||||||
(WRONG)
|
|
||||||
const double d = 0;
|
|
||||||
int i, j;
|
|
||||||
char *s;
|
|
||||||
float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate);
|
|
||||||
Derived* x(dynamic_cast<Derived*>(base));
|
|
||||||
for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {}
|
|
||||||
|
|
||||||
|
|
||||||
(CORRECT)
|
|
||||||
enum class Accuracy
|
enum class Accuracy
|
||||||
{
|
{
|
||||||
Approximate,
|
Approximate,
|
||||||
@ -154,78 +136,78 @@ char* s;
|
|||||||
MeanAndSigma ms meanAndSigma(std::vector<float> const& _v, Accuracy _a);
|
MeanAndSigma ms meanAndSigma(std::vector<float> const& _v, Accuracy _a);
|
||||||
Derived* x = dynamic_cast<Derived*>(base);
|
Derived* x = dynamic_cast<Derived*>(base);
|
||||||
for (auto i = x->begin(); i != x->end(); ++i) {}
|
for (auto i = x->begin(); i != x->end(); ++i) {}
|
||||||
|
```
|
||||||
|
|
||||||
|
No:
|
||||||
|
```cp
|
||||||
|
const double d = 0;
|
||||||
|
int i, j;
|
||||||
|
char *s;
|
||||||
|
float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate);
|
||||||
|
Derived* x(dynamic_cast<Derived*>(base));
|
||||||
|
for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {}
|
||||||
|
```
|
||||||
|
|
||||||
7. Structs & classes
|
## 7. Structs & classes
|
||||||
|
|
||||||
a. Structs to be used when all members public and no virtual functions.
|
1. Structs to be used when all members public and no virtual functions:
|
||||||
- In this case, members should be named naturally and not prefixed with 'm_'
|
- In this case, members should be named naturally and not prefixed with `m_`.
|
||||||
b. Classes to be used in all other circumstances.
|
2. Classes to be used in all other circumstances.
|
||||||
|
|
||||||
|
## 8. Members
|
||||||
|
|
||||||
|
1. One member per line only.
|
||||||
|
2. Private, non-static, non-const fields prefixed with `m_`.
|
||||||
|
3. Avoid public fields, except in structs.
|
||||||
|
4. Use override, final and const as much as possible.
|
||||||
|
5. No implementations with the class declaration, except:
|
||||||
|
- template or force-inline method (though prefer implementation at bottom of header file).
|
||||||
|
- one-line implementation (in which case include it in same line as declaration).
|
||||||
|
6. For a property `foo`
|
||||||
|
- Member: `m_foo`
|
||||||
|
- Getter: `foo()` [ also: for booleans, `isFoo()` ]
|
||||||
|
- Setter: `setFoo()`
|
||||||
|
|
||||||
8. Members:
|
## 9. Naming
|
||||||
|
|
||||||
a. One member per line only.
|
1. Avoid unpronouncable names.
|
||||||
b. Private, non-static, non-const fields prefixed with m_.
|
2. Names should be shortened only if they are extremely common, but shortening should be generally avoided
|
||||||
c. Avoid public fields, except in structs.
|
3. Avoid prefixes of initials (e.g. do not use `IMyInterface`, `CMyImplementation`)
|
||||||
d. Use override, final and const as much as possible.
|
4. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments:
|
||||||
e. No implementations with the class declaration, except:
|
- A dictionary and thesaurus are your friends;
|
||||||
- template or force-inline method (though prefer implementation at bottom of header file).
|
- Spell correctly;
|
||||||
- one-line implementation (in which case include it in same line as declaration).
|
- Think carefully about the class's purpose;
|
||||||
f. For a property 'foo'
|
- Imagine it as an isolated component to try to decontextualise it when considering its name;
|
||||||
- Member: m_foo;
|
- Don't be trapped into naming it (purely) in terms of its implementation.
|
||||||
- Getter: foo() [ also: for booleans, isFoo() ];
|
|
||||||
- Setter: setFoo();
|
|
||||||
|
|
||||||
|
## 10. Type definitions
|
||||||
|
|
||||||
|
1. Prefer `using` to `typedef`. e.g. `using ints = std::vector<int>;` rather than typedef `std::vector<int> ints;`
|
||||||
|
2. Generally avoid shortening a standard form that already includes all important information:
|
||||||
|
- e.g. stick to `shared_ptr<X>` rather than shortening to `ptr<X>`.
|
||||||
|
3. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently:
|
||||||
|
- e.g. `using Guard = std::lock_guard<std::mutex>;` ///< Guard is used throughout the codebase since it is clear in meaning and used commonly.
|
||||||
|
4. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
|
||||||
|
5. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time.
|
||||||
|
|
||||||
9. Naming
|
## 11. Commenting
|
||||||
|
|
||||||
a. Avoid unpronouncable names
|
1. Comments should be doxygen-compilable, using @notation rather than \notation.
|
||||||
b. Names should be shortened only if they are extremely common, but shortening should be generally avoided
|
2. Document the interface, not the implementation:
|
||||||
c. Avoid prefixes of initials (e.g. do not use IMyInterface, CMyImplementation)
|
- Documentation should be able to remain completely unchanged, even if the method is reimplemented;
|
||||||
c. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments.
|
- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports);
|
||||||
- A dictionary and thesaurus are your friends.
|
- Be careful to scrutinise documentation that extends only to intended purpose and usage;
|
||||||
- Spell correctly.
|
- Reject documentation that is simply an English transaction of the implementation.
|
||||||
- Think carefully about the class's purpose.
|
3. Avoid in-code comments. Instead, try to extract blocks of functionality into functions. This often already eliminates the need for an in-code comment.
|
||||||
- Imagine it as an isolated component to try to decontextualise it when considering its name.
|
|
||||||
- Don't be trapped into naming it (purely) in terms of its implementation.
|
|
||||||
|
|
||||||
|
## 12. Include Headers
|
||||||
|
|
||||||
|
1. Includes should go in increasing order of generality (`libsolidity` -> `libevmasm` -> `libdevcore` -> `boost` -> `STL`).
|
||||||
10. Type-definitions
|
2. The corresponding `.h` file should be the first include in the respective `.cpp` file.
|
||||||
|
3. Insert empty lines between blocks of include files.
|
||||||
a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints;
|
|
||||||
b. Generally avoid shortening a standard form that already includes all important information:
|
|
||||||
- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>.
|
|
||||||
c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently.
|
|
||||||
- e.g. using Guard = std::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it is clear in meaning and used commonly.
|
|
||||||
d. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
|
|
||||||
e. Avoid introducing aliases for types unless they are very complicated. Consider the number of items a brain can keep track of at the same time.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
11. Commenting
|
|
||||||
|
|
||||||
a. Comments should be doxygen-compilable, using @notation rather than \notation.
|
|
||||||
b. Document the interface, not the implementation.
|
|
||||||
- Documentation should be able to remain completely unchanged, even if the method is reimplemented.
|
|
||||||
- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports).
|
|
||||||
- Be careful to scrutinise documentation that extends only to intended purpose and usage.
|
|
||||||
- Reject documentation that is simply an English transaction of the implementation.
|
|
||||||
c. Avoid in-code comments. Instead, try to extract blocks of functionality into functions. This often already eliminates the need for an in-code comment.
|
|
||||||
|
|
||||||
|
|
||||||
12. Include Headers
|
|
||||||
|
|
||||||
Includes should go in increasing order of generality (libsolidity -> libevmasm -> libdevcore -> boost -> STL).
|
|
||||||
The corresponding .h file should be the first include in the respective .cpp file.
|
|
||||||
Insert empty lines between blocks of include files.
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
```cpp
|
||||||
```
|
|
||||||
#include <libsolidity/codegen/ExpressionCompiler.h>
|
#include <libsolidity/codegen/ExpressionCompiler.h>
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
#include <libsolidity/ast/AST.h>
|
||||||
@ -245,18 +227,17 @@ Example:
|
|||||||
#include <numeric>
|
#include <numeric>
|
||||||
```
|
```
|
||||||
|
|
||||||
See http://stackoverflow.com/questions/614302/c-header-order/614333#614333 for the reason: this makes it easier to find missing includes in header files.
|
See [this issue](http://stackoverflow.com/questions/614302/c-header-order/614333#614333 "C header order") for the reason: this makes it easier to find missing includes in header files.
|
||||||
|
|
||||||
|
## 13. Recommended reading
|
||||||
|
|
||||||
13. Recommended reading
|
- Herb Sutter and Bjarne Stroustrup:
|
||||||
|
- [C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)
|
||||||
|
|
||||||
Herb Sutter and Bjarne Stroustrup
|
- Herb Sutter and Andrei Alexandrescu:
|
||||||
- "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md)
|
- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices"
|
||||||
|
|
||||||
Herb Sutter and Andrei Alexandrescu
|
- Scott Meyers:
|
||||||
- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices"
|
- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)"
|
||||||
|
- "More Effective C++: 35 New Ways to Improve Your Programs and Designs"
|
||||||
Scott Meyers
|
- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14"
|
||||||
- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)"
|
|
||||||
- "More Effective C++: 35 New Ways to Improve Your Programs and Designs"
|
|
||||||
- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14"
|
|
||||||
|
Loading…
Reference in New Issue
Block a user