michael@0: = mfbt style rules = michael@0: michael@0: == Line length == michael@0: michael@0: The line limit is 80 characters, except that excessively long blocks of michael@0: preprocessor directives may exceed this if it makes the code more readable (e.g. michael@0: MOZ_STATIC_ASSERT in Assertions.h.), and unbreakable text in comments (e.g. michael@0: URLs) may exceed this as well. Wrap expressions after binary operators. michael@0: michael@0: == Capitalization == michael@0: michael@0: Standalone functions, classes, structs, and template parameters are named michael@0: InterCaps-style. Member functions and fields in classes and structs are named michael@0: camelCaps-style. michael@0: michael@0: == Indentation == michael@0: michael@0: Indentation is two spaces, never tabs. michael@0: michael@0: if (x == 2) michael@0: return 17; michael@0: michael@0: == Whitespace == michael@0: michael@0: Surround binary operators with a single space on either side. michael@0: michael@0: if (x == 2) michael@0: return 17; michael@0: michael@0: When describing pointer types, the * shall be adjacent to the type name. (Same michael@0: goes for references -- & goes by the type name.) michael@0: michael@0: int michael@0: Foo(int* p) michael@0: { michael@0: typedef void* VoidPtr; michael@0: int& i = *p; michael@0: } michael@0: michael@0: A corollary: don't mix declaration types by declaring a T and a T* (or a T**, michael@0: &c.) in the same declaration. michael@0: michael@0: T* foo, bar; // BAD michael@0: michael@0: == Expressions == michael@0: michael@0: Ternary expressions (a ? b : c) should use only one line if sufficiently short. michael@0: Longer ternary expressions should use multiple lines. The condition, michael@0: consequent, and alternative should each be on separate lines (each part michael@0: overflowing to additional lines as necessary), and the ? and : should be aligned michael@0: with the start of the condition: michael@0: michael@0: size_t michael@0: BinaryTree::height() michael@0: { michael@0: return isLeaf() michael@0: ? 0 michael@0: : 1 + std::max(left()->height(), michael@0: right()->height()); michael@0: } michael@0: michael@0: == Bracing == michael@0: michael@0: Don't brace single statements. michael@0: michael@0: if (y == 7) michael@0: return 3; michael@0: for (size_t i = 0; i < 5; i++) michael@0: frob(i); michael@0: michael@0: But do brace them if the statement (or condition(s) or any additional michael@0: consequents, if the braces would be associated with an if statement) occupies michael@0: multiple lines. michael@0: michael@0: if (cond1 || michael@0: cond2) michael@0: { michael@0: action(); michael@0: } michael@0: if (cond1) { michael@0: consequent(); michael@0: } else { michael@0: alternative(arg1, michael@0: arg2); michael@0: } michael@0: if (cond1 || cond2) { michael@0: callMethod(arg1, michael@0: arg2); michael@0: } michael@0: for (size_t j = 0; michael@0: j < 17; michael@0: j++) michael@0: { michael@0: action(); michael@0: } michael@0: michael@0: Braces in control flow go at the end of the line except when associated with an michael@0: |if| or loop-head where the condition covers multiple lines michael@0: michael@0: == Classes and structs == michael@0: michael@0: Inside class and structure definitions, public/private consume one level of michael@0: indentation. michael@0: michael@0: class Baz michael@0: { michael@0: public: michael@0: Baz() { } michael@0: }; michael@0: michael@0: The absence of public/private in structs in which all members are public still michael@0: consumes a level. michael@0: michael@0: struct Foo michael@0: { michael@0: int field; michael@0: }; michael@0: michael@0: Braces delimiting a class or struct go on their own lines. michael@0: michael@0: Member initialization in constructors should be formatted as follows: michael@0: michael@0: class Fnord michael@0: { michael@0: size_t s1, s2, s3, s4, s5; michael@0: michael@0: public: michael@0: Fnord(size_t s) : s1(s), s2(s), s3(s), s4(s), s5(s) { } michael@0: Fnord() michael@0: : s1(0), /* member initialization can be compressed if desired */ michael@0: s2(0), michael@0: s3(0), michael@0: s4(0), michael@0: s5(0) michael@0: { michael@0: ... michael@0: } michael@0: }; michael@0: michael@0: Fields should go first in the class so that the basic structure is all in one michael@0: place, consistently. michael@0: michael@0: Use the inline keyword to annotate functions defined inline in a header. (If michael@0: the function is defined inline in the class, don't bother adding it michael@0: redundantly.) michael@0: michael@0: Explicitly delete (using Attributes.h's MOZ_DELETE) the copy constructor and michael@0: assignment operator from classes not intended to be copied or assigned to avoid michael@0: mistakes. michael@0: michael@0: class Funky michael@0: { michael@0: public: michael@0: Funky() { } michael@0: michael@0: private: michael@0: Funky(const Funky& other) MOZ_DELETE; michael@0: void operator=(const Funky& other) MOZ_DELETE; michael@0: }; michael@0: michael@0: Include a blank line between sections of structs and classes with different michael@0: access control. michael@0: michael@0: The "get" prefix is used when a method is fallible. If it's infallible, don't michael@0: use it. michael@0: michael@0: class String michael@0: { michael@0: public: michael@0: size_t length() const; // not getLength() michael@0: }; michael@0: michael@0: == Templates == michael@0: michael@0: Capitalize template parameter names to distinguish them from fields. michael@0: michael@0: template michael@0: class BloomFilter michael@0: { michael@0: }; michael@0: michael@0: Use single-letter names if it makes sense (T for an arbitrary type, K for key michael@0: type, V for value type, &c.). Otherwise use InterCaps-style names. michael@0: michael@0: When declaring or defining a function, template<...> goes on one line, the michael@0: return type and other specifiers go on another line, and the function name and michael@0: argument list go on a third line. michael@0: michael@0: template michael@0: inline bool michael@0: Vector::add(T t) michael@0: { michael@0: } michael@0: michael@0: == Namespaces == michael@0: michael@0: All C++ code shall be in the mozilla namespace, except that functionality only michael@0: used to implement external-facing API should be in the mozilla::detail michael@0: namespace, indicating that it should not be directly used. michael@0: michael@0: Namespace opening braces go on the same line as the namespace declaration. michael@0: Namespace closing braces shall be commented. Namespace contents are not michael@0: indented. michael@0: michael@0: namespace mozilla { michael@0: ... michael@0: } // namespace mozilla michael@0: michael@0: Don't use |using| in a header unless it's confined to a class or method. michael@0: Implementation files for out-of-line functionality may use |using|. michael@0: michael@0: Name data structures and methods which must be usable in C code with a Moz* michael@0: prefix, e.g. MozCustomStructure. If the data structure is not meant to be used michael@0: outside of the header in which it is found (i.e. it would be in mozilla::detail michael@0: but for its being required to work in C code), add a corresponding comment to michael@0: highlight this. michael@0: michael@0: == #includes == michael@0: michael@0: Headers that include mfbt headers use a fully-qualified include path, even if michael@0: full qualification is not strictly necessary. michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: michael@0: mfbt headers should be included first, alphabetically. Standard includes should michael@0: follow, separated from mfbt includes by a blank line. michael@0: michael@0: #include "mozilla/Assertions.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: #include michael@0: michael@0: If a header dependency is limited simply to the existence of a class, michael@0: forward-declare it rather than #include that header. michael@0: michael@0: namespace mozilla { michael@0: michael@0: class BloomFilter; michael@0: extern bool michael@0: Test(BloomFilter* bf); michael@0: michael@0: } // namespace mozilla michael@0: michael@0: == Preprocessor == michael@0: michael@0: Include guards should be named by determining the fully-qualified include path, michael@0: and substituting _ for / and . in it. For example, "mozilla/Assertions.h" michael@0: becomes mozilla_Assertions_h. michael@0: michael@0: Nested preprocessor directives indent the directive name (but not the #) by two michael@0: spaces. michael@0: michael@0: #ifdef __clang__ michael@0: # define FOO ... michael@0: #else michael@0: # define FOO ... michael@0: #endif michael@0: michael@0: Comments within nested preprocessor directives align with directive names at michael@0: that nesting depth. michael@0: michael@0: #if defined(__GNUC__) michael@0: /* gcc supports C++11 override syntax. */ michael@0: # define MOZ_OVERRIDE override michael@0: #else michael@0: # define MOZ_OVERRIDE /* unsupported */ michael@0: #endif michael@0: michael@0: Feature-testing macros may be defined to nothing. Macros intended to be michael@0: textually expanded should be defined to a comment indicating non-support, as michael@0: above or as appropriate to the situation. michael@0: michael@0: No particular preference is expressed between testing for a macro being defined michael@0: using defined(...) and using #ifdef. michael@0: michael@0: When defining a macro with different expansions for different compilers, the top michael@0: level of distinction should be the compiler, and the next nested level should be michael@0: the compiler version. Clang seems likely to be around for awhile, so to reduce michael@0: confusion test for it separately from gcc even when it's not strictly necessary. michael@0: michael@0: #if defined(__clang__) michael@0: #elif defined(__GNUC__) michael@0: # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) michael@0: # else michael@0: # endif michael@0: #elif defined(_MSC_VER) michael@0: #endif michael@0: michael@0: But don't distinguish clang's feature support using version checks: use the michael@0: __has_feature() and __has_extension() macros instead, because vendors may michael@0: customize clang's version numbers. michael@0: michael@0: Use a MOZ_* prefix when defining macros (e.g. MOZ_OVERRIDE, MOZ_LIKELY, and so michael@0: on) that are part of the mfbt interface. (C++ implementation files implementing michael@0: mfbt's interface but which are not directly part of that interface may ignore michael@0: this rule.) michael@0: michael@0: Prefer inline functions to macros whenever possible. michael@0: michael@0: == Comments == michael@0: michael@0: Header files shall have a short descriptive comment underneath license michael@0: boilerplate indicating what functionality the file implements, to be picked up michael@0: by MXR and displayed in directory listings. (But see bug 717196, which michael@0: currently prevents MXR from doing this if the MPL2 boilerplate is used.) michael@0: michael@0: Assertions.h: michael@0: ...license boilerplate... michael@0: michael@0: /* Implementations of runtime and static assertion macros for C and C++. */ michael@0: michael@0: Classes intended for public use shall have interface comments explaining their michael@0: functionality from the user's perspective. These comments shall include michael@0: examples of how the relevant functionality might be used. These interface michael@0: comments use /** */ doxygen/Javadoc-style comments. michael@0: michael@0: /** michael@0: * The Frobber class simplifies the process of frobbing. michael@0: */ michael@0: class Frobber michael@0: { michael@0: }; michael@0: michael@0: Comments describing implementation details (tradeoffs considered, assumptions michael@0: made, mathematical background, &c.) occur separately from interface comments so michael@0: that users need not consider them. They should go inside the class definition michael@0: or inside the appropriate method, depending on the specificity of the comment. michael@0: michael@0: Headers which are intended to be C-compatible shall use only /**/-style michael@0: comments. (Code examples nested inside documentation comments may use //-style michael@0: comments.) Headers which are C++-compatible may also use //-style comments. michael@0: michael@0: Non-interface comments that are /**/-style shall not also be doxygen-style. michael@0: michael@0: Use Python-style ** to denote exponentiation inside comments, not ^ (which can michael@0: be confused with C-style bitwise xor). If you're writing sufficiently complex michael@0: math, feel free to descend into LaTeX math mode ;-) inside implementation michael@0: comments if you need to. (But keep it out of interface comments, because most michael@0: people probably haven't seen LaTeX.) michael@0: michael@0: == Miscellaneous == michael@0: michael@0: Enclose C-compatible code in |extern "C"| blocks, and #ifdef __cplusplus the michael@0: block start/end as needed. The contents of these blocks should not be indented. michael@0: michael@0: Add new functionality to new headers unless an existing header makes sense. michael@0: Err on the side of more headers rather than fewer, as this helps to minimize michael@0: dependencies. michael@0: michael@0: Don't use bool for argument types unless the method is a "set" or "enable"-style michael@0: method where the method name and bool value together indicate the sense of its michael@0: effect. Use well-named enums in all other places, so that the semantics of the michael@0: argument are clear at a glance and do not require knowing how the method michael@0: interprets that argument. michael@0: michael@0: void michael@0: setVisible(bool visible); // true clearly means visible, false clearly not michael@0: enum Enumerability { michael@0: Enumerable, michael@0: NonEnumerable michael@0: }; michael@0: bool michael@0: DefineProperty(JSObject* obj, const char* name, Value v, Enumerability e); michael@0: michael@0: Use NULL for the null pointer constant. michael@0: michael@0: If a consequent in an if-statement ends with a return, don't specify an else. michael@0: The else would be redundant with the return, and not using it avoids excess michael@0: indentation. If you feel the if-else alternation is important as a way to michael@0: think about the choice being made, consider a ternary expression instead. michael@0: michael@0: // BAD michael@0: if (f()) michael@0: return 2; michael@0: else michael@0: return 5; michael@0: // GOOD michael@0: if (f()) michael@0: return 2; michael@0: return 5; michael@0: // GOOD michael@0: return f() ? 2 : 5