(In case the formatting doesn't survive transit, a copy of this note can be
found here:
https://docs.google.com/document/d/1CTaWucldHxEri5BUB1kL4faF4prwPlBa31yHFd-l8uc
.)


TL;DR

To improve developer productivity, we are planning to a) start
automatically formatting all Gecko C++ code with clang-format, and b)
switch to the Google C++ style
<https://google.github.io/styleguide/cppguide.html> and retire the Mozilla
C/C++ coding style
<https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style>.
These changes are being tested and verified with a small part of the
codebase before rolling out to the entire tree.

Background

Mozilla has been moving towards using more automated tools for checking and
rewriting code. For example, eslint <https://eslint.org/> (JS), checkstyle
<https://github.com/checkstyle/checkstyle> (Java), flake8
<http://flake8.pycqa.org/en/latest/> (Python) are now Tier-1 in the CI. We
also deployed C/C++ static analysis as part of the development process.

In parallel, tooling to reformat C & C++ is now used in a wide variety of
projects like Chromium, LLVM and MongoDB. Mozilla has historically had a
coding style but it was never really enforced through tooling. In addition,
the Mozilla style is incomplete and used only in our projects; by contrast
the Google style is very complete, well supported in automated tooling, and
widely used by projects inside and outside of Google such as Chromium,
Tensorflow, and MySQL.

Because of the lack of checks and automation, we now have significant
inconsistencies in the style of our codebase.  On top of that, we have been
spending a lot of time talking about and adjusting whitespace. This wastes
human time when writing, reviewing, and discussing code.

Last but not least, being able to automatically format whitespace in our
C/C++ code is helpful for other types of automated rewrites so we can fix
wide-scale problems in our codebase using static analysis tools.  Right now
such fixes are difficult or impossible because of inconsistencies in the
Mozilla C++ coding style and lack of support in clang-format and other
tools. Addressing this issue is the first step in unblocking those future
improvements.

Goals

During patch authoring, code reviews, and mailing list discussions, Mozilla
developers have traditionally spent a lot of time on minor issues that
could easily be fixed through automated processes. Our Engineering
Operations and Product Integrity groups have helped to improve developer
productivity in this area through tools such as static analysis
<https://static-analysis.moz.tools/#/stats>, linting via Phabricator
reviewbot <https://phabricator.services.mozilla.com/p/reviewbot/>, and codebase
reformats
<https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style/Formatting_C++_Code_With_clang-format>
using clang-format. We will build on this foundation by applying coding
style checks and automated rewrites throughout the authoring process
(pre-commit, commit, review, landing).

Details

