For Developers‎ > ‎

Coding Style

Primary style guides and links

Chromium follows:

See also:

Try to follow any per-file conventions you notice when modifying existing code.

Specific languages

C++11

Google style has adopted most C++11 features, but Chromium has a more restricted set. The status of C++11 features in Chromium is tracked in the separate C++11 use in Chromium page.

C

C code, such as firmware and other specific codebases in Chromium OS, should follow the Linux kernel Documentation/CodingStyle. Changes to existing C source should maintain consistency with that project's style.

IDL

For IDL files, see Web IDL in Blink: Style.

Jinja

Jinja templates should follow the Jinja Style Guide.

Python

Python code should follow PEP-8, except:

  • Use two-space indentation instead of four-space indentation.
  • Use CamelCase() method and function names instead of unix_hacker_style() names.

(The rationale for these is mostly legacy: the code was originally written following Google's internal style guideline, the cost of updating all of the code to PEP-8 compliance was not small, and consistency was seen to be a greater virtue than compliance.)

depot_tools contains a local copy of pylint, appropriately configured.

Note that asserts are of limited use, and should not be used for validating input – throw an exception instead. Asserts can be used for validating program logic, especially use of interfaces or invariants (e.g., asserting that a function is only called with dictionaries that contain a certain key). See Using Assertions Effectively.

See also the Chromium OS Python Style Guidelines.

Web languages (JavaScript, HTML, CSS)

When working on Web-based UI features, consult the Web Development Style Guide for the Chromium conventions used in JS/CSS/HTML files.

Internal uses of web languages, notably "layout" tests, should preferably follow these style guides, but it is not enforced.

Naming

  • "Chromium" is the name of the project, not the product, and should never appear in code, variable names, API names etc. Use "Chrome" instead.
  • Though the Google C++ Style Guide now says to use kConstantNaming for enums, Chromium was written using MACRO_STYLE naming. In enums that are actually enumerations (i.e. have multiple values), continue to use this style for consistency. Use kConstantNaming when using the "enum hack" to define a single constant, as you would for a const int or the like.
  • Functions used only for testing should be restricted to test-only scenarios either by #ifdefing them appropriately (e.g. #if defined(UNIT_TEST)) or by naming them with a ForTesting suffix. The latter will be checked at presubmit time to ensure they're only called by test files.

Code formatting

  • Put * and & by the type rather than the variable name.
  • Always linebreak after a conditional, even if the body is only a return or other simple action.
  • Wrap after binary operators, not before. Exception: when you have logging statements longer than 80 characters, subsequent lines should start with the << operator and should be aligned based on the first << from the original line:
    VLOG(1) << "I have a long log message here, with variables like "
            << var1 << " and var2: " << var2;
  • You may wrap before or after the ? and : in ternary operators. If wrapping before, align the ? and : vertically:
    int x = foo ? a
                : b;
    
    int x = foo
        ? a
        : b;
    
    int x = foo
        ? a : b;
  • If wrapping after, wrap after the ? before wrapping after the ::
    int x = foo ?
        a : b;
    
    int x = foo ?
        a :
        b;
    
    int x = foo ? a :
        b;
  • When you derive from a base class, group any overriding functions in your header file in one labeled section. Use the override specifier on all these functions.
  • For function declarations and definitions, put each argument on a separate line unless the whole declaration fits on one line:
    void OK1(TypeA first_argument, TypeB second_argument, TypeC third_argument);
    
    void OK2(TypeA first_argument,
             TypeB second_argument,
             TypeC third_argument);
    
    void OK3ReallyLongFunctionName(
        ReallyLongType really_long_arg,
        ReallyLongType really_long_arg2);
    
    void Bad(TypeA first_argument, TypeB second_argument,
             TypeC third_argument);
    For function calls, it's OK to collapse args onto fewer lines. Just make sure in either case that all lines of args begin at the same horizontal position:
    OK1(first_argument, second_argument,
        third_argument, fourth_argument);
    
    OK2ReallyLongFunctionName(
        first_argument, second_argument,
        third_argument, fourth_argument);
    
    void Bad(first_argument,
        second_argument);
  • Prefer (foo == 0) to (0 == foo).
  • Function declaration order should match function definition order.
  • Prefer putting delegate classes in their own header files. Implementors of the delegate interface will often be included elsewhere, which will often cause more coupling with the header of the main class.
  • Don't use else after return:
    if (foo)
      return 1;
    else
      return 2;
    
    if (foo)
      return 1;
    return 2;
    
    return foo ? 1 : 2;

Unnamed namespaces

Items local to a .cc file should be wrapped in an unnamed namespace. While some such items are already file-scope by default in C++, not all are; also, shared objects on Linux builds export all symbols, so unnamed namespaces (which restrict these symbols to the compilation unit) improve function call cost and reduce the size of entry point tables.

Exporting symbols

When building shared libraries and DLLs, we need to indicate which functions and classes should be visible outside of the library, and which should only be visible inside the library.

  • Symbols can be exported by annotating with a <COMPONENT>_EXPORT macro name (where <COMPONENT> is the name of the component being built, e.g. BASE, NET, CONTENT, etc.). Class annotations should precede the class name:
    class FOO_EXPORT Foo {
      void Bar();
      void Baz();
      // ...
    };
    Function annotations should precede the return type:
    class FooSingleton {
      FOO_EXPORT Foo& GetFoo();
      FOO_EXPORT Foo& SetFooForTesting(Foo& foo);
      void SetFoo(Foo& foo);
    };
    These examples result in Foo::Bar(), Foo::Baz(), FooSingleton::GetFoo(), and FooSingleton::SetFooForTesting() all being available outside of the DLL, but not FooSingleton::SetFoo().
  • Whether something is exported is distinct from whether it is public or private, or even whether it would normally be considered part of the external API. For example, if part of the external API is an inlined function that calls a private function, that private function must be exported as well.

Multiple inheritance

Multiple inheritance and virtual inheritance are permitted in Chromium code, but discouraged (beyond the "interface" style of inheritance allowed by the Google style guide, for which we do not require classes to have the "Interface" suffix). Consider whether composition could solve the problem instead.

Inline functions

Simple accessors should generally be the only inline functions. These should be named unix_hacker_style(). Virtual functions should never be declared this way. For more detail, consult the C++ Dos and Don'ts section on inlining.

Logging

  • Remove most logging calls before checking in. Unless you're adding temporary logging to track down a specific bug, and you have a plan for how to collect the logged data from user machines, you should generally not add logging statements.
  • For the rare case when logging needs to stay in the codebase for a while, prefer DVLOG(1) to other logging methods. This avoids bloating the release executable and in debug can be selectively enabled at runtime by command-line arguments:
    • --v=n sets the global log level to n (default 0). All log statements with a log level less than or equal to the global level will be printed.
    • --vmodule=mod=n[,mod=n,...] overrides the global log level for the module mod. Supplying the string foo for mod will affect all files named foo.cc, while supplying a wildcard like *bar/baz* will affect all files with bar/baz in their full pathnames.

Platform-specific code

  • To #ifdef code for specific platforms, use the macros defined in build/build_config.h and in the Chromium build config files, not other macros set by specific compilers or build environments (e.g. WIN32). Some of the major #defines:
    • OS_WIN, OS_MACOSX, OS_LINUX, and OS_CHROMEOS can be used for code specific to Windows, Mac, Linux, and Chromium OS, respectively.
    • OS_POSIX can be used for code applicable to all non-Windows platforms, e.g. pthreads.
    • TOOLKIT_VIEWS can be used for code relying on the views framework (used, for now, on Windows, Linux, and Chromium OS).
    • TOOLKIT_GTK can be used for code relying on the GTK framework (desktop Linux, but not ChromeOS), e.g. creating a GtkWidget or showing a GTK-native file picker dialog. Do not use OS_LINUX for this code.
    • USE_X11 can be used for X11 code (desktop Linux and Chromium OS), e.g. dealing with XEvent.
    • COMPILER_GCC and COMPILER_MSVC can be used for code specific to GCC/Clang and MSVC, respectively. (Do not assume OS_WIN implies COMPILER_MSVC!)
    Further defines exist for other OSes, specific aspects of the CPU such as architecture or word size, the number of bits in wchar_t, and others.
  • Place platform-specific #includes in their own section below the "normal" #includes. Repeat the standard #include order within this section:
    #include "foo/foo.h"
    
    #include <stdint.h>
    #include <algorithm>
    
    #include "base/strings/utf_string_conversions.h"
    #include "chrome/common/render_messages.h"
    
    #if defined(OS_WIN)
    #include <windows.h>
    #include "base/win/scoped_comptr.h"
    #elif defined(OS_POSIX)
    #include "base/posix/global_descriptors.h"
    #endif

Types

  • Use size_t for object and allocation sizes, object counts, array and pointer offsets, vector indices, and so on. The signed types are incorrect and unsafe for these purposes (e.g. integer overflow behavior for signed types is undefined in the C and C++ standards, while the behavior is defined for unsigned types.) The C++ STL is a guide here: they use size_t and foo::size_type for very good reasons.
  • Use size_t directly in preference to std::string::size_type and similar.
  • Occasionally classes may have a good reason to use a type other than size_t for one of these concepts, e.g. as a storage space optimization. In these cases, continue to use size_t in public-facing function declarations.
  • Be aware that size_t (object sizes and indices), off_t (file offsets), ptrdiff_t (the difference between two pointer values), intptr_t (an integer type large enough to hold the value of a pointer), uint32_t, uint64_t, and so on are not necessarily the same. Use the right type for your purpose.
  • When casting to and from different types, use static_cast<>() when you know the conversion is safe. Use checked_cast<>() (from base/numerics/safe_conversions.h) when you need to enforce via CHECK() that the source value is in-range for the destination type. Use saturated_cast<>() (from the same file) if you instead wish to clamp out-of-range values.
  • Do not use unsigned types to mean "this value should never be < 0". For that, use assertions or run-time checks (as appropriate).
  • In cases where the exact size of the type matters (e.g. a 32-bit pixel value, a bitmask, or a counter that has to be a particular width), use one of the sized types from <stdint.h>, e.g. uint32_t.
  • When passing values across network or process boundaries, use explicitly-sized types for safety, since the sending and receiving ends may not have been compiled with the same sizes for things like int and size_t. However, to the greatest degree possible, avoid letting these sized types bleed through the APIs of the layers in question.
  • Don't use std::wstring. Use base::string16 or FilePath instead. (Windows-specific code interfacing with system APIs using wstring and wchar_t can still use string16 and char16; it is safe to assume that these are equivalent to the "wide" types.)

Object ownership and calling conventions

  • When functions need to take raw or smart pointers as parameters, use the following conventions. Here we refer to the parameter type as T and name as t.
    • If the function does not modify t's ownership, declare the param as T*. The caller is expected to ensure t stays alive as long as necessary, generally through the duration of the call. Exception: In rare cases (e.g. using lambdas with STL algorithms over containers of scoped_ptr<>s), you may be forced to declare the param as const scoped_ptr<T>&. Do this only when required.
    • If the function takes ownership of a non-refcounted object, declare the param as scoped_ptr<T>.
    • If the function (at least sometimes) takes a ref on a refcounted object, declare the param as scoped_refptr<T>. The caller can decide whether it wishes to transfer ownership (by calling std::move(t) when passing t) or retain its ref (by simply passing t directly).
    In short, functions should never take ownership of parameters passed as raw pointers, and there should rarely be a need to pass smart pointers by const ref.
  • Conventions for return values are similar: return raw pointers when the caller does not take ownership, and return smart pointers by value otherwise, potentially in conjunction with std::move().

A great deal of Chromium code predates the above rules. In particular, some functions take ownership of params passed as T*, or take const scoped_refptr<T>& instead of T*, or return T* instead of scoped_refptr<T> (to avoid refcount churn pre-C++11). Try to clean up such code when you find it, or at least not make such usage any more widespread.

Forward declarations vs. #includes

Unlike the Google style guide, Chromium style prefers forward declarations to #includes where possible. This can reduce compile times and result in fewer files needing recompilation when a header changes.

  • You can and should use forward declarations for most types passed or returned by value, reference, or pointer, or types stored as pointer members or in most STL containers.
  • However, if it would otherwise make sense to use a type as a member by-value, don't convert it to a pointer just to be able to forward-declare the type.

Returning by value vs. outparam

After testing, it seems just as fast to return a std::[w]string by value as by outparam. So we encourage returning strings by value when possible for simpler-looking code.

File headers

  • All files in Chromium start with a common license header. That header should look like this:
    // Copyright $YEAR The Chromium Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    Some important notes about this header:
    • There is no (c) after Copyright.
    • $YEAR should be set to the current year at the time a file is created, and not changed thereafter.
    • For files specific to Chromium OS, replace the word Chromium with the phrase Chromium OS.
    • If the style changes, don't bother to update existing files to comply with the new style. For the same reason, don't just blindly copy an existing file's header when creating a new file, since the existing file may use an outdated style.
    • The Chromium project hosts mirrors of some upstream open-source projects. When contributing to these portions of the repository, retain the existing file headers.
  • Use standard #include guards in all header files (see the Google style guide section on these for the naming convention). Do not use #pragma once; historically it was not supported on all platforms, and it does not seem to outperform #include guards even on platforms which do support it.

CHECK(), DCHECK(), and NOTREACHED()

The CHECK() macro will cause an immediate crash if its condition is not met. DCHECK() is like CHECK() but is only compiled in when DCHECK_IS_ON is true (debug builds and some bot configurations, but not end-user builds). NOTREACHED() is equivalent to DCHECK(false). Here are some rules for using these:

  • Use DCHECK() or NOTREACHED() as assertions, e.g. to document pre- and post-conditions. A DCHECK() means "this condition must always be true", not "this condition is normally true, but perhaps not in exceptional cases." Things like disk corruption or strange network errors are examples of exceptional circumstances that nevertheless should not result in DCHECK() failure.
  • A consequence of this is that you should not handle DCHECK() failures, even if failure would result in a crash. Attempting to handle a DCHECK() failure is a statement that the DCHECK() can fail, which contradicts the point of writing the DCHECK(). In particular, do not write code like the following:
    DCHECK(foo);
    if (!foo) ...  // Can't succeed!
    
    if (!bar) {
      NOTREACHED();
      return;  // Replace this whole conditional with "DCHECK(bar);" and keep going instead.
    }
    ...
  • Use CHECK() if the consequence of a failed assertion would be a security vulnerability, where crashing the browser is preferable. Because this takes down the whole browser, sometimes there are better options than CHECK(). For example, if a renderer sends the browser process a malformed IPC, an attacker may control the renderer, but we can simply kill the offending renderer instead of crashing the whole browser.
  • You can temporarily use CHECK() instead of DCHECK() when trying to force crashes in release builds to sniff out which of your assertions is failing. Don't leave these in the codebase forever; remove them or change them back once you've solved the problem.
  • Don't use these macros in tests, as they crash the test binary and leave bots in a bad state. Use the ASSERT_xx() and EXPECT_xx() family of macros, which report failures gracefully and can continue running other tests.

Miscellany

  • Use UTF-8 file encodings and LF line endings.
  • Unit tests and performance tests should be placed in the same directory as the functionality they're testing.