|
| 1 | +0. Formatting |
| 2 | + |
| 3 | +GOLDEN RULE: Follow the style of the existing code when you make changes. |
| 4 | + |
| 5 | +a. Use tabs for leading indentation |
| 6 | +- tab stops are every 4 characters (only relevant for line length). |
| 7 | +- One indentation level -> exactly one byte (i.e. a tab character) in the source file. |
| 8 | +b. Line widths: |
| 9 | +- Lines should be at most 99 characters wide to make diff views readable and reduce merge conflicts. |
| 10 | +- Lines of comments should be formatted according to ease of viewing, but simplicity is to be preferred over beauty. |
| 11 | +c. Single-statement blocks should not have braces, unless required for clarity. |
| 12 | +d. Never place condition bodies on same line as condition. |
| 13 | +e. Space between keyword and opening parenthesis, but not following opening parenthesis or before final parenthesis. |
| 14 | +f. No spaces for unary operators, `->` or `.`. |
| 15 | +g. No space before ':' but one after it, except in the ternary operator: one on both sides. |
| 16 | +h. Add spaces around all other operators. |
| 17 | +i. Braces, when used, always have their own lines and are at same indentation level as "parent" scope. |
| 18 | +j. If lines are broken, a list of elements enclosed with parentheses (of any kind) and separated by a |
| 19 | + separator (of any kind) are formatted such that there is exactly one element per line, followed by |
| 20 | + the separator, the opening parenthesis is on the first line, followed by a line break and the closing |
| 21 | + parenthesis is on a line of its own (unindented). See example below. |
| 22 | + |
| 23 | +(WRONG) |
| 24 | +if( a==b[ i ] ) { printf ("Hello\n"); } |
| 25 | +foo->bar(someLongVariableName, |
| 26 | + anotherLongVariableName, |
| 27 | + anotherLongVariableName, |
| 28 | + anotherLongVariableName, |
| 29 | + anotherLongVariableName); |
| 30 | +cout << "some very long string that contains completely irrelevant text that talks about this and that and contains the words \"lorem\" and \"ipsum\"" << endl; |
| 31 | + |
| 32 | +(RIGHT) |
| 33 | +if (a == b[i]) |
| 34 | + printf("Hello\n"); // NOTE spaces used instead of tab here for clarity - first byte should be '\t'. |
| 35 | +foo->bar( |
| 36 | + someLongVariableName, |
| 37 | + anotherLongVariableName, |
| 38 | + anotherLongVariableName, |
| 39 | + anotherLongVariableName, |
| 40 | + anotherLongVariableName |
| 41 | +); |
| 42 | +cout << |
| 43 | + "some very long string that contains completely irrelevant " << |
| 44 | + "text that talks about this and that and contains the words " << |
| 45 | + "\"lorem\" and \"ipsum\"" << |
| 46 | + endl; |
| 47 | + |
| 48 | + |
| 49 | + |
| 50 | +1. Namespaces; |
| 51 | + |
| 52 | +a. No "using namespace" declarations in header files. |
| 53 | +b. All symbols should be declared in a namespace except for final applications. |
| 54 | +c. Use anonymous namespaces for helpers whose scope is a cpp file only. |
| 55 | +d. Preprocessor symbols should be prefixed with the namespace in all-caps and an underscore. |
| 56 | + |
| 57 | +(WRONG) |
| 58 | +#include <cassert> |
| 59 | +using namespace std; |
| 60 | +tuple<float, float> meanAndSigma(vector<float> const& _v); |
| 61 | + |
| 62 | +(CORRECT) |
| 63 | +#include <cassert> |
| 64 | +std::tuple<float, float> meanAndSigma(std::vector<float> const& _v); |
| 65 | + |
| 66 | + |
| 67 | + |
| 68 | +2. Preprocessor; |
| 69 | + |
| 70 | +a. File comment is always at top, and includes: |
| 71 | +- Copyright. |
| 72 | +- License (e.g. see COPYING). |
| 73 | +b. Never use #ifdef/#define/#endif file guards. Prefer #pragma once as first line below file comment. |
| 74 | +c. Prefer static const variable to value macros. |
| 75 | +d. Prefer inline constexpr functions to function macros. |
| 76 | +e. Split complex macro on multiple lines with '\'. |
| 77 | + |
| 78 | + |
| 79 | + |
| 80 | +3. Capitalization; |
| 81 | + |
| 82 | +GOLDEN RULE: Preprocessor: ALL_CAPS; C++: camelCase. |
| 83 | + |
| 84 | +a. Use camelCase for splitting words in names, except where obviously extending STL/boost functionality in which case follow those naming conventions. |
| 85 | +b. The following entities' first alpha is upper case: |
| 86 | +- Type names. |
| 87 | +- Template parameters. |
| 88 | +- Enum members. |
| 89 | +- static const variables that form an external API. |
| 90 | +c. All preprocessor symbols (macros, macro arguments) in full uppercase with underscore word separation. |
| 91 | + |
| 92 | + |
| 93 | +All other entities' first alpha is lower case. |
| 94 | + |
| 95 | + |
| 96 | + |
| 97 | +4. Variable prefixes: |
| 98 | + |
| 99 | +a. Leading underscore "_" to parameter names. |
| 100 | +- Exception: "o_parameterName" when it is used exclusively for output. See 6(f). |
| 101 | +- Exception: "io_parameterName" when it is used for both input and output. See 6(f). |
| 102 | +b. Leading "g_" to global (non-const) variables. |
| 103 | +c. Leading "s_" to static (non-const, non-global) variables. |
| 104 | + |
| 105 | + |
| 106 | + |
| 107 | +5. Assertions: |
| 108 | + |
| 109 | +- use `solAssert` and `solUnimplementedAssert` generously to check assumptions |
| 110 | + that span across different parts of the code base, for example before dereferencing |
| 111 | + a pointer. |
| 112 | + |
| 113 | + |
| 114 | +6. Declarations: |
| 115 | + |
| 116 | +a. {Typename} + {qualifiers} + {name}. |
| 117 | +b. Only one per line. |
| 118 | +c. Associate */& with type, not variable (at ends with parser, but more readable, and safe if in conjunction with (b)). |
| 119 | +d. Favour declarations close to use; don't habitually declare at top of scope ala C. |
| 120 | +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. |
| 121 | +f. If a function returns multiple values, use std::tuple (std::pair acceptable) or better introduce a struct type. Do not use */& arguments. |
| 122 | +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. |
| 123 | +h. Never use a macro where adequate non-preprocessor C++ can be written. |
| 124 | +i. Only use ``auto`` if the type is very long and rather irrelevant. |
| 125 | +j. Do not pass bools: prefer enumerations instead. |
| 126 | +k. Prefer enum class to straight enum. |
| 127 | +l. Always initialize POD variables, even if their value is overwritten later. |
| 128 | + |
| 129 | + |
| 130 | +(WRONG) |
| 131 | +const double d = 0; |
| 132 | +int i, j; |
| 133 | +char *s; |
| 134 | +float meanAndSigma(std::vector<float> _v, float* _sigma, bool _approximate); |
| 135 | +Derived* x(dynamic_cast<Derived*>(base)); |
| 136 | +for (map<ComplexTypeOne, ComplexTypeTwo>::iterator i = l.begin(); i != l.end(); ++l) {} |
| 137 | + |
| 138 | + |
| 139 | +(CORRECT) |
| 140 | +enum class Accuracy |
| 141 | +{ |
| 142 | + Approximate, |
| 143 | + Exact |
| 144 | +}; |
| 145 | +struct MeanSigma |
| 146 | +{ |
| 147 | + float mean; |
| 148 | + float standardDeviation; |
| 149 | +}; |
| 150 | +double const d = 0; |
| 151 | +int i; |
| 152 | +int j; |
| 153 | +char* s; |
| 154 | +MeanAndSigma ms meanAndSigma(std::vector<float> const& _v, Accuracy _a); |
| 155 | +Derived* x = dynamic_cast<Derived*>(base); |
| 156 | +for (auto i = x->begin(); i != x->end(); ++i) {} |
| 157 | + |
| 158 | + |
| 159 | +7. Structs & classes |
| 160 | + |
| 161 | +a. Structs to be used when all members public and no virtual functions. |
| 162 | +- In this case, members should be named naturally and not prefixed with 'm_' |
| 163 | +b. Classes to be used in all other circumstances. |
| 164 | + |
| 165 | + |
| 166 | + |
| 167 | +8. Members: |
| 168 | + |
| 169 | +a. One member per line only. |
| 170 | +b. Private, non-static, non-const fields prefixed with m_. |
| 171 | +c. Avoid public fields, except in structs. |
| 172 | +d. Use override, final and const as much as possible. |
| 173 | +e. No implementations with the class declaration, except: |
| 174 | +- template or force-inline method (though prefer implementation at bottom of header file). |
| 175 | +- one-line implementation (in which case include it in same line as declaration). |
| 176 | +f. For a property 'foo' |
| 177 | +- Member: m_foo; |
| 178 | +- Getter: foo() [ also: for booleans, isFoo() ]; |
| 179 | +- Setter: setFoo(); |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | +9. Naming |
| 184 | + |
| 185 | +a. Avoid unpronouncable names |
| 186 | +b. Names should be shortened only if they are extremely common, but shortening should be generally avoided |
| 187 | +c. Avoid prefixes of initials (e.g. do not use IMyInterface, CMyImplementation) |
| 188 | +c. Find short, memorable & (at least semi-) descriptive names for commonly used classes or name-fragments. |
| 189 | +- A dictionary and thesaurus are your friends. |
| 190 | +- Spell correctly. |
| 191 | +- Think carefully about the class's purpose. |
| 192 | +- Imagine it as an isolated component to try to decontextualise it when considering its name. |
| 193 | +- Don't be trapped into naming it (purely) in terms of its implementation. |
| 194 | + |
| 195 | + |
| 196 | + |
| 197 | +10. Type-definitions |
| 198 | + |
| 199 | +a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than typedef std::vector<int> ints; |
| 200 | +b. Generally avoid shortening a standard form that already includes all important information: |
| 201 | +- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>. |
| 202 | +c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently. |
| 203 | +- e.g. using Guard = std::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it is clear in meaning and used commonly. |
| 204 | +d. In general expressions should be roughly as important/semantically meaningful as the space they occupy. |
| 205 | +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. |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | +11. Commenting |
| 210 | + |
| 211 | +a. Comments should be doxygen-compilable, using @notation rather than \notation. |
| 212 | +b. Document the interface, not the implementation. |
| 213 | +- Documentation should be able to remain completely unchanged, even if the method is reimplemented. |
| 214 | +- Comment in terms of the method properties and intended alteration to class state (or what aspects of the state it reports). |
| 215 | +- Be careful to scrutinise documentation that extends only to intended purpose and usage. |
| 216 | +- Reject documentation that is simply an English transaction of the implementation. |
| 217 | +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. |
| 218 | + |
| 219 | + |
| 220 | +12. Include Headers |
| 221 | + |
| 222 | +Includes should go in increasing order of generality (libsolidity -> libevmasm -> libdevcore -> boost -> STL). |
| 223 | +The corresponding .h file should be the first include in the respective .cpp file. |
| 224 | +Insert empty lines between blocks of include files. |
| 225 | + |
| 226 | +Example: |
| 227 | + |
| 228 | +``` |
| 229 | +#include <libsolidity/codegen/ExpressionCompiler.h> |
| 230 | +
|
| 231 | +#include <libsolidity/ast/AST.h> |
| 232 | +#include <libsolidity/codegen/CompilerContext.h> |
| 233 | +#include <libsolidity/codegen/CompilerUtils.h> |
| 234 | +#include <libsolidity/codegen/LValue.h> |
| 235 | +
|
| 236 | +#include <libevmasm/GasMeter.h> |
| 237 | +
|
| 238 | +#include <libdevcore/Common.h> |
| 239 | +#include <libdevcore/SHA3.h> |
| 240 | +
|
| 241 | +#include <boost/range/adaptor/reversed.hpp> |
| 242 | +#include <boost/algorithm/string/replace.hpp> |
| 243 | +
|
| 244 | +#include <utility> |
| 245 | +#include <numeric> |
| 246 | +``` |
| 247 | + |
| 248 | +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. |
| 249 | + |
| 250 | + |
| 251 | +13. Recommended reading |
| 252 | + |
| 253 | +Herb Sutter and Bjarne Stroustrup |
| 254 | +- "C++ Core Guidelines" (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md) |
| 255 | + |
| 256 | +Herb Sutter and Andrei Alexandrescu |
| 257 | +- "C++ Coding Standards: 101 Rules, Guidelines, and Best Practices" |
| 258 | + |
| 259 | +Scott Meyers |
| 260 | +- "Effective C++: 55 Specific Ways to Improve Your Programs and Designs (3rd Edition)" |
| 261 | +- "More Effective C++: 35 New Ways to Improve Your Programs and Designs" |
| 262 | +- "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" |
0 commit comments