We’re announcing the following changes to our coding style and its
enforcement through our commit policy:


   1.

   We will check conformance with coding style rules upon commit, review,
   and landing so that issues can be easily addressed or fixed through
   automation. The preference will be to enforce style issues as early as
   possible (before landing) to avoid late surprises.

   2.

   We will migrate to the Google C++ coding style to encourage more
   consistent code and re-use a wider array of existing tools.  As part of
   this migration, we will retire the existing Mozilla C/C++ Coding Style. The
   intention behind retiring the current Mozilla style is to just stop
   maintaining it as an active coding style going forward, but the
   documentation for this coding style will be kept intact.



   1.

   We will automatically enforce restrictions on formatting of whitespace
   (such as indentation and braces). For stylistic features other than that
   (such as naming of functions and #include order), Google C++ style will be
   permitted but not initially enforced, and consistency with surrounding code
   should take precedence.


These changes have been approved both by Firefox senior engineering
leadership and the Firefox Technical Leadership Module
<https://wiki.mozilla.org/Modules/Firefox_Technical_Leadership>.  This work
is being tracked in bug 1188202
<https://bugzilla.mozilla.org/show_bug.cgi?id=1188202>.

When?

On Monday this week, we pushed a patch
<https://bugzilla.mozilla.org/show_bug.cgi?id=1204606> to an integration
branch to rewrite a section of the tree (dom/media) in the Google C++ style
using clang-format.  This first step is intended to be a smoke test step,
designed to test the process of doing the rewrite and test the waters in a
small controlled environment with a small team of developers who have
volunteered to help us test this change. We haven’t found any major
surprises yet.

Assuming that everything goes well, on Friday, November 30, we will push a
patch to mozilla-central and the integration branches syncing into it in
order to rewrite the entire tree using clang-format with the Google C++
Coding Style.

We want to do this work right before a merge (when nightly version moves to
beta) to limit the impact on the beta uplift process. Conveniently, this
happens to be the Friday just before the Mozilla All Hands when a lot of
Mozilla developers will be traveling, so we are hoping that would be a less
busy time for landing this change.

To mitigate the impact on the developers who backport fixes to ESR, on
Friday, December 14, we will also reformat the ESR60 code base.

Reformatting Code Locally

To reformat code locally

On a directory or a file specified by <path>:

$ ./mach clang-format -p <path>

On a modified tree (where hg diff or git diff) return a non-empty output:

$ ./mach clang-format

See the documentation for more information
<https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style/Formatting_C++_Code_With_clang-format>
.  There are integrations available for most popular code editors allowing
developers to easily format the code they’re working on at the time they’re
making changes to it.  The documentation links to several integrations for
the popular editors.

Rationale Behind Current Plan

We understand that switching coding styles can be a contentious choice, and
not one that everyone may be happy about initially.  Many people would
agree that having a consistent style across the code base is valuable, but
that’s not where we are now. To a great degree, that has been caused by
lack of good tools to enforce our existing coding style.  By contrast,
there is tooling to enforce quite a bit of the Google C++ Style, and this
is why we would like to convert entirely to this coding style -- perhaps
with some exceptions for Mozilla-specific constraints. That is something
that we are going to look at seriously going forward.

We have decided here to start this conversion by converting the whitespace
related portions of our coding style mechanically using clang-format as a
first step. Of course, other strategies for this conversion are also
possible, such as waiting until such a time when we have the tooling ready
for switching wholesale to the Google C++ Style.  But we have decided that
by allowing the usage of the Google C++ Style in new areas, we are taking
an incremental step towards that ultimate goal by allowing (not requiring)
people to write code immediately after our switch that is consistent with
our newly adopted coding style and can be verified as such using tools. The
intention here is not that people intermix Google C++ Style and Mozilla
Style code on a per function or even a per file basis but rather that they
be free to do so when starting new, self-contained work, or to convert an
entire module.

Providing Feedback

This post is intended as an announcement, but we do welcome your feedback
on this, both at a high level and at the technical level.  For high level
feedback please reach out to t...@mozilla.com and CC myself.  For technical
feedback (e.g. bugs about the conversion process) please file bugs under bug
clang-format <https://bugzilla.mozilla.org/show_bug.cgi?id=1188202>.

Last but not least, coding style is a living organism. This change doesn’t
mean that the coding style will remain forever this way; to the contrary
this will give us the opportunity to easily change our coding style and
apply the change on the code base.

I’d like to extend my gratitude to many who have helped getting us to this
point, including Sylvestre Ledru, Peter Saint-Andre, Andi-Bogdan Postelnicu
and Birunthan Mohanathas.

Best regards,

Ehsan

FAQ:

Can I see what it looks like?

With an up-to-date repository, you can use

$ ./mach clang-format -p <path>

A formatted repository is available on github:
https://github.com/sylvestre/gecko-dev/ to visualize the changes.

Is it going to break something?

Of course, every software has bugs but all the testing that we have done
didn’t show any sign of regression.

You will break the blame on VCS with this change

Yes and no. Of course, just like many tree-wide mass changes in the past
(e.g. the MPL2 header update), this will remain in the log.

Mercurial and Git both support a -w argument to ignore whitespace with
annotate/blame.

In addition, modern versions of Mercurial have `hg annotate --skip
<revset>` which allows you to specify a revset used to select revisions to
skip over when annotating.

Last but not least, we will tag the changeset’s commit message with
“skip-blame” so that Mercurial would automatically ignore the reformat
changeset for blame operations.

Why doing that in a single patch instead of doing that file per file or
module per module?

We are doing that into a single patch for several reasons:

   -

   We will be done quickly
   -

   We will have a single revision to ignore in the annotate/blame
   -

   We can tag this magic revision to run some tasks on it (local reformat
   to avoid conflicts)


clang-format doesn’t add missing braces, is that normal?

clang-format only does whitespace changes. It doesn’t add or remove code.

However, this can be done through ./mach static-analysis. For example:

   -

   ./mach static-analysis check --check
   google-readability-braces-around-statements --fix js/src/wasm/


This checker is enabled at review phase
<https://static-analysis.moz.tools/#/check/clang-tidy.readability-braces-around-statements>
in Phabricator.  Note that the --fix argument here means that the
static-analysis job will automatically rewrite the local tree in order to
add braces around statements anywhere it finds those issues, no need to do
it manually!

Does everything has to be formatted?

Yes, all of the C/C++ code that we maintain in mozilla-central has to be
formatted.

There are cases, like some structure declarations, for which we want to
ignore the formatting. Example:

https://hg.mozilla.org/mozilla-central/rev/7807742373e1

In that case, add:

// clang-format off

code not to be formatted

// clang-format on

My component has some very specific needs with very good reasons, can I
customize the coding style?

No, going forward we are planning to unify all of our code (excluding
third-party code and any potential code owned by us that is developed
outside of mozilla-central) under the same coding style.  If there are
individual blocks within your code that require custom formatting for good
reasons, please see the previous question for how to turn clang-format off
for specific sections.

If you see issues about the style change that make you unhappy and you
think affect the code in the areas you work on in negative ways, please
consider spending some time to try to get used to the change.  But if after
some time the change still seems inferior compared to before please raise
the issues and we will work to figure out how to address those problems to
the best of our ability.

Can I ignore just a file?

If you have a good reason, yes. For example, in some cases, we have some
tooling which parses the C/C++ code with a very specific format. For this,
just add it into .clang-format-ignore
<https://dxr.mozilla.org/mozilla-central/source/.clang-format-ignore> file
with a comment explaining why it should be ignored.

Please note that examples of what constitutes a good reason for excluding
single files would be external tools needing to parse the file in specific
ways, or cases where clang-format can’t deal with the input (such as bug
1342657 <https://bugzilla.mozilla.org/show_bug.cgi?id=1342657>).  Examples
of what does not constitute a good reason would be personal preferences.

What about variable naming convention?  What about function/class/etc.
naming conventions?

With this change, we are not aiming to enforce any naming conventions at
this time.

What about third party code?

Third party code will not be touched. See this list:
https://dxr.mozilla.org/mozilla-central/source/tools/rewriting/ThirdPartyPaths.txt

This is mirrored here for clang-format to ignore these directories:

https://dxr.mozilla.org/mozilla-central/source/.clang-format-ignore

If you are aware of third-party code developed outside of mozilla-central
that isn’t listed here, please file a bug as soon as possible to get it
added to this list.

Why are we switching to the Google C++ coding style?

The current Mozilla C++ style
<https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style>
is not well supported by tools (in particular clang-format) and it has
been difficult
to <https://reviews.llvm.org/D37979> upstream patches
<https://reviews.llvm.org/D12921#247649> to clang-format to handle the
Mozilla style. By contrast, the Google C++ style used in a number of
projects (parts of NSS
<https://hg.mozilla.org/projects/nss/file/tip/cpputil/.clang-format>, MySQL
<https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_CODING_GUIDELINES.html>,
Android
<https://github.com/search?q=org%3Aaosp-mirror+BasedOnStyle&type=Code>,
Tensorflow
<https://github.com/tensorflow/tensorflow/blob/master/tensorflow/.clang-format>,
and many others
<https://github.com/search?q=BasedOnStyle%3A+Google&type=Code>) and well
supported in clang-format, linters
<https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py>,
and clang-tidy checks
<https://clang.llvm.org/extra/clang-tidy/checks/list.html>. Defining and
maintaining our own C++ coding style probably isn’t the best use of our
time, and switching to the Google style will help us improve the
productivity of our developers, make onboarding easier, and pave the way
for more automation of trivial but time-consuming code fixes.

The feature foo from the coding style is missing in clang-format, what
should I do?

Going forward, our precise coding style will be the result of formatting
our tree with clang-format, so by definition our code, when formatted with
clang-format, will be following our new coding style.

In cases where you have found bugs in how clang-format implements the
Google C++ Style, please report those issues to the LLVM project:
https://bugs.llvm.org/.  When the fixes are available in new versions of
clang-format, we’ll pick up the resulting reformatting automatically
through version upgrades.

In case you have feedback on the Google C++ Style Guide itself, please
consider filing an issue/PR in the upstream repository
<https://github.com/google/styleguide>.

How will we be sure we don’t regress?

For a while we’ve been running clang-format linting checks at review time
on Phabricator in shadow mode
<https://static-analysis.moz.tools/#/check/clang-format.lint> (executed but
not published). Over the next few weeks, we will enable verifications at
review phase on on Phabricator.

In parallel of that, we will offer hooks that can be enabled locally to
check for formatting.  We’re hoping to enable a hook on hg.mozilla.org to
automatically reject improperly formatted commits soon after that.  This
will prevent badly formatted code from being pushed to hg.mozilla.org in
the first place.

What will happen to my local changes? Will I have to rebase everything?

In order to mitigate the impact for pending changes, we developed a
mercurial extension called hg format-source
<https://pypi.python.org/pypi/hg-formatsource> to locally reformat the
local changes before the big patch is pulled. This will fix most of the
conflict issues.

We will share more details later.

For git users, we are working on providing a similar script based on the
one developed by the Mongo project
<https://github.com/mongodb/mongo/blob/8b66399b8536dc3120be5444b81ba51d4b8a95e4/buildscripts/clang_format.py>
.

Playing with clang-format, I noticed changes in the output between
versions, how will we manage that?

Because clang-format evolves, this is true that the output can change from
a version to another. This is why ./mach clang-format downloads an specific
artifact from the taskcluster CI. At this date, we are using clang-format
version 7.

As the Phabricator review bot is using ./mach clang-format to run the
analysis, the same version is used.

The version of the LLVM tools used for this purpose is defined in-tree for
Linux
<https://searchfox.org/mozilla-central/source/build/build-clang/clang-tidy-linux64.json>,
Mac
<https://searchfox.org/mozilla-central/source/build/build-clang/clang-tidy-macosx64.json>
and Windows
<https://searchfox.org/mozilla-central/source/build/build-clang/clang-tidy-win64.json>
.

What will happen to the downstream consumers of the ESR repository after
ESR60 is rewritten with clang-format?

We are aware of the impact of this plan on Firefox derivatives but we think
it is worth it the pain.  The goal behind rewriting the ESR branch is to
make it easier to uplift patches from trunk onto the ESR branch, and this
change should make things easier for downstream consumers creating Firefox
derivatives based on the ESR60 codebase.

Such consumers still have the capability to run the following pseudo code
in the derivative project to generate up to date patches if they have local
modifications on top of ESR.  In the example below, fx-esr60-reformatted is
the SHA1 hash of the Mercurial changeset that has rewritten the ESR60
repository with clang-format.  This pseudo code shows the necessary steps
if the local modifications are applied on top of fx-esr60-reformatted.


   -

   # Rewrite the locally modified tree
   ./mach clang-format -p <path of the file touched>
   -

   # Generate a diff of the local changes against
   hg diff -r [fx-esr60-reformatted]
_______________________________________________
dev-platform mailing list
dev-platform@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-platform

Reply via email to