blob: 1ce522e8387bd9af3d3678ea592d2f2a24069d4b [file] [log] [blame] [view]
---
breadcrumbs:
- - /developers
- For Developers
- - /developers/coding-style
- Coding Style
page_name: chromium-style-checker-errors
title: Chromium Style Checker Errors
---
[TOC]
## Introduction
Due to constant over inlining, we now have plugins to the clang compiler which
check for certain patterns that can increase code bloat. This document lists
these errors, explains the motivation behind adding it as an error and shows how
to fix them. The [chromium/clang wiki
page](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/updating_clang_format_binaries.md)
explains how you can run the plugin yourself, or how you can run your CLs
through the clang trybots which run this plugin as well.
All diagnostics produced by the style checker are marked with
\[chromium-style\].
## Constructor/Destructor Errors
Constructors and destructors are often much larger and more complex than
programmers think. They are also implicitly defined in each translation unit if
you don't declare them. This can have a cascading effect if a class has member
variables that have inlined/implicitly declared constructors/destructors, or are
templates.
(Internally, the plugin determines whether a class is complex using a point
system, adding 9 points for each templated base class, 10 for each templated
member variable, 3 for each non-POD type member variable, and (only for the
constructor score) 1 for each integral data type. If a class's score is greater
than or equal to 10, it will trip these errors.)
If you get any of these compiler errors:
* Complex class/struct needs an explicit out-of-line constructor
* Complex class/struct needs an explicit out-of-line destructor
It's because you've written something like the following in a header:
```c++
class ComplexStuff {
public:
void NoDeclaredConstructor();
private:
// Enough data members to trip the detector
BigObject big_object_;
std::map<std::string, OtherObj> complex_stl_stuff_;
};
```
This is fixed by adding declared constructors:
```c++
class ComplexStuff {
public:
// Defined in the .cc file:
ComplexStuff();
~ComplexStuff();
private:
BigObject big_object_;
std::map<std::string, OtherObj> complex_stl_stuff_;
};
```
Likewise, if you get these compiler errors:
* Complex constructor has an inlined body.
* Complex destructor has an inline body.
It's because you've written something like the following in a header:
```c++
class MoreComplexStuff {
public:
MoreComplexStuff() = default;
~MoreComplexStuff() = default;
private:
BigObject big_object_;
std::map<std::string, OtherObj> complex_stl_stuff_;
};
```
The solution is the same; put the definitions for the constructor/destructor in
the implementation file.
Sometimes, you might need to inline a constructor/destructor for performance
reasons. The style checker makes an exception for explicitly inlined
constructors/destructors:
In the .h file:
```c++
class ComplexFastStuff {
public:
ComplexFastStuff();
~ComplexFastStuff();
private:
/* complicated members */
};
```
In the .cc file:
```c++
inline ComplexFastStuff::ComplexFastStuff() = default;
inline ComplexFastStuff::~ComplexFastStuff() = default;
```
If this class is being copied somewhere in the code, then the compiler will
generate an implicit copy constructor for the class. As a result, you might also
see the following error:
* Complex class/struct needs an explicit out-of-line copy constructor.
This can be fixed by adding an explicit copy constructor to your class:
In the .h file:
```c++
class ComplexCopyableStuff {
public:
ComplexCopyableStuff();
ComplexCopyableStuff(const ComplexCopyableStuff& other);
~ComplexCopyableStuff();
private:
/* complicated members */
};
```
In the .cc file:
```c++
ComplexCopyableStuff::ComplexCopyableStuff(const ComplexCopyableStuff& other) = default;
```
Note that by defaulting the implementation, you ensure that you don't forget to
copy a member and this code will not need to be updated as the members of the
class change.
Also note that copying a complex class can be an expensive operation. The
preferred solution is almost always is to avoid the copy if possible. Please
consider changing the code and eliminating unnecessary copies instead of simply
adding an out of line copy constructor to silence the error. Additionally, in a
large number of cases, you can utilize move semantics to improve the efficiency
of the code.
Usually a compiler would generate a move constructor for your class, making
moving objects efficient. This is particularly true for STL containers such as
std::map. However, specifying either a copy constructor or a destructor prevents
the compiler from generating a move constructor. All in all, you should prefer
specifying a move constructor instead of a copy constructor. In cases where your
object is used as an rvalue, this will also prevent the error since the compiler
will not generate a copy constructor:
In the .h file:
```c++
class ComplexMovableStuff {
public:
ComplexMovableStuff();
ComplexMovableStuff(ComplexMovableStuff&& other);
~ComplexMovableStuff();
private:
/* complicated members */
};
```
In the .cc file:
```c++
ComplexMovableStuff::ComplexMovableStuff(ComplexMovableStuff&& other) = default;
```
For more information on move semantics, please refer to
<https://www.chromium.org/rvalue-references>
## Virtual Method Out-of-lining
Virtual methods are almost never inlined in practice. Because of this, methods
on a base class will be emitted in each translation unit that allocates the
object or any subclasses that don't override that method. This is usually not a
major gain, unless you have a wide class hierarchy in which case it can be a big
win (<http://codereview.chromium.org/5741001/>). Since virtual methods will
almost never be inlined anyway (because they'll need to go through vtable
dispatch), there are almost no downsides.
If you get the error:
* virtual methods with non-empty bodies shouldn't be declared inline
It's because you wrote something like this:
```c++
class BaseClass {
public:
virtual void ThisOneIsOK() = default;
virtual bool ButWeDrawTheLineAtMethodsWithRealImplementation() { return false; }
};
```
And can be fixed by out of lining the method that does work:
```c++
class BaseClass {
public:
virtual void ThisIsHandledByTheCompiler() {}
virtual bool AndThisOneIsDefinedInTheImplementation();
};
```
## Virtual methods and override/final
If you get the error:
* Overriding method must be marked with 'override' or 'final'.
It is because you are overriding a base class method, yet not annotating that
override with override or final. For example:
```c++
class BaseClass {
public:
virtual ~BaseClass() {}
virtual void SomeMethod() = 0;
};
class DerivedClass : public BaseClass {
public:
virtual void SomeMethod();
};
```
The solution? Just tell the compiler what you intend:
```c++
// ...
class DerivedClass : public BaseClass {
public:
void SomeMethod() override;
};
```
This allows the compiler to warn you when your intentions stop matching parsed
reality.
## Redundant Virtual specifiers
If you get one of the following errors:
* 'virtual' is redundant; 'override' implies 'virtual'
* 'virtual' is redundant; 'final' implies 'virtual'
* 'override' is redundant; 'final' implies 'override'
Just remove the redundant specifier. Google style is to use only one of virtual,
override, or final per method. For example:
```c++
class BaseClass {
public:
virtual void SomeMethod() = 0;
};
class DerivedClass : public BaseClass {
public:
virtual void SomeMethod() override final;
};
```
Can be simply written:
```c++
// ...
class DerivedClass : public BaseClass {
public:
void SomeMethod() final;
};
```
## Virtual final base class methods
If you get the error:
The virtual method does not override anything and is final; consider making it
non-virtual
That means you have a final method that's not overriding anything. In that case,
consider removing the virtual keyword, since no one can override the method
anyway. For example:
```c++
class BaseClass {
public:
virtual void SomeMethod() final;
};
```
Should be written:
```c++
class BaseClass {
public:
void SomeMethod();
};
```
## "Using namespace" in a header
You should never have using namespace directives in a header because this can
change the lookup rules in unrelated implementation files.
This is enforced by clang's -Wheader-hygiene warning. This isn't checked by the
style plugin.
If you get the error:
* using namespace directive in global context in header
\[-Wheader-hygiene\]
It's because you did something like this in a header:
```c++
using namespace WebKit;
class OurDerivedClass : public WebKitType {
};
```
You can fix this by removing the "using namespace" line and explicitly stating
the namespace:
```c++
class OurDerivedClass : public WebKit::WebKitType {
};
```
## RefCounted types with public destructors
When you declare a type to be referenced counted by making it derive from
base::RefCounted or base::RefCountedThreadSafe, you're indicating that it should
not be destructed until the last reference is Released, either explicitly or by
destructing a scoped_refptr&lt;&gt;. Having a public destructor allows this
contract to be violated, by allowing callers to stack allocate the object, store
it in a scoped_ptr&lt;&gt; instead of a scoped_refptr&lt;&gt;, or to explicitly
delete the object before all references have gone away. Because this can lead to
subtle security bugs, the style checker will warn if class that is derived from
a RefCounted type has either an explicit public destructor or an implicit
destructor, which is automatically public.
If you get the error:
* Classes that are ref-counted should not have public destructors.
It's because you did something like this:
```c++
class Foo : public base::RefCounted<Foo> {
public:
Foo() {}
~Foo() {}
};
```
You can fix this by ensuring that the destructor is either protected (if
expecting classes to subclass this base) or private. You'll also need to ensure
that the RefCounted type is friended, as appropriate.
```c++
class Foo : public base::RefCounted<Foo> {
public:
Foo() {}
private:
friend class base::RefCounted<Foo>;
~Foo() {}
};
```
If you get the error:
* Classes that are ref-counted should have explicit destructors that
are protected or private.
It's because you did something like this:
```c++
class Foo : public base::RefCounted<Foo> {
// Compiler generated constructors, destructor, and copy operator are public.
};
```
You can fix it by ensuring you explicitly declare a protected or private
destructor:
```c++
class Foo : public base::RefCounted<Foo> {
// Compiler generated constructors and copy operator are public.
private:
friend class base::RefCounted<Foo>;
~Foo() {} // Explicit destructor is private.
};
```
## Enumerator max values
If you have an enumerator value that needs to be the max value (useful for
histograms or for IPC), declare your enum as an enum class and name the max
value kMaxValue. The plugin will automatically warn if kMaxValue is no longer
the max value.
For example:
```c++
enum class Foo {
kOne,
kTwo,
kMaxValue = kOne,
};
```
Will produce the error:
* kMaxValue enumerator does not match max value 0 of other enumerators
This can be fixed by assigning the correct value to kMaxValue:
```c++
enum class Foo {
kOne,
kTwo,
kMaxValue = kTwo,
};
```