diff --git a/README.md b/README.md new file mode 100644 index 000000000..b8f87fcd3 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +Google Style Guides +=================== + +Every major open-source project has its own style guide: a set of conventions +(sometimes arbitrary) about how to write code for that project. It is much +easier to understand a large codebase when all the code in it is in a +consistent style. + +“Style” covers a lot of ground, from “use camelCase for variable names” to +“never use global variables” to “never use exceptions.” This project +([google/styleguide](https://github.com/google/styleguide)) links to the +style guidelines we use for Google code. If you are modifying a project that +originated at Google, you may be pointed to this page to see the style guides +that apply to that project. + +This project holds the [C++ Style Guide][cpp], [Objective-C Style Guide][objc], +[Java Style Guide][java], [Python Style Guide][py], [R Style Guide][r], +[Shell Style Guide][sh], [HTML/CSS Style Guide][htmlcss], +[JavaScript Style Guide][js], [AngularJS Style Guide][angular], +[Common Lisp Style Guide][cl], and [Vimscript Style Guide][vim]. This project +also contains [cpplint][cpplint], a tool to assist with style guide compliance, +and [google-c-style.el][emacs], an Emacs settings file for Google style. + +If your project requires that you create a new XML document format, the [XML +Document Format Style Guide][xml] may be helpful. In addition to actual style +rules, it also contains advice on designing your own vs. adapting an existing +format, on XML instance document formatting, and on elements vs. attributes. + +The style guides in this project are licensed under the CC-By 3.0 License, +which encourages you to share these documents. +See [https://creativecommons.org/licenses/by/3.0/][ccl] for more details. + +The following Google style guides live outside of this project: +[Go Code Review Comments][go] and [Effective Dart][dart]. + +Creative Commons License + +[cpp]: https://google.github.io/styleguide/cppguide.html +[objc]: objcguide.md +[java]: https://google.github.io/styleguide/javaguide.html +[py]: https://google.github.io/styleguide/pyguide.html +[r]: https://google.github.io/styleguide/Rguide.xml +[sh]: https://google.github.io/styleguide/shell.xml +[htmlcss]: https://google.github.io/styleguide/htmlcssguide.html +[js]: https://google.github.io/styleguide/jsguide.html +[angular]: https://google.github.io/styleguide/angularjs-google-style.html +[cl]: https://google.github.io/styleguide/lispguide.xml +[vim]: https://google.github.io/styleguide/vimscriptguide.xml +[cpplint]: https://github.com/google/styleguide/tree/gh-pages/cpplint +[emacs]: https://raw.githubusercontent.com/google/styleguide/gh-pages/google-c-style.el +[xml]: https://google.github.io/styleguide/xmlstyle.html +[go]: https://golang.org/wiki/CodeReviewComments +[dart]: https://www.dartlang.org/guides/language/effective-dart +[ccl]: https://creativecommons.org/licenses/by/3.0/ diff --git a/Rguide.xml b/Rguide.xml new file mode 100644 index 000000000..ef8787263 --- /dev/null +++ b/Rguide.xml @@ -0,0 +1,447 @@ + + + + + + Google's R Style Guide + + + + +

Google's R Style Guide

+ +

+ R is a high-level programming language used primarily for + statistical computing and graphics. The goal of the R + Programming Style Guide is to make our R code easier to read, + share, and verify. The rules below were designed in + collaboration with the entire R user community at Google. + +

+ + + + + + +

Summary: R Style Rules

+ +
    +
  1. File Names: end in .R
  2. +
  3. Identifiers: variable.name + (or variableName), + FunctionName, kConstantName
  4. +
  5. Line Length: maximum 80 characters
  6. +
  7. Indentation: two spaces, no tabs
  8. +
  9. Spacing
  10. +
  11. Curly Braces: first on same line, last on + own line
  12. +
  13. else: Surround else with braces
  14. +
  15. Assignment: use <-, not + =
  16. +
  17. Semicolons: don't use them
  18. +
  19. General Layout and Ordering
  20. +
  21. Commenting Guidelines: all comments begin + with # followed by a space; inline comments need two + spaces before the #
  22. +
  23. Function Definitions and Calls
  24. +
  25. Function Documentation
  26. +
  27. Example Function
  28. +
  29. TODO Style: TODO(username)
  30. +
+ +

Summary: R Language Rules

+
    +
  1. attach: avoid using it
  2. +
  3. Functions: + errors should be raised using stop()
  4. +
  5. Objects and Methods: avoid S4 objects and + methods when possible; never mix S3 and S4
  6. +
+ +

Notation and Naming

+ +

File Names

+

+ File names should end in .R and, of course, be + meaningful. +
GOOD: predict_ad_revenue.R +
BAD: foo.R +

+ +

Identifiers

+

+ Don't use underscores ( _ ) or hyphens + ( - ) in identifiers. + Identifiers should be named according to the following conventions. + The preferred form for variable names is all lower case + letters and words separated with dots + (variable.name), but variableName + is also accepted; + function names have initial capital letters and no dots + (FunctionName); + constants are named like functions but with an initial + k. +

+ + + +

Syntax

+ +

Line Length

+

+ The maximum line length is 80 characters. +

+ +

Indentation

+

+ When indenting your code, use two spaces. Never use tabs or mix + tabs and spaces. +
Exception: When a line break occurs inside parentheses, + align the wrapped line with the first character inside the + parenthesis. +

+ +

Spacing

+

+ Place spaces around all binary operators (=, + +, -, <-, etc.). +
Exception: Spaces around ='s are + optional when passing parameters in a function call. +

+

+ Do not place a space before a comma, but always place one after a + comma. +

GOOD: +

+
tab.prior <- table(df[df$days.from.opt < 0, "campaign.id"])
+total <- sum(x[, 1])
+total <- sum(x[1, ])
+

+ BAD: +

+
tab.prior <- table(df[df$days.from.opt<0, "campaign.id"])  # Needs spaces around '<'
+tab.prior <- table(df[df$days.from.opt < 0,"campaign.id"])  # Needs a space after the comma
+tab.prior<- table(df[df$days.from.opt < 0, "campaign.id"])  # Needs a space before <-
+tab.prior<-table(df[df$days.from.opt < 0, "campaign.id"])  # Needs spaces around <-
+total <- sum(x[,1])  # Needs a space after the comma
+total <- sum(x[ ,1])  # Needs a space after the comma, not before
+
+

+ Place a space before left parenthesis, except in a function call. +

+

+ GOOD: +
if (debug) +

+

+ BAD: +
if(debug) +

+

+ Extra spacing (i.e., more than one space in a row) is okay if it + improves alignment of equals signs or arrows (<-). +

+
plot(x    = x.coord,
+     y    = data.mat[, MakeColName(metric, ptiles[1], "roiOpt")],
+     ylim = ylim,
+     xlab = "dates",
+     ylab = metric,
+     main = (paste(metric, " for 3 samples ", sep = "")))
+
+

+ Do not place spaces around code in parentheses or square brackets. +
Exception: Always place a space after a comma. +

+

+ GOOD:

if (debug)
+x[1, ]
+

+ BAD:

if ( debug )  # No spaces around debug
+x[1,]  # Needs a space after the comma 
+ +

Curly Braces

+

+ An opening curly brace should never go on its own line; a closing + curly brace should always go on its own line. You may omit curly + braces when a block consists of a single statement; however, you + must consistently either use or not use curly braces for + single statement blocks. +

+
+if (is.null(ylim)) {
+  ylim <- c(0, 0.06)
+}
+

+ xor (but not both) +

+
+if (is.null(ylim))
+  ylim <- c(0, 0.06)
+

+ Always begin the body of a block on a new line. +

+

+ BAD: +
if (is.null(ylim)) + ylim <- c(0, 0.06) +
if (is.null(ylim)) + {ylim <- c(0, 0.06)} +

+ +

Surround else with braces

+

+ An else statement should always be surrounded on the + same line by curly braces.

+
+if (condition) {
+  one or more lines
+} else {
+  one or more lines
+}
+
+

+ BAD:
+

+
+if (condition) {
+  one or more lines
+}
+else {
+  one or more lines
+}
+
+

+ BAD:
+

+
+if (condition)
+  one line
+else
+  one line
+
+ +

Assignment

+

+ Use <-, not =, for assignment. +

+

+ GOOD: +
x <- 5 +

+

+ BAD: +
x = 5 +

+

Semicolons

+

+ Do not terminate your lines with semicolons or use semicolons to + put more than one command on the same line. (Semicolons are not + necessary, and are omitted for consistency with other Google style + guides.) +

+ + +

Organization

+

General Layout and Ordering

+

+ If everyone uses the same general ordering, we'll be able to + read and understand each other's scripts faster and more easily. +

+
    +
  1. Copyright statement comment
  2. +
  3. Author comment
  4. +
  5. File description comment, including purpose of + program, inputs, and outputs
  6. +
  7. source() and library() statements
  8. +
  9. Function definitions
  10. +
  11. Executed statements, if applicable (e.g., + print, plot)
  12. +
+

+ Unit tests should go in a separate file named + originalfilename_test.R. +

+

Commenting Guidelines

+

+ Comment your code. Entire commented lines should begin with + # and one space. +

+

+ Short comments can be placed after code preceded by two spaces, + #, and then one space. +

+
# Create histogram of frequency of campaigns by pct budget spent.
+hist(df$pct.spent,
+     breaks = "scott",  # method for choosing number of buckets
+     main   = "Histogram: fraction budget spent by campaignid",
+     xlab   = "Fraction of budget spent",
+     ylab   = "Frequency (count of campaignids)")
+
+

Function Definitions and + Calls

+

+ Function definitions should first list arguments without default + values, followed by those with default values. +

+

+ In both function definitions and function calls, multiple + arguments per line are allowed; line breaks are only allowed + between assignments. +
GOOD: +

+
PredictCTR <- function(query, property, num.days,
+                       show.plot = TRUE)
+
+ BAD: +
PredictCTR <- function(query, property, num.days, show.plot =
+                       TRUE)
+
+

Ideally, unit tests should serve as sample function calls (for + shared library routines). +

+

Function Documentation

+

Functions should contain a comments section immediately below + the function definition line. These comments should consist of a + one-sentence description of the function; a list of the function's + arguments, denoted by Args:, with a description of + each (including the data type); and a description of the return + value, denoted by Returns:. The comments should be + descriptive enough that a caller can use the function without + reading any of the function's code. +

+ +

Example Function

+
+CalculateSampleCovariance <- function(x, y, verbose = TRUE) {
+  # Computes the sample covariance between two vectors.
+  #
+  # Args:
+  #   x: One of two vectors whose sample covariance is to be calculated.
+  #   y: The other vector. x and y must have the same length, greater than one,
+  #      with no missing values.
+  #   verbose: If TRUE, prints sample covariance; if not, not. Default is TRUE.
+  #
+  # Returns:
+  #   The sample covariance between x and y.
+  n <- length(x)
+  # Error handling
+  if (n <= 1 || n != length(y)) {
+    stop("Arguments x and y have different lengths: ",
+         length(x), " and ", length(y), ".")
+  }
+  if (TRUE %in% is.na(x) || TRUE %in% is.na(y)) {
+    stop(" Arguments x and y must not have missing values.")
+  }
+  covariance <- var(x, y)
+  if (verbose)
+    cat("Covariance = ", round(covariance, 4), ".\n", sep = "")
+  return(covariance)
+}
+
+ +

TODO Style

+ +

+ Use a consistent style for TODOs throughout your code. +
TODO(username): Explicit description of action to + be taken +

+ + +

Language

+ +

Attach

+

The possibilities for creating errors when using + attach are numerous. Avoid it.

+

Functions

+

Errors should be raised using stop().

+

Objects and Methods

+

The S language has two object systems, S3 and S4, both of which + are available in R. S3 methods are more interactive and flexible, + whereas S4 methods are more formal and rigorous. (For an illustration + of the two systems, see Thomas Lumley's + "Programmer's Niche: A Simple + Class, in S3 and S4" in R News 4/1, 2004, pgs. 33 - 36: + + https://cran.r-project.org/doc/Rnews/Rnews_2004-1.pdf.) +

+

Use S3 objects and methods unless there is a strong reason to use + S4 objects or methods. A primary justification for an S4 object + would be to use objects directly in C++ code. A primary + justification for an S4 generic/method would be to dispatch on two + arguments. +

+

Avoid mixing S3 and S4: S4 methods ignore S3 inheritance and + vice-versa. +

+ + +

Exceptions

+ +

+ The coding conventions described above should be followed, unless + there is good reason to do otherwise. Exceptions include legacy + code and modifying third-party code. +

+ + +

Parting Words

+ +

+ Use common sense and BE CONSISTENT. +

+

+ If you are editing code, take a few minutes to look at the code around + you and determine its style. If others use spaces around their + if + clauses, you should, too. If their comments have little boxes of stars + around them, make your comments have little boxes of stars around them, + too. +

+

+ The point of having style guidelines is to have a common vocabulary of + coding so people can concentrate on what you are saying, + rather than on how you are saying it. We present global style + rules here so people + know the vocabulary. But local style is also important. If code you add + to a file looks drastically different from the existing code around it, + the discontinuity will throw readers out of their rhythm when they go to + read it. Try to avoid this. +

+ +

+ OK, enough writing about writing code; the code itself is much more + interesting. Have fun! +

+ + +

References

+ +

+ + http://www.maths.lth.se/help/R/RCC/ - R Coding Conventions +

+

+ http://ess.r-project.org/ - For + emacs users. This runs R in your emacs and has an emacs mode. +

+ + + + diff --git a/angularjs-google-style.html b/angularjs-google-style.html new file mode 100644 index 000000000..6bcd5d2a0 --- /dev/null +++ b/angularjs-google-style.html @@ -0,0 +1,393 @@ + + + + + + + + + + Google's AngularJS Style Guide + + + +

An AngularJS Style Guide for Closure Users at Google

+ +

This is the external version of a document that was primarily written for Google + engineers. It describes a recommended style for AngularJS apps that use Closure, as used + internally at Google. Members of the broader AngularJS community should feel free to apply + (or not apply) these recommendations, as relevant to their own use cases.

+ +

This document describes style for AngularJS apps in google3. This guide + supplements and extends the + Google JavaScript Style Guide. +

+ +

Style Note: Examples on the AngularJS external webpage, and many external apps, are + written in a style that freely uses closures, favors functional inheritance, and does not often use + + JavaScript types. Google follows a more rigorous Javascript style to support JSCompiler + optimizations and large code bases - see the javascript-style mailing list. + This is not an Angular-specific issue, and is not discussed further in this style guide. + (But if you want further reading: + Martin Fowler on closures, + much longer description, appendix A of the + + closure book has a good description of inheritance patterns and why it prefers + pseudoclassical, + + Javascript, the Good Parts as a counter.)

+ +
1 Angular Language Rules
+ +
2 Angular Style Rules
+ +
3 Angular Tips, Tricks, and Best Practices
+ + +
4 Best practices links and docs
+ +

1 Angular Language Rules

+ +

Manage dependencies with Closure's goog.require and goog.provide

+

Choose a namespace for your project, and use goog.provide and goog.require.

+
+goog.provide('hello.about.AboutCtrl');
+goog.provide('hello.versions.Versions');
+
+ +

Why? + Google BUILD rules integrate nicely with closure provide/require.

+ +

Modules

+ +

Your main application module should be in your root client directory. A module should never be + altered other than the one where it is defined.

+ +

Modules may either be defined in the same file as their components (this works well for a module + that contains exactly one service) or in a separate file for wiring pieces together.

+ +

Why? + A module should be consistent for anyone that wants to include it as a reusable component. + If a module can mean different things depending on which files are included, it is not consistent. +

+ +

+ Modules should reference other modules using the Angular Module's "name" property +

+ +

For example:

+ +
+// file submodulea.js:
+  goog.provide('my.submoduleA');
+
+  my.submoduleA = angular.module('my.submoduleA', []);
+  // ...
+
+// file app.js
+  goog.require('my.submoduleA');
+
+  Yes: my.application.module = angular.module('hello', [my.submoduleA.name]);
+  
+      No: my.application.module = angular.module('hello', ['my.submoduleA']);
+  
+ +

Why? + Using a property of my.submoduleA prevents Closure presubmit failures complaining that the file is + required but never used. Using the .name property avoids duplicating strings.

+ +

Use a common externs file

+ +

This maximally allows the JS compiler to enforce type safety in the presence of externally + provided types from Angular, and means you don't have to worry about Angular vars being obfuscated + in a confusing way.

+ +

Note to readers outside Google: the current externs file is located in an internal-to-Google + directory, but an example can be found on github + here.

+ +

JSCompiler Flags

+

Reminder: According to the JS style guide, customer facing code must be compiled.

+ +

Recommended: Use the JSCompiler (the closure compiler that works with js_binary by + default) and ANGULAR_COMPILER_FLAGS_FULL from //javascript/angular/build_defs/build_defs for + your base flags. +

+ +

Note - if you are using @export for methods, you will need to add the compiler flag

+
+"--generate_exports",
+
+ +

If you are using @export for properties, you will need to add the flags:

+
+"--generate_exports",
+"--remove_unused_prototype_props_in_externs=false",
+"--export_local_property_definitions",
+
+ +

Controllers and Scopes

+

Controllers are classes. Methods should be defined on MyCtrl.prototype.

+ +

Google Angular applications should use the 'controller as' style to export the controller + onto the scope. This is fully implemented in Angular 1.2 and can be mimicked in pre-Angular 1.2 + builds. +

+ +

Pre Angular 1.2, this looks like:

+
+/**
+ * Home controller.
+ *
+ * @param {!angular.Scope} $scope
+ * @constructor
+ * @ngInject
+ * @export
+ */
+hello.mainpage.HomeCtrl = function($scope) {
+  /** @export */
+  $scope.homeCtrl = this; // This is a bridge until Angular 1.2 controller-as
+
+  /**
+   * @type {string}
+   * @export
+   */
+  this.myColor = 'blue';
+};
+
+
+/**
+ * @param {number} a
+ * @param {number} b
+ * @export
+ */
+hello.mainpage.HomeCtrl.prototype.add = function(a, b) {
+  return a + b;
+};
+
+ +

And the template:

+ +
+<div ng-controller="hello.mainpage.HomeCtrl"/>
+  <span ng-class="homeCtrl.myColor">I'm in a color!</span>
+  <span>{{homeCtrl.add(5, 6)}}</span>
+</div>
+
+ +

After Angular 1.2, this looks like:

+ +
+/**
+ * Home controller.
+ *
+ * @constructor
+ * @ngInject
+ * @export
+ */
+hello.mainpage.HomeCtrl = function() {
+  /**
+   * @type {string}
+   * @export
+   */
+  this.myColor = 'blue';
+};
+
+
+/**
+ * @param {number} a
+ * @param {number} b
+ * @export
+ */
+hello.mainpage.HomeCtrl.prototype.add = function(a, b) {
+  return a + b;
+};
+
+ +

If you are compiling with property renaming, expose properties and methods using the @export + annotation. Remember to @export the constructor as well.

+ +

And in the template:

+ +
+<div ng-controller="hello.mainpage.HomeCtrl as homeCtrl"/>
+  <span ng-class="homeCtrl.myColor">I'm in a color!</span>
+  <span>{{homeCtrl.add(5, 6)}}</span>
+</div>
+
+ +

Why? + Putting methods and properties directly onto the controller, instead of building up a scope + object, fits better with the Google Closure class style. Additionally, using 'controller as' + makes it obvious which controller you are accessing when multiple controllers apply to an element. + Since there is always a '.' in the bindings, you don't have to worry about prototypal inheritance + masking primitives.

+ +

Directives

+ +

All DOM manipulation should be done inside directives. Directives should be kept small and use + composition. Files defining directives should goog.provide a static function which returns the + directive definition object.

+ +
+goog.provide('hello.pane.paneDirective');
+
+/**
+ * Description and usage
+ * @return {angular.Directive} Directive definition object.
+ */
+hello.pane.paneDirective = function() {
+  // ...
+};
+
+ +

Exception: DOM manipulation may occur in services for DOM elements disconnected from the + rest of the view, e.g. dialogs or keyboard shortcuts.

+ +

Services

+ +

Services registered on the module with module.service are classes. + Use module.service instead of module.provider or + module.factory unless you need to do initialization beyond just creating a + new instance of the class.

+ +
+/**
+ * @param {!angular.$http} $http The Angular http service.
+ * @constructor
+ */
+hello.request.Request = function($http) {
+  /** @type {!angular.$http} */
+  this.http_ = $http;
+};
+
+hello.request.Request.prototype.get = function() {/*...*/};
+
+ +

In the module:

+ +
+module.service('request', hello.request.Request);
+
+ + +

2 Angular Style Rules

+ +

Reserve $ for Angular properties and services

+

Do not use $ to prepend your own object properties and service identifiers. Consider this style + of naming reserved by AngularJS and jQuery.

+ +

Yes:

+
+  $scope.myModel = { value: 'foo' }
+  myModule.service('myService', function() { /*...*/ });
+  var MyCtrl = function($http) {this.http_ = $http;};
+
+ +

No:

+
+  $scope.$myModel = { value: 'foo' } // BAD
+  $scope.myModel = { $value: 'foo' } // BAD
+  myModule.service('$myService', function() { ... }); // BAD
+  var MyCtrl = function($http) {this.$http_ = $http;}; // BAD
+
+ +

Why? + It's useful to distinguish between Angular / jQuery builtins and things you add yourself. + In addition, $ is not an acceptable character for variables names in the JS style guide. +

+ +

Custom elements

+ +

For custom elements (e.g. <ng-include src="template"></ng-include>), IE8 + requires special support (html5shiv-like hacks) to enable css styling. Be aware of this + restriction in apps targeting old versions of IE.

+ +

3 Angular Tips, Tricks, and Best Practices

+ +

These are not strict style guide rules, but are placed here as reference for folks getting + started with Angular at Google.

+ +

Testing

+ +

Angular is designed for test-driven development.

+ +

The recommended unit testing setup is Jasmine + Karma (though you could use closure tests + or js_test)

+ +

Angular provides easy adapters to load modules and use the injector in Jasmine tests. +

+

+ + +

Consider using the Best Practices for App Structure

+

+ This directory structure doc describes how to structure your application with controllers in + nested subdirectories and all components (e.g. services and directives) in a 'components' dir. +

+ + +

Be aware of how scope inheritance works

+ +

See + The Nuances of Scope Prototypal Inheritance

+ +

Use @ngInject for easy dependency injection compilation

+

This removes the need to add myCtrl['$inject'] = ... to prevent minification from + messing up Angular's dependency injection.

+ +

Usage:

+
+/**
+ * My controller.
+ * @param {!angular.$http} $http
+ * @param {!my.app.myService} myService
+ * @constructor
+ * @export
+ * @ngInject
+ */
+my.app.MyCtrl = function($http, myService) {
+  //...
+};
+
+ +

4 Best practices links and docs

+ + +
+ Last modified Feb 07 2013 +
+ + diff --git a/cppguide.html b/cppguide.html new file mode 100644 index 000000000..590cc9f26 --- /dev/null +++ b/cppguide.html @@ -0,0 +1,6170 @@ + + + + +Google C++ Style Guide + + + + + +
+

Google C++ Style Guide

+
+ +
+ + + +

C++ is one of the main development languages used by +many of Google's open-source projects. As every C++ +programmer knows, the language has many powerful features, but +this power brings with it complexity, which in turn can make +code more bug-prone and harder to read and maintain.

+ +

The goal of this guide is to manage this complexity by +describing in detail the dos and don'ts of writing C++ code. +These rules exist to +keep the code base manageable while still allowing +coders to use C++ language features productively.

+ +

Style, also known as readability, is what we call +the conventions that govern our C++ code. The term Style is a +bit of a misnomer, since these conventions cover far more than +just source file formatting.

+ +

+Most open-source projects developed by +Google conform to the requirements in this guide. +

+ + + + + +

Note that this guide is not a C++ tutorial: we assume that +the reader is familiar with the language.

+ +

Goals of the Style Guide

+
+

Why do we have this document?

+ +

There are a few core goals that we believe this guide should +serve. These are the fundamental whys that +underlie all of the individual rules. By bringing these ideas to +the fore, we hope to ground discussions and make it clearer to our +broader community why the rules are in place and why particular +decisions have been made. If you understand what goals each rule is +serving, it should be clearer to everyone when a rule may be waived +(some can be), and what sort of argument or alternative would be +necessary to change a rule in the guide.

+ +

The goals of the style guide as we currently see them are as follows:

+
+
Style rules should pull their weight
+
The benefit of a style rule +must be large enough to justify asking all of our engineers to +remember it. The benefit is measured relative to the codebase we would +get without the rule, so a rule against a very harmful practice may +still have a small benefit if people are unlikely to do it +anyway. This principle mostly explains the rules we don’t have, rather +than the rules we do: for example, goto contravenes many +of the following principles, but is already vanishingly rare, so the Style +Guide doesn’t discuss it.
+ +
Optimize for the reader, not the writer
+
Our codebase (and most individual components submitted to it) is +expected to continue for quite some time. As a result, more time will +be spent reading most of our code than writing it. We explicitly +choose to optimize for the experience of our average software engineer +reading, maintaining, and debugging code in our codebase rather than +ease when writing said code. "Leave a trace for the reader" is a +particularly common sub-point of this principle: When something +surprising or unusual is happening in a snippet of code (for example, +transfer of pointer ownership), leaving textual hints for the reader +at the point of use is valuable (std::unique_ptr +demonstrates the ownership transfer unambiguously at the call +site).
+ +
Be consistent with existing code
+
Using one style consistently through our codebase lets us focus on +other (more important) issues. Consistency also allows for +automation: tools that format your code or adjust +your #includes only work properly when your code is +consistent with the expectations of the tooling. In many cases, rules +that are attributed to "Be Consistent" boil down to "Just pick one and +stop worrying about it"; the potential value of allowing flexibility +on these points is outweighed by the cost of having people argue over +them.
+ +
Be consistent with the broader C++ community when appropriate
+
Consistency with the way other organizations use C++ has value for +the same reasons as consistency within our code base. If a feature in +the C++ standard solves a problem, or if some idiom is widely known +and accepted, that's an argument for using it. However, sometimes +standard features and idioms are flawed, or were just designed without +our codebase's needs in mind. In those cases (as described below) it's +appropriate to constrain or ban standard features. In some cases we +prefer a homegrown or third-party library over a library defined in +the C++ Standard, either out of perceived superiority or insufficient +value to transition the codebase to the standard interface.
+ +
Avoid surprising or dangerous constructs
+
C++ has features that are more surprising or dangerous than one +might think at a glance. Some style guide restrictions are in place to +prevent falling into these pitfalls. There is a high bar for style +guide waivers on such restrictions, because waiving such rules often +directly risks compromising program correctness. +
+ +
Avoid constructs that our average C++ programmer would find tricky +or hard to maintain
+
C++ has features that may not be generally appropriate because of +the complexity they introduce to the code. In widely used +code, it may be more acceptable to use +trickier language constructs, because any benefits of more complex +implementation are multiplied widely by usage, and the cost in understanding +the complexity does not need to be paid again when working with new +portions of the codebase. When in doubt, waivers to rules of this type +can be sought by asking +your project leads. This is specifically +important for our codebase because code ownership and team membership +changes over time: even if everyone that works with some piece of code +currently understands it, such understanding is not guaranteed to hold a +few years from now.
+ +
Be mindful of our scale
+
With a codebase of 100+ million lines and thousands of engineers, +some mistakes and simplifications for one engineer can become costly +for many. For instance it's particularly important to +avoid polluting the global namespace: name collisions across a +codebase of hundreds of millions of lines are difficult to work with +and hard to avoid if everyone puts things into the global +namespace.
+ +
Concede to optimization when necessary
+
Performance optimizations can sometimes be necessary and +appropriate, even when they conflict with the other principles of this +document.
+
+ +

The intent of this document is to provide maximal guidance with +reasonable restriction. As always, common sense and good taste should +prevail. By this we specifically refer to the established conventions +of the entire Google C++ community, not just your personal preferences +or those of your team. Be skeptical about and reluctant to use +clever or unusual constructs: the absence of a prohibition is not the +same as a license to proceed. Use your judgment, and if you are +unsure, please don't hesitate to ask your project leads to get additional +input.

+ +
+ + + +

Header Files

+ +

In general, every .cc file should have an +associated .h file. There are some common +exceptions, such as unittests and +small .cc files containing just a +main() function.

+ +

Correct use of header files can make a huge difference to +the readability, size and performance of your code.

+ +

The following rules will guide you through the various +pitfalls of using header files.

+ + +

Self-contained Headers

+ +
+

Header files should be self-contained (compile on their own) and +end in .h. Non-header files that are meant for inclusion +should end in .inc and be used sparingly.

+
+ +
+

All header files should be self-contained. Users and refactoring +tools should not have to adhere to special conditions to include the +header. Specifically, a header should +have header guards and include all +other headers it needs.

+ +

Prefer placing the definitions for template and inline functions in +the same file as their declarations. The definitions of these +constructs must be included into every .cc file that uses +them, or the program may fail to link in some build configurations. If +declarations and definitions are in different files, including the +former should transitively include the latter. Do not move these +definitions to separately included header files (-inl.h); +this practice was common in the past, but is no longer allowed.

+ +

As an exception, a template that is explicitly instantiated for +all relevant sets of template arguments, or that is a private +implementation detail of a class, is allowed to be defined in the one +and only .cc file that instantiates the template.

+ +

There are rare cases where a file designed to be included is not +self-contained. These are typically intended to be included at unusual +locations, such as the middle of another file. They might not +use header guards, and might not include +their prerequisites. Name such files with the .inc +extension. Use sparingly, and prefer self-contained headers when +possible.

+ +
+ +

The #define Guard

+ +
+

All header files should have #define guards to +prevent multiple inclusion. The format of the symbol name +should be +<PROJECT>_<PATH>_<FILE>_H_.

+
+ +
+ + + +

To guarantee uniqueness, they should +be based on the full path in a project's source tree. For +example, the file foo/src/bar/baz.h in +project foo should have the following +guard:

+ +
#ifndef FOO_BAR_BAZ_H_
+#define FOO_BAR_BAZ_H_
+
+...
+
+#endif  // FOO_BAR_BAZ_H_
+
+ + + + +
+ +

Forward Declarations

+ +
+

Avoid using forward declarations where possible. + Just #include the headers you need.

+
+ +
+ +
+

A "forward declaration" is a declaration of a class, +function, or template without an associated definition.

+
+ +
+
    +
  • Forward declarations can save compile time, as + #includes force the compiler to open + more files and process more input.
  • + +
  • Forward declarations can save on unnecessary + recompilation. #includes can force + your code to be recompiled more often, due to unrelated + changes in the header.
  • +
+
+ +
+
    +
  • Forward declarations can hide a dependency, allowing + user code to skip necessary recompilation when headers + change.
  • + +
  • A forward declaration may be broken by subsequent + changes to the library. Forward declarations of functions + and templates can prevent the header owners from making + otherwise-compatible changes to their APIs, such as + widening a parameter type, adding a template parameter + with a default value, or migrating to a new namespace.
  • + +
  • Forward declaring symbols from namespace + std:: yields undefined behavior.
  • + +
  • It can be difficult to determine whether a forward + declaration or a full #include is needed. + Replacing an #include with a forward + declaration can silently change the meaning of + code: +
          // b.h:
    +      struct B {};
    +      struct D : B {};
    +
    +      // good_user.cc:
    +      #include "b.h"
    +      void f(B*);
    +      void f(void*);
    +      void test(D* x) { f(x); }  // calls f(B*)
    +      
    + If the #include was replaced with forward + decls for B and D, + test() would call f(void*). +
  • + +
  • Forward declaring multiple symbols from a header + can be more verbose than simply + #includeing the header.
  • + +
  • Structuring code to enable forward declarations + (e.g. using pointer members instead of object members) + can make the code slower and more complex.
  • + + +
+
+ +
+
    +
  • Try to avoid forward declarations of entities + defined in another project.
  • + +
  • When using a function declared in a header file, + always #include that header.
  • + +
  • When using a class template, prefer to + #include its header file.
  • +
+ +

Please see Names and Order +of Includes for rules about when to #include a header.

+
+ +
+ +

Inline Functions

+ +
+

Define functions inline only when they are small, say, 10 +lines or fewer.

+
+ +
+ +
+

You can declare functions in a way that allows the compiler to expand +them inline rather than calling them through the usual +function call mechanism.

+
+ +
+

Inlining a function can generate more efficient object +code, as long as the inlined function is small. Feel free +to inline accessors and mutators, and other short, +performance-critical functions.

+
+ +
+

Overuse of inlining can actually make programs slower. +Depending on a function's size, inlining it can cause the +code size to increase or decrease. Inlining a very small +accessor function will usually decrease code size while +inlining a very large function can dramatically increase +code size. On modern processors smaller code usually runs +faster due to better use of the instruction cache.

+
+ +
+

A decent rule of thumb is to not inline a function if +it is more than 10 lines long. Beware of destructors, +which are often longer than they appear because of +implicit member- and base-destructor calls!

+ +

Another useful rule of thumb: it's typically not cost +effective to inline functions with loops or switch +statements (unless, in the common case, the loop or +switch statement is never executed).

+ +

It is important to know that functions are not always +inlined even if they are declared as such; for example, +virtual and recursive functions are not normally inlined. +Usually recursive functions should not be inline. The +main reason for making a virtual function inline is to +place its definition in the class, either for convenience +or to document its behavior, e.g., for accessors and +mutators.

+
+ +
+ +

Names and Order of Includes

+ +
+

Use standard order for readability and to avoid hidden +dependencies: Related header, C library, C++ library, other libraries' +.h, your project's .h.

+
+ +
+

+All of a project's header files should be +listed as descendants of the project's source +directory without use of UNIX directory shortcuts +. (the current directory) or .. +(the parent directory). For example, + +google-awesome-project/src/base/logging.h +should be included as:

+ +
#include "base/logging.h"
+
+ +

In dir/foo.cc or +dir/foo_test.cc, whose main +purpose is to implement or test the stuff in +dir2/foo2.h, order your includes +as follows:

+ +
    +
  1. dir2/foo2.h.
  2. + +
  3. C system files.
  4. + +
  5. C++ system files.
  6. + +
  7. Other libraries' .h + files.
  8. + +
  9. + Your project's .h + files.
  10. +
+ +

With the preferred ordering, if +dir2/foo2.h omits any necessary +includes, the build of dir/foo.cc +or dir/foo_test.cc will break. +Thus, this rule ensures that build breaks show up first +for the people working on these files, not for innocent +people in other packages.

+ +

dir/foo.cc and +dir2/foo2.h are usually in the same +directory (e.g. base/basictypes_test.cc and +base/basictypes.h), but may sometimes be in different +directories too.

+ + + +

Within each section the includes should be ordered +alphabetically. Note that older code might not conform to +this rule and should be fixed when convenient.

+ +

You should include all the headers that define the symbols you rely +upon, except in the unusual case of forward +declaration. If you rely on symbols from bar.h, +don't count on the fact that you included foo.h which +(currently) includes bar.h: include bar.h +yourself, unless foo.h explicitly demonstrates its intent +to provide you the symbols of bar.h. However, any +includes present in the related header do not need to be included +again in the related cc (i.e., foo.cc can +rely on foo.h's includes).

+ +

For example, the includes in + +google-awesome-project/src/foo/internal/fooserver.cc +might look like this:

+ + +
#include "foo/server/fooserver.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <hash_map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/commandlineflags.h"
+#include "foo/server/bar.h"
+
+ +

Sometimes, system-specific code needs +conditional includes. Such code can put conditional +includes after other includes. Of course, keep your +system-specific code small and localized. Example:

+ +
#include "foo/public/fooserver.h"
+
+#include "base/port.h"  // For LANG_CXX11.
+
+#ifdef LANG_CXX11
+#include <initializer_list>
+#endif  // LANG_CXX11
+
+ +
+ +

Scoping

+ +

Namespaces

+ +
+

With few exceptions, place code in a namespace. Namespaces +should have unique names based on the project name, and possibly +its path. Do not use using-directives (e.g. +using namespace foo). Do not use +inline namespaces. For unnamed namespaces, see +Unnamed Namespaces and +Static Variables. +

+ +
+ +
+

Namespaces subdivide the global scope +into distinct, named scopes, and so are useful for preventing +name collisions in the global scope.

+
+ +
+ +

Namespaces provide a method for preventing name conflicts +in large programs while allowing most code to use reasonably +short names.

+ +

For example, if two different projects have a class +Foo in the global scope, these symbols may +collide at compile time or at runtime. If each project +places their code in a namespace, project1::Foo +and project2::Foo are now distinct symbols that +do not collide, and code within each project's namespace +can continue to refer to Foo without the prefix.

+ +

Inline namespaces automatically place their names in +the enclosing scope. Consider the following snippet, for +example:

+ +
namespace X {
+inline namespace Y {
+  void foo();
+}  // namespace Y
+}  // namespace X
+
+ +

The expressions X::Y::foo() and +X::foo() are interchangeable. Inline +namespaces are primarily intended for ABI compatibility +across versions.

+
+ +
+ +

Namespaces can be confusing, because they complicate +the mechanics of figuring out what definition a name refers +to.

+ +

Inline namespaces, in particular, can be confusing +because names aren't actually restricted to the namespace +where they are declared. They are only useful as part of +some larger versioning policy.

+ +

In some contexts, it's necessary to repeatedly refer to +symbols by their fully-qualified names. For deeply-nested +namespaces, this can add a lot of clutter.

+
+ +
+ +

Namespaces should be used as follows:

+ +
    +
  • Follow the rules on Namespace Names. +
  • Terminate namespaces with comments as shown in the given examples. +
  • + +

    Namespaces wrap the entire source file after + includes, + + gflags definitions/declarations + and forward declarations of classes from other namespaces.

    + +
    // In the .h file
    +namespace mynamespace {
    +
    +// All declarations are within the namespace scope.
    +// Notice the lack of indentation.
    +class MyClass {
    + public:
    +  ...
    +  void Foo();
    +};
    +
    +}  // namespace mynamespace
    +
    + +
    // In the .cc file
    +namespace mynamespace {
    +
    +// Definition of functions is within scope of the namespace.
    +void MyClass::Foo() {
    +  ...
    +}
    +
    +}  // namespace mynamespace
    +
    + +

    More complex .cc files might have additional details, + like flags or using-declarations.

    + +
    #include "a.h"
    +
    +DEFINE_FLAG(bool, someflag, false, "dummy flag");
    +
    +namespace a {
    +
    +using ::foo::bar;
    +
    +...code for a...         // Code goes against the left margin.
    +
    +}  // namespace a
    +
    +
  • + + + +
  • Do not declare anything in namespace + std, including forward declarations of + standard library classes. Declaring entities in + namespace std is undefined behavior, i.e., + not portable. To declare entities from the standard + library, include the appropriate header file.
  • + +
  • You may not use a using-directive + to make all names from a namespace available.

    + +
    // Forbidden -- This pollutes the namespace.
    +using namespace foo;
    +
    +
  • + +
  • Do not use Namespace aliases at namespace scope + in header files except in explicitly marked + internal-only namespaces, because anything imported into a namespace + in a header file becomes part of the public + API exported by that file.

    + +
    // Shorten access to some commonly used names in .cc files.
    +namespace baz = ::foo::bar::baz;
    +
    + +
    // Shorten access to some commonly used names (in a .h file).
    +namespace librarian {
    +namespace impl {  // Internal, not part of the API.
    +namespace sidetable = ::pipeline_diagnostics::sidetable;
    +}  // namespace impl
    +
    +inline void my_inline_function() {
    +  // namespace alias local to a function (or method).
    +  namespace baz = ::foo::bar::baz;
    +  ...
    +}
    +}  // namespace librarian
    +
    + +
  • Do not use inline namespaces.
  • +
+
+
+ +

Unnamed Namespaces and Static +Variables

+ +
+

When definitions in a .cc file do not need to be +referenced outside that file, place them in an unnamed +namespace or declare them static. Do not use either +of these constructs in .h files. +

+ +
+ +
+

All declarations can be given internal linkage by placing them in +unnamed namespaces, and functions and variables can be given internal linkage by +declaring them static. This means that anything you're declaring +can't be accessed from another file. If a different file declares something +with the same name, then the two entities are completely independent.

+
+ +
+ +

Use of internal linkage in .cc files is encouraged +for all code that does not need to be referenced elsewhere. +Do not use internal linkage in .h files.

+ +

Format unnamed namespaces like named namespaces. In the + terminating comment, leave the namespace name empty:

+ +
namespace {
+...
+}  // namespace
+
+
+
+ +

Nonmember, Static Member, and Global Functions

+ +
+

Prefer placing nonmember functions in a namespace; use completely global +functions rarely. Prefer grouping functions with a namespace instead of +using a class as if it were a namespace. Static methods of a class should +generally be closely related to instances of the class or the class's static +data.

+
+ +
+ +
+

Nonmember and static member functions can be useful in + some situations. Putting nonmember functions in a + namespace avoids polluting the global namespace.

+
+ +
+

Nonmember and static member functions may make more sense +as members of a new class, especially if they access +external resources or have significant dependencies.

+
+ +
+

Sometimes it is useful to define a +function not bound to a class instance. Such a function +can be either a static member or a nonmember function. +Nonmember functions should not depend on external +variables, and should nearly always exist in a namespace. +Rather than creating classes only to group static member +functions which do not share static data, use +namespaces instead. For a header +myproject/foo_bar.h, for example, write

+
namespace myproject {
+namespace foo_bar {
+void Function1();
+void Function2();
+}  // namespace foo_bar
+}  // namespace myproject
+
+

instead of

+
namespace myproject {
+class FooBar {
+ public:
+  static void Function1();
+  static void Function2();
+};
+}  // namespace myproject
+
+ +

If you define a nonmember function and it is only +needed in its .cc file, use +internal linkage to limit +its scope.

+
+ +
+ +

Local Variables

+ +
+

Place a function's variables in the narrowest scope +possible, and initialize variables in the declaration.

+
+ +
+ +

C++ allows you to declare variables anywhere in a +function. We encourage you to declare them in as local a +scope as possible, and as close to the first use as +possible. This makes it easier for the reader to find the +declaration and see what type the variable is and what it +was initialized to. In particular, initialization should +be used instead of declaration and assignment, e.g.:

+ +
int i;
+i = f();      // Bad -- initialization separate from declaration.
+
+ +
int j = g();  // Good -- declaration has initialization.
+
+ +
std::vector<int> v;
+v.push_back(1);  // Prefer initializing using brace initialization.
+v.push_back(2);
+
+ +
std::vector<int> v = {1, 2};  // Good -- v starts initialized.
+
+ +

Variables needed for if, while +and for statements should normally be declared +within those statements, so that such variables are confined +to those scopes. E.g.:

+ +
while (const char* p = strchr(str, '/')) str = p + 1;
+
+ +

There is one caveat: if the variable is an object, its +constructor is invoked every time it enters scope and is +created, and its destructor is invoked every time it goes +out of scope.

+ +
// Inefficient implementation:
+for (int i = 0; i < 1000000; ++i) {
+  Foo f;  // My ctor and dtor get called 1000000 times each.
+  f.DoSomething(i);
+}
+
+ +

It may be more efficient to declare such a variable +used in a loop outside that loop:

+ +
Foo f;  // My ctor and dtor get called once each.
+for (int i = 0; i < 1000000; ++i) {
+  f.DoSomething(i);
+}
+
+ +
+ +

Static and Global Variables

+ +
+

Variables of class type with + static storage duration are forbidden: they cause hard-to-find bugs due + to indeterminate order of construction and destruction. However, such + variables are allowed if they are constexpr: they have no + dynamic initialization or destruction.

+
+ +
+ +

Objects with static storage duration, including global +variables, static variables, static class member +variables, and function static variables, must be Plain +Old Data (POD): only ints, chars, floats, or pointers, or +arrays/structs of POD.

+ +

The order in which class constructors and initializers +for static variables are called is only partially +specified in C++ and can even change from build to build, +which can cause bugs that are difficult to find. +Therefore in addition to banning globals of class type, +we do not allow non-local static variables to be initialized +with the result of a function, unless that function (such +as getenv(), or getpid()) does not itself depend on any +other globals. However, a static POD variable within +function scope may be initialized with the result of a +function, since its initialization order is well-defined +and does not occur until control passes through its +declaration.

+ +

Likewise, global and static variables are destroyed +when the program terminates, regardless of whether the +termination is by returning from main() or +by calling exit(). The order in which +destructors are called is defined to be the reverse of +the order in which the constructors were called. Since +constructor order is indeterminate, so is destructor +order. For example, at program-end time a static variable +might have been destroyed, but code still running +— perhaps in another thread +— tries to access it and fails. Or the +destructor for a static string variable +might be run prior to the destructor for another variable +that contains a reference to that string.

+ +

One way to alleviate the destructor problem is to +terminate the program by calling +quick_exit() instead of exit(). +The difference is that quick_exit() does not +invoke destructors and does not invoke any handlers that +were registered by calling atexit(). If you +have a handler that needs to run when a program +terminates via quick_exit() (flushing logs, +for example), you can register it using +at_quick_exit(). (If you have a handler that +needs to run at both exit() and +quick_exit(), you need to register it in +both places.)

+ +

As a result we only allow static variables to contain +POD data. This rule completely disallows +std::vector (use C arrays instead), or +string (use const char []).

+ + + +

If you need a static or global +variable of a class type, consider initializing a pointer +(which will never be freed), from either your main() +function or from pthread_once(). Note that this must be a +raw pointer, not a "smart" pointer, since the smart +pointer's destructor will have the order-of-destructor +issue that we are trying to avoid.

+ + + + + +
+ +

Classes

+ +

Classes are the fundamental unit of code in C++. Naturally, +we use them extensively. This section lists the main dos and +don'ts you should follow when writing a class.

+ +

Doing Work in Constructors

+ +
+

Avoid virtual method calls in constructors, and avoid +initialization that can fail if you can't signal an error.

+
+ +
+ +
+

It is possible to perform arbitrary initialization in the body +of the constructor.

+
+ +
+
    +
  • No need to worry about whether the class has been initialized or + not.
  • + +
  • Objects that are fully initialized by constructor call can + be const and may also be easier to use with standard containers + or algorithms.
  • +
+ +
+ +
+
    +
  • If the work calls virtual functions, these calls + will not get dispatched to the subclass + implementations. Future modification to your class can + quietly introduce this problem even if your class is + not currently subclassed, causing much confusion.
  • + +
  • There is no easy way for constructors to signal errors, short of + crashing the program (not always appropriate) or using exceptions + (which are forbidden).
  • + +
  • If the work fails, we now have an object whose initialization + code failed, so it may be an unusual state requiring a bool + IsValid() state checking mechanism (or similar) which is easy + to forget to call.
  • + +
  • You cannot take the address of a constructor, so whatever work + is done in the constructor cannot easily be handed off to, for + example, another thread.
  • +
+
+ + +
+

Constructors should never call virtual functions. If appropriate +for your code +, +terminating the program may be an appropriate error handling +response. Otherwise, consider a factory function +or Init() method. Avoid Init() methods on objects with +no other states that affect which public methods may be called +(semi-constructed objects of this form are particularly hard to work +with correctly).

+
+ +
+ + +

Implicit Conversions

+ +
+

Do not define implicit conversions. Use the explicit +keyword for conversion operators and single-argument +constructors.

+
+ +
+ +
+

Implicit conversions allow an +object of one type (called the source type) to +be used where a different type (called the destination +type) is expected, such as when passing an +int argument to a function that takes a +double parameter.

+ +

In addition to the implicit conversions defined by the language, +users can define their own, by adding appropriate members to the +class definition of the source or destination type. An implicit +conversion in the source type is defined by a type conversion operator +named after the destination type (e.g. operator +bool()). An implicit conversion in the destination +type is defined by a constructor that can take the source type as +its only argument (or only argument with no default value).

+ +

The explicit keyword can be applied to a constructor +or (since C++11) a conversion operator, to ensure that it can only be +used when the destination type is explicit at the point of use, +e.g. with a cast. This applies not only to implicit conversions, but to +C++11's list initialization syntax:

+
class Foo {
+  explicit Foo(int x, double y);
+  ...
+};
+
+void Func(Foo f);
+
+
Func({42, 3.14});  // Error
+
+This kind of code isn't technically an implicit conversion, but the +language treats it as one as far as explicit is concerned. +
+ +
+
    +
  • Implicit conversions can make a type more usable and + expressive by eliminating the need to explicitly name a type + when it's obvious.
  • +
  • Implicit conversions can be a simpler alternative to + overloading.
  • +
  • List initialization syntax is a concise and expressive + way of initializing objects.
  • +
+
+ +
+
    +
  • Implicit conversions can hide type-mismatch bugs, where the + destination type does not match the user's expectation, or + the user is unaware that any conversion will take place.
  • + +
  • Implicit conversions can make code harder to read, particularly + in the presence of overloading, by making it less obvious what + code is actually getting called.
  • + +
  • Constructors that take a single argument may accidentally + be usable as implicit type conversions, even if they are not + intended to do so.
  • + +
  • When a single-argument constructor is not marked + explicit, there's no reliable way to tell whether + it's intended to define an implicit conversion, or the author + simply forgot to mark it.
  • + +
  • It's not always clear which type should provide the conversion, + and if they both do, the code becomes ambiguous.
  • + +
  • List initialization can suffer from the same problems if + the destination type is implicit, particularly if the + list has only a single element.
  • +
+
+ +
+

Type conversion operators, and constructors that are +callable with a single argument, must be marked +explicit in the class definition. As an +exception, copy and move constructors should not be +explicit, since they do not perform type +conversion. Implicit conversions can sometimes be necessary and +appropriate for types that are designed to transparently wrap other +types. In that case, contact +your project leads to request +a waiver of this rule.

+ +

Constructors that cannot be called with a single argument +should usually omit explicit. Constructors that +take a single std::initializer_list parameter should +also omit explicit, in order to support copy-initialization +(e.g. MyType m = {1, 2};).

+
+ +
+ +

Copyable and Movable Types

+ +
+

Support copying and/or moving if these operations are clear and meaningful +for your type. Otherwise, disable the implicitly generated special functions +that perform copies and moves. +

+ +
+ +
+

A copyable type allows its objects to be initialized or assigned +from any other object of the same type, without changing the value of the source. +For user-defined types, the copy behavior is defined by the copy +constructor and the copy-assignment operator. +string is an example of a copyable type.

+ +

A movable type is one that can be initialized and assigned +from temporaries (all copyable types are therefore movable). +std::unique_ptr<int> is an example of a movable but not +copyable type. For user-defined types, the move behavior is defined by the move +constructor and the move-assignment operator.

+ +

The copy/move constructors can be implicitly invoked by the compiler +in some situations, e.g. when passing objects by value.

+
+ +
+

Objects of copyable and movable types can be passed and returned by value, +which makes APIs simpler, safer, and more general. Unlike when passing objects +by pointer or reference, there's no risk of confusion over ownership, +lifetime, mutability, and similar issues, and no need to specify them in the +contract. It also prevents non-local interactions between the client and the +implementation, which makes them easier to understand, maintain, and optimize by +the compiler. Further, such objects can be used with generic APIs that +require pass-by-value, such as most containers, and they allow for additional +flexibility in e.g., type composition.

+ +

Copy/move constructors and assignment operators are usually +easier to define correctly than alternatives +like Clone(), CopyFrom() or Swap(), +because they can be generated by the compiler, either implicitly or +with = default. They are concise, and ensure +that all data members are copied. Copy and move +constructors are also generally more efficient, because they don't +require heap allocation or separate initialization and assignment +steps, and they're eligible for optimizations such as + + +copy elision.

+ +

Move operations allow the implicit and efficient transfer of +resources out of rvalue objects. This allows a plainer coding style +in some cases.

+
+ +
+

Some types do not need to be copyable, and providing copy +operations for such types can be confusing, nonsensical, or outright +incorrect. Types representing singleton objects (Registerer), +objects tied to a specific scope (Cleanup), or closely coupled to +object identity (Mutex) cannot be copied meaningfully. +Copy operations for base class types that are to be used +polymorphically are hazardous, because use of them can lead to +object slicing. +Defaulted or carelessly-implemented copy operations can be incorrect, and the +resulting bugs can be confusing and difficult to diagnose.

+ +

Copy constructors are invoked implicitly, which makes the +invocation easy to miss. This may cause confusion for programmers used to +languages where pass-by-reference is conventional or mandatory. It may also +encourage excessive copying, which can cause performance problems.

+
+ +
+ +

Provide the copy and move operations if their meaning is clear to a casual +user and the copying/moving does not incur unexpected costs. If you define a +copy or move constructor, define the corresponding assignment operator, and +vice-versa. If your type is copyable, do not define move operations unless they +are significantly more efficient than the corresponding copy operations. If your +type is not copyable, but the correctness of a move is obvious to users of the +type, you may make the type move-only by defining both of the move operations. +

+ +

If your type provides copy operations, it is recommended that you design +your class so that the default implementation of those operations is correct. +Remember to review the correctness of any defaulted operations as you would any +other code, and to document that your class is copyable and/or cheaply movable +if that's an API guarantee.

+ +
class Foo {
+ public:
+  Foo(Foo&& other) : field_(other.field) {}
+  // Bad, defines only move constructor, but not operator=.
+
+ private:
+  Field field_;
+};
+
+ +

Due to the risk of slicing, avoid providing an assignment +operator or public copy/move constructor for a class that's +intended to be derived from (and avoid deriving from a class +with such members). If your base class needs to be +copyable, provide a public virtual Clone() +method, and a protected copy constructor that derived classes +can use to implement it.

+ +

If you do not want to support copy/move operations on your type, +explicitly disable them using = delete in +the public: section:

+ +
// MyClass is neither copyable nor movable.
+MyClass(const MyClass&) = delete;
+MyClass& operator=(const MyClass&) = delete;
+
+ +

+ +
+
+ +

Structs vs. Classes

+ +
+

Use a struct only for passive objects that + carry data; everything else is a class.

+
+ +
+ +

The struct and class +keywords behave almost identically in C++. We add our own +semantic meanings to each keyword, so you should use the +appropriate keyword for the data-type you're +defining.

+ +

structs should be used for passive +objects that carry data, and may have associated +constants, but lack any functionality other than +access/setting the data members. The accessing/setting of +fields is done by directly accessing the fields rather +than through method invocations. Methods should not +provide behavior but should only be used to set up the +data members, e.g., constructor, destructor, +Initialize(), Reset(), +Validate().

+ +

If more functionality is required, a +class is more appropriate. If in doubt, make +it a class.

+ +

For consistency with STL, you can use +struct instead of class for +functors and traits.

+ +

Note that member variables in structs and classes have +different naming rules.

+ +
+ +

Inheritance

+ +
+

Composition is often more appropriate than inheritance. +When using inheritance, make it public.

+
+ +
+ +
+

When a sub-class +inherits from a base class, it includes the definitions +of all the data and operations that the parent base class +defines. In practice, inheritance is used in two major +ways in C++: implementation inheritance, in which actual +code is inherited by the child, and +interface inheritance, in which +only method names are inherited.

+
+ +
+

Implementation inheritance reduces code size by re-using +the base class code as it specializes an existing type. +Because inheritance is a compile-time declaration, you +and the compiler can understand the operation and detect +errors. Interface inheritance can be used to +programmatically enforce that a class expose a particular +API. Again, the compiler can detect errors, in this case, +when a class does not define a necessary method of the +API.

+
+ +
+

For implementation inheritance, because the code +implementing a sub-class is spread between the base and +the sub-class, it can be more difficult to understand an +implementation. The sub-class cannot override functions +that are not virtual, so the sub-class cannot change +implementation. The base class may also define some data +members, so that specifies physical layout of the base +class.

+
+ +
+ +

All inheritance should be public. If you +want to do private inheritance, you should be including +an instance of the base class as a member instead.

+ +

Do not overuse implementation inheritance. Composition +is often more appropriate. Try to restrict use of +inheritance to the "is-a" case: Bar +subclasses Foo if it can reasonably be said +that Bar "is a kind of" +Foo.

+ +

Make your destructor virtual if +necessary. If your class has virtual methods, its +destructor should be virtual.

+ +

Limit the use of protected to those +member functions that might need to be accessed from +subclasses. Note that data +members should be private.

+ +

Explicitly annotate overrides of virtual functions +or virtual destructors with an override +or (less frequently) final specifier. +Older (pre-C++11) code will use the +virtual keyword as an inferior +alternative annotation. For clarity, use exactly one of +override, final, or +virtual when declaring an override. +Rationale: A function or destructor marked +override or final that is +not an override of a base class virtual function will +not compile, and this helps catch common errors. The +specifiers serve as documentation; if no specifier is +present, the reader has to check all ancestors of the +class in question to determine if the function or +destructor is virtual or not.

+
+ +
+ +

Multiple Inheritance

+ +
+

Only very rarely is multiple implementation inheritance +actually useful. We allow multiple inheritance only when at +most one of the base classes has an implementation; all +other base classes must be pure +interface classes tagged with the +Interface suffix.

+
+ +
+ +
+

Multiple inheritance allows a sub-class to have more than +one base class. We distinguish between base classes that are +pure interfaces and those that have an +implementation.

+
+ +
+

Multiple implementation inheritance may let you re-use +even more code than single inheritance (see Inheritance).

+
+ +
+

Only very rarely is multiple implementation +inheritance actually useful. When multiple implementation +inheritance seems like the solution, you can usually find +a different, more explicit, and cleaner solution.

+
+ +
+

Multiple inheritance is allowed only when all +superclasses, with the possible exception of the first one, +are pure interfaces. In order to +ensure that they remain pure interfaces, they must end with +the Interface suffix.

+
+ +
+

There is an exception to +this rule on Windows.

+
+ +
+ +

Interfaces

+ +
+

Classes that satisfy certain conditions are allowed, but +not required, to end with an Interface suffix.

+
+ +
+ +
+

A class is a pure interface if it meets the following +requirements:

+ +
    +
  • It has only public pure virtual ("= + 0") methods and static methods (but see below + for destructor).
  • + +
  • It may not have non-static data members.
  • + +
  • It need not have any constructors defined. If a + constructor is provided, it must take no arguments and + it must be protected.
  • + +
  • If it is a subclass, it may only be derived from + classes that satisfy these conditions and are tagged + with the Interface suffix.
  • +
+ +

An interface class can never be directly instantiated +because of the pure virtual method(s) it declares. To +make sure all implementations of the interface can be +destroyed correctly, the interface must also declare a +virtual destructor (in an exception to the first rule, +this should not be pure). See Stroustrup, The C++ +Programming Language, 3rd edition, section 12.4 +for details.

+
+ +
+

Tagging a class with the Interface suffix +lets others know that they must not add implemented +methods or non static data members. This is particularly +important in the case of multiple inheritance. +Additionally, the interface concept is already +well-understood by Java programmers.

+
+ +
+

The Interface suffix lengthens the class +name, which can make it harder to read and understand. +Also, the interface property may be considered an +implementation detail that shouldn't be exposed to +clients.

+
+ +
+

A class may end +with Interface only if it meets the above +requirements. We do not require the converse, however: +classes that meet the above requirements are not required +to end with Interface.

+
+ +
+ +

Operator Overloading

+ +
+

Overload operators judiciously. Do not create user-defined literals.

+
+ +
+ +
+

C++ permits user code to +declare +overloaded versions of the built-in operators using the +operator keyword, so long as one of the parameters +is a user-defined type. The operator keyword also +permits user code to define new kinds of literals using +operator"", and to define type-conversion functions +such as operator bool().

+
+ +
+

Operator overloading can make code more concise and +intuitive by enabling user-defined types to behave the same +as built-in types. Overloaded operators are the idiomatic names +for certain operations (e.g. ==, <, +=, and <<), and adhering to +those conventions can make user-defined types more readable +and enable them to interoperate with libraries that expect +those names.

+ +

User-defined literals are a very concise notation for +creating objects of user-defined types.

+
+ +
+
    +
  • Providing a correct, consistent, and unsurprising + set of operator overloads requires some care, and failure + to do so can lead to confusion and bugs.
  • + +
  • Overuse of operators can lead to obfuscated code, + particularly if the overloaded operator's semantics + don't follow convention.
  • + +
  • The hazards of function overloading apply just as + much to operator overloading, if not more so.
  • + +
  • Operator overloads can fool our intuition into + thinking that expensive operations are cheap, built-in + operations.
  • + +
  • Finding the call sites for overloaded operators may + require a search tool that's aware of C++ syntax, rather + than e.g. grep.
  • + +
  • If you get the argument type of an overloaded operator + wrong, you may get a different overload rather than a + compiler error. For example, foo < bar + may do one thing, while &foo < &bar + does something totally different.
  • + +
  • Certain operator overloads are inherently hazardous. + Overloading unary & can cause the same + code to have different meanings depending on whether + the overload declaration is visible. Overloads of + &&, ||, and , + (comma) cannot match the evaluation-order semantics of the + built-in operators.
  • + +
  • Operators are often defined outside the class, + so there's a risk of different files introducing + different definitions of the same operator. If both + definitions are linked into the same binary, this results + in undefined behavior, which can manifest as subtle + run-time bugs.
  • + +
  • User-defined literals allow the creation of new + syntactic forms that are unfamiliar even to experienced C++ + programmers.
  • +
+
+ +
+

Define overloaded operators only if their meaning is +obvious, unsurprising, and consistent with the corresponding +built-in operators. For example, use | as a +bitwise- or logical-or, not as a shell-style pipe.

+ +

Define operators only on your own types. More precisely, +define them in the same headers, .cc files, and namespaces +as the types they operate on. That way, the operators are available +wherever the type is, minimizing the risk of multiple +definitions. If possible, avoid defining operators as templates, +because they must satisfy this rule for any possible template +arguments. If you define an operator, also define +any related operators that make sense, and make sure they +are defined consistently. For example, if you overload +<, overload all the comparison operators, +and make sure < and > never +return true for the same arguments.

+ +

Prefer to define non-modifying binary operators as +non-member functions. If a binary operator is defined as a +class member, implicit conversions will apply to the +right-hand argument, but not the left-hand one. It will +confuse your users if a < b compiles but +b < a doesn't.

+ +

Don't go out of your way to avoid defining operator +overloads. For example, prefer to define ==, +=, and <<, rather than +Equals(), CopyFrom(), and +PrintTo(). Conversely, don't define +operator overloads just because other libraries expect +them. For example, if your type doesn't have a natural +ordering, but you want to store it in a std::set, +use a custom comparator rather than overloading +<.

+ +

Do not overload &&, ||, +, (comma), or unary &. Do not overload +operator"", i.e. do not introduce user-defined +literals.

+ +

Type conversion operators are covered in the section on +implicit conversions. +The = operator is covered in the section on +copy constructors. Overloading +<< for use with streams is covered in the +section on streams. See also the rules on +function overloading, which +apply to operator overloading as well.

+
+ +
+ +

Access Control

+ +
+

Make data members private, unless they are +static const (and follow the +naming convention for constants). For technical +reasons, we allow data members of a test fixture class to +be protected when using + + +Google +Test).

+
+ +

Declaration Order

+ +
+

Group similar declarations together, placing public parts +earlier.

+
+ +
+ +

A class definition should usually start with a +public: section, followed by +protected:, then private:. Omit +sections that would be empty.

+ +

Within each section, generally prefer grouping similar +kinds of declarations together, and generally prefer the +following order: types (including typedef, +using, and nested structs and classes), +constants, factory functions, constructors, assignment +operators, destructor, all other methods, data members.

+ +

Do not put large method definitions inline in the +class definition. Usually, only trivial or +performance-critical, and very short, methods may be +defined inline. See Inline +Functions for more details.

+ +
+ +

Functions

+ +

Parameter Ordering

+ +
+

When defining a function, parameter order is: inputs, then +outputs.

+
+ +
+

Parameters to C/C++ functions are either input to the +function, output from the function, or both. Input +parameters are usually values or const +references, while output and input/output parameters will +be pointers to non-const. When ordering +function parameters, put all input-only parameters before +any output parameters. In particular, do not add new +parameters to the end of the function just because they +are new; place new input-only parameters before the +output parameters.

+ +

This is not a hard-and-fast rule. Parameters that are +both input and output (often classes/structs) muddy the +waters, and, as always, consistency with related +functions may require you to bend the rule.

+ +
+ +

Write Short Functions

+ +
+

Prefer small and focused functions.

+
+ +
+

We recognize that long functions are sometimes +appropriate, so no hard limit is placed on functions +length. If a function exceeds about 40 lines, think about +whether it can be broken up without harming the structure +of the program.

+ +

Even if your long function works perfectly now, +someone modifying it in a few months may add new +behavior. This could result in bugs that are hard to +find. Keeping your functions short and simple makes it +easier for other people to read and modify your code.

+ +

You could find long and complicated functions when +working with +some code. Do not be +intimidated by modifying existing code: if working with +such a function proves to be difficult, you find that +errors are hard to debug, or you want to use a piece of +it in several different contexts, consider breaking up +the function into smaller and more manageable pieces.

+ +
+ +

Reference Arguments

+ +
+

All parameters passed by reference must be labeled +const.

+
+ +
+ +
+

In C, if a +function needs to modify a variable, the parameter must +use a pointer, eg int foo(int *pval). In +C++, the function can alternatively declare a reference +parameter: int foo(int &val).

+
+ +
+

Defining a parameter as reference avoids ugly code like +(*pval)++. Necessary for some applications +like copy constructors. Makes it clear, unlike with +pointers, that a null pointer is not a possible +value.

+
+ +
+

References can be confusing, as they have value syntax +but pointer semantics.

+
+ +
+

Within function parameter lists all references must be +const:

+ +
void Foo(const string &in, string *out);
+
+ +

In fact it is a very strong convention in Google code +that input arguments are values or const +references while output arguments are pointers. Input +parameters may be const pointers, but we +never allow non-const reference parameters +except when required by convention, e.g., +swap().

+ +

However, there are some instances where using +const T* is preferable to const +T& for input parameters. For example:

+ +
    +
  • You want to pass in a null pointer.
  • + +
  • The function saves a pointer or reference to the + input.
  • +
+ +

Remember that most of the time input +parameters are going to be specified as const +T&. Using const T* instead +communicates to the reader that the input is somehow +treated differently. So if you choose const +T* rather than const T&, do so +for a concrete reason; otherwise it will likely confuse +readers by making them look for an explanation that +doesn't exist.

+
+ +
+ +

Function Overloading

+ +
+

Use overloaded functions (including constructors) only if a +reader looking at a call site can get a good idea of what +is happening without having to first figure out exactly +which overload is being called.

+
+ +
+ +
+

You may write a function that takes a const +string& and overload it with another that +takes const char*.

+ +
class MyClass {
+ public:
+  void Analyze(const string &text);
+  void Analyze(const char *text, size_t textlen);
+};
+
+
+ +
+

Overloading can make code more intuitive by allowing an +identically-named function to take different arguments. +It may be necessary for templatized code, and it can be +convenient for Visitors.

+
+ +
+

If a function is overloaded by the argument types alone, +a reader may have to understand C++'s complex matching +rules in order to tell what's going on. Also many people +are confused by the semantics of inheritance if a derived +class overrides only some of the variants of a +function.

+
+ +
+

If you want to overload a function, consider qualifying +the name with some information about the arguments, e.g., +AppendString(), AppendInt() +rather than just Append(). If you are +overloading a function to support variable number of +arguments of the same type, consider making it take a +std::vector so that the user can use an +initializer list + to specify the arguments.

+
+ +
+ +

Default Arguments

+ +
+

Default arguments are allowed on non-virtual functions +when the default is guaranteed to always have the same +value. Follow the same restrictions as for function overloading, and +prefer overloaded functions if the readability gained with +default arguments doesn't outweigh the downsides below.

+
+ +
+ +
+

Often you have a function that uses default values, but +occasionally you want to override the defaults. Default +parameters allow an easy way to do this without having to +define many functions for the rare exceptions. Compared +to overloading the function, default arguments have a +cleaner syntax, with less boilerplate and a clearer +distinction between 'required' and 'optional' +arguments.

+
+ +
+

Defaulted arguments are another way to achieve the +semantics of overloaded functions, so all the reasons not to overload +functions apply.

+ +

The defaults for arguments in a virtual function call are +determined by the static type of the target object, and +there's no guarantee that all overrides of a given function +declare the same defaults.

+ +

Default parameters are re-evaluated at each call site, +which can bloat the generated code. Readers may also expect +the default's value to be fixed at the declaration instead +of varying at each call.

+ +

Function pointers are confusing in the presence of +default arguments, since the function signature often +doesn't match the call signature. Adding +function overloads avoids these problems.

+
+ +
+

Default arguments are banned on virtual functions, where +they don't work properly, and in cases where the specified +default might not evaluate to the same value depending on +when it was evaluated. (For example, don't write void +f(int n = counter++);.)

+ +

In some other cases, default arguments can improve the +readability of their function declarations enough to +overcome the downsides above, so they are allowed. When in +doubt, use overloads.

+
+ +
+ +

Trailing Return Type Syntax

+
+

Use trailing return types only where using the ordinary syntax (leading + return types) is impractical or much less readable.

+
+ +
+

C++ allows two different forms of function declarations. In the older + form, the return type appears before the function name. For example:

+
int foo(int x);
+
+

The new form, introduced in C++11, uses the auto + keyword before the function name and a trailing return type after + the argument list. For example, the declaration above could + equivalently be written:

+
auto foo(int x) -> int;
+
+

The trailing return type is in the function's scope. This doesn't + make a difference for a simple case like int but it matters + for more complicated cases, like types declared in class scope or + types written in terms of the function parameters.

+
+ +
+
+

Trailing return types are the only way to explicitly specify the + return type of a lambda expression. + In some cases the compiler is able to deduce a lambda's return type, + but not in all cases. Even when the compiler can deduce it automatically, + sometimes specifying it explicitly would be clearer for readers. +

+

Sometimes it's easier and more readable to specify a return type + after the function's parameter list has already appeared. This is + particularly true when the return type depends on template parameters. + For example:

+
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
+ versus +
template <class T, class U> decltype(declval<T&>() + declval<U&>()) add(T t, U u);
+
+ +
+

Trailing return type syntax is relatively new and it has no + analogue in C++-like languages like C and Java, so some readers may + find it unfamiliar.

+

Existing code bases have an enormous number of function + declarations that aren't going to get changed to use the new syntax, + so the realistic choices are using the old syntax only or using a mixture + of the two. Using a single version is better for uniformity of style.

+
+ +
+

In most cases, continue to use the older style of function + declaration where the return type goes before the function name. + Use the new trailing-return-type form only in cases where it's + required (such as lambdas) or where, by putting the type after the + function's parameter list, it allows you to write the type in a much + more readable way. The latter case should be rare; it's mostly an + issue in fairly complicated template code, which is + discouraged in most cases.

+ +
+
+ +

Google-Specific Magic

+ + + +

There are various tricks and utilities that +we use to make C++ code more robust, and various ways we use +C++ that may differ from what you see elsewhere.

+ + + +

Ownership and Smart Pointers

+ +
+

Prefer to have single, fixed owners for dynamically +allocated objects. Prefer to transfer ownership with smart +pointers.

+
+ +
+ +
+

"Ownership" is a bookkeeping technique for managing +dynamically allocated memory (and other resources). The +owner of a dynamically allocated object is an object or +function that is responsible for ensuring that it is +deleted when no longer needed. Ownership can sometimes be +shared, in which case the last owner is typically +responsible for deleting it. Even when ownership is not +shared, it can be transferred from one piece of code to +another.

+ +

"Smart" pointers are classes that act like pointers, +e.g. by overloading the * and +-> operators. Some smart pointer types +can be used to automate ownership bookkeeping, to ensure +these responsibilities are met. + +std::unique_ptr is a smart pointer type +introduced in C++11, which expresses exclusive ownership +of a dynamically allocated object; the object is deleted +when the std::unique_ptr goes out of scope. +It cannot be copied, but can be moved to +represent ownership transfer. + +std::shared_ptr is a smart pointer type +that expresses shared ownership of +a dynamically allocated object. std::shared_ptrs +can be copied; ownership of the object is shared among +all copies, and the object is deleted when the last +std::shared_ptr is destroyed.

+
+ +
+
    +
  • It's virtually impossible to manage dynamically + allocated memory without some sort of ownership + logic.
  • + +
  • Transferring ownership of an object can be cheaper + than copying it (if copying it is even possible).
  • + +
  • Transferring ownership can be simpler than + 'borrowing' a pointer or reference, because it reduces + the need to coordinate the lifetime of the object + between the two users.
  • + +
  • Smart pointers can improve readability by making + ownership logic explicit, self-documenting, and + unambiguous.
  • + +
  • Smart pointers can eliminate manual ownership + bookkeeping, simplifying the code and ruling out large + classes of errors.
  • + +
  • For const objects, shared ownership can be a simple + and efficient alternative to deep copying.
  • +
+
+ +
+
    +
  • Ownership must be represented and transferred via + pointers (whether smart or plain). Pointer semantics + are more complicated than value semantics, especially + in APIs: you have to worry not just about ownership, + but also aliasing, lifetime, and mutability, among + other issues.
  • + +
  • The performance costs of value semantics are often + overestimated, so the performance benefits of ownership + transfer might not justify the readability and + complexity costs.
  • + +
  • APIs that transfer ownership force their clients + into a single memory management model.
  • + +
  • Code using smart pointers is less explicit about + where the resource releases take place.
  • + +
  • std::unique_ptr expresses ownership + transfer using C++11's move semantics, which are + relatively new and may confuse some programmers.
  • + +
  • Shared ownership can be a tempting alternative to + careful ownership design, obfuscating the design of a + system.
  • + +
  • Shared ownership requires explicit bookkeeping at + run-time, which can be costly.
  • + +
  • In some cases (e.g. cyclic references), objects + with shared ownership may never be deleted.
  • + +
  • Smart pointers are not perfect substitutes for + plain pointers.
  • +
+
+ +
+

If dynamic allocation is necessary, prefer to keep +ownership with the code that allocated it. If other code +needs access to the object, consider passing it a copy, +or passing a pointer or reference without transferring +ownership. Prefer to use std::unique_ptr to +make ownership transfer explicit. For example:

+ +
std::unique_ptr<Foo> FooFactory();
+void FooConsumer(std::unique_ptr<Foo> ptr);
+
+ + + +

Do not design your code to use shared ownership +without a very good reason. One such reason is to avoid +expensive copy operations, but you should only do this if +the performance benefits are significant, and the +underlying object is immutable (i.e. +std::shared_ptr<const Foo>). If you +do use shared ownership, prefer to use +std::shared_ptr.

+ +

Never use std::auto_ptr. Instead, use +std::unique_ptr.

+
+ +
+ +

cpplint

+ +
+

Use cpplint.py +to detect style errors.

+
+ +
+ +

cpplint.py +is a tool that reads a source file and identifies many +style errors. It is not perfect, and has both false +positives and false negatives, but it is still a valuable +tool. False positives can be ignored by putting // +NOLINT at the end of the line or +// NOLINTNEXTLINE in the previous line.

+ + + +

Some projects have instructions on +how to run cpplint.py from their project +tools. If the project you are contributing to does not, +you can download + +cpplint.py separately.

+ +
+ + + +

Other C++ Features

+ +

Rvalue References

+ +
+

Use rvalue references only to define move constructors and move assignment +operators, or for perfect forwarding. +

+
+ +
+ +
+

Rvalue references +are a type of reference that can only bind to temporary +objects. The syntax is similar to traditional reference +syntax. For example, void f(string&& +s); declares a function whose argument is an +rvalue reference to a string.

+
+ +
+
    +
  • Defining a move constructor (a constructor taking + an rvalue reference to the class type) makes it + possible to move a value instead of copying it. If + v1 is a std::vector<string>, + for example, then auto v2(std::move(v1)) + will probably just result in some simple pointer + manipulation instead of copying a large amount of data. + In some cases this can result in a major performance + improvement.
  • + +
  • Rvalue references make it possible to write a + generic function wrapper that forwards its arguments to + another function, and works whether or not its + arguments are temporary objects. (This is sometimes called + "perfect forwarding".)
  • + +
  • Rvalue references make it possible to implement + types that are movable but not copyable, which can be + useful for types that have no sensible definition of + copying but where you might still want to pass them as + function arguments, put them in containers, etc.
  • + +
  • std::move is necessary to make + effective use of some standard-library types, such as + std::unique_ptr.
  • +
+
+ +
+
    +
  • Rvalue references are a relatively new feature + (introduced as part of C++11), and not yet widely + understood. Rules like reference collapsing, and + automatic synthesis of move constructors, are + complicated.
  • +
+
+ +
+

Use rvalue references only to define move constructors and move assignment + operators (as described in Copyable and + Movable Types) and, in conjunction with std::forward, +to support perfect forwarding. You may use std::move to express +moving a value from one object to another rather than copying it.

+
+ +
+ +

Friends

+ +
+

We allow use of friend classes and functions, +within reason.

+
+ +
+ +

Friends should usually be defined in the same file so +that the reader does not have to look in another file to +find uses of the private members of a class. A common use +of friend is to have a +FooBuilder class be a friend of +Foo so that it can construct the inner state +of Foo correctly, without exposing this +state to the world. In some cases it may be useful to +make a unittest class a friend of the class it tests.

+ +

Friends extend, but do not break, the encapsulation +boundary of a class. In some cases this is better than +making a member public when you want to give only one +other class access to it. However, most classes should +interact with other classes solely through their public +members.

+ +
+ +

Exceptions

+ +
+

We do not use C++ exceptions.

+
+ +
+ +
+
    +
  • Exceptions allow higher levels of an application to + decide how to handle "can't happen" failures in deeply + nested functions, without the obscuring and error-prone + bookkeeping of error codes.
  • + + + +
  • Exceptions are used by most other + modern languages. Using them in C++ would make it more + consistent with Python, Java, and the C++ that others + are familiar with.
  • + +
  • Some third-party C++ libraries use exceptions, and + turning them off internally makes it harder to + integrate with those libraries.
  • + +
  • Exceptions are the only way for a constructor to + fail. We can simulate this with a factory function or + an Init() method, but these require heap + allocation or a new "invalid" state, respectively.
  • + +
  • Exceptions are really handy in testing + frameworks.
  • +
+
+ +
+
    +
  • When you add a throw statement to an + existing function, you must examine all of its + transitive callers. Either they must make at least the + basic exception safety guarantee, or they must never + catch the exception and be happy with the program + terminating as a result. For instance, if + f() calls g() calls + h(), and h throws an + exception that f catches, g + has to be careful or it may not clean up properly.
  • + +
  • More generally, exceptions make the control flow of + programs difficult to evaluate by looking at code: + functions may return in places you don't expect. This + causes maintainability and debugging difficulties. You + can minimize this cost via some rules on how and where + exceptions can be used, but at the cost of more that a + developer needs to know and understand.
  • + +
  • Exception safety requires both RAII and different + coding practices. Lots of supporting machinery is + needed to make writing correct exception-safe code + easy. Further, to avoid requiring readers to understand + the entire call graph, exception-safe code must isolate + logic that writes to persistent state into a "commit" + phase. This will have both benefits and costs (perhaps + where you're forced to obfuscate code to isolate the + commit). Allowing exceptions would force us to always + pay those costs even when they're not worth it.
  • + +
  • Turning on exceptions adds data to each binary + produced, increasing compile time (probably slightly) + and possibly increasing address space pressure. +
  • + +
  • The availability of exceptions may encourage + developers to throw them when they are not appropriate + or recover from them when it's not safe to do so. For + example, invalid user input should not cause exceptions + to be thrown. We would need to make the style guide + even longer to document these restrictions!
  • +
+
+ +
+

On their face, the benefits of using exceptions +outweigh the costs, especially in new projects. However, +for existing code, the introduction of exceptions has +implications on all dependent code. If exceptions can be +propagated beyond a new project, it also becomes +problematic to integrate the new project into existing +exception-free code. Because most existing C++ code at +Google is not prepared to deal with exceptions, it is +comparatively difficult to adopt new code that generates +exceptions.

+ +

Given that Google's existing code is not +exception-tolerant, the costs of using exceptions are +somewhat greater than the costs in a new project. The +conversion process would be slow and error-prone. We +don't believe that the available alternatives to +exceptions, such as error codes and assertions, introduce +a significant burden.

+ +

Our advice against using exceptions is not predicated +on philosophical or moral grounds, but practical ones. + Because we'd like to use our open-source +projects at Google and it's difficult to do so if those +projects use exceptions, we need to advise against +exceptions in Google open-source projects as well. +Things would probably be different if we had to do it all +over again from scratch.

+ +

This prohibition also applies to the exception-related +features added in C++11, such as noexcept, +std::exception_ptr, and +std::nested_exception.

+ +

There is an exception to +this rule (no pun intended) for Windows code.

+
+ +
+ +

Run-Time Type +Information (RTTI)

+ +
+

Avoid using Run Time Type Information (RTTI).

+
+ +
+ +
+

RTTI allows a +programmer to query the C++ class of an object at run +time. This is done by use of typeid or +dynamic_cast.

+
+ +
+

Querying the type of an object at run-time frequently +means a design problem. Needing to know the type of an +object at runtime is often an indication that the design +of your class hierarchy is flawed.

+ +

Undisciplined use of RTTI makes code hard to maintain. +It can lead to type-based decision trees or switch +statements scattered throughout the code, all of which +must be examined when making further changes.

+
+ +
+

The standard alternatives to RTTI (described below) +require modification or redesign of the class hierarchy +in question. Sometimes such modifications are infeasible +or undesirable, particularly in widely-used or mature +code.

+ +

RTTI can be useful in some unit tests. For example, it +is useful in tests of factory classes where the test has +to verify that a newly created object has the expected +dynamic type. It is also useful in managing the +relationship between objects and their mocks.

+ +

RTTI is useful when considering multiple abstract +objects. Consider

+ +
bool Base::Equal(Base* other) = 0;
+bool Derived::Equal(Base* other) {
+  Derived* that = dynamic_cast<Derived*>(other);
+  if (that == NULL)
+    return false;
+  ...
+}
+
+
+ +
+

RTTI has legitimate uses but is prone to abuse, so you +must be careful when using it. You may use it freely in +unittests, but avoid it when possible in other code. In +particular, think twice before using RTTI in new code. If +you find yourself needing to write code that behaves +differently based on the class of an object, consider one +of the following alternatives to querying the type:

+ +
    +
  • Virtual methods are the preferred way of executing + different code paths depending on a specific subclass + type. This puts the work within the object itself.
  • + +
  • If the work belongs outside the object and instead + in some processing code, consider a double-dispatch + solution, such as the Visitor design pattern. This + allows a facility outside the object itself to + determine the type of class using the built-in type + system.
  • +
+ +

When the logic of a program guarantees that a given +instance of a base class is in fact an instance of a +particular derived class, then a +dynamic_cast may be used freely on the +object. Usually one +can use a static_cast as an alternative in +such situations.

+ +

Decision trees based on type are a strong indication +that your code is on the wrong track.

+ +
if (typeid(*data) == typeid(D1)) {
+  ...
+} else if (typeid(*data) == typeid(D2)) {
+  ...
+} else if (typeid(*data) == typeid(D3)) {
+...
+
+ +

Code such as this usually breaks when additional +subclasses are added to the class hierarchy. Moreover, +when properties of a subclass change, it is difficult to +find and modify all the affected code segments.

+ +

Do not hand-implement an RTTI-like workaround. The +arguments against RTTI apply just as much to workarounds +like class hierarchies with type tags. Moreover, +workarounds disguise your true intent.

+
+ +
+ +

Casting

+ +
+

Use C++-style casts +like static_cast<float>(double_value), or brace +initialization for conversion of arithmetic types like +int64 y = int64{1} << 42. Do not use +cast formats like +int y = (int)x or int y = int(x) (but the latter +is okay when invoking a constructor of a class type).

+
+ +
+ +
+

C++ introduced a +different cast system from C that distinguishes the types +of cast operations.

+
+ +
+

The problem with C casts is the ambiguity of the operation; +sometimes you are doing a conversion +(e.g., (int)3.5) and sometimes you are doing +a cast (e.g., (int)"hello"). Brace +initialization and C++ casts can often help avoid this +ambiguity. Additionally, C++ casts are more visible when searching for +them.

+
+ +
+

The C++-style cast syntax is verbose and cumbersome.

+
+ +
+

Do not use C-style casts. Instead, use these C++-style casts when +explicit type conversion is necessary.

+ +
    +
  • Use brace initialization to convert arithmetic types + (e.g. int64{x}). This is the safest approach because code + will not compile if conversion can result in information loss. The + syntax is also concise.
  • + + + +
  • Use static_cast as the equivalent of a C-style cast + that does value conversion, when you need to + explicitly up-cast a pointer from a class to its superclass, or when + you need to explicitly cast a pointer from a superclass to a + subclass. In this last case, you must be sure your object is + actually an instance of the subclass.
  • + + + +
  • Use const_cast to remove the + const qualifier (see const).
  • + +
  • Use reinterpret_cast to do unsafe + conversions of pointer types to and from integer and + other pointer types. Use this only if you know what you + are doing and you understand the aliasing issues. +
  • + + +
+ +

See the +RTTI section for guidance on the use of +dynamic_cast.

+
+ +
+ +

Streams

+ +
+

Use streams where appropriate, and stick to "simple" +usages.

+
+ +
+ +
+

Streams are the standard I/O abstraction in C++, as +exemplified by the standard header <iostream>. +They are widely used in Google code, but only for debug logging +and test diagnostics.

+
+ +
+

The << and >> +stream operators provide an API for formatted I/O that +is easily learned, portable, reusable, and extensible. +printf, by contrast, doesn't even support +string, to say nothing of user-defined types, +and is very difficult to use portably. +printf also obliges you to choose among the +numerous slightly different versions of that function, +and navigate the dozens of conversion specifiers.

+ +

Streams provide first-class support for console I/O +via std::cin, std::cout, +std::cerr, and std::clog. +The C APIs do as well, but are hampered by the need to +manually buffer the input.

+
+ +
+
    +
  • Stream formatting can be configured by mutating the +state of the stream. Such mutations are persistent, so +the behavior of your code can be affected by the entire +previous history of the stream, unless you go out of your +way to restore it to a known state every time other code +might have touched it. User code can not only modify the +built-in state, it can add new state variables and behaviors +through a registration system.
  • + +
  • It is difficult to precisely control stream output, due +to the above issues, the way code and data are mixed in +streaming code, and the use of operator overloading (which +may select a different overload than you expect).
  • + +
  • The practice of building up output through chains +of << operators interferes with +internationalization, because it bakes word order into the +code, and streams' support for localization is +flawed.
  • + + + + + +
  • The streams API is subtle and complex, so programmers must +develop experience with it in order to use it effectively. +However, streams were historically banned in Google code (except +for logging and diagnostics), so Google engineers tend not to +have that experience. Consequently, streams-based code is likely +to be less readable and maintainable by Googlers than code based +on more familiar abstractions.
  • + +
  • Resolving the many overloads of << is +extremely costly for the compiler. When used pervasively in a +large code base, it can consume as much as 20% of the parsing +and semantic analysis time.
  • +
+
+ +
+

Use streams only when they are the best tool for the job. +This is typically the case when the I/O is ad-hoc, local, +human-readable, and targeted at other developers rather than +end-users. Be consistent with the code around you, and with the +codebase as a whole; if there's an established tool for +your problem, use that tool instead.

+ +

Avoid using streams for I/O that faces external users or +handles untrusted data. Instead, find and use the appropriate +templating libraries to handle issues like internationalization, +localization, and security hardening.

+ +

If you do use streams, avoid the stateful parts of the +streams API (other than error state), such as imbue(), +xalloc(), and register_callback(). +Use explicit formatting functions rather than +stream manipulators or formatting flags to control formatting +details such as number base, precision, or padding.

+ +

Overload << as a streaming operator +for your type only if your type represents a value, and +<< writes out a human-readable string +representation of that value. Avoid exposing implementation +details in the output of <<; if you need to print +object internals for debugging, use named functions instead +(a method named DebugString() is the most common +convention).

+
+ +
+ +

Preincrement and Predecrement

+ +
+

Use prefix form (++i) of the increment and +decrement operators with iterators and other template +objects.

+
+ +
+ +
+

When a variable +is incremented (++i or i++) or +decremented (--i or i--) and +the value of the expression is not used, one must decide +whether to preincrement (decrement) or postincrement +(decrement).

+
+ +
+

When the return value is ignored, the "pre" form +(++i) is never less efficient than the +"post" form (i++), and is often more +efficient. This is because post-increment (or decrement) +requires a copy of i to be made, which is +the value of the expression. If i is an +iterator or other non-scalar type, copying i +could be expensive. Since the two types of increment +behave the same when the value is ignored, why not just +always pre-increment?

+
+ +
+

The tradition developed, in C, of using post-increment +when the expression value is not used, especially in +for loops. Some find post-increment easier +to read, since the "subject" (i) precedes +the "verb" (++), just like in English.

+
+ +
+

For simple scalar +(non-object) values there is no reason to prefer one form +and we allow either. For iterators and other template +types, use pre-increment.

+
+ +
+ +

Use of const

+ +
+

Use const whenever it makes sense. With C++11, +constexpr is a better choice for some uses of +const.

+
+ +
+ +
+

Declared variables and parameters can be preceded +by the keyword const to indicate the variables +are not changed (e.g., const int foo). Class +functions can have the const qualifier to +indicate the function does not change the state of the +class member variables (e.g., class Foo { int +Bar(char c) const; };).

+
+ +
+

Easier for people to understand how variables are being +used. Allows the compiler to do better type checking, +and, conceivably, generate better code. Helps people +convince themselves of program correctness because they +know the functions they call are limited in how they can +modify your variables. Helps people know what functions +are safe to use without locks in multi-threaded +programs.

+
+ +
+

const is viral: if you pass a +const variable to a function, that function +must have const in its prototype (or the +variable will need a const_cast). This can +be a particular problem when calling library +functions.

+
+ +
+

const variables, data members, methods +and arguments add a level of compile-time type checking; +it is better to detect errors as soon as possible. +Therefore we strongly recommend that you use +const whenever it makes sense to do so:

+ +
    +
  • If a function guarantees that it will not modify an argument + passed by reference or by pointer, the corresponding function parameter + should be a reference-to-const (const T&) or + pointer-to-const (const T*), respectively.
  • + +
  • Declare methods to be const whenever + possible. Accessors should almost always be + const. Other methods should be const if + they do not modify any data members, do not call any + non-const methods, and do not return a + non-const pointer or + non-const reference to a data member.
  • + +
  • Consider making data members const + whenever they do not need to be modified after + construction.
  • +
+ +

The mutable keyword is allowed but is +unsafe when used with threads, so thread safety should be +carefully considered first.

+
+ +
+

Where to put the const

+ +

Some people favor the form int const *foo +to const int* foo. They argue that this is +more readable because it's more consistent: it keeps the +rule that const always follows the object +it's describing. However, this consistency argument +doesn't apply in codebases with few deeply-nested pointer +expressions since most const expressions +have only one const, and it applies to the +underlying value. In such cases, there's no consistency +to maintain. Putting the const first is +arguably more readable, since it follows English in +putting the "adjective" (const) before the +"noun" (int).

+ +

That said, while we encourage putting +const first, we do not require it. But be +consistent with the code around you!

+
+ +
+ +

Use of constexpr

+ +
+

In C++11, use constexpr to define true +constants or to ensure constant initialization.

+
+ +
+ +
+

Some variables can be declared constexpr +to indicate the variables are true constants, i.e. fixed at +compilation/link time. Some functions and constructors +can be declared constexpr which enables them +to be used in defining a constexpr +variable.

+
+ +
+

Use of constexpr enables definition of +constants with floating-point expressions rather than +just literals; definition of constants of user-defined +types; and definition of constants with function +calls.

+
+ +
+

Prematurely marking something as constexpr may cause +migration problems if later on it has to be downgraded. +Current restrictions on what is allowed in constexpr +functions and constructors may invite obscure workarounds +in these definitions.

+
+ +
+

constexpr definitions enable a more +robust specification of the constant parts of an +interface. Use constexpr to specify true +constants and the functions that support their +definitions. Avoid complexifying function definitions to +enable their use with constexpr. Do not use +constexpr to force inlining.

+
+ +
+ +

Integer Types

+ +
+

Of the built-in C++ integer types, the only one used + is +int. If a program needs a variable of a +different size, use +a precise-width integer type from +<stdint.h>, such as +int16_t. If your variable represents a +value that could ever be greater than or equal to 2^31 +(2GiB), use a 64-bit type such as +int64_t. +Keep in mind that even if your value won't ever be too large +for an int, it may be used in intermediate +calculations which may require a larger type. When in doubt, +choose a larger type.

+
+ +
+ +
+

C++ does not specify the sizes of its integer types. +Typically people assume that short is 16 bits, +int is 32 bits, long is 32 bits +and long long is 64 bits.

+
+ +
+

Uniformity of declaration.

+
+ +
+

The sizes of integral types in C++ can vary based on +compiler and architecture.

+
+ +
+ +

+<stdint.h> defines types +like int16_t, uint32_t, +int64_t, etc. You should always use +those in preference to short, unsigned +long long and the like, when you need a guarantee +on the size of an integer. Of the C integer types, only +int should be used. When appropriate, you +are welcome to use standard types like +size_t and ptrdiff_t.

+ +

We use int very often, for integers we +know are not going to be too big, e.g., loop counters. +Use plain old int for such things. You +should assume that an int is + +at least 32 bits, but don't +assume that it has more than 32 bits. If you need a 64-bit +integer type, use +int64_t +or +uint64_t.

+ +

For integers we know can be "big", + use +int64_t. +

+ +

You should not use the unsigned integer types such as +uint32_t, unless there is a valid +reason such as representing a bit pattern rather than a +number, or you need defined overflow modulo 2^N. In +particular, do not use unsigned types to say a number +will never be negative. Instead, use +assertions for this.

+ + + +

If your code is a container that returns a size, be +sure to use a type that will accommodate any possible +usage of your container. When in doubt, use a larger type +rather than a smaller type.

+ +

Use care when converting integer types. Integer +conversions and promotions can cause non-intuitive +behavior.

+
+ +
+ +

On Unsigned Integers

+ +

Some people, including some textbook authors, +recommend using unsigned types to represent numbers that +are never negative. This is intended as a form of +self-documentation. However, in C, the advantages of such +documentation are outweighed by the real bugs it can +introduce. Consider:

+ +
for (unsigned int i = foo.Length()-1; i >= 0; --i) ...
+
+ +

This code will never terminate! Sometimes gcc will +notice this bug and warn you, but often it will not. +Equally bad bugs can occur when comparing signed and +unsigned variables. Basically, C's type-promotion scheme +causes unsigned types to behave differently than one +might expect.

+ +

So, document that a variable is non-negative using +assertions. Don't use an unsigned +type.

+
+ +
+ +

64-bit Portability

+ +
+

Code should be 64-bit and 32-bit friendly. Bear in mind +problems of printing, comparisons, and structure alignment.

+
+ +
+ +
    +
  • +

    printf() specifiers for some types + are not cleanly portable between 32-bit and 64-bit + systems. C99 defines some portable format specifiers. + Unfortunately, MSVC 7.1 does not understand some of + these specifiers and the standard is missing a few, + so we + have to define our own ugly versions in some cases + (in the style of the standard include file + inttypes.h):

    + +
    +
    // printf macros for size_t, in the style of inttypes.h
    +#ifdef _LP64
    +#define __PRIS_PREFIX "z"
    +#else
    +#define __PRIS_PREFIX
    +#endif
    +
    +// Use these macros after a % in a printf format string
    +// to get correct 32/64 bit behavior, like this:
    +// size_t size = records.size();
    +// printf("%" PRIuS "\n", size);
    +
    +#define PRIdS __PRIS_PREFIX "d"
    +#define PRIxS __PRIS_PREFIX "x"
    +#define PRIuS __PRIS_PREFIX "u"
    +#define PRIXS __PRIS_PREFIX "X"
    +#define PRIoS __PRIS_PREFIX "o"
    +  
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeDO NOT useDO useNotes
    void * (or any pointer)%lx%p
    int64_t%qd, %lld%" PRId64 "
    uint64_t%qu, %llu, + %llx%" PRIu64 ", + %" PRIx64 "
    size_t%u%" PRIuS ", %" PRIxS " + C99 specifies %zu
    ptrdiff_t%d%" PRIdS " + C99 specifies %td
    + +

    Note that the PRI* macros expand to + independent strings which are concatenated by the + compiler. Hence if you are using a non-constant + format string, you need to insert the value of the + macro into the format, rather than the name. Note also + that spaces are required around the macro identifier to + separate it from the string literal. It is + still possible, as usual, to include length + specifiers, etc., after the % when using + the PRI* macros. So, e.g. + printf("x = %30" PRIuS "\n", x) would + expand on 32-bit Linux to printf("x = %30" "u" + "\n", x), which the compiler will treat as + printf("x = %30u\n", x).

    + + +
  • + +
  • Remember that sizeof(void *) != + sizeof(int). Use intptr_t if + you want a pointer-sized integer.
  • + +
  • You may need to be careful with structure + alignments, particularly for structures being stored on + disk. Any class/structure with a + int64_t/uint64_t + member will by default end up being 8-byte aligned on a + 64-bit system. If you have such structures being shared + on disk between 32-bit and 64-bit code, you will need + to ensure that they are packed the same on both + architectures. + Most compilers offer a way to + alter structure alignment. For gcc, you can use + __attribute__((packed)). MSVC offers + #pragma pack() and + __declspec(align()).
  • + +
  • +

    Use the LL or ULL + suffixes as needed to create 64-bit constants. For + example:

    + + +
    int64_t my_value = 0x123456789LL;
    +uint64_t my_mask = 3ULL << 48;
    +
    +
  • +
+ +
+ +

Preprocessor Macros

+ +
+

Avoid defining macros, especially in headers; prefer +inline functions, enums, and const variables. +Name macros with a project-specific prefix. Do not use +macros to define pieces of a C++ API.

+
+ +
+ +

Macros mean that the code you see is not the same as +the code the compiler sees. This can introduce unexpected +behavior, especially since macros have global scope.

+ +

The problems introduced by macros are especially severe +when they are used to define pieces of a C++ API, +and still more so for public APIs. Every error message from +the compiler when developers incorrectly use that interface +now must explain how the macros formed the interface. +Refactoring and analysis tools have a dramatically harder +time updating the interface. As a consequence, we +specifically disallow using macros in this way. +For example, avoid patterns like:

+ +
class WOMBAT_TYPE(Foo) {
+  // ...
+
+ public:
+  EXPAND_PUBLIC_WOMBAT_API(Foo)
+
+  EXPAND_WOMBAT_COMPARISONS(Foo, ==, <)
+};
+
+ +

Luckily, macros are not nearly as necessary in C++ as +they are in C. Instead of using a macro to inline +performance-critical code, use an inline function. +Instead of using a macro to store a constant, use a +const variable. Instead of using a macro to +"abbreviate" a long variable name, use a reference. +Instead of using a macro to conditionally compile code +... well, don't do that at all (except, of course, for +the #define guards to prevent double +inclusion of header files). It makes testing much more +difficult.

+ +

Macros can do things these other techniques cannot, +and you do see them in the codebase, especially in the +lower-level libraries. And some of their special features +(like stringifying, concatenation, and so forth) are not +available through the language proper. But before using a +macro, consider carefully whether there's a non-macro way +to achieve the same result. If you need to use a macro to +define an interface, contact +your project leads to request +a waiver of this rule.

+ +

The following usage pattern will avoid many problems +with macros; if you use macros, follow it whenever +possible:

+ +
    +
  • Don't define macros in a .h file.
  • + +
  • #define macros right before you use + them, and #undef them right after.
  • + +
  • Do not just #undef an existing macro + before replacing it with your own; instead, pick a name + that's likely to be unique.
  • + +
  • Try not to use macros that expand to unbalanced C++ + constructs, or at least document that behavior + well.
  • + +
  • Prefer not using ## to generate + function/class/variable names.
  • +
+ +

Exporting macros from headers (i.e. defining them in a header +without #undefing them before the end of the header) +is extremely strongly discouraged. If you do export a macro from a +header, it must have a globally unique name. To achieve this, it +must be named with a prefix consisting of your project's namespace +name (but upper case).

+ +
+ +

0 and nullptr/NULL

+ +
+

Use 0 for integers, 0.0 for +reals, nullptr (or NULL) for +pointers, and '\0' for chars.

+
+ +
+ +

Use 0 for integers and 0.0 +for reals. This is not controversial.

+ +

For +pointers (address values), there is a choice between +0, NULL, and +nullptr. For projects that allow C++11 +features, use nullptr. For C++03 projects, +we prefer NULL because it looks like a +pointer. In fact, some C++ compilers provide special +definitions of NULL which enable them to +give useful warnings, particularly in situations where +sizeof(NULL) is not equal to +sizeof(0).

+ +

Use '\0' for chars. This is the correct +type and also makes code more readable.

+ +
+ +

sizeof

+ +
+

Prefer sizeof(varname) to +sizeof(type).

+
+ +
+ +

Use sizeof(varname) when you +take the size of a particular variable. +sizeof(varname) will update +appropriately if someone changes the variable type either +now or later. You may use +sizeof(type) for code unrelated +to any particular variable, such as code that manages an +external or internal data format where a variable of an +appropriate C++ type is not convenient.

+ +
Struct data;
+memset(&data, 0, sizeof(data));
+
+ +
memset(&data, 0, sizeof(Struct));
+
+ +
if (raw_size < sizeof(int)) {
+  LOG(ERROR) << "compressed record not big enough for count: " << raw_size;
+  return false;
+}
+
+ +
+ +

auto

+ +
+

Use auto to avoid type names that are noisy, obvious, +or unimportant - cases where the type doesn't aid in clarity for the +reader. Continue to use manifest type declarations when it helps +readability.

+
+ +
+ +
+

+

    +
  • C++ type names can be long and cumbersome, especially when they +involve templates or namespaces.
  • +
  • When a C++ type name is repeated within a single declaration or a +small code region, the repetition may not be aiding readability.
  • +
  • It is sometimes safer to let the type be specified by the type of +the initialization expression, since that avoids the possibility of +unintended copies or type conversions.
  • +
+
+
+ +

Sometimes code is clearer when types are manifest, +especially when a variable's initialization depends on +things that were declared far away. In expressions +like:

+ +
auto foo = x.add_foo();
+auto i = y.Find(key);
+
+ +

it may not be obvious what the resulting types are if the type +of y isn't very well known, or if y was +declared many lines earlier.

+ +

Programmers have to understand the difference between +auto and const auto& or +they'll get copies when they didn't mean to.

+ +

If an auto variable is used as part of an +interface, e.g. as a constant in a header, then a +programmer might change its type while only intending to +change its value, leading to a more radical API change +than intended.

+
+ +
+ +

auto is permitted when it increases readability, +particularly as described below. Never initialize an auto-typed +variable with a braced initializer list.

+ +

Specific cases where auto is allowed or encouraged: +

    +
  • (Encouraged) For iterators and other long/cluttery type names, particularly +when the type is clear from context (calls +to find, begin, or end for +instance).
  • +
  • (Allowed) When the type is clear from local context (in the same expression +or within a few lines). Initialization of a pointer or smart pointer +with calls +to new +commonly falls into this category, as does use of auto in +a range-based loop over a container whose type is spelled out +nearby.
  • +
  • (Allowed) When the type doesn't matter because it isn't being used for +anything other than equality comparison.
  • +
  • (Encouraged) When iterating over a map with a range-based loop +(because it is often assumed that the correct type +is std::pair<KeyType, ValueType> whereas it is actually +std::pair<const KeyType, ValueType>). This is +particularly well paired with local key +and value aliases for .first +and .second (often const-ref). +
    for (const auto& item : some_map) {
    +  const KeyType& key = item.first;
    +  const ValType& value = item.second;
    +  // The rest of the loop can now just refer to key and value,
    +  // a reader can see the types in question, and we've avoided
    +  // the too-common case of extra copies in this iteration.
    +}
    +
    +
  • +
+ +
+ +
+ +

Braced Initializer List

+ +
+

You may use braced initializer lists.

+
+ +
+ +

In C++03, aggregate types (arrays and structs with no +constructor) could be initialized with braced initializer lists.

+ +
struct Point { int x; int y; };
+Point p = {1, 2};
+
+ +

In C++11, this syntax was generalized, and any object type can now +be created with a braced initializer list, known as a +braced-init-list in the C++ grammar. Here are a few examples +of its use.

+ +
// Vector takes a braced-init-list of elements.
+std::vector<string> v{"foo", "bar"};
+
+// Basically the same, ignoring some small technicalities.
+// You may choose to use either form.
+std::vector<string> v = {"foo", "bar"};
+
+// Usable with 'new' expressions.
+auto p = new vector<string>{"foo", "bar"};
+
+// A map can take a list of pairs. Nested braced-init-lists work.
+std::map<int, string> m = {{1, "one"}, {2, "2"}};
+
+// A braced-init-list can be implicitly converted to a return type.
+std::vector<int> test_function() { return {1, 2, 3}; }
+
+// Iterate over a braced-init-list.
+for (int i : {-1, -2, -3}) {}
+
+// Call a function using a braced-init-list.
+void TestFunction2(std::vector<int> v) {}
+TestFunction2({1, 2, 3});
+
+ +

A user-defined type can also define a constructor and/or assignment operator +that take std::initializer_list<T>, which is automatically +created from braced-init-list:

+ +
class MyType {
+ public:
+  // std::initializer_list references the underlying init list.
+  // It should be passed by value.
+  MyType(std::initializer_list<int> init_list) {
+    for (int i : init_list) append(i);
+  }
+  MyType& operator=(std::initializer_list<int> init_list) {
+    clear();
+    for (int i : init_list) append(i);
+  }
+};
+MyType m{2, 3, 5, 7};
+
+ +

Finally, brace initialization can also call ordinary +constructors of data types, even if they do not have +std::initializer_list<T> constructors.

+ +
double d{1.23};
+// Calls ordinary constructor as long as MyOtherType has no
+// std::initializer_list constructor.
+class MyOtherType {
+ public:
+  explicit MyOtherType(string);
+  MyOtherType(int, string);
+};
+MyOtherType m = {1, "b"};
+// If the constructor is explicit, you can't use the "= {}" form.
+MyOtherType m{"b"};
+
+ +

Never assign a braced-init-list to an auto +local variable. In the single element case, what this +means can be confusing.

+ +
auto d = {1.23};        // d is a std::initializer_list<double>
+
+ +
auto d = double{1.23};  // Good -- d is a double, not a std::initializer_list.
+
+ +

See Braced_Initializer_List_Format for formatting.

+ +
+ +

Lambda expressions

+ +
+

Use lambda expressions where appropriate. Prefer explicit captures +when the lambda will escape the current scope.

+
+ +
+ +
+ +

Lambda expressions are a concise way of creating anonymous +function objects. They're often useful when passing +functions as arguments. For example:

+ +
std::sort(v.begin(), v.end(), [](int x, int y) {
+  return Weight(x) < Weight(y);
+});
+
+ +

They further allow capturing variables from the enclosing scope either +explicitly by name, or implicitly using a default capture. Explicit captures +require each variable to be listed, as +either a value or reference capture:

+ +
int weight = 3;
+int sum = 0;
+// Captures `weight` by value and `sum` by reference.
+std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
+  sum += weight * x;
+});
+
+ + +Default captures implicitly capture any variable referenced in the +lambda body, including this if any members are used: + +
const std::vector<int> lookup_table = ...;
+std::vector<int> indices = ...;
+// Captures `lookup_table` by reference, sorts `indices` by the value
+// of the associated element in `lookup_table`.
+std::sort(indices.begin(), indices.end(), [&](int a, int b) {
+  return lookup_table[a] < lookup_table[b];
+});
+
+ +

Lambdas were introduced in C++11 along with a set of utilities +for working with function objects, such as the polymorphic +wrapper std::function. +

+
+ +
+
    +
  • Lambdas are much more concise than other ways of + defining function objects to be passed to STL + algorithms, which can be a readability + improvement.
  • + +
  • Appropriate use of default captures can remove + redundancy and highlight important exceptions from + the default.
  • + +
  • Lambdas, std::function, and + std::bind can be used in combination as a + general purpose callback mechanism; they make it easy + to write functions that take bound functions as + arguments.
  • +
+
+ +
+
    +
  • Variable capture in lambdas can be a source of dangling-pointer + bugs, particularly if a lambda escapes the current scope.
  • + +
  • Default captures by value can be misleading because they do not prevent + dangling-pointer bugs. Capturing a pointer by value doesn't cause a deep + copy, so it often has the same lifetime issues as capture by reference. + This is especially confusing when capturing 'this' by value, since the use + of 'this' is often implicit.
  • + +
  • It's possible for use of lambdas to get out of + hand; very long nested anonymous functions can make + code harder to understand.
  • + +
+
+ +
+
    +
  • Use lambda expressions where appropriate, with formatting as +described below.
  • +
  • Prefer explicit captures if the lambda may escape the current scope. +For example, instead of: +
    {
    +  Foo foo;
    +  ...
    +  executor->Schedule([&] { Frobnicate(foo); })
    +  ...
    +}
    +// BAD! The fact that the lambda makes use of a reference to `foo` and
    +// possibly `this` (if `Frobnicate` is a member function) may not be
    +// apparent on a cursory inspection. If the lambda is invoked after
    +// the function returns, that would be bad, because both `foo`
    +// and the enclosing object could have been destroyed.
    +
    +prefer to write: +
    {
    +  Foo foo;
    +  ...
    +  executor->Schedule([&foo] { Frobnicate(foo); })
    +  ...
    +}
    +// BETTER - The compile will fail if `Frobnicate` is a member
    +// function, and it's clearer that `foo` is dangerously captured by
    +// reference.
    +
    +
  • +
  • Use default capture by reference ([&]) only when the +lifetime of the lambda is obviously shorter than any potential +captures. +
  • +
  • Use default capture by value ([=]) only as a means of binding a +few variables for a short lambda, where the set of captured +variables is obvious at a glance. Prefer not to write long or +complex lambdas with default capture by value. +
  • +
  • Keep unnamed lambdas short. If a lambda body is more than +maybe five lines long, prefer to give the lambda a name, or to +use a named function instead of a lambda.
  • +
  • Specify the return type of the lambda explicitly if that will +make it more obvious to readers, as with +auto.
  • + +
+
+ +
+ +

Template metaprogramming

+
+

Avoid complicated template programming.

+
+ +
+ +
+

Template metaprogramming refers to a family of techniques that +exploit the fact that the C++ template instantiation mechanism is +Turing complete and can be used to perform arbitrary compile-time +computation in the type domain.

+
+ +
+

Template metaprogramming allows extremely flexible interfaces that +are type safe and high performance. Facilities like + +Google Test, +std::tuple, std::function, and +Boost.Spirit would be impossible without it.

+
+ +
+

The techniques used in template metaprogramming are often obscure +to anyone but language experts. Code that uses templates in +complicated ways is often unreadable, and is hard to debug or +maintain.

+ +

Template metaprogramming often leads to extremely poor compiler +time error messages: even if an interface is simple, the complicated +implementation details become visible when the user does something +wrong.

+ +

Template metaprogramming interferes with large scale refactoring by +making the job of refactoring tools harder. First, the template code +is expanded in multiple contexts, and it's hard to verify that the +transformation makes sense in all of them. Second, some refactoring +tools work with an AST that only represents the structure of the code +after template expansion. It can be difficult to automatically work +back to the original source construct that needs to be +rewritten.

+
+ +
+

Template metaprogramming sometimes allows cleaner and easier-to-use +interfaces than would be possible without it, but it's also often a +temptation to be overly clever. It's best used in a small number of +low level components where the extra maintenance burden is spread out +over a large number of uses.

+ +

Think twice before using template metaprogramming or other +complicated template techniques; think about whether the average +member of your team will be able to understand your code well enough +to maintain it after you switch to another project, or whether a +non-C++ programmer or someone casually browsing the code base will be +able to understand the error messages or trace the flow of a function +they want to call. If you're using recursive template instantiations +or type lists or metafunctions or expression templates, or relying on +SFINAE or on the sizeof trick for detecting function +overload resolution, then there's a good chance you've gone too +far.

+ +

If you use template metaprogramming, you should expect to put +considerable effort into minimizing and isolating the complexity. You +should hide metaprogramming as an implementation detail whenever +possible, so that user-facing headers are readable, and you should +make sure that tricky code is especially well commented. You should +carefully document how the code is used, and you should say something +about what the "generated" code looks like. Pay extra attention to the +error messages that the compiler emits when users make mistakes. The +error messages are part of your user interface, and your code should +be tweaked as necessary so that the error messages are understandable +and actionable from a user point of view.

+ +
+
+ + +

Boost

+ +
+

Use only approved libraries from the Boost library +collection.

+
+ +
+ +
+

The + +Boost library collection is a popular collection of +peer-reviewed, free, open-source C++ libraries.

+
+ +
+

Boost code is generally very high-quality, is widely +portable, and fills many important gaps in the C++ +standard library, such as type traits and better binders.

+
+ +
+

Some Boost libraries encourage coding practices which can +hamper readability, such as metaprogramming and other +advanced template techniques, and an excessively +"functional" style of programming.

+
+ +
+ + + +
+

In order to maintain a high level of readability for +all contributors who might read and maintain code, we +only allow an approved subset of Boost features. +Currently, the following libraries are permitted:

+ + + +

We are actively considering adding other Boost +features to the list, so this list may be expanded in +the future.

+
+ +

The following libraries are permitted, but their use +is discouraged because they've been superseded by +standard libraries in C++11:

+ + +
+ +
+ + + +

std::hash

+ +
+

Do not define specializations of std::hash.

+
+ +
+ +
+

std::hash<T> is the function object that the +C++11 hash containers use to hash keys of type T, +unless the user explicitly specifies a different hash function. For +example, std::unordered_map<int, string> is a hash +map that uses std::hash<int> to hash its keys, +whereas std::unordered_map<int, string, MyIntHash> +uses MyIntHash.

+ +

std::hash is defined for all integral, floating-point, +pointer, and enum types, as well as some standard library +types such as string and unique_ptr. Users +can enable it to work for their own types by defining specializations +of it for those types.

+
+ +
+

std::hash is easy to use, and simplifies the code +since you don't have to name it explicitly. Specializing +std::hash is the standard way of specifying how to +hash a type, so it's what outside resources will teach, and what +new engineers will expect.

+
+ +
+

std::hash is hard to specialize. It requires a lot +of boilerplate code, and more importantly, it combines responsibility +for identifying the hash inputs with responsibility for executing the +hashing algorithm itself. The type author has to be responsible for +the former, but the latter requires expertise that a type author +usually doesn't have, and shouldn't need. The stakes here are high +because low-quality hash functions can be security vulnerabilities, +due to the emergence of + +hash flooding attacks.

+ +

Even for experts, std::hash specializations are +inordinately difficult to implement correctly for compound types, +because the implementation cannot recursively call std::hash +on data members. High-quality hash algorithms maintain large +amounts of internal state, and reducing that state to the +size_t bytes that std::hash +returns is usually the slowest part of the computation, so it +should not be done more than once.

+ +

Due to exactly that issue, std::hash does not work +with std::pair or std::tuple, and the +language does not allow us to extend it to support them.

+
+ +
+

You can use std::hash with the types that it supports +"out of the box", but do not specialize it to support additional types. +If you need a hash table with a key type that std::hash +does not support, consider using legacy hash containers (e.g. +hash_map) for now; they use a different default hasher, +which is unaffected by this prohibition.

+ +

If you want to use the standard hash containers anyway, you will +need to specify a custom hasher for the key type, e.g.

+
std::unordered_map<MyKeyType, Value, MyKeyTypeHasher> my_map;
+

+Consult with the type's owners to see if there is an existing hasher +that you can use; otherwise work with them to provide one, + or roll your own.

+ +

We are planning to provide a hash function that can work with any type, +using a new customization mechanism that doesn't have the drawbacks of +std::hash.

+
+ +
+ +

C++11

+ +
+

Use libraries and language extensions from C++11 when appropriate. +Consider portability to other environments +before using C++11 features in your +project.

+ +
+ +
+ +
+

C++11 contains +significant changes both to the language and +libraries.

+
+ +
+

C++11 was the official standard until august 2014, and +is supported by most C++ compilers. It standardizes +some common C++ extensions that we use already, allows +shorthands for some operations, and has some performance +and safety improvements.

+
+ +
+

The C++11 standard is substantially more complex than +its predecessor (1,300 pages versus 800 pages), and is +unfamiliar to many developers. The long-term effects of +some features on code readability and maintenance are +unknown. We cannot predict when its various features will +be implemented uniformly by tools that may be of +interest, particularly in the case of projects that are +forced to use older versions of tools.

+ +

As with Boost, some C++11 +extensions encourage coding practices that hamper +readability—for example by removing +checked redundancy (such as type names) that may be +helpful to readers, or by encouraging template +metaprogramming. Other extensions duplicate functionality +available through existing mechanisms, which may lead to confusion +and conversion costs.

+ + +
+ +
+ +

C++11 features may be used unless specified otherwise. +In addition to what's described in the rest of the style +guide, the following C++11 features may not be used:

+ +
    + + + + + + + + +
  • Compile-time rational numbers + (<ratio>), because of concerns that + it's tied to a more template-heavy interface + style.
  • + +
  • The <cfenv> and + <fenv.h> headers, because many + compilers do not support those features reliably.
  • + +
  • Ref-qualifiers on member functions, such as void X::Foo() + & or void X::Foo() &&, because of concerns + that they're an overly obscure feature.
  • + + + + +
+
+ +
+ +

Nonstandard Extensions

+ +
+

Nonstandard extensions to C++ may not be used unless otherwise specified.

+
+
+
+

Compilers support various extensions that are not part of standard C++. Such + extensions include GCC's __attribute__, intrinsic functions such + as __builtin_prefetch, designated initializers (e.g. + Foo f = {.field = 3}), inline assembly, __COUNTER__, + __PRETTY_FUNCTION__, compound statement expressions (e.g. + foo = ({ int x; Bar(&x); x }), variable-length arrays and + alloca(), and the a?:b syntax.

+
+ +
+
    +
  • Nonstandard extensions may provide useful features that do not exist + in standard C++. For example, some people think that designated + initializers are more readable than standard C++ features like + constructors.
  • +
  • Important performance guidance to the compiler can only be specified + using extensions.
  • +
+
+ +
+
    +
  • Nonstandard extensions do not work in all compilers. Use of nonstandard + extensions reduces portability of code.
  • +
  • Even if they are supported in all targeted compilers, the extensions + are often not well-specified, and there may be subtle behavior differences + between compilers.
  • +
  • Nonstandard extensions add to the language features that a reader must + know to understand the code.
  • +
+
+ +
+

Do not use nonstandard extensions. You may use portability wrappers that + are implemented using nonstandard extensions, so long as those wrappers + + are provided by a designated project-wide + portability header.

+
+
+ +

Aliases

+ +
+

Public aliases are for the benefit of an API's user, and should be clearly documented.

+
+
+
+

There are several ways to create names that are aliases of other entities:

+
typedef Foo Bar;
+using Bar = Foo;
+using other_namespace::Foo;
+
+ +

Like other declarations, aliases declared in a header file are part of that + header's public API unless they're in a function definition, in the private portion of a class, + or in an explicitly-marked internal namespace. Aliases in such areas or in .cc files are + implementation details (because client code can't refer to them), and are not restricted by this + rule.

+
+ +
+
    +
  • Aliases can improve readability by simplifying a long or complicated name.
  • +
  • Aliases can reduce duplication by naming in one place a type used repeatedly in an API, + which might make it easier to change the type later. +
  • +
+
+ +
+
    +
  • When placed in a header where client code can refer to them, aliases increase the + number of entities in that header's API, increasing its complexity.
  • +
  • Clients can easily rely on unintended details of public aliases, making + changes difficult.
  • +
  • It can be tempting to create a public alias that is only intended for use + in the implementation, without considering its impact on the API, or on maintainability.
  • +
  • Aliases can create risk of name collisions
  • +
  • Aliases can reduce readability by giving a familiar construct an unfamiliar name
  • +
  • Type aliases can create an unclear API contract: + it is unclear whether the alias is guaranteed to be identical to the type it aliases, + to have the same API, or only to be usable in specified narrow ways
  • +
+
+ +
+

Don't put an alias in your public API just to save typing in the implementation; + do so only if you intend it to be used by your clients.

+

When defining a public alias, document the intent of +the new name, including whether it is guaranteed to always be the same as the type +it's currently aliased to, or whether a more limited compatibility is +intended. This lets the user know whether they can treat the types as +substitutable or whether more specific rules must be followed, and can help the +implementation retain some degree of freedom to change the alias.

+

Don't put namespace aliases in your public API. (See also Namespaces). +

+ +

For example, these aliases document how they are intended to be used in client code:

+
namespace a {
+// Used to store field measurements. DataPoint may change from Bar* to some internal type.
+// Client code should treat it as an opaque pointer.
+using DataPoint = foo::bar::Bar*;
+
+// A set of measurements. Just an alias for user convenience.
+using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>;
+}  // namespace a
+
+ +

These aliases don't document intended use, and half of them aren't meant for client use:

+ +
namespace a {
+// Bad: none of these say how they should be used.
+using DataPoint = foo::bar::Bar*;
+using std::unordered_set;  // Bad: just for local convenience
+using std::hash;           // Bad: just for local convenience
+typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries;
+}  // namespace a
+
+ +

However, local convenience aliases are fine in function definitions, private sections of + classes, explicitly marked internal namespaces, and in .cc files:

+ +
// In a .cc file
+using std::unordered_set;
+
+ +
+
+ +

Naming

+ +

The most important consistency rules are those that govern +naming. The style of a name immediately informs us what sort of +thing the named entity is: a type, a variable, a function, a +constant, a macro, etc., without requiring us to search for the +declaration of that entity. The pattern-matching engine in our +brains relies a great deal on these naming rules. +

+ +

Naming rules are pretty arbitrary, but + we feel that +consistency is more important than individual preferences in this +area, so regardless of whether you find them sensible or not, +the rules are the rules.

+ +

General Naming Rules

+ +
+

Names should be descriptive; avoid abbreviation.

+
+ +
+

Give as descriptive a name as possible, within reason. +Do not worry about saving horizontal space as it is far +more important to make your code immediately +understandable by a new reader. Do not use abbreviations +that are ambiguous or unfamiliar to readers outside your +project, and do not abbreviate by deleting letters within +a word.

+ +
int price_count_reader;    // No abbreviation.
+int num_errors;            // "num" is a widespread convention.
+int num_dns_connections;   // Most people know what "DNS" stands for.
+
+ +
int n;                     // Meaningless.
+int nerr;                  // Ambiguous abbreviation.
+int n_comp_conns;          // Ambiguous abbreviation.
+int wgc_connections;       // Only your group knows what this stands for.
+int pc_reader;             // Lots of things can be abbreviated "pc".
+int cstmr_id;              // Deletes internal letters.
+
+ +

Note that certain universally-known abbreviations are OK, such as +i for an iteration variable and T for a +template parameter.

+ +

Template parameters should follow the naming style for their +category: type template parameters should follow the rules for +type names, and non-type template +parameters should follow the rules for +variable names. + +

+ +

File Names

+ +
+

Filenames should be all lowercase and can include +underscores (_) or dashes (-). +Follow the convention that your + +project uses. If there is no consistent +local pattern to follow, prefer "_".

+
+ +
+ +

Examples of acceptable file names:

+ +
    +
  • my_useful_class.cc
  • +
  • my-useful-class.cc
  • +
  • myusefulclass.cc
  • +
  • myusefulclass_test.cc // _unittest and _regtest are deprecated.
  • +
+ +

C++ files should end in .cc and header files should end in +.h. Files that rely on being textually included at specific points +should end in .inc (see also the section on +self-contained headers).

+ +

Do not use filenames that already exist in +/usr/include, such as db.h.

+ +

In general, make your filenames very specific. For +example, use http_server_logs.h rather than +logs.h. A very common case is to have a pair +of files called, e.g., foo_bar.h and +foo_bar.cc, defining a class called +FooBar.

+ +

Inline functions must be in a .h file. If +your inline functions are very short, they should go +directly into your .h file.

+ +
+ +

Type Names

+ +
+

Type names start with a capital letter and have a capital +letter for each new word, with no underscores: +MyExcitingClass, MyExcitingEnum.

+
+ +
+ +

The names of all types — classes, structs, type aliases, +enums, and type template parameters — have the same naming convention. +Type names should start with a capital letter and have a capital letter +for each new word. No underscores. For example:

+ +
// classes and structs
+class UrlTable { ...
+class UrlTableTester { ...
+struct UrlTableProperties { ...
+
+// typedefs
+typedef hash_map<UrlTableProperties *, string> PropertiesMap;
+
+// using aliases
+using PropertiesMap = hash_map<UrlTableProperties *, string>;
+
+// enums
+enum UrlTableErrors { ...
+
+ +
+ +

Variable Names

+ +
+

The names of variables (including function parameters) and data members are +all lowercase, with underscores between words. Data members of classes (but not +structs) additionally have trailing underscores. For instance: +a_local_variable, a_struct_data_member, +a_class_data_member_.

+
+ +
+ +

Common Variable names

+ +

For example:

+ +
string table_name;  // OK - uses underscore.
+string tablename;   // OK - all lowercase.
+
+ +
string tableName;   // Bad - mixed case.
+
+ +

Class Data Members

+ +

Data members of classes, both static and non-static, are +named like ordinary nonmember variables, but with a +trailing underscore.

+ +
class TableInfo {
+  ...
+ private:
+  string table_name_;  // OK - underscore at end.
+  string tablename_;   // OK.
+  static Pool<TableInfo>* pool_;  // OK.
+};
+
+ +

Struct Data Members

+ +

Data members of structs, both static and non-static, +are named like ordinary nonmember variables. They do not have +the trailing underscores that data members in classes have.

+ +
struct UrlTableProperties {
+  string name;
+  int num_entries;
+  static Pool<UrlTableProperties>* pool;
+};
+
+ + +

See Structs vs. +Classes for a discussion of when to use a struct +versus a class.

+ +
+ +

Constant Names

+ +
+

Variables declared constexpr or const, and whose value is fixed for + the duration of the program, are named with a leading "k" followed + by mixed case. For example:

+
+ +
const int kDaysInAWeek = 7;
+
+ +
+ +

All such variables with static storage duration (i.e. statics and globals, + see + Storage Duration for details) should be named this way. This + convention is optional for variables of other storage classes, e.g. automatic + variables, otherwise the usual variable naming rules apply.

+ +

+ +

Function Names

+ +
+

Regular functions have mixed case; accessors and mutators may be named +like variables.

+
+ +
+ +

Ordinarily, functions should start with a capital letter and have a +capital letter for each new word +(a.k.a. "Camel +Case" or "Pascal case"). Such names should not have +underscores. Prefer to capitalize acronyms as single words +(i.e. StartRpc(), not StartRPC()).

+ +
AddTableEntry()
+DeleteUrl()
+OpenFileOrDie()
+
+ +

(The same naming rule applies to class- and namespace-scope +constants that are exposed as part of an API and that are intended to look +like functions, because the fact that they're +objects rather than functions is an unimportant implementation detail.)

+ +

Accessors and mutators (get and set functions) may be named like +variables. These often correspond to actual member variables, but this is +not required. For example, int count() and void +set_count(int count).

+ +
+ +

Namespace Names

+ +
+Namespace names are all lower-case. Top-level namespace names are +based on the project name +. Avoid collisions +between nested namespaces and well-known top-level namespaces. +
+ +
+

The name of a top-level namespace should usually be the +name of the project or team whose code is contained in that +namespace. The code in that namespace should usually be in +a directory whose basename matches the namespace name (or +subdirectories thereof).

+ + + + + +

Keep in mind that the rule +against abbreviated names applies to namespaces just as much +as variable names. Code inside the namespace seldom needs to +mention the namespace name, so there's usually no particular need +for abbreviation anyway.

+ +

Avoid nested namespaces that match well-known top-level +namespaces. Collisions between namespace names can lead to surprising +build breaks because of name lookup rules. In particular, do not +create any nested std namespaces. Prefer unique project +identifiers +(websearch::index, websearch::index_util) +over collision-prone names like websearch::util.

+ +

For internal namespaces, be wary of other code being +added to the same internal namespace causing a collision +(internal helpers within a team tend to be related and may lead to +collisions). In such a situation, using the filename to make a unique +internal name is helpful +(websearch::index::frobber_internal for use +in frobber.h)

+ +
+ +

Enumerator Names

+ +
+

Enumerators (for both scoped and unscoped enums) should be named either like +constants or like +macros: either kEnumName or +ENUM_NAME.

+
+ +
+ +

Preferably, the individual enumerators should be named +like constants. However, it +is also acceptable to name them like +macros. The enumeration name, +UrlTableErrors (and +AlternateUrlTableErrors), is a type, and +therefore mixed case.

+ +
enum UrlTableErrors {
+  kOK = 0,
+  kErrorOutOfMemory,
+  kErrorMalformedInput,
+};
+enum AlternateUrlTableErrors {
+  OK = 0,
+  OUT_OF_MEMORY = 1,
+  MALFORMED_INPUT = 2,
+};
+
+ +

Until January 2009, the style was to name enum values +like macros. This caused +problems with name collisions between enum values and +macros. Hence, the change to prefer constant-style naming +was put in place. New code should prefer constant-style +naming if possible. However, there is no reason to change +old code to use constant-style names, unless the old +names are actually causing a compile-time problem.

+ + + +
+ +

Macro Names

+ +
+

You're not really going to +define a macro, are you? If you do, they're like this: +MY_MACRO_THAT_SCARES_SMALL_CHILDREN.

+
+ +
+ +

Please see the description +of macros; in general macros should not be used. +However, if they are absolutely needed, then they should be +named with all capitals and underscores.

+ +
#define ROUND(x) ...
+#define PI_ROUNDED 3.0
+
+ +
+ +

Exceptions to Naming Rules

+ +
+

If you are naming something that is analogous to an +existing C or C++ entity then you can follow the existing +naming convention scheme.

+
+ +
+ +
+
bigopen()
+
function name, follows form of open()
+ +
uint
+
typedef
+ +
bigpos
+
struct or class, follows + form of pos
+ +
sparse_hash_map
+
STL-like entity; follows STL naming conventions
+ +
LONGLONG_MAX
+
a constant, as in INT_MAX
+
+ +
+ +

Comments

+ +

Though a pain to write, comments are absolutely vital to +keeping our code readable. The following rules describe what +you should comment and where. But remember: while comments are +very important, the best code is self-documenting. Giving +sensible names to types and variables is much better than using +obscure names that you must then explain through comments.

+ +

When writing your comments, write for your audience: the +next +contributor who will need to +understand your code. Be generous — the next +one may be you!

+ +

Comment Style

+ +
+

Use either the // or /* */ +syntax, as long as you are consistent.

+
+ +
+ +

You can use either the // or the /* +*/ syntax; however, // is +much more common. Be consistent with how you +comment and what style you use where.

+ +
+ +

File Comments

+ +
+

Start each file with license boilerplate.

+ +

File comments describe the contents of a file. If a file declares, +implements, or tests exactly one abstraction that is documented by a comment +at the point of declaration, file comments are not required. All other files +must have file comments.

+ +
+ +
+ +

Legal Notice and Author +Line

+ + + +

Every file should contain license +boilerplate. Choose the appropriate boilerplate for the +license used by the project (for example, Apache 2.0, +BSD, LGPL, GPL).

+ +

If you make significant changes to a file with an +author line, consider deleting the author line.

+ +

File Contents

+ +

If a .h declares multiple abstractions, the file-level comment +should broadly describe the contents of the file, and how the abstractions are +related. A 1 or 2 sentence file-level comment may be sufficient. The detailed +documentation about individual abstractions belongs with those abstractions, +not at the file level.

+ +

Do not duplicate comments in both the .h and the +.cc. Duplicated comments diverge.

+ +
+ +

Class Comments

+ +
+

Every non-obvious class declaration should have an accompanying +comment that describes what it is for and how it should be used.

+
+ +
+ +
// Iterates over the contents of a GargantuanTable.
+// Example:
+//    GargantuanTableIterator* iter = table->NewIterator();
+//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
+//      process(iter->key(), iter->value());
+//    }
+//    delete iter;
+class GargantuanTableIterator {
+  ...
+};
+
+ +

The class comment should provide the reader with enough information to know +how and when to use the class, as well as any additional considerations +necessary to correctly use the class. Document the synchronization assumptions +the class makes, if any. If an instance of the class can be accessed by +multiple threads, take extra care to document the rules and invariants +surrounding multithreaded use.

+ +

The class comment is often a good place for a small example code snippet +demonstrating a simple and focused usage of the class.

+ +

When sufficiently separated (e.g. .h and .cc +files), comments describing the use of the class should go together with its +interface definition; comments about the class operation and implementation +should accompany the implementation of the class's methods.

+ +
+ +

Function Comments

+ +
+

Declaration comments describe use of the function (when it is +non-obvious); comments at the definition of a function describe +operation.

+
+ +
+ +

Function Declarations

+ +

Almost every function declaration should have comments immediately +preceding it that describe what the function does and how to use +it. These comments may be omitted only if the function is simple and +obvious (e.g. simple accessors for obvious properties of the +class). These comments should be descriptive ("Opens the file") +rather than imperative ("Open the file"); the comment describes the +function, it does not tell the function what to do. In general, these +comments do not describe how the function performs its task. Instead, +that should be left to comments in the function definition.

+ +

Types of things to mention in comments at the function +declaration:

+ +
    +
  • What the inputs and outputs are.
  • + +
  • For class member functions: whether the object + remembers reference arguments beyond the duration of + the method call, and whether it will free them or + not.
  • + +
  • If the function allocates memory that the caller + must free.
  • + +
  • Whether any of the arguments can be a null + pointer.
  • + +
  • If there are any performance implications of how a + function is used.
  • + +
  • If the function is re-entrant. What are its + synchronization assumptions?
  • +
+ +

Here is an example:

+ +
// Returns an iterator for this table.  It is the client's
+// responsibility to delete the iterator when it is done with it,
+// and it must not use the iterator once the GargantuanTable object
+// on which the iterator was created has been deleted.
+//
+// The iterator is initially positioned at the beginning of the table.
+//
+// This method is equivalent to:
+//    Iterator* iter = table->NewIterator();
+//    iter->Seek("");
+//    return iter;
+// If you are going to immediately seek to another place in the
+// returned iterator, it will be faster to use NewIterator()
+// and avoid the extra seek.
+Iterator* GetIterator() const;
+
+ +

However, do not be unnecessarily verbose or state the +completely obvious. Notice below that it is not necessary + to say "returns false otherwise" because this is +implied.

+ +
// Returns true if the table cannot hold any more entries.
+bool IsTableFull();
+
+ +

When documenting function overrides, focus on the +specifics of the override itself, rather than repeating +the comment from the overridden function. In many of these +cases, the override needs no additional documentation and +thus no comment is required.

+ +

When commenting constructors and destructors, remember +that the person reading your code knows what constructors +and destructors are for, so comments that just say +something like "destroys this object" are not useful. +Document what constructors do with their arguments (for +example, if they take ownership of pointers), and what +cleanup the destructor does. If this is trivial, just +skip the comment. It is quite common for destructors not +to have a header comment.

+ +

Function Definitions

+ +

If there is anything tricky about how a function does +its job, the function definition should have an +explanatory comment. For example, in the definition +comment you might describe any coding tricks you use, +give an overview of the steps you go through, or explain +why you chose to implement the function in the way you +did rather than using a viable alternative. For instance, +you might mention why it must acquire a lock for the +first half of the function but why it is not needed for +the second half.

+ +

Note you should not just repeat the comments +given with the function declaration, in the +.h file or wherever. It's okay to +recapitulate briefly what the function does, but the +focus of the comments should be on how it does it.

+ +
+ +

Variable Comments

+ +
+

In general the actual name of the variable should be +descriptive enough to give a good idea of what the variable +is used for. In certain cases, more comments are required.

+
+ +
+ +

Class Data Members

+ +

The purpose of each class data member (also called an instance +variable or member variable) must be clear. If there are any +invariants (special values, relationships between members, lifetime +requirements) not clearly expressed by the type and name, they must be +commented. However, if the type and name suffice (int +num_events_;), no comment is needed.

+ +

In particular, add comments to describe the existence and meaning +of sentinel values, such as nullptr or -1, when they are not +obvious. For example:

+ +
private:
+ // Used to bounds-check table accesses. -1 means
+ // that we don't yet know how many entries the table has.
+ int num_total_entries_;
+
+ +

Global Variables

+ +

All global variables should have a comment describing what they +are, what they are used for, and (if unclear) why it needs to be +global. For example:

+ +
// The total number of tests cases that we run through in this regression test.
+const int kNumTestCases = 6;
+
+ +
+ +

Implementation Comments

+ +
+

In your implementation you should have comments in tricky, +non-obvious, interesting, or important parts of your code.

+
+ +
+ +

Explanatory Comments

+ +

Tricky or complicated code blocks should have comments +before them. Example:

+ +
// Divide result by two, taking into account that x
+// contains the carry from the add.
+for (int i = 0; i < result->size(); i++) {
+  x = (x << 8) + (*result)[i];
+  (*result)[i] = x >> 1;
+  x &= 1;
+}
+
+ +

Line Comments

+ +

Also, lines that are non-obvious should get a comment +at the end of the line. These end-of-line comments should +be separated from the code by 2 spaces. Example:

+ +
// If we have enough memory, mmap the data portion too.
+mmap_budget = max<int64>(0, mmap_budget - index_->length());
+if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock))
+  return;  // Error already logged.
+
+ +

Note that there are both comments that describe what +the code is doing, and comments that mention that an +error has already been logged when the function +returns.

+ +

If you have several comments on subsequent lines, it +can often be more readable to line them up:

+ +
DoSomething();                  // Comment here so the comments line up.
+DoSomethingElseThatIsLonger();  // Two spaces between the code and the comment.
+{ // One space before comment when opening a new scope is allowed,
+  // thus the comment lines up with the following comments and code.
+  DoSomethingElse();  // Two spaces before line comments normally.
+}
+std::vector<string> list{
+                    // Comments in braced lists describe the next element...
+                    "First item",
+                    // .. and should be aligned appropriately.
+                    "Second item"};
+DoSomething(); /* For trailing block comments, one space is fine. */
+
+ +

Function Argument Comments

+ +

When the meaning of a function argument is nonobvious, consider +one of the following remedies:

+ +
    +
  • If the argument is a literal constant, and the same constant is + used in multiple function calls in a way that tacitly assumes they're + the same, you should use a named constant to make that constraint + explicit, and to guarantee that it holds.
  • + +
  • Consider changing the function signature to replace a bool + argument with an enum argument. This will make the argument + values self-describing.
  • + +
  • For functions that have several configuration options, consider + defining a single class or struct to hold all the options + , + and pass an instance of that. + This approach has several advantages. Options are referenced by name + at the call site, which clarifies their meaning. It also reduces + function argument count, which makes function calls easier to read and + write. As an added benefit, you don't have to change call sites when + you add another option. +
  • + +
  • Replace large or complex nested expressions with named variables.
  • + +
  • As a last resort, use comments to clarify argument meanings at the + call site.
  • +
+ +Consider the following example: + +
// What are these arguments?
+const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);
+
+ +

versus:

+ +
ProductOptions options;
+options.set_precision_decimals(7);
+options.set_use_cache(ProductOptions::kDontUseCache);
+const DecimalNumber product =
+    CalculateProduct(values, options, /*completion_callback=*/nullptr);
+
+ +

Don'ts

+ +

Do not state the obvious. In particular, don't literally describe what +code does, unless the behavior is nonobvious to a reader who understands +C++ well. Instead, provide higher level comments that describe why +the code does what it does, or make the code self describing.

+ +Compare this: + +
// Find the element in the vector.  <-- Bad: obvious!
+auto iter = std::find(v.begin(), v.end(), element);
+if (iter != v.end()) {
+  Process(element);
+}
+
+ +To this: + +
// Process "element" unless it was already processed.
+auto iter = std::find(v.begin(), v.end(), element);
+if (iter != v.end()) {
+  Process(element);
+}
+
+ +Self-describing code doesn't need a comment. The comment from +the example above would be obvious: + +
if (!IsAlreadyProcessed(element)) {
+  Process(element);
+}
+
+ +
+ +

Punctuation, Spelling and Grammar

+ +
+

Pay attention to punctuation, spelling, and grammar; it is +easier to read well-written comments than badly written +ones.

+
+ +
+ +

Comments should be as readable as narrative text, with +proper capitalization and punctuation. In many cases, +complete sentences are more readable than sentence +fragments. Shorter comments, such as comments at the end +of a line of code, can sometimes be less formal, but you +should be consistent with your style.

+ +

Although it can be frustrating to have a code reviewer +point out that you are using a comma when you should be +using a semicolon, it is very important that source code +maintain a high level of clarity and readability. Proper +punctuation, spelling, and grammar help with that +goal.

+ +
+ +

TODO Comments

+ +
+

Use TODO comments for code that is temporary, +a short-term solution, or good-enough but not perfect.

+
+ +
+ +

TODOs should include the string +TODO in all caps, followed by the + +name, e-mail address, bug ID, or other +identifier +of the person or issue with the best context +about the problem referenced by the TODO. The +main purpose is to have a consistent TODO that +can be searched to find out how to get more details upon +request. A TODO is not a commitment that the +person referenced will fix the problem. Thus when you create +a TODO with a name, it is almost always your +name that is given.

+ + + +
+
// TODO(kl@gmail.com): Use a "*" here for concatenation operator.
+// TODO(Zeke) change this to use relations.
+// TODO(bug 12345): remove the "Last visitors" feature
+
+
+ +

If your TODO is of the form "At a future +date do something" make sure that you either include a +very specific date ("Fix by November 2005") or a very +specific event ("Remove this code when all clients can +handle XML responses.").

+ +
+ +

Deprecation Comments

+ +
+

Mark deprecated interface points with DEPRECATED +comments.

+
+ +
+ +

You can mark an interface as deprecated by writing a +comment containing the word DEPRECATED in +all caps. The comment goes either before the declaration +of the interface or on the same line as the +declaration.

+ + + +

After the word +DEPRECATED, write your name, e-mail address, +or other identifier in parentheses.

+ +

A deprecation comment must include simple, clear +directions for people to fix their callsites. In C++, you +can implement a deprecated function as an inline function +that calls the new interface point.

+ +

Marking an interface point DEPRECATED +will not magically cause any callsites to change. If you +want people to actually stop using the deprecated +facility, you will have to fix the callsites yourself or +recruit a crew to help you.

+ +

New code should not contain calls to deprecated +interface points. Use the new interface point instead. If +you cannot understand the directions, find the person who +created the deprecation and ask them for help using the +new interface point.

+ + + +
+ +

Formatting

+ +

Coding style and formatting are pretty arbitrary, but a + +project is much easier to follow +if everyone uses the same style. Individuals may not agree with every +aspect of the formatting rules, and some of the rules may take +some getting used to, but it is important that all + +project contributors follow the +style rules so that +they can all read and understand +everyone's code easily.

+ + + +

To help you format code correctly, we've +created a + +settings file for emacs.

+ +

Line Length

+ +
+

Each line of text in your code should be at most 80 +characters long.

+
+ +
+ + + +

We recognize that this rule is +controversial, but so much existing code already adheres +to it, and we feel that consistency is important.

+ +
+

Those who favor this rule +argue that it is rude to force them to resize +their windows and there is no need for anything longer. +Some folks are used to having several code windows +side-by-side, and thus don't have room to widen their +windows in any case. People set up their work environment +assuming a particular maximum window width, and 80 +columns has been the traditional standard. Why change +it?

+
+ +
+

Proponents of change argue that a wider line can make +code more readable. The 80-column limit is an hidebound +throwback to 1960s mainframes; modern equipment has wide screens that +can easily show longer lines.

+
+ +
+

80 characters is the maximum.

+ +

Comment lines can be longer than 80 +characters if it is not feasible to split them without +harming readability, ease of cut and paste or auto-linking +-- e.g. if a line contains an example command or a literal +URL longer than 80 characters.

+ +

A raw-string literal may have content +that exceeds 80 characters. Except for test code, such literals +should appear near the top of a file.

+ +

An #include statement with a +long path may exceed 80 columns.

+ +

You needn't be concerned about +header guards that exceed +the maximum length.

+
+ +
+ +

Non-ASCII Characters

+ +
+

Non-ASCII characters should be rare, and must use UTF-8 +formatting.

+
+ +
+ +

You shouldn't hard-code user-facing text in source, +even English, so use of non-ASCII characters should be +rare. However, in certain cases it is appropriate to +include such words in your code. For example, if your +code parses data files from foreign sources, it may be +appropriate to hard-code the non-ASCII string(s) used in +those data files as delimiters. More commonly, unittest +code (which does not need to be localized) might +contain non-ASCII strings. In such cases, you should use +UTF-8, since that is an encoding +understood by most tools able to handle more than just +ASCII.

+ +

Hex encoding is also OK, and encouraged where it +enhances readability — for example, +"\xEF\xBB\xBF", or, even more simply, +u8"\uFEFF", is the Unicode zero-width +no-break space character, which would be invisible if +included in the source as straight UTF-8.

+ +

Use the u8 prefix +to guarantee that a string literal containing +\uXXXX escape sequences is encoded as UTF-8. +Do not use it for strings containing non-ASCII characters +encoded as UTF-8, because that will produce incorrect +output if the compiler does not interpret the source file +as UTF-8.

+ +

You shouldn't use the C++11 char16_t and +char32_t character types, since they're for +non-UTF-8 text. For similar reasons you also shouldn't +use wchar_t (unless you're writing code that +interacts with the Windows API, which uses +wchar_t extensively).

+ +
+ +

Spaces vs. Tabs

+ +
+

Use only spaces, and indent 2 spaces at a time.

+
+ +
+ +

We use spaces for indentation. Do not use tabs in your +code. You should set your editor to emit spaces when you +hit the tab key.

+ +
+ +

Function Declarations and Definitions

+ +
+

Return type on the same line as function name, parameters +on the same line if they fit. Wrap parameter lists which do +not fit on a single line as you would wrap arguments in a +function call.

+
+ +
+ +

Functions look like this:

+ + +
ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
+  DoSomething();
+  ...
+}
+
+ +

If you have too much text to fit on one line:

+ +
ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
+                                             Type par_name3) {
+  DoSomething();
+  ...
+}
+
+ +

or if you cannot fit even the first parameter:

+ +
ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
+    Type par_name1,  // 4 space indent
+    Type par_name2,
+    Type par_name3) {
+  DoSomething();  // 2 space indent
+  ...
+}
+
+ +

Some points to note:

+ +
    +
  • Choose good parameter names.
  • + +
  • Parameter names may be omitted only if the parameter is unused and its + purpose is obvious.
  • + +
  • If you cannot fit the return type and the function + name on a single line, break between them.
  • + +
  • If you break after the return type of a function + declaration or definition, do not indent.
  • + +
  • The open parenthesis is always on the same line as + the function name.
  • + +
  • There is never a space between the function name + and the open parenthesis.
  • + +
  • There is never a space between the parentheses and + the parameters.
  • + +
  • The open curly brace is always on the end of the last line of the function + declaration, not the start of the next line.
  • + +
  • The close curly brace is either on the last line by + itself or on the same line as the open curly brace.
  • + +
  • There should be a space between the close + parenthesis and the open curly brace.
  • + +
  • All parameters should be aligned if possible.
  • + +
  • Default indentation is 2 spaces.
  • + +
  • Wrapped parameters have a 4 space indent.
  • +
+ +

Unused parameters that are obvious from context may be omitted:

+ +
class Foo {
+ public:
+  Foo(Foo&&);
+  Foo(const Foo&);
+  Foo& operator=(Foo&&);
+  Foo& operator=(const Foo&);
+};
+
+ +

Unused parameters that might not be obvious should comment out the variable +name in the function definition:

+ +
class Shape {
+ public:
+  virtual void Rotate(double radians) = 0;
+};
+
+class Circle : public Shape {
+ public:
+  void Rotate(double radians) override;
+};
+
+void Circle::Rotate(double /*radians*/) {}
+
+ +
// Bad - if someone wants to implement later, it's not clear what the
+// variable means.
+void Circle::Rotate(double) {}
+
+ +

Attributes, and macros that expand to attributes, appear at the very +beginning of the function declaration or definition, before the +return type:

+
MUST_USE_RESULT bool IsOK();
+
+ +
+ +

Lambda Expressions

+ +
+

Format parameters and bodies as for any other function, and capture +lists like other comma-separated lists.

+
+ +
+

For by-reference captures, do not leave a space between the +ampersand (&) and the variable name.

+
int x = 0;
+auto x_plus_n = [&x](int n) -> int { return x + n; }
+
+

Short lambdas may be written inline as function arguments.

+
std::set<int> blacklist = {7, 8, 9};
+std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
+digits.erase(std::remove_if(digits.begin(), digits.end(), [&blacklist](int i) {
+               return blacklist.find(i) != blacklist.end();
+             }),
+             digits.end());
+
+ +
+ +

Function Calls

+ +
+

Either write the call all on a single line, wrap the +arguments at the parenthesis, or start the arguments on a new +line indented by four spaces and continue at that 4 space +indent. In the absence of other considerations, use the +minimum number of lines, including placing multiple arguments +on each line where appropriate.

+
+ +
+ +

Function calls have the following format:

+
bool result = DoSomething(argument1, argument2, argument3);
+
+ +

If the arguments do not all fit on one line, they +should be broken up onto multiple lines, with each +subsequent line aligned with the first argument. Do not +add spaces after the open paren or before the close +paren:

+
bool result = DoSomething(averyveryveryverylongargument1,
+                          argument2, argument3);
+
+ +

Arguments may optionally all be placed on subsequent +lines with a four space indent:

+
if (...) {
+  ...
+  ...
+  if (...) {
+    bool result = DoSomething(
+        argument1, argument2,  // 4 space indent
+        argument3, argument4);
+    ...
+  }
+
+ +

Put multiple arguments on a single line to reduce the +number of lines necessary for calling a function unless +there is a specific readability problem. Some find that +formatting with strictly one argument on each line is +more readable and simplifies editing of the arguments. +However, we prioritize for the reader over the ease of +editing arguments, and most readability problems are +better addressed with the following techniques.

+ +

If having multiple arguments in a single line decreases +readability due to the complexity or confusing nature of the +expressions that make up some arguments, try creating +variables that capture those arguments in a descriptive name:

+
int my_heuristic = scores[x] * y + bases[x];
+bool result = DoSomething(my_heuristic, x, y, z);
+
+ +

Or put the confusing argument on its own line with +an explanatory comment:

+
bool result = DoSomething(scores[x] * y + bases[x],  // Score heuristic.
+                          x, y, z);
+
+ +

If there is still a case where one argument is +significantly more readable on its own line, then put it on +its own line. The decision should be specific to the argument +which is made more readable rather than a general policy.

+ +

Sometimes arguments form a structure that is important +for readability. In those cases, feel free to format the +arguments according to that structure:

+
// Transform the widget by a 3x3 matrix.
+my_widget.Transform(x1, x2, x3,
+                    y1, y2, y3,
+                    z1, z2, z3);
+
+ +
+ +

Braced Initializer List Format

+ +
+

Format a braced initializer list +exactly like you would format a function call in its place.

+
+ +
+ +

If the braced list follows a name (e.g. a type or +variable name), format as if the {} were the +parentheses of a function call with that name. If there +is no name, assume a zero-length name.

+ +
// Examples of braced init list on a single line.
+return {foo, bar};
+functioncall({foo, bar});
+std::pair<int, int> p{foo, bar};
+
+// When you have to wrap.
+SomeFunction(
+    {"assume a zero-length name before {"},
+    some_other_function_parameter);
+SomeType variable{
+    some, other, values,
+    {"assume a zero-length name before {"},
+    SomeOtherType{
+        "Very long string requiring the surrounding breaks.",
+        some, other values},
+    SomeOtherType{"Slightly shorter string",
+                  some, other, values}};
+SomeType variable{
+    "This is too long to fit all in one line"};
+MyType m = {  // Here, you could also break before {.
+    superlongvariablename1,
+    superlongvariablename2,
+    {short, interior, list},
+    {interiorwrappinglist,
+     interiorwrappinglist2}};
+
+ +
+ +

Conditionals

+ +
+

Prefer no spaces inside parentheses. The if +and else keywords belong on separate lines.

+
+ +
+ +

There are two acceptable formats for a basic +conditional statement. One includes spaces between the +parentheses and the condition, and one does not.

+ +

The most common form is without spaces. Either is +fine, but be consistent. If you are modifying a +file, use the format that is already present. If you are +writing new code, use the format that the other files in +that directory or project use. If in doubt and you have +no personal preference, do not add the spaces.

+ +
if (condition) {  // no spaces inside parentheses
+  ...  // 2 space indent.
+} else if (...) {  // The else goes on the same line as the closing brace.
+  ...
+} else {
+  ...
+}
+
+ +

If you prefer you may add spaces inside the +parentheses:

+ +
if ( condition ) {  // spaces inside parentheses - rare
+  ...  // 2 space indent.
+} else {  // The else goes on the same line as the closing brace.
+  ...
+}
+
+ +

Note that in all cases you must have a space between +the if and the open parenthesis. You must +also have a space between the close parenthesis and the +curly brace, if you're using one.

+ +
if(condition) {   // Bad - space missing after IF.
+if (condition){   // Bad - space missing before {.
+if(condition){    // Doubly bad.
+
+ +
if (condition) {  // Good - proper space after IF and before {.
+
+ +

Short conditional statements may be written on one +line if this enhances readability. You may use this only +when the line is brief and the statement does not use the +else clause.

+ +
if (x == kFoo) return new Foo();
+if (x == kBar) return new Bar();
+
+ +

This is not allowed when the if statement has an +else:

+ +
// Not allowed - IF statement on one line when there is an ELSE clause
+if (x) DoThis();
+else DoThat();
+
+ +

In general, curly braces are not required for +single-line statements, but they are allowed if you like +them; conditional or loop statements with complex +conditions or statements may be more readable with curly +braces. Some +projects require that an +if must always always have an accompanying +brace.

+ +
if (condition)
+  DoSomething();  // 2 space indent.
+
+if (condition) {
+  DoSomething();  // 2 space indent.
+}
+
+ +

However, if one part of an +if-else statement uses curly +braces, the other part must too:

+ +
// Not allowed - curly on IF but not ELSE
+if (condition) {
+  foo;
+} else
+  bar;
+
+// Not allowed - curly on ELSE but not IF
+if (condition)
+  foo;
+else {
+  bar;
+}
+
+ +
// Curly braces around both IF and ELSE required because
+// one of the clauses used braces.
+if (condition) {
+  foo;
+} else {
+  bar;
+}
+
+ +
+ +

Loops and Switch Statements

+ +
+

Switch statements may use braces for blocks. Annotate +non-trivial fall-through between cases. +Braces are optional for single-statement loops. +Empty loop bodies should use empty braces or continue.

+
+ +
+ +

case blocks in switch +statements can have curly braces or not, depending on +your preference. If you do include curly braces they +should be placed as shown below.

+ +

If not conditional on an enumerated value, switch +statements should always have a default case +(in the case of an enumerated value, the compiler will +warn you if any values are not handled). If the default +case should never execute, simply +assert:

+ + + +
+
switch (var) {
+  case 0: {  // 2 space indent
+    ...      // 4 space indent
+    break;
+  }
+  case 1: {
+    ...
+    break;
+  }
+  default: {
+    assert(false);
+  }
+}
+
+
+ + + + + +

Braces are optional for single-statement loops.

+ +
for (int i = 0; i < kSomeNumber; ++i)
+  printf("I love you\n");
+
+for (int i = 0; i < kSomeNumber; ++i) {
+  printf("I take it back\n");
+}
+
+ + +

Empty loop bodies should use an empty pair of braces or continue, +but not a single semicolon.

+ +
while (condition) {
+  // Repeat test until it returns false.
+}
+for (int i = 0; i < kSomeNumber; ++i) {}  // Good - one newline is also OK.
+while (condition) continue;  // Good - continue indicates no logic.
+
+ +
while (condition);  // Bad - looks like part of do/while loop.
+
+ +
+ +

Pointer and Reference Expressions

+ +
+

No spaces around period or arrow. Pointer operators do not +have trailing spaces.

+
+ +
+ +

The following are examples of correctly-formatted +pointer and reference expressions:

+ +
x = *p;
+p = &x;
+x = r.y;
+x = r->y;
+
+ +

Note that:

+ +
    +
  • There are no spaces around the period or arrow when + accessing a member.
  • + +
  • Pointer operators have no space after the + * or &.
  • +
+ +

When declaring a pointer variable or argument, you may +place the asterisk adjacent to either the type or to the +variable name:

+ +
// These are fine, space preceding.
+char *c;
+const string &str;
+
+// These are fine, space following.
+char* c;
+const string& str;
+
+ +It is allowed (if unusual) to declare multiple variables in the same +declaration, but it is disallowed if any of those have pointer or +reference decorations. Such declarations are easily misread. +
// Fine if helpful for readability.
+int x, y;
+
+
int x, *y;  // Disallowed - no & or * in multiple declaration
+char * c;  // Bad - spaces on both sides of *
+const string & str;  // Bad - spaces on both sides of &
+
+ +

You should do this consistently within a single +file, +so, when modifying an existing file, use the style in +that file.

+ +
+ +

Boolean Expressions

+ +
+

When you have a boolean expression that is longer than the +standard line length, be +consistent in how you break up the lines.

+
+ +
+ +

In this example, the logical AND operator is always at +the end of the lines:

+ +
if (this_one_thing > this_other_thing &&
+    a_third_thing == a_fourth_thing &&
+    yet_another && last_one) {
+  ...
+}
+
+ +

Note that when the code wraps in this example, both of +the && logical AND operators are at +the end of the line. This is more common in Google code, +though wrapping all operators at the beginning of the +line is also allowed. Feel free to insert extra +parentheses judiciously because they can be very helpful +in increasing readability when used +appropriately. Also note that you should always use +the punctuation operators, such as +&& and ~, rather than +the word operators, such as and and +compl.

+ +
+ +

Return Values

+ +
+

Do not needlessly surround the return +expression with parentheses.

+
+ +
+ +

Use parentheses in return expr; only +where you would use them in x = expr;.

+ +
return result;                  // No parentheses in the simple case.
+// Parentheses OK to make a complex expression more readable.
+return (some_long_condition &&
+        another_condition);
+
+ +
return (value);                // You wouldn't write var = (value);
+return(result);                // return is not a function!
+
+ +
+ + + +

Variable and Array Initialization

+ +
+

Your choice of =, (), or +{}.

+
+ +
+ +

You may choose between =, +(), and {}; the following are +all correct:

+ +
int x = 3;
+int x(3);
+int x{3};
+string name = "Some Name";
+string name("Some Name");
+string name{"Some Name"};
+
+ +

Be careful when using a braced initialization list {...} +on a type with an std::initializer_list constructor. +A nonempty braced-init-list prefers the +std::initializer_list constructor whenever +possible. Note that empty braces {} are special, and +will call a default constructor if available. To force the +non-std::initializer_list constructor, use parentheses +instead of braces.

+ +
std::vector<int> v(100, 1);  // A vector of 100 1s.
+std::vector<int> v{100, 1};  // A vector of 100, 1.
+
+ +

Also, the brace form prevents narrowing of integral +types. This can prevent some types of programming +errors.

+ +
int pi(3.14);  // OK -- pi == 3.
+int pi{3.14};  // Compile error: narrowing conversion.
+
+ +
+ +

Preprocessor Directives

+ +
+

The hash mark that starts a preprocessor directive should +always be at the beginning of the line.

+
+ +
+ +

Even when preprocessor directives are within the body +of indented code, the directives should start at the +beginning of the line.

+ +
// Good - directives at beginning of line
+  if (lopsided_score) {
+#if DISASTER_PENDING      // Correct -- Starts at beginning of line
+    DropEverything();
+# if NOTIFY               // OK but not required -- Spaces after #
+    NotifyClient();
+# endif
+#endif
+    BackToNormal();
+  }
+
+ +
// Bad - indented directives
+  if (lopsided_score) {
+    #if DISASTER_PENDING  // Wrong!  The "#if" should be at beginning of line
+    DropEverything();
+    #endif                // Wrong!  Do not indent "#endif"
+    BackToNormal();
+  }
+
+ +
+ +

Class Format

+ +
+

Sections in public, protected and +private order, each indented one space.

+
+ +
+ +

The basic format for a class definition (lacking the +comments, see Class +Comments for a discussion of what comments are +needed) is:

+ +
class MyClass : public OtherClass {
+ public:      // Note the 1 space indent!
+  MyClass();  // Regular 2 space indent.
+  explicit MyClass(int var);
+  ~MyClass() {}
+
+  void SomeFunction();
+  void SomeFunctionThatDoesNothing() {
+  }
+
+  void set_some_var(int var) { some_var_ = var; }
+  int some_var() const { return some_var_; }
+
+ private:
+  bool SomeInternalFunction();
+
+  int some_var_;
+  int some_other_var_;
+};
+
+ +

Things to note:

+ +
    +
  • Any base class name should be on the same line as + the subclass name, subject to the 80-column limit.
  • + +
  • The public:, protected:, + and private: keywords should be indented + one space.
  • + +
  • Except for the first instance, these keywords + should be preceded by a blank line. This rule is + optional in small classes.
  • + +
  • Do not leave a blank line after these + keywords.
  • + +
  • The public section should be first, + followed by the protected and finally the + private section.
  • + +
  • See Declaration + Order for rules on ordering declarations within + each of these sections.
  • +
+ +
+ +

Constructor Initializer Lists

+ +
+

Constructor initializer lists can be all on one line or +with subsequent lines indented four spaces.

+
+ +
+ +

The acceptable formats for initializer lists are:

+ +
// When everything fits on one line:
+MyClass::MyClass(int var) : some_var_(var) {
+  DoSomething();
+}
+
+// If the signature and initializer list are not all on one line,
+// you must wrap before the colon and indent 4 spaces:
+MyClass::MyClass(int var)
+    : some_var_(var), some_other_var_(var + 1) {
+  DoSomething();
+}
+
+// When the list spans multiple lines, put each member on its own line
+// and align them:
+MyClass::MyClass(int var)
+    : some_var_(var),             // 4 space indent
+      some_other_var_(var + 1) {  // lined up
+  DoSomething();
+}
+
+// As with any other code block, the close curly can be on the same
+// line as the open curly, if it fits.
+MyClass::MyClass(int var)
+    : some_var_(var) {}
+
+ +
+ +

Namespace Formatting

+ +
+

The contents of namespaces are not indented.

+
+ +
+ +

Namespaces do not add an +extra level of indentation. For example, use:

+ +
namespace {
+
+void foo() {  // Correct.  No extra indentation within namespace.
+  ...
+}
+
+}  // namespace
+
+ +

Do not indent within a namespace:

+ +
namespace {
+
+  // Wrong.  Indented when it should not be.
+  void foo() {
+    ...
+  }
+
+}  // namespace
+
+ +

When declaring nested namespaces, put each namespace +on its own line.

+ +
namespace foo {
+namespace bar {
+
+ +
+ +

Horizontal Whitespace

+ +
+

Use of horizontal whitespace depends on location. Never put +trailing whitespace at the end of a line.

+
+ +
+ +

General

+ +
void f(bool b) {  // Open braces should always have a space before them.
+  ...
+int i = 0;  // Semicolons usually have no space before them.
+// Spaces inside braces for braced-init-list are optional.  If you use them,
+// put them on both sides!
+int x[] = { 0 };
+int x[] = {0};
+
+// Spaces around the colon in inheritance and initializer lists.
+class Foo : public Bar {
+ public:
+  // For inline function implementations, put spaces between the braces
+  // and the implementation itself.
+  Foo(int b) : Bar(), baz_(b) {}  // No spaces inside empty braces.
+  void Reset() { baz_ = 0; }  // Spaces separating braces from implementation.
+  ...
+
+ +

Adding trailing whitespace can cause extra work for +others editing the same file, when they merge, as can +removing existing trailing whitespace. So: Don't +introduce trailing whitespace. Remove it if you're +already changing that line, or do it in a separate +clean-up +operation (preferably when no-one +else is working on the file).

+ +

Loops and Conditionals

+ +
if (b) {          // Space after the keyword in conditions and loops.
+} else {          // Spaces around else.
+}
+while (test) {}   // There is usually no space inside parentheses.
+switch (i) {
+for (int i = 0; i < 5; ++i) {
+// Loops and conditions may have spaces inside parentheses, but this
+// is rare.  Be consistent.
+switch ( i ) {
+if ( test ) {
+for ( int i = 0; i < 5; ++i ) {
+// For loops always have a space after the semicolon.  They may have a space
+// before the semicolon, but this is rare.
+for ( ; i < 5 ; ++i) {
+  ...
+
+// Range-based for loops always have a space before and after the colon.
+for (auto x : counts) {
+  ...
+}
+switch (i) {
+  case 1:         // No space before colon in a switch case.
+    ...
+  case 2: break;  // Use a space after a colon if there's code after it.
+
+ +

Operators

+ +
// Assignment operators always have spaces around them.
+x = 0;
+
+// Other binary operators usually have spaces around them, but it's
+// OK to remove spaces around factors.  Parentheses should have no
+// internal padding.
+v = w * x + y / z;
+v = w*x + y/z;
+v = w * (x + z);
+
+// No spaces separating unary operators and their arguments.
+x = -5;
+++x;
+if (x && !y)
+  ...
+
+ +

Templates and Casts

+ +
// No spaces inside the angle brackets (< and >), before
+// <, or between >( in a cast
+std::vector<string> x;
+y = static_cast<char*>(x);
+
+// Spaces between type and pointer are OK, but be consistent.
+std::vector<char *> x;
+
+ +
+ +

Vertical Whitespace

+ +
+

Minimize use of vertical whitespace.

+
+ +
+ +

This is more a principle than a rule: don't use blank +lines when you don't have to. In particular, don't put +more than one or two blank lines between functions, +resist starting functions with a blank line, don't end +functions with a blank line, and be discriminating with +your use of blank lines inside functions.

+ +

The basic principle is: The more code that fits on one +screen, the easier it is to follow and understand the +control flow of the program. Of course, readability can +suffer from code being too dense as well as too spread +out, so use your judgement. But in general, minimize use +of vertical whitespace.

+ +

Some rules of thumb to help when blank lines may be +useful:

+ +
    +
  • Blank lines at the beginning or end of a function + very rarely help readability.
  • + +
  • Blank lines inside a chain of if-else blocks may + well help readability.
  • +
+ +
+ +

Exceptions to the Rules

+ +

The coding conventions described above are mandatory. +However, like all good rules, these sometimes have exceptions, +which we discuss here.

+ + + +
+

Existing Non-conformant Code

+ +
+

You may diverge from the rules when dealing with code that +does not conform to this style guide.

+
+ +
+ +

If you find yourself modifying code that was written +to specifications other than those presented by this +guide, you may have to diverge from these rules in order +to stay consistent with the local conventions in that +code. If you are in doubt about how to do this, ask the +original author or the person currently responsible for +the code. Remember that consistency includes +local consistency, too.

+ +
+
+ + + +

Windows Code

+ +
+

Windows +programmers have developed their own set of coding +conventions, mainly derived from the conventions in Windows +headers and other Microsoft code. We want to make it easy +for anyone to understand your code, so we have a single set +of guidelines for everyone writing C++ on any platform.

+
+ +
+

It is worth reiterating a few of the guidelines that +you might forget if you are used to the prevalent Windows +style:

+ +
    +
  • Do not use Hungarian notation (for example, naming + an integer iNum). Use the Google naming + conventions, including the .cc extension + for source files.
  • + +
  • Windows defines many of its own synonyms for + primitive types, such as DWORD, + HANDLE, etc. It is perfectly acceptable, + and encouraged, that you use these types when calling + Windows API functions. Even so, keep as close as you + can to the underlying C++ types. For example, use + const TCHAR * instead of + LPCTSTR.
  • + +
  • When compiling with Microsoft Visual C++, set the + compiler to warning level 3 or higher, and treat all + warnings as errors.
  • + +
  • Do not use #pragma once; instead use + the standard Google include guards. The path in the + include guards should be relative to the top of your + project tree.
  • + +
  • In fact, do not use any nonstandard extensions, + like #pragma and __declspec, + unless you absolutely must. Using + __declspec(dllimport) and + __declspec(dllexport) is allowed; however, + you must use them through macros such as + DLLIMPORT and DLLEXPORT, so + that someone can easily disable the extensions if they + share the code.
  • +
+ +

However, there are just a few rules that we +occasionally need to break on Windows:

+ +
    +
  • Normally we forbid + the use of multiple implementation inheritance; + however, it is required when using COM and some ATL/WTL + classes. You may use multiple implementation + inheritance to implement COM or ATL/WTL classes and + interfaces.
  • + +
  • Although you should not use exceptions in your own + code, they are used extensively in the ATL and some + STLs, including the one that comes with Visual C++. + When using the ATL, you should define + _ATL_NO_EXCEPTIONS to disable exceptions. + You should investigate whether you can also disable + exceptions in your STL, but if not, it is OK to turn on + exceptions in the compiler. (Note that this is only to + get the STL to compile. You should still not write + exception handling code yourself.)
  • + +
  • The usual way of working with precompiled headers + is to include a header file at the top of each source + file, typically with a name like StdAfx.h + or precompile.h. To make your code easier + to share with other projects, avoid including this file + explicitly (except in precompile.cc), and + use the /FI compiler option to include the + file automatically.
  • + +
  • Resource headers, which are usually named + resource.h and contain only macros, do not + need to conform to these style guidelines.
  • +
+ +
+ + + +

Use common sense and BE CONSISTENT.

+ +

If you are editing code, take a few minutes to look at the +code around you and determine its style. If they use spaces +around their if clauses, you should, too. If their +comments have little boxes of stars around them, make your +comments have little boxes of stars around them too.

+ +

The point of having style guidelines is to have a common +vocabulary of coding so people can concentrate on what you are +saying, rather than on how you are saying it. We present global +style rules here so people know the vocabulary. But local style +is also important. If code you add to a file looks drastically +different from the existing code around it, the discontinuity +throws readers out of their rhythm when they go to read it. Try +to avoid this.

+ + + +

OK, enough writing about writing code; the code itself is much +more interesting. Have fun!

+ +
+ +
+
+ + diff --git a/cppguide.xml b/cppguide.xml new file mode 100644 index 000000000..8efc102fe --- /dev/null +++ b/cppguide.xml @@ -0,0 +1,18 @@ + + + + + + + Redirecting + + + + Redirecting you to cppguide.html. + + diff --git a/cpplint/README b/cpplint/README new file mode 100644 index 000000000..ee6b9ded5 --- /dev/null +++ b/cpplint/README @@ -0,0 +1,45 @@ +This is automated checker to make sure a C++ file follows Google's C++ style +guide (https://google.github.io/styleguide/cppguide.html). As it +heavily relies on regular expressions, cpplint.py won't catch all violations of +the style guide and will very occasionally report a false positive. There is a +list of things we currently don't handle very well at the top of cpplint.py, +and we welcome patches to improve it. + +The linting tool takes a list of files as input. For full usage instructions, +please see the output of: + + ./cpplint.py --help + +Unit tests are provided in cpplint_unittest.py. This file can safely be ignored +by end users who have downloaded this package and only want to run the lint +tool. + +--- + +cpplint.py and its corresponding unit tests are Copyright (C) 2009 Google Inc. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/cpplint/cpplint.py b/cpplint/cpplint.py new file mode 100755 index 000000000..53dbe818f --- /dev/null +++ b/cpplint/cpplint.py @@ -0,0 +1,6228 @@ +#!/usr/bin/env python +# +# Copyright (c) 2009 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Does google-lint on c++ files. + +The goal of this script is to identify places in the code that *may* +be in non-compliance with google style. It does not attempt to fix +up these problems -- the point is to educate. It does also not +attempt to find all problems, or to ensure that everything it does +find is legitimately a problem. + +In particular, we can get very confused by /* and // inside strings! +We do a small hack, which is to ignore //'s with "'s after them on the +same line, but it is far from perfect (in either direction). +""" + +import codecs +import copy +import getopt +import math # for log +import os +import re +import sre_compile +import string +import sys +import unicodedata + + +_USAGE = """ +Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] + [--counting=total|toplevel|detailed] [--root=subdir] + [--linelength=digits] [--headers=x,y,...] + [--quiet] + [file] ... + + The style guidelines this tries to follow are those in + https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml + + Every problem is given a confidence score from 1-5, with 5 meaning we are + certain of the problem, and 1 meaning it could be a legitimate construct. + This will miss some errors, and is not a substitute for a code review. + + To suppress false-positive errors of a certain category, add a + 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) + suppresses errors of all categories on that line. + + The files passed in will be linted; at least one file must be provided. + Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the + extensions with the --extensions flag. + + Flags: + + output=vs7 + By default, the output is formatted to ease emacs parsing. Visual Studio + compatible output (vs7) may also be used. Other formats are unsupported. + + verbose=# + Specify a number 0-5 to restrict errors to certain verbosity levels. + + quiet + Don't print anything if no errors are found. + + filter=-x,+y,... + Specify a comma-separated list of category-filters to apply: only + error messages whose category names pass the filters will be printed. + (Category names are printed with the message and look like + "[whitespace/indent]".) Filters are evaluated left to right. + "-FOO" and "FOO" means "do not print categories that start with FOO". + "+FOO" means "do print categories that start with FOO". + + Examples: --filter=-whitespace,+whitespace/braces + --filter=whitespace,runtime/printf,+runtime/printf_format + --filter=-,+build/include_what_you_use + + To see a list of all the categories used in cpplint, pass no arg: + --filter= + + counting=total|toplevel|detailed + The total number of errors found is always printed. If + 'toplevel' is provided, then the count of errors in each of + the top-level categories like 'build' and 'whitespace' will + also be printed. If 'detailed' is provided, then a count + is provided for each category like 'build/class'. + + root=subdir + The root directory used for deriving header guard CPP variable. + By default, the header guard CPP variable is calculated as the relative + path to the directory that contains .git, .hg, or .svn. When this flag + is specified, the relative path is calculated from the specified + directory. If the specified directory does not exist, this flag is + ignored. + + Examples: + Assuming that top/src/.git exists (and cwd=top/src), the header guard + CPP variables for top/src/chrome/browser/ui/browser.h are: + + No flag => CHROME_BROWSER_UI_BROWSER_H_ + --root=chrome => BROWSER_UI_BROWSER_H_ + --root=chrome/browser => UI_BROWSER_H_ + --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_ + + linelength=digits + This is the allowed line length for the project. The default value is + 80 characters. + + Examples: + --linelength=120 + + extensions=extension,extension,... + The allowed file extensions that cpplint will check + + Examples: + --extensions=hpp,cpp + + headers=x,y,... + The header extensions that cpplint will treat as .h in checks. Values are + automatically added to --extensions list. + + Examples: + --headers=hpp,hxx + --headers=hpp + + cpplint.py supports per-directory configurations specified in CPPLINT.cfg + files. CPPLINT.cfg file can contain a number of key=value pairs. + Currently the following options are supported: + + set noparent + filter=+filter1,-filter2,... + exclude_files=regex + linelength=80 + root=subdir + headers=x,y,... + + "set noparent" option prevents cpplint from traversing directory tree + upwards looking for more .cfg files in parent directories. This option + is usually placed in the top-level project directory. + + The "filter" option is similar in function to --filter flag. It specifies + message filters in addition to the |_DEFAULT_FILTERS| and those specified + through --filter command-line flag. + + "exclude_files" allows to specify a regular expression to be matched against + a file name. If the expression matches, the file is skipped and not run + through liner. + + "linelength" allows to specify the allowed line length for the project. + + The "root" option is similar in function to the --root flag (see example + above). Paths are relative to the directory of the CPPLINT.cfg. + + The "headers" option is similar in function to the --headers flag + (see example above). + + CPPLINT.cfg has an effect on files in the same directory and all + sub-directories, unless overridden by a nested configuration file. + + Example file: + filter=-build/include_order,+build/include_alpha + exclude_files=.*\.cc + + The above example disables build/include_order warning and enables + build/include_alpha as well as excludes all .cc from being + processed by linter, in the current directory (where the .cfg + file is located) and all sub-directories. +""" + +# We categorize each error message we print. Here are the categories. +# We want an explicit list so we can list them all in cpplint --filter=. +# If you add a new error message with a new category, add it to the list +# here! cpplint_unittest.py should tell you if you forget to do this. +_ERROR_CATEGORIES = [ + 'build/class', + 'build/c++11', + 'build/c++14', + 'build/c++tr1', + 'build/deprecated', + 'build/endif_comment', + 'build/explicit_make_pair', + 'build/forward_decl', + 'build/header_guard', + 'build/include', + 'build/include_alpha', + 'build/include_order', + 'build/include_what_you_use', + 'build/namespaces', + 'build/printf_format', + 'build/storage_class', + 'legal/copyright', + 'readability/alt_tokens', + 'readability/braces', + 'readability/casting', + 'readability/check', + 'readability/constructors', + 'readability/fn_size', + 'readability/inheritance', + 'readability/multiline_comment', + 'readability/multiline_string', + 'readability/namespace', + 'readability/nolint', + 'readability/nul', + 'readability/strings', + 'readability/todo', + 'readability/utf8', + 'runtime/arrays', + 'runtime/casting', + 'runtime/explicit', + 'runtime/int', + 'runtime/init', + 'runtime/invalid_increment', + 'runtime/member_string_references', + 'runtime/memset', + 'runtime/indentation_namespace', + 'runtime/operator', + 'runtime/printf', + 'runtime/printf_format', + 'runtime/references', + 'runtime/string', + 'runtime/threadsafe_fn', + 'runtime/vlog', + 'whitespace/blank_line', + 'whitespace/braces', + 'whitespace/comma', + 'whitespace/comments', + 'whitespace/empty_conditional_body', + 'whitespace/empty_if_body', + 'whitespace/empty_loop_body', + 'whitespace/end_of_line', + 'whitespace/ending_newline', + 'whitespace/forcolon', + 'whitespace/indent', + 'whitespace/line_length', + 'whitespace/newline', + 'whitespace/operators', + 'whitespace/parens', + 'whitespace/semicolon', + 'whitespace/tab', + 'whitespace/todo', + ] + +# These error categories are no longer enforced by cpplint, but for backwards- +# compatibility they may still appear in NOLINT comments. +_LEGACY_ERROR_CATEGORIES = [ + 'readability/streams', + 'readability/function', + ] + +# The default state of the category filter. This is overridden by the --filter= +# flag. By default all errors are on, so only add here categories that should be +# off by default (i.e., categories that must be enabled by the --filter= flags). +# All entries here should start with a '-' or '+', as in the --filter= flag. +_DEFAULT_FILTERS = ['-build/include_alpha'] + +# The default list of categories suppressed for C (not C++) files. +_DEFAULT_C_SUPPRESSED_CATEGORIES = [ + 'readability/casting', + ] + +# The default list of categories suppressed for Linux Kernel files. +_DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [ + 'whitespace/tab', + ] + +# We used to check for high-bit characters, but after much discussion we +# decided those were OK, as long as they were in UTF-8 and didn't represent +# hard-coded international strings, which belong in a separate i18n file. + +# C++ headers +_CPP_HEADERS = frozenset([ + # Legacy + 'algobase.h', + 'algo.h', + 'alloc.h', + 'builtinbuf.h', + 'bvector.h', + 'complex.h', + 'defalloc.h', + 'deque.h', + 'editbuf.h', + 'fstream.h', + 'function.h', + 'hash_map', + 'hash_map.h', + 'hash_set', + 'hash_set.h', + 'hashtable.h', + 'heap.h', + 'indstream.h', + 'iomanip.h', + 'iostream.h', + 'istream.h', + 'iterator.h', + 'list.h', + 'map.h', + 'multimap.h', + 'multiset.h', + 'ostream.h', + 'pair.h', + 'parsestream.h', + 'pfstream.h', + 'procbuf.h', + 'pthread_alloc', + 'pthread_alloc.h', + 'rope', + 'rope.h', + 'ropeimpl.h', + 'set.h', + 'slist', + 'slist.h', + 'stack.h', + 'stdiostream.h', + 'stl_alloc.h', + 'stl_relops.h', + 'streambuf.h', + 'stream.h', + 'strfile.h', + 'strstream.h', + 'tempbuf.h', + 'tree.h', + 'type_traits.h', + 'vector.h', + # 17.6.1.2 C++ library headers + 'algorithm', + 'array', + 'atomic', + 'bitset', + 'chrono', + 'codecvt', + 'complex', + 'condition_variable', + 'deque', + 'exception', + 'forward_list', + 'fstream', + 'functional', + 'future', + 'initializer_list', + 'iomanip', + 'ios', + 'iosfwd', + 'iostream', + 'istream', + 'iterator', + 'limits', + 'list', + 'locale', + 'map', + 'memory', + 'mutex', + 'new', + 'numeric', + 'ostream', + 'queue', + 'random', + 'ratio', + 'regex', + 'scoped_allocator', + 'set', + 'sstream', + 'stack', + 'stdexcept', + 'streambuf', + 'string', + 'strstream', + 'system_error', + 'thread', + 'tuple', + 'typeindex', + 'typeinfo', + 'type_traits', + 'unordered_map', + 'unordered_set', + 'utility', + 'valarray', + 'vector', + # 17.6.1.2 C++ headers for C library facilities + 'cassert', + 'ccomplex', + 'cctype', + 'cerrno', + 'cfenv', + 'cfloat', + 'cinttypes', + 'ciso646', + 'climits', + 'clocale', + 'cmath', + 'csetjmp', + 'csignal', + 'cstdalign', + 'cstdarg', + 'cstdbool', + 'cstddef', + 'cstdint', + 'cstdio', + 'cstdlib', + 'cstring', + 'ctgmath', + 'ctime', + 'cuchar', + 'cwchar', + 'cwctype', + ]) + +# Type names +_TYPES = re.compile( + r'^(?:' + # [dcl.type.simple] + r'(char(16_t|32_t)?)|wchar_t|' + r'bool|short|int|long|signed|unsigned|float|double|' + # [support.types] + r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|' + # [cstdint.syn] + r'(u?int(_fast|_least)?(8|16|32|64)_t)|' + r'(u?int(max|ptr)_t)|' + r')$') + + +# These headers are excluded from [build/include] and [build/include_order] +# checks: +# - Anything not following google file name conventions (containing an +# uppercase character, such as Python.h or nsStringAPI.h, for example). +# - Lua headers. +_THIRD_PARTY_HEADERS_PATTERN = re.compile( + r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$') + +# Pattern for matching FileInfo.BaseName() against test file name +_TEST_FILE_SUFFIX = r'(_test|_unittest|_regtest)$' + +# Pattern that matches only complete whitespace, possibly across multiple lines. +_EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL) + +# Assertion macros. These are defined in base/logging.h and +# testing/base/public/gunit.h. +_CHECK_MACROS = [ + 'DCHECK', 'CHECK', + 'EXPECT_TRUE', 'ASSERT_TRUE', + 'EXPECT_FALSE', 'ASSERT_FALSE', + ] + +# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE +_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS]) + +for op, replacement in [('==', 'EQ'), ('!=', 'NE'), + ('>=', 'GE'), ('>', 'GT'), + ('<=', 'LE'), ('<', 'LT')]: + _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement + _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement + _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement + _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement + +for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), + ('>=', 'LT'), ('>', 'LE'), + ('<=', 'GT'), ('<', 'GE')]: + _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement + _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement + +# Alternative tokens and their replacements. For full list, see section 2.5 +# Alternative tokens [lex.digraph] in the C++ standard. +# +# Digraphs (such as '%:') are not included here since it's a mess to +# match those on a word boundary. +_ALT_TOKEN_REPLACEMENT = { + 'and': '&&', + 'bitor': '|', + 'or': '||', + 'xor': '^', + 'compl': '~', + 'bitand': '&', + 'and_eq': '&=', + 'or_eq': '|=', + 'xor_eq': '^=', + 'not': '!', + 'not_eq': '!=' + } + +# Compile regular expression that matches all the above keywords. The "[ =()]" +# bit is meant to avoid matching these keywords outside of boolean expressions. +# +# False positives include C-style multi-line comments and multi-line strings +# but those have always been troublesome for cpplint. +_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( + r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') + + +# These constants define types of headers for use with +# _IncludeState.CheckNextIncludeOrder(). +_C_SYS_HEADER = 1 +_CPP_SYS_HEADER = 2 +_LIKELY_MY_HEADER = 3 +_POSSIBLE_MY_HEADER = 4 +_OTHER_HEADER = 5 + +# These constants define the current inline assembly state +_NO_ASM = 0 # Outside of inline assembly block +_INSIDE_ASM = 1 # Inside inline assembly block +_END_ASM = 2 # Last line of inline assembly block +_BLOCK_ASM = 3 # The whole block is an inline assembly block + +# Match start of assembly blocks +_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' + r'(?:\s+(volatile|__volatile__))?' + r'\s*[{(]') + +# Match strings that indicate we're working on a C (not C++) file. +_SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|' + r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))') + +# Match string that indicates we're working on a Linux Kernel file. +_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)') + +_regexp_compile_cache = {} + +# {str, set(int)}: a map from error categories to sets of linenumbers +# on which those errors are expected and should be suppressed. +_error_suppressions = {} + +# The root directory used for deriving header guard CPP variable. +# This is set by --root flag. +_root = None +_root_debug = False + +# The allowed line length of files. +# This is set by --linelength flag. +_line_length = 80 + +# The allowed extensions for file names +# This is set by --extensions flag. +_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) + +# Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc. +# This is set by --headers flag. +_hpp_headers = set(['h']) + +# {str, bool}: a map from error categories to booleans which indicate if the +# category should be suppressed for every line. +_global_error_suppressions = {} + +def ProcessHppHeadersOption(val): + global _hpp_headers + try: + _hpp_headers = set(val.split(',')) + # Automatically append to extensions list so it does not have to be set 2 times + _valid_extensions.update(_hpp_headers) + except ValueError: + PrintUsage('Header extensions must be comma seperated list.') + +def IsHeaderExtension(file_extension): + return file_extension in _hpp_headers + +def ParseNolintSuppressions(filename, raw_line, linenum, error): + """Updates the global list of line error-suppressions. + + Parses any NOLINT comments on the current line, updating the global + error_suppressions store. Reports an error if the NOLINT comment + was malformed. + + Args: + filename: str, the name of the input file. + raw_line: str, the line of input text, with comments. + linenum: int, the number of the current line. + error: function, an error handler. + """ + matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line) + if matched: + if matched.group(1): + suppressed_line = linenum + 1 + else: + suppressed_line = linenum + category = matched.group(2) + if category in (None, '(*)'): # => "suppress all" + _error_suppressions.setdefault(None, set()).add(suppressed_line) + else: + if category.startswith('(') and category.endswith(')'): + category = category[1:-1] + if category in _ERROR_CATEGORIES: + _error_suppressions.setdefault(category, set()).add(suppressed_line) + elif category not in _LEGACY_ERROR_CATEGORIES: + error(filename, linenum, 'readability/nolint', 5, + 'Unknown NOLINT error category: %s' % category) + + +def ProcessGlobalSuppresions(lines): + """Updates the list of global error suppressions. + + Parses any lint directives in the file that have global effect. + + Args: + lines: An array of strings, each representing a line of the file, with the + last element being empty if the file is terminated with a newline. + """ + for line in lines: + if _SEARCH_C_FILE.search(line): + for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: + _global_error_suppressions[category] = True + if _SEARCH_KERNEL_FILE.search(line): + for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES: + _global_error_suppressions[category] = True + + +def ResetNolintSuppressions(): + """Resets the set of NOLINT suppressions to empty.""" + _error_suppressions.clear() + _global_error_suppressions.clear() + + +def IsErrorSuppressedByNolint(category, linenum): + """Returns true if the specified error category is suppressed on this line. + + Consults the global error_suppressions map populated by + ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions. + + Args: + category: str, the category of the error. + linenum: int, the current line number. + Returns: + bool, True iff the error should be suppressed due to a NOLINT comment or + global suppression. + """ + return (_global_error_suppressions.get(category, False) or + linenum in _error_suppressions.get(category, set()) or + linenum in _error_suppressions.get(None, set())) + + +def Match(pattern, s): + """Matches the string with the pattern, caching the compiled regexp.""" + # The regexp compilation caching is inlined in both Match and Search for + # performance reasons; factoring it out into a separate function turns out + # to be noticeably expensive. + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].match(s) + + +def ReplaceAll(pattern, rep, s): + """Replaces instances of pattern in a string with a replacement. + + The compiled regex is kept in a cache shared by Match and Search. + + Args: + pattern: regex pattern + rep: replacement text + s: search string + + Returns: + string with replacements made (or original string if no replacements) + """ + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].sub(rep, s) + + +def Search(pattern, s): + """Searches the string for the pattern, caching the compiled regexp.""" + if pattern not in _regexp_compile_cache: + _regexp_compile_cache[pattern] = sre_compile.compile(pattern) + return _regexp_compile_cache[pattern].search(s) + + +def _IsSourceExtension(s): + """File extension (excluding dot) matches a source file extension.""" + return s in ('c', 'cc', 'cpp', 'cxx') + + +class _IncludeState(object): + """Tracks line numbers for includes, and the order in which includes appear. + + include_list contains list of lists of (header, line number) pairs. + It's a lists of lists rather than just one flat list to make it + easier to update across preprocessor boundaries. + + Call CheckNextIncludeOrder() once for each header in the file, passing + in the type constants defined above. Calls in an illegal order will + raise an _IncludeError with an appropriate error message. + + """ + # self._section will move monotonically through this set. If it ever + # needs to move backwards, CheckNextIncludeOrder will raise an error. + _INITIAL_SECTION = 0 + _MY_H_SECTION = 1 + _C_SECTION = 2 + _CPP_SECTION = 3 + _OTHER_H_SECTION = 4 + + _TYPE_NAMES = { + _C_SYS_HEADER: 'C system header', + _CPP_SYS_HEADER: 'C++ system header', + _LIKELY_MY_HEADER: 'header this file implements', + _POSSIBLE_MY_HEADER: 'header this file may implement', + _OTHER_HEADER: 'other header', + } + _SECTION_NAMES = { + _INITIAL_SECTION: "... nothing. (This can't be an error.)", + _MY_H_SECTION: 'a header this file implements', + _C_SECTION: 'C system header', + _CPP_SECTION: 'C++ system header', + _OTHER_H_SECTION: 'other header', + } + + def __init__(self): + self.include_list = [[]] + self.ResetSection('') + + def FindHeader(self, header): + """Check if a header has already been included. + + Args: + header: header to check. + Returns: + Line number of previous occurrence, or -1 if the header has not + been seen before. + """ + for section_list in self.include_list: + for f in section_list: + if f[0] == header: + return f[1] + return -1 + + def ResetSection(self, directive): + """Reset section checking for preprocessor directive. + + Args: + directive: preprocessor directive (e.g. "if", "else"). + """ + # The name of the current section. + self._section = self._INITIAL_SECTION + # The path of last found header. + self._last_header = '' + + # Update list of includes. Note that we never pop from the + # include list. + if directive in ('if', 'ifdef', 'ifndef'): + self.include_list.append([]) + elif directive in ('else', 'elif'): + self.include_list[-1] = [] + + def SetLastHeader(self, header_path): + self._last_header = header_path + + def CanonicalizeAlphabeticalOrder(self, header_path): + """Returns a path canonicalized for alphabetical comparison. + + - replaces "-" with "_" so they both cmp the same. + - removes '-inl' since we don't require them to be after the main header. + - lowercase everything, just in case. + + Args: + header_path: Path to be canonicalized. + + Returns: + Canonicalized path. + """ + return header_path.replace('-inl.h', '.h').replace('-', '_').lower() + + def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): + """Check if a header is in alphabetical order with the previous header. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + header_path: Canonicalized header to be checked. + + Returns: + Returns true if the header is in alphabetical order. + """ + # If previous section is different from current section, _last_header will + # be reset to empty string, so it's always less than current header. + # + # If previous line was a blank line, assume that the headers are + # intentionally sorted the way they are. + if (self._last_header > header_path and + Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): + return False + return True + + def CheckNextIncludeOrder(self, header_type): + """Returns a non-empty error message if the next header is out of order. + + This function also updates the internal state to be ready to check + the next include. + + Args: + header_type: One of the _XXX_HEADER constants defined above. + + Returns: + The empty string if the header is in the right order, or an + error message describing what's wrong. + + """ + error_message = ('Found %s after %s' % + (self._TYPE_NAMES[header_type], + self._SECTION_NAMES[self._section])) + + last_section = self._section + + if header_type == _C_SYS_HEADER: + if self._section <= self._C_SECTION: + self._section = self._C_SECTION + else: + self._last_header = '' + return error_message + elif header_type == _CPP_SYS_HEADER: + if self._section <= self._CPP_SECTION: + self._section = self._CPP_SECTION + else: + self._last_header = '' + return error_message + elif header_type == _LIKELY_MY_HEADER: + if self._section <= self._MY_H_SECTION: + self._section = self._MY_H_SECTION + else: + self._section = self._OTHER_H_SECTION + elif header_type == _POSSIBLE_MY_HEADER: + if self._section <= self._MY_H_SECTION: + self._section = self._MY_H_SECTION + else: + # This will always be the fallback because we're not sure + # enough that the header is associated with this file. + self._section = self._OTHER_H_SECTION + else: + assert header_type == _OTHER_HEADER + self._section = self._OTHER_H_SECTION + + if last_section != self._section: + self._last_header = '' + + return '' + + +class _CppLintState(object): + """Maintains module-wide state..""" + + def __init__(self): + self.verbose_level = 1 # global setting. + self.error_count = 0 # global count of reported errors + # filters to apply when emitting error messages + self.filters = _DEFAULT_FILTERS[:] + # backup of filter list. Used to restore the state after each file. + self._filters_backup = self.filters[:] + self.counting = 'total' # In what way are we counting errors? + self.errors_by_category = {} # string to int dict storing error counts + self.quiet = False # Suppress non-error messagess? + + # output format: + # "emacs" - format that emacs can parse (default) + # "vs7" - format that Microsoft Visual Studio 7 can parse + self.output_format = 'emacs' + + def SetOutputFormat(self, output_format): + """Sets the output format for errors.""" + self.output_format = output_format + + def SetQuiet(self, quiet): + """Sets the module's quiet settings, and returns the previous setting.""" + last_quiet = self.quiet + self.quiet = quiet + return last_quiet + + def SetVerboseLevel(self, level): + """Sets the module's verbosity, and returns the previous setting.""" + last_verbose_level = self.verbose_level + self.verbose_level = level + return last_verbose_level + + def SetCountingStyle(self, counting_style): + """Sets the module's counting options.""" + self.counting = counting_style + + def SetFilters(self, filters): + """Sets the error-message filters. + + These filters are applied when deciding whether to emit a given + error message. + + Args: + filters: A string of comma-separated filters (eg "+whitespace/indent"). + Each filter should start with + or -; else we die. + + Raises: + ValueError: The comma-separated filters did not all start with '+' or '-'. + E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" + """ + # Default filters always have less priority than the flag ones. + self.filters = _DEFAULT_FILTERS[:] + self.AddFilters(filters) + + def AddFilters(self, filters): + """ Adds more filters to the existing list of error-message filters. """ + for filt in filters.split(','): + clean_filt = filt.strip() + if clean_filt: + self.filters.append(clean_filt) + for filt in self.filters: + if not (filt.startswith('+') or filt.startswith('-')): + raise ValueError('Every filter in --filters must start with + or -' + ' (%s does not)' % filt) + + def BackupFilters(self): + """ Saves the current filter list to backup storage.""" + self._filters_backup = self.filters[:] + + def RestoreFilters(self): + """ Restores filters previously backed up.""" + self.filters = self._filters_backup[:] + + def ResetErrorCounts(self): + """Sets the module's error statistic back to zero.""" + self.error_count = 0 + self.errors_by_category = {} + + def IncrementErrorCount(self, category): + """Bumps the module's error statistic.""" + self.error_count += 1 + if self.counting in ('toplevel', 'detailed'): + if self.counting != 'detailed': + category = category.split('/')[0] + if category not in self.errors_by_category: + self.errors_by_category[category] = 0 + self.errors_by_category[category] += 1 + + def PrintErrorCounts(self): + """Print a summary of errors by category, and the total.""" + for category, count in self.errors_by_category.iteritems(): + sys.stderr.write('Category \'%s\' errors found: %d\n' % + (category, count)) + sys.stdout.write('Total errors found: %d\n' % self.error_count) + +_cpplint_state = _CppLintState() + + +def _OutputFormat(): + """Gets the module's output format.""" + return _cpplint_state.output_format + + +def _SetOutputFormat(output_format): + """Sets the module's output format.""" + _cpplint_state.SetOutputFormat(output_format) + +def _Quiet(): + """Return's the module's quiet setting.""" + return _cpplint_state.quiet + +def _SetQuiet(quiet): + """Set the module's quiet status, and return previous setting.""" + return _cpplint_state.SetQuiet(quiet) + + +def _VerboseLevel(): + """Returns the module's verbosity setting.""" + return _cpplint_state.verbose_level + + +def _SetVerboseLevel(level): + """Sets the module's verbosity, and returns the previous setting.""" + return _cpplint_state.SetVerboseLevel(level) + + +def _SetCountingStyle(level): + """Sets the module's counting options.""" + _cpplint_state.SetCountingStyle(level) + + +def _Filters(): + """Returns the module's list of output filters, as a list.""" + return _cpplint_state.filters + + +def _SetFilters(filters): + """Sets the module's error-message filters. + + These filters are applied when deciding whether to emit a given + error message. + + Args: + filters: A string of comma-separated filters (eg "whitespace/indent"). + Each filter should start with + or -; else we die. + """ + _cpplint_state.SetFilters(filters) + +def _AddFilters(filters): + """Adds more filter overrides. + + Unlike _SetFilters, this function does not reset the current list of filters + available. + + Args: + filters: A string of comma-separated filters (eg "whitespace/indent"). + Each filter should start with + or -; else we die. + """ + _cpplint_state.AddFilters(filters) + +def _BackupFilters(): + """ Saves the current filter list to backup storage.""" + _cpplint_state.BackupFilters() + +def _RestoreFilters(): + """ Restores filters previously backed up.""" + _cpplint_state.RestoreFilters() + +class _FunctionState(object): + """Tracks current function name and the number of lines in its body.""" + + _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. + _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. + + def __init__(self): + self.in_a_function = False + self.lines_in_function = 0 + self.current_function = '' + + def Begin(self, function_name): + """Start analyzing function body. + + Args: + function_name: The name of the function being tracked. + """ + self.in_a_function = True + self.lines_in_function = 0 + self.current_function = function_name + + def Count(self): + """Count line in current function body.""" + if self.in_a_function: + self.lines_in_function += 1 + + def Check(self, error, filename, linenum): + """Report if too many lines in function body. + + Args: + error: The function to call with any errors found. + filename: The name of the current file. + linenum: The number of the line to check. + """ + if not self.in_a_function: + return + + if Match(r'T(EST|est)', self.current_function): + base_trigger = self._TEST_TRIGGER + else: + base_trigger = self._NORMAL_TRIGGER + trigger = base_trigger * 2**_VerboseLevel() + + if self.lines_in_function > trigger: + error_level = int(math.log(self.lines_in_function / base_trigger, 2)) + # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... + if error_level > 5: + error_level = 5 + error(filename, linenum, 'readability/fn_size', error_level, + 'Small and focused functions are preferred:' + ' %s has %d non-comment lines' + ' (error triggered by exceeding %d lines).' % ( + self.current_function, self.lines_in_function, trigger)) + + def End(self): + """Stop analyzing function body.""" + self.in_a_function = False + + +class _IncludeError(Exception): + """Indicates a problem with the include order in a file.""" + pass + + +class FileInfo(object): + """Provides utility functions for filenames. + + FileInfo provides easy access to the components of a file's path + relative to the project root. + """ + + def __init__(self, filename): + self._filename = filename + + def FullName(self): + """Make Windows paths like Unix.""" + return os.path.abspath(self._filename).replace('\\', '/') + + def RepositoryName(self): + """FullName after removing the local path to the repository. + + If we have a real absolute path name here we can try to do something smart: + detecting the root of the checkout and truncating /path/to/checkout from + the name so that we get header guards that don't include things like + "C:\Documents and Settings\..." or "/home/username/..." in them and thus + people on different computers who have checked the source out to different + locations won't see bogus errors. + """ + fullname = self.FullName() + + if os.path.exists(fullname): + project_dir = os.path.dirname(fullname) + + if os.path.exists(os.path.join(project_dir, ".svn")): + # If there's a .svn file in the current directory, we recursively look + # up the directory tree for the top of the SVN checkout + root_dir = project_dir + one_up_dir = os.path.dirname(root_dir) + while os.path.exists(os.path.join(one_up_dir, ".svn")): + root_dir = os.path.dirname(root_dir) + one_up_dir = os.path.dirname(one_up_dir) + + prefix = os.path.commonprefix([root_dir, project_dir]) + return fullname[len(prefix) + 1:] + + # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by + # searching up from the current path. + root_dir = current_dir = os.path.dirname(fullname) + while current_dir != os.path.dirname(current_dir): + if (os.path.exists(os.path.join(current_dir, ".git")) or + os.path.exists(os.path.join(current_dir, ".hg")) or + os.path.exists(os.path.join(current_dir, ".svn"))): + root_dir = current_dir + current_dir = os.path.dirname(current_dir) + + if (os.path.exists(os.path.join(root_dir, ".git")) or + os.path.exists(os.path.join(root_dir, ".hg")) or + os.path.exists(os.path.join(root_dir, ".svn"))): + prefix = os.path.commonprefix([root_dir, project_dir]) + return fullname[len(prefix) + 1:] + + # Don't know what to do; header guard warnings may be wrong... + return fullname + + def Split(self): + """Splits the file into the directory, basename, and extension. + + For 'chrome/browser/browser.cc', Split() would + return ('chrome/browser', 'browser', '.cc') + + Returns: + A tuple of (directory, basename, extension). + """ + + googlename = self.RepositoryName() + project, rest = os.path.split(googlename) + return (project,) + os.path.splitext(rest) + + def BaseName(self): + """File base name - text after the final slash, before the final period.""" + return self.Split()[1] + + def Extension(self): + """File extension - text following the final period.""" + return self.Split()[2] + + def NoExtension(self): + """File has no source file extension.""" + return '/'.join(self.Split()[0:2]) + + def IsSource(self): + """File has a source file extension.""" + return _IsSourceExtension(self.Extension()[1:]) + + +def _ShouldPrintError(category, confidence, linenum): + """If confidence >= verbose, category passes filter and is not suppressed.""" + + # There are three ways we might decide not to print an error message: + # a "NOLINT(category)" comment appears in the source, + # the verbosity level isn't high enough, or the filters filter it out. + if IsErrorSuppressedByNolint(category, linenum): + return False + + if confidence < _cpplint_state.verbose_level: + return False + + is_filtered = False + for one_filter in _Filters(): + if one_filter.startswith('-'): + if category.startswith(one_filter[1:]): + is_filtered = True + elif one_filter.startswith('+'): + if category.startswith(one_filter[1:]): + is_filtered = False + else: + assert False # should have been checked for in SetFilter. + if is_filtered: + return False + + return True + + +def Error(filename, linenum, category, confidence, message): + """Logs the fact we've found a lint error. + + We log where the error was found, and also our confidence in the error, + that is, how certain we are this is a legitimate style regression, and + not a misidentification or a use that's sometimes justified. + + False positives can be suppressed by the use of + "cpplint(category)" comments on the offending line. These are + parsed into _error_suppressions. + + Args: + filename: The name of the file containing the error. + linenum: The number of the line containing the error. + category: A string used to describe the "category" this bug + falls under: "whitespace", say, or "runtime". Categories + may have a hierarchy separated by slashes: "whitespace/indent". + confidence: A number from 1-5 representing a confidence score for + the error, with 5 meaning that we are certain of the problem, + and 1 meaning that it could be a legitimate construct. + message: The error message. + """ + if _ShouldPrintError(category, confidence, linenum): + _cpplint_state.IncrementErrorCount(category) + if _cpplint_state.output_format == 'vs7': + sys.stderr.write('%s(%s): error cpplint: [%s] %s [%d]\n' % ( + filename, linenum, category, message, confidence)) + elif _cpplint_state.output_format == 'eclipse': + sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + else: + sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( + filename, linenum, message, category, confidence)) + + +# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. +_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( + r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') +# Match a single C style comment on the same line. +_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/' +# Matches multi-line C style comments. +# This RE is a little bit more complicated than one might expect, because we +# have to take care of space removals tools so we can handle comments inside +# statements better. +# The current rule is: We only clear spaces from both sides when we're at the +# end of the line. Otherwise, we try to remove spaces from the right side, +# if this doesn't work we try on left side but only if there's a non-character +# on the right. +_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( + r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' + + _RE_PATTERN_C_COMMENTS + r'\s+|' + + r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' + + _RE_PATTERN_C_COMMENTS + r')') + + +def IsCppString(line): + """Does line terminate so, that the next symbol is in string constant. + + This function does not consider single-line nor multi-line comments. + + Args: + line: is a partial line of code starting from the 0..n. + + Returns: + True, if next character appended to 'line' is inside a + string constant. + """ + + line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" + return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 + + +def CleanseRawStrings(raw_lines): + """Removes C++11 raw strings from lines. + + Before: + static const char kData[] = R"( + multi-line string + )"; + + After: + static const char kData[] = "" + (replaced by blank line) + ""; + + Args: + raw_lines: list of raw lines. + + Returns: + list of lines with C++11 raw strings replaced by empty strings. + """ + + delimiter = None + lines_without_raw_strings = [] + for line in raw_lines: + if delimiter: + # Inside a raw string, look for the end + end = line.find(delimiter) + if end >= 0: + # Found the end of the string, match leading space for this + # line and resume copying the original lines, and also insert + # a "" on the last line. + leading_space = Match(r'^(\s*)\S', line) + line = leading_space.group(1) + '""' + line[end + len(delimiter):] + delimiter = None + else: + # Haven't found the end yet, append a blank line. + line = '""' + + # Look for beginning of a raw string, and replace them with + # empty strings. This is done in a loop to handle multiple raw + # strings on the same line. + while delimiter is None: + # Look for beginning of a raw string. + # See 2.14.15 [lex.string] for syntax. + # + # Once we have matched a raw string, we check the prefix of the + # line to make sure that the line is not part of a single line + # comment. It's done this way because we remove raw strings + # before removing comments as opposed to removing comments + # before removing raw strings. This is because there are some + # cpplint checks that requires the comments to be preserved, but + # we don't want to check comments that are inside raw strings. + matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) + if (matched and + not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//', + matched.group(1))): + delimiter = ')' + matched.group(2) + '"' + + end = matched.group(3).find(delimiter) + if end >= 0: + # Raw string ended on same line + line = (matched.group(1) + '""' + + matched.group(3)[end + len(delimiter):]) + delimiter = None + else: + # Start of a multi-line raw string + line = matched.group(1) + '""' + else: + break + + lines_without_raw_strings.append(line) + + # TODO(unknown): if delimiter is not None here, we might want to + # emit a warning for unterminated string. + return lines_without_raw_strings + + +def FindNextMultiLineCommentStart(lines, lineix): + """Find the beginning marker for a multiline comment.""" + while lineix < len(lines): + if lines[lineix].strip().startswith('/*'): + # Only return this marker if the comment goes beyond this line + if lines[lineix].strip().find('*/', 2) < 0: + return lineix + lineix += 1 + return len(lines) + + +def FindNextMultiLineCommentEnd(lines, lineix): + """We are inside a comment, find the end marker.""" + while lineix < len(lines): + if lines[lineix].strip().endswith('*/'): + return lineix + lineix += 1 + return len(lines) + + +def RemoveMultiLineCommentsFromRange(lines, begin, end): + """Clears a range of lines for multi-line comments.""" + # Having // dummy comments makes the lines non-empty, so we will not get + # unnecessary blank line warnings later in the code. + for i in range(begin, end): + lines[i] = '/**/' + + +def RemoveMultiLineComments(filename, lines, error): + """Removes multiline (c-style) comments from lines.""" + lineix = 0 + while lineix < len(lines): + lineix_begin = FindNextMultiLineCommentStart(lines, lineix) + if lineix_begin >= len(lines): + return + lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) + if lineix_end >= len(lines): + error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, + 'Could not find end of multi-line comment') + return + RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) + lineix = lineix_end + 1 + + +def CleanseComments(line): + """Removes //-comments and single-line C-style /* */ comments. + + Args: + line: A line of C++ source. + + Returns: + The line with single-line comments removed. + """ + commentpos = line.find('//') + if commentpos != -1 and not IsCppString(line[:commentpos]): + line = line[:commentpos].rstrip() + # get rid of /* ... */ + return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) + + +class CleansedLines(object): + """Holds 4 copies of all lines with different preprocessing applied to them. + + 1) elided member contains lines without strings and comments. + 2) lines member contains lines without comments. + 3) raw_lines member contains all the lines without processing. + 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw + strings removed. + All these members are of , and of the same length. + """ + + def __init__(self, lines): + self.elided = [] + self.lines = [] + self.raw_lines = lines + self.num_lines = len(lines) + self.lines_without_raw_strings = CleanseRawStrings(lines) + for linenum in range(len(self.lines_without_raw_strings)): + self.lines.append(CleanseComments( + self.lines_without_raw_strings[linenum])) + elided = self._CollapseStrings(self.lines_without_raw_strings[linenum]) + self.elided.append(CleanseComments(elided)) + + def NumLines(self): + """Returns the number of lines represented.""" + return self.num_lines + + @staticmethod + def _CollapseStrings(elided): + """Collapses strings and chars on a line to simple "" or '' blocks. + + We nix strings first so we're not fooled by text like '"http://"' + + Args: + elided: The line being processed. + + Returns: + The line with collapsed strings. + """ + if _RE_PATTERN_INCLUDE.match(elided): + return elided + + # Remove escaped characters first to make quote/single quote collapsing + # basic. Things that look like escaped characters shouldn't occur + # outside of strings and chars. + elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) + + # Replace quoted strings and digit separators. Both single quotes + # and double quotes are processed in the same loop, otherwise + # nested quotes wouldn't work. + collapsed = '' + while True: + # Find the first quote character + match = Match(r'^([^\'"]*)([\'"])(.*)$', elided) + if not match: + collapsed += elided + break + head, quote, tail = match.groups() + + if quote == '"': + # Collapse double quoted strings + second_quote = tail.find('"') + if second_quote >= 0: + collapsed += head + '""' + elided = tail[second_quote + 1:] + else: + # Unmatched double quote, don't bother processing the rest + # of the line since this is probably a multiline string. + collapsed += elided + break + else: + # Found single quote, check nearby text to eliminate digit separators. + # + # There is no special handling for floating point here, because + # the integer/fractional/exponent parts would all be parsed + # correctly as long as there are digits on both sides of the + # separator. So we are fine as long as we don't see something + # like "0.'3" (gcc 4.9.0 will not allow this literal). + if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): + match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail) + collapsed += head + match_literal.group(1).replace("'", '') + elided = match_literal.group(2) + else: + second_quote = tail.find('\'') + if second_quote >= 0: + collapsed += head + "''" + elided = tail[second_quote + 1:] + else: + # Unmatched single quote + collapsed += elided + break + + return collapsed + + +def FindEndOfExpressionInLine(line, startpos, stack): + """Find the position just after the end of current parenthesized expression. + + Args: + line: a CleansedLines line. + startpos: start searching at this position. + stack: nesting stack at startpos. + + Returns: + On finding matching end: (index just after matching end, None) + On finding an unclosed expression: (-1, None) + Otherwise: (-1, new stack at end of this line) + """ + for i in xrange(startpos, len(line)): + char = line[i] + if char in '([{': + # Found start of parenthesized expression, push to expression stack + stack.append(char) + elif char == '<': + # Found potential start of template argument list + if i > 0 and line[i - 1] == '<': + # Left shift operator + if stack and stack[-1] == '<': + stack.pop() + if not stack: + return (-1, None) + elif i > 0 and Search(r'\boperator\s*$', line[0:i]): + # operator<, don't add to stack + continue + else: + # Tentative start of template argument list + stack.append('<') + elif char in ')]}': + # Found end of parenthesized expression. + # + # If we are currently expecting a matching '>', the pending '<' + # must have been an operator. Remove them from expression stack. + while stack and stack[-1] == '<': + stack.pop() + if not stack: + return (-1, None) + if ((stack[-1] == '(' and char == ')') or + (stack[-1] == '[' and char == ']') or + (stack[-1] == '{' and char == '}')): + stack.pop() + if not stack: + return (i + 1, None) + else: + # Mismatched parentheses + return (-1, None) + elif char == '>': + # Found potential end of template argument list. + + # Ignore "->" and operator functions + if (i > 0 and + (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))): + continue + + # Pop the stack if there is a matching '<'. Otherwise, ignore + # this '>' since it must be an operator. + if stack: + if stack[-1] == '<': + stack.pop() + if not stack: + return (i + 1, None) + elif char == ';': + # Found something that look like end of statements. If we are currently + # expecting a '>', the matching '<' must have been an operator, since + # template argument list should not contain statements. + while stack and stack[-1] == '<': + stack.pop() + if not stack: + return (-1, None) + + # Did not find end of expression or unbalanced parentheses on this line + return (-1, stack) + + +def CloseExpression(clean_lines, linenum, pos): + """If input points to ( or { or [ or <, finds the position that closes it. + + If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the + linenum/pos that correspond to the closing of the expression. + + TODO(unknown): cpplint spends a fair bit of time matching parentheses. + Ideally we would want to index all opening and closing parentheses once + and have CloseExpression be just a simple lookup, but due to preprocessor + tricks, this is not so easy. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: A position on the line. + + Returns: + A tuple (line, linenum, pos) pointer *past* the closing brace, or + (line, len(lines), -1) if we never find a close. Note we ignore + strings and comments when matching; and the line we return is the + 'cleansed' line at linenum. + """ + + line = clean_lines.elided[linenum] + if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]): + return (line, clean_lines.NumLines(), -1) + + # Check first line + (end_pos, stack) = FindEndOfExpressionInLine(line, pos, []) + if end_pos > -1: + return (line, linenum, end_pos) + + # Continue scanning forward + while stack and linenum < clean_lines.NumLines() - 1: + linenum += 1 + line = clean_lines.elided[linenum] + (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack) + if end_pos > -1: + return (line, linenum, end_pos) + + # Did not find end of expression before end of file, give up + return (line, clean_lines.NumLines(), -1) + + +def FindStartOfExpressionInLine(line, endpos, stack): + """Find position at the matching start of current expression. + + This is almost the reverse of FindEndOfExpressionInLine, but note + that the input position and returned position differs by 1. + + Args: + line: a CleansedLines line. + endpos: start searching at this position. + stack: nesting stack at endpos. + + Returns: + On finding matching start: (index at matching start, None) + On finding an unclosed expression: (-1, None) + Otherwise: (-1, new stack at beginning of this line) + """ + i = endpos + while i >= 0: + char = line[i] + if char in ')]}': + # Found end of expression, push to expression stack + stack.append(char) + elif char == '>': + # Found potential end of template argument list. + # + # Ignore it if it's a "->" or ">=" or "operator>" + if (i > 0 and + (line[i - 1] == '-' or + Match(r'\s>=\s', line[i - 1:]) or + Search(r'\boperator\s*$', line[0:i]))): + i -= 1 + else: + stack.append('>') + elif char == '<': + # Found potential start of template argument list + if i > 0 and line[i - 1] == '<': + # Left shift operator + i -= 1 + else: + # If there is a matching '>', we can pop the expression stack. + # Otherwise, ignore this '<' since it must be an operator. + if stack and stack[-1] == '>': + stack.pop() + if not stack: + return (i, None) + elif char in '([{': + # Found start of expression. + # + # If there are any unmatched '>' on the stack, they must be + # operators. Remove those. + while stack and stack[-1] == '>': + stack.pop() + if not stack: + return (-1, None) + if ((char == '(' and stack[-1] == ')') or + (char == '[' and stack[-1] == ']') or + (char == '{' and stack[-1] == '}')): + stack.pop() + if not stack: + return (i, None) + else: + # Mismatched parentheses + return (-1, None) + elif char == ';': + # Found something that look like end of statements. If we are currently + # expecting a '<', the matching '>' must have been an operator, since + # template argument list should not contain statements. + while stack and stack[-1] == '>': + stack.pop() + if not stack: + return (-1, None) + + i -= 1 + + return (-1, stack) + + +def ReverseCloseExpression(clean_lines, linenum, pos): + """If input points to ) or } or ] or >, finds the position that opens it. + + If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the + linenum/pos that correspond to the opening of the expression. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: A position on the line. + + Returns: + A tuple (line, linenum, pos) pointer *at* the opening brace, or + (line, 0, -1) if we never find the matching opening brace. Note + we ignore strings and comments when matching; and the line we + return is the 'cleansed' line at linenum. + """ + line = clean_lines.elided[linenum] + if line[pos] not in ')}]>': + return (line, 0, -1) + + # Check last line + (start_pos, stack) = FindStartOfExpressionInLine(line, pos, []) + if start_pos > -1: + return (line, linenum, start_pos) + + # Continue scanning backward + while stack and linenum > 0: + linenum -= 1 + line = clean_lines.elided[linenum] + (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack) + if start_pos > -1: + return (line, linenum, start_pos) + + # Did not find start of expression before beginning of file, give up + return (line, 0, -1) + + +def CheckForCopyright(filename, lines, error): + """Logs an error if no Copyright message appears at the top of the file.""" + + # We'll say it should occur by line 10. Don't forget there's a + # dummy line at the front. + for line in xrange(1, min(len(lines), 11)): + if re.search(r'Copyright', lines[line], re.I): break + else: # means no copyright line was found + error(filename, 0, 'legal/copyright', 5, + 'No copyright message found. ' + 'You should have a line: "Copyright [year] "') + + +def GetIndentLevel(line): + """Return the number of leading spaces in line. + + Args: + line: A string to check. + + Returns: + An integer count of leading spaces, possibly zero. + """ + indent = Match(r'^( *)\S', line) + if indent: + return len(indent.group(1)) + else: + return 0 + +def PathSplitToList(path): + """Returns the path split into a list by the separator. + + Args: + path: An absolute or relative path (e.g. '/a/b/c/' or '../a') + + Returns: + A list of path components (e.g. ['a', 'b', 'c]). + """ + lst = [] + while True: + (head, tail) = os.path.split(path) + if head == path: # absolute paths end + lst.append(head) + break + if tail == path: # relative paths end + lst.append(tail) + break + + path = head + lst.append(tail) + + lst.reverse() + return lst + +def GetHeaderGuardCPPVariable(filename): + """Returns the CPP variable that should be used as a header guard. + + Args: + filename: The name of a C++ header file. + + Returns: + The CPP variable that should be used as a header guard in the + named file. + + """ + + # Restores original filename in case that cpplint is invoked from Emacs's + # flymake. + filename = re.sub(r'_flymake\.h$', '.h', filename) + filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) + # Replace 'c++' with 'cpp'. + filename = filename.replace('C++', 'cpp').replace('c++', 'cpp') + + fileinfo = FileInfo(filename) + file_path_from_root = fileinfo.RepositoryName() + + def FixupPathFromRoot(): + if _root_debug: + sys.stderr.write("\n_root fixup, _root = '%s', repository name = '%s'\n" + %(_root, fileinfo.RepositoryName())) + + # Process the file path with the --root flag if it was set. + if not _root: + if _root_debug: + sys.stderr.write("_root unspecified\n") + return file_path_from_root + + def StripListPrefix(lst, prefix): + # f(['x', 'y'], ['w, z']) -> None (not a valid prefix) + if lst[:len(prefix)] != prefix: + return None + # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd'] + return lst[(len(prefix)):] + + # root behavior: + # --root=subdir , lstrips subdir from the header guard + maybe_path = StripListPrefix(PathSplitToList(file_path_from_root), + PathSplitToList(_root)) + + if _root_debug: + sys.stderr.write("_root lstrip (maybe_path=%s, file_path_from_root=%s," + + " _root=%s)\n" %(maybe_path, file_path_from_root, _root)) + + if maybe_path: + return os.path.join(*maybe_path) + + # --root=.. , will prepend the outer directory to the header guard + full_path = fileinfo.FullName() + root_abspath = os.path.abspath(_root) + + maybe_path = StripListPrefix(PathSplitToList(full_path), + PathSplitToList(root_abspath)) + + if _root_debug: + sys.stderr.write("_root prepend (maybe_path=%s, full_path=%s, " + + "root_abspath=%s)\n" %(maybe_path, full_path, root_abspath)) + + if maybe_path: + return os.path.join(*maybe_path) + + if _root_debug: + sys.stderr.write("_root ignore, returning %s\n" %(file_path_from_root)) + + # --root=FAKE_DIR is ignored + return file_path_from_root + + file_path_from_root = FixupPathFromRoot() + return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_' + + +def CheckForHeaderGuard(filename, clean_lines, error): + """Checks that the file contains a header guard. + + Logs an error if no #ifndef header guard is present. For other + headers, checks that the full pathname is used. + + Args: + filename: The name of the C++ header file. + clean_lines: A CleansedLines instance containing the file. + error: The function to call with any errors found. + """ + + # Don't check for header guards if there are error suppression + # comments somewhere in this file. + # + # Because this is silencing a warning for a nonexistent line, we + # only support the very specific NOLINT(build/header_guard) syntax, + # and not the general NOLINT or NOLINT(*) syntax. + raw_lines = clean_lines.lines_without_raw_strings + for i in raw_lines: + if Search(r'//\s*NOLINT\(build/header_guard\)', i): + return + + cppvar = GetHeaderGuardCPPVariable(filename) + + ifndef = '' + ifndef_linenum = 0 + define = '' + endif = '' + endif_linenum = 0 + for linenum, line in enumerate(raw_lines): + linesplit = line.split() + if len(linesplit) >= 2: + # find the first occurrence of #ifndef and #define, save arg + if not ifndef and linesplit[0] == '#ifndef': + # set ifndef to the header guard presented on the #ifndef line. + ifndef = linesplit[1] + ifndef_linenum = linenum + if not define and linesplit[0] == '#define': + define = linesplit[1] + # find the last occurrence of #endif, save entire line + if line.startswith('#endif'): + endif = line + endif_linenum = linenum + + if not ifndef or not define or ifndef != define: + error(filename, 0, 'build/header_guard', 5, + 'No #ifndef header guard found, suggested CPP variable is: %s' % + cppvar) + return + + # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ + # for backward compatibility. + if ifndef != cppvar: + error_level = 0 + if ifndef != cppvar + '_': + error_level = 5 + + ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum, + error) + error(filename, ifndef_linenum, 'build/header_guard', error_level, + '#ifndef header guard has wrong style, please use: %s' % cppvar) + + # Check for "//" comments on endif line. + ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum, + error) + match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif) + if match: + if match.group(1) == '_': + # Issue low severity warning for deprecated double trailing underscore + error(filename, endif_linenum, 'build/header_guard', 0, + '#endif line should be "#endif // %s"' % cppvar) + return + + # Didn't find the corresponding "//" comment. If this file does not + # contain any "//" comments at all, it could be that the compiler + # only wants "/**/" comments, look for those instead. + no_single_line_comments = True + for i in xrange(1, len(raw_lines) - 1): + line = raw_lines[i] + if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line): + no_single_line_comments = False + break + + if no_single_line_comments: + match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif) + if match: + if match.group(1) == '_': + # Low severity warning for double trailing underscore + error(filename, endif_linenum, 'build/header_guard', 0, + '#endif line should be "#endif /* %s */"' % cppvar) + return + + # Didn't find anything + error(filename, endif_linenum, 'build/header_guard', 5, + '#endif line should be "#endif // %s"' % cppvar) + + +def CheckHeaderFileIncluded(filename, include_state, error): + """Logs an error if a .cc file does not include its header.""" + + # Do not check test files + fileinfo = FileInfo(filename) + if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()): + return + + headerfile = filename[0:len(filename) - len(fileinfo.Extension())] + '.h' + if not os.path.exists(headerfile): + return + headername = FileInfo(headerfile).RepositoryName() + first_include = 0 + for section_list in include_state.include_list: + for f in section_list: + if headername in f[0] or f[0] in headername: + return + if not first_include: + first_include = f[1] + + error(filename, first_include, 'build/include', 5, + '%s should include its header file %s' % (fileinfo.RepositoryName(), + headername)) + + +def CheckForBadCharacters(filename, lines, error): + """Logs an error for each line containing bad characters. + + Two kinds of bad characters: + + 1. Unicode replacement characters: These indicate that either the file + contained invalid UTF-8 (likely) or Unicode replacement characters (which + it shouldn't). Note that it's possible for this to throw off line + numbering if the invalid UTF-8 occurred adjacent to a newline. + + 2. NUL bytes. These are problematic for some tools. + + Args: + filename: The name of the current file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + for linenum, line in enumerate(lines): + if u'\ufffd' in line: + error(filename, linenum, 'readability/utf8', 5, + 'Line contains invalid UTF-8 (or Unicode replacement character).') + if '\0' in line: + error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.') + + +def CheckForNewlineAtEOF(filename, lines, error): + """Logs an error if there is no newline char at the end of the file. + + Args: + filename: The name of the current file. + lines: An array of strings, each representing a line of the file. + error: The function to call with any errors found. + """ + + # The array lines() was created by adding two newlines to the + # original file (go figure), then splitting on \n. + # To verify that the file ends in \n, we just have to make sure the + # last-but-two element of lines() exists and is empty. + if len(lines) < 3 or lines[-2]: + error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, + 'Could not find a newline character at the end of the file.') + + +def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): + """Logs an error if we see /* ... */ or "..." that extend past one line. + + /* ... */ comments are legit inside macros, for one line. + Otherwise, we prefer // comments, so it's ok to warn about the + other. Likewise, it's ok for strings to extend across multiple + lines, as long as a line continuation character (backslash) + terminates each line. Although not currently prohibited by the C++ + style guide, it's ugly and unnecessary. We don't do well with either + in this lint program, so we warn about both. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Remove all \\ (escaped backslashes) from the line. They are OK, and the + # second (escaped) slash may trigger later \" detection erroneously. + line = line.replace('\\\\', '') + + if line.count('/*') > line.count('*/'): + error(filename, linenum, 'readability/multiline_comment', 5, + 'Complex multi-line /*...*/-style comment found. ' + 'Lint may give bogus warnings. ' + 'Consider replacing these with //-style comments, ' + 'with #if 0...#endif, ' + 'or with more clearly structured multi-line comments.') + + if (line.count('"') - line.count('\\"')) % 2: + error(filename, linenum, 'readability/multiline_string', 5, + 'Multi-line string ("...") found. This lint script doesn\'t ' + 'do well with such strings, and may give bogus warnings. ' + 'Use C++11 raw strings or concatenation instead.') + + +# (non-threadsafe name, thread-safe alternative, validation pattern) +# +# The validation pattern is used to eliminate false positives such as: +# _rand(); // false positive due to substring match. +# ->rand(); // some member function rand(). +# ACMRandom rand(seed); // some variable named rand. +# ISAACRandom rand(); // another variable named rand. +# +# Basically we require the return value of these functions to be used +# in some expression context on the same line by matching on some +# operator before the function name. This eliminates constructors and +# member function calls. +_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)' +_THREADING_LIST = ( + ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'), + ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'), + ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'), + ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'), + ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'), + ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'), + ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'), + ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'), + ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'), + ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'), + ('strtok(', 'strtok_r(', + _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'), + ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'), + ) + + +def CheckPosixThreading(filename, clean_lines, linenum, error): + """Checks for calls to thread-unsafe functions. + + Much code has been originally written without consideration of + multi-threading. Also, engineers are relying on their old experience; + they have learned posix before threading extensions were added. These + tests guide the engineers to use thread-safe functions (when using + posix directly). + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST: + # Additional pattern matching check to confirm that this is the + # function we are looking for + if Search(pattern, line): + error(filename, linenum, 'runtime/threadsafe_fn', 2, + 'Consider using ' + multithread_safe_func + + '...) instead of ' + single_thread_func + + '...) for improved thread safety.') + + +def CheckVlogArguments(filename, clean_lines, linenum, error): + """Checks that VLOG() is only used for defining a logging level. + + For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and + VLOG(FATAL) are not. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line): + error(filename, linenum, 'runtime/vlog', 5, + 'VLOG() should be used with numeric verbosity level. ' + 'Use LOG() if you want symbolic severity levels.') + +# Matches invalid increment: *count++, which moves pointer instead of +# incrementing a value. +_RE_PATTERN_INVALID_INCREMENT = re.compile( + r'^\s*\*\w+(\+\+|--);') + + +def CheckInvalidIncrement(filename, clean_lines, linenum, error): + """Checks for invalid increment *count++. + + For example following function: + void increment_counter(int* count) { + *count++; + } + is invalid, because it effectively does count++, moving pointer, and should + be replaced with ++*count, (*count)++ or *count += 1. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + if _RE_PATTERN_INVALID_INCREMENT.match(line): + error(filename, linenum, 'runtime/invalid_increment', 5, + 'Changing pointer instead of value (or unused value of operator*).') + + +def IsMacroDefinition(clean_lines, linenum): + if Search(r'^#define', clean_lines[linenum]): + return True + + if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]): + return True + + return False + + +def IsForwardClassDeclaration(clean_lines, linenum): + return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum]) + + +class _BlockInfo(object): + """Stores information about a generic block of code.""" + + def __init__(self, linenum, seen_open_brace): + self.starting_linenum = linenum + self.seen_open_brace = seen_open_brace + self.open_parentheses = 0 + self.inline_asm = _NO_ASM + self.check_namespace_indentation = False + + def CheckBegin(self, filename, clean_lines, linenum, error): + """Run checks that applies to text up to the opening brace. + + This is mostly for checking the text after the class identifier + and the "{", usually where the base class is specified. For other + blocks, there isn't much to check, so we always pass. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + pass + + def CheckEnd(self, filename, clean_lines, linenum, error): + """Run checks that applies to text after the closing brace. + + This is mostly used for checking end of namespace comments. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + pass + + def IsBlockInfo(self): + """Returns true if this block is a _BlockInfo. + + This is convenient for verifying that an object is an instance of + a _BlockInfo, but not an instance of any of the derived classes. + + Returns: + True for this class, False for derived classes. + """ + return self.__class__ == _BlockInfo + + +class _ExternCInfo(_BlockInfo): + """Stores information about an 'extern "C"' block.""" + + def __init__(self, linenum): + _BlockInfo.__init__(self, linenum, True) + + +class _ClassInfo(_BlockInfo): + """Stores information about a class.""" + + def __init__(self, name, class_or_struct, clean_lines, linenum): + _BlockInfo.__init__(self, linenum, False) + self.name = name + self.is_derived = False + self.check_namespace_indentation = True + if class_or_struct == 'struct': + self.access = 'public' + self.is_struct = True + else: + self.access = 'private' + self.is_struct = False + + # Remember initial indentation level for this class. Using raw_lines here + # instead of elided to account for leading comments. + self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum]) + + # Try to find the end of the class. This will be confused by things like: + # class A { + # } *x = { ... + # + # But it's still good enough for CheckSectionSpacing. + self.last_line = 0 + depth = 0 + for i in range(linenum, clean_lines.NumLines()): + line = clean_lines.elided[i] + depth += line.count('{') - line.count('}') + if not depth: + self.last_line = i + break + + def CheckBegin(self, filename, clean_lines, linenum, error): + # Look for a bare ':' + if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]): + self.is_derived = True + + def CheckEnd(self, filename, clean_lines, linenum, error): + # If there is a DISALLOW macro, it should appear near the end of + # the class. + seen_last_thing_in_class = False + for i in xrange(linenum - 1, self.starting_linenum, -1): + match = Search( + r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' + + self.name + r'\)', + clean_lines.elided[i]) + if match: + if seen_last_thing_in_class: + error(filename, i, 'readability/constructors', 3, + match.group(1) + ' should be the last thing in the class') + break + + if not Match(r'^\s*$', clean_lines.elided[i]): + seen_last_thing_in_class = True + + # Check that closing brace is aligned with beginning of the class. + # Only do this if the closing brace is indented by only whitespaces. + # This means we will not check single-line class definitions. + indent = Match(r'^( *)\}', clean_lines.elided[linenum]) + if indent and len(indent.group(1)) != self.class_indent: + if self.is_struct: + parent = 'struct ' + self.name + else: + parent = 'class ' + self.name + error(filename, linenum, 'whitespace/indent', 3, + 'Closing brace should be aligned with beginning of %s' % parent) + + +class _NamespaceInfo(_BlockInfo): + """Stores information about a namespace.""" + + def __init__(self, name, linenum): + _BlockInfo.__init__(self, linenum, False) + self.name = name or '' + self.check_namespace_indentation = True + + def CheckEnd(self, filename, clean_lines, linenum, error): + """Check end of namespace comments.""" + line = clean_lines.raw_lines[linenum] + + # Check how many lines is enclosed in this namespace. Don't issue + # warning for missing namespace comments if there aren't enough + # lines. However, do apply checks if there is already an end of + # namespace comment and it's incorrect. + # + # TODO(unknown): We always want to check end of namespace comments + # if a namespace is large, but sometimes we also want to apply the + # check if a short namespace contained nontrivial things (something + # other than forward declarations). There is currently no logic on + # deciding what these nontrivial things are, so this check is + # triggered by namespace size only, which works most of the time. + if (linenum - self.starting_linenum < 10 + and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)): + return + + # Look for matching comment at end of namespace. + # + # Note that we accept C style "/* */" comments for terminating + # namespaces, so that code that terminate namespaces inside + # preprocessor macros can be cpplint clean. + # + # We also accept stuff like "// end of namespace ." with the + # period at the end. + # + # Besides these, we don't accept anything else, otherwise we might + # get false negatives when existing comment is a substring of the + # expected namespace. + if self.name: + # Named namespace + if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' + + re.escape(self.name) + r'[\*/\.\\\s]*$'), + line): + error(filename, linenum, 'readability/namespace', 5, + 'Namespace should be terminated with "// namespace %s"' % + self.name) + else: + # Anonymous namespace + if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): + # If "// namespace anonymous" or "// anonymous namespace (more text)", + # mention "// anonymous namespace" as an acceptable form + if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line): + error(filename, linenum, 'readability/namespace', 5, + 'Anonymous namespace should be terminated with "// namespace"' + ' or "// anonymous namespace"') + else: + error(filename, linenum, 'readability/namespace', 5, + 'Anonymous namespace should be terminated with "// namespace"') + + +class _PreprocessorInfo(object): + """Stores checkpoints of nesting stacks when #if/#else is seen.""" + + def __init__(self, stack_before_if): + # The entire nesting stack before #if + self.stack_before_if = stack_before_if + + # The entire nesting stack up to #else + self.stack_before_else = [] + + # Whether we have already seen #else or #elif + self.seen_else = False + + +class NestingState(object): + """Holds states related to parsing braces.""" + + def __init__(self): + # Stack for tracking all braces. An object is pushed whenever we + # see a "{", and popped when we see a "}". Only 3 types of + # objects are possible: + # - _ClassInfo: a class or struct. + # - _NamespaceInfo: a namespace. + # - _BlockInfo: some other type of block. + self.stack = [] + + # Top of the previous stack before each Update(). + # + # Because the nesting_stack is updated at the end of each line, we + # had to do some convoluted checks to find out what is the current + # scope at the beginning of the line. This check is simplified by + # saving the previous top of nesting stack. + # + # We could save the full stack, but we only need the top. Copying + # the full nesting stack would slow down cpplint by ~10%. + self.previous_stack_top = [] + + # Stack of _PreprocessorInfo objects. + self.pp_stack = [] + + def SeenOpenBrace(self): + """Check if we have seen the opening brace for the innermost block. + + Returns: + True if we have seen the opening brace, False if the innermost + block is still expecting an opening brace. + """ + return (not self.stack) or self.stack[-1].seen_open_brace + + def InNamespaceBody(self): + """Check if we are currently one level inside a namespace body. + + Returns: + True if top of the stack is a namespace block, False otherwise. + """ + return self.stack and isinstance(self.stack[-1], _NamespaceInfo) + + def InExternC(self): + """Check if we are currently one level inside an 'extern "C"' block. + + Returns: + True if top of the stack is an extern block, False otherwise. + """ + return self.stack and isinstance(self.stack[-1], _ExternCInfo) + + def InClassDeclaration(self): + """Check if we are currently one level inside a class or struct declaration. + + Returns: + True if top of the stack is a class/struct, False otherwise. + """ + return self.stack and isinstance(self.stack[-1], _ClassInfo) + + def InAsmBlock(self): + """Check if we are currently one level inside an inline ASM block. + + Returns: + True if the top of the stack is a block containing inline ASM. + """ + return self.stack and self.stack[-1].inline_asm != _NO_ASM + + def InTemplateArgumentList(self, clean_lines, linenum, pos): + """Check if current position is inside template argument list. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + pos: position just after the suspected template argument. + Returns: + True if (linenum, pos) is inside template arguments. + """ + while linenum < clean_lines.NumLines(): + # Find the earliest character that might indicate a template argument + line = clean_lines.elided[linenum] + match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:]) + if not match: + linenum += 1 + pos = 0 + continue + token = match.group(1) + pos += len(match.group(0)) + + # These things do not look like template argument list: + # class Suspect { + # class Suspect x; } + if token in ('{', '}', ';'): return False + + # These things look like template argument list: + # template + # template + # template + # template + if token in ('>', '=', '[', ']', '.'): return True + + # Check if token is an unmatched '<'. + # If not, move on to the next character. + if token != '<': + pos += 1 + if pos >= len(line): + linenum += 1 + pos = 0 + continue + + # We can't be sure if we just find a single '<', and need to + # find the matching '>'. + (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1) + if end_pos < 0: + # Not sure if template argument list or syntax error in file + return False + linenum = end_line + pos = end_pos + return False + + def UpdatePreprocessor(self, line): + """Update preprocessor stack. + + We need to handle preprocessors due to classes like this: + #ifdef SWIG + struct ResultDetailsPageElementExtensionPoint { + #else + struct ResultDetailsPageElementExtensionPoint : public Extension { + #endif + + We make the following assumptions (good enough for most files): + - Preprocessor condition evaluates to true from #if up to first + #else/#elif/#endif. + + - Preprocessor condition evaluates to false from #else/#elif up + to #endif. We still perform lint checks on these lines, but + these do not affect nesting stack. + + Args: + line: current line to check. + """ + if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): + # Beginning of #if block, save the nesting stack here. The saved + # stack will allow us to restore the parsing state in the #else case. + self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) + elif Match(r'^\s*#\s*(else|elif)\b', line): + # Beginning of #else block + if self.pp_stack: + if not self.pp_stack[-1].seen_else: + # This is the first #else or #elif block. Remember the + # whole nesting stack up to this point. This is what we + # keep after the #endif. + self.pp_stack[-1].seen_else = True + self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) + + # Restore the stack to how it was before the #if + self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) + else: + # TODO(unknown): unexpected #else, issue warning? + pass + elif Match(r'^\s*#\s*endif\b', line): + # End of #if or #else blocks. + if self.pp_stack: + # If we saw an #else, we will need to restore the nesting + # stack to its former state before the #else, otherwise we + # will just continue from where we left off. + if self.pp_stack[-1].seen_else: + # Here we can just use a shallow copy since we are the last + # reference to it. + self.stack = self.pp_stack[-1].stack_before_else + # Drop the corresponding #if + self.pp_stack.pop() + else: + # TODO(unknown): unexpected #endif, issue warning? + pass + + # TODO(unknown): Update() is too long, but we will refactor later. + def Update(self, filename, clean_lines, linenum, error): + """Update nesting state with current line. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Remember top of the previous nesting stack. + # + # The stack is always pushed/popped and not modified in place, so + # we can just do a shallow copy instead of copy.deepcopy. Using + # deepcopy would slow down cpplint by ~28%. + if self.stack: + self.previous_stack_top = self.stack[-1] + else: + self.previous_stack_top = None + + # Update pp_stack + self.UpdatePreprocessor(line) + + # Count parentheses. This is to avoid adding struct arguments to + # the nesting stack. + if self.stack: + inner_block = self.stack[-1] + depth_change = line.count('(') - line.count(')') + inner_block.open_parentheses += depth_change + + # Also check if we are starting or ending an inline assembly block. + if inner_block.inline_asm in (_NO_ASM, _END_ASM): + if (depth_change != 0 and + inner_block.open_parentheses == 1 and + _MATCH_ASM.match(line)): + # Enter assembly block + inner_block.inline_asm = _INSIDE_ASM + else: + # Not entering assembly block. If previous line was _END_ASM, + # we will now shift to _NO_ASM state. + inner_block.inline_asm = _NO_ASM + elif (inner_block.inline_asm == _INSIDE_ASM and + inner_block.open_parentheses == 0): + # Exit assembly block + inner_block.inline_asm = _END_ASM + + # Consume namespace declaration at the beginning of the line. Do + # this in a loop so that we catch same line declarations like this: + # namespace proto2 { namespace bridge { class MessageSet; } } + while True: + # Match start of namespace. The "\b\s*" below catches namespace + # declarations even if it weren't followed by a whitespace, this + # is so that we don't confuse our namespace checker. The + # missing spaces will be flagged by CheckSpacing. + namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) + if not namespace_decl_match: + break + + new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) + self.stack.append(new_namespace) + + line = namespace_decl_match.group(2) + if line.find('{') != -1: + new_namespace.seen_open_brace = True + line = line[line.find('{') + 1:] + + # Look for a class declaration in whatever is left of the line + # after parsing namespaces. The regexp accounts for decorated classes + # such as in: + # class LOCKABLE API Object { + # }; + class_decl_match = Match( + r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?' + r'(class|struct)\s+(?:[A-Z_]+\s+)*(\w+(?:::\w+)*))' + r'(.*)$', line) + if (class_decl_match and + (not self.stack or self.stack[-1].open_parentheses == 0)): + # We do not want to accept classes that are actually template arguments: + # template , + # template class Ignore3> + # void Function() {}; + # + # To avoid template argument cases, we scan forward and look for + # an unmatched '>'. If we see one, assume we are inside a + # template argument list. + end_declaration = len(class_decl_match.group(1)) + if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration): + self.stack.append(_ClassInfo( + class_decl_match.group(3), class_decl_match.group(2), + clean_lines, linenum)) + line = class_decl_match.group(4) + + # If we have not yet seen the opening brace for the innermost block, + # run checks here. + if not self.SeenOpenBrace(): + self.stack[-1].CheckBegin(filename, clean_lines, linenum, error) + + # Update access control if we are inside a class/struct + if self.stack and isinstance(self.stack[-1], _ClassInfo): + classinfo = self.stack[-1] + access_match = Match( + r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' + r':(?:[^:]|$)', + line) + if access_match: + classinfo.access = access_match.group(2) + + # Check that access keywords are indented +1 space. Skip this + # check if the keywords are not preceded by whitespaces. + indent = access_match.group(1) + if (len(indent) != classinfo.class_indent + 1 and + Match(r'^\s*$', indent)): + if classinfo.is_struct: + parent = 'struct ' + classinfo.name + else: + parent = 'class ' + classinfo.name + slots = '' + if access_match.group(3): + slots = access_match.group(3) + error(filename, linenum, 'whitespace/indent', 3, + '%s%s: should be indented +1 space inside %s' % ( + access_match.group(2), slots, parent)) + + # Consume braces or semicolons from what's left of the line + while True: + # Match first brace, semicolon, or closed parenthesis. + matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) + if not matched: + break + + token = matched.group(1) + if token == '{': + # If namespace or class hasn't seen a opening brace yet, mark + # namespace/class head as complete. Push a new block onto the + # stack otherwise. + if not self.SeenOpenBrace(): + self.stack[-1].seen_open_brace = True + elif Match(r'^extern\s*"[^"]*"\s*\{', line): + self.stack.append(_ExternCInfo(linenum)) + else: + self.stack.append(_BlockInfo(linenum, True)) + if _MATCH_ASM.match(line): + self.stack[-1].inline_asm = _BLOCK_ASM + + elif token == ';' or token == ')': + # If we haven't seen an opening brace yet, but we already saw + # a semicolon, this is probably a forward declaration. Pop + # the stack for these. + # + # Similarly, if we haven't seen an opening brace yet, but we + # already saw a closing parenthesis, then these are probably + # function arguments with extra "class" or "struct" keywords. + # Also pop these stack for these. + if not self.SeenOpenBrace(): + self.stack.pop() + else: # token == '}' + # Perform end of block checks and pop the stack. + if self.stack: + self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) + self.stack.pop() + line = matched.group(2) + + def InnermostClass(self): + """Get class info on the top of the stack. + + Returns: + A _ClassInfo object if we are inside a class, or None otherwise. + """ + for i in range(len(self.stack), 0, -1): + classinfo = self.stack[i - 1] + if isinstance(classinfo, _ClassInfo): + return classinfo + return None + + def CheckCompletedBlocks(self, filename, error): + """Checks that all classes and namespaces have been completely parsed. + + Call this when all lines in a file have been processed. + Args: + filename: The name of the current file. + error: The function to call with any errors found. + """ + # Note: This test can result in false positives if #ifdef constructs + # get in the way of brace matching. See the testBuildClass test in + # cpplint_unittest.py for an example of this. + for obj in self.stack: + if isinstance(obj, _ClassInfo): + error(filename, obj.starting_linenum, 'build/class', 5, + 'Failed to find complete declaration of class %s' % + obj.name) + elif isinstance(obj, _NamespaceInfo): + error(filename, obj.starting_linenum, 'build/namespaces', 5, + 'Failed to find complete declaration of namespace %s' % + obj.name) + + +def CheckForNonStandardConstructs(filename, clean_lines, linenum, + nesting_state, error): + r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. + + Complain about several constructs which gcc-2 accepts, but which are + not standard C++. Warning about these in lint is one way to ease the + transition to new compilers. + - put storage class first (e.g. "static const" instead of "const static"). + - "%lld" instead of %qd" in printf-type functions. + - "%1$d" is non-standard in printf-type functions. + - "\%" is an undefined character escape sequence. + - text after #endif is not allowed. + - invalid inner-style forward declaration. + - >? and ?= and )\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', + line): + error(filename, linenum, 'build/deprecated', 3, + '>? and ))?' + # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' + error(filename, linenum, 'runtime/member_string_references', 2, + 'const string& members are dangerous. It is much better to use ' + 'alternatives, such as pointers or simple constants.') + + # Everything else in this function operates on class declarations. + # Return early if the top of the nesting stack is not a class, or if + # the class head is not completed yet. + classinfo = nesting_state.InnermostClass() + if not classinfo or not classinfo.seen_open_brace: + return + + # The class may have been declared with namespace or classname qualifiers. + # The constructor and destructor will not have those qualifiers. + base_classname = classinfo.name.split('::')[-1] + + # Look for single-argument constructors that aren't marked explicit. + # Technically a valid construct, but against style. + explicit_constructor_match = Match( + r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?' + r'(?:(?:inline|constexpr)\s+)*%s\s*' + r'\(((?:[^()]|\([^()]*\))*)\)' + % re.escape(base_classname), + line) + + if explicit_constructor_match: + is_marked_explicit = explicit_constructor_match.group(1) + + if not explicit_constructor_match.group(2): + constructor_args = [] + else: + constructor_args = explicit_constructor_match.group(2).split(',') + + # collapse arguments so that commas in template parameter lists and function + # argument parameter lists don't split arguments in two + i = 0 + while i < len(constructor_args): + constructor_arg = constructor_args[i] + while (constructor_arg.count('<') > constructor_arg.count('>') or + constructor_arg.count('(') > constructor_arg.count(')')): + constructor_arg += ',' + constructor_args[i + 1] + del constructor_args[i + 1] + constructor_args[i] = constructor_arg + i += 1 + + defaulted_args = [arg for arg in constructor_args if '=' in arg] + noarg_constructor = (not constructor_args or # empty arg list + # 'void' arg specifier + (len(constructor_args) == 1 and + constructor_args[0].strip() == 'void')) + onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg + not noarg_constructor) or + # all but at most one arg defaulted + (len(constructor_args) >= 1 and + not noarg_constructor and + len(defaulted_args) >= len(constructor_args) - 1)) + initializer_list_constructor = bool( + onearg_constructor and + Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) + copy_constructor = bool( + onearg_constructor and + Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' + % re.escape(base_classname), constructor_args[0].strip())) + + if (not is_marked_explicit and + onearg_constructor and + not initializer_list_constructor and + not copy_constructor): + if defaulted_args: + error(filename, linenum, 'runtime/explicit', 5, + 'Constructors callable with one argument ' + 'should be marked explicit.') + else: + error(filename, linenum, 'runtime/explicit', 5, + 'Single-parameter constructors should be marked explicit.') + elif is_marked_explicit and not onearg_constructor: + if noarg_constructor: + error(filename, linenum, 'runtime/explicit', 5, + 'Zero-parameter constructors should not be marked explicit.') + + +def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): + """Checks for the correctness of various spacing around function calls. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Since function calls often occur inside if/for/while/switch + # expressions - which have their own, more liberal conventions - we + # first see if we should be looking inside such an expression for a + # function call, to which we can apply more strict standards. + fncall = line # if there's no control flow construct, look at whole line + for pattern in (r'\bif\s*\((.*)\)\s*{', + r'\bfor\s*\((.*)\)\s*{', + r'\bwhile\s*\((.*)\)\s*[{;]', + r'\bswitch\s*\((.*)\)\s*{'): + match = Search(pattern, line) + if match: + fncall = match.group(1) # look inside the parens for function calls + break + + # Except in if/for/while/switch, there should never be space + # immediately inside parens (eg "f( 3, 4 )"). We make an exception + # for nested parens ( (a+b) + c ). Likewise, there should never be + # a space before a ( when it's a function argument. I assume it's a + # function argument when the char before the whitespace is legal in + # a function name (alnum + _) and we're not starting a macro. Also ignore + # pointers and references to arrays and functions coz they're too tricky: + # we use a very simple way to recognize these: + # " (something)(maybe-something)" or + # " (something)(maybe-something," or + # " (something)[something]" + # Note that we assume the contents of [] to be short enough that + # they'll never need to wrap. + if ( # Ignore control structures. + not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b', + fncall) and + # Ignore pointers/references to functions. + not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and + # Ignore pointers/references to arrays. + not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): + if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call + error(filename, linenum, 'whitespace/parens', 4, + 'Extra space after ( in function call') + elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): + error(filename, linenum, 'whitespace/parens', 2, + 'Extra space after (') + if (Search(r'\w\s+\(', fncall) and + not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and + not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and + not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and + not Search(r'\bcase\s+\(', fncall)): + # TODO(unknown): Space after an operator function seem to be a common + # error, silence those for now by restricting them to highest verbosity. + if Search(r'\boperator_*\b', line): + error(filename, linenum, 'whitespace/parens', 0, + 'Extra space before ( in function call') + else: + error(filename, linenum, 'whitespace/parens', 4, + 'Extra space before ( in function call') + # If the ) is followed only by a newline or a { + newline, assume it's + # part of a control statement (if/while/etc), and don't complain + if Search(r'[^)]\s+\)\s*[^{\s]', fncall): + # If the closing parenthesis is preceded by only whitespaces, + # try to give a more descriptive error message. + if Search(r'^\s+\)', fncall): + error(filename, linenum, 'whitespace/parens', 2, + 'Closing ) should be moved to the previous line') + else: + error(filename, linenum, 'whitespace/parens', 2, + 'Extra space before )') + + +def IsBlankLine(line): + """Returns true if the given line is blank. + + We consider a line to be blank if the line is empty or consists of + only white spaces. + + Args: + line: A line of a string. + + Returns: + True, if the given line is blank. + """ + return not line or line.isspace() + + +def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, + error): + is_namespace_indent_item = ( + len(nesting_state.stack) > 1 and + nesting_state.stack[-1].check_namespace_indentation and + isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and + nesting_state.previous_stack_top == nesting_state.stack[-2]) + + if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, + clean_lines.elided, line): + CheckItemIndentationInNamespace(filename, clean_lines.elided, + line, error) + + +def CheckForFunctionLengths(filename, clean_lines, linenum, + function_state, error): + """Reports for long function bodies. + + For an overview why this is done, see: + https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions + + Uses a simplistic algorithm assuming other style guidelines + (especially spacing) are followed. + Only checks unindented functions, so class members are unchecked. + Trivial bodies are unchecked, so constructors with huge initializer lists + may be missed. + Blank/comment lines are not counted so as to avoid encouraging the removal + of vertical space and comments just to get through a lint check. + NOLINT *on the last line of a function* disables this check. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + function_state: Current function name and lines in body so far. + error: The function to call with any errors found. + """ + lines = clean_lines.lines + line = lines[linenum] + joined_line = '' + + starting_func = False + regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... + match_result = Match(regexp, line) + if match_result: + # If the name is all caps and underscores, figure it's a macro and + # ignore it, unless it's TEST or TEST_F. + function_name = match_result.group(1).split()[-1] + if function_name == 'TEST' or function_name == 'TEST_F' or ( + not Match(r'[A-Z_]+$', function_name)): + starting_func = True + + if starting_func: + body_found = False + for start_linenum in xrange(linenum, clean_lines.NumLines()): + start_line = lines[start_linenum] + joined_line += ' ' + start_line.lstrip() + if Search(r'(;|})', start_line): # Declarations and trivial functions + body_found = True + break # ... ignore + elif Search(r'{', start_line): + body_found = True + function = Search(r'((\w|:)*)\(', line).group(1) + if Match(r'TEST', function): # Handle TEST... macros + parameter_regexp = Search(r'(\(.*\))', joined_line) + if parameter_regexp: # Ignore bad syntax + function += parameter_regexp.group(1) + else: + function += '()' + function_state.Begin(function) + break + if not body_found: + # No body for the function (or evidence of a non-function) was found. + error(filename, linenum, 'readability/fn_size', 5, + 'Lint failed to find start of function body.') + elif Match(r'^\}\s*$', line): # function end + function_state.Check(error, filename, linenum) + function_state.End() + elif not Match(r'^\s*$', line): + function_state.Count() # Count non-blank/non-comment lines. + + +_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') + + +def CheckComment(line, filename, linenum, next_line_start, error): + """Checks for common mistakes in comments. + + Args: + line: The line in question. + filename: The name of the current file. + linenum: The number of the line to check. + next_line_start: The first non-whitespace column of the next line. + error: The function to call with any errors found. + """ + commentpos = line.find('//') + if commentpos != -1: + # Check if the // may be in quotes. If so, ignore it + if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0: + # Allow one space for new scopes, two spaces otherwise: + if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and + ((commentpos >= 1 and + line[commentpos-1] not in string.whitespace) or + (commentpos >= 2 and + line[commentpos-2] not in string.whitespace))): + error(filename, linenum, 'whitespace/comments', 2, + 'At least two spaces is best between code and comments') + + # Checks for common mistakes in TODO comments. + comment = line[commentpos:] + match = _RE_PATTERN_TODO.match(comment) + if match: + # One whitespace is correct; zero whitespace is handled elsewhere. + leading_whitespace = match.group(1) + if len(leading_whitespace) > 1: + error(filename, linenum, 'whitespace/todo', 2, + 'Too many spaces before TODO') + + username = match.group(2) + if not username: + error(filename, linenum, 'readability/todo', 2, + 'Missing username in TODO; it should look like ' + '"// TODO(my_username): Stuff."') + + middle_whitespace = match.group(3) + # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison + if middle_whitespace != ' ' and middle_whitespace != '': + error(filename, linenum, 'whitespace/todo', 2, + 'TODO(my_username) should be followed by a space') + + # If the comment contains an alphanumeric character, there + # should be a space somewhere between it and the // unless + # it's a /// or //! Doxygen comment. + if (Match(r'//[^ ]*\w', comment) and + not Match(r'(///|//\!)(\s+|$)', comment)): + error(filename, linenum, 'whitespace/comments', 4, + 'Should have a space between // and comment') + + +def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): + """Checks for the correctness of various spacing issues in the code. + + Things we check for: spaces around operators, spaces after + if/for/while/switch, no spaces around parens in function calls, two + spaces between code and comment, don't start a block with a blank + line, don't end a function with a blank line, don't add a blank line + after public/protected/private, don't have too many blank lines in a row. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + + # Don't use "elided" lines here, otherwise we can't check commented lines. + # Don't want to use "raw" either, because we don't want to check inside C++11 + # raw strings, + raw = clean_lines.lines_without_raw_strings + line = raw[linenum] + + # Before nixing comments, check if the line is blank for no good + # reason. This includes the first line after a block is opened, and + # blank lines at the end of a function (ie, right before a line like '}' + # + # Skip all the blank line checks if we are immediately inside a + # namespace body. In other words, don't issue blank line warnings + # for this block: + # namespace { + # + # } + # + # A warning about missing end of namespace comments will be issued instead. + # + # Also skip blank line checks for 'extern "C"' blocks, which are formatted + # like namespaces. + if (IsBlankLine(line) and + not nesting_state.InNamespaceBody() and + not nesting_state.InExternC()): + elided = clean_lines.elided + prev_line = elided[linenum - 1] + prevbrace = prev_line.rfind('{') + # TODO(unknown): Don't complain if line before blank line, and line after, + # both start with alnums and are indented the same amount. + # This ignores whitespace at the start of a namespace block + # because those are not usually indented. + if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: + # OK, we have a blank line at the start of a code block. Before we + # complain, we check if it is an exception to the rule: The previous + # non-empty line has the parameters of a function header that are indented + # 4 spaces (because they did not fit in a 80 column line when placed on + # the same line as the function name). We also check for the case where + # the previous line is indented 6 spaces, which may happen when the + # initializers of a constructor do not fit into a 80 column line. + exception = False + if Match(r' {6}\w', prev_line): # Initializer list? + # We are looking for the opening column of initializer list, which + # should be indented 4 spaces to cause 6 space indentation afterwards. + search_position = linenum-2 + while (search_position >= 0 + and Match(r' {6}\w', elided[search_position])): + search_position -= 1 + exception = (search_position >= 0 + and elided[search_position][:5] == ' :') + else: + # Search for the function arguments or an initializer list. We use a + # simple heuristic here: If the line is indented 4 spaces; and we have a + # closing paren, without the opening paren, followed by an opening brace + # or colon (for initializer lists) we assume that it is the last line of + # a function header. If we have a colon indented 4 spaces, it is an + # initializer list. + exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', + prev_line) + or Match(r' {4}:', prev_line)) + + if not exception: + error(filename, linenum, 'whitespace/blank_line', 2, + 'Redundant blank line at the start of a code block ' + 'should be deleted.') + # Ignore blank lines at the end of a block in a long if-else + # chain, like this: + # if (condition1) { + # // Something followed by a blank line + # + # } else if (condition2) { + # // Something else + # } + if linenum + 1 < clean_lines.NumLines(): + next_line = raw[linenum + 1] + if (next_line + and Match(r'\s*}', next_line) + and next_line.find('} else ') == -1): + error(filename, linenum, 'whitespace/blank_line', 3, + 'Redundant blank line at the end of a code block ' + 'should be deleted.') + + matched = Match(r'\s*(public|protected|private):', prev_line) + if matched: + error(filename, linenum, 'whitespace/blank_line', 3, + 'Do not leave a blank line after "%s:"' % matched.group(1)) + + # Next, check comments + next_line_start = 0 + if linenum + 1 < clean_lines.NumLines(): + next_line = raw[linenum + 1] + next_line_start = len(next_line) - len(next_line.lstrip()) + CheckComment(line, filename, linenum, next_line_start, error) + + # get rid of comments and strings + line = clean_lines.elided[linenum] + + # You shouldn't have spaces before your brackets, except maybe after + # 'delete []' or 'return []() {};' + if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Extra space before [') + + # In range-based for, we wanted spaces before and after the colon, but + # not around "::" tokens that might appear. + if (Search(r'for *\(.*[^:]:[^: ]', line) or + Search(r'for *\(.*[^: ]:[^:]', line)): + error(filename, linenum, 'whitespace/forcolon', 2, + 'Missing space around colon in range-based for loop') + + +def CheckOperatorSpacing(filename, clean_lines, linenum, error): + """Checks for horizontal spacing around operators. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Don't try to do spacing checks for operator methods. Do this by + # replacing the troublesome characters with something else, + # preserving column position for all other characters. + # + # The replacement is done repeatedly to avoid false positives from + # operators that call operators. + while True: + match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line) + if match: + line = match.group(1) + ('_' * len(match.group(2))) + match.group(3) + else: + break + + # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". + # Otherwise not. Note we only check for non-spaces on *both* sides; + # sometimes people put non-spaces on one side when aligning ='s among + # many lines (not that this is behavior that I approve of...) + if ((Search(r'[\w.]=', line) or + Search(r'=[\w.]', line)) + and not Search(r'\b(if|while|for) ', line) + # Operators taken from [lex.operators] in C++11 standard. + and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line) + and not Search(r'operator=', line)): + error(filename, linenum, 'whitespace/operators', 4, + 'Missing spaces around =') + + # It's ok not to have spaces around binary operators like + - * /, but if + # there's too little whitespace, we get concerned. It's hard to tell, + # though, so we punt on this one for now. TODO. + + # You should always have whitespace around binary operators. + # + # Check <= and >= first to avoid false positives with < and >, then + # check non-include lines for spacing around < and >. + # + # If the operator is followed by a comma, assume it's be used in a + # macro context and don't do any checks. This avoids false + # positives. + # + # Note that && is not included here. This is because there are too + # many false positives due to RValue references. + match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line) + if match: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around %s' % match.group(1)) + elif not Match(r'#.*include', line): + # Look for < that is not surrounded by spaces. This is only + # triggered if both sides are missing spaces, even though + # technically should should flag if at least one side is missing a + # space. This is done to avoid some false positives with shifts. + match = Match(r'^(.*[^\s<])<[^\s=<,]', line) + if match: + (_, _, end_pos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + if end_pos <= -1: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around <') + + # Look for > that is not surrounded by spaces. Similar to the + # above, we only trigger if both sides are missing spaces to avoid + # false positives with shifts. + match = Match(r'^(.*[^-\s>])>[^\s=>,]', line) + if match: + (_, _, start_pos) = ReverseCloseExpression( + clean_lines, linenum, len(match.group(1))) + if start_pos <= -1: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around >') + + # We allow no-spaces around << when used like this: 10<<20, but + # not otherwise (particularly, not when used as streams) + # + # We also allow operators following an opening parenthesis, since + # those tend to be macros that deal with operators. + match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line) + if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and + not (match.group(1) == 'operator' and match.group(2) == ';')): + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around <<') + + # We allow no-spaces around >> for almost anything. This is because + # C++11 allows ">>" to close nested templates, which accounts for + # most cases when ">>" is not followed by a space. + # + # We still warn on ">>" followed by alpha character, because that is + # likely due to ">>" being used for right shifts, e.g.: + # value >> alpha + # + # When ">>" is used to close templates, the alphanumeric letter that + # follows would be part of an identifier, and there should still be + # a space separating the template type and the identifier. + # type> alpha + match = Search(r'>>[a-zA-Z_]', line) + if match: + error(filename, linenum, 'whitespace/operators', 3, + 'Missing spaces around >>') + + # There shouldn't be space around unary operators + match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) + if match: + error(filename, linenum, 'whitespace/operators', 4, + 'Extra space for operator %s' % match.group(1)) + + +def CheckParenthesisSpacing(filename, clean_lines, linenum, error): + """Checks for horizontal spacing around parentheses. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # No spaces after an if, while, switch, or for + match = Search(r' (if\(|for\(|while\(|switch\()', line) + if match: + error(filename, linenum, 'whitespace/parens', 5, + 'Missing space before ( in %s' % match.group(1)) + + # For if/for/while/switch, the left and right parens should be + # consistent about how many spaces are inside the parens, and + # there should either be zero or one spaces inside the parens. + # We don't want: "if ( foo)" or "if ( foo )". + # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. + match = Search(r'\b(if|for|while|switch)\s*' + r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', + line) + if match: + if len(match.group(2)) != len(match.group(4)): + if not (match.group(3) == ';' and + len(match.group(2)) == 1 + len(match.group(4)) or + not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): + error(filename, linenum, 'whitespace/parens', 5, + 'Mismatching spaces inside () in %s' % match.group(1)) + if len(match.group(2)) not in [0, 1]: + error(filename, linenum, 'whitespace/parens', 5, + 'Should have zero or one spaces inside ( and ) in %s' % + match.group(1)) + + +def CheckCommaSpacing(filename, clean_lines, linenum, error): + """Checks for horizontal spacing near commas and semicolons. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + raw = clean_lines.lines_without_raw_strings + line = clean_lines.elided[linenum] + + # You should always have a space after a comma (either as fn arg or operator) + # + # This does not apply when the non-space character following the + # comma is another comma, since the only time when that happens is + # for empty macro arguments. + # + # We run this check in two passes: first pass on elided lines to + # verify that lines contain missing whitespaces, second pass on raw + # lines to confirm that those missing whitespaces are not due to + # elided comments. + if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and + Search(r',[^,\s]', raw[linenum])): + error(filename, linenum, 'whitespace/comma', 3, + 'Missing space after ,') + + # You should always have a space after a semicolon + # except for few corner cases + # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more + # space after ; + if Search(r';[^\s};\\)/]', line): + error(filename, linenum, 'whitespace/semicolon', 3, + 'Missing space after ;') + + +def _IsType(clean_lines, nesting_state, expr): + """Check if expression looks like a type name, returns true if so. + + Args: + clean_lines: A CleansedLines instance containing the file. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + expr: The expression to check. + Returns: + True, if token looks like a type. + """ + # Keep only the last token in the expression + last_word = Match(r'^.*(\b\S+)$', expr) + if last_word: + token = last_word.group(1) + else: + token = expr + + # Match native types and stdint types + if _TYPES.match(token): + return True + + # Try a bit harder to match templated types. Walk up the nesting + # stack until we find something that resembles a typename + # declaration for what we are looking for. + typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) + + r'\b') + block_index = len(nesting_state.stack) - 1 + while block_index >= 0: + if isinstance(nesting_state.stack[block_index], _NamespaceInfo): + return False + + # Found where the opening brace is. We want to scan from this + # line up to the beginning of the function, minus a few lines. + # template + # class C + # : public ... { // start scanning here + last_line = nesting_state.stack[block_index].starting_linenum + + next_block_start = 0 + if block_index > 0: + next_block_start = nesting_state.stack[block_index - 1].starting_linenum + first_line = last_line + while first_line >= next_block_start: + if clean_lines.elided[first_line].find('template') >= 0: + break + first_line -= 1 + if first_line < next_block_start: + # Didn't find any "template" keyword before reaching the next block, + # there are probably no template things to check for this block + block_index -= 1 + continue + + # Look for typename in the specified range + for i in xrange(first_line, last_line + 1, 1): + if Search(typename_pattern, clean_lines.elided[i]): + return True + block_index -= 1 + + return False + + +def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error): + """Checks for horizontal spacing near commas. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Except after an opening paren, or after another opening brace (in case of + # an initializer list, for instance), you should have spaces before your + # braces when they are delimiting blocks, classes, namespaces etc. + # And since you should never have braces at the beginning of a line, + # this is an easy test. Except that braces used for initialization don't + # follow the same rule; we often don't want spaces before those. + match = Match(r'^(.*[^ ({>]){', line) + + if match: + # Try a bit harder to check for brace initialization. This + # happens in one of the following forms: + # Constructor() : initializer_list_{} { ... } + # Constructor{}.MemberFunction() + # Type variable{}; + # FunctionCall(type{}, ...); + # LastArgument(..., type{}); + # LOG(INFO) << type{} << " ..."; + # map_of_type[{...}] = ...; + # ternary = expr ? new type{} : nullptr; + # OuterTemplate{}> + # + # We check for the character following the closing brace, and + # silence the warning if it's one of those listed above, i.e. + # "{.;,)<>]:". + # + # To account for nested initializer list, we allow any number of + # closing braces up to "{;,)<". We can't simply silence the + # warning on first sight of closing brace, because that would + # cause false negatives for things that are not initializer lists. + # Silence this: But not this: + # Outer{ if (...) { + # Inner{...} if (...){ // Missing space before { + # }; } + # + # There is a false negative with this approach if people inserted + # spurious semicolons, e.g. "if (cond){};", but we will catch the + # spurious semicolon with a separate check. + leading_text = match.group(1) + (endline, endlinenum, endpos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + trailing_text = '' + if endpos > -1: + trailing_text = endline[endpos:] + for offset in xrange(endlinenum + 1, + min(endlinenum + 3, clean_lines.NumLines() - 1)): + trailing_text += clean_lines.elided[offset] + # We also suppress warnings for `uint64_t{expression}` etc., as the style + # guide recommends brace initialization for integral types to avoid + # overflow/truncation. + if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text) + and not _IsType(clean_lines, nesting_state, leading_text)): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before {') + + # Make sure '} else {' has spaces. + if Search(r'}else', line): + error(filename, linenum, 'whitespace/braces', 5, + 'Missing space before else') + + # You shouldn't have a space before a semicolon at the end of the line. + # There's a special case for "for" since the style guide allows space before + # the semicolon there. + if Search(r':\s*;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Semicolon defining empty statement. Use {} instead.') + elif Search(r'^\s*;\s*$', line): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Line contains only semicolon. If this should be an empty statement, ' + 'use {} instead.') + elif (Search(r'\s+;\s*$', line) and + not Search(r'\bfor\b', line)): + error(filename, linenum, 'whitespace/semicolon', 5, + 'Extra space before last semicolon. If this should be an empty ' + 'statement, use {} instead.') + + +def IsDecltype(clean_lines, linenum, column): + """Check if the token ending on (linenum, column) is decltype(). + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: the number of the line to check. + column: end column of the token to check. + Returns: + True if this token is decltype() expression, False otherwise. + """ + (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column) + if start_col < 0: + return False + if Search(r'\bdecltype\s*$', text[0:start_col]): + return True + return False + + +def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): + """Checks for additional blank line issues related to sections. + + Currently the only thing checked here is blank line before protected/private. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + class_info: A _ClassInfo objects. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + # Skip checks if the class is small, where small means 25 lines or less. + # 25 lines seems like a good cutoff since that's the usual height of + # terminals, and any class that can't fit in one screen can't really + # be considered "small". + # + # Also skip checks if we are on the first line. This accounts for + # classes that look like + # class Foo { public: ... }; + # + # If we didn't find the end of the class, last_line would be zero, + # and the check will be skipped by the first condition. + if (class_info.last_line - class_info.starting_linenum <= 24 or + linenum <= class_info.starting_linenum): + return + + matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) + if matched: + # Issue warning if the line before public/protected/private was + # not a blank line, but don't do this if the previous line contains + # "class" or "struct". This can happen two ways: + # - We are at the beginning of the class. + # - We are forward-declaring an inner class that is semantically + # private, but needed to be public for implementation reasons. + # Also ignores cases where the previous line ends with a backslash as can be + # common when defining classes in C macros. + prev_line = clean_lines.lines[linenum - 1] + if (not IsBlankLine(prev_line) and + not Search(r'\b(class|struct)\b', prev_line) and + not Search(r'\\$', prev_line)): + # Try a bit harder to find the beginning of the class. This is to + # account for multi-line base-specifier lists, e.g.: + # class Derived + # : public Base { + end_class_head = class_info.starting_linenum + for i in range(class_info.starting_linenum, linenum): + if Search(r'\{\s*$', clean_lines.lines[i]): + end_class_head = i + break + if end_class_head < linenum - 1: + error(filename, linenum, 'whitespace/blank_line', 3, + '"%s:" should be preceded by a blank line' % matched.group(1)) + + +def GetPreviousNonBlankLine(clean_lines, linenum): + """Return the most recent non-blank line and its line number. + + Args: + clean_lines: A CleansedLines instance containing the file contents. + linenum: The number of the line to check. + + Returns: + A tuple with two elements. The first element is the contents of the last + non-blank line before the current line, or the empty string if this is the + first non-blank line. The second is the line number of that line, or -1 + if this is the first non-blank line. + """ + + prevlinenum = linenum - 1 + while prevlinenum >= 0: + prevline = clean_lines.elided[prevlinenum] + if not IsBlankLine(prevline): # if not a blank line... + return (prevline, prevlinenum) + prevlinenum -= 1 + return ('', -1) + + +def CheckBraces(filename, clean_lines, linenum, error): + """Looks for misplaced braces (e.g. at the end of line). + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + line = clean_lines.elided[linenum] # get rid of comments and strings + + if Match(r'\s*{\s*$', line): + # We allow an open brace to start a line in the case where someone is using + # braces in a block to explicitly create a new scope, which is commonly used + # to control the lifetime of stack-allocated variables. Braces are also + # used for brace initializers inside function calls. We don't detect this + # perfectly: we just don't complain if the last non-whitespace character on + # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the + # previous line starts a preprocessor block. We also allow a brace on the + # following line if it is part of an array initialization and would not fit + # within the 80 character limit of the preceding line. + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if (not Search(r'[,;:}{(]\s*$', prevline) and + not Match(r'\s*#', prevline) and + not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)): + error(filename, linenum, 'whitespace/braces', 4, + '{ should almost always be at the end of the previous line') + + # An else clause should be on the same line as the preceding closing brace. + if Match(r'\s*else\b\s*(?:if\b|\{|$)', line): + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if Match(r'\s*}\s*$', prevline): + error(filename, linenum, 'whitespace/newline', 4, + 'An else should appear on the same line as the preceding }') + + # If braces come on one side of an else, they should be on both. + # However, we have to worry about "else if" that spans multiple lines! + if Search(r'else if\s*\(', line): # could be multi-line if + brace_on_left = bool(Search(r'}\s*else if\s*\(', line)) + # find the ( after the if + pos = line.find('else if') + pos = line.find('(', pos) + if pos > 0: + (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) + brace_on_right = endline[endpos:].find('{') != -1 + if brace_on_left != brace_on_right: # must be brace after if + error(filename, linenum, 'readability/braces', 5, + 'If an else has a brace on one side, it should have it on both') + elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): + error(filename, linenum, 'readability/braces', 5, + 'If an else has a brace on one side, it should have it on both') + + # Likewise, an else should never have the else clause on the same line + if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): + error(filename, linenum, 'whitespace/newline', 4, + 'Else clause should never be on same line as else (use 2 lines)') + + # In the same way, a do/while should never be on one line + if Match(r'\s*do [^\s{]', line): + error(filename, linenum, 'whitespace/newline', 4, + 'do/while clauses should not be on a single line') + + # Check single-line if/else bodies. The style guide says 'curly braces are not + # required for single-line statements'. We additionally allow multi-line, + # single statements, but we reject anything with more than one semicolon in + # it. This means that the first semicolon after the if should be at the end of + # its line, and the line after that should have an indent level equal to or + # lower than the if. We also check for ambiguous if/else nesting without + # braces. + if_else_match = Search(r'\b(if\s*\(|else\b)', line) + if if_else_match and not Match(r'\s*#', line): + if_indent = GetIndentLevel(line) + endline, endlinenum, endpos = line, linenum, if_else_match.end() + if_match = Search(r'\bif\s*\(', line) + if if_match: + # This could be a multiline if condition, so find the end first. + pos = if_match.end() - 1 + (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos) + # Check for an opening brace, either directly after the if or on the next + # line. If found, this isn't a single-statement conditional. + if (not Match(r'\s*{', endline[endpos:]) + and not (Match(r'\s*$', endline[endpos:]) + and endlinenum < (len(clean_lines.elided) - 1) + and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))): + while (endlinenum < len(clean_lines.elided) + and ';' not in clean_lines.elided[endlinenum][endpos:]): + endlinenum += 1 + endpos = 0 + if endlinenum < len(clean_lines.elided): + endline = clean_lines.elided[endlinenum] + # We allow a mix of whitespace and closing braces (e.g. for one-liner + # methods) and a single \ after the semicolon (for macros) + endpos = endline.find(';') + if not Match(r';[\s}]*(\\?)$', endline[endpos:]): + # Semicolon isn't the last character, there's something trailing. + # Output a warning if the semicolon is not contained inside + # a lambda expression. + if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$', + endline): + error(filename, linenum, 'readability/braces', 4, + 'If/else bodies with multiple statements require braces') + elif endlinenum < len(clean_lines.elided) - 1: + # Make sure the next line is dedented + next_line = clean_lines.elided[endlinenum + 1] + next_indent = GetIndentLevel(next_line) + # With ambiguous nested if statements, this will error out on the + # if that *doesn't* match the else, regardless of whether it's the + # inner one or outer one. + if (if_match and Match(r'\s*else\b', next_line) + and next_indent != if_indent): + error(filename, linenum, 'readability/braces', 4, + 'Else clause should be indented at the same level as if. ' + 'Ambiguous nested if/else chains require braces.') + elif next_indent > if_indent: + error(filename, linenum, 'readability/braces', 4, + 'If/else bodies with multiple statements require braces') + + +def CheckTrailingSemicolon(filename, clean_lines, linenum, error): + """Looks for redundant trailing semicolon. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + line = clean_lines.elided[linenum] + + # Block bodies should not be followed by a semicolon. Due to C++11 + # brace initialization, there are more places where semicolons are + # required than not, so we use a whitelist approach to check these + # rather than a blacklist. These are the places where "};" should + # be replaced by just "}": + # 1. Some flavor of block following closing parenthesis: + # for (;;) {}; + # while (...) {}; + # switch (...) {}; + # Function(...) {}; + # if (...) {}; + # if (...) else if (...) {}; + # + # 2. else block: + # if (...) else {}; + # + # 3. const member function: + # Function(...) const {}; + # + # 4. Block following some statement: + # x = 42; + # {}; + # + # 5. Block at the beginning of a function: + # Function(...) { + # {}; + # } + # + # Note that naively checking for the preceding "{" will also match + # braces inside multi-dimensional arrays, but this is fine since + # that expression will not contain semicolons. + # + # 6. Block following another block: + # while (true) {} + # {}; + # + # 7. End of namespaces: + # namespace {}; + # + # These semicolons seems far more common than other kinds of + # redundant semicolons, possibly due to people converting classes + # to namespaces. For now we do not warn for this case. + # + # Try matching case 1 first. + match = Match(r'^(.*\)\s*)\{', line) + if match: + # Matched closing parenthesis (case 1). Check the token before the + # matching opening parenthesis, and don't warn if it looks like a + # macro. This avoids these false positives: + # - macro that defines a base class + # - multi-line macro that defines a base class + # - macro that defines the whole class-head + # + # But we still issue warnings for macros that we know are safe to + # warn, specifically: + # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P + # - TYPED_TEST + # - INTERFACE_DEF + # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: + # + # We implement a whitelist of safe macros instead of a blacklist of + # unsafe macros, even though the latter appears less frequently in + # google code and would have been easier to implement. This is because + # the downside for getting the whitelist wrong means some extra + # semicolons, while the downside for getting the blacklist wrong + # would result in compile errors. + # + # In addition to macros, we also don't want to warn on + # - Compound literals + # - Lambdas + # - alignas specifier with anonymous structs + # - decltype + closing_brace_pos = match.group(1).rfind(')') + opening_parenthesis = ReverseCloseExpression( + clean_lines, linenum, closing_brace_pos) + if opening_parenthesis[2] > -1: + line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] + macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix) + func = Match(r'^(.*\])\s*$', line_prefix) + if ((macro and + macro.group(1) not in ( + 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', + 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', + 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or + (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or + Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or + Search(r'\bdecltype$', line_prefix) or + Search(r'\s+=\s*$', line_prefix)): + match = None + if (match and + opening_parenthesis[1] > 1 and + Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])): + # Multi-line lambda-expression + match = None + + else: + # Try matching cases 2-3. + match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line) + if not match: + # Try matching cases 4-6. These are always matched on separate lines. + # + # Note that we can't simply concatenate the previous line to the + # current line and do a single match, otherwise we may output + # duplicate warnings for the blank line case: + # if (cond) { + # // blank line + # } + prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] + if prevline and Search(r'[;{}]\s*$', prevline): + match = Match(r'^(\s*)\{', line) + + # Check matching closing brace + if match: + (endline, endlinenum, endpos) = CloseExpression( + clean_lines, linenum, len(match.group(1))) + if endpos > -1 and Match(r'^\s*;', endline[endpos:]): + # Current {} pair is eligible for semicolon check, and we have found + # the redundant semicolon, output warning here. + # + # Note: because we are scanning forward for opening braces, and + # outputting warnings for the matching closing brace, if there are + # nested blocks with trailing semicolons, we will get the error + # messages in reversed order. + + # We need to check the line forward for NOLINT + raw_lines = clean_lines.raw_lines + ParseNolintSuppressions(filename, raw_lines[endlinenum-1], endlinenum-1, + error) + ParseNolintSuppressions(filename, raw_lines[endlinenum], endlinenum, + error) + + error(filename, endlinenum, 'readability/braces', 4, + "You don't need a ; after a }") + + +def CheckEmptyBlockBody(filename, clean_lines, linenum, error): + """Look for empty loop/conditional body with only a single semicolon. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + # Search for loop keywords at the beginning of the line. Because only + # whitespaces are allowed before the keywords, this will also ignore most + # do-while-loops, since those lines should start with closing brace. + # + # We also check "if" blocks here, since an empty conditional block + # is likely an error. + line = clean_lines.elided[linenum] + matched = Match(r'\s*(for|while|if)\s*\(', line) + if matched: + # Find the end of the conditional expression. + (end_line, end_linenum, end_pos) = CloseExpression( + clean_lines, linenum, line.find('(')) + + # Output warning if what follows the condition expression is a semicolon. + # No warning for all other cases, including whitespace or newline, since we + # have a separate check for semicolons preceded by whitespace. + if end_pos >= 0 and Match(r';', end_line[end_pos:]): + if matched.group(1) == 'if': + error(filename, end_linenum, 'whitespace/empty_conditional_body', 5, + 'Empty conditional bodies should use {}') + else: + error(filename, end_linenum, 'whitespace/empty_loop_body', 5, + 'Empty loop bodies should use {} or continue') + + # Check for if statements that have completely empty bodies (no comments) + # and no else clauses. + if end_pos >= 0 and matched.group(1) == 'if': + # Find the position of the opening { for the if statement. + # Return without logging an error if it has no brackets. + opening_linenum = end_linenum + opening_line_fragment = end_line[end_pos:] + # Loop until EOF or find anything that's not whitespace or opening {. + while not Search(r'^\s*\{', opening_line_fragment): + if Search(r'^(?!\s*$)', opening_line_fragment): + # Conditional has no brackets. + return + opening_linenum += 1 + if opening_linenum == len(clean_lines.elided): + # Couldn't find conditional's opening { or any code before EOF. + return + opening_line_fragment = clean_lines.elided[opening_linenum] + # Set opening_line (opening_line_fragment may not be entire opening line). + opening_line = clean_lines.elided[opening_linenum] + + # Find the position of the closing }. + opening_pos = opening_line_fragment.find('{') + if opening_linenum == end_linenum: + # We need to make opening_pos relative to the start of the entire line. + opening_pos += end_pos + (closing_line, closing_linenum, closing_pos) = CloseExpression( + clean_lines, opening_linenum, opening_pos) + if closing_pos < 0: + return + + # Now construct the body of the conditional. This consists of the portion + # of the opening line after the {, all lines until the closing line, + # and the portion of the closing line before the }. + if (clean_lines.raw_lines[opening_linenum] != + CleanseComments(clean_lines.raw_lines[opening_linenum])): + # Opening line ends with a comment, so conditional isn't empty. + return + if closing_linenum > opening_linenum: + # Opening line after the {. Ignore comments here since we checked above. + body = list(opening_line[opening_pos+1:]) + # All lines until closing line, excluding closing line, with comments. + body.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum]) + # Closing line before the }. Won't (and can't) have comments. + body.append(clean_lines.elided[closing_linenum][:closing_pos-1]) + body = '\n'.join(body) + else: + # If statement has brackets and fits on a single line. + body = opening_line[opening_pos+1:closing_pos-1] + + # Check if the body is empty + if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body): + return + # The body is empty. Now make sure there's not an else clause. + current_linenum = closing_linenum + current_line_fragment = closing_line[closing_pos:] + # Loop until EOF or find anything that's not whitespace or else clause. + while Search(r'^\s*$|^(?=\s*else)', current_line_fragment): + if Search(r'^(?=\s*else)', current_line_fragment): + # Found an else clause, so don't log an error. + return + current_linenum += 1 + if current_linenum == len(clean_lines.elided): + break + current_line_fragment = clean_lines.elided[current_linenum] + + # The body is empty and there's no else clause until EOF or other code. + error(filename, end_linenum, 'whitespace/empty_if_body', 4, + ('If statement had no body and no else clause')) + + +def FindCheckMacro(line): + """Find a replaceable CHECK-like macro. + + Args: + line: line to search on. + Returns: + (macro name, start position), or (None, -1) if no replaceable + macro is found. + """ + for macro in _CHECK_MACROS: + i = line.find(macro) + if i >= 0: + # Find opening parenthesis. Do a regular expression match here + # to make sure that we are matching the expected CHECK macro, as + # opposed to some other macro that happens to contain the CHECK + # substring. + matched = Match(r'^(.*\b' + macro + r'\s*)\(', line) + if not matched: + continue + return (macro, len(matched.group(1))) + return (None, -1) + + +def CheckCheck(filename, clean_lines, linenum, error): + """Checks the use of CHECK and EXPECT macros. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + + # Decide the set of replacement macros that should be suggested + lines = clean_lines.elided + (check_macro, start_pos) = FindCheckMacro(lines[linenum]) + if not check_macro: + return + + # Find end of the boolean expression by matching parentheses + (last_line, end_line, end_pos) = CloseExpression( + clean_lines, linenum, start_pos) + if end_pos < 0: + return + + # If the check macro is followed by something other than a + # semicolon, assume users will log their own custom error messages + # and don't suggest any replacements. + if not Match(r'\s*;', last_line[end_pos:]): + return + + if linenum == end_line: + expression = lines[linenum][start_pos + 1:end_pos - 1] + else: + expression = lines[linenum][start_pos + 1:] + for i in xrange(linenum + 1, end_line): + expression += lines[i] + expression += last_line[0:end_pos - 1] + + # Parse expression so that we can take parentheses into account. + # This avoids false positives for inputs like "CHECK((a < 4) == b)", + # which is not replaceable by CHECK_LE. + lhs = '' + rhs = '' + operator = None + while expression: + matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' + r'==|!=|>=|>|<=|<|\()(.*)$', expression) + if matched: + token = matched.group(1) + if token == '(': + # Parenthesized operand + expression = matched.group(2) + (end, _) = FindEndOfExpressionInLine(expression, 0, ['(']) + if end < 0: + return # Unmatched parenthesis + lhs += '(' + expression[0:end] + expression = expression[end:] + elif token in ('&&', '||'): + # Logical and/or operators. This means the expression + # contains more than one term, for example: + # CHECK(42 < a && a < b); + # + # These are not replaceable with CHECK_LE, so bail out early. + return + elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): + # Non-relational operator + lhs += token + expression = matched.group(2) + else: + # Relational operator + operator = token + rhs = matched.group(2) + break + else: + # Unparenthesized operand. Instead of appending to lhs one character + # at a time, we do another regular expression match to consume several + # characters at once if possible. Trivial benchmark shows that this + # is more efficient when the operands are longer than a single + # character, which is generally the case. + matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) + if not matched: + matched = Match(r'^(\s*\S)(.*)$', expression) + if not matched: + break + lhs += matched.group(1) + expression = matched.group(2) + + # Only apply checks if we got all parts of the boolean expression + if not (lhs and operator and rhs): + return + + # Check that rhs do not contain logical operators. We already know + # that lhs is fine since the loop above parses out && and ||. + if rhs.find('&&') > -1 or rhs.find('||') > -1: + return + + # At least one of the operands must be a constant literal. This is + # to avoid suggesting replacements for unprintable things like + # CHECK(variable != iterator) + # + # The following pattern matches decimal, hex integers, strings, and + # characters (in that order). + lhs = lhs.strip() + rhs = rhs.strip() + match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' + if Match(match_constant, lhs) or Match(match_constant, rhs): + # Note: since we know both lhs and rhs, we can provide a more + # descriptive error message like: + # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) + # Instead of: + # Consider using CHECK_EQ instead of CHECK(a == b) + # + # We are still keeping the less descriptive message because if lhs + # or rhs gets long, the error message might become unreadable. + error(filename, linenum, 'readability/check', 2, + 'Consider using %s instead of %s(a %s b)' % ( + _CHECK_REPLACEMENT[check_macro][operator], + check_macro, operator)) + + +def CheckAltTokens(filename, clean_lines, linenum, error): + """Check alternative keywords being used in boolean expressions. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Avoid preprocessor lines + if Match(r'^\s*#', line): + return + + # Last ditch effort to avoid multi-line comments. This will not help + # if the comment started before the current line or ended after the + # current line, but it catches most of the false positives. At least, + # it provides a way to workaround this warning for people who use + # multi-line comments in preprocessor macros. + # + # TODO(unknown): remove this once cpplint has better support for + # multi-line comments. + if line.find('/*') >= 0 or line.find('*/') >= 0: + return + + for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): + error(filename, linenum, 'readability/alt_tokens', 2, + 'Use operator %s instead of %s' % ( + _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) + + +def GetLineWidth(line): + """Determines the width of the line in column positions. + + Args: + line: A string, which may be a Unicode string. + + Returns: + The width of the line in column positions, accounting for Unicode + combining characters and wide characters. + """ + if isinstance(line, unicode): + width = 0 + for uc in unicodedata.normalize('NFC', line): + if unicodedata.east_asian_width(uc) in ('W', 'F'): + width += 2 + elif not unicodedata.combining(uc): + width += 1 + return width + else: + return len(line) + + +def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, + error): + """Checks rules from the 'C++ style rules' section of cppguide.html. + + Most of these rules are hard to test (naming, comment style), but we + do what we can. In particular we check for 2-space indents, line lengths, + tab usage, spaces inside code, etc. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + file_extension: The extension (without the dot) of the filename. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + + # Don't use "elided" lines here, otherwise we can't check commented lines. + # Don't want to use "raw" either, because we don't want to check inside C++11 + # raw strings, + raw_lines = clean_lines.lines_without_raw_strings + line = raw_lines[linenum] + prev = raw_lines[linenum - 1] if linenum > 0 else '' + + if line.find('\t') != -1: + error(filename, linenum, 'whitespace/tab', 1, + 'Tab found; better to use spaces') + + # One or three blank spaces at the beginning of the line is weird; it's + # hard to reconcile that with 2-space indents. + # NOTE: here are the conditions rob pike used for his tests. Mine aren't + # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces + # if(RLENGTH > 20) complain = 0; + # if(match($0, " +(error|private|public|protected):")) complain = 0; + # if(match(prev, "&& *$")) complain = 0; + # if(match(prev, "\\|\\| *$")) complain = 0; + # if(match(prev, "[\",=><] *$")) complain = 0; + # if(match($0, " <<")) complain = 0; + # if(match(prev, " +for \\(")) complain = 0; + # if(prevodd && match(prevprev, " +for \\(")) complain = 0; + scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$' + classinfo = nesting_state.InnermostClass() + initial_spaces = 0 + cleansed_line = clean_lines.elided[linenum] + while initial_spaces < len(line) and line[initial_spaces] == ' ': + initial_spaces += 1 + # There are certain situations we allow one space, notably for + # section labels, and also lines containing multi-line raw strings. + # We also don't check for lines that look like continuation lines + # (of lines ending in double quotes, commas, equals, or angle brackets) + # because the rules for how to indent those are non-trivial. + if (not Search(r'[",=><] *$', prev) and + (initial_spaces == 1 or initial_spaces == 3) and + not Match(scope_or_label_pattern, cleansed_line) and + not (clean_lines.raw_lines[linenum] != line and + Match(r'^\s*""', line))): + error(filename, linenum, 'whitespace/indent', 3, + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent?') + + if line and line[-1].isspace(): + error(filename, linenum, 'whitespace/end_of_line', 4, + 'Line ends in whitespace. Consider deleting these extra spaces.') + + # Check if the line is a header guard. + is_header_guard = False + if IsHeaderExtension(file_extension): + cppvar = GetHeaderGuardCPPVariable(filename) + if (line.startswith('#ifndef %s' % cppvar) or + line.startswith('#define %s' % cppvar) or + line.startswith('#endif // %s' % cppvar)): + is_header_guard = True + # #include lines and header guards can be long, since there's no clean way to + # split them. + # + # URLs can be long too. It's possible to split these, but it makes them + # harder to cut&paste. + # + # The "$Id:...$" comment may also get very long without it being the + # developers fault. + if (not line.startswith('#include') and not is_header_guard and + not Match(r'^\s*//.*http(s?)://\S*$', line) and + not Match(r'^\s*//\s*[^\s]*$', line) and + not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): + line_width = GetLineWidth(line) + if line_width > _line_length: + error(filename, linenum, 'whitespace/line_length', 2, + 'Lines should be <= %i characters long' % _line_length) + + if (cleansed_line.count(';') > 1 and + # for loops are allowed two ;'s (and may run over two lines). + cleansed_line.find('for') == -1 and + (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or + GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and + # It's ok to have many commands in a switch case that fits in 1 line + not ((cleansed_line.find('case ') != -1 or + cleansed_line.find('default:') != -1) and + cleansed_line.find('break;') != -1)): + error(filename, linenum, 'whitespace/newline', 0, + 'More than one command on the same line') + + # Some more style checks + CheckBraces(filename, clean_lines, linenum, error) + CheckTrailingSemicolon(filename, clean_lines, linenum, error) + CheckEmptyBlockBody(filename, clean_lines, linenum, error) + CheckSpacing(filename, clean_lines, linenum, nesting_state, error) + CheckOperatorSpacing(filename, clean_lines, linenum, error) + CheckParenthesisSpacing(filename, clean_lines, linenum, error) + CheckCommaSpacing(filename, clean_lines, linenum, error) + CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error) + CheckSpacingForFunctionCall(filename, clean_lines, linenum, error) + CheckCheck(filename, clean_lines, linenum, error) + CheckAltTokens(filename, clean_lines, linenum, error) + classinfo = nesting_state.InnermostClass() + if classinfo: + CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error) + + +_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') +# Matches the first component of a filename delimited by -s and _s. That is: +# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' +# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' +_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') + + +def _DropCommonSuffixes(filename): + """Drops common suffixes like _test.cc or -inl.h from filename. + + For example: + >>> _DropCommonSuffixes('foo/foo-inl.h') + 'foo/foo' + >>> _DropCommonSuffixes('foo/bar/foo.cc') + 'foo/bar/foo' + >>> _DropCommonSuffixes('foo/foo_internal.h') + 'foo/foo' + >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') + 'foo/foo_unusualinternal' + + Args: + filename: The input filename. + + Returns: + The filename with the common suffix removed. + """ + for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', + 'inl.h', 'impl.h', 'internal.h'): + if (filename.endswith(suffix) and len(filename) > len(suffix) and + filename[-len(suffix) - 1] in ('-', '_')): + return filename[:-len(suffix) - 1] + return os.path.splitext(filename)[0] + + +def _ClassifyInclude(fileinfo, include, is_system): + """Figures out what kind of header 'include' is. + + Args: + fileinfo: The current file cpplint is running over. A FileInfo instance. + include: The path to a #included file. + is_system: True if the #include used <> rather than "". + + Returns: + One of the _XXX_HEADER constants. + + For example: + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) + _C_SYS_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) + _CPP_SYS_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) + _LIKELY_MY_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), + ... 'bar/foo_other_ext.h', False) + _POSSIBLE_MY_HEADER + >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) + _OTHER_HEADER + """ + # This is a list of all standard c++ header files, except + # those already checked for above. + is_cpp_h = include in _CPP_HEADERS + + if is_system: + if is_cpp_h: + return _CPP_SYS_HEADER + else: + return _C_SYS_HEADER + + # If the target file and the include we're checking share a + # basename when we drop common extensions, and the include + # lives in . , then it's likely to be owned by the target file. + target_dir, target_base = ( + os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) + include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) + if target_base == include_base and ( + include_dir == target_dir or + include_dir == os.path.normpath(target_dir + '/../public')): + return _LIKELY_MY_HEADER + + # If the target and include share some initial basename + # component, it's possible the target is implementing the + # include, so it's allowed to be first, but we'll never + # complain if it's not there. + target_first_component = _RE_FIRST_COMPONENT.match(target_base) + include_first_component = _RE_FIRST_COMPONENT.match(include_base) + if (target_first_component and include_first_component and + target_first_component.group(0) == + include_first_component.group(0)): + return _POSSIBLE_MY_HEADER + + return _OTHER_HEADER + + + +def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): + """Check rules that are applicable to #include lines. + + Strings on #include lines are NOT removed from elided line, to make + certain tasks easier. However, to prevent false positives, checks + applicable to #include lines in CheckLanguage must be put here. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + include_state: An _IncludeState instance in which the headers are inserted. + error: The function to call with any errors found. + """ + fileinfo = FileInfo(filename) + line = clean_lines.lines[linenum] + + # "include" should use the new style "foo/bar.h" instead of just "bar.h" + # Only do this check if the included header follows google naming + # conventions. If not, assume that it's a 3rd party API that + # requires special include conventions. + # + # We also make an exception for Lua headers, which follow google + # naming convention but not the include convention. + match = Match(r'#include\s*"([^/]+\.h)"', line) + if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)): + error(filename, linenum, 'build/include', 4, + 'Include the directory when naming .h files') + + # we shouldn't include a file more than once. actually, there are a + # handful of instances where doing so is okay, but in general it's + # not. + match = _RE_PATTERN_INCLUDE.search(line) + if match: + include = match.group(2) + is_system = (match.group(1) == '<') + duplicate_line = include_state.FindHeader(include) + if duplicate_line >= 0: + error(filename, linenum, 'build/include', 4, + '"%s" already included at %s:%s' % + (include, filename, duplicate_line)) + elif (include.endswith('.cc') and + os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)): + error(filename, linenum, 'build/include', 4, + 'Do not include .cc files from other packages') + elif not _THIRD_PARTY_HEADERS_PATTERN.match(include): + include_state.include_list[-1].append((include, linenum)) + + # We want to ensure that headers appear in the right order: + # 1) for foo.cc, foo.h (preferred location) + # 2) c system files + # 3) cpp system files + # 4) for foo.cc, foo.h (deprecated location) + # 5) other google headers + # + # We classify each include statement as one of those 5 types + # using a number of techniques. The include_state object keeps + # track of the highest type seen, and complains if we see a + # lower type after that. + error_message = include_state.CheckNextIncludeOrder( + _ClassifyInclude(fileinfo, include, is_system)) + if error_message: + error(filename, linenum, 'build/include_order', 4, + '%s. Should be: %s.h, c system, c++ system, other.' % + (error_message, fileinfo.BaseName())) + canonical_include = include_state.CanonicalizeAlphabeticalOrder(include) + if not include_state.IsInAlphabeticalOrder( + clean_lines, linenum, canonical_include): + error(filename, linenum, 'build/include_alpha', 4, + 'Include "%s" not in alphabetical order' % include) + include_state.SetLastHeader(canonical_include) + + + +def _GetTextInside(text, start_pattern): + r"""Retrieves all the text between matching open and close parentheses. + + Given a string of lines and a regular expression string, retrieve all the text + following the expression and between opening punctuation symbols like + (, [, or {, and the matching close-punctuation symbol. This properly nested + occurrences of the punctuations, so for the text like + printf(a(), b(c())); + a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. + start_pattern must match string having an open punctuation symbol at the end. + + Args: + text: The lines to extract text. Its comments and strings must be elided. + It can be single line and can span multiple lines. + start_pattern: The regexp string indicating where to start extracting + the text. + Returns: + The extracted text. + None if either the opening string or ending punctuation could not be found. + """ + # TODO(unknown): Audit cpplint.py to see what places could be profitably + # rewritten to use _GetTextInside (and use inferior regexp matching today). + + # Give opening punctuations to get the matching close-punctuations. + matching_punctuation = {'(': ')', '{': '}', '[': ']'} + closing_punctuation = set(matching_punctuation.itervalues()) + + # Find the position to start extracting text. + match = re.search(start_pattern, text, re.M) + if not match: # start_pattern not found in text. + return None + start_position = match.end(0) + + assert start_position > 0, ( + 'start_pattern must ends with an opening punctuation.') + assert text[start_position - 1] in matching_punctuation, ( + 'start_pattern must ends with an opening punctuation.') + # Stack of closing punctuations we expect to have in text after position. + punctuation_stack = [matching_punctuation[text[start_position - 1]]] + position = start_position + while punctuation_stack and position < len(text): + if text[position] == punctuation_stack[-1]: + punctuation_stack.pop() + elif text[position] in closing_punctuation: + # A closing punctuation without matching opening punctuations. + return None + elif text[position] in matching_punctuation: + punctuation_stack.append(matching_punctuation[text[position]]) + position += 1 + if punctuation_stack: + # Opening punctuations left without matching close-punctuations. + return None + # punctuations match. + return text[start_position:position - 1] + + +# Patterns for matching call-by-reference parameters. +# +# Supports nested templates up to 2 levels deep using this messy pattern: +# < (?: < (?: < [^<>]* +# > +# | [^<>] )* +# > +# | [^<>] )* +# > +_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]* +_RE_PATTERN_TYPE = ( + r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?' + r'(?:\w|' + r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|' + r'::)+') +# A call-by-reference parameter ends with '& identifier'. +_RE_PATTERN_REF_PARAM = re.compile( + r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*' + r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]') +# A call-by-const-reference parameter either ends with 'const& identifier' +# or looks like 'const type& identifier' when 'type' is atomic. +_RE_PATTERN_CONST_REF_PARAM = ( + r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + + r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')') +# Stream types. +_RE_PATTERN_REF_STREAM_PARAM = ( + r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')') + + +def CheckLanguage(filename, clean_lines, linenum, file_extension, + include_state, nesting_state, error): + """Checks rules from the 'C++ language rules' section of cppguide.html. + + Some of these rules are hard to test (function overloading, using + uint32 inappropriately), but we do the best we can. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + file_extension: The extension (without the dot) of the filename. + include_state: An _IncludeState instance in which the headers are inserted. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + # If the line is empty or consists of entirely a comment, no need to + # check it. + line = clean_lines.elided[linenum] + if not line: + return + + match = _RE_PATTERN_INCLUDE.search(line) + if match: + CheckIncludeLine(filename, clean_lines, linenum, include_state, error) + return + + # Reset include state across preprocessor directives. This is meant + # to silence warnings for conditional includes. + match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line) + if match: + include_state.ResetSection(match.group(1)) + + # Make Windows paths like Unix. + fullname = os.path.abspath(filename).replace('\\', '/') + + # Perform other checks now that we are sure that this is not an include line + CheckCasts(filename, clean_lines, linenum, error) + CheckGlobalStatic(filename, clean_lines, linenum, error) + CheckPrintf(filename, clean_lines, linenum, error) + + if IsHeaderExtension(file_extension): + # TODO(unknown): check that 1-arg constructors are explicit. + # How to tell it's a constructor? + # (handled in CheckForNonStandardConstructs for now) + # TODO(unknown): check that classes declare or disable copy/assign + # (level 1 error) + pass + + # Check if people are using the verboten C basic types. The only exception + # we regularly allow is "unsigned short port" for port. + if Search(r'\bshort port\b', line): + if not Search(r'\bunsigned short port\b', line): + error(filename, linenum, 'runtime/int', 4, + 'Use "unsigned short" for ports, not "short"') + else: + match = Search(r'\b(short|long(?! +double)|long long)\b', line) + if match: + error(filename, linenum, 'runtime/int', 4, + 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) + + # Check if some verboten operator overloading is going on + # TODO(unknown): catch out-of-line unary operator&: + # class X {}; + # int operator&(const X& x) { return 42; } // unary operator& + # The trick is it's hard to tell apart from binary operator&: + # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& + if Search(r'\boperator\s*&\s*\(\s*\)', line): + error(filename, linenum, 'runtime/operator', 4, + 'Unary operator& is dangerous. Do not use it.') + + # Check for suspicious usage of "if" like + # } if (a == b) { + if Search(r'\}\s*if\s*\(', line): + error(filename, linenum, 'readability/braces', 4, + 'Did you mean "else if"? If not, start a new line for "if".') + + # Check for potential format string bugs like printf(foo). + # We constrain the pattern not to pick things like DocidForPrintf(foo). + # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) + # TODO(unknown): Catch the following case. Need to change the calling + # convention of the whole function to process multiple line to handle it. + # printf( + # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); + printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') + if printf_args: + match = Match(r'([\w.\->()]+)$', printf_args) + if match and match.group(1) != '__VA_ARGS__': + function_name = re.search(r'\b((?:string)?printf)\s*\(', + line, re.I).group(1) + error(filename, linenum, 'runtime/printf', 4, + 'Potential format string bug. Do %s("%%s", %s) instead.' + % (function_name, match.group(1))) + + # Check for potential memset bugs like memset(buf, sizeof(buf), 0). + match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) + if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): + error(filename, linenum, 'runtime/memset', 4, + 'Did you mean "memset(%s, 0, %s)"?' + % (match.group(1), match.group(2))) + + if Search(r'\busing namespace\b', line): + error(filename, linenum, 'build/namespaces', 5, + 'Do not use namespace using-directives. ' + 'Use using-declarations instead.') + + # Detect variable-length arrays. + match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) + if (match and match.group(2) != 'return' and match.group(2) != 'delete' and + match.group(3).find(']') == -1): + # Split the size using space and arithmetic operators as delimiters. + # If any of the resulting tokens are not compile time constants then + # report the error. + tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) + is_const = True + skip_next = False + for tok in tokens: + if skip_next: + skip_next = False + continue + + if Search(r'sizeof\(.+\)', tok): continue + if Search(r'arraysize\(\w+\)', tok): continue + + tok = tok.lstrip('(') + tok = tok.rstrip(')') + if not tok: continue + if Match(r'\d+', tok): continue + if Match(r'0[xX][0-9a-fA-F]+', tok): continue + if Match(r'k[A-Z0-9]\w*', tok): continue + if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue + if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue + # A catch all for tricky sizeof cases, including 'sizeof expression', + # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' + # requires skipping the next token because we split on ' ' and '*'. + if tok.startswith('sizeof'): + skip_next = True + continue + is_const = False + break + if not is_const: + error(filename, linenum, 'runtime/arrays', 1, + 'Do not use variable-length arrays. Use an appropriately named ' + "('k' followed by CamelCase) compile-time constant for the size.") + + # Check for use of unnamed namespaces in header files. Registration + # macros are typically OK, so we allow use of "namespace {" on lines + # that end with backslashes. + if (IsHeaderExtension(file_extension) + and Search(r'\bnamespace\s*{', line) + and line[-1] != '\\'): + error(filename, linenum, 'build/namespaces', 4, + 'Do not use unnamed namespaces in header files. See ' + 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' + ' for more information.') + + +def CheckGlobalStatic(filename, clean_lines, linenum, error): + """Check for unsafe global or static objects. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Match two lines at a time to support multiline declarations + if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line): + line += clean_lines.elided[linenum + 1].strip() + + # Check for people declaring static/global STL strings at the top level. + # This is dangerous because the C++ language does not guarantee that + # globals with constructors are initialized before the first access, and + # also because globals can be destroyed when some threads are still running. + # TODO(unknown): Generalize this to also find static unique_ptr instances. + # TODO(unknown): File bugs for clang-tidy to find these. + match = Match( + r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +' + r'([a-zA-Z0-9_:]+)\b(.*)', + line) + + # Remove false positives: + # - String pointers (as opposed to values). + # string *pointer + # const string *pointer + # string const *pointer + # string *const pointer + # + # - Functions and template specializations. + # string Function(... + # string Class::Method(... + # + # - Operators. These are matched separately because operator names + # cross non-word boundaries, and trying to match both operators + # and functions at the same time would decrease accuracy of + # matching identifiers. + # string Class::operator*() + if (match and + not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and + not Search(r'\boperator\W', line) and + not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))): + if Search(r'\bconst\b', line): + error(filename, linenum, 'runtime/string', 4, + 'For a static/global string constant, use a C style string ' + 'instead: "%schar%s %s[]".' % + (match.group(1), match.group(2) or '', match.group(3))) + else: + error(filename, linenum, 'runtime/string', 4, + 'Static/global string variables are not permitted.') + + if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or + Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)): + error(filename, linenum, 'runtime/init', 4, + 'You seem to be initializing a member variable with itself.') + + +def CheckPrintf(filename, clean_lines, linenum, error): + """Check for printf related issues. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # When snprintf is used, the second argument shouldn't be a literal. + match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) + if match and match.group(2) != '0': + # If 2nd arg is zero, snprintf is used to calculate size. + error(filename, linenum, 'runtime/printf', 3, + 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' + 'to snprintf.' % (match.group(1), match.group(2))) + + # Check if some verboten C functions are being used. + if Search(r'\bsprintf\s*\(', line): + error(filename, linenum, 'runtime/printf', 5, + 'Never use sprintf. Use snprintf instead.') + match = Search(r'\b(strcpy|strcat)\s*\(', line) + if match: + error(filename, linenum, 'runtime/printf', 4, + 'Almost always, snprintf is better than %s' % match.group(1)) + + +def IsDerivedFunction(clean_lines, linenum): + """Check if current line contains an inherited function. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + Returns: + True if current line contains a function with "override" + virt-specifier. + """ + # Scan back a few lines for start of current function + for i in xrange(linenum, max(-1, linenum - 10), -1): + match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i]) + if match: + # Look for "override" after the matching closing parenthesis + line, _, closing_paren = CloseExpression( + clean_lines, i, len(match.group(1))) + return (closing_paren >= 0 and + Search(r'\boverride\b', line[closing_paren:])) + return False + + +def IsOutOfLineMethodDefinition(clean_lines, linenum): + """Check if current line contains an out-of-line method definition. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + Returns: + True if current line contains an out-of-line method definition. + """ + # Scan back a few lines for start of current function + for i in xrange(linenum, max(-1, linenum - 10), -1): + if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]): + return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None + return False + + +def IsInitializerList(clean_lines, linenum): + """Check if current line is inside constructor initializer list. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + Returns: + True if current line appears to be inside constructor initializer + list, False otherwise. + """ + for i in xrange(linenum, 1, -1): + line = clean_lines.elided[i] + if i == linenum: + remove_function_body = Match(r'^(.*)\{\s*$', line) + if remove_function_body: + line = remove_function_body.group(1) + + if Search(r'\s:\s*\w+[({]', line): + # A lone colon tend to indicate the start of a constructor + # initializer list. It could also be a ternary operator, which + # also tend to appear in constructor initializer lists as + # opposed to parameter lists. + return True + if Search(r'\}\s*,\s*$', line): + # A closing brace followed by a comma is probably the end of a + # brace-initialized member in constructor initializer list. + return True + if Search(r'[{};]\s*$', line): + # Found one of the following: + # - A closing brace or semicolon, probably the end of the previous + # function. + # - An opening brace, probably the start of current class or namespace. + # + # Current line is probably not inside an initializer list since + # we saw one of those things without seeing the starting colon. + return False + + # Got to the beginning of the file without seeing the start of + # constructor initializer list. + return False + + +def CheckForNonConstReference(filename, clean_lines, linenum, + nesting_state, error): + """Check for non-const references. + + Separate from CheckLanguage since it scans backwards from current + line, instead of scanning forward. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: The function to call with any errors found. + """ + # Do nothing if there is no '&' on current line. + line = clean_lines.elided[linenum] + if '&' not in line: + return + + # If a function is inherited, current function doesn't have much of + # a choice, so any non-const references should not be blamed on + # derived function. + if IsDerivedFunction(clean_lines, linenum): + return + + # Don't warn on out-of-line method definitions, as we would warn on the + # in-line declaration, if it isn't marked with 'override'. + if IsOutOfLineMethodDefinition(clean_lines, linenum): + return + + # Long type names may be broken across multiple lines, usually in one + # of these forms: + # LongType + # ::LongTypeContinued &identifier + # LongType:: + # LongTypeContinued &identifier + # LongType< + # ...>::LongTypeContinued &identifier + # + # If we detected a type split across two lines, join the previous + # line to current line so that we can match const references + # accordingly. + # + # Note that this only scans back one line, since scanning back + # arbitrary number of lines would be expensive. If you have a type + # that spans more than 2 lines, please use a typedef. + if linenum > 1: + previous = None + if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): + # previous_line\n + ::current_line + previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', + clean_lines.elided[linenum - 1]) + elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): + # previous_line::\n + current_line + previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', + clean_lines.elided[linenum - 1]) + if previous: + line = previous.group(1) + line.lstrip() + else: + # Check for templated parameter that is split across multiple lines + endpos = line.rfind('>') + if endpos > -1: + (_, startline, startpos) = ReverseCloseExpression( + clean_lines, linenum, endpos) + if startpos > -1 and startline < linenum: + # Found the matching < on an earlier line, collect all + # pieces up to current line. + line = '' + for i in xrange(startline, linenum + 1): + line += clean_lines.elided[i].strip() + + # Check for non-const references in function parameters. A single '&' may + # found in the following places: + # inside expression: binary & for bitwise AND + # inside expression: unary & for taking the address of something + # inside declarators: reference parameter + # We will exclude the first two cases by checking that we are not inside a + # function body, including one that was just introduced by a trailing '{'. + # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. + if (nesting_state.previous_stack_top and + not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or + isinstance(nesting_state.previous_stack_top, _NamespaceInfo))): + # Not at toplevel, not within a class, and not within a namespace + return + + # Avoid initializer lists. We only need to scan back from the + # current line for something that starts with ':'. + # + # We don't need to check the current line, since the '&' would + # appear inside the second set of parentheses on the current line as + # opposed to the first set. + if linenum > 0: + for i in xrange(linenum - 1, max(0, linenum - 10), -1): + previous_line = clean_lines.elided[i] + if not Search(r'[),]\s*$', previous_line): + break + if Match(r'^\s*:\s+\S', previous_line): + return + + # Avoid preprocessors + if Search(r'\\\s*$', line): + return + + # Avoid constructor initializer lists + if IsInitializerList(clean_lines, linenum): + return + + # We allow non-const references in a few standard places, like functions + # called "swap()" or iostream operators like "<<" or ">>". Do not check + # those function parameters. + # + # We also accept & in static_assert, which looks like a function but + # it's actually a declaration expression. + whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|' + r'operator\s*[<>][<>]|' + r'static_assert|COMPILE_ASSERT' + r')\s*\(') + if Search(whitelisted_functions, line): + return + elif not Search(r'\S+\([^)]*$', line): + # Don't see a whitelisted function on this line. Actually we + # didn't see any function name on this line, so this is likely a + # multi-line parameter list. Try a bit harder to catch this case. + for i in xrange(2): + if (linenum > i and + Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])): + return + + decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body + for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): + if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and + not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)): + error(filename, linenum, 'runtime/references', 2, + 'Is this a non-const reference? ' + 'If so, make const or use a pointer: ' + + ReplaceAll(' *<', '<', parameter)) + + +def CheckCasts(filename, clean_lines, linenum, error): + """Various cast related checks. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + # Check to see if they're using an conversion function cast. + # I just try to capture the most common basic types, though there are more. + # Parameterless conversion functions, such as bool(), are allowed as they are + # probably a member operator declaration or default constructor. + match = Search( + r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b' + r'(int|float|double|bool|char|int32|uint32|int64|uint64)' + r'(\([^)].*)', line) + expecting_function = ExpectingFunctionArgs(clean_lines, linenum) + if match and not expecting_function: + matched_type = match.group(2) + + # matched_new_or_template is used to silence two false positives: + # - New operators + # - Template arguments with function types + # + # For template arguments, we match on types immediately following + # an opening bracket without any spaces. This is a fast way to + # silence the common case where the function type is the first + # template argument. False negative with less-than comparison is + # avoided because those operators are usually followed by a space. + # + # function // bracket + no space = false positive + # value < double(42) // bracket + space = true positive + matched_new_or_template = match.group(1) + + # Avoid arrays by looking for brackets that come after the closing + # parenthesis. + if Match(r'\([^()]+\)\s*\[', match.group(3)): + return + + # Other things to ignore: + # - Function pointers + # - Casts to pointer types + # - Placement new + # - Alias declarations + matched_funcptr = match.group(3) + if (matched_new_or_template is None and + not (matched_funcptr and + (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', + matched_funcptr) or + matched_funcptr.startswith('(*)'))) and + not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and + not Search(r'new\(\S+\)\s*' + matched_type, line)): + error(filename, linenum, 'readability/casting', 4, + 'Using deprecated casting style. ' + 'Use static_cast<%s>(...) instead' % + matched_type) + + if not expecting_function: + CheckCStyleCast(filename, clean_lines, linenum, 'static_cast', + r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) + + # This doesn't catch all cases. Consider (const char * const)"hello". + # + # (char *) "foo" should always be a const_cast (reinterpret_cast won't + # compile). + if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast', + r'\((char\s?\*+\s?)\)\s*"', error): + pass + else: + # Check pointer casts for other than string constants + CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast', + r'\((\w+\s?\*+\s?)\)', error) + + # In addition, we look for people taking the address of a cast. This + # is dangerous -- casts can assign to temporaries, so the pointer doesn't + # point where you think. + # + # Some non-identifier character is required before the '&' for the + # expression to be recognized as a cast. These are casts: + # expression = &static_cast(temporary()); + # function(&(int*)(temporary())); + # + # This is not a cast: + # reference_type&(int* function_param); + match = Search( + r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|' + r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line) + if match: + # Try a better error message when the & is bound to something + # dereferenced by the casted pointer, as opposed to the casted + # pointer itself. + parenthesis_error = False + match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line) + if match: + _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1))) + if x1 >= 0 and clean_lines.elided[y1][x1] == '(': + _, y2, x2 = CloseExpression(clean_lines, y1, x1) + if x2 >= 0: + extended_line = clean_lines.elided[y2][x2:] + if y2 < clean_lines.NumLines() - 1: + extended_line += clean_lines.elided[y2 + 1] + if Match(r'\s*(?:->|\[)', extended_line): + parenthesis_error = True + + if parenthesis_error: + error(filename, linenum, 'readability/casting', 4, + ('Are you taking an address of something dereferenced ' + 'from a cast? Wrapping the dereferenced expression in ' + 'parentheses will make the binding more obvious')) + else: + error(filename, linenum, 'runtime/casting', 4, + ('Are you taking an address of a cast? ' + 'This is dangerous: could be a temp var. ' + 'Take the address before doing the cast, rather than after')) + + +def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error): + """Checks for a C-style cast by looking for the pattern. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + cast_type: The string for the C++ cast to recommend. This is either + reinterpret_cast, static_cast, or const_cast, depending. + pattern: The regular expression used to find C-style casts. + error: The function to call with any errors found. + + Returns: + True if an error was emitted. + False otherwise. + """ + line = clean_lines.elided[linenum] + match = Search(pattern, line) + if not match: + return False + + # Exclude lines with keywords that tend to look like casts + context = line[0:match.start(1) - 1] + if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context): + return False + + # Try expanding current context to see if we one level of + # parentheses inside a macro. + if linenum > 0: + for i in xrange(linenum - 1, max(0, linenum - 5), -1): + context = clean_lines.elided[i] + context + if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context): + return False + + # operator++(int) and operator--(int) + if context.endswith(' operator++') or context.endswith(' operator--'): + return False + + # A single unnamed argument for a function tends to look like old style cast. + # If we see those, don't issue warnings for deprecated casts. + remainder = line[match.end(0):] + if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)', + remainder): + return False + + # At this point, all that should be left is actual casts. + error(filename, linenum, 'readability/casting', 4, + 'Using C-style cast. Use %s<%s>(...) instead' % + (cast_type, match.group(1))) + + return True + + +def ExpectingFunctionArgs(clean_lines, linenum): + """Checks whether where function type arguments are expected. + + Args: + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + + Returns: + True if the line at 'linenum' is inside something that expects arguments + of function types. + """ + line = clean_lines.elided[linenum] + return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or + (linenum >= 2 and + (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', + clean_lines.elided[linenum - 1]) or + Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', + clean_lines.elided[linenum - 2]) or + Search(r'\bstd::m?function\s*\<\s*$', + clean_lines.elided[linenum - 1])))) + + +_HEADERS_CONTAINING_TEMPLATES = ( + ('', ('deque',)), + ('', ('unary_function', 'binary_function', + 'plus', 'minus', 'multiplies', 'divides', 'modulus', + 'negate', + 'equal_to', 'not_equal_to', 'greater', 'less', + 'greater_equal', 'less_equal', + 'logical_and', 'logical_or', 'logical_not', + 'unary_negate', 'not1', 'binary_negate', 'not2', + 'bind1st', 'bind2nd', + 'pointer_to_unary_function', + 'pointer_to_binary_function', + 'ptr_fun', + 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', + 'mem_fun_ref_t', + 'const_mem_fun_t', 'const_mem_fun1_t', + 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', + 'mem_fun_ref', + )), + ('', ('numeric_limits',)), + ('', ('list',)), + ('', ('map', 'multimap',)), + ('', ('allocator', 'make_shared', 'make_unique', 'shared_ptr', + 'unique_ptr', 'weak_ptr')), + ('', ('queue', 'priority_queue',)), + ('', ('set', 'multiset',)), + ('', ('stack',)), + ('', ('char_traits', 'basic_string',)), + ('', ('tuple',)), + ('', ('unordered_map', 'unordered_multimap')), + ('', ('unordered_set', 'unordered_multiset')), + ('', ('pair',)), + ('', ('vector',)), + + # gcc extensions. + # Note: std::hash is their hash, ::hash is our hash + ('', ('hash_map', 'hash_multimap',)), + ('', ('hash_set', 'hash_multiset',)), + ('', ('slist',)), + ) + +_HEADERS_MAYBE_TEMPLATES = ( + ('', ('copy', 'max', 'min', 'min_element', 'sort', + 'transform', + )), + ('', ('forward', 'make_pair', 'move', 'swap')), + ) + +_RE_PATTERN_STRING = re.compile(r'\bstring\b') + +_re_pattern_headers_maybe_templates = [] +for _header, _templates in _HEADERS_MAYBE_TEMPLATES: + for _template in _templates: + # Match max(..., ...), max(..., ...), but not foo->max, foo.max or + # type::max(). + _re_pattern_headers_maybe_templates.append( + (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), + _template, + _header)) + +# Other scripts may reach in and modify this pattern. +_re_pattern_templates = [] +for _header, _templates in _HEADERS_CONTAINING_TEMPLATES: + for _template in _templates: + _re_pattern_templates.append( + (re.compile(r'(\<|\b)' + _template + r'\s*\<'), + _template + '<>', + _header)) + + +def FilesBelongToSameModule(filename_cc, filename_h): + """Check if these two filenames belong to the same module. + + The concept of a 'module' here is a as follows: + foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the + same 'module' if they are in the same directory. + some/path/public/xyzzy and some/path/internal/xyzzy are also considered + to belong to the same module here. + + If the filename_cc contains a longer path than the filename_h, for example, + '/absolute/path/to/base/sysinfo.cc', and this file would include + 'base/sysinfo.h', this function also produces the prefix needed to open the + header. This is used by the caller of this function to more robustly open the + header file. We don't have access to the real include paths in this context, + so we need this guesswork here. + + Known bugs: tools/base/bar.cc and base/bar.h belong to the same module + according to this implementation. Because of this, this function gives + some false positives. This should be sufficiently rare in practice. + + Args: + filename_cc: is the path for the .cc file + filename_h: is the path for the header path + + Returns: + Tuple with a bool and a string: + bool: True if filename_cc and filename_h belong to the same module. + string: the additional prefix needed to open the header file. + """ + + fileinfo = FileInfo(filename_cc) + if not fileinfo.IsSource(): + return (False, '') + filename_cc = filename_cc[:-len(fileinfo.Extension())] + matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()) + if matched_test_suffix: + filename_cc = filename_cc[:-len(matched_test_suffix.group(1))] + filename_cc = filename_cc.replace('/public/', '/') + filename_cc = filename_cc.replace('/internal/', '/') + + if not filename_h.endswith('.h'): + return (False, '') + filename_h = filename_h[:-len('.h')] + if filename_h.endswith('-inl'): + filename_h = filename_h[:-len('-inl')] + filename_h = filename_h.replace('/public/', '/') + filename_h = filename_h.replace('/internal/', '/') + + files_belong_to_same_module = filename_cc.endswith(filename_h) + common_path = '' + if files_belong_to_same_module: + common_path = filename_cc[:-len(filename_h)] + return files_belong_to_same_module, common_path + + +def UpdateIncludeState(filename, include_dict, io=codecs): + """Fill up the include_dict with new includes found from the file. + + Args: + filename: the name of the header to read. + include_dict: a dictionary in which the headers are inserted. + io: The io factory to use to read the file. Provided for testability. + + Returns: + True if a header was successfully added. False otherwise. + """ + headerfile = None + try: + headerfile = io.open(filename, 'r', 'utf8', 'replace') + except IOError: + return False + linenum = 0 + for line in headerfile: + linenum += 1 + clean_line = CleanseComments(line) + match = _RE_PATTERN_INCLUDE.search(clean_line) + if match: + include = match.group(2) + include_dict.setdefault(include, linenum) + return True + + +def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, + io=codecs): + """Reports for missing stl includes. + + This function will output warnings to make sure you are including the headers + necessary for the stl containers and functions that you use. We only give one + reason to include a header. For example, if you use both equal_to<> and + less<> in a .h file, only one (the latter in the file) of these will be + reported as a reason to include the . + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + include_state: An _IncludeState instance. + error: The function to call with any errors found. + io: The IO factory to use to read the header file. Provided for unittest + injection. + """ + required = {} # A map of header name to linenumber and the template entity. + # Example of required: { '': (1219, 'less<>') } + + for linenum in xrange(clean_lines.NumLines()): + line = clean_lines.elided[linenum] + if not line or line[0] == '#': + continue + + # String is special -- it is a non-templatized type in STL. + matched = _RE_PATTERN_STRING.search(line) + if matched: + # Don't warn about strings in non-STL namespaces: + # (We check only the first match per line; good enough.) + prefix = line[:matched.start()] + if prefix.endswith('std::') or not prefix.endswith('::'): + required[''] = (linenum, 'string') + + for pattern, template, header in _re_pattern_headers_maybe_templates: + if pattern.search(line): + required[header] = (linenum, template) + + # The following function is just a speed up, no semantics are changed. + if not '<' in line: # Reduces the cpu time usage by skipping lines. + continue + + for pattern, template, header in _re_pattern_templates: + matched = pattern.search(line) + if matched: + # Don't warn about IWYU in non-STL namespaces: + # (We check only the first match per line; good enough.) + prefix = line[:matched.start()] + if prefix.endswith('std::') or not prefix.endswith('::'): + required[header] = (linenum, template) + + # The policy is that if you #include something in foo.h you don't need to + # include it again in foo.cc. Here, we will look at possible includes. + # Let's flatten the include_state include_list and copy it into a dictionary. + include_dict = dict([item for sublist in include_state.include_list + for item in sublist]) + + # Did we find the header for this file (if any) and successfully load it? + header_found = False + + # Use the absolute path so that matching works properly. + abs_filename = FileInfo(filename).FullName() + + # For Emacs's flymake. + # If cpplint is invoked from Emacs's flymake, a temporary file is generated + # by flymake and that file name might end with '_flymake.cc'. In that case, + # restore original file name here so that the corresponding header file can be + # found. + # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' + # instead of 'foo_flymake.h' + abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) + + # include_dict is modified during iteration, so we iterate over a copy of + # the keys. + header_keys = include_dict.keys() + for header in header_keys: + (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) + fullpath = common_path + header + if same_module and UpdateIncludeState(fullpath, include_dict, io): + header_found = True + + # If we can't find the header file for a .cc, assume it's because we don't + # know where to look. In that case we'll give up as we're not sure they + # didn't include it in the .h file. + # TODO(unknown): Do a better job of finding .h files so we are confident that + # not having the .h file means there isn't one. + if filename.endswith('.cc') and not header_found: + return + + # All the lines have been processed, report the errors found. + for required_header_unstripped in required: + template = required[required_header_unstripped][1] + if required_header_unstripped.strip('<>"') not in include_dict: + error(filename, required[required_header_unstripped][0], + 'build/include_what_you_use', 4, + 'Add #include ' + required_header_unstripped + ' for ' + template) + + +_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') + + +def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): + """Check that make_pair's template arguments are deduced. + + G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are + specified explicitly, and such use isn't intended in any case. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) + if match: + error(filename, linenum, 'build/explicit_make_pair', + 4, # 4 = high confidence + 'For C++11-compatibility, omit template arguments from make_pair' + ' OR use pair directly OR if appropriate, construct a pair directly') + + +def CheckRedundantVirtual(filename, clean_lines, linenum, error): + """Check if line contains a redundant "virtual" function-specifier. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + # Look for "virtual" on current line. + line = clean_lines.elided[linenum] + virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line) + if not virtual: return + + # Ignore "virtual" keywords that are near access-specifiers. These + # are only used in class base-specifier and do not apply to member + # functions. + if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or + Match(r'^\s+(public|protected|private)\b', virtual.group(3))): + return + + # Ignore the "virtual" keyword from virtual base classes. Usually + # there is a column on the same line in these cases (virtual base + # classes are rare in google3 because multiple inheritance is rare). + if Match(r'^.*[^:]:[^:].*$', line): return + + # Look for the next opening parenthesis. This is the start of the + # parameter list (possibly on the next line shortly after virtual). + # TODO(unknown): doesn't work if there are virtual functions with + # decltype() or other things that use parentheses, but csearch suggests + # that this is rare. + end_col = -1 + end_line = -1 + start_col = len(virtual.group(2)) + for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())): + line = clean_lines.elided[start_line][start_col:] + parameter_list = Match(r'^([^(]*)\(', line) + if parameter_list: + # Match parentheses to find the end of the parameter list + (_, end_line, end_col) = CloseExpression( + clean_lines, start_line, start_col + len(parameter_list.group(1))) + break + start_col = 0 + + if end_col < 0: + return # Couldn't find end of parameter list, give up + + # Look for "override" or "final" after the parameter list + # (possibly on the next few lines). + for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())): + line = clean_lines.elided[i][end_col:] + match = Search(r'\b(override|final)\b', line) + if match: + error(filename, linenum, 'readability/inheritance', 4, + ('"virtual" is redundant since function is ' + 'already declared as "%s"' % match.group(1))) + + # Set end_col to check whole lines after we are done with the + # first line. + end_col = 0 + if Search(r'[^\w]\s*$', line): + break + + +def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error): + """Check if line contains a redundant "override" or "final" virt-specifier. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + # Look for closing parenthesis nearby. We need one to confirm where + # the declarator ends and where the virt-specifier starts to avoid + # false positives. + line = clean_lines.elided[linenum] + declarator_end = line.rfind(')') + if declarator_end >= 0: + fragment = line[declarator_end:] + else: + if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0: + fragment = line + else: + return + + # Check that at most one of "override" or "final" is present, not both + if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment): + error(filename, linenum, 'readability/inheritance', 4, + ('"override" is redundant since function is ' + 'already declared as "final"')) + + + + +# Returns true if we are at a new block, and it is directly +# inside of a namespace. +def IsBlockInNameSpace(nesting_state, is_forward_declaration): + """Checks that the new block is directly in a namespace. + + Args: + nesting_state: The _NestingState object that contains info about our state. + is_forward_declaration: If the class is a forward declared class. + Returns: + Whether or not the new block is directly in a namespace. + """ + if is_forward_declaration: + if len(nesting_state.stack) >= 1 and ( + isinstance(nesting_state.stack[-1], _NamespaceInfo)): + return True + else: + return False + + return (len(nesting_state.stack) > 1 and + nesting_state.stack[-1].check_namespace_indentation and + isinstance(nesting_state.stack[-2], _NamespaceInfo)) + + +def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, + raw_lines_no_comments, linenum): + """This method determines if we should apply our namespace indentation check. + + Args: + nesting_state: The current nesting state. + is_namespace_indent_item: If we just put a new class on the stack, True. + If the top of the stack is not a class, or we did not recently + add the class, False. + raw_lines_no_comments: The lines without the comments. + linenum: The current line number we are processing. + + Returns: + True if we should apply our namespace indentation check. Currently, it + only works for classes and namespaces inside of a namespace. + """ + + is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments, + linenum) + + if not (is_namespace_indent_item or is_forward_declaration): + return False + + # If we are in a macro, we do not want to check the namespace indentation. + if IsMacroDefinition(raw_lines_no_comments, linenum): + return False + + return IsBlockInNameSpace(nesting_state, is_forward_declaration) + + +# Call this method if the line is directly inside of a namespace. +# If the line above is blank (excluding comments) or the start of +# an inner namespace, it cannot be indented. +def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum, + error): + line = raw_lines_no_comments[linenum] + if Match(r'^\s+', line): + error(filename, linenum, 'runtime/indentation_namespace', 4, + 'Do not indent within a namespace') + + +def ProcessLine(filename, file_extension, clean_lines, line, + include_state, function_state, nesting_state, error, + extra_check_functions=[]): + """Processes a single line in the file. + + Args: + filename: Filename of the file that is being processed. + file_extension: The extension (dot not included) of the file. + clean_lines: An array of strings, each representing a line of the file, + with comments stripped. + line: Number of line being processed. + include_state: An _IncludeState instance in which the headers are inserted. + function_state: A _FunctionState instance which counts function lines, etc. + nesting_state: A NestingState instance which maintains information about + the current stack of nested blocks being parsed. + error: A callable to which errors are reported, which takes 4 arguments: + filename, line number, error level, and message + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + raw_lines = clean_lines.raw_lines + ParseNolintSuppressions(filename, raw_lines[line], line, error) + nesting_state.Update(filename, clean_lines, line, error) + CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, + error) + if nesting_state.InAsmBlock(): return + CheckForFunctionLengths(filename, clean_lines, line, function_state, error) + CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) + CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error) + CheckLanguage(filename, clean_lines, line, file_extension, include_state, + nesting_state, error) + CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) + CheckForNonStandardConstructs(filename, clean_lines, line, + nesting_state, error) + CheckVlogArguments(filename, clean_lines, line, error) + CheckPosixThreading(filename, clean_lines, line, error) + CheckInvalidIncrement(filename, clean_lines, line, error) + CheckMakePairUsesDeduction(filename, clean_lines, line, error) + CheckRedundantVirtual(filename, clean_lines, line, error) + CheckRedundantOverrideOrFinal(filename, clean_lines, line, error) + for check_fn in extra_check_functions: + check_fn(filename, clean_lines, line, error) + +def FlagCxx11Features(filename, clean_lines, linenum, error): + """Flag those c++11 features that we only allow in certain places. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) + + # Flag unapproved C++ TR1 headers. + if include and include.group(1).startswith('tr1/'): + error(filename, linenum, 'build/c++tr1', 5, + ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1)) + + # Flag unapproved C++11 headers. + if include and include.group(1) in ('cfenv', + 'condition_variable', + 'fenv.h', + 'future', + 'mutex', + 'thread', + 'chrono', + 'ratio', + 'regex', + 'system_error', + ): + error(filename, linenum, 'build/c++11', 5, + ('<%s> is an unapproved C++11 header.') % include.group(1)) + + # The only place where we need to worry about C++11 keywords and library + # features in preprocessor directives is in macro definitions. + if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return + + # These are classes and free functions. The classes are always + # mentioned as std::*, but we only catch the free functions if + # they're not found by ADL. They're alphabetical by header. + for top_name in ( + # type_traits + 'alignment_of', + 'aligned_union', + ): + if Search(r'\bstd::%s\b' % top_name, line): + error(filename, linenum, 'build/c++11', 5, + ('std::%s is an unapproved C++11 class or function. Send c-style ' + 'an example of where it would make your code more readable, and ' + 'they may let you use it.') % top_name) + + +def FlagCxx14Features(filename, clean_lines, linenum, error): + """Flag those C++14 features that we restrict. + + Args: + filename: The name of the current file. + clean_lines: A CleansedLines instance containing the file. + linenum: The number of the line to check. + error: The function to call with any errors found. + """ + line = clean_lines.elided[linenum] + + include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) + + # Flag unapproved C++14 headers. + if include and include.group(1) in ('scoped_allocator', 'shared_mutex'): + error(filename, linenum, 'build/c++14', 5, + ('<%s> is an unapproved C++14 header.') % include.group(1)) + + +def ProcessFileData(filename, file_extension, lines, error, + extra_check_functions=[]): + """Performs lint checks and reports any errors to the given error function. + + Args: + filename: Filename of the file that is being processed. + file_extension: The extension (dot not included) of the file. + lines: An array of strings, each representing a line of the file, with the + last element being empty if the file is terminated with a newline. + error: A callable to which errors are reported, which takes 4 arguments: + filename, line number, error level, and message + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + lines = (['// marker so line numbers and indices both start at 1'] + lines + + ['// marker so line numbers end in a known way']) + + include_state = _IncludeState() + function_state = _FunctionState() + nesting_state = NestingState() + + ResetNolintSuppressions() + + CheckForCopyright(filename, lines, error) + ProcessGlobalSuppresions(lines) + RemoveMultiLineComments(filename, lines, error) + clean_lines = CleansedLines(lines) + + if IsHeaderExtension(file_extension): + CheckForHeaderGuard(filename, clean_lines, error) + + for line in xrange(clean_lines.NumLines()): + ProcessLine(filename, file_extension, clean_lines, line, + include_state, function_state, nesting_state, error, + extra_check_functions) + FlagCxx11Features(filename, clean_lines, line, error) + nesting_state.CheckCompletedBlocks(filename, error) + + CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) + + # Check that the .cc file has included its header if it exists. + if _IsSourceExtension(file_extension): + CheckHeaderFileIncluded(filename, include_state, error) + + # We check here rather than inside ProcessLine so that we see raw + # lines rather than "cleaned" lines. + CheckForBadCharacters(filename, lines, error) + + CheckForNewlineAtEOF(filename, lines, error) + +def ProcessConfigOverrides(filename): + """ Loads the configuration files and processes the config overrides. + + Args: + filename: The name of the file being processed by the linter. + + Returns: + False if the current |filename| should not be processed further. + """ + + abs_filename = os.path.abspath(filename) + cfg_filters = [] + keep_looking = True + while keep_looking: + abs_path, base_name = os.path.split(abs_filename) + if not base_name: + break # Reached the root directory. + + cfg_file = os.path.join(abs_path, "CPPLINT.cfg") + abs_filename = abs_path + if not os.path.isfile(cfg_file): + continue + + try: + with open(cfg_file) as file_handle: + for line in file_handle: + line, _, _ = line.partition('#') # Remove comments. + if not line.strip(): + continue + + name, _, val = line.partition('=') + name = name.strip() + val = val.strip() + if name == 'set noparent': + keep_looking = False + elif name == 'filter': + cfg_filters.append(val) + elif name == 'exclude_files': + # When matching exclude_files pattern, use the base_name of + # the current file name or the directory name we are processing. + # For example, if we are checking for lint errors in /foo/bar/baz.cc + # and we found the .cfg file at /foo/CPPLINT.cfg, then the config + # file's "exclude_files" filter is meant to be checked against "bar" + # and not "baz" nor "bar/baz.cc". + if base_name: + pattern = re.compile(val) + if pattern.match(base_name): + if _cpplint_state.quiet: + # Suppress "Ignoring file" warning when using --quiet. + return False + sys.stderr.write('Ignoring "%s": file excluded by "%s". ' + 'File path component "%s" matches ' + 'pattern "%s"\n' % + (filename, cfg_file, base_name, val)) + return False + elif name == 'linelength': + global _line_length + try: + _line_length = int(val) + except ValueError: + sys.stderr.write('Line length must be numeric.') + elif name == 'root': + global _root + # root directories are specified relative to CPPLINT.cfg dir. + _root = os.path.join(os.path.dirname(cfg_file), val) + elif name == 'headers': + ProcessHppHeadersOption(val) + else: + sys.stderr.write( + 'Invalid configuration option (%s) in file %s\n' % + (name, cfg_file)) + + except IOError: + sys.stderr.write( + "Skipping config file '%s': Can't open for reading\n" % cfg_file) + keep_looking = False + + # Apply all the accumulated filters in reverse order (top-level directory + # config options having the least priority). + for filter in reversed(cfg_filters): + _AddFilters(filter) + + return True + + +def ProcessFile(filename, vlevel, extra_check_functions=[]): + """Does google-lint on a single file. + + Args: + filename: The name of the file to parse. + + vlevel: The level of errors to report. Every error of confidence + >= verbose_level will be reported. 0 is a good default. + + extra_check_functions: An array of additional check functions that will be + run on each source line. Each function takes 4 + arguments: filename, clean_lines, line, error + """ + + _SetVerboseLevel(vlevel) + _BackupFilters() + old_errors = _cpplint_state.error_count + + if not ProcessConfigOverrides(filename): + _RestoreFilters() + return + + lf_lines = [] + crlf_lines = [] + try: + # Support the UNIX convention of using "-" for stdin. Note that + # we are not opening the file with universal newline support + # (which codecs doesn't support anyway), so the resulting lines do + # contain trailing '\r' characters if we are reading a file that + # has CRLF endings. + # If after the split a trailing '\r' is present, it is removed + # below. + if filename == '-': + lines = codecs.StreamReaderWriter(sys.stdin, + codecs.getreader('utf8'), + codecs.getwriter('utf8'), + 'replace').read().split('\n') + else: + lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') + + # Remove trailing '\r'. + # The -1 accounts for the extra trailing blank line we get from split() + for linenum in range(len(lines) - 1): + if lines[linenum].endswith('\r'): + lines[linenum] = lines[linenum].rstrip('\r') + crlf_lines.append(linenum + 1) + else: + lf_lines.append(linenum + 1) + + except IOError: + sys.stderr.write( + "Skipping input '%s': Can't open for reading\n" % filename) + _RestoreFilters() + return + + # Note, if no dot is found, this will give the entire filename as the ext. + file_extension = filename[filename.rfind('.') + 1:] + + # When reading from stdin, the extension is unknown, so no cpplint tests + # should rely on the extension. + if filename != '-' and file_extension not in _valid_extensions: + sys.stderr.write('Ignoring %s; not a valid file name ' + '(%s)\n' % (filename, ', '.join(_valid_extensions))) + else: + ProcessFileData(filename, file_extension, lines, Error, + extra_check_functions) + + # If end-of-line sequences are a mix of LF and CR-LF, issue + # warnings on the lines with CR. + # + # Don't issue any warnings if all lines are uniformly LF or CR-LF, + # since critique can handle these just fine, and the style guide + # doesn't dictate a particular end of line sequence. + # + # We can't depend on os.linesep to determine what the desired + # end-of-line sequence should be, since that will return the + # server-side end-of-line sequence. + if lf_lines and crlf_lines: + # Warn on every line with CR. An alternative approach might be to + # check whether the file is mostly CRLF or just LF, and warn on the + # minority, we bias toward LF here since most tools prefer LF. + for linenum in crlf_lines: + Error(filename, linenum, 'whitespace/newline', 1, + 'Unexpected \\r (^M) found; better to use only \\n') + + # Suppress printing anything if --quiet was passed unless the error + # count has increased after processing this file. + if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count: + sys.stdout.write('Done processing %s\n' % filename) + _RestoreFilters() + + +def PrintUsage(message): + """Prints a brief usage string and exits, optionally with an error message. + + Args: + message: The optional error message. + """ + sys.stderr.write(_USAGE) + if message: + sys.exit('\nFATAL ERROR: ' + message) + else: + sys.exit(1) + + +def PrintCategories(): + """Prints a list of all the error-categories used by error messages. + + These are the categories used to filter messages via --filter. + """ + sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) + sys.exit(0) + + +def ParseArguments(args): + """Parses the command line arguments. + + This may set the output format and verbosity level as side-effects. + + Args: + args: The command line arguments: + + Returns: + The list of filenames to lint. + """ + try: + (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', + 'counting=', + 'filter=', + 'root=', + 'linelength=', + 'extensions=', + 'headers=', + 'quiet']) + except getopt.GetoptError: + PrintUsage('Invalid arguments.') + + verbosity = _VerboseLevel() + output_format = _OutputFormat() + filters = '' + quiet = _Quiet() + counting_style = '' + + for (opt, val) in opts: + if opt == '--help': + PrintUsage(None) + elif opt == '--output': + if val not in ('emacs', 'vs7', 'eclipse'): + PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.') + output_format = val + elif opt == '--quiet': + quiet = True + elif opt == '--verbose': + verbosity = int(val) + elif opt == '--filter': + filters = val + if not filters: + PrintCategories() + elif opt == '--counting': + if val not in ('total', 'toplevel', 'detailed'): + PrintUsage('Valid counting options are total, toplevel, and detailed') + counting_style = val + elif opt == '--root': + global _root + _root = val + elif opt == '--linelength': + global _line_length + try: + _line_length = int(val) + except ValueError: + PrintUsage('Line length must be digits.') + elif opt == '--extensions': + global _valid_extensions + try: + _valid_extensions = set(val.split(',')) + except ValueError: + PrintUsage('Extensions must be comma seperated list.') + elif opt == '--headers': + ProcessHppHeadersOption(val) + + if not filenames: + PrintUsage('No files were specified.') + + _SetOutputFormat(output_format) + _SetQuiet(quiet) + _SetVerboseLevel(verbosity) + _SetFilters(filters) + _SetCountingStyle(counting_style) + + return filenames + + +def main(): + filenames = ParseArguments(sys.argv[1:]) + + # Change stderr to write with replacement characters so we don't die + # if we try to print something containing non-ASCII characters. + sys.stderr = codecs.StreamReaderWriter(sys.stderr, + codecs.getreader('utf8'), + codecs.getwriter('utf8'), + 'replace') + + _cpplint_state.ResetErrorCounts() + for filename in filenames: + ProcessFile(filename, _cpplint_state.verbose_level) + # If --quiet is passed, suppress printing error count unless there are errors. + if not _cpplint_state.quiet or _cpplint_state.error_count > 0: + _cpplint_state.PrintErrorCounts() + + sys.exit(_cpplint_state.error_count > 0) + + +if __name__ == '__main__': + main() diff --git a/cpplint/cpplint_test_header.h b/cpplint/cpplint_test_header.h new file mode 100644 index 000000000..4307e8008 --- /dev/null +++ b/cpplint/cpplint_test_header.h @@ -0,0 +1 @@ +// A test header for cpplint_unittest.py. diff --git a/cpplint/cpplint_unittest.py b/cpplint/cpplint_unittest.py new file mode 100755 index 000000000..50d1d826b --- /dev/null +++ b/cpplint/cpplint_unittest.py @@ -0,0 +1,5805 @@ +#!/usr/bin/python +# -*- coding: utf-8; -*- +# +# Copyright (c) 2009 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit test for cpplint.py.""" + +# TODO(unknown): Add a good test that tests UpdateIncludeState. + +import codecs +import os +import random +import re +import subprocess +import sys +import unittest + +import cpplint + + +# This class works as an error collector and replaces cpplint.Error +# function for the unit tests. We also verify each category we see +# is in cpplint._ERROR_CATEGORIES, to help keep that list up to date. +class ErrorCollector(object): + # These are a global list, covering all categories seen ever. + _ERROR_CATEGORIES = cpplint._ERROR_CATEGORIES + _SEEN_ERROR_CATEGORIES = {} + + def __init__(self, assert_fn): + """assert_fn: a function to call when we notice a problem.""" + self._assert_fn = assert_fn + self._errors = [] + cpplint.ResetNolintSuppressions() + + def __call__(self, unused_filename, linenum, + category, confidence, message): + self._assert_fn(category in self._ERROR_CATEGORIES, + 'Message "%s" has category "%s",' + ' which is not in _ERROR_CATEGORIES' % (message, category)) + self._SEEN_ERROR_CATEGORIES[category] = 1 + if cpplint._ShouldPrintError(category, confidence, linenum): + self._errors.append('%s [%s] [%d]' % (message, category, confidence)) + + def Results(self): + if len(self._errors) < 2: + return ''.join(self._errors) # Most tests expect to have a string. + else: + return self._errors # Let's give a list if there is more than one. + + def ResultList(self): + return self._errors + + def VerifyAllCategoriesAreSeen(self): + """Fails if there's a category in _ERROR_CATEGORIES~_SEEN_ERROR_CATEGORIES. + + This should only be called after all tests are run, so + _SEEN_ERROR_CATEGORIES has had a chance to fully populate. Since + this isn't called from within the normal unittest framework, we + can't use the normal unittest assert macros. Instead we just exit + when we see an error. Good thing this test is always run last! + """ + for category in self._ERROR_CATEGORIES: + if category not in self._SEEN_ERROR_CATEGORIES: + sys.exit('FATAL ERROR: There are no tests for category "%s"' % category) + + def RemoveIfPresent(self, substr): + for (index, error) in enumerate(self._errors): + if error.find(substr) != -1: + self._errors = self._errors[0:index] + self._errors[(index + 1):] + break + + +# This class is a lame mock of codecs. We do not verify filename, mode, or +# encoding, but for the current use case it is not needed. +class MockIo(object): + + def __init__(self, mock_file): + self.mock_file = mock_file + + def open(self, # pylint: disable-msg=C6409 + unused_filename, unused_mode, unused_encoding, _): + return self.mock_file + + +class CpplintTestBase(unittest.TestCase): + """Provides some useful helper functions for cpplint tests.""" + + def setUp(self): + # Allow subclasses to cheat os.path.abspath called in FileInfo class. + self.os_path_abspath_orig = os.path.abspath + + def tearDown(self): + os.path.abspath = self.os_path_abspath_orig + + # Perform lint on single line of input and return the error message. + def PerformSingleLineLint(self, code): + error_collector = ErrorCollector(self.assert_) + lines = code.split('\n') + cpplint.RemoveMultiLineComments('foo.h', lines, error_collector) + clean_lines = cpplint.CleansedLines(lines) + include_state = cpplint._IncludeState() + function_state = cpplint._FunctionState() + nesting_state = cpplint.NestingState() + cpplint.ProcessLine('foo.cc', 'cc', clean_lines, 0, + include_state, function_state, + nesting_state, error_collector) + # Single-line lint tests are allowed to fail the 'unlintable function' + # check. + error_collector.RemoveIfPresent( + 'Lint failed to find start of function body.') + return error_collector.Results() + + # Perform lint over multiple lines and return the error message. + def PerformMultiLineLint(self, code): + error_collector = ErrorCollector(self.assert_) + lines = code.split('\n') + cpplint.RemoveMultiLineComments('foo.h', lines, error_collector) + lines = cpplint.CleansedLines(lines) + nesting_state = cpplint.NestingState() + for i in xrange(lines.NumLines()): + nesting_state.Update('foo.h', lines, i, error_collector) + cpplint.CheckStyle('foo.h', lines, i, 'h', nesting_state, + error_collector) + cpplint.CheckForNonStandardConstructs('foo.h', lines, i, + nesting_state, error_collector) + nesting_state.CheckCompletedBlocks('foo.h', error_collector) + return error_collector.Results() + + # Similar to PerformMultiLineLint, but calls CheckLanguage instead of + # CheckForNonStandardConstructs + def PerformLanguageRulesCheck(self, file_name, code): + error_collector = ErrorCollector(self.assert_) + include_state = cpplint._IncludeState() + nesting_state = cpplint.NestingState() + lines = code.split('\n') + cpplint.RemoveMultiLineComments(file_name, lines, error_collector) + lines = cpplint.CleansedLines(lines) + ext = file_name[file_name.rfind('.') + 1:] + for i in xrange(lines.NumLines()): + cpplint.CheckLanguage(file_name, lines, i, ext, include_state, + nesting_state, error_collector) + return error_collector.Results() + + def PerformFunctionLengthsCheck(self, code): + """Perform Lint function length check on block of code and return warnings. + + Builds up an array of lines corresponding to the code and strips comments + using cpplint functions. + + Establishes an error collector and invokes the function length checking + function following cpplint's pattern. + + Args: + code: C++ source code expected to generate a warning message. + + Returns: + The accumulated errors. + """ + file_name = 'foo.cc' + error_collector = ErrorCollector(self.assert_) + function_state = cpplint._FunctionState() + lines = code.split('\n') + cpplint.RemoveMultiLineComments(file_name, lines, error_collector) + lines = cpplint.CleansedLines(lines) + for i in xrange(lines.NumLines()): + cpplint.CheckForFunctionLengths(file_name, lines, i, + function_state, error_collector) + return error_collector.Results() + + def PerformIncludeWhatYouUse(self, code, filename='foo.h', io=codecs): + # First, build up the include state. + error_collector = ErrorCollector(self.assert_) + include_state = cpplint._IncludeState() + nesting_state = cpplint.NestingState() + lines = code.split('\n') + cpplint.RemoveMultiLineComments(filename, lines, error_collector) + lines = cpplint.CleansedLines(lines) + for i in xrange(lines.NumLines()): + cpplint.CheckLanguage(filename, lines, i, '.h', include_state, + nesting_state, error_collector) + # We could clear the error_collector here, but this should + # also be fine, since our IncludeWhatYouUse unittests do not + # have language problems. + + # Second, look for missing includes. + cpplint.CheckForIncludeWhatYouUse(filename, lines, include_state, + error_collector, io) + return error_collector.Results() + + # Perform lint and compare the error message with "expected_message". + def TestLint(self, code, expected_message): + self.assertEquals(expected_message, self.PerformSingleLineLint(code)) + + def TestMultiLineLint(self, code, expected_message): + self.assertEquals(expected_message, self.PerformMultiLineLint(code)) + + def TestMultiLineLintRE(self, code, expected_message_re): + message = self.PerformMultiLineLint(code) + if not re.search(expected_message_re, message): + self.fail('Message was:\n' + message + 'Expected match to "' + + expected_message_re + '"') + + def TestLanguageRulesCheck(self, file_name, code, expected_message): + self.assertEquals(expected_message, + self.PerformLanguageRulesCheck(file_name, code)) + + def TestIncludeWhatYouUse(self, code, expected_message): + self.assertEquals(expected_message, + self.PerformIncludeWhatYouUse(code)) + + def TestBlankLinesCheck(self, lines, start_errors, end_errors): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', lines, error_collector) + self.assertEquals( + start_errors, + error_collector.Results().count( + 'Redundant blank line at the start of a code block ' + 'should be deleted. [whitespace/blank_line] [2]')) + self.assertEquals( + end_errors, + error_collector.Results().count( + 'Redundant blank line at the end of a code block ' + 'should be deleted. [whitespace/blank_line] [3]')) + + +class CpplintTest(CpplintTestBase): + + def GetNamespaceResults(self, lines): + error_collector = ErrorCollector(self.assert_) + cpplint.RemoveMultiLineComments('foo.h', lines, error_collector) + lines = cpplint.CleansedLines(lines) + nesting_state = cpplint.NestingState() + for i in xrange(lines.NumLines()): + nesting_state.Update('foo.h', lines, i, error_collector) + cpplint.CheckForNamespaceIndentation('foo.h', nesting_state, + lines, i, error_collector) + + return error_collector.Results() + + def testForwardDeclarationNameSpaceIndentation(self): + lines = ['namespace Test {', + ' class ForwardDeclaration;', + '} // namespace Test'] + + results = self.GetNamespaceResults(lines) + self.assertEquals(results, 'Do not indent within a namespace ' + ' [runtime/indentation_namespace] [4]') + + def testNameSpaceIndentationForClass(self): + lines = ['namespace Test {', + 'void foo() { }', + ' class Test {', + ' };', + '} // namespace Test'] + + results = self.GetNamespaceResults(lines) + self.assertEquals(results, 'Do not indent within a namespace ' + ' [runtime/indentation_namespace] [4]') + + def testNameSpaceIndentationNoError(self): + lines = ['namespace Test {', + 'void foo() { }', + '} // namespace Test'] + + results = self.GetNamespaceResults(lines) + self.assertEquals(results, '') + + def testWhitespaceBeforeNamespace(self): + lines = [' namespace Test {', + ' void foo() { }', + ' } // namespace Test'] + + results = self.GetNamespaceResults(lines) + self.assertEquals(results, '') + + def testFalsePositivesNoError(self): + lines = ['namespace Test {', + 'struct OuterClass {', + ' struct NoFalsePositivesHere;', + ' struct NoFalsePositivesHere member_variable;', + '};', + '} // namespace Test'] + + results = self.GetNamespaceResults(lines) + self.assertEquals(results, '') + + + # Test get line width. + def testGetLineWidth(self): + self.assertEquals(0, cpplint.GetLineWidth('')) + self.assertEquals(10, cpplint.GetLineWidth(u'x' * 10)) + self.assertEquals(16, cpplint.GetLineWidth(u'都|道|府|県|支庁')) + + def testGetTextInside(self): + self.assertEquals('', cpplint._GetTextInside('fun()', r'fun\(')) + self.assertEquals('x, y', cpplint._GetTextInside('f(x, y)', r'f\(')) + self.assertEquals('a(), b(c())', cpplint._GetTextInside( + 'printf(a(), b(c()))', r'printf\(')) + self.assertEquals('x, y{}', cpplint._GetTextInside('f[x, y{}]', r'f\[')) + self.assertEquals(None, cpplint._GetTextInside('f[a, b(}]', r'f\[')) + self.assertEquals(None, cpplint._GetTextInside('f[x, y]', r'f\(')) + self.assertEquals('y, h(z, (a + b))', cpplint._GetTextInside( + 'f(x, g(y, h(z, (a + b))))', r'g\(')) + self.assertEquals('f(f(x))', cpplint._GetTextInside('f(f(f(x)))', r'f\(')) + # Supports multiple lines. + self.assertEquals('\n return loop(x);\n', + cpplint._GetTextInside( + 'int loop(int x) {\n return loop(x);\n}\n', r'\{')) + # '^' matches the beginning of each line. + self.assertEquals('x, y', + cpplint._GetTextInside( + '#include "inl.h" // skip #define\n' + '#define A2(x, y) a_inl_(x, y, __LINE__)\n' + '#define A(x) a_inl_(x, "", __LINE__)\n', + r'^\s*#define\s*\w+\(')) + + def testFindNextMultiLineCommentStart(self): + self.assertEquals(1, cpplint.FindNextMultiLineCommentStart([''], 0)) + + lines = ['a', 'b', '/* c'] + self.assertEquals(2, cpplint.FindNextMultiLineCommentStart(lines, 0)) + + lines = ['char a[] = "/*";'] # not recognized as comment. + self.assertEquals(1, cpplint.FindNextMultiLineCommentStart(lines, 0)) + + def testFindNextMultiLineCommentEnd(self): + self.assertEquals(1, cpplint.FindNextMultiLineCommentEnd([''], 0)) + lines = ['a', 'b', ' c */'] + self.assertEquals(2, cpplint.FindNextMultiLineCommentEnd(lines, 0)) + + def testRemoveMultiLineCommentsFromRange(self): + lines = ['a', ' /* comment ', ' * still comment', ' comment */ ', 'b'] + cpplint.RemoveMultiLineCommentsFromRange(lines, 1, 4) + self.assertEquals(['a', '/**/', '/**/', '/**/', 'b'], lines) + + def testSpacesAtEndOfLine(self): + self.TestLint( + '// Hello there ', + 'Line ends in whitespace. Consider deleting these extra spaces.' + ' [whitespace/end_of_line] [4]') + + # Test line length check. + def testLineLengthCheck(self): + self.TestLint( + '// Hello', + '') + self.TestLint( + '// x' + ' x' * 40, + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestLint( + '// x' + ' x' * 50, + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestLint( + '// //some/path/to/f' + ('i' * 100) + 'le', + '') + self.TestLint( + '// //some/path/to/f' + ('i' * 100) + 'le', + '') + self.TestLint( + '// //some/path/to/f' + ('i' * 50) + 'le and some comments', + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestLint( + '// http://g' + ('o' * 100) + 'gle.com/', + '') + self.TestLint( + '// https://g' + ('o' * 100) + 'gle.com/', + '') + self.TestLint( + '// https://g' + ('o' * 60) + 'gle.com/ and some comments', + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestLint( + '// Read https://g' + ('o' * 60) + 'gle.com/', + '') + self.TestLint( + '// $Id: g' + ('o' * 80) + 'gle.cc#1 $', + '') + self.TestLint( + '// $Id: g' + ('o' * 80) + 'gle.cc#1', + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestMultiLineLint( + 'static const char kCStr[] = "g' + ('o' * 50) + 'gle";\n', + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestMultiLineLint( + 'static const char kRawStr[] = R"(g' + ('o' * 50) + 'gle)";\n', + '') # no warning because raw string content is elided + self.TestMultiLineLint( + 'static const char kMultiLineRawStr[] = R"(\n' + 'g' + ('o' * 80) + 'gle\n' + ')";', + '') + self.TestMultiLineLint( + 'static const char kL' + ('o' * 50) + 'ngIdentifier[] = R"()";\n', + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + + # Test error suppression annotations. + def testErrorSuppression(self): + # Two errors on same line: + self.TestLint( + 'long a = (int64) 65;', + ['Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]', + 'Use int16/int64/etc, rather than the C type long' + ' [runtime/int] [4]', + ]) + # One category of error suppressed: + self.TestLint( + 'long a = (int64) 65; // NOLINT(runtime/int)', + 'Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]') + # All categories suppressed: (two aliases) + self.TestLint('long a = (int64) 65; // NOLINT', '') + self.TestLint('long a = (int64) 65; // NOLINT(*)', '') + # Malformed NOLINT directive: + self.TestLint( + 'long a = 65; // NOLINT(foo)', + ['Unknown NOLINT error category: foo' + ' [readability/nolint] [5]', + 'Use int16/int64/etc, rather than the C type long [runtime/int] [4]', + ]) + # Irrelevant NOLINT directive has no effect: + self.TestLint( + 'long a = 65; // NOLINT(readability/casting)', + 'Use int16/int64/etc, rather than the C type long' + ' [runtime/int] [4]') + # NOLINTNEXTLINE silences warning for the next line instead of current line + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('test.cc', 'cc', + ['// Copyright 2014 Your Company.', + '// NOLINTNEXTLINE(whitespace/line_length)', + '// ./command' + (' -verbose' * 80), + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + # LINT_C_FILE silences cast warnings for entire file. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('test.h', 'h', + ['// Copyright 2014 Your Company.', + '// NOLINT(build/header_guard)', + 'int64 a = (uint64) 65;', + '// LINT_C_FILE', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + # Vim modes silence cast warnings for entire file. + for modeline in ['vi:filetype=c', + 'vi:sw=8 filetype=c', + 'vi:sw=8 filetype=c ts=8', + 'vi: filetype=c', + 'vi: sw=8 filetype=c', + 'vi: sw=8 filetype=c ts=8', + 'vim:filetype=c', + 'vim:sw=8 filetype=c', + 'vim:sw=8 filetype=c ts=8', + 'vim: filetype=c', + 'vim: sw=8 filetype=c', + 'vim: sw=8 filetype=c ts=8', + 'vim: set filetype=c:', + 'vim: set sw=8 filetype=c:', + 'vim: set sw=8 filetype=c ts=8:', + 'vim: set filetype=c :', + 'vim: set sw=8 filetype=c :', + 'vim: set sw=8 filetype=c ts=8 :', + 'vim: se filetype=c:', + 'vim: se sw=8 filetype=c:', + 'vim: se sw=8 filetype=c ts=8:', + 'vim: se filetype=c :', + 'vim: se sw=8 filetype=c :', + 'vim: se sw=8 filetype=c ts=8 :']: + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('test.h', 'h', + ['// Copyright 2014 Your Company.', + '// NOLINT(build/header_guard)', + 'int64 a = (uint64) 65;', + '/* Prevent warnings about the modeline', + modeline, + '*/', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + # LINT_KERNEL_FILE silences whitespace/tab warnings for entire file. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('test.h', 'h', + ['// Copyright 2014 Your Company.', + '// NOLINT(build/header_guard)', + 'struct test {', + '\tint member;', + '};', + '// LINT_KERNEL_FILE', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + # NOLINT, NOLINTNEXTLINE silences the readability/braces warning for "};". + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('test.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'for (int i = 0; i != 100; ++i) {', + '\tstd::cout << i << std::endl;', + '}; // NOLINT', + 'for (int i = 0; i != 100; ++i) {', + '\tstd::cout << i << std::endl;', + '// NOLINTNEXTLINE', + '};', + '// LINT_KERNEL_FILE', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + # Test Variable Declarations. + def testVariableDeclarations(self): + self.TestLint( + 'long a = 65;', + 'Use int16/int64/etc, rather than the C type long' + ' [runtime/int] [4]') + self.TestLint( + 'long double b = 65.0;', + '') + self.TestLint( + 'long long aa = 6565;', + 'Use int16/int64/etc, rather than the C type long' + ' [runtime/int] [4]') + + # Test C-style cast cases. + def testCStyleCast(self): + self.TestLint( + 'int a = (int)1.0;', + 'Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]') + self.TestLint( + 'int a = (int)-1.0;', + 'Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]') + self.TestLint( + 'int *a = (int *)NULL;', + 'Using C-style cast. Use reinterpret_cast(...) instead' + ' [readability/casting] [4]') + + self.TestLint( + 'uint16 a = (uint16)1.0;', + 'Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]') + self.TestLint( + 'int32 a = (int32)1.0;', + 'Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]') + self.TestLint( + 'uint64 a = (uint64)1.0;', + 'Using C-style cast. Use static_cast(...) instead' + ' [readability/casting] [4]') + + # These shouldn't be recognized casts. + self.TestLint('u a = (u)NULL;', '') + self.TestLint('uint a = (uint)NULL;', '') + self.TestLint('typedef MockCallback CallbackType;', '') + self.TestLint('scoped_ptr< MockCallback > callback_value;', '') + self.TestLint('std::function', '') + self.TestLint('x = sizeof(int)', '') + self.TestLint('x = alignof(int)', '') + self.TestLint('alignas(int) char x[42]', '') + self.TestLint('alignas(alignof(x)) char y[42]', '') + self.TestLint('void F(int (func)(int));', '') + self.TestLint('void F(int (func)(int*));', '') + self.TestLint('void F(int (Class::member)(int));', '') + self.TestLint('void F(int (Class::member)(int*));', '') + self.TestLint('void F(int (Class::member)(int), int param);', '') + self.TestLint('void F(int (Class::member)(int*), int param);', '') + + # These should not be recognized (lambda functions without arg names). + self.TestLint('[](int/*unused*/) -> bool {', '') + self.TestLint('[](int /*unused*/) -> bool {', '') + self.TestLint('auto f = [](MyStruct* /*unused*/)->int {', '') + self.TestLint('[](int) -> bool {', '') + self.TestLint('auto f = [](MyStruct*)->int {', '') + + # Cast with brace initializers + self.TestLint('int64_t{4096} * 1000 * 1000', '') + self.TestLint('size_t{4096} * 1000 * 1000', '') + self.TestLint('uint_fast16_t{4096} * 1000 * 1000', '') + + # Brace initializer with templated type + self.TestMultiLineLint( + """ + template + void Function(int arg1, + int arg2) { + variable &= ~Type1{0} - 1; + }""", + '') + self.TestMultiLineLint( + """ + template + class Class { + void Function() { + variable &= ~Type{0} - 1; + } + };""", + '') + self.TestMultiLineLint( + """ + template + class Class { + void Function() { + variable &= ~Type{0} - 1; + } + };""", + '') + self.TestMultiLineLint( + """ + namespace { + template + class Class { + void Function() { + if (block) { + variable &= ~Type{0} - 1; + } + } + }; + }""", + '') + + # Test taking address of casts (runtime/casting) + def testRuntimeCasting(self): + error_msg = ('Are you taking an address of a cast? ' + 'This is dangerous: could be a temp var. ' + 'Take the address before doing the cast, rather than after' + ' [runtime/casting] [4]') + self.TestLint('int* x = &static_cast(foo);', error_msg) + self.TestLint('int* x = &reinterpret_cast(foo);', error_msg) + self.TestLint('int* x = &(int*)foo;', + ['Using C-style cast. Use reinterpret_cast(...) ' + 'instead [readability/casting] [4]', + error_msg]) + self.TestLint('BudgetBuckets&(BudgetWinHistory::*BucketFn)(void) const;', + '') + self.TestLint('&(*func_ptr)(arg)', '') + self.TestLint('Compute(arg, &(*func_ptr)(i, j));', '') + + # Alternative error message + alt_error_msg = ('Are you taking an address of something dereferenced ' + 'from a cast? Wrapping the dereferenced expression in ' + 'parentheses will make the binding more obvious' + ' [readability/casting] [4]') + self.TestLint('int* x = &down_cast(obj)->member_;', alt_error_msg) + self.TestLint('int* x = &down_cast(obj)[index];', alt_error_msg) + self.TestLint('int* x = &(down_cast(obj)->member_);', '') + self.TestLint('int* x = &(down_cast(obj)[index]);', '') + self.TestLint('int* x = &down_cast(obj)\n->member_;', alt_error_msg) + self.TestLint('int* x = &(down_cast(obj)\n->member_);', '') + + # It's OK to cast an address. + self.TestLint('int* x = reinterpret_cast(&foo);', '') + + # Function pointers returning references should not be confused + # with taking address of old-style casts. + self.TestLint('auto x = implicit_cast(&foo);', '') + + def testRuntimeSelfinit(self): + self.TestLint( + 'Foo::Foo(Bar r, Bel l) : r_(r_), l_(l_) { }', + 'You seem to be initializing a member variable with itself.' + ' [runtime/init] [4]') + self.TestLint( + 'Foo::Foo(Bar r, Bel l) : r_(CHECK_NOTNULL(r_)) { }', + 'You seem to be initializing a member variable with itself.' + ' [runtime/init] [4]') + self.TestLint( + 'Foo::Foo(Bar r, Bel l) : r_(r), l_(l) { }', + '') + self.TestLint( + 'Foo::Foo(Bar r) : r_(r), l_(r_), ll_(l_) { }', + '') + + # Test for unnamed arguments in a method. + def testCheckForUnnamedParams(self): + self.TestLint('virtual void Func(int*) const;', '') + self.TestLint('virtual void Func(int*);', '') + self.TestLint('void Method(char*) {', '') + self.TestLint('void Method(char*);', '') + self.TestLint('static void operator delete[](void*) throw();', '') + self.TestLint('int Method(int);', '') + + self.TestLint('virtual void Func(int* p);', '') + self.TestLint('void operator delete(void* x) throw();', '') + self.TestLint('void Method(char* x) {', '') + self.TestLint('void Method(char* /*x*/) {', '') + self.TestLint('void Method(char* x);', '') + self.TestLint('typedef void (*Method)(int32 x);', '') + self.TestLint('static void operator delete[](void* x) throw();', '') + self.TestLint('static void operator delete[](void* /*x*/) throw();', '') + + self.TestLint('X operator++(int);', '') + self.TestLint('X operator++(int) {', '') + self.TestLint('X operator--(int);', '') + self.TestLint('X operator--(int /*unused*/) {', '') + self.TestLint('MACRO(int);', '') + self.TestLint('MACRO(func(int));', '') + self.TestLint('MACRO(arg, func(int));', '') + + self.TestLint('void (*func)(void*);', '') + self.TestLint('void Func((*func)(void*)) {}', '') + self.TestLint('template void func();', '') + self.TestLint('virtual void f(int /*unused*/) {', '') + self.TestLint('void f(int /*unused*/) override {', '') + self.TestLint('void f(int /*unused*/) final {', '') + + # Test deprecated casts such as int(d) + def testDeprecatedCast(self): + self.TestLint( + 'int a = int(2.2);', + 'Using deprecated casting style. ' + 'Use static_cast(...) instead' + ' [readability/casting] [4]') + + self.TestLint( + '(char *) "foo"', + 'Using C-style cast. ' + 'Use const_cast(...) instead' + ' [readability/casting] [4]') + + self.TestLint( + '(int*)foo', + 'Using C-style cast. ' + 'Use reinterpret_cast(...) instead' + ' [readability/casting] [4]') + + # Checks for false positives... + self.TestLint('int a = int();', '') # constructor + self.TestLint('X::X() : a(int()) {}', '') # default constructor + self.TestLint('operator bool();', '') # Conversion operator + self.TestLint('new int64(123);', '') # "new" operator on basic type + self.TestLint('new int64(123);', '') # "new" operator on basic type + self.TestLint('new const int(42);', '') # "new" on const-qualified type + self.TestLint('using a = bool(int arg);', '') # C++11 alias-declaration + self.TestLint('x = bit_cast(y);', '') # array of array + self.TestLint('void F(const char(&src)[N]);', '') # array of references + + # Placement new + self.TestLint( + 'new(field_ptr) int(field->default_value_enum()->number());', + '') + + # C++11 function wrappers + self.TestLint('std::function', '') + self.TestLint('std::function', '') + self.TestLint('std::function< int(bool) >', '') + self.TestLint('mfunction', '') + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'test.cc', 'cc', + ['// Copyright 2014 Your Company. All Rights Reserved.', + 'typedef std::function<', + ' bool(int)> F;', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + # Return types for function pointers + self.TestLint('typedef bool(FunctionPointer)();', '') + self.TestLint('typedef bool(FunctionPointer)(int param);', '') + self.TestLint('typedef bool(MyClass::*MemberFunctionPointer)();', '') + self.TestLint('typedef bool(MyClass::* MemberFunctionPointer)();', '') + self.TestLint('typedef bool(MyClass::*MemberFunctionPointer)() const;', '') + self.TestLint('void Function(bool(FunctionPointerArg)());', '') + self.TestLint('void Function(bool(FunctionPointerArg)()) {}', '') + self.TestLint('typedef set SortedIdSet', '') + self.TestLint( + 'bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *t)) {}', + '') + + # The second parameter to a gMock method definition is a function signature + # that often looks like a bad cast but should not picked up by lint. + def testMockMethod(self): + self.TestLint( + 'MOCK_METHOD0(method, int());', + '') + self.TestLint( + 'MOCK_CONST_METHOD1(method, float(string));', + '') + self.TestLint( + 'MOCK_CONST_METHOD2_T(method, double(float, float));', + '') + self.TestLint( + 'MOCK_CONST_METHOD1(method, SomeType(int));', + '') + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('mock.cc', 'cc', + ['MOCK_METHOD1(method1,', + ' bool(int));', + 'MOCK_METHOD1(', + ' method2,', + ' bool(int));', + 'MOCK_CONST_METHOD2(', + ' method3, bool(int,', + ' int));', + 'MOCK_METHOD1(method4, int(bool));', + 'const int kConstant = int(42);'], # true positive + error_collector) + self.assertEquals( + 0, + error_collector.Results().count( + ('Using deprecated casting style. ' + 'Use static_cast(...) instead ' + '[readability/casting] [4]'))) + self.assertEquals( + 1, + error_collector.Results().count( + ('Using deprecated casting style. ' + 'Use static_cast(...) instead ' + '[readability/casting] [4]'))) + + # Like gMock method definitions, MockCallback instantiations look very similar + # to bad casts. + def testMockCallback(self): + self.TestLint( + 'MockCallback', + '') + self.TestLint( + 'MockCallback', + '') + + # Test false errors that happened with some include file names + def testIncludeFilenameFalseError(self): + self.TestLint( + '#include "foo/long-foo.h"', + '') + self.TestLint( + '#include "foo/sprintf.h"', + '') + + # Test typedef cases. There was a bug that cpplint misidentified + # typedef for pointer to function as C-style cast and produced + # false-positive error messages. + def testTypedefForPointerToFunction(self): + self.TestLint( + 'typedef void (*Func)(int x);', + '') + self.TestLint( + 'typedef void (*Func)(int *x);', + '') + self.TestLint( + 'typedef void Func(int x);', + '') + self.TestLint( + 'typedef void Func(int *x);', + '') + + def testIncludeWhatYouUseNoImplementationFiles(self): + code = 'std::vector foo;' + self.assertEquals('Add #include for vector<>' + ' [build/include_what_you_use] [4]', + self.PerformIncludeWhatYouUse(code, 'foo.h')) + self.assertEquals('', + self.PerformIncludeWhatYouUse(code, 'foo.cc')) + + def testIncludeWhatYouUse(self): + self.TestIncludeWhatYouUse( + """#include + std::vector foo; + """, + '') + self.TestIncludeWhatYouUse( + """#include + std::pair foo; + """, + 'Add #include for pair<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + std::pair foo; + """, + 'Add #include for pair<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + std::pair foo; + """, + 'Add #include for pair<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + auto foo = std::make_pair(1, 2); + """, + 'Add #include for make_pair' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + std::pair foo; + """, + '') + self.TestIncludeWhatYouUse( + """#include + DECLARE_string(foobar); + """, + '') + self.TestIncludeWhatYouUse( + """#include + DEFINE_string(foobar, "", ""); + """, + '') + self.TestIncludeWhatYouUse( + """#include + std::pair foo; + """, + 'Add #include for pair<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + std::vector foo; + """, + 'Add #include for vector<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + std::set foo; + """, + 'Add #include for set<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + hash_map foobar; + """, + 'Add #include for hash_map<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include "base/containers/hash_tables.h" + base::hash_map foobar; + """, + '') + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + bool foobar = std::less(0,1); + """, + 'Add #include for less<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + bool foobar = min(0,1); + """, + 'Add #include for min [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + 'void a(const string &foobar);', + 'Add #include for string [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + 'void a(const std::string &foobar);', + 'Add #include for string [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + 'void a(const my::string &foobar);', + '') # Avoid false positives on strings in other namespaces. + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + bool foobar = swap(0,1); + """, + 'Add #include for swap [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + bool foobar = transform(a.begin(), a.end(), b.start(), Foo); + """, + 'Add #include for transform ' + '[build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include "base/foobar.h" + bool foobar = min_element(a.begin(), a.end()); + """, + 'Add #include for min_element ' + '[build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """foo->swap(0,1); + foo.swap(0,1); + """, + '') + self.TestIncludeWhatYouUse( + """#include + void a(const std::multimap &foobar); + """, + 'Add #include for multimap<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + void a(const std::unordered_map &foobar); + """, + 'Add #include for unordered_map<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + void a(const std::unordered_set &foobar); + """, + 'Add #include for unordered_set<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + void a(const std::priority_queue &foobar); + """, + '') + self.TestIncludeWhatYouUse( + """#include + #include + #include + #include "base/basictypes.h" + #include "base/port.h" + vector hajoa;""", '') + self.TestIncludeWhatYouUse( + """#include + int i = numeric_limits::max() + """, + 'Add #include for numeric_limits<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + int i = numeric_limits::max() + """, + '') + self.TestIncludeWhatYouUse( + """#include + std::unique_ptr x; + """, + 'Add #include for unique_ptr<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + auto x = std::make_unique(0); + """, + 'Add #include for make_unique<>' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + vector foo(vector x) { return std::move(x); } + """, + 'Add #include for move' + ' [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + """#include + int a, b; + std::swap(a, b); + """, + 'Add #include for swap' + ' [build/include_what_you_use] [4]') + + # Test the UpdateIncludeState code path. + mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"'] + message = self.PerformIncludeWhatYouUse( + '#include "blah/a.h"', + filename='blah/a.cc', + io=MockIo(mock_header_contents)) + self.assertEquals(message, '') + + mock_header_contents = ['#include '] + message = self.PerformIncludeWhatYouUse( + """#include "blah/a.h" + std::set foo;""", + filename='blah/a.cc', + io=MockIo(mock_header_contents)) + self.assertEquals(message, '') + + # Make sure we can find the correct header file if the cc file seems to be + # a temporary file generated by Emacs's flymake. + mock_header_contents = [''] + message = self.PerformIncludeWhatYouUse( + """#include "blah/a.h" + std::set foo;""", + filename='blah/a_flymake.cc', + io=MockIo(mock_header_contents)) + self.assertEquals(message, 'Add #include for set<> ' + '[build/include_what_you_use] [4]') + + # If there's just a cc and the header can't be found then it's ok. + message = self.PerformIncludeWhatYouUse( + """#include "blah/a.h" + std::set foo;""", + filename='blah/a.cc') + self.assertEquals(message, '') + + # Make sure we find the headers with relative paths. + mock_header_contents = [''] + message = self.PerformIncludeWhatYouUse( + """#include "%s/a.h" + std::set foo;""" % os.path.basename(os.getcwd()), + filename='a.cc', + io=MockIo(mock_header_contents)) + self.assertEquals(message, 'Add #include for set<> ' + '[build/include_what_you_use] [4]') + + def testFilesBelongToSameModule(self): + f = cpplint.FilesBelongToSameModule + self.assertEquals((True, ''), f('a.cc', 'a.h')) + self.assertEquals((True, ''), f('base/google.cc', 'base/google.h')) + self.assertEquals((True, ''), f('base/google_test.cc', 'base/google.h')) + self.assertEquals((True, ''), + f('base/google_unittest.cc', 'base/google.h')) + self.assertEquals((True, ''), + f('base/internal/google_unittest.cc', + 'base/public/google.h')) + self.assertEquals((True, 'xxx/yyy/'), + f('xxx/yyy/base/internal/google_unittest.cc', + 'base/public/google.h')) + self.assertEquals((True, 'xxx/yyy/'), + f('xxx/yyy/base/google_unittest.cc', + 'base/public/google.h')) + self.assertEquals((True, ''), + f('base/google_unittest.cc', 'base/google-inl.h')) + self.assertEquals((True, '/home/build/google3/'), + f('/home/build/google3/base/google.cc', 'base/google.h')) + + self.assertEquals((False, ''), + f('/home/build/google3/base/google.cc', 'basu/google.h')) + self.assertEquals((False, ''), f('a.cc', 'b.h')) + + def testCleanseLine(self): + self.assertEquals('int foo = 0;', + cpplint.CleanseComments('int foo = 0; // danger!')) + self.assertEquals('int o = 0;', + cpplint.CleanseComments('int /* foo */ o = 0;')) + self.assertEquals('foo(int a, int b);', + cpplint.CleanseComments('foo(int a /* abc */, int b);')) + self.assertEqual('f(a, b);', + cpplint.CleanseComments('f(a, /* name */ b);')) + self.assertEqual('f(a, b);', + cpplint.CleanseComments('f(a /* name */, b);')) + self.assertEqual('f(a, b);', + cpplint.CleanseComments('f(a, /* name */b);')) + self.assertEqual('f(a, b, c);', + cpplint.CleanseComments('f(a, /**/b, /**/c);')) + self.assertEqual('f(a, b, c);', + cpplint.CleanseComments('f(a, /**/b/**/, c);')) + + def testRawStrings(self): + self.TestMultiLineLint( + """ + void Func() { + static const char kString[] = R"( + #endif <- invalid preprocessor should be ignored + */ <- invalid comment should be ignored too + )"; + }""", + '') + self.TestMultiLineLint( + """ + void Func() { + string s = R"TrueDelimiter( + )" + )FalseDelimiter" + )TrueDelimiter"; + }""", + '') + self.TestMultiLineLint( + """ + void Func() { + char char kString[] = R"( ";" )"; + }""", + '') + self.TestMultiLineLint( + """ + static const char kRawString[] = R"( + \tstatic const int kLineWithTab = 1; + static const int kLineWithTrailingWhiteSpace = 1;\x20 + + void WeirdNumberOfSpacesAtLineStart() { + string x; + x += StrCat("Use StrAppend instead"); + } + + void BlankLineAtEndOfBlock() { + // TODO incorrectly formatted + //Badly formatted comment + + } + + )";""", + '') + self.TestMultiLineLint( + """ + void Func() { + string s = StrCat(R"TrueDelimiter( + )" + )FalseDelimiter" + )TrueDelimiter", R"TrueDelimiter2( + )" + )FalseDelimiter2" + )TrueDelimiter2"); + }""", + '') + self.TestMultiLineLint( + """ + static SomeStruct kData = { + {0, R"(line1 + line2 + )"} + };""", + '') + + def testMultiLineComments(self): + # missing explicit is bad + self.TestMultiLineLint( + r"""int a = 0; + /* multi-liner + class Foo { + Foo(int f); // should cause a lint warning in code + } + */ """, + '') + self.TestMultiLineLint( + r"""/* int a = 0; multi-liner + static const int b = 0;""", + 'Could not find end of multi-line comment' + ' [readability/multiline_comment] [5]') + self.TestMultiLineLint(r""" /* multi-line comment""", + 'Could not find end of multi-line comment' + ' [readability/multiline_comment] [5]') + self.TestMultiLineLint(r""" // /* comment, but not multi-line""", '') + self.TestMultiLineLint(r"""/********** + */""", '') + self.TestMultiLineLint(r"""/** + * Doxygen comment + */""", + '') + self.TestMultiLineLint(r"""/*! + * Doxygen comment + */""", + '') + + def testMultilineStrings(self): + multiline_string_error_message = ( + 'Multi-line string ("...") found. This lint script doesn\'t ' + 'do well with such strings, and may give bogus warnings. ' + 'Use C++11 raw strings or concatenation instead.' + ' [readability/multiline_string] [5]') + + file_path = 'mydir/foo.cc' + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'cc', + ['const char* str = "This is a\\', + ' multiline string.";'], + error_collector) + self.assertEquals( + 2, # One per line. + error_collector.ResultList().count(multiline_string_error_message)) + + # Test non-explicit single-argument constructors + def testExplicitSingleArgumentConstructors(self): + old_verbose_level = cpplint._cpplint_state.verbose_level + cpplint._cpplint_state.verbose_level = 0 + + try: + # missing explicit is bad + self.TestMultiLineLint( + """ + class Foo { + Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # missing explicit is bad, even with whitespace + self.TestMultiLineLint( + """ + class Foo { + Foo (int f); + };""", + ['Extra space before ( in function call [whitespace/parens] [4]', + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]']) + # missing explicit, with distracting comment, is still bad + self.TestMultiLineLint( + """ + class Foo { + Foo(int f); // simpler than Foo(blargh, blarg) + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # missing explicit, with qualified classname + self.TestMultiLineLint( + """ + class Qualifier::AnotherOne::Foo { + Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # missing explicit for inline constructors is bad as well + self.TestMultiLineLint( + """ + class Foo { + inline Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # missing explicit for constexpr constructors is bad as well + self.TestMultiLineLint( + """ + class Foo { + constexpr Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # missing explicit for constexpr+inline constructors is bad as well + self.TestMultiLineLint( + """ + class Foo { + constexpr inline Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + self.TestMultiLineLint( + """ + class Foo { + inline constexpr Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # explicit with inline is accepted + self.TestMultiLineLint( + """ + class Foo { + inline explicit Foo(int f); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + explicit inline Foo(int f); + };""", + '') + # explicit with constexpr is accepted + self.TestMultiLineLint( + """ + class Foo { + constexpr explicit Foo(int f); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + explicit constexpr Foo(int f); + };""", + '') + # explicit with constexpr+inline is accepted + self.TestMultiLineLint( + """ + class Foo { + inline constexpr explicit Foo(int f); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + explicit inline constexpr Foo(int f); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + constexpr inline explicit Foo(int f); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + explicit constexpr inline Foo(int f); + };""", + '') + # structs are caught as well. + self.TestMultiLineLint( + """ + struct Foo { + Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # Templatized classes are caught as well. + self.TestMultiLineLint( + """ + template class Foo { + Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # inline case for templatized classes. + self.TestMultiLineLint( + """ + template class Foo { + inline Foo(int f); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # constructors with a default argument should still be marked explicit + self.TestMultiLineLint( + """ + class Foo { + Foo(int f = 0); + };""", + 'Constructors callable with one argument should be marked explicit.' + ' [runtime/explicit] [5]') + # multi-argument constructors with all but one default argument should be + # marked explicit + self.TestMultiLineLint( + """ + class Foo { + Foo(int f, int g = 0); + };""", + 'Constructors callable with one argument should be marked explicit.' + ' [runtime/explicit] [5]') + # multi-argument constructors with all default arguments should be marked + # explicit + self.TestMultiLineLint( + """ + class Foo { + Foo(int f = 0, int g = 0); + };""", + 'Constructors callable with one argument should be marked explicit.' + ' [runtime/explicit] [5]') + # explicit no-argument constructors are bad + self.TestMultiLineLint( + """ + class Foo { + explicit Foo(); + };""", + 'Zero-parameter constructors should not be marked explicit.' + ' [runtime/explicit] [5]') + # void constructors are considered no-argument + self.TestMultiLineLint( + """ + class Foo { + explicit Foo(void); + };""", + 'Zero-parameter constructors should not be marked explicit.' + ' [runtime/explicit] [5]') + # No warning for multi-parameter constructors + self.TestMultiLineLint( + """ + class Foo { + explicit Foo(int f, int g); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + explicit Foo(int f, int g = 0); + };""", + '') + # single-argument constructors that take a function that takes multiple + # arguments should be explicit + self.TestMultiLineLint( + """ + class Foo { + Foo(void (*f)(int f, int g)); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # single-argument constructors that take a single template argument with + # multiple parameters should be explicit + self.TestMultiLineLint( + """ + template + class Foo { + Foo(Bar b); + };""", + 'Single-parameter constructors should be marked explicit.' + ' [runtime/explicit] [5]') + # but copy constructors that take multiple template parameters are OK + self.TestMultiLineLint( + """ + template + class Foo { + Foo(Foo& f); + };""", + '') + # proper style is okay + self.TestMultiLineLint( + """ + class Foo { + explicit Foo(int f); + };""", + '') + # two argument constructor is okay + self.TestMultiLineLint( + """ + class Foo { + Foo(int f, int b); + };""", + '') + # two argument constructor, across two lines, is okay + self.TestMultiLineLint( + """ + class Foo { + Foo(int f, + int b); + };""", + '') + # non-constructor (but similar name), is okay + self.TestMultiLineLint( + """ + class Foo { + aFoo(int f); + };""", + '') + # constructor with void argument is okay + self.TestMultiLineLint( + """ + class Foo { + Foo(void); + };""", + '') + # single argument method is okay + self.TestMultiLineLint( + """ + class Foo { + Bar(int b); + };""", + '') + # comments should be ignored + self.TestMultiLineLint( + """ + class Foo { + // Foo(int f); + };""", + '') + # single argument function following class definition is okay + # (okay, it's not actually valid, but we don't want a false positive) + self.TestMultiLineLint( + """ + class Foo { + Foo(int f, int b); + }; + Foo(int f);""", + '') + # single argument function is okay + self.TestMultiLineLint( + """static Foo(int f);""", + '') + # single argument copy constructor is okay. + self.TestMultiLineLint( + """ + class Foo { + Foo(const Foo&); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + Foo(Foo const&); + };""", + '') + self.TestMultiLineLint( + """ + class Foo { + Foo(Foo&); + };""", + '') + # templatized copy constructor is okay. + self.TestMultiLineLint( + """ + template class Foo { + Foo(const Foo&); + };""", + '') + # Special case for std::initializer_list + self.TestMultiLineLint( + """ + class Foo { + Foo(std::initializer_list &arg) {} + };""", + '') + # Anything goes inside an assembly block + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['void Func() {', + ' __asm__ (', + ' "hlt"', + ' );', + ' asm {', + ' movdqa [edx + 32], xmm2', + ' }', + '}'], + error_collector) + self.assertEquals( + 0, + error_collector.ResultList().count( + 'Extra space before ( in function call [whitespace/parens] [4]')) + self.assertEquals( + 0, + error_collector.ResultList().count( + 'Closing ) should be moved to the previous line ' + '[whitespace/parens] [2]')) + self.assertEquals( + 0, + error_collector.ResultList().count( + 'Extra space before [ [whitespace/braces] [5]')) + finally: + cpplint._cpplint_state.verbose_level = old_verbose_level + + def testSlashStarCommentOnSingleLine(self): + self.TestMultiLineLint( + """/* static */ Foo(int f);""", + '') + self.TestMultiLineLint( + """/*/ static */ Foo(int f);""", + '') + self.TestMultiLineLint( + """/*/ static Foo(int f);""", + 'Could not find end of multi-line comment' + ' [readability/multiline_comment] [5]') + self.TestMultiLineLint( + """ /*/ static Foo(int f);""", + 'Could not find end of multi-line comment' + ' [readability/multiline_comment] [5]') + self.TestMultiLineLint( + """ /**/ static Foo(int f);""", + '') + + # Test suspicious usage of "if" like this: + # if (a == b) { + # DoSomething(); + # } if (a == c) { // Should be "else if". + # DoSomething(); // This gets called twice if a == b && a == c. + # } + def testSuspiciousUsageOfIf(self): + self.TestLint( + ' if (a == b) {', + '') + self.TestLint( + ' } if (a == b) {', + 'Did you mean "else if"? If not, start a new line for "if".' + ' [readability/braces] [4]') + + # Test suspicious usage of memset. Specifically, a 0 + # as the final argument is almost certainly an error. + def testSuspiciousUsageOfMemset(self): + # Normal use is okay. + self.TestLint( + ' memset(buf, 0, sizeof(buf))', + '') + + # A 0 as the final argument is almost certainly an error. + self.TestLint( + ' memset(buf, sizeof(buf), 0)', + 'Did you mean "memset(buf, 0, sizeof(buf))"?' + ' [runtime/memset] [4]') + self.TestLint( + ' memset(buf, xsize * ysize, 0)', + 'Did you mean "memset(buf, 0, xsize * ysize)"?' + ' [runtime/memset] [4]') + + # There is legitimate test code that uses this form. + # This is okay since the second argument is a literal. + self.TestLint( + " memset(buf, 'y', 0)", + '') + self.TestLint( + ' memset(buf, 4, 0)', + '') + self.TestLint( + ' memset(buf, -1, 0)', + '') + self.TestLint( + ' memset(buf, 0xF1, 0)', + '') + self.TestLint( + ' memset(buf, 0xcd, 0)', + '') + + def testRedundantVirtual(self): + self.TestLint('virtual void F()', '') + self.TestLint('virtual void F();', '') + self.TestLint('virtual void F() {}', '') + + message_template = ('"%s" is redundant since function is already ' + 'declared as "%s" [readability/inheritance] [4]') + for virt_specifier in ['override', 'final']: + error_message = message_template % ('virtual', virt_specifier) + self.TestLint('virtual int F() %s' % virt_specifier, error_message) + self.TestLint('virtual int F() %s;' % virt_specifier, error_message) + self.TestLint('virtual int F() %s {' % virt_specifier, error_message) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'virtual void F(int a,', + ' int b) ' + virt_specifier + ';', + 'virtual void F(int a,', + ' int b) LOCKS_EXCLUDED(lock) ' + virt_specifier + ';', + 'virtual void F(int a,', + ' int b)', + ' LOCKS_EXCLUDED(lock) ' + virt_specifier + ';', + ''], + error_collector) + self.assertEquals( + [error_message, error_message, error_message], + error_collector.Results()) + + error_message = message_template % ('override', 'final') + self.TestLint('int F() override final', error_message) + self.TestLint('int F() override final;', error_message) + self.TestLint('int F() override final {}', error_message) + self.TestLint('int F() final override', error_message) + self.TestLint('int F() final override;', error_message) + self.TestLint('int F() final override {}', error_message) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'struct A : virtual B {', + ' ~A() override;' + '};', + 'class C', + ' : public D,', + ' public virtual E {', + ' void Func() override;', + '}', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + self.TestLint('void Finalize(AnnotationProto *final) override;', '') + + def testCheckDeprecated(self): + self.TestLanguageRulesCheck('foo_test.cc', '#include ', '') + self.TestLanguageRulesCheck('foo_unittest.cc', '#include ', '') + + def testCheckPosixThreading(self): + self.TestLint('var = sctime_r()', '') + self.TestLint('var = strtok_r()', '') + self.TestLint('var = strtok_r(foo, ba, r)', '') + self.TestLint('var = brand()', '') + self.TestLint('_rand()', '') + self.TestLint('.rand()', '') + self.TestLint('->rand()', '') + self.TestLint('ACMRandom rand(seed)', '') + self.TestLint('ISAACRandom rand()', '') + self.TestLint('var = rand()', + 'Consider using rand_r(...) instead of rand(...)' + ' for improved thread safety.' + ' [runtime/threadsafe_fn] [2]') + self.TestLint('var = strtok(str, delim)', + 'Consider using strtok_r(...) ' + 'instead of strtok(...)' + ' for improved thread safety.' + ' [runtime/threadsafe_fn] [2]') + + def testVlogMisuse(self): + self.TestLint('VLOG(1)', '') + self.TestLint('VLOG(99)', '') + self.TestLint('LOG(ERROR)', '') + self.TestLint('LOG(INFO)', '') + self.TestLint('LOG(WARNING)', '') + self.TestLint('LOG(FATAL)', '') + self.TestLint('LOG(DFATAL)', '') + self.TestLint('VLOG(SOMETHINGWEIRD)', '') + self.TestLint('MYOWNVLOG(ERROR)', '') + errmsg = ('VLOG() should be used with numeric verbosity level. ' + 'Use LOG() if you want symbolic severity levels.' + ' [runtime/vlog] [5]') + self.TestLint('VLOG(ERROR)', errmsg) + self.TestLint('VLOG(INFO)', errmsg) + self.TestLint('VLOG(WARNING)', errmsg) + self.TestLint('VLOG(FATAL)', errmsg) + self.TestLint('VLOG(DFATAL)', errmsg) + self.TestLint(' VLOG(ERROR)', errmsg) + self.TestLint(' VLOG(INFO)', errmsg) + self.TestLint(' VLOG(WARNING)', errmsg) + self.TestLint(' VLOG(FATAL)', errmsg) + self.TestLint(' VLOG(DFATAL)', errmsg) + + + # Test potential format string bugs like printf(foo). + def testFormatStrings(self): + self.TestLint('printf("foo")', '') + self.TestLint('printf("foo: %s", foo)', '') + self.TestLint('DocidForPrintf(docid)', '') # Should not trigger. + self.TestLint('printf(format, value)', '') # Should not trigger. + self.TestLint('printf(__VA_ARGS__)', '') # Should not trigger. + self.TestLint('printf(format.c_str(), value)', '') # Should not trigger. + self.TestLint('printf(format(index).c_str(), value)', '') + self.TestLint( + 'printf(foo)', + 'Potential format string bug. Do printf("%s", foo) instead.' + ' [runtime/printf] [4]') + self.TestLint( + 'printf(foo.c_str())', + 'Potential format string bug. ' + 'Do printf("%s", foo.c_str()) instead.' + ' [runtime/printf] [4]') + self.TestLint( + 'printf(foo->c_str())', + 'Potential format string bug. ' + 'Do printf("%s", foo->c_str()) instead.' + ' [runtime/printf] [4]') + self.TestLint( + 'StringPrintf(foo)', + 'Potential format string bug. Do StringPrintf("%s", foo) instead.' + '' + ' [runtime/printf] [4]') + + # Test disallowed use of operator& and other operators. + def testIllegalOperatorOverloading(self): + errmsg = ('Unary operator& is dangerous. Do not use it.' + ' [runtime/operator] [4]') + self.TestLint('void operator=(const Myclass&)', '') + self.TestLint('void operator&(int a, int b)', '') # binary operator& ok + self.TestLint('void operator&() { }', errmsg) + self.TestLint('void operator & ( ) { }', + ['Extra space after ( [whitespace/parens] [2]', errmsg]) + + # const string reference members are dangerous.. + def testConstStringReferenceMembers(self): + errmsg = ('const string& members are dangerous. It is much better to use ' + 'alternatives, such as pointers or simple constants.' + ' [runtime/member_string_references] [2]') + + members_declarations = ['const string& church', + 'const string &turing', + 'const string & godel'] + # TODO(unknown): Enable also these tests if and when we ever + # decide to check for arbitrary member references. + # "const Turing & a", + # "const Church& a", + # "const vector& a", + # "const Kurt::Godel & godel", + # "const Kazimierz::Kuratowski& kk" ] + + # The Good. + + self.TestLint('void f(const string&)', '') + self.TestLint('const string& f(const string& a, const string& b)', '') + self.TestLint('typedef const string& A;', '') + + for decl in members_declarations: + self.TestLint(decl + ' = b;', '') + self.TestLint(decl + ' =', '') + + # The Bad. + + for decl in members_declarations: + self.TestLint(decl + ';', errmsg) + + # Variable-length arrays are not permitted. + def testVariableLengthArrayDetection(self): + errmsg = ('Do not use variable-length arrays. Use an appropriately named ' + "('k' followed by CamelCase) compile-time constant for the size." + ' [runtime/arrays] [1]') + + self.TestLint('int a[any_old_variable];', errmsg) + self.TestLint('int doublesize[some_var * 2];', errmsg) + self.TestLint('int a[afunction()];', errmsg) + self.TestLint('int a[function(kMaxFooBars)];', errmsg) + self.TestLint('bool a_list[items_->size()];', errmsg) + self.TestLint('namespace::Type buffer[len+1];', errmsg) + + self.TestLint('int a[64];', '') + self.TestLint('int a[0xFF];', '') + self.TestLint('int first[256], second[256];', '') + self.TestLint('int array_name[kCompileTimeConstant];', '') + self.TestLint('char buf[somenamespace::kBufSize];', '') + self.TestLint('int array_name[ALL_CAPS];', '') + self.TestLint('AClass array1[foo::bar::ALL_CAPS];', '') + self.TestLint('int a[kMaxStrLen + 1];', '') + self.TestLint('int a[sizeof(foo)];', '') + self.TestLint('int a[sizeof(*foo)];', '') + self.TestLint('int a[sizeof foo];', '') + self.TestLint('int a[sizeof(struct Foo)];', '') + self.TestLint('int a[128 - sizeof(const bar)];', '') + self.TestLint('int a[(sizeof(foo) * 4)];', '') + self.TestLint('int a[(arraysize(fixed_size_array)/2) << 1];', '') + self.TestLint('delete a[some_var];', '') + self.TestLint('return a[some_var];', '') + + # DISALLOW_COPY_AND_ASSIGN and DISALLOW_IMPLICIT_CONSTRUCTORS should be at + # end of class if present. + def testDisallowMacrosAtEnd(self): + for macro_name in ( + 'DISALLOW_COPY_AND_ASSIGN', + 'DISALLOW_IMPLICIT_CONSTRUCTORS'): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'class SomeClass {', + ' private:', + ' %s(SomeClass);' % macro_name, + ' int member_;', + '};', + ''], + error_collector) + self.assertEquals( + ('%s should be the last thing in the class' % macro_name) + + ' [readability/constructors] [3]', + error_collector.Results()) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'class OuterClass {', + ' private:', + ' struct InnerClass {', + ' private:', + ' %s(InnerClass);' % macro_name, + ' int member;', + ' };', + '};', + ''], + error_collector) + self.assertEquals( + ('%s should be the last thing in the class' % macro_name) + + ' [readability/constructors] [3]', + error_collector.Results()) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'class OuterClass1 {', + ' private:', + ' struct InnerClass1 {', + ' private:', + ' %s(InnerClass1);' % macro_name, + ' };', + ' %s(OuterClass1);' % macro_name, + '};', + 'struct OuterClass2 {', + ' private:', + ' class InnerClass2 {', + ' private:', + ' %s(InnerClass2);' % macro_name, + ' // comment', + ' };', + '', + ' %s(OuterClass2);' % macro_name, + '', + ' // comment', + '};', + 'void Func() {', + ' struct LocalClass {', + ' private:', + ' %s(LocalClass);' % macro_name, + ' } variable;', + '}', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + # Brace usage + def testBraces(self): + # Braces shouldn't be followed by a ; unless they're defining a struct + # or initializing an array + self.TestLint('int a[3] = { 1, 2, 3 };', '') + self.TestLint( + """const int foo[] = + {1, 2, 3 };""", + '') + # For single line, unmatched '}' with a ';' is ignored (not enough context) + self.TestMultiLineLint( + """int a[3] = { 1, + 2, + 3 };""", + '') + self.TestMultiLineLint( + """int a[2][3] = { { 1, 2 }, + { 3, 4 } };""", + '') + self.TestMultiLineLint( + """int a[2][3] = + { { 1, 2 }, + { 3, 4 } };""", + '') + + # CHECK/EXPECT_TRUE/EXPECT_FALSE replacements + def testCheckCheck(self): + self.TestLint('CHECK(x == 42);', + 'Consider using CHECK_EQ instead of CHECK(a == b)' + ' [readability/check] [2]') + self.TestLint('CHECK(x != 42);', + 'Consider using CHECK_NE instead of CHECK(a != b)' + ' [readability/check] [2]') + self.TestLint('CHECK(x >= 42);', + 'Consider using CHECK_GE instead of CHECK(a >= b)' + ' [readability/check] [2]') + self.TestLint('CHECK(x > 42);', + 'Consider using CHECK_GT instead of CHECK(a > b)' + ' [readability/check] [2]') + self.TestLint('CHECK(x <= 42);', + 'Consider using CHECK_LE instead of CHECK(a <= b)' + ' [readability/check] [2]') + self.TestLint('CHECK(x < 42);', + 'Consider using CHECK_LT instead of CHECK(a < b)' + ' [readability/check] [2]') + + self.TestLint('DCHECK(x == 42);', + 'Consider using DCHECK_EQ instead of DCHECK(a == b)' + ' [readability/check] [2]') + self.TestLint('DCHECK(x != 42);', + 'Consider using DCHECK_NE instead of DCHECK(a != b)' + ' [readability/check] [2]') + self.TestLint('DCHECK(x >= 42);', + 'Consider using DCHECK_GE instead of DCHECK(a >= b)' + ' [readability/check] [2]') + self.TestLint('DCHECK(x > 42);', + 'Consider using DCHECK_GT instead of DCHECK(a > b)' + ' [readability/check] [2]') + self.TestLint('DCHECK(x <= 42);', + 'Consider using DCHECK_LE instead of DCHECK(a <= b)' + ' [readability/check] [2]') + self.TestLint('DCHECK(x < 42);', + 'Consider using DCHECK_LT instead of DCHECK(a < b)' + ' [readability/check] [2]') + + self.TestLint( + 'EXPECT_TRUE("42" == x);', + 'Consider using EXPECT_EQ instead of EXPECT_TRUE(a == b)' + ' [readability/check] [2]') + self.TestLint( + 'EXPECT_TRUE("42" != x);', + 'Consider using EXPECT_NE instead of EXPECT_TRUE(a != b)' + ' [readability/check] [2]') + self.TestLint( + 'EXPECT_TRUE(+42 >= x);', + 'Consider using EXPECT_GE instead of EXPECT_TRUE(a >= b)' + ' [readability/check] [2]') + + self.TestLint( + 'EXPECT_FALSE(x == 42);', + 'Consider using EXPECT_NE instead of EXPECT_FALSE(a == b)' + ' [readability/check] [2]') + self.TestLint( + 'EXPECT_FALSE(x != 42);', + 'Consider using EXPECT_EQ instead of EXPECT_FALSE(a != b)' + ' [readability/check] [2]') + self.TestLint( + 'EXPECT_FALSE(x >= 42);', + 'Consider using EXPECT_LT instead of EXPECT_FALSE(a >= b)' + ' [readability/check] [2]') + self.TestLint( + 'ASSERT_FALSE(x > 42);', + 'Consider using ASSERT_LE instead of ASSERT_FALSE(a > b)' + ' [readability/check] [2]') + self.TestLint( + 'ASSERT_FALSE(x <= 42);', + 'Consider using ASSERT_GT instead of ASSERT_FALSE(a <= b)' + ' [readability/check] [2]') + + self.TestLint('CHECK(x<42);', + ['Missing spaces around <' + ' [whitespace/operators] [3]', + 'Consider using CHECK_LT instead of CHECK(a < b)' + ' [readability/check] [2]']) + self.TestLint('CHECK(x>42);', + ['Missing spaces around >' + ' [whitespace/operators] [3]', + 'Consider using CHECK_GT instead of CHECK(a > b)' + ' [readability/check] [2]']) + + self.TestLint('using some::namespace::operator<<;', '') + self.TestLint('using some::namespace::operator>>;', '') + + self.TestLint('CHECK(x->y == 42);', + 'Consider using CHECK_EQ instead of CHECK(a == b)' + ' [readability/check] [2]') + + self.TestLint( + ' EXPECT_TRUE(42 < x); // Random comment.', + 'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)' + ' [readability/check] [2]') + self.TestLint( + 'EXPECT_TRUE( 42 < x );', + ['Extra space after ( in function call' + ' [whitespace/parens] [4]', + 'Extra space before ) [whitespace/parens] [2]', + 'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)' + ' [readability/check] [2]']) + + self.TestLint('CHECK(4\'2 == x);', + 'Consider using CHECK_EQ instead of CHECK(a == b)' + ' [readability/check] [2]') + + def testCheckCheckFalsePositives(self): + self.TestLint('CHECK(some_iterator == obj.end());', '') + self.TestLint('EXPECT_TRUE(some_iterator == obj.end());', '') + self.TestLint('EXPECT_FALSE(some_iterator == obj.end());', '') + self.TestLint('CHECK(some_pointer != NULL);', '') + self.TestLint('EXPECT_TRUE(some_pointer != NULL);', '') + self.TestLint('EXPECT_FALSE(some_pointer != NULL);', '') + + self.TestLint('CHECK(CreateTestFile(dir, (1 << 20)));', '') + self.TestLint('CHECK(CreateTestFile(dir, (1 >> 20)));', '') + + self.TestLint('CHECK(x ^ (y < 42));', '') + self.TestLint('CHECK((x > 42) ^ (x < 54));', '') + self.TestLint('CHECK(a && b < 42);', '') + self.TestLint('CHECK(42 < a && a < b);', '') + self.TestLint('SOFT_CHECK(x > 42);', '') + + self.TestMultiLineLint( + """_STLP_DEFINE_BINARY_OP_CHECK(==, _OP_EQUAL); + _STLP_DEFINE_BINARY_OP_CHECK(!=, _OP_NOT_EQUAL); + _STLP_DEFINE_BINARY_OP_CHECK(<, _OP_LESS_THAN); + _STLP_DEFINE_BINARY_OP_CHECK(<=, _OP_LESS_EQUAL); + _STLP_DEFINE_BINARY_OP_CHECK(>, _OP_GREATER_THAN); + _STLP_DEFINE_BINARY_OP_CHECK(>=, _OP_GREATER_EQUAL); + _STLP_DEFINE_BINARY_OP_CHECK(+, _OP_PLUS); + _STLP_DEFINE_BINARY_OP_CHECK(*, _OP_TIMES); + _STLP_DEFINE_BINARY_OP_CHECK(/, _OP_DIVIDE); + _STLP_DEFINE_BINARY_OP_CHECK(-, _OP_SUBTRACT); + _STLP_DEFINE_BINARY_OP_CHECK(%, _OP_MOD);""", + '') + + self.TestLint('CHECK(x < 42) << "Custom error message";', '') + + # Alternative token to punctuation operator replacements + def testCheckAltTokens(self): + self.TestLint('true or true', + 'Use operator || instead of or' + ' [readability/alt_tokens] [2]') + self.TestLint('true and true', + 'Use operator && instead of and' + ' [readability/alt_tokens] [2]') + self.TestLint('if (not true)', + 'Use operator ! instead of not' + ' [readability/alt_tokens] [2]') + self.TestLint('1 bitor 1', + 'Use operator | instead of bitor' + ' [readability/alt_tokens] [2]') + self.TestLint('1 xor 1', + 'Use operator ^ instead of xor' + ' [readability/alt_tokens] [2]') + self.TestLint('1 bitand 1', + 'Use operator & instead of bitand' + ' [readability/alt_tokens] [2]') + self.TestLint('x = compl 1', + 'Use operator ~ instead of compl' + ' [readability/alt_tokens] [2]') + self.TestLint('x and_eq y', + 'Use operator &= instead of and_eq' + ' [readability/alt_tokens] [2]') + self.TestLint('x or_eq y', + 'Use operator |= instead of or_eq' + ' [readability/alt_tokens] [2]') + self.TestLint('x xor_eq y', + 'Use operator ^= instead of xor_eq' + ' [readability/alt_tokens] [2]') + self.TestLint('x not_eq y', + 'Use operator != instead of not_eq' + ' [readability/alt_tokens] [2]') + self.TestLint('line_continuation or', + 'Use operator || instead of or' + ' [readability/alt_tokens] [2]') + self.TestLint('if(true and(parentheses', + 'Use operator && instead of and' + ' [readability/alt_tokens] [2]') + + self.TestLint('#include "base/false-and-false.h"', '') + self.TestLint('#error false or false', '') + self.TestLint('false nor false', '') + self.TestLint('false nand false', '') + + # Passing and returning non-const references + def testNonConstReference(self): + # Passing a non-const reference as function parameter is forbidden. + operand_error_message = ('Is this a non-const reference? ' + 'If so, make const or use a pointer: %s' + ' [runtime/references] [2]') + # Warn of use of a non-const reference in operators and functions + self.TestLint('bool operator>(Foo& s, Foo& f);', + [operand_error_message % 'Foo& s', + operand_error_message % 'Foo& f']) + self.TestLint('bool operator+(Foo& s, Foo& f);', + [operand_error_message % 'Foo& s', + operand_error_message % 'Foo& f']) + self.TestLint('int len(Foo& s);', operand_error_message % 'Foo& s') + # Allow use of non-const references in a few specific cases + self.TestLint('stream& operator>>(stream& s, Foo& f);', '') + self.TestLint('stream& operator<<(stream& s, Foo& f);', '') + self.TestLint('void swap(Bar& a, Bar& b);', '') + self.TestLint('ostream& LogFunc(ostream& s);', '') + self.TestLint('ostringstream& LogFunc(ostringstream& s);', '') + self.TestLint('istream& LogFunc(istream& s);', '') + self.TestLint('istringstream& LogFunc(istringstream& s);', '') + # Returning a non-const reference from a function is OK. + self.TestLint('int& g();', '') + # Passing a const reference to a struct (using the struct keyword) is OK. + self.TestLint('void foo(const struct tm& tm);', '') + # Passing a const reference to a typename is OK. + self.TestLint('void foo(const typename tm& tm);', '') + # Const reference to a pointer type is OK. + self.TestLint('void foo(const Bar* const& p) {', '') + self.TestLint('void foo(Bar const* const& p) {', '') + self.TestLint('void foo(Bar* const& p) {', '') + # Const reference to a templated type is OK. + self.TestLint('void foo(const std::vector& v);', '') + # Non-const reference to a pointer type is not OK. + self.TestLint('void foo(Bar*& p);', + operand_error_message % 'Bar*& p') + self.TestLint('void foo(const Bar*& p);', + operand_error_message % 'const Bar*& p') + self.TestLint('void foo(Bar const*& p);', + operand_error_message % 'Bar const*& p') + self.TestLint('void foo(struct Bar*& p);', + operand_error_message % 'struct Bar*& p') + self.TestLint('void foo(const struct Bar*& p);', + operand_error_message % 'const struct Bar*& p') + self.TestLint('void foo(struct Bar const*& p);', + operand_error_message % 'struct Bar const*& p') + # Non-const reference to a templated type is not OK. + self.TestLint('void foo(std::vector& p);', + operand_error_message % 'std::vector& p') + # Returning an address of something is not prohibited. + self.TestLint('return &something;', '') + self.TestLint('if (condition) {return &something; }', '') + self.TestLint('if (condition) return &something;', '') + self.TestLint('if (condition) address = &something;', '') + self.TestLint('if (condition) result = lhs&rhs;', '') + self.TestLint('if (condition) result = lhs & rhs;', '') + self.TestLint('a = (b+c) * sizeof &f;', '') + self.TestLint('a = MySize(b) * sizeof &f;', '') + # We don't get confused by C++11 range-based for loops. + self.TestLint('for (const string& s : c)', '') + self.TestLint('for (auto& r : c)', '') + self.TestLint('for (typename Type& a : b)', '') + # We don't get confused by some other uses of '&'. + self.TestLint('T& operator=(const T& t);', '') + self.TestLint('int g() { return (a & b); }', '') + self.TestLint('T& r = (T&)*(vp());', '') + self.TestLint('T& r = v', '') + self.TestLint('static_assert((kBits & kMask) == 0, "text");', '') + self.TestLint('COMPILE_ASSERT((kBits & kMask) == 0, text);', '') + # Spaces before template arguments. This is poor style, but + # happens 0.15% of the time. + self.TestLint('void Func(const vector &const_x, ' + 'vector &nonconst_x) {', + operand_error_message % 'vector &nonconst_x') + + # Derived member functions are spared from override check + self.TestLint('void Func(X& x);', operand_error_message % 'X& x') + self.TestLint('void Func(X& x) {}', operand_error_message % 'X& x') + self.TestLint('void Func(X& x) override;', '') + self.TestLint('void Func(X& x) override {', '') + self.TestLint('void Func(X& x) const override;', '') + self.TestLint('void Func(X& x) const override {', '') + + # Don't warn on out-of-line method definitions. + self.TestLint('void NS::Func(X& x) {', '') + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company. All Rights Reserved.', + 'void a::b() {}', + 'void f(int& q) {}', + ''], + error_collector) + self.assertEquals( + operand_error_message % 'int& q', + error_collector.Results()) + + # Other potential false positives. These need full parser + # state to reproduce as opposed to just TestLint. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company. All Rights Reserved.', + 'void swap(int &x,', + ' int &y) {', + '}', + 'void swap(', + ' sparsegroup &x,', + ' sparsegroup &y) {', + '}', + 'ostream& operator<<(', + ' ostream& out', + ' const dense_hash_set& seq) {', + '}', + 'class A {', + ' void Function(', + ' string &x) override {', + ' }', + '};', + 'void Derived::Function(', + ' string &x) {', + '}', + '#define UNSUPPORTED_MASK(_mask) \\', + ' if (flags & _mask) { \\', + ' LOG(FATAL) << "Unsupported flag: " << #_mask; \\', + ' }', + 'Constructor::Constructor()', + ' : initializer1_(a1 & b1),', + ' initializer2_(a2 & b2) {', + '}', + 'Constructor::Constructor()', + ' : initializer1_{a3 & b3},', + ' initializer2_(a4 & b4) {', + '}', + 'Constructor::Constructor()', + ' : initializer1_{a5 & b5},', + ' initializer2_(a6 & b6) {}', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + # Multi-line references + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company. All Rights Reserved.', + 'void Func(const Outer::', + ' Inner& const_x,', + ' const Outer', + ' ::Inner& const_y,', + ' const Outer<', + ' int>::Inner& const_z,', + ' Outer::', + ' Inner& nonconst_x,', + ' Outer', + ' ::Inner& nonconst_y,', + ' Outer<', + ' int>::Inner& nonconst_z) {', + '}', + ''], + error_collector) + self.assertEquals( + [operand_error_message % 'Outer::Inner& nonconst_x', + operand_error_message % 'Outer::Inner& nonconst_y', + operand_error_message % 'Outer::Inner& nonconst_z'], + error_collector.Results()) + + # A peculiar false positive due to bad template argument parsing + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company. All Rights Reserved.', + 'inline RCULocked::ReadPtr::ReadPtr(const RCULocked* rcu) {', + ' DCHECK(!(data & kFlagMask)) << "Error";', + '}', + '', + 'RCULocked::WritePtr::WritePtr(RCULocked* rcu)', + ' : lock_(&rcu_->mutex_) {', + '}', + ''], + error_collector.Results()) + self.assertEquals('', error_collector.Results()) + + def testBraceAtBeginOfLine(self): + self.TestLint('{', + '{ should almost always be at the end of the previous line' + ' [whitespace/braces] [4]') + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['int function()', + '{', # warning here + ' MutexLock l(&mu);', + '}', + 'int variable;' + '{', # no warning + ' MutexLock l(&mu);', + '}', + 'MyType m = {', + ' {value1, value2},', + ' {', # no warning + ' loooong_value1, looooong_value2', + ' }', + '};', + '#if PREPROCESSOR', + '{', # no warning + ' MutexLock l(&mu);', + '}', + '#endif'], + error_collector) + self.assertEquals(1, error_collector.Results().count( + '{ should almost always be at the end of the previous line' + ' [whitespace/braces] [4]')) + + self.TestMultiLineLint( + """ + foo( + { + loooooooooooooooong_value, + });""", + '') + + def testMismatchingSpacesInParens(self): + self.TestLint('if (foo ) {', 'Mismatching spaces inside () in if' + ' [whitespace/parens] [5]') + self.TestLint('switch ( foo) {', 'Mismatching spaces inside () in switch' + ' [whitespace/parens] [5]') + self.TestLint('for (foo; ba; bar ) {', 'Mismatching spaces inside () in for' + ' [whitespace/parens] [5]') + self.TestLint('for (; foo; bar) {', '') + self.TestLint('for ( ; foo; bar) {', '') + self.TestLint('for ( ; foo; bar ) {', '') + self.TestLint('for (foo; bar; ) {', '') + self.TestLint('while ( foo ) {', 'Should have zero or one spaces inside' + ' ( and ) in while [whitespace/parens] [5]') + + def testSpacingForFncall(self): + self.TestLint('if (foo) {', '') + self.TestLint('for (foo; bar; baz) {', '') + self.TestLint('for (;;) {', '') + # Space should be allowed in placement new operators. + self.TestLint('Something* p = new (place) Something();', '') + # Test that there is no warning when increment statement is empty. + self.TestLint('for (foo; baz;) {', '') + self.TestLint('for (foo;bar;baz) {', 'Missing space after ;' + ' [whitespace/semicolon] [3]') + # we don't warn about this semicolon, at least for now + self.TestLint('if (condition) {return &something; }', + '') + # seen in some macros + self.TestLint('DoSth();\\', '') + # Test that there is no warning about semicolon here. + self.TestLint('abc;// this is abc', + 'At least two spaces is best between code' + ' and comments [whitespace/comments] [2]') + self.TestLint('while (foo) {', '') + self.TestLint('switch (foo) {', '') + self.TestLint('foo( bar)', 'Extra space after ( in function call' + ' [whitespace/parens] [4]') + self.TestLint('foo( // comment', '') + self.TestLint('foo( // comment', + 'At least two spaces is best between code' + ' and comments [whitespace/comments] [2]') + self.TestLint('foobar( \\', '') + self.TestLint('foobar( \\', '') + self.TestLint('( a + b)', 'Extra space after (' + ' [whitespace/parens] [2]') + self.TestLint('((a+b))', '') + self.TestLint('foo (foo)', 'Extra space before ( in function call' + ' [whitespace/parens] [4]') + # asm volatile () may have a space, as it isn't a function call. + self.TestLint('asm volatile ("")', '') + self.TestLint('__asm__ __volatile__ ("")', '') + self.TestLint('} catch (const Foo& ex) {', '') + self.TestLint('case (42):', '') + self.TestLint('typedef foo (*foo)(foo)', '') + self.TestLint('typedef foo (*foo12bar_)(foo)', '') + self.TestLint('typedef foo (Foo::*bar)(foo)', '') + self.TestLint('using foo = type (Foo::*bar)(foo)', '') + self.TestLint('using foo = type (Foo::*bar)(', '') + self.TestLint('using foo = type (Foo::*)(', '') + self.TestLint('foo (Foo::*bar)(', '') + self.TestLint('foo (x::y::*z)(', '') + self.TestLint('foo (Foo::bar)(', + 'Extra space before ( in function call' + ' [whitespace/parens] [4]') + self.TestLint('foo (*bar)(', '') + self.TestLint('typedef foo (Foo::*bar)(', '') + self.TestLint('(foo)(bar)', '') + self.TestLint('Foo (*foo)(bar)', '') + self.TestLint('Foo (*foo)(Bar bar,', '') + self.TestLint('char (*p)[sizeof(foo)] = &foo', '') + self.TestLint('char (&ref)[sizeof(foo)] = &foo', '') + self.TestLint('const char32 (*table[])[6];', '') + # The sizeof operator is often written as if it were a function call, with + # an opening parenthesis directly following the operator name, but it can + # also be written like any other operator, with a space following the + # operator name, and the argument optionally in parentheses. + self.TestLint('sizeof(foo)', '') + self.TestLint('sizeof foo', '') + self.TestLint('sizeof (foo)', '') + + def testSpacingBeforeBraces(self): + self.TestLint('if (foo){', 'Missing space before {' + ' [whitespace/braces] [5]') + self.TestLint('for{', 'Missing space before {' + ' [whitespace/braces] [5]') + self.TestLint('for {', '') + self.TestLint('EXPECT_DEBUG_DEATH({', '') + self.TestLint('std::is_convertible{}', '') + self.TestLint('blah{32}', 'Missing space before {' + ' [whitespace/braces] [5]') + self.TestLint('int8_t{3}', '') + self.TestLint('int16_t{3}', '') + self.TestLint('int32_t{3}', '') + self.TestLint('uint64_t{12345}', '') + self.TestLint('constexpr int64_t kBatchGapMicros =' + ' int64_t{7} * 24 * 3600 * 1000000; // 1 wk.', '') + self.TestLint('MoveOnly(int i1, int i2) : ip1{new int{i1}}, ' + 'ip2{new int{i2}} {}', + '') + + def testSemiColonAfterBraces(self): + self.TestLint('if (cond) { func(); };', + 'You don\'t need a ; after a } [readability/braces] [4]') + self.TestLint('void Func() {};', + 'You don\'t need a ; after a } [readability/braces] [4]') + self.TestLint('void Func() const {};', + 'You don\'t need a ; after a } [readability/braces] [4]') + self.TestLint('class X {};', '') + for keyword in ['struct', 'union']: + for align in ['', ' alignas(16)']: + for typename in ['', ' X']: + for identifier in ['', ' x']: + self.TestLint(keyword + align + typename + ' {}' + identifier + ';', + '') + + self.TestLint('class X : public Y {};', '') + self.TestLint('class X : public MACRO() {};', '') + self.TestLint('class X : public decltype(expr) {};', '') + self.TestLint('DEFINE_FACADE(PCQueue::Watcher, PCQueue) {};', '') + self.TestLint('VCLASS(XfaTest, XfaContextTest) {};', '') + self.TestLint('class STUBBY_CLASS(H, E) {};', '') + self.TestLint('class STUBBY2_CLASS(H, E) {};', '') + self.TestLint('TEST(TestCase, TestName) {};', + 'You don\'t need a ; after a } [readability/braces] [4]') + self.TestLint('TEST_F(TestCase, TestName) {};', + 'You don\'t need a ; after a } [readability/braces] [4]') + + self.TestLint('file_tocs_[i] = (FileToc) {a, b, c};', '') + self.TestMultiLineLint('class X : public Y,\npublic Z {};', '') + + def testLambda(self): + self.TestLint('auto x = []() {};', '') + self.TestLint('return []() {};', '') + self.TestMultiLineLint('auto x = []() {\n};\n', '') + self.TestLint('int operator[](int x) {};', + 'You don\'t need a ; after a } [readability/braces] [4]') + + self.TestMultiLineLint('auto x = [&a,\nb]() {};', '') + self.TestMultiLineLint('auto x = [&a,\nb]\n() {};', '') + self.TestMultiLineLint('auto x = [&a,\n' + ' b](\n' + ' int a,\n' + ' int b) {\n' + ' return a +\n' + ' b;\n' + '};\n', + '') + + # Avoid false positives with operator[] + self.TestLint('table_to_children[&*table].push_back(dependent);', '') + + def testBraceInitializerList(self): + self.TestLint('MyStruct p = {1, 2};', '') + self.TestLint('MyStruct p{1, 2};', '') + self.TestLint('vector p = {1, 2};', '') + self.TestLint('vector p{1, 2};', '') + self.TestLint('x = vector{1, 2};', '') + self.TestLint('x = (struct in_addr){ 0 };', '') + self.TestLint('Func(vector{1, 2})', '') + self.TestLint('Func((struct in_addr){ 0 })', '') + self.TestLint('Func(vector{1, 2}, 3)', '') + self.TestLint('Func((struct in_addr){ 0 }, 3)', '') + self.TestLint('LOG(INFO) << char{7};', '') + self.TestLint('LOG(INFO) << char{7} << "!";', '') + self.TestLint('int p[2] = {1, 2};', '') + self.TestLint('return {1, 2};', '') + self.TestLint('std::unique_ptr foo{new Foo{}};', '') + self.TestLint('auto foo = std::unique_ptr{new Foo{}};', '') + self.TestLint('static_assert(Max7String{}.IsValid(), "");', '') + self.TestLint('map_of_pairs[{1, 2}] = 3;', '') + self.TestLint('ItemView{has_offer() ? new Offer{offer()} : nullptr', '') + self.TestLint('template {}> = 0>', '') + + self.TestMultiLineLint('std::unique_ptr foo{\n' + ' new Foo{}\n' + '};\n', '') + self.TestMultiLineLint('std::unique_ptr foo{\n' + ' new Foo{\n' + ' new Bar{}\n' + ' }\n' + '};\n', '') + self.TestMultiLineLint('if (true) {\n' + ' if (false){ func(); }\n' + '}\n', + 'Missing space before { [whitespace/braces] [5]') + self.TestMultiLineLint('MyClass::MyClass()\n' + ' : initializer_{\n' + ' Func()} {\n' + '}\n', '') + self.TestLint('const pair kCL' + + ('o' * 41) + 'gStr[] = {\n', + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + self.TestMultiLineLint('const pair kCL' + + ('o' * 40) + 'ngStr[] =\n' + ' {\n' + ' {"gooooo", "oooogle"},\n' + '};\n', '') + self.TestMultiLineLint('const pair kCL' + + ('o' * 39) + 'ngStr[] =\n' + ' {\n' + ' {"gooooo", "oooogle"},\n' + '};\n', '{ should almost always be at the end of ' + 'the previous line [whitespace/braces] [4]') + + def testSpacingAroundElse(self): + self.TestLint('}else {', 'Missing space before else' + ' [whitespace/braces] [5]') + self.TestLint('} else{', 'Missing space before {' + ' [whitespace/braces] [5]') + self.TestLint('} else {', '') + self.TestLint('} else if (foo) {', '') + + def testSpacingWithInitializerLists(self): + self.TestLint('int v[1][3] = {{1, 2, 3}};', '') + self.TestLint('int v[1][1] = {{0}};', '') + + def testSpacingForBinaryOps(self): + self.TestLint('if (foo||bar) {', 'Missing spaces around ||' + ' [whitespace/operators] [3]') + self.TestLint('if (foo<=bar) {', 'Missing spaces around <=' + ' [whitespace/operators] [3]') + self.TestLint('if (foobar) {', 'Missing spaces around >' + ' [whitespace/operators] [3]') + self.TestLint('if (foobaz) {', 'Missing spaces around <' + ' [whitespace/operators] [3]') + self.TestLint('if (foobar) {', 'Missing spaces around <' + ' [whitespace/operators] [3]') + self.TestLint('template', '') + self.TestLint('std::unique_ptr>', '') + self.TestLint('typedef hash_map', '') + self.TestLint('10<<20', '') + self.TestLint('10<>b', + 'Missing spaces around >> [whitespace/operators] [3]') + self.TestLint('10>>b', + 'Missing spaces around >> [whitespace/operators] [3]') + self.TestLint('LOG(ERROR)<<*foo', + 'Missing spaces around << [whitespace/operators] [3]') + self.TestLint('LOG(ERROR)<<&foo', + 'Missing spaces around << [whitespace/operators] [3]') + self.TestLint('StringCoder>::ToString()', '') + self.TestLint('map, map>::iterator', '') + self.TestLint('func>>()', '') + self.TestLint('MACRO1(list>)', '') + self.TestLint('MACRO2(list>, 42)', '') + self.TestLint('void DoFoo(const set>& arg1);', '') + self.TestLint('void SetFoo(set>* arg1);', '') + self.TestLint('foo = new set>;', '') + self.TestLint('reinterpret_cast>*>(a);', '') + self.TestLint('MACRO(<<)', '') + self.TestLint('MACRO(<<, arg)', '') + self.TestLint('MACRO(<<=)', '') + self.TestLint('MACRO(<<=, arg)', '') + + self.TestLint('using Vector3::operator==;', '') + self.TestLint('using Vector3::operator!=;', '') + + def testSpacingBeforeLastSemicolon(self): + self.TestLint('call_function() ;', + 'Extra space before last semicolon. If this should be an ' + 'empty statement, use {} instead.' + ' [whitespace/semicolon] [5]') + self.TestLint('while (true) ;', + 'Extra space before last semicolon. If this should be an ' + 'empty statement, use {} instead.' + ' [whitespace/semicolon] [5]') + self.TestLint('default:;', + 'Semicolon defining empty statement. Use {} instead.' + ' [whitespace/semicolon] [5]') + self.TestLint(' ;', + 'Line contains only semicolon. If this should be an empty ' + 'statement, use {} instead.' + ' [whitespace/semicolon] [5]') + self.TestLint('for (int i = 0; ;', '') + + def testEmptyBlockBody(self): + self.TestLint('while (true);', + 'Empty loop bodies should use {} or continue' + ' [whitespace/empty_loop_body] [5]') + self.TestLint('if (true);', + 'Empty conditional bodies should use {}' + ' [whitespace/empty_conditional_body] [5]') + self.TestLint('while (true)', '') + self.TestLint('while (true) continue;', '') + self.TestLint('for (;;);', + 'Empty loop bodies should use {} or continue' + ' [whitespace/empty_loop_body] [5]') + self.TestLint('for (;;)', '') + self.TestLint('for (;;) continue;', '') + self.TestLint('for (;;) func();', '') + self.TestLint('if (test) {}', + 'If statement had no body and no else clause' + ' [whitespace/empty_if_body] [4]') + self.TestLint('if (test) func();', '') + self.TestLint('if (test) {} else {}', '') + self.TestMultiLineLint("""while (true && + false);""", + 'Empty loop bodies should use {} or continue' + ' [whitespace/empty_loop_body] [5]') + self.TestMultiLineLint("""do { + } while (false);""", + '') + self.TestMultiLineLint("""#define MACRO \\ + do { \\ + } while (false);""", + '') + self.TestMultiLineLint("""do { + } while (false); // next line gets a warning + while (false);""", + 'Empty loop bodies should use {} or continue' + ' [whitespace/empty_loop_body] [5]') + self.TestMultiLineLint("""if (test) { + }""", + 'If statement had no body and no else clause' + ' [whitespace/empty_if_body] [4]') + self.TestMultiLineLint("""if (test, + func({})) { + }""", + 'If statement had no body and no else clause' + ' [whitespace/empty_if_body] [4]') + self.TestMultiLineLint("""if (test) + func();""", '') + self.TestLint('if (test) { hello; }', '') + self.TestLint('if (test({})) { hello; }', '') + self.TestMultiLineLint("""if (test) { + func(); + }""", '') + self.TestMultiLineLint("""if (test) { + // multiline + // comment + }""", '') + self.TestMultiLineLint("""if (test) { // comment + }""", '') + self.TestMultiLineLint("""if (test) { + } else { + }""", '') + self.TestMultiLineLint("""if (func(p1, + p2, + p3)) { + func(); + }""", '') + self.TestMultiLineLint("""if (func({}, p1)) { + func(); + }""", '') + + def testSpacingForRangeBasedFor(self): + # Basic correctly formatted case: + self.TestLint('for (int i : numbers) {', '') + + # Missing space before colon: + self.TestLint('for (int i: numbers) {', + 'Missing space around colon in range-based for loop' + ' [whitespace/forcolon] [2]') + # Missing space after colon: + self.TestLint('for (int i :numbers) {', + 'Missing space around colon in range-based for loop' + ' [whitespace/forcolon] [2]') + # Missing spaces both before and after the colon. + self.TestLint('for (int i:numbers) {', + 'Missing space around colon in range-based for loop' + ' [whitespace/forcolon] [2]') + + # The scope operator '::' shouldn't cause warnings... + self.TestLint('for (std::size_t i : sizes) {}', '') + # ...but it shouldn't suppress them either. + self.TestLint('for (std::size_t i: sizes) {}', + 'Missing space around colon in range-based for loop' + ' [whitespace/forcolon] [2]') + + + # Static or global STL strings. + def testStaticOrGlobalSTLStrings(self): + # A template for the error message for a const global/static string. + error_msg = ('For a static/global string constant, use a C style ' + 'string instead: "%s[]". [runtime/string] [4]') + + # The error message for a non-const global/static string variable. + nonconst_error_msg = ('Static/global string variables are not permitted.' + ' [runtime/string] [4]') + + self.TestLint('string foo;', + nonconst_error_msg) + self.TestLint('string kFoo = "hello"; // English', + nonconst_error_msg) + self.TestLint('static string foo;', + nonconst_error_msg) + self.TestLint('static const string foo;', + error_msg % 'static const char foo') + self.TestLint('static const std::string foo;', + error_msg % 'static const char foo') + self.TestLint('string Foo::bar;', + nonconst_error_msg) + + self.TestLint('std::string foo;', + nonconst_error_msg) + self.TestLint('std::string kFoo = "hello"; // English', + nonconst_error_msg) + self.TestLint('static std::string foo;', + nonconst_error_msg) + self.TestLint('static const std::string foo;', + error_msg % 'static const char foo') + self.TestLint('std::string Foo::bar;', + nonconst_error_msg) + + self.TestLint('::std::string foo;', + nonconst_error_msg) + self.TestLint('::std::string kFoo = "hello"; // English', + nonconst_error_msg) + self.TestLint('static ::std::string foo;', + nonconst_error_msg) + self.TestLint('static const ::std::string foo;', + error_msg % 'static const char foo') + self.TestLint('::std::string Foo::bar;', + nonconst_error_msg) + + self.TestLint('string* pointer', '') + self.TestLint('string *pointer', '') + self.TestLint('string* pointer = Func();', '') + self.TestLint('string *pointer = Func();', '') + self.TestLint('const string* pointer', '') + self.TestLint('const string *pointer', '') + self.TestLint('const string* pointer = Func();', '') + self.TestLint('const string *pointer = Func();', '') + self.TestLint('string const* pointer', '') + self.TestLint('string const *pointer', '') + self.TestLint('string const* pointer = Func();', '') + self.TestLint('string const *pointer = Func();', '') + self.TestLint('string* const pointer', '') + self.TestLint('string *const pointer', '') + self.TestLint('string* const pointer = Func();', '') + self.TestLint('string *const pointer = Func();', '') + self.TestLint('string Foo::bar() {}', '') + self.TestLint('string Foo::operator*() {}', '') + # Rare case. + self.TestLint('string foo("foobar");', nonconst_error_msg) + # Should not catch local or member variables. + self.TestLint(' string foo', '') + # Should not catch functions. + self.TestLint('string EmptyString() { return ""; }', '') + self.TestLint('string EmptyString () { return ""; }', '') + self.TestLint('string const& FileInfo::Pathname() const;', '') + self.TestLint('string const &FileInfo::Pathname() const;', '') + self.TestLint('string VeryLongNameFunctionSometimesEndsWith(\n' + ' VeryLongNameType very_long_name_variable) {}', '') + self.TestLint('template<>\n' + 'string FunctionTemplateSpecialization(\n' + ' int x) { return ""; }', '') + self.TestLint('template<>\n' + 'string FunctionTemplateSpecialization* >(\n' + ' int x) { return ""; }', '') + + # should not catch methods of template classes. + self.TestLint('string Class::Method() const {\n' + ' return "";\n' + '}\n', '') + self.TestLint('string Class::Method(\n' + ' int arg) const {\n' + ' return "";\n' + '}\n', '') + + # Check multiline cases. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'string Class', + '::MemberFunction1();', + 'string Class::', + 'MemberFunction2();', + 'string Class::', + 'NestedClass::MemberFunction3();', + 'string TemplateClass::', + 'NestedClass::MemberFunction4();', + 'const string Class', + '::static_member_variable1;', + 'const string Class::', + 'static_member_variable2;', + 'const string Class', + '::static_member_variable3 = "initial value";', + 'const string Class::', + 'static_member_variable4 = "initial value";', + 'string Class::', + 'static_member_variable5;', + ''], + error_collector) + self.assertEquals(error_collector.Results(), + [error_msg % 'const char Class::static_member_variable1', + error_msg % 'const char Class::static_member_variable2', + error_msg % 'const char Class::static_member_variable3', + error_msg % 'const char Class::static_member_variable4', + nonconst_error_msg]) + + def testNoSpacesInFunctionCalls(self): + self.TestLint('TellStory(1, 3);', + '') + self.TestLint('TellStory(1, 3 );', + 'Extra space before )' + ' [whitespace/parens] [2]') + self.TestLint('TellStory(1 /* wolf */, 3 /* pigs */);', + '') + self.TestMultiLineLint("""TellStory(1, 3 + );""", + 'Closing ) should be moved to the previous line' + ' [whitespace/parens] [2]') + self.TestMultiLineLint("""TellStory(Wolves(1), + Pigs(3 + ));""", + 'Closing ) should be moved to the previous line' + ' [whitespace/parens] [2]') + self.TestMultiLineLint("""TellStory(1, + 3 );""", + 'Extra space before )' + ' [whitespace/parens] [2]') + + def testToDoComments(self): + start_space = ('Too many spaces before TODO' + ' [whitespace/todo] [2]') + missing_username = ('Missing username in TODO; it should look like ' + '"// TODO(my_username): Stuff."' + ' [readability/todo] [2]') + end_space = ('TODO(my_username) should be followed by a space' + ' [whitespace/todo] [2]') + + self.TestLint('// TODOfix this', + [start_space, missing_username, end_space]) + self.TestLint('// TODO(ljenkins)fix this', + [start_space, end_space]) + self.TestLint('// TODO fix this', + [start_space, missing_username]) + self.TestLint('// TODO fix this', missing_username) + self.TestLint('// TODO: fix this', missing_username) + self.TestLint('//TODO(ljenkins): Fix this', + 'Should have a space between // and comment' + ' [whitespace/comments] [4]') + self.TestLint('// TODO(ljenkins):Fix this', end_space) + self.TestLint('// TODO(ljenkins):', '') + self.TestLint('// TODO(ljenkins): fix this', '') + self.TestLint('// TODO(ljenkins): Fix this', '') + self.TestLint('#if 1 // TEST_URLTODOCID_WHICH_HAS_THAT_WORD_IN_IT_H_', '') + self.TestLint('// See also similar TODO above', '') + self.TestLint(r'EXPECT_EQ("\\", ' + r'NormalizePath("/./../foo///bar/..//x/../..", ""));', + '') + + def testTwoSpacesBetweenCodeAndComments(self): + self.TestLint('} // namespace foo', + 'At least two spaces is best between code and comments' + ' [whitespace/comments] [2]') + self.TestLint('}// namespace foo', + 'At least two spaces is best between code and comments' + ' [whitespace/comments] [2]') + self.TestLint('printf("foo"); // Outside quotes.', + 'At least two spaces is best between code and comments' + ' [whitespace/comments] [2]') + self.TestLint('int i = 0; // Having two spaces is fine.', '') + self.TestLint('int i = 0; // Having three spaces is OK.', '') + self.TestLint('// Top level comment', '') + self.TestLint(' // Line starts with two spaces.', '') + self.TestMultiLineLint('void foo() {\n' + ' { // A scope is opening.\n' + ' int a;', '') + self.TestMultiLineLint('void foo() {\n' + ' { // A scope is opening.\n' + '#define A a', + 'At least two spaces is best between code and ' + 'comments [whitespace/comments] [2]') + self.TestMultiLineLint(' foo();\n' + ' { // An indented scope is opening.\n' + ' int a;', '') + self.TestMultiLineLint('vector my_elements = {// first\n' + ' 1,', '') + self.TestMultiLineLint('vector my_elements = {// my_elements is ..\n' + ' 1,', + 'At least two spaces is best between code and ' + 'comments [whitespace/comments] [2]') + self.TestLint('if (foo) { // not a pure scope; comment is too close!', + 'At least two spaces is best between code and comments' + ' [whitespace/comments] [2]') + self.TestLint('printf("// In quotes.")', '') + self.TestLint('printf("\\"%s // In quotes.")', '') + self.TestLint('printf("%s", "// In quotes.")', '') + + def testSpaceAfterCommentMarker(self): + self.TestLint('//', '') + self.TestLint('//x', 'Should have a space between // and comment' + ' [whitespace/comments] [4]') + self.TestLint('// x', '') + self.TestLint('///', '') + self.TestLint('/// x', '') + self.TestLint('//!', '') + self.TestLint('//----', '') + self.TestLint('//====', '') + self.TestLint('//////', '') + self.TestLint('////// x', '') + self.TestLint('///< x', '') # After-member Doxygen comment + self.TestLint('//!< x', '') # After-member Doxygen comment + self.TestLint('////x', 'Should have a space between // and comment' + ' [whitespace/comments] [4]') + self.TestLint('//}', '') + self.TestLint('//}x', 'Should have a space between // and comment' + ' [whitespace/comments] [4]') + self.TestLint('//!, ', + ' class B = piyo, ', + ' class C = fuga >', + 'class D {', + ' public:', + '};', + '', '', '', '', + '}'], + error_collector) + self.assertEquals(0, error_collector.Results().count( + 'Redundant blank line at the end of a code block should be deleted.' + ' [whitespace/blank_line] [3]')) + + def testAllowBlankLineBeforeIfElseChain(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['if (hoge) {', + '', # No warning + '} else if (piyo) {', + '', # No warning + '} else if (piyopiyo) {', + ' hoge = true;', # No warning + '} else {', + '', # Warning on this line + '}'], + error_collector) + self.assertEquals(1, error_collector.Results().count( + 'Redundant blank line at the end of a code block should be deleted.' + ' [whitespace/blank_line] [3]')) + + def testAllowBlankLineAfterExtern(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['extern "C" {', + '', + 'EXPORTAPI void APICALL Some_function() {}', + '', + '}'], + error_collector) + self.assertEquals(0, error_collector.Results().count( + 'Redundant blank line at the start of a code block should be deleted.' + ' [whitespace/blank_line] [2]')) + self.assertEquals(0, error_collector.Results().count( + 'Redundant blank line at the end of a code block should be deleted.' + ' [whitespace/blank_line] [3]')) + + def testBlankLineBeforeSectionKeyword(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['class A {', + ' public:', + ' protected:', # warning 1 + ' private:', # warning 2 + ' struct B {', + ' public:', + ' private:'] + # warning 3 + ([''] * 100) + # Make A and B longer than 100 lines + [' };', + ' struct C {', + ' protected:', + ' private:', # C is too short for warnings + ' };', + '};', + 'class D', + ' : public {', + ' public:', # no warning + '};', + 'class E {\\', + ' public:\\'] + + (['\\'] * 100) + # Makes E > 100 lines + [' int non_empty_line;\\', + ' private:\\', # no warning + ' int a;\\', + '};'], + error_collector) + self.assertEquals(2, error_collector.Results().count( + '"private:" should be preceded by a blank line' + ' [whitespace/blank_line] [3]')) + self.assertEquals(1, error_collector.Results().count( + '"protected:" should be preceded by a blank line' + ' [whitespace/blank_line] [3]')) + + def testNoBlankLineAfterSectionKeyword(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['class A {', + ' public:', + '', # warning 1 + ' private:', + '', # warning 2 + ' struct B {', + ' protected:', + '', # warning 3 + ' };', + '};'], + error_collector) + self.assertEquals(1, error_collector.Results().count( + 'Do not leave a blank line after "public:"' + ' [whitespace/blank_line] [3]')) + self.assertEquals(1, error_collector.Results().count( + 'Do not leave a blank line after "protected:"' + ' [whitespace/blank_line] [3]')) + self.assertEquals(1, error_collector.Results().count( + 'Do not leave a blank line after "private:"' + ' [whitespace/blank_line] [3]')) + + def testAllowBlankLinesInRawStrings(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + 'static const char *kData[] = {R"(', + '', + ')", R"(', + '', + ')"};', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + def testElseOnSameLineAsClosingBraces(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['if (hoge) {', + '}', + 'else if (piyo) {', # Warning on this line + '}', + ' else {' # Warning on this line + '', + '}'], + error_collector) + self.assertEquals(2, error_collector.Results().count( + 'An else should appear on the same line as the preceding }' + ' [whitespace/newline] [4]')) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['if (hoge) {', + '', + '}', + 'else', # Warning on this line + '{', + '', + '}'], + error_collector) + self.assertEquals(1, error_collector.Results().count( + 'An else should appear on the same line as the preceding }' + ' [whitespace/newline] [4]')) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['if (hoge) {', + '', + '}', + 'else_function();'], + error_collector) + self.assertEquals(0, error_collector.Results().count( + 'An else should appear on the same line as the preceding }' + ' [whitespace/newline] [4]')) + + def testMultipleStatementsOnSameLine(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['for (int i = 0; i < 1; i++) {}', + 'switch (x) {', + ' case 0: func(); break; ', + '}', + 'sum += MathUtil::SafeIntRound(x); x += 0.1;'], + error_collector) + self.assertEquals(0, error_collector.Results().count( + 'More than one command on the same line [whitespace/newline] [0]')) + + old_verbose_level = cpplint._cpplint_state.verbose_level + cpplint._cpplint_state.verbose_level = 0 + cpplint.ProcessFileData('foo.cc', 'cc', + ['sum += MathUtil::SafeIntRound(x); x += 0.1;'], + error_collector) + cpplint._cpplint_state.verbose_level = old_verbose_level + + def testEndOfNamespaceComments(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('foo.cc', 'cc', + ['namespace {', + '', + '}', # No warning (too short) + 'namespace expected {', + '} // namespace mismatched', # Warning here + 'namespace {', + '} // namespace mismatched', # Warning here + 'namespace outer { namespace nested {'] + + ([''] * 10) + + ['}', # Warning here + '}', # Warning here + 'namespace {'] + + ([''] * 10) + + ['}', # Warning here + 'namespace {'] + + ([''] * 10) + + ['} // namespace some description', # Anon warning + 'namespace {'] + + ([''] * 10) + + ['} // namespace anonymous', # Variant warning + 'namespace {'] + + ([''] * 10) + + ['} // anonymous namespace (utils)', # Variant + 'namespace {'] + + ([''] * 10) + + ['} // anonymous namespace', # No warning + 'namespace missing_comment {'] + + ([''] * 10) + + ['}', # Warning here + 'namespace no_warning {'] + + ([''] * 10) + + ['} // namespace no_warning', + 'namespace no_warning {'] + + ([''] * 10) + + ['}; // end namespace no_warning', + '#define MACRO \\', + 'namespace c_style { \\'] + + (['\\'] * 10) + + ['} /* namespace c_style. */ \\', + ';'], + error_collector) + self.assertEquals(1, error_collector.Results().count( + 'Namespace should be terminated with "// namespace expected"' + ' [readability/namespace] [5]')) + self.assertEquals(1, error_collector.Results().count( + 'Namespace should be terminated with "// namespace outer"' + ' [readability/namespace] [5]')) + self.assertEquals(1, error_collector.Results().count( + 'Namespace should be terminated with "// namespace nested"' + ' [readability/namespace] [5]')) + self.assertEquals(3, error_collector.Results().count( + 'Anonymous namespace should be terminated with "// namespace"' + ' [readability/namespace] [5]')) + self.assertEquals(2, error_collector.Results().count( + 'Anonymous namespace should be terminated with "// namespace" or' + ' "// anonymous namespace"' + ' [readability/namespace] [5]')) + self.assertEquals(1, error_collector.Results().count( + 'Namespace should be terminated with "// namespace missing_comment"' + ' [readability/namespace] [5]')) + self.assertEquals(0, error_collector.Results().count( + 'Namespace should be terminated with "// namespace no_warning"' + ' [readability/namespace] [5]')) + + def testElseClauseNotOnSameLineAsElse(self): + self.TestLint(' else DoSomethingElse();', + 'Else clause should never be on same line as else ' + '(use 2 lines) [whitespace/newline] [4]') + self.TestLint(' else ifDoSomethingElse();', + 'Else clause should never be on same line as else ' + '(use 2 lines) [whitespace/newline] [4]') + self.TestLint(' } else if (blah) {', '') + self.TestLint(' variable_ends_in_else = true;', '') + + def testComma(self): + self.TestLint('a = f(1,2);', + 'Missing space after , [whitespace/comma] [3]') + self.TestLint('int tmp=a,a=b,b=tmp;', + ['Missing spaces around = [whitespace/operators] [4]', + 'Missing space after , [whitespace/comma] [3]']) + self.TestLint('f(a, /* name */ b);', '') + self.TestLint('f(a, /* name */b);', '') + self.TestLint('f(a, /* name */-1);', '') + self.TestLint('f(a, /* name */"1");', '') + self.TestLint('f(1, /* empty macro arg */, 2)', '') + self.TestLint('f(1,, 2)', '') + self.TestLint('operator,()', '') + self.TestLint('operator,(a,b)', + 'Missing space after , [whitespace/comma] [3]') + + def testEqualsOperatorSpacing(self): + self.TestLint('int tmp= a;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int tmp =a;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int tmp=a;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int tmp= 7;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int tmp =7;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int tmp=7;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int* tmp=*p;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('int* tmp= *p;', + 'Missing spaces around = [whitespace/operators] [4]') + self.TestMultiLineLint( + TrimExtraIndent(''' + lookahead_services_= + ::strings::Split(FLAGS_ls, ",", ::strings::SkipEmpty());'''), + 'Missing spaces around = [whitespace/operators] [4]') + self.TestLint('bool result = a>=42;', + 'Missing spaces around >= [whitespace/operators] [3]') + self.TestLint('bool result = a<=42;', + 'Missing spaces around <= [whitespace/operators] [3]') + self.TestLint('bool result = a==42;', + 'Missing spaces around == [whitespace/operators] [3]') + self.TestLint('auto result = a!=42;', + 'Missing spaces around != [whitespace/operators] [3]') + self.TestLint('int a = b!=c;', + 'Missing spaces around != [whitespace/operators] [3]') + self.TestLint('a&=42;', '') + self.TestLint('a|=42;', '') + self.TestLint('a^=42;', '') + self.TestLint('a+=42;', '') + self.TestLint('a*=42;', '') + self.TestLint('a/=42;', '') + self.TestLint('a%=42;', '') + self.TestLint('a>>=5;', '') + self.TestLint('a<<=5;', '') + + def testShiftOperatorSpacing(self): + self.TestLint('a<>b', + 'Missing spaces around >> [whitespace/operators] [3]') + self.TestLint('1<<20', '') + self.TestLint('1024>>10', '') + self.TestLint('Kernel<<<1, 2>>>()', '') + + def testIndent(self): + self.TestLint('static int noindent;', '') + self.TestLint(' int two_space_indent;', '') + self.TestLint(' int four_space_indent;', '') + self.TestLint(' int one_space_indent;', + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent? [whitespace/indent] [3]') + self.TestLint(' int three_space_indent;', + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent? [whitespace/indent] [3]') + self.TestLint(' char* one_space_indent = "public:";', + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent? [whitespace/indent] [3]') + self.TestLint(' public:', '') + self.TestLint(' protected:', '') + self.TestLint(' private:', '') + self.TestLint(' protected: \\', '') + self.TestLint(' public: \\', '') + self.TestLint(' private: \\', '') + self.TestMultiLineLint( + TrimExtraIndent(""" + class foo { + public slots: + void bar(); + };"""), + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent? [whitespace/indent] [3]') + self.TestMultiLineLint( + TrimExtraIndent(''' + static const char kRawString[] = R"(" + ")";'''), + '') + self.TestMultiLineLint( + TrimExtraIndent(''' + KV>'''), + '') + self.TestMultiLineLint( + ' static const char kSingleLineRawString[] = R"(...)";', + 'Weird number of spaces at line-start. ' + 'Are you using a 2-space indent? [whitespace/indent] [3]') + + def testSectionIndent(self): + self.TestMultiLineLint( + """ + class A { + public: // no warning + private: // warning here + };""", + 'private: should be indented +1 space inside class A' + ' [whitespace/indent] [3]') + self.TestMultiLineLint( + """ + class B { + public: // no warning + template<> struct C { + public: // warning here + protected: // no warning + }; + };""", + 'public: should be indented +1 space inside struct C' + ' [whitespace/indent] [3]') + self.TestMultiLineLint( + """ + struct D { + };""", + 'Closing brace should be aligned with beginning of struct D' + ' [whitespace/indent] [3]') + self.TestMultiLineLint( + """ + template class F { + };""", + 'Closing brace should be aligned with beginning of class F' + ' [whitespace/indent] [3]') + self.TestMultiLineLint( + """ + class G { + Q_OBJECT + public slots: + signals: + };""", + ['public slots: should be indented +1 space inside class G' + ' [whitespace/indent] [3]', + 'signals: should be indented +1 space inside class G' + ' [whitespace/indent] [3]']) + self.TestMultiLineLint( + """ + class H { + /* comments */ class I { + public: // no warning + private: // warning here + }; + };""", + 'private: should be indented +1 space inside class I' + ' [whitespace/indent] [3]') + self.TestMultiLineLint( + """ + class J + : public ::K { + public: // no warning + protected: // warning here + };""", + 'protected: should be indented +1 space inside class J' + ' [whitespace/indent] [3]') + self.TestMultiLineLint( + """ + class L + : public M, + public ::N { + };""", + '') + self.TestMultiLineLint( + """ + template + static void Func() { + }""", + '') + + def testConditionals(self): + self.TestMultiLineLint( + """ + if (foo) + goto fail; + goto fail;""", + 'If/else bodies with multiple statements require braces' + ' [readability/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) + goto fail; goto fail;""", + 'If/else bodies with multiple statements require braces' + ' [readability/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) + foo; + else + goto fail; + goto fail;""", + 'If/else bodies with multiple statements require braces' + ' [readability/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) goto fail; + goto fail;""", + 'If/else bodies with multiple statements require braces' + ' [readability/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) + if (bar) + baz; + else + qux;""", + 'Else clause should be indented at the same level as if. Ambiguous' + ' nested if/else chains require braces. [readability/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) + if (bar) + baz; + else + qux;""", + 'Else clause should be indented at the same level as if. Ambiguous' + ' nested if/else chains require braces. [readability/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) { + bar; + baz; + } else + qux;""", + 'If an else has a brace on one side, it should have it on both' + ' [readability/braces] [5]') + self.TestMultiLineLint( + """ + if (foo) + bar; + else { + baz; + }""", + 'If an else has a brace on one side, it should have it on both' + ' [readability/braces] [5]') + self.TestMultiLineLint( + """ + if (foo) + bar; + else if (baz) { + qux; + }""", + 'If an else has a brace on one side, it should have it on both' + ' [readability/braces] [5]') + self.TestMultiLineLint( + """ + if (foo) { + bar; + } else if (baz) + qux;""", + 'If an else has a brace on one side, it should have it on both' + ' [readability/braces] [5]') + self.TestMultiLineLint( + """ + if (foo) + goto fail; + bar;""", + '') + self.TestMultiLineLint( + """ + if (foo + && bar) { + baz; + qux; + }""", + '') + self.TestMultiLineLint( + """ + if (foo) + goto + fail;""", + '') + self.TestMultiLineLint( + """ + if (foo) + bar; + else + baz; + qux;""", + '') + self.TestMultiLineLint( + """ + for (;;) { + if (foo) + bar; + else + baz; + }""", + '') + self.TestMultiLineLint( + """ + if (foo) + bar; + else if (baz) + baz;""", + '') + self.TestMultiLineLint( + """ + if (foo) + bar; + else + baz;""", + '') + self.TestMultiLineLint( + """ + if (foo) { + bar; + } else { + baz; + }""", + '') + self.TestMultiLineLint( + """ + if (foo) { + bar; + } else if (baz) { + qux; + }""", + '') + # Note: this is an error for a different reason, but should not trigger the + # single-line if error. + self.TestMultiLineLint( + """ + if (foo) + { + bar; + baz; + }""", + '{ should almost always be at the end of the previous line' + ' [whitespace/braces] [4]') + self.TestMultiLineLint( + """ + if (foo) { \\ + bar; \\ + baz; \\ + }""", + '') + self.TestMultiLineLint( + """ + void foo() { if (bar) baz; }""", + '') + self.TestMultiLineLint( + """ + #if foo + bar; + #else + baz; + qux; + #endif""", + '') + self.TestMultiLineLint( + """void F() { + variable = [] { if (true); }; + variable = + [] { if (true); }; + Call( + [] { if (true); }, + [] { if (true); }); + }""", + '') + + def testTab(self): + self.TestLint('\tint a;', + 'Tab found; better to use spaces [whitespace/tab] [1]') + self.TestLint('int a = 5;\t\t// set a to 5', + 'Tab found; better to use spaces [whitespace/tab] [1]') + + def testParseArguments(self): + old_usage = cpplint._USAGE + old_error_categories = cpplint._ERROR_CATEGORIES + old_output_format = cpplint._cpplint_state.output_format + old_verbose_level = cpplint._cpplint_state.verbose_level + old_headers = cpplint._hpp_headers + old_filters = cpplint._cpplint_state.filters + old_line_length = cpplint._line_length + old_valid_extensions = cpplint._valid_extensions + try: + # Don't print usage during the tests, or filter categories + cpplint._USAGE = '' + cpplint._ERROR_CATEGORIES = '' + + self.assertRaises(SystemExit, cpplint.ParseArguments, []) + self.assertRaises(SystemExit, cpplint.ParseArguments, ['--badopt']) + self.assertRaises(SystemExit, cpplint.ParseArguments, ['--help']) + self.assertRaises(SystemExit, cpplint.ParseArguments, ['--v=0']) + self.assertRaises(SystemExit, cpplint.ParseArguments, ['--filter=']) + # This is illegal because all filters must start with + or - + self.assertRaises(SystemExit, cpplint.ParseArguments, ['--filter=foo']) + self.assertRaises(SystemExit, cpplint.ParseArguments, + ['--filter=+a,b,-c']) + self.assertRaises(SystemExit, cpplint.ParseArguments, ['--headers']) + + self.assertEquals(['foo.cc'], cpplint.ParseArguments(['foo.cc'])) + self.assertEquals(old_output_format, cpplint._cpplint_state.output_format) + self.assertEquals(old_verbose_level, cpplint._cpplint_state.verbose_level) + + self.assertEquals(['foo.cc'], + cpplint.ParseArguments(['--v=1', 'foo.cc'])) + self.assertEquals(1, cpplint._cpplint_state.verbose_level) + self.assertEquals(['foo.h'], + cpplint.ParseArguments(['--v=3', 'foo.h'])) + self.assertEquals(3, cpplint._cpplint_state.verbose_level) + self.assertEquals(['foo.cpp'], + cpplint.ParseArguments(['--verbose=5', 'foo.cpp'])) + self.assertEquals(5, cpplint._cpplint_state.verbose_level) + self.assertRaises(ValueError, + cpplint.ParseArguments, ['--v=f', 'foo.cc']) + + self.assertEquals(['foo.cc'], + cpplint.ParseArguments(['--output=emacs', 'foo.cc'])) + self.assertEquals('emacs', cpplint._cpplint_state.output_format) + self.assertEquals(['foo.h'], + cpplint.ParseArguments(['--output=vs7', 'foo.h'])) + self.assertEquals('vs7', cpplint._cpplint_state.output_format) + self.assertRaises(SystemExit, + cpplint.ParseArguments, ['--output=blah', 'foo.cc']) + + filt = '-,+whitespace,-whitespace/indent' + self.assertEquals(['foo.h'], + cpplint.ParseArguments(['--filter='+filt, 'foo.h'])) + self.assertEquals(['-', '+whitespace', '-whitespace/indent'], + cpplint._cpplint_state.filters) + + self.assertEquals(['foo.cc', 'foo.h'], + cpplint.ParseArguments(['foo.cc', 'foo.h'])) + + self.assertEqual(['foo.h'], + cpplint.ParseArguments(['--linelength=120', 'foo.h'])) + self.assertEqual(120, cpplint._line_length) + + self.assertEqual(['foo.h'], + cpplint.ParseArguments(['--extensions=hpp,cpp,cpp', 'foo.h'])) + self.assertEqual(set(['hpp', 'cpp']), cpplint._valid_extensions) + + self.assertEqual(set(['h']), cpplint._hpp_headers) # Default value + self.assertEqual(['foo.h'], + cpplint.ParseArguments(['--extensions=cpp,cpp', '--headers=hpp,h', 'foo.h'])) + self.assertEqual(set(['hpp', 'h']), cpplint._hpp_headers) + self.assertEqual(set(['hpp', 'h', 'cpp']), cpplint._valid_extensions) + + finally: + cpplint._USAGE = old_usage + cpplint._ERROR_CATEGORIES = old_error_categories + cpplint._cpplint_state.output_format = old_output_format + cpplint._cpplint_state.verbose_level = old_verbose_level + cpplint._cpplint_state.filters = old_filters + cpplint._line_length = old_line_length + cpplint._valid_extensions = old_valid_extensions + cpplint._hpp_headers = old_headers + + def testLineLength(self): + old_line_length = cpplint._line_length + try: + cpplint._line_length = 80 + self.TestLint( + '// H %s' % ('H' * 75), + '') + self.TestLint( + '// H %s' % ('H' * 76), + 'Lines should be <= 80 characters long' + ' [whitespace/line_length] [2]') + cpplint._line_length = 120 + self.TestLint( + '// H %s' % ('H' * 115), + '') + self.TestLint( + '// H %s' % ('H' * 116), + 'Lines should be <= 120 characters long' + ' [whitespace/line_length] [2]') + finally: + cpplint._line_length = old_line_length + + def testFilter(self): + old_filters = cpplint._cpplint_state.filters + try: + cpplint._cpplint_state.SetFilters('-,+whitespace,-whitespace/indent') + self.TestLint( + '// Hello there ', + 'Line ends in whitespace. Consider deleting these extra spaces.' + ' [whitespace/end_of_line] [4]') + self.TestLint('int a = (int)1.0;', '') + self.TestLint(' weird opening space', '') + finally: + cpplint._cpplint_state.filters = old_filters + + def testDefaultFilter(self): + default_filters = cpplint._DEFAULT_FILTERS + old_filters = cpplint._cpplint_state.filters + cpplint._DEFAULT_FILTERS = ['-whitespace'] + try: + # Reset filters + cpplint._cpplint_state.SetFilters('') + self.TestLint('// Hello there ', '') + cpplint._cpplint_state.SetFilters('+whitespace/end_of_line') + self.TestLint( + '// Hello there ', + 'Line ends in whitespace. Consider deleting these extra spaces.' + ' [whitespace/end_of_line] [4]') + self.TestLint(' weird opening space', '') + finally: + cpplint._cpplint_state.filters = old_filters + cpplint._DEFAULT_FILTERS = default_filters + + def testDuplicateHeader(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData('path/self.cc', 'cc', + ['// Copyright 2014 Your Company. All Rights Reserved.', + '#include "path/self.h"', + '#include "path/duplicate.h"', + '#include "path/duplicate.h"', + '#ifdef MACRO', + '#include "path/unique.h"', + '#else', + '#include "path/unique.h"', + '#endif', + ''], + error_collector) + self.assertEquals( + ['"path/duplicate.h" already included at path/self.cc:3 ' + '[build/include] [4]'], + error_collector.ResultList()) + + def testUnnamedNamespacesInHeaders(self): + self.TestLanguageRulesCheck( + 'foo.h', 'namespace {', + 'Do not use unnamed namespaces in header files. See' + ' https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' + ' for more information. [build/namespaces] [4]') + # namespace registration macros are OK. + self.TestLanguageRulesCheck('foo.h', 'namespace { \\', '') + # named namespaces are OK. + self.TestLanguageRulesCheck('foo.h', 'namespace foo {', '') + self.TestLanguageRulesCheck('foo.h', 'namespace foonamespace {', '') + self.TestLanguageRulesCheck('foo.cc', 'namespace {', '') + self.TestLanguageRulesCheck('foo.cc', 'namespace foo {', '') + + def testBuildClass(self): + # Test that the linter can parse to the end of class definitions, + # and that it will report when it can't. + # Use multi-line linter because it performs the ClassState check. + self.TestMultiLineLint( + 'class Foo {', + 'Failed to find complete declaration of class Foo' + ' [build/class] [5]') + # Do the same for namespaces + self.TestMultiLineLint( + 'namespace Foo {', + 'Failed to find complete declaration of namespace Foo' + ' [build/namespaces] [5]') + # Don't warn on forward declarations of various types. + self.TestMultiLineLint( + 'class Foo;', + '') + self.TestMultiLineLint( + """struct Foo* + foo = NewFoo();""", + '') + # Test preprocessor. + self.TestMultiLineLint( + """#ifdef DERIVE_FROM_GOO + struct Foo : public Goo { + #else + struct Foo : public Hoo { + #endif + };""", + '') + self.TestMultiLineLint( + """ + class Foo + #ifdef DERIVE_FROM_GOO + : public Goo { + #else + : public Hoo { + #endif + };""", + '') + # Test incomplete class + self.TestMultiLineLint( + 'class Foo {', + 'Failed to find complete declaration of class Foo' + ' [build/class] [5]') + + def testBuildEndComment(self): + # The crosstool compiler we currently use will fail to compile the + # code in this test, so we might consider removing the lint check. + self.TestMultiLineLint( + """#if 0 + #endif Not a comment""", + 'Uncommented text after #endif is non-standard. Use a comment.' + ' [build/endif_comment] [5]') + + def testBuildForwardDecl(self): + # The crosstool compiler we currently use will fail to compile the + # code in this test, so we might consider removing the lint check. + self.TestLint('class Foo::Goo;', + 'Inner-style forward declarations are invalid.' + ' Remove this line.' + ' [build/forward_decl] [5]') + + def GetBuildHeaderGuardPreprocessorSymbol(self, file_path): + # Figure out the expected header guard by processing an empty file. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', [], error_collector) + for error in error_collector.ResultList(): + matched = re.search( + 'No #ifndef header guard found, suggested CPP variable is: ' + '([A-Z0-9_]+)', + error) + if matched is not None: + return matched.group(1) + + def testBuildHeaderGuard(self): + file_path = 'mydir/foo.h' + expected_guard = self.GetBuildHeaderGuardPreprocessorSymbol(file_path) + self.assertTrue(re.search('MYDIR_FOO_H_$', expected_guard)) + + # No guard at all: expect one error. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', [], error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + 'No #ifndef header guard found, suggested CPP variable is: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # No header guard, but the error is suppressed. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['// Copyright 2014 Your Company.', + '// NOLINT(build/header_guard)', ''], + error_collector) + self.assertEquals([], error_collector.ResultList()) + + # Wrong guard + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef FOO_H', '#define FOO_H'], error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#ifndef header guard has wrong style, please use: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # No define + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s' % expected_guard], error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + 'No #ifndef header guard found, suggested CPP variable is: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # Mismatched define + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s' % expected_guard, + '#define FOO_H'], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + 'No #ifndef header guard found, suggested CPP variable is: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # No endif + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s' % expected_guard, + '#define %s' % expected_guard, + ''], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#endif line should be "#endif // %s"' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # Commentless endif + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s' % expected_guard, + '#define %s' % expected_guard, + '#endif'], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#endif line should be "#endif // %s"' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # Commentless endif for old-style guard + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s_' % expected_guard, + '#define %s_' % expected_guard, + '#endif'], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#endif line should be "#endif // %s"' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # No header guard errors + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s' % expected_guard, + '#define %s' % expected_guard, + '#endif // %s' % expected_guard], + error_collector) + for line in error_collector.ResultList(): + if line.find('build/header_guard') != -1: + self.fail('Unexpected error: %s' % line) + + # No header guard errors for old-style guard + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s_' % expected_guard, + '#define %s_' % expected_guard, + '#endif // %s_' % expected_guard], + error_collector) + for line in error_collector.ResultList(): + if line.find('build/header_guard') != -1: + self.fail('Unexpected error: %s' % line) + + old_verbose_level = cpplint._cpplint_state.verbose_level + try: + cpplint._cpplint_state.verbose_level = 0 + # Warn on old-style guard if verbosity is 0. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef %s_' % expected_guard, + '#define %s_' % expected_guard, + '#endif // %s_' % expected_guard], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#ifndef header guard has wrong style, please use: %s' + ' [build/header_guard] [0]' % expected_guard), + error_collector.ResultList()) + finally: + cpplint._cpplint_state.verbose_level = old_verbose_level + + # Completely incorrect header guard + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef FOO', + '#define FOO', + '#endif // FOO'], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#ifndef header guard has wrong style, please use: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + self.assertEquals( + 1, + error_collector.ResultList().count( + '#endif line should be "#endif // %s"' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # incorrect header guard with nolint + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'h', + ['#ifndef FOO // NOLINT', + '#define FOO', + '#endif // FOO NOLINT'], + error_collector) + self.assertEquals( + 0, + error_collector.ResultList().count( + '#ifndef header guard has wrong style, please use: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + self.assertEquals( + 0, + error_collector.ResultList().count( + '#endif line should be "#endif // %s"' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + # Special case for flymake + for test_file in ['mydir/foo_flymake.h', 'mydir/.flymake/foo.h']: + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(test_file, 'h', + ['// Copyright 2014 Your Company.', ''], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count( + 'No #ifndef header guard found, suggested CPP variable is: %s' + ' [build/header_guard] [5]' % expected_guard), + error_collector.ResultList()) + + def testBuildHeaderGuardWithRoot(self): + # note: Tested file paths must be real, otherwise + # the repository name lookup will fail. + file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'cpplint_test_header.h') + file_info = cpplint.FileInfo(file_path) + if file_info.FullName() == file_info.RepositoryName(): + # When FileInfo cannot deduce the root directory of the repository, + # FileInfo.RepositoryName returns the same value as FileInfo.FullName. + # This can happen when this source file was obtained without .svn or + # .git directory. (e.g. using 'svn export' or 'git archive'). + # Skip this test in such a case because --root flag makes sense only + # when the root directory of the repository is properly deduced. + return + + self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_', + cpplint.GetHeaderGuardCPPVariable(file_path)) + # + # test --root flags: + # this changes the cpp header guard prefix + # + + # left-strip the header guard by using a root dir inside of the repo dir. + # relative directory + cpplint._root = 'cpplint' + self.assertEquals('CPPLINT_TEST_HEADER_H_', + cpplint.GetHeaderGuardCPPVariable(file_path)) + + nested_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), + os.path.join('nested', + 'cpplint_test_header.h')) + cpplint._root = os.path.join('cpplint', 'nested') + actual = cpplint.GetHeaderGuardCPPVariable(nested_file_path) + self.assertEquals('CPPLINT_TEST_HEADER_H_', + actual) + + # absolute directory + # (note that CPPLINT.cfg root=setting is always made absolute) + cpplint._root = os.path.join(os.path.dirname(os.path.abspath(__file__))) + self.assertEquals('CPPLINT_TEST_HEADER_H_', + cpplint.GetHeaderGuardCPPVariable(file_path)) + + nested_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), + os.path.join('nested', + 'cpplint_test_header.h')) + cpplint._root = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'nested') + self.assertEquals('CPPLINT_TEST_HEADER_H_', + cpplint.GetHeaderGuardCPPVariable(nested_file_path)) + + # --root flag is ignored if an non-existent directory is specified. + cpplint._root = 'NON_EXISTENT_DIR' + self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_', + cpplint.GetHeaderGuardCPPVariable(file_path)) + + # prepend to the header guard by using a root dir that is more outer + # than the repo dir + + # (using absolute paths) + # (note that CPPLINT.cfg root=setting is always made absolute) + this_files_path = os.path.dirname(os.path.abspath(__file__)) + (styleguide_path, this_files_dir) = os.path.split(this_files_path) + (styleguide_parent_path, styleguide_dir_name) = os.path.split(styleguide_path) + # parent dir of styleguide + cpplint._root = styleguide_parent_path + self.assertIsNotNone(styleguide_parent_path) + # do not hardcode the 'styleguide' repository name, it could be anything. + expected_prefix = re.sub(r'[^a-zA-Z0-9]', '_', styleguide_dir_name).upper() + '_' + # do not have 'styleguide' repo in '/' + self.assertEquals('%sCPPLINT_CPPLINT_TEST_HEADER_H_' %(expected_prefix), + cpplint.GetHeaderGuardCPPVariable(file_path)) + + # To run the 'relative path' tests, we must be in the directory of this test file. + cur_dir = os.getcwd() + os.chdir(this_files_path) + + # (using relative paths) + styleguide_rel_path = os.path.relpath(styleguide_path, this_files_path) + # '..' + cpplint._root = styleguide_rel_path + self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_', + cpplint.GetHeaderGuardCPPVariable(file_path)) + + styleguide_rel_path = os.path.relpath(styleguide_parent_path, + this_files_path) # '../..' + cpplint._root = styleguide_rel_path + self.assertEquals('%sCPPLINT_CPPLINT_TEST_HEADER_H_' %(expected_prefix), + cpplint.GetHeaderGuardCPPVariable(file_path)) + + cpplint._root = None + + # Restore previous CWD. + os.chdir(cur_dir) + + def testPathSplitToList(self): + self.assertEquals([''], + cpplint.PathSplitToList(os.path.join(''))) + + self.assertEquals(['.'], + cpplint.PathSplitToList(os.path.join('.'))) + + self.assertEquals(['..'], + cpplint.PathSplitToList(os.path.join('..'))) + + self.assertEquals(['..', 'a', 'b'], + cpplint.PathSplitToList(os.path.join('..', 'a', 'b'))) + + self.assertEquals(['a', 'b', 'c', 'd'], + cpplint.PathSplitToList(os.path.join('a', 'b', 'c', 'd'))) + + def testBuildInclude(self): + # Test that include statements have slashes in them. + self.TestLint('#include "foo.h"', + 'Include the directory when naming .h files' + ' [build/include] [4]') + self.TestLint('#include "Python.h"', '') + self.TestLint('#include "lua.h"', '') + + def testBuildPrintfFormat(self): + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + [r'printf("\%%d", value);', + r'snprintf(buffer, sizeof(buffer), "\[%d", value);', + r'fprintf(file, "\(%d", value);', + r'vsnprintf(buffer, sizeof(buffer), "\\\{%d", ap);'], + error_collector) + self.assertEquals( + 4, + error_collector.Results().count( + '%, [, (, and { are undefined character escapes. Unescape them.' + ' [build/printf_format] [3]')) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + 'foo.cc', 'cc', + ['// Copyright 2014 Your Company.', + r'printf("\\%%%d", value);', + r'printf(R"(\[)");', + r'printf(R"(\[%s)", R"(\])");', + ''], + error_collector) + self.assertEquals('', error_collector.Results()) + + def testRuntimePrintfFormat(self): + self.TestLint( + r'fprintf(file, "%q", value);', + '%q in format strings is deprecated. Use %ll instead.' + ' [runtime/printf_format] [3]') + + self.TestLint( + r'aprintf(file, "The number is %12q", value);', + '%q in format strings is deprecated. Use %ll instead.' + ' [runtime/printf_format] [3]') + + self.TestLint( + r'printf(file, "The number is" "%-12q", value);', + '%q in format strings is deprecated. Use %ll instead.' + ' [runtime/printf_format] [3]') + + self.TestLint( + r'printf(file, "The number is" "%+12q", value);', + '%q in format strings is deprecated. Use %ll instead.' + ' [runtime/printf_format] [3]') + + self.TestLint( + r'printf(file, "The number is" "% 12q", value);', + '%q in format strings is deprecated. Use %ll instead.' + ' [runtime/printf_format] [3]') + + self.TestLint( + r'snprintf(file, "Never mix %d and %1$d parameters!", value);', + '%N$ formats are unconventional. Try rewriting to avoid them.' + ' [runtime/printf_format] [2]') + + def TestLintLogCodeOnError(self, code, expected_message): + # Special TestLint which logs the input code on error. + result = self.PerformSingleLineLint(code) + if result != expected_message: + self.fail('For code: "%s"\nGot: "%s"\nExpected: "%s"' + % (code, result, expected_message)) + + def testBuildStorageClass(self): + qualifiers = [None, 'const', 'volatile'] + signs = [None, 'signed', 'unsigned'] + types = ['void', 'char', 'int', 'float', 'double', + 'schar', 'int8', 'uint8', 'int16', 'uint16', + 'int32', 'uint32', 'int64', 'uint64'] + storage_classes = ['extern', 'register', 'static', 'typedef'] + + build_storage_class_error_message = ( + 'Storage-class specifier (static, extern, typedef, etc) should be ' + 'at the beginning of the declaration. [build/storage_class] [5]') + + # Some explicit cases. Legal in C++, deprecated in C99. + self.TestLint('const int static foo = 5;', + build_storage_class_error_message) + + self.TestLint('char static foo;', + build_storage_class_error_message) + + self.TestLint('double const static foo = 2.0;', + build_storage_class_error_message) + + self.TestLint('uint64 typedef unsigned_long_long;', + build_storage_class_error_message) + + self.TestLint('int register foo = 0;', + build_storage_class_error_message) + + # Since there are a very large number of possibilities, randomly + # construct declarations. + # Make sure that the declaration is logged if there's an error. + # Seed generator with an integer for absolute reproducibility. + random.seed(25) + for unused_i in range(10): + # Build up random list of non-storage-class declaration specs. + other_decl_specs = [random.choice(qualifiers), random.choice(signs), + random.choice(types)] + # remove None + other_decl_specs = [x for x in other_decl_specs if x is not None] + + # shuffle + random.shuffle(other_decl_specs) + + # insert storage class after the first + storage_class = random.choice(storage_classes) + insertion_point = random.randint(1, len(other_decl_specs)) + decl_specs = (other_decl_specs[0:insertion_point] + + [storage_class] + + other_decl_specs[insertion_point:]) + + self.TestLintLogCodeOnError( + ' '.join(decl_specs) + ';', + build_storage_class_error_message) + + # but no error if storage class is first + self.TestLintLogCodeOnError( + storage_class + ' ' + ' '.join(other_decl_specs), + '') + + def testLegalCopyright(self): + legal_copyright_message = ( + 'No copyright message found. ' + 'You should have a line: "Copyright [year] "' + ' [legal/copyright] [5]') + + copyright_line = '// Copyright 2014 Google Inc. All Rights Reserved.' + + file_path = 'mydir/googleclient/foo.cc' + + # There should be a copyright message in the first 10 lines + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'cc', [], error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count(legal_copyright_message)) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + file_path, 'cc', + ['' for unused_i in range(10)] + [copyright_line], + error_collector) + self.assertEquals( + 1, + error_collector.ResultList().count(legal_copyright_message)) + + # Test that warning isn't issued if Copyright line appears early enough. + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(file_path, 'cc', [copyright_line], error_collector) + for message in error_collector.ResultList(): + if message.find('legal/copyright') != -1: + self.fail('Unexpected error: %s' % message) + + error_collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData( + file_path, 'cc', + ['' for unused_i in range(9)] + [copyright_line], + error_collector) + for message in error_collector.ResultList(): + if message.find('legal/copyright') != -1: + self.fail('Unexpected error: %s' % message) + + def testInvalidIncrement(self): + self.TestLint('*count++;', + 'Changing pointer instead of value (or unused value of ' + 'operator*). [runtime/invalid_increment] [5]') + + def testSnprintfSize(self): + self.TestLint('vsnprintf(NULL, 0, format)', '') + self.TestLint('snprintf(fisk, 1, format)', + 'If you can, use sizeof(fisk) instead of 1 as the 2nd arg ' + 'to snprintf. [runtime/printf] [3]') +class Cxx11Test(CpplintTestBase): + + def Helper(self, package, extension, lines, count): + filename = package + '/foo.' + extension + lines = lines[:] + + # Header files need to have an ifdef guard wrapped around their code. + if extension == 'h': + guard = filename.upper().replace('/', '_').replace('.', '_') + '_' + lines.insert(0, '#ifndef ' + guard) + lines.insert(1, '#define ' + guard) + lines.append('#endif // ' + guard) + + # All files need a final blank line. + lines.append('') + + # Process the file and check resulting error count. + collector = ErrorCollector(self.assert_) + cpplint.ProcessFileData(filename, extension, lines, collector) + error_list = collector.ResultList() + self.assertEquals(count, len(error_list), error_list) + + def TestCxx11Feature(self, code, expected_error): + lines = code.split('\n') + collector = ErrorCollector(self.assert_) + cpplint.RemoveMultiLineComments('foo.h', lines, collector) + clean_lines = cpplint.CleansedLines(lines) + cpplint.FlagCxx11Features('foo.cc', clean_lines, 0, collector) + self.assertEquals(expected_error, collector.Results()) + + def testBlockedHeaders(self): + self.TestCxx11Feature('#include ', + 'C++ TR1 headers such as are ' + 'unapproved. [build/c++tr1] [5]') + self.TestCxx11Feature('#include ', + ' is an unapproved C++11 header.' + ' [build/c++11] [5]') + + def testBlockedClasses(self): + self.TestCxx11Feature('std::alignment_of', + 'std::alignment_of is an unapproved ' + 'C++11 class or function. Send c-style an example ' + 'of where it would make your code more readable, ' + 'and they may let you use it.' + ' [build/c++11] [5]') + self.TestCxx11Feature('std::alignment_offer', '') + self.TestCxx11Feature('mystd::alignment_of', '') + self.TestCxx11Feature('std::binomial_distribution', '') + + def testBlockedFunctions(self): + self.TestCxx11Feature('std::alignment_of', + 'std::alignment_of is an unapproved ' + 'C++11 class or function. Send c-style an example ' + 'of where it would make your code more readable, ' + 'and they may let you use it.' + ' [build/c++11] [5]') + # Missed because of the lack of "std::". Compiles because ADL + # looks in the namespace of my_shared_ptr, which (presumably) is + # std::. But there will be a lint error somewhere in this file + # since my_shared_ptr had to be defined. + self.TestCxx11Feature('static_pointer_cast(my_shared_ptr)', '') + self.TestCxx11Feature('std::declval()', '') + + def testExplicitMakePair(self): + self.TestLint('make_pair', '') + self.TestLint('make_pair(42, 42)', '') + self.TestLint('make_pair<', + 'For C++11-compatibility, omit template arguments from' + ' make_pair OR use pair directly OR if appropriate,' + ' construct a pair directly' + ' [build/explicit_make_pair] [4]') + self.TestLint('make_pair <', + 'For C++11-compatibility, omit template arguments from' + ' make_pair OR use pair directly OR if appropriate,' + ' construct a pair directly' + ' [build/explicit_make_pair] [4]') + self.TestLint('my_make_pair', '') + +class Cxx14Test(CpplintTestBase): + + def TestCxx14Feature(self, code, expected_error): + lines = code.split('\n') + collector = ErrorCollector(self.assert_) + cpplint.RemoveMultiLineComments('foo.h', lines, collector) + clean_lines = cpplint.CleansedLines(lines) + cpplint.FlagCxx14Features('foo.cc', clean_lines, 0, collector) + self.assertEquals(expected_error, collector.Results()) + + def testBlockedHeaders(self): + self.TestCxx14Feature('#include ', + ' is an unapproved C++14 header.' + ' [build/c++14] [5]') + self.TestCxx14Feature('#include ', + ' is an unapproved C++14 header.' + ' [build/c++14] [5]') + + +class CleansedLinesTest(unittest.TestCase): + + def testInit(self): + lines = ['Line 1', + 'Line 2', + 'Line 3 // Comment test', + 'Line 4 /* Comment test */', + 'Line 5 "foo"'] + + clean_lines = cpplint.CleansedLines(lines) + self.assertEquals(lines, clean_lines.raw_lines) + self.assertEquals(5, clean_lines.NumLines()) + + self.assertEquals(['Line 1', + 'Line 2', + 'Line 3', + 'Line 4', + 'Line 5 "foo"'], + clean_lines.lines) + + self.assertEquals(['Line 1', + 'Line 2', + 'Line 3', + 'Line 4', + 'Line 5 ""'], + clean_lines.elided) + + def testInitEmpty(self): + clean_lines = cpplint.CleansedLines([]) + self.assertEquals([], clean_lines.raw_lines) + self.assertEquals(0, clean_lines.NumLines()) + + def testCollapseStrings(self): + collapse = cpplint.CleansedLines._CollapseStrings + self.assertEquals('""', collapse('""')) # "" (empty) + self.assertEquals('"""', collapse('"""')) # """ (bad) + self.assertEquals('""', collapse('"xyz"')) # "xyz" (string) + self.assertEquals('""', collapse('"\\\""')) # "\"" (string) + self.assertEquals('""', collapse('"\'"')) # "'" (string) + self.assertEquals('"\"', collapse('"\"')) # "\" (bad) + self.assertEquals('""', collapse('"\\\\"')) # "\\" (string) + self.assertEquals('"', collapse('"\\\\\\"')) # "\\\" (bad) + self.assertEquals('""', collapse('"\\\\\\\\"')) # "\\\\" (string) + + self.assertEquals('\'\'', collapse('\'\'')) # '' (empty) + self.assertEquals('\'\'', collapse('\'a\'')) # 'a' (char) + self.assertEquals('\'\'', collapse('\'\\\'\'')) # '\'' (char) + self.assertEquals('\'', collapse('\'\\\'')) # '\' (bad) + self.assertEquals('', collapse('\\012')) # '\012' (char) + self.assertEquals('', collapse('\\xfF0')) # '\xfF0' (char) + self.assertEquals('', collapse('\\n')) # '\n' (char) + self.assertEquals(r'\#', collapse('\\#')) # '\#' (bad) + + self.assertEquals('"" + ""', collapse('"\'" + "\'"')) + self.assertEquals("'', ''", collapse("'\"', '\"'")) + self.assertEquals('""[0b10]', collapse('"a\'b"[0b1\'0]')) + + self.assertEquals('42', collapse("4'2")) + self.assertEquals('0b0101', collapse("0b0'1'0'1")) + self.assertEquals('1048576', collapse("1'048'576")) + self.assertEquals('0X100000', collapse("0X10'0000")) + self.assertEquals('0004000000', collapse("0'004'000'000")) + self.assertEquals('1.602176565e-19', collapse("1.602'176'565e-19")) + self.assertEquals('\'\' + 0xffff', collapse("'i' + 0xf'f'f'f")) + self.assertEquals('sizeof\'\' == 1', collapse("sizeof'x' == 1")) + self.assertEquals('0x.03p100', collapse('0x.0\'3p1\'0\'0')) + self.assertEquals('123.45', collapse('1\'23.4\'5')) + + self.assertEquals('StringReplace(body, "", "");', + collapse('StringReplace(body, "\\\\", "\\\\\\\\");')) + self.assertEquals('\'\' ""', + collapse('\'"\' "foo"')) + + +class OrderOfIncludesTest(CpplintTestBase): + + def setUp(self): + CpplintTestBase.setUp(self) + self.include_state = cpplint._IncludeState() + os.path.abspath = lambda value: value + + def testCheckNextIncludeOrder_OtherThenCpp(self): + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._OTHER_HEADER)) + self.assertEqual('Found C++ system header after other header', + self.include_state.CheckNextIncludeOrder( + cpplint._CPP_SYS_HEADER)) + + def testCheckNextIncludeOrder_CppThenC(self): + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._CPP_SYS_HEADER)) + self.assertEqual('Found C system header after C++ system header', + self.include_state.CheckNextIncludeOrder( + cpplint._C_SYS_HEADER)) + + def testCheckNextIncludeOrder_LikelyThenCpp(self): + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._LIKELY_MY_HEADER)) + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._CPP_SYS_HEADER)) + + def testCheckNextIncludeOrder_PossibleThenCpp(self): + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._POSSIBLE_MY_HEADER)) + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._CPP_SYS_HEADER)) + + def testCheckNextIncludeOrder_CppThenLikely(self): + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._CPP_SYS_HEADER)) + # This will eventually fail. + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._LIKELY_MY_HEADER)) + + def testCheckNextIncludeOrder_CppThenPossible(self): + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._CPP_SYS_HEADER)) + self.assertEqual('', self.include_state.CheckNextIncludeOrder( + cpplint._POSSIBLE_MY_HEADER)) + + def testClassifyInclude(self): + file_info = cpplint.FileInfo + classify_include = cpplint._ClassifyInclude + self.assertEqual(cpplint._C_SYS_HEADER, + classify_include(file_info('foo/foo.cc'), + 'stdio.h', + True)) + self.assertEqual(cpplint._CPP_SYS_HEADER, + classify_include(file_info('foo/foo.cc'), + 'string', + True)) + self.assertEqual(cpplint._CPP_SYS_HEADER, + classify_include(file_info('foo/foo.cc'), + 'typeinfo', + True)) + self.assertEqual(cpplint._OTHER_HEADER, + classify_include(file_info('foo/foo.cc'), + 'string', + False)) + + self.assertEqual(cpplint._LIKELY_MY_HEADER, + classify_include(file_info('foo/foo.cc'), + 'foo/foo-inl.h', + False)) + self.assertEqual(cpplint._LIKELY_MY_HEADER, + classify_include(file_info('foo/internal/foo.cc'), + 'foo/public/foo.h', + False)) + self.assertEqual(cpplint._POSSIBLE_MY_HEADER, + classify_include(file_info('foo/internal/foo.cc'), + 'foo/other/public/foo.h', + False)) + self.assertEqual(cpplint._OTHER_HEADER, + classify_include(file_info('foo/internal/foo.cc'), + 'foo/other/public/foop.h', + False)) + + def testTryDropCommonSuffixes(self): + self.assertEqual('foo/foo', cpplint._DropCommonSuffixes('foo/foo-inl.h')) + self.assertEqual('foo/bar/foo', + cpplint._DropCommonSuffixes('foo/bar/foo_inl.h')) + self.assertEqual('foo/foo', cpplint._DropCommonSuffixes('foo/foo.cc')) + self.assertEqual('foo/foo_unusualinternal', + cpplint._DropCommonSuffixes('foo/foo_unusualinternal.h')) + self.assertEqual('', + cpplint._DropCommonSuffixes('_test.cc')) + self.assertEqual('test', + cpplint._DropCommonSuffixes('test.cc')) + + def testRegression(self): + def Format(includes): + include_list = [] + for item in includes: + if item.startswith('"') or item.startswith('<'): + include_list.append('#include %s\n' % item) + else: + include_list.append(item + '\n') + return ''.join(include_list) + + # Test singleton cases first. + self.TestLanguageRulesCheck('foo/foo.cc', Format(['"foo/foo.h"']), '') + self.TestLanguageRulesCheck('foo/foo.cc', Format(['']), '') + self.TestLanguageRulesCheck('foo/foo.cc', Format(['']), '') + self.TestLanguageRulesCheck('foo/foo.cc', Format(['"foo/foo-inl.h"']), '') + self.TestLanguageRulesCheck('foo/foo.cc', Format(['"bar/bar-inl.h"']), '') + self.TestLanguageRulesCheck('foo/foo.cc', Format(['"bar/bar.h"']), '') + + # Test everything in a good and new order. + self.TestLanguageRulesCheck('foo/foo.cc', + Format(['"foo/foo.h"', + '"foo/foo-inl.h"', + '', + '', + '', + '"bar/bar-inl.h"', + '"bar/bar.h"']), + '') + + # Test bad orders. + self.TestLanguageRulesCheck( + 'foo/foo.cc', + Format(['', '']), + 'Found C system header after C++ system header.' + ' Should be: foo.h, c system, c++ system, other.' + ' [build/include_order] [4]') + self.TestLanguageRulesCheck( + 'foo/foo.cc', + Format(['"foo/bar-inl.h"', + '"foo/foo-inl.h"']), + '') + self.TestLanguageRulesCheck( + 'foo/foo.cc', + Format(['"foo/e.h"', + '"foo/b.h"', # warning here (e>b) + '"foo/c.h"', + '"foo/d.h"', + '"foo/a.h"']), # warning here (d>a) + ['Include "foo/b.h" not in alphabetical order' + ' [build/include_alpha] [4]', + 'Include "foo/a.h" not in alphabetical order' + ' [build/include_alpha] [4]']) + # -inl.h headers are no longer special. + self.TestLanguageRulesCheck('foo/foo.cc', + Format(['"foo/foo-inl.h"', '']), + '') + self.TestLanguageRulesCheck('foo/foo.cc', + Format(['"foo/bar.h"', '"foo/bar-inl.h"']), + '') + # Test componentized header. OK to have my header in ../public dir. + self.TestLanguageRulesCheck('foo/internal/foo.cc', + Format(['"foo/public/foo.h"', '']), + '') + # OK to have my header in other dir (not stylistically, but + # cpplint isn't as good as a human). + self.TestLanguageRulesCheck('foo/internal/foo.cc', + Format(['"foo/other/public/foo.h"', + '']), + '') + self.TestLanguageRulesCheck('foo/foo.cc', + Format(['"foo/foo.h"', + '', + '"base/google.h"', + '"base/flags.h"']), + 'Include "base/flags.h" not in alphabetical ' + 'order [build/include_alpha] [4]') + # According to the style, -inl.h should come before .h, but we don't + # complain about that. + self.TestLanguageRulesCheck('foo/foo.cc', + Format(['"foo/foo-inl.h"', + '"foo/foo.h"', + '"base/google.h"', + '"base/google-inl.h"']), + '') + # Allow project includes to be separated by blank lines + self.TestLanguageRulesCheck('a/a.cc', + Format(['"a/a.h"', + '', + '"base/google.h"', + '', + '"b/c.h"', + '', + 'MACRO', + '"a/b.h"']), + '') + self.TestLanguageRulesCheck('a/a.cc', + Format(['"a/a.h"', + '', + '"base/google.h"', + '"a/b.h"']), + 'Include "a/b.h" not in alphabetical ' + 'order [build/include_alpha] [4]') + + # Test conditional includes + self.TestLanguageRulesCheck( + 'a/a.cc', + ''.join(['#include \n', + '#include "base/port.h"\n', + '#include \n']), + ('Found C++ system header after other header. ' + 'Should be: a.h, c system, c++ system, other. ' + '[build/include_order] [4]')) + self.TestLanguageRulesCheck( + 'a/a.cc', + ''.join(['#include \n', + '#include "base/port.h"\n', + '#ifdef LANG_CXX11\n', + '#include \n', + '#endif // LANG_CXX11\n']), + '') + self.TestLanguageRulesCheck( + 'a/a.cc', + ''.join(['#include \n', + '#ifdef LANG_CXX11\n', + '#include "base/port.h"\n', + '#include \n', + '#endif // LANG_CXX11\n']), + ('Found C++ system header after other header. ' + 'Should be: a.h, c system, c++ system, other. ' + '[build/include_order] [4]')) + + # Third party headers are exempt from order checks + self.TestLanguageRulesCheck('foo/foo.cc', + Format(['', '"Python.h"', '']), + '') + + +class CheckForFunctionLengthsTest(CpplintTestBase): + + def setUp(self): + # Reducing these thresholds for the tests speeds up tests significantly. + self.old_normal_trigger = cpplint._FunctionState._NORMAL_TRIGGER + self.old_test_trigger = cpplint._FunctionState._TEST_TRIGGER + + cpplint._FunctionState._NORMAL_TRIGGER = 10 + cpplint._FunctionState._TEST_TRIGGER = 25 + + def tearDown(self): + cpplint._FunctionState._NORMAL_TRIGGER = self.old_normal_trigger + cpplint._FunctionState._TEST_TRIGGER = self.old_test_trigger + + def TestFunctionLengthsCheck(self, code, expected_message): + """Check warnings for long function bodies are as expected. + + Args: + code: C++ source code expected to generate a warning message. + expected_message: Message expected to be generated by the C++ code. + """ + self.assertEquals(expected_message, + self.PerformFunctionLengthsCheck(code)) + + def TriggerLines(self, error_level): + """Return number of lines needed to trigger a function length warning. + + Args: + error_level: --v setting for cpplint. + + Returns: + Number of lines needed to trigger a function length warning. + """ + return cpplint._FunctionState._NORMAL_TRIGGER * 2**error_level + + def TestLines(self, error_level): + """Return number of lines needed to trigger a test function length warning. + + Args: + error_level: --v setting for cpplint. + + Returns: + Number of lines needed to trigger a test function length warning. + """ + return cpplint._FunctionState._TEST_TRIGGER * 2**error_level + + def TestFunctionLengthCheckDefinition(self, lines, error_level): + """Generate long function definition and check warnings are as expected. + + Args: + lines: Number of lines to generate. + error_level: --v setting for cpplint. + """ + trigger_level = self.TriggerLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + 'void test(int x)' + self.FunctionBody(lines), + ('Small and focused functions are preferred: ' + 'test() has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]' + % (lines, trigger_level, error_level))) + + def TestFunctionLengthCheckDefinitionOK(self, lines): + """Generate shorter function definition and check no warning is produced. + + Args: + lines: Number of lines to generate. + """ + self.TestFunctionLengthsCheck( + 'void test(int x)' + self.FunctionBody(lines), + '') + + def TestFunctionLengthCheckAtErrorLevel(self, error_level): + """Generate and check function at the trigger level for --v setting. + + Args: + error_level: --v setting for cpplint. + """ + self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level), + error_level) + + def TestFunctionLengthCheckBelowErrorLevel(self, error_level): + """Generate and check function just below the trigger level for --v setting. + + Args: + error_level: --v setting for cpplint. + """ + self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level)-1, + error_level-1) + + def TestFunctionLengthCheckAboveErrorLevel(self, error_level): + """Generate and check function just above the trigger level for --v setting. + + Args: + error_level: --v setting for cpplint. + """ + self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level)+1, + error_level) + + def FunctionBody(self, number_of_lines): + return ' {\n' + ' this_is_just_a_test();\n'*number_of_lines + '}' + + def FunctionBodyWithBlankLines(self, number_of_lines): + return ' {\n' + ' this_is_just_a_test();\n\n'*number_of_lines + '}' + + def FunctionBodyWithNoLints(self, number_of_lines): + return (' {\n' + + ' this_is_just_a_test(); // NOLINT\n'*number_of_lines + '}') + + # Test line length checks. + def testFunctionLengthCheckDeclaration(self): + self.TestFunctionLengthsCheck( + 'void test();', # Not a function definition + '') + + def testFunctionLengthCheckDeclarationWithBlockFollowing(self): + self.TestFunctionLengthsCheck( + ('void test();\n' + + self.FunctionBody(66)), # Not a function definition + '') + + def testFunctionLengthCheckClassDefinition(self): + self.TestFunctionLengthsCheck( # Not a function definition + 'class Test' + self.FunctionBody(66) + ';', + '') + + def testFunctionLengthCheckTrivial(self): + self.TestFunctionLengthsCheck( + 'void test() {}', # Not counted + '') + + def testFunctionLengthCheckEmpty(self): + self.TestFunctionLengthsCheck( + 'void test() {\n}', + '') + + def testFunctionLengthCheckDefinitionBelowSeverity0(self): + old_verbosity = cpplint._SetVerboseLevel(0) + self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(0)-1) + cpplint._SetVerboseLevel(old_verbosity) + + def testFunctionLengthCheckDefinitionAtSeverity0(self): + old_verbosity = cpplint._SetVerboseLevel(0) + self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(0)) + cpplint._SetVerboseLevel(old_verbosity) + + def testFunctionLengthCheckDefinitionAboveSeverity0(self): + old_verbosity = cpplint._SetVerboseLevel(0) + self.TestFunctionLengthCheckAboveErrorLevel(0) + cpplint._SetVerboseLevel(old_verbosity) + + def testFunctionLengthCheckDefinitionBelowSeverity1v0(self): + old_verbosity = cpplint._SetVerboseLevel(0) + self.TestFunctionLengthCheckBelowErrorLevel(1) + cpplint._SetVerboseLevel(old_verbosity) + + def testFunctionLengthCheckDefinitionAtSeverity1v0(self): + old_verbosity = cpplint._SetVerboseLevel(0) + self.TestFunctionLengthCheckAtErrorLevel(1) + cpplint._SetVerboseLevel(old_verbosity) + + def testFunctionLengthCheckDefinitionBelowSeverity1(self): + self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(1)-1) + + def testFunctionLengthCheckDefinitionAtSeverity1(self): + self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(1)) + + def testFunctionLengthCheckDefinitionAboveSeverity1(self): + self.TestFunctionLengthCheckAboveErrorLevel(1) + + def testFunctionLengthCheckDefinitionSeverity1PlusBlanks(self): + error_level = 1 + error_lines = self.TriggerLines(error_level) + 1 + trigger_level = self.TriggerLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + 'void test_blanks(int x)' + self.FunctionBody(error_lines), + ('Small and focused functions are preferred: ' + 'test_blanks() has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]') + % (error_lines, trigger_level, error_level)) + + def testFunctionLengthCheckComplexDefinitionSeverity1(self): + error_level = 1 + error_lines = self.TriggerLines(error_level) + 1 + trigger_level = self.TriggerLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + ('my_namespace::my_other_namespace::MyVeryLongTypeName*\n' + 'my_namespace::my_other_namespace::MyFunction(int arg1, char* arg2)' + + self.FunctionBody(error_lines)), + ('Small and focused functions are preferred: ' + 'my_namespace::my_other_namespace::MyFunction()' + ' has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]') + % (error_lines, trigger_level, error_level)) + + def testFunctionLengthCheckDefinitionSeverity1ForTest(self): + error_level = 1 + error_lines = self.TestLines(error_level) + 1 + trigger_level = self.TestLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + 'TEST_F(Test, Mutator)' + self.FunctionBody(error_lines), + ('Small and focused functions are preferred: ' + 'TEST_F(Test, Mutator) has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]') + % (error_lines, trigger_level, error_level)) + + def testFunctionLengthCheckDefinitionSeverity1ForSplitLineTest(self): + error_level = 1 + error_lines = self.TestLines(error_level) + 1 + trigger_level = self.TestLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + ('TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,\n' + ' FixGoogleUpdate_AllValues_MachineApp)' # note: 4 spaces + + self.FunctionBody(error_lines)), + ('Small and focused functions are preferred: ' + 'TEST_F(GoogleUpdateRecoveryRegistryProtectedTest, ' # 1 space + 'FixGoogleUpdate_AllValues_MachineApp) has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]') + % (error_lines+1, trigger_level, error_level)) + + def testFunctionLengthCheckDefinitionSeverity1ForBadTestDoesntBreak(self): + error_level = 1 + error_lines = self.TestLines(error_level) + 1 + trigger_level = self.TestLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + ('TEST_F(' + + self.FunctionBody(error_lines)), + ('Small and focused functions are preferred: ' + 'TEST_F has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]') + % (error_lines, trigger_level, error_level)) + + def testFunctionLengthCheckDefinitionSeverity1WithEmbeddedNoLints(self): + error_level = 1 + error_lines = self.TriggerLines(error_level)+1 + trigger_level = self.TriggerLines(cpplint._VerboseLevel()) + self.TestFunctionLengthsCheck( + 'void test(int x)' + self.FunctionBodyWithNoLints(error_lines), + ('Small and focused functions are preferred: ' + 'test() has %d non-comment lines ' + '(error triggered by exceeding %d lines).' + ' [readability/fn_size] [%d]') + % (error_lines, trigger_level, error_level)) + + def testFunctionLengthCheckDefinitionSeverity1WithNoLint(self): + self.TestFunctionLengthsCheck( + ('void test(int x)' + self.FunctionBody(self.TriggerLines(1)) + + ' // NOLINT -- long function'), + '') + + def testFunctionLengthCheckDefinitionBelowSeverity2(self): + self.TestFunctionLengthCheckBelowErrorLevel(2) + + def testFunctionLengthCheckDefinitionSeverity2(self): + self.TestFunctionLengthCheckAtErrorLevel(2) + + def testFunctionLengthCheckDefinitionAboveSeverity2(self): + self.TestFunctionLengthCheckAboveErrorLevel(2) + + def testFunctionLengthCheckDefinitionBelowSeverity3(self): + self.TestFunctionLengthCheckBelowErrorLevel(3) + + def testFunctionLengthCheckDefinitionSeverity3(self): + self.TestFunctionLengthCheckAtErrorLevel(3) + + def testFunctionLengthCheckDefinitionAboveSeverity3(self): + self.TestFunctionLengthCheckAboveErrorLevel(3) + + def testFunctionLengthCheckDefinitionBelowSeverity4(self): + self.TestFunctionLengthCheckBelowErrorLevel(4) + + def testFunctionLengthCheckDefinitionSeverity4(self): + self.TestFunctionLengthCheckAtErrorLevel(4) + + def testFunctionLengthCheckDefinitionAboveSeverity4(self): + self.TestFunctionLengthCheckAboveErrorLevel(4) + + def testFunctionLengthCheckDefinitionBelowSeverity5(self): + self.TestFunctionLengthCheckBelowErrorLevel(5) + + def testFunctionLengthCheckDefinitionAtSeverity5(self): + self.TestFunctionLengthCheckAtErrorLevel(5) + + def testFunctionLengthCheckDefinitionAboveSeverity5(self): + self.TestFunctionLengthCheckAboveErrorLevel(5) + + def testFunctionLengthCheckDefinitionHugeLines(self): + # 5 is the limit + self.TestFunctionLengthCheckDefinition(self.TriggerLines(10), 5) + + def testFunctionLengthNotDeterminable(self): + # Macro invocation without terminating semicolon. + self.TestFunctionLengthsCheck( + 'MACRO(arg)', + '') + + # Macro with underscores + self.TestFunctionLengthsCheck( + 'MACRO_WITH_UNDERSCORES(arg1, arg2, arg3)', + '') + + self.TestFunctionLengthsCheck( + 'NonMacro(arg)', + 'Lint failed to find start of function body.' + ' [readability/fn_size] [5]') + + def testFunctionLengthCheckWithNamespace(self): + old_verbosity = cpplint._SetVerboseLevel(1) + self.TestFunctionLengthsCheck( + ('namespace {\n' + 'void CodeCoverageCL35256059() {\n' + + (' X++;\n' * 3000) + + '}\n' + '} // namespace\n'), + ('Small and focused functions are preferred: ' + 'CodeCoverageCL35256059() has 3000 non-comment lines ' + '(error triggered by exceeding 20 lines).' + ' [readability/fn_size] [5]')) + cpplint._SetVerboseLevel(old_verbosity) + + +def TrimExtraIndent(text_block): + """Trim a uniform amount of whitespace off of each line in a string. + + Compute the minimum indent on all non blank lines and trim that from each, so + that the block of text has no extra indentation. + + Args: + text_block: a multiline string + + Returns: + text_block with the common whitespace indent of each line removed. + """ + + def CountLeadingWhitespace(s): + count = 0 + for c in s: + if not c.isspace(): + break + count += 1 + return count + # find the minimum indent (except for blank lines) + min_indent = min([CountLeadingWhitespace(line) + for line in text_block.split('\n') if line]) + return '\n'.join([line[min_indent:] for line in text_block.split('\n')]) + + +class CloseExpressionTest(unittest.TestCase): + + def setUp(self): + self.lines = cpplint.CleansedLines( + # 1 2 3 4 5 + # 0123456789012345678901234567890123456789012345678901234567890 + ['// Line 0', + 'inline RCULocked::ReadPtr::ReadPtr(const RCULocked* rcu) {', + ' DCHECK(!(data & kFlagMask)) << "Error";', + '}', + '// Line 4', + 'RCULocked::WritePtr::WritePtr(RCULocked* rcu)', + ' : lock_(&rcu_->mutex_) {', + '}', + '// Line 8', + 'template ', + 'typename std::enable_if<', + ' std::is_array::value && (std::extent::value > 0)>::type', + 'MakeUnique(A&&... a) = delete;', + '// Line 13', + 'auto x = []() {};', + '// Line 15', + 'template ', + 'friend bool operator==(const reffed_ptr& a,', + ' const reffed_ptr& b) {', + ' return a.get() == b.get();', + '}', + '// Line 21']) + + def testCloseExpression(self): + # List of positions to test: + # (start line, start position, end line, end position + 1) + positions = [(1, 16, 1, 19), + (1, 37, 1, 59), + (1, 60, 3, 1), + (2, 8, 2, 29), + (2, 30, 22, -1), # Left shift operator + (9, 9, 9, 36), + (10, 23, 11, 59), + (11, 54, 22, -1), # Greater than operator + (14, 9, 14, 11), + (14, 11, 14, 13), + (14, 14, 14, 16), + (17, 22, 18, 46), + (18, 47, 20, 1)] + for p in positions: + (_, line, column) = cpplint.CloseExpression(self.lines, p[0], p[1]) + self.assertEquals((p[2], p[3]), (line, column)) + + def testReverseCloseExpression(self): + # List of positions to test: + # (end line, end position, start line, start position) + positions = [(1, 18, 1, 16), + (1, 58, 1, 37), + (2, 27, 2, 10), + (2, 28, 2, 8), + (6, 18, 0, -1), # -> operator + (9, 35, 9, 9), + (11, 54, 0, -1), # Greater than operator + (11, 57, 11, 31), + (14, 10, 14, 9), + (14, 12, 14, 11), + (14, 15, 14, 14), + (18, 45, 17, 22), + (20, 0, 18, 47)] + for p in positions: + (_, line, column) = cpplint.ReverseCloseExpression(self.lines, p[0], p[1]) + self.assertEquals((p[2], p[3]), (line, column)) + + +class NestingStateTest(unittest.TestCase): + + def setUp(self): + self.nesting_state = cpplint.NestingState() + self.error_collector = ErrorCollector(self.assert_) + + def UpdateWithLines(self, lines): + clean_lines = cpplint.CleansedLines(lines) + for line in xrange(clean_lines.NumLines()): + self.nesting_state.Update('test.cc', + clean_lines, line, self.error_collector) + + def testEmpty(self): + self.UpdateWithLines([]) + self.assertEquals(self.nesting_state.stack, []) + + def testNamespace(self): + self.UpdateWithLines(['namespace {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], + cpplint._NamespaceInfo)) + self.assertTrue(self.nesting_state.stack[0].seen_open_brace) + self.assertEquals(self.nesting_state.stack[0].name, '') + + self.UpdateWithLines(['namespace outer { namespace inner']) + self.assertEquals(len(self.nesting_state.stack), 3) + self.assertTrue(self.nesting_state.stack[0].seen_open_brace) + self.assertTrue(self.nesting_state.stack[1].seen_open_brace) + self.assertFalse(self.nesting_state.stack[2].seen_open_brace) + self.assertEquals(self.nesting_state.stack[0].name, '') + self.assertEquals(self.nesting_state.stack[1].name, 'outer') + self.assertEquals(self.nesting_state.stack[2].name, 'inner') + + self.UpdateWithLines(['{']) + self.assertTrue(self.nesting_state.stack[2].seen_open_brace) + + self.UpdateWithLines(['}', '}}']) + self.assertEquals(len(self.nesting_state.stack), 0) + + def testClass(self): + self.UpdateWithLines(['class A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'A') + self.assertFalse(self.nesting_state.stack[0].is_derived) + self.assertEquals(self.nesting_state.stack[0].class_indent, 0) + + self.UpdateWithLines(['};', + 'struct B : public A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'B') + self.assertTrue(self.nesting_state.stack[0].is_derived) + + self.UpdateWithLines(['};', + 'class C', + ': public A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'C') + self.assertTrue(self.nesting_state.stack[0].is_derived) + + self.UpdateWithLines(['};', + 'template']) + self.assertEquals(len(self.nesting_state.stack), 0) + + self.UpdateWithLines(['class D {', ' class E {']) + self.assertEquals(len(self.nesting_state.stack), 2) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'D') + self.assertFalse(self.nesting_state.stack[0].is_derived) + self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[1].name, 'E') + self.assertFalse(self.nesting_state.stack[1].is_derived) + self.assertEquals(self.nesting_state.stack[1].class_indent, 2) + self.assertEquals(self.nesting_state.InnermostClass().name, 'E') + + self.UpdateWithLines(['}', '}']) + self.assertEquals(len(self.nesting_state.stack), 0) + + def testClassAccess(self): + self.UpdateWithLines(['class A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].access, 'private') + + self.UpdateWithLines([' public:']) + self.assertEquals(self.nesting_state.stack[0].access, 'public') + self.UpdateWithLines([' protracted:']) + self.assertEquals(self.nesting_state.stack[0].access, 'public') + self.UpdateWithLines([' protected:']) + self.assertEquals(self.nesting_state.stack[0].access, 'protected') + self.UpdateWithLines([' private:']) + self.assertEquals(self.nesting_state.stack[0].access, 'private') + + self.UpdateWithLines([' struct B {']) + self.assertEquals(len(self.nesting_state.stack), 2) + self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[1].access, 'public') + self.assertEquals(self.nesting_state.stack[0].access, 'private') + + self.UpdateWithLines([' protected :']) + self.assertEquals(self.nesting_state.stack[1].access, 'protected') + self.assertEquals(self.nesting_state.stack[0].access, 'private') + + self.UpdateWithLines([' }', '}']) + self.assertEquals(len(self.nesting_state.stack), 0) + + def testStruct(self): + self.UpdateWithLines(['struct A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'A') + self.assertFalse(self.nesting_state.stack[0].is_derived) + + self.UpdateWithLines(['}', + 'void Func(struct B arg) {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertFalse(isinstance(self.nesting_state.stack[0], + cpplint._ClassInfo)) + + self.UpdateWithLines(['}']) + self.assertEquals(len(self.nesting_state.stack), 0) + + def testPreprocessor(self): + self.assertEquals(len(self.nesting_state.pp_stack), 0) + self.UpdateWithLines(['#if MACRO1']) + self.assertEquals(len(self.nesting_state.pp_stack), 1) + self.UpdateWithLines(['#endif']) + self.assertEquals(len(self.nesting_state.pp_stack), 0) + + self.UpdateWithLines(['#ifdef MACRO2']) + self.assertEquals(len(self.nesting_state.pp_stack), 1) + self.UpdateWithLines(['#else']) + self.assertEquals(len(self.nesting_state.pp_stack), 1) + self.UpdateWithLines(['#ifdef MACRO3']) + self.assertEquals(len(self.nesting_state.pp_stack), 2) + self.UpdateWithLines(['#elif MACRO4']) + self.assertEquals(len(self.nesting_state.pp_stack), 2) + self.UpdateWithLines(['#endif']) + self.assertEquals(len(self.nesting_state.pp_stack), 1) + self.UpdateWithLines(['#endif']) + self.assertEquals(len(self.nesting_state.pp_stack), 0) + + self.UpdateWithLines(['#ifdef MACRO5', + 'class A {', + '#elif MACRO6', + 'class B {', + '#else', + 'class C {', + '#endif']) + self.assertEquals(len(self.nesting_state.pp_stack), 0) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'A') + self.UpdateWithLines(['};']) + self.assertEquals(len(self.nesting_state.stack), 0) + + self.UpdateWithLines(['class D', + '#ifdef MACRO7']) + self.assertEquals(len(self.nesting_state.pp_stack), 1) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'D') + self.assertFalse(self.nesting_state.stack[0].is_derived) + + self.UpdateWithLines(['#elif MACRO8', + ': public E']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[0].name, 'D') + self.assertTrue(self.nesting_state.stack[0].is_derived) + self.assertFalse(self.nesting_state.stack[0].seen_open_brace) + + self.UpdateWithLines(['#else', + '{']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[0].name, 'D') + self.assertFalse(self.nesting_state.stack[0].is_derived) + self.assertTrue(self.nesting_state.stack[0].seen_open_brace) + + self.UpdateWithLines(['#endif']) + self.assertEquals(len(self.nesting_state.pp_stack), 0) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[0].name, 'D') + self.assertFalse(self.nesting_state.stack[0].is_derived) + self.assertFalse(self.nesting_state.stack[0].seen_open_brace) + + self.UpdateWithLines([';']) + self.assertEquals(len(self.nesting_state.stack), 0) + + def testTemplate(self): + self.UpdateWithLines(['template >']) + self.assertEquals(len(self.nesting_state.stack), 0) + self.UpdateWithLines(['class A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'A') + + self.UpdateWithLines(['};', + 'template class B>', + 'class C']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'C') + self.UpdateWithLines([';']) + self.assertEquals(len(self.nesting_state.stack), 0) + + self.UpdateWithLines(['class D : public Tmpl']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'D') + + self.UpdateWithLines(['{', '};']) + self.assertEquals(len(self.nesting_state.stack), 0) + + self.UpdateWithLines(['template ', + 'static void Func() {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertFalse(isinstance(self.nesting_state.stack[0], + cpplint._ClassInfo)) + self.UpdateWithLines(['}', + 'template class K {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'K') + + def testTemplateInnerClass(self): + self.UpdateWithLines(['class A {', + ' public:']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + + self.UpdateWithLines([' template ', + ' class C >', + ' : public A {']) + self.assertEquals(len(self.nesting_state.stack), 2) + self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo)) + + def testArguments(self): + self.UpdateWithLines(['class A {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'A') + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + + self.UpdateWithLines([' void Func(', + ' struct X arg1,']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.UpdateWithLines([' struct X *arg2);']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + + self.UpdateWithLines(['};']) + self.assertEquals(len(self.nesting_state.stack), 0) + + self.UpdateWithLines(['struct B {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo)) + self.assertEquals(self.nesting_state.stack[0].name, 'B') + + self.UpdateWithLines(['#ifdef MACRO', + ' void Func(', + ' struct X arg1']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.UpdateWithLines(['#else']) + + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + self.UpdateWithLines([' void Func(', + ' struct X arg1']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + + self.UpdateWithLines(['#endif']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.UpdateWithLines([' struct X *arg2);']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + + self.UpdateWithLines(['};']) + self.assertEquals(len(self.nesting_state.stack), 0) + + def testInlineAssembly(self): + self.UpdateWithLines(['void CopyRow_SSE2(const uint8* src, uint8* dst,', + ' int count) {']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, cpplint._NO_ASM) + + self.UpdateWithLines([' asm volatile (']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, + cpplint._INSIDE_ASM) + + self.UpdateWithLines([' "sub %0,%1 \\n"', + ' "1: \\n"', + ' "movdqa (%0),%%xmm0 \\n"', + ' "movdqa 0x10(%0),%%xmm1 \\n"', + ' "movdqa %%xmm0,(%0,%1) \\n"', + ' "movdqa %%xmm1,0x10(%0,%1) \\n"', + ' "lea 0x20(%0),%0 \\n"', + ' "sub $0x20,%2 \\n"', + ' "jg 1b \\n"', + ' : "+r"(src), // %0', + ' "+r"(dst), // %1', + ' "+r"(count) // %2', + ' :', + ' : "memory", "cc"']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, + cpplint._INSIDE_ASM) + + self.UpdateWithLines(['#if defined(__SSE2__)', + ' , "xmm0", "xmm1"']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, + cpplint._INSIDE_ASM) + + self.UpdateWithLines(['#endif']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, + cpplint._INSIDE_ASM) + + self.UpdateWithLines([' );']) + self.assertEquals(len(self.nesting_state.stack), 1) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, cpplint._END_ASM) + + self.UpdateWithLines(['__asm {']) + self.assertEquals(len(self.nesting_state.stack), 2) + self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0) + self.assertEquals(self.nesting_state.stack[-1].inline_asm, + cpplint._BLOCK_ASM) + + self.UpdateWithLines(['}']) + self.assertEquals(len(self.nesting_state.stack), 1) + + self.UpdateWithLines(['}']) + self.assertEquals(len(self.nesting_state.stack), 0) + + +class QuietTest(unittest.TestCase): + + def setUp(self): + self.this_dir_path = os.path.dirname(os.path.abspath(__file__)) + self.python_executable = sys.executable or 'python' + self.cpplint_test_h = os.path.join(self.this_dir_path, + 'cpplint_test_header.h') + + def _runCppLint(self, *args): + cpplint_abspath = os.path.join(self.this_dir_path, 'cpplint.py') + + cmd_line = [self.python_executable, cpplint_abspath] + \ + list(args) + \ + [ self.cpplint_test_h ] + + return_code = 0 + try: + output = subprocess.check_output(cmd_line, + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as err: + return_code = err.returncode + output = err.output + + return (return_code, output) + + def testNonQuietWithErrors(self): + # This will fail: the test header is missing a copyright and header guard. + (return_code, output) = self._runCppLint() + self.assertEquals(1, return_code) + # Always-on behavior: Print error messages as they come up. + self.assertIn("[legal/copyright]", output) + self.assertIn("[build/header_guard]", output) + # If --quiet was unspecified: Print 'Done processing' and 'Total errors..' + self.assertIn("Done processing", output) + self.assertIn("Total errors found:", output) + + def testQuietWithErrors(self): + # When there are errors, behavior is identical to not passing --quiet. + (return_code, output) = self._runCppLint('--quiet') + self.assertEquals(1, return_code) + self.assertIn("[legal/copyright]", output) + self.assertIn("[build/header_guard]", output) + # Even though --quiet was used, print these since there were errors. + self.assertIn("Done processing", output) + self.assertIn("Total errors found:", output) + + def testNonQuietWithoutErrors(self): + # This will succeed. We filtered out all the known errors for that file. + (return_code, output) = self._runCppLint('--filter=' + + '-legal/copyright,' + + '-build/header_guard') + self.assertEquals(0, return_code, output) + # No cpplint errors are printed since there were no errors. + self.assertNotIn("[legal/copyright]", output) + self.assertNotIn("[build/header_guard]", output) + # Print 'Done processing' and 'Total errors found' since + # --quiet was not specified. + self.assertIn("Done processing", output) + self.assertIn("Total errors found:", output) + + def testQuietWithoutErrors(self): + # This will succeed. We filtered out all the known errors for that file. + (return_code, output) = self._runCppLint('--quiet', + '--filter=' + + '-legal/copyright,' + + '-build/header_guard') + self.assertEquals(0, return_code, output) + # No cpplint errors are printed since there were no errors. + self.assertNotIn("[legal/copyright]", output) + self.assertNotIn("[build/header_guard]", output) + # --quiet was specified and there were no errors: + # skip the printing of 'Done processing' and 'Total errors..' + self.assertNotIn("Done processing", output) + self.assertNotIn("Total errors found:", output) + # Output with no errors must be completely blank! + self.assertEquals("", output) + +# pylint: disable-msg=C6409 +def setUp(): + """Runs before all tests are executed. + """ + # Enable all filters, so we don't miss anything that is off by default. + cpplint._DEFAULT_FILTERS = [] + cpplint._cpplint_state.SetFilters('') + + +# pylint: disable-msg=C6409 +def tearDown(): + """A global check to make sure all error-categories have been tested. + + The main tearDown() routine is the only code we can guarantee will be + run after all other tests have been executed. + """ + try: + if _run_verifyallcategoriesseen: + ErrorCollector(None).VerifyAllCategoriesAreSeen() + except NameError: + # If nobody set the global _run_verifyallcategoriesseen, then + # we assume we should silently not run the test + pass + + +if __name__ == '__main__': + # We don't want to run the VerifyAllCategoriesAreSeen() test unless + # we're running the full test suite: if we only run one test, + # obviously we're not going to see all the error categories. So we + # only run VerifyAllCategoriesAreSeen() when no commandline flags + # are passed in. + global _run_verifyallcategoriesseen + _run_verifyallcategoriesseen = (len(sys.argv) == 1) + + setUp() + unittest.main() + tearDown() diff --git a/cpplint/nested/cpplint_test_header.h b/cpplint/nested/cpplint_test_header.h new file mode 100644 index 000000000..4307e8008 --- /dev/null +++ b/cpplint/nested/cpplint_test_header.h @@ -0,0 +1 @@ +// A test header for cpplint_unittest.py. diff --git a/docguide/README.md b/docguide/README.md new file mode 100644 index 000000000..39fe2ecca --- /dev/null +++ b/docguide/README.md @@ -0,0 +1,10 @@ +# Google documentation guide + +* [Markdown styleguide](style.md) +* [Best practices](best_practices.md) +* [README files](READMEs.md) +* [Philosophy](philosophy.md) + +## See also + +* [How to update this guide](https://goto.google.com/doc-guide), for Googlers. diff --git a/docguide/READMEs.md b/docguide/READMEs.md new file mode 100644 index 000000000..5854af25b --- /dev/null +++ b/docguide/READMEs.md @@ -0,0 +1,69 @@ +# README.md files + +About README.md files. + +1. [Overview](#overview) +1. [Guidelines](#guidelines) +1. [Filename](#filename) +1. [Contents](#contents) +1. [Example](#example) + +## Overview + +`README.md` files are Markdown files that describe a directory. +GitHub and Gitiles renders it when you browse the directory. + +For example, the file /README.md is rendered when you view the contents of the +containing directory: + +https://github.com/google/styleguide/tree/gh-pages + +Also `README.md` at `HEAD` ref is rendered by Gitiles when displaying repository +index: + +https://gerrit.googlesource.com/gitiles/ + +## Guidelines + +**`README.md` files are intended to provide orientation for engineers browsing +your code, especially first-time users.** The `README.md` is likely the first +file a reader encounters when they browse a directory that +contains your code. In this way, it acts as a landing page for the directory. + +We recommend that top-level directories for your code have an up-to-date +`README.md` file. This is especially important for package directories that +provide interfaces for other teams. + +### Filename + +Use `README.md`. + +Files named `README` are not displayed in the directory view in Gitiles. + +### Contents + +At minimum, every package-level `README.md` should include or point to the +following information: + +1. **What** is in this package/library and what's it used for. +2. **Who** to contact. +3. **Status**: whether this package/library is deprecated, or not for general + release, etc. +4. **More info**: where to go for more detailed documentation, such as: + * An overview.md file for more detailed conceptual information. + * Any API documentation for using this package/library. + +## Example + +```markdown +# APIs + +This is the top-level directory for all externally-visible APIs, plus some +private APIs under `internal/` directories. +See [API Style Guide](docs/apistyle.md) for more information. + +*TL;DR*: API definitions and configurations should be defined in `.proto` files, +checked into `apis/`. + +... +``` diff --git a/docguide/VERSION b/docguide/VERSION new file mode 100644 index 000000000..d3827e75a --- /dev/null +++ b/docguide/VERSION @@ -0,0 +1 @@ +1.0 diff --git a/docguide/best_practices.md b/docguide/best_practices.md new file mode 100644 index 000000000..8f02545ba --- /dev/null +++ b/docguide/best_practices.md @@ -0,0 +1,115 @@ +# Documentation Best Practices + +"Say what you mean, simply and directly." - [Brian Kernighan] +(https://en.wikipedia.org/wiki/The_Elements_of_Programming_Style) + +Contents: + +1. [Minimum viable documentation](#minimum-viable-documentation) +1. [Update docs with code](#update-docs-with-code) +1. [Delete dead documentation](#delete-dead-documentation) +1. [Documentation is the story of your code](#documentation-is-the-story-of-your-code) + +## Minimum viable documentation + +A small set of fresh and accurate docs are better than a sprawling, loose +assembly of "documentation" in various states of disrepair. + +Write short and useful documents. Cut out everything unnecessary, while also +making a habit of continually massaging and improving every doc to suit your +changing needs. **Docs work best when they are alive but frequently trimmed, +like a bonsai tree**. + +This guide encourages engineers to take ownership of their docs and keep +them up to date with the same zeal we keep our tests in good order. Strive for +this. + +* Identify what you really need: release docs, API docs, testing guidelines. +* Delete cruft frequently and in small batches. + +## Update docs with code + +**Change your documentation in the same CL as the code change**. This keeps your +docs fresh, and is also a good place to explain to your reviewer what you're +doing. + +A good reviewer can at least insist that docstrings, header files, README.md +files, and any other docs get updated alongside the CL. + +## Delete dead documentation + +Dead docs are bad. They misinform, they slow down, they incite despair in +engineers and laziness in team leads. They set a precedent for leaving behind +messes in a code base. If your home is clean, most guests will be clean without +being asked. + +Just like any big cleaning project, **it's easy to be overwhelmed**. If your +docs are in bad shape: + +* Take it slow, doc health is a gradual accumulation. +* First delete what you're certain is wrong, ignore what's unclear. +* Get your whole team involved. Devote time to quickly scan every doc and make + a simple decision: Keep or delete? +* Default to delete or leave behind if migrating. Stragglers can always be + recovered. +* Iterate. + +## Prefer the good over the perfect + +Your documentation should be as good as possible within a reasonable time frame. +The standards for an documentation review are different from the +standards for code reviews. Reviewers can and should ask for improvements, but +in general, the author should always be able to invoke the "Good Over Perfect +Rule". It's preferable to allow authors to quickly submit changes that improve +the document, instead of forcing rounds of review until it's "perfect". Docs are +never perfect, and tend to gradually improve as the team learns what they really +need to write down. + +## Documentation is the story of your code + +Writing excellent code doesn't end when your code compiles or even if your +test coverage reaches 100%. It's easy to write something a computer understands, +it's much harder to write something both a human and a computer understand. Your +mission as a Code Health-conscious engineer is to **write for humans first, +computers second.** Documentation is an important part of this skill. + +There's a spectrum of engineering documentation that ranges from terse comments +to detailed prose: + +1. **Inline comments**: The primary purpose of inline comments is to provide + information that the code itself cannot contain, such as why the code is + there. + +2. **Method and class comments**: + + * **Method API documentation**: The header / Javadoc / docstring + comments that say what methods do and how to use them. This + documentation is **the contract of how your code must behave**. The + intended audience is future programmers who will use and modify your + code. + + It is often reasonable to say that any behavior documented here should + have a test verifying it. This documentation details what arguments the + method takes, what it returns, any "gotchas" or restrictions, and what + exceptions it can throw or errors it can return. It does not usually + explain why code behaves a particular way unless that's relevant to a + developer's understanding of how to use the method. "Why" explanations + are for inline comments. Think in practical terms when writing method + documentation: "This is a hammer. You use it to pound nails." + + * **Class / Module API documentation**: The header / Javadoc / docstring + comments for a class or a whole file. This documentation gives a brief + overview of what the class / file does and often gives a few short + examples of how you might use the class / file. + + Examples are particularly relevant when there's several distinct ways to + use the class (some advanced, some simple). Always list the simplest + use case first. + +3. **README.md**: A good README.md orients the new user to the directory and + points to more detailed explanation and user guides: + * What is this directory intended to hold? + * Which files should the developer look at first? Are some files an API? + * Who maintains this directory and where I can learn more? + + See the [README.md guidelines](READMEs.md). diff --git a/docguide/philosophy.md b/docguide/philosophy.md new file mode 100644 index 000000000..0937c5bb7 --- /dev/null +++ b/docguide/philosophy.md @@ -0,0 +1,71 @@ +# Philosophy + +埏埴以為器,當其無,有器之用. + +*Clay becomes pottery through craft, but it's the emptiness that makes a pot +useful.* + +\- [Laozi](http://ctext.org/dictionary.pl?if=en&id=11602) + +Contents: + +1. [Radical simplicity](#radical-simplicity) +1. [Readable source text](#readable-source-text) +1. [Minimum viable documentation](#minimum-viable-documentation) +1. [Better is better than perfect](#better-is-better-than-perfect) + +## Radical simplicity + +* **Scalability and interoperability** are more important than a menagerie of + unessential features. Scale comes from simplicity, speed, and ease. + Interoperability comes from unadorned, digestable content. + +* **Fewer distractions** make for better writing and more productive reading. + +* **New features should never interfere with the simplest use case** and should + remain invisible to users who don't need them. + +* **This guide is designed for the average engineer** -- the busy, + just-want-to-go-back-to-coding engineer. Large and complex documentation is + possible but not the primary focus. + +* **Minimizing context switching makes people happier.** Engineers should be + able to interact with documentation using the same tools they use to read and + write code. + +## Readable source text + +* **Plain text not only suffices, it is superior**. Markdown itself is not + essential to this formula, but it is the best and most widely supported + solution right now. HTML is generally not encouraged. + +* **Content and presentation should not mingle**. It should always be possible + to ditch the renderer and read the essential information at source. Users + should never have to touch the presentation layer if they don't want to. + +* **Portability and future-proofing leave room for the unimagined integrations + to come**, and are best achieved by keeping the source as human-readable as + possible. + +* **Static content is better than dynamic**, because content should not depend + on the features of any one server. However, **fresh is better than stale**. We + strive to balance these needs. + +## Minimum viable documentation + +* **Docs thrive when they're treated like tests**: a necessary chore one learns + to savor because it rewards over time. + See [Best Practices](best_practices.md). + +* **Brief and utilitarian is better than long and exhaustive**. The vast + majority of users need only a small fraction of the author's total knowledge, + but they need it quickly and often. + +## Better is better than perfect + +* **Incremental improvement is better than prolonged debate**. Patience and + tolerance of imperfection allow projects to evolve organically. + +* **Don't lick the cookie, pass the plate**. We're drowning in potentially + impactful projects. Choose only those you can really handle and release those + you can't. diff --git a/docguide/style.md b/docguide/style.md new file mode 100644 index 000000000..f00d61e52 --- /dev/null +++ b/docguide/style.md @@ -0,0 +1,420 @@ +# Markdown style guide + +Much of what makes Markdown great is the ability to write plain text, and get +great formatted output as a result. To keep the slate clean for the next author, +your Markdown should be simple and consistent with the whole corpus wherever +possible. + +We seek to balance three goals: + +1. *Source text is readable and portable.* +2. *Markdown files are maintainable over time and across teams.* +3. *The syntax is simple and easy to remember.* + +Contents: + +1. [Document layout](#document-layout) +1. [Character line limit](#character-line-limit) +1. [Trailing whitespace](#trailing-whitespace) +1. [Headings](#headings) + 1. [ATX-style headings](#atx-style-headings) + 1. [Add spacing to headings](#add-spacing-to-headings) +1. [Lists](#lists) + 1. [Use lazy numbering for long lists](#use-lazy-numbering-for-long-lists) + 1. [Nested list spacing](#nested-list-spacing) +1. [Code](#code) + 1. [Inline](#inline) + 1. [Codeblocks](#codeblocks) + 1. [Declare the language](#declare-the-language) + 1. [Escape newlines](#escape-newlines) + 1. [Nest codeblocks within lists](#nest-codeblocks-within-lists) +1. [Links](#links) + 1. [Use informative Markdown link titles](#use-informative-markdown-link-titles) +1. [Images](#images) +1. [Prefer lists to tables](#prefer-lists-to-tables) +1. [Strongly prefer Markdown to HTML](#strongly-prefer-markdown-to-html) + +## Document layout + +In general, most documents benefit from some variation of the following layout: + +```markdown +# Document Title + +Short introduction. + +[TOC] + +## Topic + +Content. + +## See also + +* https://link-to-more-info +``` + +1. `# Document Title`: The first heading should be a level one heading, and + should ideally be the same or nearly the same as the filename. The first + level one heading is used as the page ``. + +1. `author`: *Optional*. If you'd like to claim ownership of the document or + if you are very proud of it, add yourself under the title. However, + revision history generally suffices. + +1. `Short introduction.` 1-3 sentences providing a high-level overview of the + topic. Imagine yourself as a complete newbie, who landed on your "Extending + Foo" doc and needs to know the most basic assumptions you take for granted. + "What is Foo? Why would I extend it?" + +1. `[TOC]`: if you use hosting that supports table of contents, such as Gitiles, + put `[TOC]` after the short introduction. See + [`[TOC]` documentation](https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md#Table-of-contents). + +1. `## Topic`: The rest of your headings should start from level 2. + +1. `## See also`: Put miscellaneous links at the bottom for the user who wants + to know more or didn't find what she needed. + +## Character line limit + +Obey projects' character line limit wherever possible. Long URLs and tables are +the usual suspects when breaking the rule. (Headings also can't be wrapped, but +we encourage keeping them short). Otherwise, wrap your text: + +```markdown +Lorem ipsum dolor sit amet, nec eius volumus patrioque cu, nec et commodo +hendrerit, id nobis saperet fuisset ius. + +* Malorum moderatius vim eu. In vix dico persecuti. Te nam saperet percipitur + interesset. See the [foo docs](https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md). +``` + +Often, inserting a newline before a long link preserves readability while +minimizing the overflow: + +```markdown +Lorem ipsum dolor sit amet. See the +[foo docs](https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md) +for details. +``` + +## Trailing whitespace + +Don't use trailing whitespace, use a trailing backslash. + +The [CommonMark spec](http://spec.commonmark.org/0.20/#hard-line-breaks) decrees +that two spaces at the end of a line should insert a `<br />` tag. However, many +directories have a trailing whitespace presubmit check in place, and many IDEs +will clean it up anyway. + +Best practice is to avoid the need for a `<br />` altogether. Markdown creates +paragraph tags for you simply with newlines: get used to that. + +## Headings + +### ATX-style headings + +```markdown +## Heading 2 +``` + +Headings with `=` or `-` underlines can be annoying to maintain and don't fit +with the rest of the heading syntax. The user has to ask: Does `---` mean H1 or +H2? + +```markdown +Heading - do you remember what level? DO NOT DO THIS. +--------- +``` + +### Add spacing to headings + +Prefer spacing after `#` and newlines before and after: + +```markdown +...text before. + +# Heading 1 + +Text after... +``` + +Lack of spacing makes it a little harder to read in source: + +```markdown +...text before. + +#Heading 1 +Text after... DO NOT DO THIS. +``` + +## Lists + +### Use lazy numbering for long lists + +Markdown is smart enough to let the resulting HTML render your numbered lists +correctly. For longer lists that may change, especially long nested lists, use +"lazy" numbering: + +```markdown +1. Foo. +1. Bar. + 1. Foofoo. + 1. Barbar. +1. Baz. +``` + +However, if the list is small and you don't anticipate changing it, prefer fully +numbered lists, because it's nicer to read in source: + +```markdown +1. Foo. +2. Bar. +3. Baz. +``` + +### Nested list spacing + +When nesting lists, use a 4 space indent for both numbered and bulleted lists: + +```markdown +1. 2 spaces after a numbered list. + 4 space indent for wrapped text. +2. 2 spaces again. + +* 3 spaces after a bullet. + 4 space indent for wrapped text. + 1. 2 spaces after a numbered list. + 8 space indent for the wrapped text of a nested list. + 2. Looks nice, don't it? +* 3 spaces after a bullet. +``` + +The following works, but it's very messy: + +```markdown +* One space, +with no indent for wrapped text. + 1. Irregular nesting... DO NOT DO THIS. +``` + +Even when there's no nesting, using the 4 space indent makes layout consistent +for wrapped text: + +```markdown +* Foo, + wrapped. + +1. 2 spaces + and 4 space indenting. +2. 2 spaces again. +``` + +However, when lists are small, not nested, and a single line, one space can +suffice for both kinds of lists: + +```markdown +* Foo +* Bar +* Baz. + +1. Foo. +2. Bar. +``` + +## Code + +### Inline + +`Backticks` designate `inline code`, and will render all wrapped content +literally. Use them for short code quotations and field names: + +```markdown +You'll want to run `really_cool_script.sh arg`. + +Pay attention to the `foo_bar_whammy` field in that table. +``` + +Use inline code when referring to file types in an abstract sense, rather than a +specific file: + +```markdown +Be sure to update your `README.md`! +``` + +Backticks are the most common approach for "escaping" Markdown metacharacters; +in most situations where escaping would be needed, code font just makes sense +anyway. + +### Codeblocks + +For code quotations longer than a single line, use a codeblock: + +<pre> +```python +def Foo(self, bar): + self.bar = bar +``` +</pre> + +#### Declare the language + +It is best practice to explicitly declare the language, so that neither the +syntax highlighter nor the next editor must guess. + +#### Indented codeblocks are sometimes cleaner + +Four-space indenting is also interpreted as a codeblock. These can look +cleaner and be easier to read in source, but there is no way to specify the +language. We encourage their use when writing many short snippets: + +```markdown +You'll need to run: + + bazel run :thing -- --foo + +And then: + + bazel run :another_thing -- --bar + +And again: + + bazel run :yet_again -- --baz +``` + +#### Escape newlines + +Because most commandline snippets are intended to be copied and pasted directly +into a terminal, it's best practice to escape any newlines. Use a single +backslash at the end of the line: + +<pre> +```shell +bazel run :target -- --flag --foo=longlonglonglonglongvalue \ +--bar=anotherlonglonglonglonglonglonglonglonglonglongvalue +``` +</pre> + +#### Nest codeblocks within lists + +If you need a codeblock within a list, make sure to indent it so as to not break +the list: + +```markdown +* Bullet. + + ```c++ + int foo; + ``` + +* Next bullet. +``` + +You can also create a nested code block with 4 spaces. Simply indent 4 +additional spaces from the list indentation: + +```markdown +* Bullet. + + int foo; + +* Next bullet. +``` + +## Links + +Long links make source Markdown difficult to read and break the 80 character +wrapping. **Wherever possible, shorten your links**. + +### Use informative Markdown link titles + +Markdown link syntax allows you to set a link title, just as HTML does. Use it +wisely. + +Titling your links as "link" or "here" tells the reader precisely nothing when +quickly scanning your doc and is a waste of space: + +```markdown +See the syntax guide for more info: [link](syntax_guide.md). +Or, check out the style guide [here](style_guide.md). +DO NOT DO THIS. +``` + +Instead, write the sentence naturally, then go back and wrap the most +appropriate phrase with the link: + +```markdown +See the [syntax guide](syntax_guide.md) for more info. +Or, check out the [style guide](style_guide.md). +``` + +## Images + +Use images sparingly, and prefer simple screenshots. This guide is designed +around the idea that plain text gets users down to the business of communication +faster with less reader distraction and author procrastination. However, it's +sometimes very helpful to show what you mean. + +See [image syntax](https://gerrit.googlesource.com/gitiles/+/master/Documentation/markdown.md#Images). + +## Prefer lists to tables + +Any tables in your Markdown should be small. Complex, large tables are difficult +to read in source and most importantly, **a pain to modify later**. + +```markdown +Fruit | Attribute | Notes +--- | --- | --- | --- +Apple | [Juicy](https://example.com/SomeReallyReallyReallyReallyReallyReallyReallyReallyLongQuery), Firm, Sweet | Apples keep doctors away. +Banana | [Convenient](https://example.com/SomeDifferentReallyReallyReallyReallyReallyReallyReallyReallyLongQuery), Soft, Sweet | Contrary to popular belief, most apes prefer mangoes. + +DO NOT DO THIS +``` + +[Lists](#lists) and subheadings usually suffice to present the same information +in a slightly less compact, though much more edit-friendly way: + +```markdown +## Fruits + +### Apple + +* [Juicy](https://SomeReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongURL) +* Firm +* Sweet + +Apples keep doctors away. + +### Banana + +* [Convenient](https://example.com/SomeDifferentReallyReallyReallyReallyReallyReallyReallyReallyLongQuery) +* Soft +* Sweet + +Contrary to popular belief, most apes prefer mangoes. +``` + +However, there are times when a small table is called for: + +```markdown +Transport | Favored by | Advantages +--- | --- | --- +Swallow | Coconuts | Otherwise unladen +Bicycle | Miss Gulch | Weatherproof +X-34 landspeeder | Whiny farmboys | Cheap since the X-38 came out +``` + +## Strongly prefer Markdown to HTML + +Please prefer standard Markdown syntax wherever possible and avoid HTML hacks. +If you can't seem to accomplish what you want, reconsider whether you really +need it. Except for [big tables](#prefer-lists-to-tables), Markdown meets almost +all needs already. + +Every bit of HTML or Javascript hacking reduces the readability and portability. +This in turn limits the usefulness of integrations with +other tools, which may either present the source as plain text or render it. See +[Philosophy](philosophy.md). + +Gitiles does not render HTML. diff --git a/eclipse-cpp-google-style.xml b/eclipse-cpp-google-style.xml new file mode 100644 index 000000000..aa05a819a --- /dev/null +++ b/eclipse-cpp-google-style.xml @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<profiles version="1"> +<profile kind="CodeFormatterProfile" name="Google C++" version="1"> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.lineSplit" value="80"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_member_access" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_base_types" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.keep_else_statement_on_same_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_constructor_initializer_list" value="83"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_exception_specification" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_base_types" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_access_specifier" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_exception_specification" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_arguments" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_declarator_list" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_bracket" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.tabulation.size" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_enumerator_list" value="51"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_declarator_list" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_empty_lines" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.put_empty_statement_on_new_line" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_arguments" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_base_clause" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.join_wrapped_lines" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_declarator_list" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_arguments_in_method_invocation" value="18"/> +<setting id="org.eclipse.cdt.core.formatter.comment.never_indent_line_comments_on_first_column" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_brackets" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_bracket" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_parameters_in_method_declaration" value="18"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_expression_list" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.continuation_indentation" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_expression_list" value="0"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_binary_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression" value="34"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_extra_spaces" value="1"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_access_specifier_compare_to_type_header" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_body_declarations_compare_to_namespace_header" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_compact_if" value="0"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_assignment" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_conditional_expression_chain" value="18"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_template_parameters" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_expression_list" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_exception_specification" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_binary_operator" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_identifier_in_function_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_base_clause_in_type_declaration" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_between_empty_parens_in_exception_specification" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_declaration_compare_to_template_header" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_body" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_binary_expression" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.indent_statements_compare_to_block" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_template_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_angle_bracket_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.tabulation.char" value="space"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_parameters" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_colon_in_constructor_initializer_list" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.compact_else_if" value="true"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_template_declaration" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_base_clause" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.keep_then_statement_on_same_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_switch" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.alignment_for_overloaded_left_shift_chain" value="18"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.keep_imple_if_on_one_line" value="false"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.indentation.size" value="2"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_namespace_declaration" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_angle_bracket_in_template_arguments" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_brace_in_namespace_declaration" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_closing_bracket" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_closing_angle_bracket_in_template_parameters" value="insert"/> +<setting id="org.eclipse.cdt.core.formatter.insert_space_after_opening_angle_bracket_in_template_arguments" value="do not insert"/> +</profile> +</profiles> diff --git a/eclipse-java-google-style.xml b/eclipse-java-google-style.xml new file mode 100644 index 000000000..7bb6804eb --- /dev/null +++ b/eclipse-java-google-style.xml @@ -0,0 +1,337 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<profiles version="13"> +<profile kind="CodeFormatterProfile" name="GoogleStyle" version="13"> +<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments.count_dependent" value="16|-1|16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_prefer_two_fragments" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_comment_inline_tags" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_local_variable_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="1040"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type.count_dependent" value="1585|-1|1585"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields.count_dependent" value="16|-1|16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression.count_dependent" value="16|4|80"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration.count_dependent" value="16|4|48"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration.count_dependent" value="16|4|49"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_cascading_method_invocation_with_arguments" value="16"/> +<setting id="org.eclipse.jdt.core.compiler.source" value="1.7"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration.count_dependent" value="16|4|48"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_non_simple_local_variable_annotation" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants.count_dependent" value="16|5|48"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="100"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation.count_dependent" value="16|4|48"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="1585"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="16"/> +<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/> +<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_non_simple_type_annotation" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_field_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.comment_new_line_at_start_of_html_paragraph" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comment_prefix" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_non_simple_parameter_annotation" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="1585"/> +<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation.count_dependent" value="16|5|80"/> +<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter.count_dependent" value="1040|-1|1040"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package.count_dependent" value="1585|-1|1585"/> +<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.force_if_else_statement_brace" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="3"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_non_simple_package_annotation" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation.count_dependent" value="16|-1|16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="1585"/> +<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.7"/> +<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_new_anonymous_class" value="20"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable.count_dependent" value="1585|-1|1585"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field.count_dependent" value="1585|-1|1585"/> +<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration.count_dependent" value="16|5|80"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/> +<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant.count_dependent" value="16|-1|16"/> +<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="100"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="2"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="1585"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer.count_dependent" value="16|5|80"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.7"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/> +<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration.count_dependent" value="16|4|48"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method.count_dependent" value="1585|-1|1585"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression.count_dependent" value="16|-1|16"/> +<setting id="org.eclipse.jdt.core.formatter.wrap_non_simple_member_annotation" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="1585"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call.count_dependent" value="16|5|80"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_generic_type_arguments.count_dependent" value="16|-1|16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression.count_dependent" value="16|5|80"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration.count_dependent" value="16|5|80"/> +<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> +<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.alignment_for_for_statement" value="16"/> +<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/> +<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/> +<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/> +</profile> +</profiles> diff --git a/google-c-style.el b/google-c-style.el new file mode 100644 index 000000000..9bb12c61a --- /dev/null +++ b/google-c-style.el @@ -0,0 +1,151 @@ +;;; google-c-style.el --- Google's C/C++ style for c-mode + +;; Keywords: c, tools + +;; google-c-style.el is Copyright (C) 2008 Google Inc. All Rights Reserved. +;; +;; It is free software; you can redistribute it and/or modify it under the +;; terms of either: +;; +;; a) the GNU General Public License as published by the Free Software +;; Foundation; either version 1, or (at your option) any later version, or +;; +;; b) the "Artistic License". + +;;; Commentary: + +;; Provides the google C/C++ coding style. You may wish to add +;; `google-set-c-style' to your `c-mode-common-hook' after requiring this +;; file. For example: +;; +;; (add-hook 'c-mode-common-hook 'google-set-c-style) +;; +;; If you want the RETURN key to go to the next line and space over +;; to the right place, add this to your .emacs right after the load-file: +;; +;; (add-hook 'c-mode-common-hook 'google-make-newline-indent) + +;;; Code: + +;; For some reason 1) c-backward-syntactic-ws is a macro and 2) under Emacs 22 +;; bytecode cannot call (unexpanded) macros at run time: +(eval-when-compile (require 'cc-defs)) + +;; Wrapper function needed for Emacs 21 and XEmacs (Emacs 22 offers the more +;; elegant solution of composing a list of lineup functions or quantities with +;; operators such as "add") +(defun google-c-lineup-expression-plus-4 (langelem) + "Indents to the beginning of the current C expression plus 4 spaces. + +This implements title \"Function Declarations and Definitions\" +of the Google C++ Style Guide for the case where the previous +line ends with an open parenthese. + +\"Current C expression\", as per the Google Style Guide and as +clarified by subsequent discussions, means the whole expression +regardless of the number of nested parentheses, but excluding +non-expression material such as \"if(\" and \"for(\" control +structures. + +Suitable for inclusion in `c-offsets-alist'." + (save-excursion + (back-to-indentation) + ;; Go to beginning of *previous* line: + (c-backward-syntactic-ws) + (back-to-indentation) + (cond + ;; We are making a reasonable assumption that if there is a control + ;; structure to indent past, it has to be at the beginning of the line. + ((looking-at "\\(\\(if\\|for\\|while\\)\\s *(\\)") + (goto-char (match-end 1))) + ;; For constructor initializer lists, the reference point for line-up is + ;; the token after the initial colon. + ((looking-at ":\\s *") + (goto-char (match-end 0)))) + (vector (+ 4 (current-column))))) + +;;;###autoload +(defconst google-c-style + `((c-recognize-knr-p . nil) + (c-enable-xemacs-performance-kludge-p . t) ; speed up indentation in XEmacs + (c-basic-offset . 2) + (indent-tabs-mode . nil) + (c-comment-only-line-offset . 0) + (c-hanging-braces-alist . ((defun-open after) + (defun-close before after) + (class-open after) + (class-close before after) + (inexpr-class-open after) + (inexpr-class-close before) + (namespace-open after) + (inline-open after) + (inline-close before after) + (block-open after) + (block-close . c-snug-do-while) + (extern-lang-open after) + (extern-lang-close after) + (statement-case-open after) + (substatement-open after))) + (c-hanging-colons-alist . ((case-label) + (label after) + (access-label after) + (member-init-intro before) + (inher-intro))) + (c-hanging-semi&comma-criteria + . (c-semi&comma-no-newlines-for-oneline-inliners + c-semi&comma-inside-parenlist + c-semi&comma-no-newlines-before-nonblanks)) + (c-indent-comments-syntactically-p . t) + (comment-column . 40) + (c-indent-comment-alist . ((other . (space . 2)))) + (c-cleanup-list . (brace-else-brace + brace-elseif-brace + brace-catch-brace + empty-defun-braces + defun-close-semi + list-close-comma + scope-operator)) + (c-offsets-alist . ((arglist-intro google-c-lineup-expression-plus-4) + (func-decl-cont . ++) + (member-init-intro . ++) + (inher-intro . ++) + (comment-intro . 0) + (arglist-close . c-lineup-arglist) + (topmost-intro . 0) + (block-open . 0) + (inline-open . 0) + (substatement-open . 0) + (statement-cont + . + (,(when (fboundp 'c-no-indent-after-java-annotations) + 'c-no-indent-after-java-annotations) + ,(when (fboundp 'c-lineup-assignments) + 'c-lineup-assignments) + ++)) + (label . /) + (case-label . +) + (statement-case-open . +) + (statement-case-intro . +) ; case w/o { + (access-label . /) + (innamespace . 0)))) + "Google C/C++ Programming Style.") + +;;;###autoload +(defun google-set-c-style () + "Set the current buffer's c-style to Google C/C++ Programming + Style. Meant to be added to `c-mode-common-hook'." + (interactive) + (make-local-variable 'c-tab-always-indent) + (setq c-tab-always-indent t) + (c-add-style "Google" google-c-style t)) + +;;;###autoload +(defun google-make-newline-indent () + "Sets up preferred newline behavior. Not set by default. Meant + to be added to `c-mode-common-hook'." + (interactive) + (define-key c-mode-base-map "\C-m" 'newline-and-indent) + (define-key c-mode-base-map [ret] 'newline-and-indent)) + +(provide 'google-c-style) +;;; google-c-style.el ends here diff --git a/google-r-style.html b/google-r-style.html new file mode 100644 index 000000000..21a73f6e1 --- /dev/null +++ b/google-r-style.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf8"> + <meta http-equiv="content-type" content="text/html;charset=utf-8"> + <meta http-equiv="refresh" content="1; url=Rguide.xml"> + <title>Redirecting + + + + Redirecting you to Rguide.xml. + + diff --git a/htmlcssguide.html b/htmlcssguide.html new file mode 100644 index 000000000..79ebafe2e --- /dev/null +++ b/htmlcssguide.html @@ -0,0 +1,877 @@ + + + + +Google HTML/CSS Style Guide + + + + + + +
+

Google HTML/CSS Style Guide

+

1 Background

+ +

This document defines formatting and style rules for HTML and CSS. It aims at +improving collaboration, code quality, and enabling supporting infrastructure. +It applies to raw, working files that use HTML and CSS, including GSS files. +Tools are free to obfuscate, minify, and compile as long as the general code +quality is maintained.

+ +

2 General

+ +

2.1 General Style Rules

+ +

2.1.1 Protocol

+ +

Use the HTTPS protocol for embedded resources where possible.

+ +

Always use the HTTPS protocol (https:) for images and other media +files, style sheets, and scripts, unless the respective files are not available +over HTTPS.

+ +
<!-- Not recommended: omits the protocol -->
+<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
+
+<!-- Not recommended: uses the HTTP protocol -->
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
+
+ +
<!-- Recommended -->
+<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
+
+ +
/* Not recommended: omits the protocol */
+@import '//fonts.googleapis.com/css?family=Open+Sans';
+
+/* Not recommended: uses the HTTP protocol */
+@import 'http://fonts.googleapis.com/css?family=Open+Sans';
+
+ +
/* Recommended */
+@import 'https://fonts.googleapis.com/css?family=Open+Sans';
+
+ +

2.2 General Formatting Rules

+ +

2.2.1 Indentation

+ +

Indent by 2 spaces at a time.

+ +

Don’t use tabs or mix tabs and spaces for indentation.

+ +
<ul>
+  <li>Fantastic
+  <li>Great
+</ul>
+
+ +
.example {
+  color: blue;
+}
+
+ +

2.2.2 Capitalization

+ +

Use only lowercase.

+ +

All code has to be lowercase: This applies to HTML element names, attributes, +attribute values (unless text/CDATA), CSS selectors, properties, and property +values (with the exception of strings).

+ +
<!-- Not recommended -->
+<A HREF="/">Home</A>
+
+ +
<!-- Recommended -->
+<img src="google.png" alt="Google">
+
+ +
/* Not recommended */
+color: #E5E5E5;
+
+ +
/* Recommended */
+color: #e5e5e5;
+
+ +

2.2.3 Trailing Whitespace

+ +

Remove trailing white spaces.

+ +

Trailing white spaces are unnecessary and can complicate diffs.

+ +
<!-- Not recommended -->
+<p>What?_
+
+ +
<!-- Recommended -->
+<p>Yes please.
+
+ +

2.3 General Meta Rules

+ +

2.3.1 Encoding

+ +

Use UTF-8 (no BOM).

+ +

Make sure your editor uses UTF-8 as character encoding, without a byte order +mark.

+ +

Specify the encoding in HTML templates and documents via <meta +charset="utf-8">. Do not specify the encoding of style sheets as these assume +UTF-8.

+ +

(More on encodings and when and how to specify them can be found in Handling +character encodings in HTML and CSS.)

+ +

2.3.2 Comments

+ +

Explain code as needed, where possible.

+ +

Use comments to explain code: What does it cover, what purpose does it serve, +why is respective solution used or preferred?

+ +

(This item is optional as it is not deemed a realistic expectation to always +demand fully documented code. Mileage may vary heavily for HTML and CSS code and +depends on the project’s complexity.)

+ +

2.3.3 Action Items

+ +

Mark todos and action items with TODO.

+ +

Highlight todos by using the keyword TODO only, not other common formats like +@@.

+ +

Append a contact (username or mailing list) in parentheses as with the format +TODO(contact).

+ +

Append action items after a colon as in TODO: action item.

+ +
{# TODO(john.doe): revisit centering #}
+<center>Test</center>
+
+ +
<!-- TODO: remove optional tags -->
+<ul>
+  <li>Apples</li>
+  <li>Oranges</li>
+</ul>
+
+ +

3 HTML

+ +

3.1 HTML Style Rules

+ +

3.1.1 Document Type

+ +

Use HTML5.

+ +

HTML5 (HTML syntax) is preferred for all HTML documents: <!DOCTYPE html>.

+ +

(It’s recommended to use HTML, as text/html. Do not use XHTML. XHTML, as +application/xhtml+xml, lacks both browser +and infrastructure support and offers less room for optimization than HTML.)

+ +

Although fine with HTML, do not close void elements, i.e. write <br>, not +<br />.

+ +

3.1.2 HTML Validity

+ +

Use valid HTML where possible.

+ +

Use valid HTML code unless that is not possible due to otherwise unattainable +performance goals regarding file size.

+ +

+ +Use tools such as the W3C HTML validator +to test. +

+ +

Using valid HTML is a measurable baseline quality attribute that contributes to +learning about technical requirements and constraints, and that ensures proper +HTML usage.

+ +
<!-- Not recommended -->
+<title>Test</title>
+<article>This is only a test.
+
+ +
<!-- Recommended -->
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Test</title>
+<article>This is only a test.</article>
+
+ +

3.1.3 Semantics

+ +

Use HTML according to its purpose.

+ +

Use elements (sometimes incorrectly called “tags”) for what they have been +created for. For example, use heading elements for headings, p elements for +paragraphs, a elements for anchors, etc.

+ +

Using HTML according to its purpose is important for accessibility, reuse, and +code efficiency reasons.

+ +
<!-- Not recommended -->
+<div onclick="goToRecommendations();">All recommendations</div>
+
+ +
<!-- Recommended -->
+<a href="recommendations/">All recommendations</a>
+
+ +

3.1.4 Multimedia Fallback

+ +

Provide alternative contents for multimedia.

+ +

For multimedia, such as images, videos, animated objects via canvas, make sure +to offer alternative access. For images that means use of meaningful alternative +text (alt) and for video and audio transcripts and captions, if available.

+ +

Providing alternative contents is important for accessibility reasons: A blind +user has few cues to tell what an image is about without @alt, and other users +may have no way of understanding what video or audio contents are about either.

+ +

(For images whose alt attributes would introduce redundancy, and for images +whose purpose is purely decorative which you cannot immediately use CSS for, use +no alternative text, as in alt="".)

+ +
<!-- Not recommended -->
+<img src="spreadsheet.png">
+
+ +
<!-- Recommended -->
+<img src="spreadsheet.png" alt="Spreadsheet screenshot.">
+
+ +

3.1.5 Separation of Concerns

+ +

Separate structure from presentation from behavior.

+ +

Strictly keep structure (markup), presentation (styling), and behavior +(scripting) apart, and try to keep the interaction between the three to an +absolute minimum.

+ +

That is, make sure documents and templates contain only HTML and HTML that is +solely serving structural purposes. Move everything presentational into style +sheets, and everything behavioral into scripts.

+ +

In addition, keep the contact area as small as possible by linking as few style +sheets and scripts as possible from documents and templates.

+ +

Separating structure from presentation from behavior is important for +maintenance reasons. It is always more expensive to change HTML documents and +templates than it is to update style sheets and scripts.

+ +
<!-- Not recommended -->
+<!DOCTYPE html>
+<title>HTML sucks</title>
+<link rel="stylesheet" href="base.css" media="screen">
+<link rel="stylesheet" href="grid.css" media="screen">
+<link rel="stylesheet" href="print.css" media="print">
+<h1 style="font-size: 1em;">HTML sucks</h1>
+<p>I’ve read about this on a few sites but now I’m sure:
+  <u>HTML is stupid!!1</u>
+<center>I can’t believe there’s no way to control the styling of
+  my website without doing everything all over again!</center>
+
+ +
<!-- Recommended -->
+<!DOCTYPE html>
+<title>My first CSS-only redesign</title>
+<link rel="stylesheet" href="default.css">
+<h1>My first CSS-only redesign</h1>
+<p>I’ve read about this on a few sites but today I’m actually
+  doing it: separating concerns and avoiding anything in the HTML of
+  my website that is presentational.
+<p>It’s awesome!
+
+ +

3.1.6 Entity References

+ +

Do not use entity references.

+ +

There is no need to use entity references like &mdash;, &rdquo;, or +&#x263a;, assuming the same encoding (UTF-8) is used for files and editors +as well as among teams.

+ +

The only exceptions apply to characters with special meaning in HTML (like < +and &) as well as control or “invisible” characters (like no-break spaces).

+ +
<!-- Not recommended -->
+The currency symbol for the Euro is &ldquo;&eur;&rdquo;.
+
+ +
<!-- Recommended -->
+The currency symbol for the Euro is “€”.
+
+ +

3.1.7 Optional Tags

+ +

Omit optional tags (optional).

+ +

For file size optimization and scannability purposes, consider omitting optional +tags. The HTML5 specification +defines what tags can be omitted.

+ +

(This approach may require a grace period to be established as a wider guideline +as it’s significantly different from what web developers are typically taught. +For consistency and simplicity reasons it’s best served omitting all optional +tags, not just a selection.)

+ +
<!-- Not recommended -->
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Spending money, spending bytes</title>
+  </head>
+  <body>
+    <p>Sic.</p>
+  </body>
+</html>
+
+ +
<!-- Recommended -->
+<!DOCTYPE html>
+<title>Saving money, saving bytes</title>
+<p>Qed.
+
+ +

3.1.8 type Attributes

+ +

Omit type attributes for style sheets and scripts.

+ +

Do not use type attributes for style sheets (unless not using CSS) and scripts +(unless not using JavaScript).

+ +

Specifying type attributes in these contexts is not necessary as HTML5 implies +text/css +and text/javascript +as defaults. This can be safely done even for older browsers.

+ +
<!-- Not recommended -->
+<link rel="stylesheet" href="https://www.google.com/css/maia.css"
+  type="text/css">
+
+ +
<!-- Recommended -->
+<link rel="stylesheet" href="https://www.google.com/css/maia.css">
+
+ +
<!-- Not recommended -->
+<script src="https://www.google.com/js/gweb/analytics/autotrack.js"
+  type="text/javascript"></script>
+
+ +
<!-- Recommended -->
+<script src="https://www.google.com/js/gweb/analytics/autotrack.js"></script>
+
+ +

3.2 HTML Formatting Rules

+ +

3.2.1 General Formatting

+ +

Use a new line for every block, list, or table element, and indent every such +child element.

+ +

Independent of the styling of an element (as CSS allows elements to assume a +different role per display property), put every block, list, or table element +on a new line.

+ +

Also, indent them if they are child elements of a block, list, or table element.

+ +

(If you run into issues around whitespace between list items it’s acceptable to +put all li elements in one line. A linter is encouraged to throw a warning +instead of an error.)

+ +
<blockquote>
+  <p><em>Space</em>, the final frontier.</p>
+</blockquote>
+
+ +
<ul>
+  <li>Moe
+  <li>Larry
+  <li>Curly
+</ul>
+
+ +
<table>
+  <thead>
+    <tr>
+      <th scope="col">Income
+      <th scope="col">Taxes
+  <tbody>
+    <tr>
+      <td>$ 5.00
+      <td>$ 4.50
+</table>
+
+ +

3.2.2 HTML Line-Wrapping

+ +

Break long lines (optional).

+ +

While there is no column limit recommendation for HTML, you may consider +wrapping long lines if it significantly improves readability.

+ +

When line-wrapping, each continuation line should be indented at least 4 +additional spaces from the original line.

+ +
<md-progress-circular md-mode="indeterminate" class="md-accent"
+    ng-show="ctrl.loading" md-diameter="35">
+</md-progress-circular>
+
+ +
<md-progress-circular
+    md-mode="indeterminate"
+    class="md-accent"
+    ng-show="ctrl.loading"
+    md-diameter="35">
+</md-progress-circular>
+
+ +
<md-progress-circular md-mode="indeterminate"
+                      class="md-accent"
+                      ng-show="ctrl.loading"
+                      md-diameter="35">
+</md-progress-circular>
+
+ +

3.2.3 HTML Quotation Marks

+ +

When quoting attributes values, use double quotation marks.

+ +

Use double ("") rather than single quotation marks ('') around attribute +values.

+ +
<!-- Not recommended -->
+<a class='maia-button maia-button-secondary'>Sign in</a>
+
+ +
<!-- Recommended -->
+<a class="maia-button maia-button-secondary">Sign in</a>
+
+ +

4 CSS

+ +

4.1 CSS Style Rules

+ +

4.1.1 CSS Validity

+ +

Use valid CSS where possible.

+ +

Unless dealing with CSS validator bugs or requiring proprietary syntax, use +valid CSS code.

+ +

+ +Use tools such as the W3C CSS validator +to test. +

+ +

Using valid CSS is a measurable baseline quality attribute that allows to spot +CSS code that may not have any effect and can be removed, and that ensures +proper CSS usage.

+ +

4.1.2 ID and Class Naming

+ +

Use meaningful or generic ID and class names.

+ +

Instead of presentational or cryptic names, always use ID and class names that +reflect the purpose of the element in question, or that are otherwise generic.

+ +

Names that are specific and reflect the purpose of the element should be +preferred as these are most understandable and the least likely to change.

+ +

Generic names are simply a fallback for elements that have no particular or no +meaning different from their siblings. They are typically needed as “helpers.”

+ +

Using functional or generic names reduces the probability of unnecessary +document or template changes.

+ +
/* Not recommended: meaningless */
+#yee-1901 {}
+
+/* Not recommended: presentational */
+.button-green {}
+.clear {}
+
+ +
/* Recommended: specific */
+#gallery {}
+#login {}
+.video {}
+
+/* Recommended: generic */
+.aux {}
+.alt {}
+
+ +

4.1.3 ID and Class Name Style

+ +

Use ID and class names that are as short as possible but as long as necessary.

+ +

Try to convey what an ID or class is about while being as brief as possible.

+ +

Using ID and class names this way contributes to acceptable levels of +understandability and code efficiency.

+ +
/* Not recommended */
+#navigation {}
+.atr {}
+
+ +
/* Recommended */
+#nav {}
+.author {}
+
+ +

4.1.4 Type Selectors

+ +

Avoid qualifying ID and class names with type selectors.

+ +

Unless necessary (for example with helper classes), do not use element names in +conjunction with IDs or classes.

+ +

Avoiding unnecessary ancestor selectors is useful for performance reasons.

+ +
/* Not recommended */
+ul#example {}
+div.error {}
+
+ +
/* Recommended */
+#example {}
+.error {}
+
+ +

4.1.5 Shorthand Properties

+ +

Use shorthand properties where possible.

+ +

CSS offers a variety of shorthand +properties (like font) that should be used whenever possible, even in cases +where only one value is explicitly set.

+ +

Using shorthand properties is useful for code efficiency and understandability.

+ +
/* Not recommended */
+border-top-style: none;
+font-family: palatino, georgia, serif;
+font-size: 100%;
+line-height: 1.6;
+padding-bottom: 2em;
+padding-left: 1em;
+padding-right: 1em;
+padding-top: 0;
+
+ +
/* Recommended */
+border-top: 0;
+font: 100%/1.6 palatino, georgia, serif;
+padding: 0 1em 2em;
+
+ +

4.1.6 0 and Units

+ +

Omit unit specification after “0” values, unless required.

+ +

Do not use units after 0 values unless they are required.

+ +
flex: 0px; /* This flex-basis component requires a unit. */
+flex: 1 1 0px; /* Not ambiguous without the unit, but needed in IE11. */
+margin: 0;
+padding: 0;
+
+ +

4.1.7 Leading 0s

+ +

Omit leading “0”s in values.

+ +

Do not put 0s in front of values or lengths between -1 and 1.

+ +
font-size: .8em;
+
+ +

4.1.8 Hexadecimal Notation

+ +

Use 3 character hexadecimal notation where possible.

+ +

For color values that permit it, 3 character hexadecimal notation is shorter and +more succinct.

+ +
/* Not recommended */
+color: #eebbcc;
+
+ +
/* Recommended */
+color: #ebc;
+
+ +

4.1.9 Prefixes

+ +

Prefix selectors with an application-specific prefix (optional).

+ +

In large projects as well as for code that gets embedded in other projects or on +external sites use prefixes (as namespaces) for ID and class names. Use short, +unique identifiers followed by a dash.

+ +

Using namespaces helps preventing naming conflicts and can make maintenance +easier, for example in search and replace operations.

+ +
.adw-help {} /* AdWords */
+#maia-note {} /* Maia */
+
+ +

4.1.10 ID and Class Name Delimiters

+ +

Separate words in ID and class names by a hyphen.

+ +

Do not concatenate words and abbreviations in selectors by any characters +(including none at all) other than hyphens, in order to improve understanding +and scannability.

+ +
/* Not recommended: does not separate the words “demo” and “image” */
+.demoimage {}
+
+/* Not recommended: uses underscore instead of hyphen */
+.error_status {}
+
+ +
/* Recommended */
+#video-id {}
+.ads-sample {}
+
+ +

4.1.11 Hacks

+ +

Avoid user agent detection as well as CSS “hacks”—try a different approach +first.

+ +

It’s tempting to address styling differences over user agent detection or +special CSS filters, workarounds, and hacks. Both approaches should be +considered last resort in order to achieve and maintain an efficient and +manageable code base. Put another way, giving detection and hacks a free pass +will hurt projects in the long run as projects tend to take the way of least +resistance. That is, allowing and making it easy to use detection and hacks +means using detection and hacks more frequently—and more frequently is too +frequently.

+ +

4.2 CSS Formatting Rules

+ +

4.2.1 Declaration Order

+ +

Alphabetize declarations.

+ +

Put declarations in alphabetical order in order to achieve consistent code in a +way that is easy to remember and maintain.

+ +

Ignore vendor-specific prefixes for sorting purposes. However, multiple +vendor-specific prefixes for a certain CSS property should be kept sorted (e.g. +-moz prefix comes before -webkit).

+ +
background: fuchsia;
+border: 1px solid;
+-moz-border-radius: 4px;
+-webkit-border-radius: 4px;
+border-radius: 4px;
+color: black;
+text-align: center;
+text-indent: 2em;
+
+ +

4.2.2 Block Content Indentation

+ +

Indent all block content.

+ +

Indent all block content, +that is rules within rules as well as declarations, so to reflect hierarchy and +improve understanding.

+ +
@media screen, projection {
+
+  html {
+    background: #fff;
+    color: #444;
+  }
+
+}
+
+ +

4.2.3 Declaration Stops

+ +

Use a semicolon after every declaration.

+ +

End every declaration with a semicolon for consistency and extensibility +reasons.

+ +
/* Not recommended */
+.test {
+  display: block;
+  height: 100px
+}
+
+ +
/* Recommended */
+.test {
+  display: block;
+  height: 100px;
+}
+
+ +

4.2.4 Property Name Stops

+ +

Use a space after a property name’s colon.

+ +

Always use a single space between property and value (but no space between +property and colon) for consistency reasons.

+ +
/* Not recommended */
+h3 {
+  font-weight:bold;
+}
+
+ +
/* Recommended */
+h3 {
+  font-weight: bold;
+}
+
+ +

4.2.5 Declaration Block Separation

+ +

Use a space between the last selector and the declaration block.

+ +

Always use a single space between the last selector and the opening brace that +begins the declaration block.

+ +

The opening brace should be on the same line as the last selector in a given +rule.

+ +
/* Not recommended: missing space */
+#video{
+  margin-top: 1em;
+}
+
+/* Not recommended: unnecessary line break */
+#video
+{
+  margin-top: 1em;
+}
+
+ +
/* Recommended */
+#video {
+  margin-top: 1em;
+}
+
+ +

4.2.6 Selector and Declaration Separation

+ +

Separate selectors and declarations by new lines.

+ +

Always start a new line for each selector and declaration.

+ +
/* Not recommended */
+a:focus, a:active {
+  position: relative; top: 1px;
+}
+
+ +
/* Recommended */
+h1,
+h2,
+h3 {
+  font-weight: normal;
+  line-height: 1.2;
+}
+
+ +

4.2.7 Rule Separation

+ +

Separate rules by new lines.

+ +

Always put a blank line (two line breaks) between rules.

+ +
html {
+  background: #fff;
+}
+
+body {
+  margin: auto;
+  width: 50%;
+}
+
+ +

4.2.8 CSS Quotation Marks

+ +

Use single ('') rather than double ("") quotation marks for attribute +selectors and property values.

+ +

Do not use quotation marks in URI values (url()).

+ +

Exception: If you do need to use the @charset rule, use double quotation +marks—single quotation marks are not permitted.

+ +
/* Not recommended */
+@import url("https://www.google.com/css/maia.css");
+
+html {
+  font-family: "open sans", arial, sans-serif;
+}
+
+ +
/* Recommended */
+@import url(https://www.google.com/css/maia.css);
+
+html {
+  font-family: 'open sans', arial, sans-serif;
+}
+
+ +

4.3 CSS Meta Rules

+ +

4.3.1 Section Comments

+ +

Group sections by a section comment (optional).

+ +

If possible, group style sheet sections together by using comments. Separate +sections with new lines.

+ +
/* Header */
+
+#adw-header {}
+
+/* Footer */
+
+#adw-footer {}
+
+/* Gallery */
+
+.adw-gallery {}
+
+ +

Parting Words

+ +

Be consistent.

+ +

If you’re editing code, take a few minutes to look at the code around you and +determine its style. If they use spaces around all their arithmetic operators, +you should too. If their comments have little boxes of hash marks around them, +make your comments have little boxes of hash marks around them too.

+ +

The point of having style guidelines is to have a common vocabulary of coding so +people can concentrate on what you’re saying rather than on how you’re saying +it. We present global style rules here so people know the vocabulary, but local +style is also important. If code you add to a file looks drastically different +from the existing code around it, it throws readers out of their rhythm when +they go to read it. Avoid this.

+
+ + diff --git a/htmlcssguide.xml b/htmlcssguide.xml new file mode 100644 index 000000000..0ab9f800c --- /dev/null +++ b/htmlcssguide.xml @@ -0,0 +1,8 @@ + + + +

+ The style guide has moved to + htmlcssguide.html +

+
diff --git a/include/jsguide.js b/include/jsguide.js new file mode 100644 index 000000000..dcf56898e --- /dev/null +++ b/include/jsguide.js @@ -0,0 +1,56 @@ +window.initStyleGuide = function(init) { + // Runs the callback on every element matched by the query selector. + function find(querySelector, callback) { + var elements = [].slice.call(document.querySelectorAll(querySelector)); + for (var i = 0; i < elements.length; i++) { + callback(elements[i]); + } + } + // Add the tocDiv at the top. + var title = document.getElementsByTagName('h1')[0]; + var toc = document.createElement('div'); + toc.id = 'tocDiv'; + toc.className = 'vertical_toc'; + title.parentNode.insertBefore(toc, title.nextSibling); + + // If a paragraph starts with (e.g.) "Note:" or "Tip:" then add + // that "callout class" to its element. + find('p', function(paragraph) { + var match = /^([a-z]+):/i.exec(paragraph.textContent); + if (match) { + paragraph.classList.add(match[1].toLowerCase()); + } + }); + + // Fill in text for intra-document links, ensuring that links + // remain up-to-date even if sections are moved or renumbered. + // This triggers on any link with "??" as its text and a URL + // starting with "#", and the filled-in text is exactly the same + // as the text of the referenced section heading. + find('a[href^="#"]', function(link) { + var href = link.getAttribute('href'); + var heading = document.getElementById(href.substring(1)); + // Fill in link text with heading title + if (heading && link.textContent == '??') { + link.textContent = heading.textContent; + } + }); + + // Hoedown renders fenced code blocks incompatibly with what + // prettify expects. As a result, prettify doesn't handle them + // properly. Fix it by moving the code directly into the pre. + find('pre > code', function(code) { + var pre = code.parentElement; + pre.className = code.className; + pre.innerHTML = code.innerHTML; + }); + + // Run the normal init function. + init(); + + // Call the pretty-printer after we've fixed up the code blocks. + var pretty = document.createElement('script'); + pretty.src = 'https://cdn.rawgit.com/google/code-prettify/master/loader/' + + 'run_prettify.js'; + document.body.appendChild(pretty); +}.bind(null, window.initStyleGuide); diff --git a/include/link.png b/include/link.png new file mode 100644 index 000000000..75d5c7ba8 Binary files /dev/null and b/include/link.png differ diff --git a/include/styleguide.css b/include/styleguide.css new file mode 100644 index 000000000..ef62024d0 --- /dev/null +++ b/include/styleguide.css @@ -0,0 +1,261 @@ +/* General CSS */ + +body { + background-color: #fff; + color: #333; + font-family: sans-serif; + font-size: 10pt; + margin-right: 100px; + margin-left: 100px; +} + +h1 { + text-align: center; + font-size: 18pt; +} + +h1, h2, h3, h4, h5, h6 { + color: #06c; + margin-top: 2em; + margin-bottom: 1em; + padding: 25px; + font-weight:bold; +} + +h2, +h3, +h4, +h5, +h6 { + margin-top:1.5em; + margin-bottom:.75em; +} + +h1 {font-size:200%;} +h2 {font-size:167%;} +h3 {font-size:133%;} +h4 {font-size:120%;} +h5 {font-size:110%;} + + +table { + border: 1px solid #bbb; + border-spacing: 0; + border-collapse: collapse; + margin: 0 0 1.5em; + vertical-align: middle; + width: 100% +} + +td, th { + border: 1px solid #ccc; + padding: 2px 12px; + font-size: 10pt; +} + +code, samp, var { + background-color:#FAFAFA; + white-space: nowrap +} + +pre { + padding:6px 10px; + background-color:#FAFAFA; + border:1px solid #bbb; + overflow:auto; +} + +pre.prettyprint { + padding:6px 10px !important; + border:1px solid #bbb !important; +} + +code.bad, code.badcode { + color: magenta; +} + +pre.bad, pre.badcode { + background-color:#ffe6d8; + border-top:1px inset #a03; + border-left:1px inset #a03; +} + +hr { + margin-top: 3.5em; + border-width: 1px; + color: #fff; +} + +/* TOC CSS */ + +table.columns { + border: none; +} + +td.two_columns { + -webkit-column-count: 2; + column-count: 2; +} + +.toc_category { + font-size: 10pt; + padding-top: 1em; + padding-bottom: 1em; + border-left-width: 2px; + border-right-width: 2px; + border-color: grey; +} + +.toc_stylepoint { + font-size: 10pt; + padding-top: 1em; + padding-bottom: 1em; +} + +li.toc_entry { + padding-right: 1em; + display: inline; + list-style-type: none; +} + +/* + * This space is required to trigger the linewrap on the links + * at href boundaries + */ +li.toc_entry::after { + content: " "; + } + +li.toc_entry a { + white-space: nowrap; +} + +/* Horizontal TOC */ +.toc td, .toc th { + border-width: 1px 5px; + overflow: hidden; +} + +/* Vertical TOC */ + +.toc td.two_columns { + border-width: 0px; +} + +/* Special Sections */ + +address { + text-align: right; +} + +.revision { + text-align: right; +} + +.headerbox { + margin-left: 50%; + font-size: 75%; +} + +.legend { + padding-top: 1em; + margin-left: 50%; + font-size: 10pt; +} + +.link_button { + float: left; + display: none; + background-color: #f8f8ff; + border-color: #f0f0ff; + border-style: solid; + border-width: 1px; + font-size: 75%; + margin-top: 0; + margin-left: -50px; + padding: 24px; + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; +} + +.ignoreLink { + padding: 0px; +} + +.divider{ + width:5px; + height:auto; + display:inline-block; +} + +/* Style Guide semantic CSS */ + +.summary { + margin-top: 1em; + margin-bottom: 1em; +} + +.stylebody { + margin-top: 1em; + margin-bottom: 1em; +} + +.stylepoint_section { + display: block; + margin-bottom: 1em; + font-family: sans-serif; + font-weight: bold; +} + +.stylepoint_subsection { + display: block; + margin-bottom: 1em; +} + +.stylepoint_subsubsection { + display: block; + margin-bottom: 1em; +} + +.definition:before { + content: "Definition: "; + font-weight: bold; + display: block; + margin-bottom: 1em; +} + +.pros:before { + content: "Pros: "; + font-weight: bold; + display: block; + margin-bottom: 1em; +} + +.cons:before { + content: "Cons: "; + font-weight: bold; + display: block; + margin-bottom: 1em; +} + +.decision:before { + content: "Decision: "; + font-weight: bold; + display: block; + margin-bottom: 1em; +} + +.exception:before { + content: "Exception: "; + font-weight: bold; + display: block; + margin-bottom: 1em; +} + +.note:before { + content: "Note: "; + font-weight: bold; + display: block; + margin-bottom: 1em; +} diff --git a/include/styleguide.js b/include/styleguide.js new file mode 100644 index 000000000..3c21e107a --- /dev/null +++ b/include/styleguide.js @@ -0,0 +1,289 @@ +TocTypeEnum = { + VERTICAL: 1, + HORIZONTAL: 2 +}; + +function CreateTOC(tocElement) { + + // Find the toc element DIV. We'll place our TOC there. + var toc = document.getElementById(tocElement); + + var tocTypeClass = toc.className; + var tocType; + + switch (tocTypeClass) { + case 'horizontal_toc': + tocType = TocTypeEnum.HORIZONTAL; + break; + case 'vertical_toc': + tocType = TocTypeEnum.VERTICAL; + break; + default: + tocType = TocTypeEnum.VERTICAL; + break; + } + + // If toc_levels is defined, set headingLevels to it. + // Otherwise, use default value of "h2,h3" + var headingLevels; + if (typeof toc_levels === 'undefined') { + headingLevels = 'h2,h3'; + } else { + + } + + // Collect all section heading elements in an array + var headings = document.querySelectorAll(headingLevels); + + // Add TOC title elements + var tocHeadingDiv = document.createElement('div'); + toc.appendChild(tocHeadingDiv); + tocHeadingDiv.className = 'toc_title'; + var tocHeading = document.createElement('h3'); + toc.appendChild(tocHeading); + tocHeading.className = 'ignoreLink'; + tocHeading.id = 'toc'; + var tocText = document.createTextNode('Table of Contents'); + tocHeading.appendChild(tocText); + + // Add table and tbody + var tocTable = document.createElement('table'); + if (tocType == TocTypeEnum.VERTICAL) { + tocTable.className = 'columns'; + } + toc.appendChild(tocTable); + + var tbody_element = document.createElement('tbody'); + tbody_element.setAttribute('valign', 'top'); + tbody_element.className = 'toc'; + tocTable.appendChild(tbody_element); + + // Get the highest level heading + var firstHeading = headings[0]; + var masterLevel = parseInt(headingLevels.charAt(1)); + + // Get the lowest heading level + var lowestLevel = parseInt(headingLevels.charAt(headingLevels - 1)); + + switch (tocType) { + case TocTypeEnum.HORIZONTAL: + CreateHorizontalTOC(headings, masterLevel, lowestLevel, tbody_element); + break; + case TocTypeEnum.VERTICAL: + CreateVerticalTOC(headings, masterLevel, lowestLevel, tbody_element); + break; + default: + } +} + +function CreateHorizontalTOC( + headings, masterLevel, lowestLevel, tbody_element) { + + // Initialize the header counter + var h = 0; + var ignoreChildren = false; + + while (h < headings.length) { + // Get current heading + var heading = headings[h]; + + // Get the current heading level + var level = parseInt(heading.tagName.charAt(1)); + + if (isNaN(level) || level < 1 || level > lowestLevel) continue; + + // If level is a masterLevel, make it a TOC parent category + if ((level == masterLevel) && (!hasClass(heading, 'ignoreLink'))) { + toc_current_row = AddTOCMaster(tbody_element, heading); + ignoreChildren = false; + } + + if ((level == masterLevel) && (hasClass(heading, 'ignoreLink'))) { + ignoreChildren = true; + } + + if ((level != masterLevel) && (!ignoreChildren)) { + AddTOCElements(toc_current_row, heading); + } + + // Advance the header counter + h++; + } +} + +// Adds a master Table of Content heading +function AddTOCMaster(tocTable, heading) { + + // Add the table row scaffolding + var toc_tr = document.createElement('tr'); + tocTable.appendChild(toc_tr); + toc_tr.setAttribute('valign', 'top'); + var toc_tr_td = document.createElement('td'); + toc_tr.appendChild(toc_tr_td); + var toc_category = document.createElement('div'); + toc_tr_td.appendChild(toc_category); + toc_category.className = 'toc_category'; + + // Create the link to this header + var link = document.createElement('a'); + link.href = '#' + heading.id; // Create the anchor link + link.textContent = heading.textContent; // Link text is same as heading + toc_category.appendChild(link); + + // Add the container table cell for its children + var toc_td = document.createElement('td'); + toc_tr.appendChild(toc_td); + var toc_td_div = document.createElement('div'); + toc_td_div.className = 'toc_stylepoint'; + toc_td.appendChild(toc_td_div); + + return (toc_td_div); +} + +// Adds Table of Contents element to a master heading as children +function AddTOCElements(toc_div, heading) { + + if (heading.offsetParent === null) { + // The element is currently hidden, so don't create a TOC entry + } else { + // Create the list item element + var toc_list_element = document.createElement('li'); + toc_list_element.className = 'toc_entry'; + toc_div.appendChild(toc_list_element); + + // Create the link to this header + var link = document.createElement('a'); + link.href = '#' + heading.id; // Create the anchor link + link.textContent = heading.textContent; // Link text is same as heading + toc_list_element.appendChild(link); + } +} + +function CreateVerticalTOC(headings, masterLevel, lowestLevel, tbody_element) { + + // Create the Column scaffolding + var toc_tr = document.createElement('tr'); + tbody_element.appendChild(toc_tr); + var toc_tr_td = document.createElement('td'); + toc_tr_td.className = 'two_columns'; + toc_tr.appendChild(toc_tr_td); + + + // Initialize the header counter and the current row + var h = 0; + var toc_current_col = null; + var ignoreChildren = false; + + while (h < headings.length) { + // Get current heading + var heading = headings[h]; + + // Get the current heading level + var level = parseInt(heading.tagName.charAt(1)); + + if (isNaN(level) || level < 1 || level > lowestLevel) continue; + + // If level is a masterLevel, make it a TOC parent category + if ((level == masterLevel) && (!hasClass(heading, 'ignoreLink'))) { + if (heading.offsetParent === null) { + // The element is currently hidden, so don't create a TOC entry + } else { + var td_dl = document.createElement('dl'); + toc_tr_td.appendChild(td_dl); + var td_dt = document.createElement('dt'); + td_dl.appendChild(td_dt); + toc_current_col = td_dl; + + // Create the link to this header + var link = document.createElement('a'); + link.href = '#' + heading.id; // Create the anchor link + link.textContent = heading.textContent; // Link text is same as heading + td_dt.appendChild(link); + ignoreChildren = false; + } + } + + // If level is a masterLevel but it's specified to ignore links, skip it + // and its children. + if ((level == masterLevel) && (hasClass(heading, 'ignoreLink'))) { + ignoreChildren = true; + } + + if ((level != masterLevel) && (!ignoreChildren)) { + if (heading.offsetParent === null) { + // The element is currently hidden, so don't create a TOC entry + } else { + var td_dd = document.createElement('dd'); + toc_current_col.appendChild(td_dd); + // Create the link to this header + var link = document.createElement('a'); + link.href = '#' + heading.id; // Create the anchor link + link.textContent = heading.textContent; // Link text is same as heading + td_dd.appendChild(link); + } + } + + // Advance the header counter + h++; + } +} + +/* + * Utility function for finding elements with a given + * class. + */ +function hasClass(element, cls) { + return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1; +} + +/* + * Linkify all h2 through h4 headers, except for those marked + * "ignoreLink" + */ + +// Add the link image to the element. +function LinkifyHeader(header, fileName, sizePixels) { + var link = document.createElement('a'); + link.href = '#' + header.id; + link.setAttribute('alt', 'link to ' + header.id); + link.innerHTML = + ''; + header.appendChild(link); +} + +// Find all elements of the given tag and linkify if +// they don't have 'ignoreLink' in their class. +function LinkifyHeadersForTag(tagName) { + var headers = document.getElementsByTagName(tagName); + var header; + for (var j = 0; j != headers.length; j++) { + header = headers[j]; + if (!hasClass(header, 'ignoreLink') && ('id' in header)) { + if (header.id != '') { + LinkifyHeader(header, 'link.png', 21); + header.style.left = '-46px'; + header.style.position = 'relative'; + } + } + } +} + +// Linkify all h2, h3, and h4s. h1s are titles. +function LinkifyHeaders() { + LinkifyHeadersForTag('h2'); + LinkifyHeadersForTag('h3'); + LinkifyHeadersForTag('h4'); +} + +/* + * Initialize the style guide by showing all internal + * elements and then linkifying the headers. + */ + +function initStyleGuide() { + LinkifyHeaders(); + CreateTOC('tocDiv'); +} diff --git a/intellij-java-google-style.xml b/intellij-java-google-style.xml new file mode 100644 index 000000000..f3a6743ef --- /dev/null +++ b/intellij-java-google-style.xml @@ -0,0 +1,598 @@ + + + + + + diff --git a/javaguide.css b/javaguide.css new file mode 100644 index 000000000..10cd73024 --- /dev/null +++ b/javaguide.css @@ -0,0 +1,572 @@ +table { + border-collapse: collapse; +} + +td, th { + border: 1px solid #ccc; + padding: 2px 12px; + font-size: 10pt; +} + +code, samp, var { + color: #060; +} + +pre { + font-size: 10pt; + display: block; + color: #060; + background-color: #e8fff6; + border-color: #f0fff0; + border-style: solid; + border-top-width: 1px; + border-bottom-width: 1px; + border-right-width: 1px; + border-left-width: 5px; + padding-left: 12px; + padding-right: 12px; + padding-top: 4px; + padding-bottom: 4px; +} + +pre.badcode { + color: #c00; + background-color: #ffe6d8; + border-color: #fff0f0; +} + +hr { + margin-top: 3.5em; + border-width: 1px; + color: #fff; +} + +html { + margin-top:2em; + margin-left:10%; + margin-right:10%; + padding:0; +} + +.bp-reset-element, +body, +h1, +h2, +h3, +h4, +h5, +h6, +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section, +summary, +blockquote, +q, +th, +td, +caption, +table, +div, +span, +object, +iframe, +p, +pre, +a, +abbr, +acronym, +address, +code, +del, +dfn, +em, +img, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +caption, +tbody, +tfoot, +thead, +tr { + margin:0; + padding:0; + border:0; + font-weight:inherit; + font-style:inherit; + font-size:100%; + font-family:inherit; + vertical-align:baseline; +} + +body { + font-family:'Arial', sans-serif; + font-size:81.25%; + color:#222; + background-color:#fff; + line-height:1.67; + overflow: auto; +} + +.change { + text-align: right; + margin-bottom:1em; +} + +em { + font-style: italic +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight:bold; +} + +h1 { + margin-bottom:.50em; + text-align: center +} + +h2, +h3, +h4, +h5, +h6 { + margin-top:1.5em; + margin-bottom:.75em; +} + +h1 {font-size:200%;} +h2 {font-size:167%;} +h3 {font-size:133%;} +h4 {font-size:120%;} +h5 {font-size:110%;} + +p { + margin:0 0 1.5em; +} + +a[href=''] { + cursor:default; +} + +h1 img, +h2 img, +h3 img, +h4 img, +h5 img, +h6 img { + margin:0; +} + +a img { + border:none; +} + +pre { + margin:1.5em 0; + white-space:pre; +} + +pre, +code, +kbd, +tt { + font:1em 'Droid Sans Mono', monospace; + line-height:1.5; +} + +dl { + margin:0 0 1.5em 0; +} + +dl dt { + font-weight:bold; +} + +dd { + margin-left:1.5em; +} + +dd.toc3 { + margin-left:3em; +} + +hr { + height:0; + border:0; + border-top:1px solid #ccc; + background-color:#ccc; +} + +table { + border:1px solid #bbb; + border-spacing:0; + border-collapse:collapse; + margin:0 0 1.5em; + vertical-align:middle; + width:100%; +} + +table.unlined, +table.unlined th, +table.unlined tr, +table.unlined td { + border:0; +} + +th, +td, +caption { + float:none !important; + text-align:left; + font-weight:normal; + vertical-align:middle; + padding:4px; +} + +caption { + padding:0; +} + +td { + border:1px solid #bbb; + vertical-align:top; +} + +th { + border:0; + border-bottom:1px solid black; + font-weight:bold; + background:rgb(229, 236, 249); +} + +table th code { + background-color:inherit; + color:inherit; +} + +table tfoot th { + border:1px solid #bbb; +} + +tfoot { + font-style:italic; +} + +caption { + background:#eee; +} + +table[border='0'] { + border:none; +} + +table[border='0']>tbody>tr>td, +table[border='0']>tr>td { + border:none; +} + +tr.alt td, +td.alt { + background-color:#efefef; +} + +table.striped tr:nth-child(even) td, +table tr.even td { + background:#efefef; +} + +table.columns { + border:none; +} + +table.columns>tbody>tr>td, +table.columns>tr>td { + border:none; + padding:0 3em 0 0; +} + +table.columns>tbody>tr>td:last-child, +table.columns>tr>td:last-child { + border:none; + padding:0; +} + +ul, +ol { + margin:0 1.5em 1.5em 0; + padding-left:2em; +} + +li ul, +li ol { + margin:0; +} + +ul { + list-style-type:disc; +} + +ol { + list-style-type:decimal; +} + +ul { + list-style-type:disc; +} + +ul ul { + list-style-type:circle; +} + +ul ul ul { + list-style-type:square; +} + +ul.disc { + list-style-type:disc; +} + +ul.circle { + list-style-type:circle; +} + +ul.square { + list-style-type:square; +} + +ol { + list-style-type:decimal; +} + +ol ol { + list-style-type:lower-alpha; +} + +ol ol ol { + list-style-type:lower-roman; +} + +ol ul { + list-style-type:circle; +} + +ol.decimal { + list-style-type:decimal; +} + +ol.upper-alpha { + list-style-type:upper-alpha; +} + +ol.lower-alpha { + list-style-type:lower-alpha; +} + +ol.upper-roman { + list-style-type:upper-roman; +} + +ol.lower-roman { + list-style-type:lower-roman; +} + +ol.nolist, +ul.nolist { + padding-left:0; + list-style-image:none; + list-style-type:none; + margin-left:0; +} + +.center { + text-align:center; +} + +code, +kbd, +pre { + color:#009900; +} + +kbd { + font-weight: bold; +} + +table.striped code { + background-color:inherit; +} + +pre { + padding:6px 10px; + background-color:#FAFAFA; + border:1px solid #bbb; + overflow:auto; +} + +pre.prettyprint { + padding:6px 10px !important; + border:1px solid #bbb !important; +} + +code.bad, code.badcode { + color: magenta; +} +pre.bad, pre.badcode { + background-color:#ffe6d8; + border-top:1px inset #a03; + border-left:1px inset #a03; +} + +.tip { + background-color:#fffbd9; + padding:6px 8px 6px 10px; + border-left:6px solid #ffef70; +} + +.note { + background-color:#e5ecf9; + padding:6px 8px 6px 10px; + border-left:6px solid #36c; +} + +@media print { + + .str { + color:#060; + } + + .kwd { + color:#006; + font-weight:bold; + } + + .com { + color:#600; + font-style:italic; + } + + .typ { + color:#404; + font-weight:bold; + } + + .lit { + color:#044; + } + + .pun, + .opn, + .clo { + color:#440; + } + + .pln { + color:#000; + } + + .tag { + color:#006; + font-weight:bold; + } + + .atn { + color:#404; + } + + .atv { + color:#060; + } + + h1 { + font-style:italic; + } +} + +ol.linenums { + margin-top:0; + margin-bottom:0; +} + +code { + background-color:#FAFAFA; + padding: 0.25em 0.5em; + white-space: nowrap +} + + +/* TOC CSS */ + +table.columns { + border: none; +} + +td.two_columns { + -webkit-column-count: 2; + column-count: 2; +} + +.toc_category { + font-size: 10pt; + padding-top: 1em; + padding-bottom: 1em; + border-left-width: 2px; + border-right-width: 2px; + border-color: grey; +} + +.toc_stylepoint { + font-size: 10pt; + padding-top: 1em; + padding-bottom: 1em; +} + +li.toc_entry { + padding-right: 1em; + display: inline; + list-style-type: none; +} + +/* + * This space is required to trigger the linewrap on the links + * at href boundaries + */ +li.toc_entry::after { + content: " "; + } + +li.toc_entry a { + white-space: nowrap; +} + +/* Horizontal TOC */ +.toc td, .toc th { + border-width: 1px 5px; + overflow: hidden; +} + +/* Vertical TOC */ + +.toc td.two_columns { + border-width: 0px; +} diff --git a/javaguide.html b/javaguide.html new file mode 100644 index 000000000..b17142655 --- /dev/null +++ b/javaguide.html @@ -0,0 +1,1187 @@ + + + + +Google Java Style Guide + + + + + + +
+

Google Java Style Guide

+
+ +
+ +

1 Introduction

+ +

This document serves as the complete definition of Google's coding standards for +source code in the Java™ Programming Language. A Java source file is described as being in +Google Style if and only if it adheres to the rules herein.

+ +

Like other programming style guides, the issues covered span not only aesthetic issues of +formatting, but other types of conventions or coding standards as well. However, this document +focuses primarily on the hard-and-fast rules that we follow universally, and +avoids giving advice that isn't clearly enforceable (whether by human or tool). +

+ + + +

1.1 Terminology notes

+ +

In this document, unless otherwise clarified:

+ +
    +
  1. The term class is used inclusively to mean an "ordinary" class, enum class, + interface or annotation type (@interface).
  2. + +
  3. The term member (of a class) is used inclusively to mean a nested class, field, + method, or constructor; that is, all top-level contents of a class except initializers + and comments. + +
  4. The term comment always refers to implementation comments. We do not + use the phrase "documentation comments", instead using the common term "Javadoc."
  5. +
+ +

Other "terminology notes" will appear occasionally throughout the document.

+ +

1.2 Guide notes

+ +

Example code in this document is non-normative. That is, while the examples +are in Google Style, they may not illustrate the only stylish way to represent the +code. Optional formatting choices made in examples should not be enforced as rules.

+ + +

2 Source file basics

+ +

2.1 File name

+ +

The source file name consists of the case-sensitive name of the top-level class it contains +(of which there is exactly one), plus the +.java extension.

+ +

2.2 File encoding: UTF-8

+ +

Source files are encoded in UTF-8.

+ +

2.3 Special characters

+ +

2.3.1 Whitespace characters

+ +

Aside from the line terminator sequence, the ASCII horizontal space +character (0x20) is the only whitespace character that appears +anywhere in a source file. This implies that:

+ +
    +
  1. All other whitespace characters in string and character literals are escaped.
  2. + +
  3. Tab characters are not used for indentation.
  4. +
+ +

2.3.2 Special escape sequences

+ +

For any character that has a + + special escape sequence +(\b, +\t, +\n, +\f, +\r, +\", +\' and +\\), that sequence +is used rather than the corresponding octal +(e.g. \012) or Unicode +(e.g. \u000a) escape.

+ +

2.3.3 Non-ASCII characters

+ +

For the remaining non-ASCII characters, either the actual Unicode character +(e.g. ) or the equivalent Unicode escape +(e.g. \u221e) is used. The choice depends only on +which makes the code easier to read and understand, although Unicode escapes +outside string literals and comments are strongly discouraged.

+ +

Tip: In the Unicode escape case, and occasionally even when actual +Unicode characters are used, an explanatory comment can be very helpful.

+ +

Examples:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExampleDiscussion
String unitAbbrev = "μs";Best: perfectly clear even without a comment.
String unitAbbrev = "\u03bcs"; // "μs"Allowed, but there's no reason to do this.
String unitAbbrev = "\u03bcs"; + // Greek letter mu, "s"Allowed, but awkward and prone to mistakes.
String unitAbbrev = "\u03bcs";Poor: the reader has no idea what this is.
return '\ufeff' + content; + // byte order markGood: use escapes for non-printable characters, and comment if necessary.
+ +

Tip: Never make your code less readable simply out of fear that +some programs might not handle non-ASCII characters properly. If that should happen, those +programs are broken and they must be fixed.

+ + + +

3 Source file structure

+ +
+

A source file consists of, in order:

+ +
    +
  1. License or copyright information, if present
  2. +
  3. Package statement
  4. +
  5. Import statements
  6. +
  7. Exactly one top-level class
  8. +
+
+ +

Exactly one blank line separates each section that is present.

+ + + +

If license or copyright information belongs in a file, it belongs here.

+ + + +

3.2 Package statement

+ +

The package statement is not line-wrapped. The column limit (Section 4.4, +Column limit: 100) does not apply to package statements.

+ + +

3.3 Import statements

+ +

3.3.1 No wildcard imports

+ +

Wildcard imports, static or otherwise, are not used.

+ +

3.3.2 No line-wrapping

+ +

Import statements are not line-wrapped. The column limit (Section 4.4, +Column limit: 100) does not apply to import +statements.

+ +

3.3.3 Ordering and spacing

+ +

Imports are ordered as follows:

+ +
    +
  1. All static imports in a single block.
  2. +
  3. All non-static imports in a single block.
  4. +
+ +

If there are both static and non-static imports, a single blank line separates the two +blocks. There are no other blank lines between import statements.

+ +

Within each block the imported names appear in ASCII sort order. (Note: +this is not the same as the import statements being in ASCII sort order, since '.' +sorts before ';'.)

+ + + +

3.3.4 No static import for classes

+ +

Static import is not used for static nested classes. They are imported with +normal imports.

+ +

3.4 Class declaration

+ + +

3.4.1 Exactly one top-level class declaration

+ +

Each top-level class resides in a source file of its own.

+ + +

3.4.2 Ordering of class contents

+ +

The order you choose for the members and initializers of your class can have a great effect on +learnability. However, there's no single correct recipe for how to do it; different classes may +order their contents in different ways.

+ +

What is important is that each class uses some logical order, which its +maintainer could explain if asked. For example, new methods are not just habitually added to the end +of the class, as that would yield "chronological by date added" ordering, which is not a logical +ordering.

+ + + + +
3.4.2.1 Overloads: never split
+ +

When a class has multiple constructors, or multiple methods with the same name, these appear +sequentially, with no other code in between (not even private members).

+ +

4 Formatting

+ +

Terminology Note: block-like construct refers to +the body of a class, method or constructor. Note that, by Section 4.8.3.1 on +array initializers, any array initializer +may optionally be treated as if it were a block-like construct.

+ + +

4.1 Braces

+ +

4.1.1 Braces are used where optional

+ +

Braces are used with +if, +else, +for, +do and +while statements, even when the +body is empty or contains only a single statement.

+ +

4.1.2 Nonempty blocks: K & R style

+ +

Braces follow the Kernighan and Ritchie style +("Egyptian brackets") +for nonempty blocks and block-like constructs:

+ +
    +
  • No line break before the opening brace.
  • + +
  • Line break after the opening brace.
  • + +
  • Line break before the closing brace.
  • + +
  • Line break after the closing brace, only if that brace terminates a statement or + terminates the body of a method, constructor, or named class. + For example, there is no line break after the brace if it is followed by + else or a comma.
  • +
+ +

Examples:

+ +
return () -> {
+  while (condition()) {
+    method();
+  }
+};
+
+return new MyClass() {
+  @Override public void method() {
+    if (condition()) {
+      try {
+        something();
+      } catch (ProblemException e) {
+        recover();
+      }
+    } else if (otherCondition()) {
+      somethingElse();
+    } else {
+      lastThing();
+    }
+  }
+};
+
+ +

A few exceptions for enum classes are given in Section 4.8.1, +Enum classes.

+ + +

4.1.3 Empty blocks: may be concise

+ +

An empty block or block-like construct may be in K & R style (as described in +Section 4.1.2). Alternatively, it may be closed immediately +after it is opened, with no characters or line break in between +({}), unless it is part of a +multi-block statement (one that directly contains multiple blocks: +if/else or +try/catch/finally).

+ +

Examples:

+ +
  // This is acceptable
+  void doNothing() {}
+
+  // This is equally acceptable
+  void doNothingElse() {
+  }
+
+
  // This is not acceptable: No concise empty blocks in a multi-block statement
+  try {
+    doSomething();
+  } catch (Exception e) {}
+
+ +

4.2 Block indentation: +2 spaces

+ +

Each time a new block or block-like construct is opened, the indent increases by two +spaces. When the block ends, the indent returns to the previous indent level. The indent level +applies to both code and comments throughout the block. (See the example in Section 4.1.2, +Nonempty blocks: K & R Style.)

+ +

4.3 One statement per line

+ +

Each statement is followed by a line break.

+ + +

4.4 Column limit: 100

+ +

Java code has a column limit of 100 characters. A "character" means any Unicode code point. +Except as noted below, any line that would exceed this limit must be line-wrapped, as explained in +Section 4.5, Line-wrapping. +

+ +

Each Unicode code point counts as one character, even if its display width is +greater or less. For example, if using +fullwidth characters, +you may choose to wrap the line earlier than where this rule strictly requires.

+ +

Exceptions:

+ +
    +
  1. Lines where obeying the column limit is not possible (for example, a long URL in Javadoc, + or a long JSNI method reference).
  2. + +
  3. package and + import statements (see Sections + 3.2 Package statement and + 3.3 Import statements).
  4. + +
  5. Command lines in a comment that may be cut-and-pasted into a shell.
  6. +
+ +

4.5 Line-wrapping

+ +

Terminology Note: When code that might otherwise legally +occupy a single line is divided into multiple lines, this activity is called +line-wrapping.

+ +

There is no comprehensive, deterministic formula showing exactly how to line-wrap in +every situation. Very often there are several valid ways to line-wrap the same piece of code.

+ +

Note: While the typical reason for line-wrapping is to avoid +overflowing the column limit, even code that would in fact fit within the column limit may +be line-wrapped at the author's discretion.

+ +

Tip: Extracting a method or local variable may solve the problem +without the need to line-wrap.

+ +

4.5.1 Where to break

+ +

The prime directive of line-wrapping is: prefer to break at a +higher syntactic level. Also:

+ +
    +
  1. When a line is broken at a non-assignment operator the break comes before + the symbol. (Note that this is not the same practice used in Google style for other languages, + such as C++ and JavaScript.) +
      +
    • This also applies to the following "operator-like" symbols: +
        +
      • the dot separator (.)
      • +
      • the two colons of a method reference + (::)
      • +
      • an ampersand in a type bound + (<T extends Foo & Bar>)
      • +
      • a pipe in a catch block + (catch (FooException | BarException e)).
      • +
      +
    • +
    +
  2. + +
  3. When a line is broken at an assignment operator the break typically comes + after the symbol, but either way is acceptable. +
      +
    • This also applies to the "assignment-operator-like" colon in an enhanced + for ("foreach") statement.
    • +
    +
  4. + +
  5. A method or constructor name stays attached to the open parenthesis + (() that follows it.
  6. + +
  7. A comma (,) stays attached to the token that + precedes it.
  8. + +
  9. A line is never broken adjacent to the arrow in a lambda, except that a + break may come immediately after the arrow if the body of the lambda consists + of a single unbraced expression. Examples: +
    MyLambda<String, Long, Object> lambda =
    +    (String label, Long value, Object obj) -> {
    +        ...
    +    };
    +
    +Predicate<String> predicate = str ->
    +    longExpressionInvolving(str);
    +
    +
  10. +
+ +

Note: The primary goal for line wrapping is to have clear +code, not necessarily code that fits in the smallest number of lines.

+ + +

4.5.2 Indent continuation lines at least +4 spaces

+ +

When line-wrapping, each line after the first (each continuation line) is indented +at least +4 from the original line.

+ +

When there are multiple continuation lines, indentation may be varied beyond +4 as +desired. In general, two continuation lines use the same indentation level if and only if they +begin with syntactically parallel elements.

+ +

Section 4.6.3 on Horizontal alignment addresses +the discouraged practice of using a variable number of spaces to align certain tokens with +previous lines.

+ +

4.6 Whitespace

+ +

4.6.1 Vertical Whitespace

+ +

A single blank line appears:

+ +
    +
  1. Between consecutive members or initializers of a class: fields, constructors, + methods, nested classes, static initializers, and instance initializers. +
      +
    • Exception: A blank line between two consecutive + fields (having no other code between them) is optional. Such blank lines are used as needed to + create logical groupings of fields.
    • +
    • Exception: Blank lines between enum constants are + covered in Section 4.8.1.
    • +
    +
  2. + +
  3. Between statements, as needed to organize the code into logical subsections. + +
  4. Optionally before the first member or initializer, or after the last member or + initializer of the class (neither encouraged nor discouraged).
  5. + +
  6. As required by other sections of this document (such as Section 3, + Source file structure, and Section 3.3, + Import statements).
  7. +
+ +

Multiple consecutive blank lines are permitted, but never required (or encouraged).

+ +

4.6.2 Horizontal whitespace

+ +

Beyond where required by the language or other style rules, and apart from literals, comments and +Javadoc, a single ASCII space also appears in the following places only.

+ +
    +
  1. Separating any reserved word, such as + if, + for or + catch, from an open parenthesis + (() + that follows it on that line
  2. + +
  3. Separating any reserved word, such as + else or + catch, from a closing curly brace + (}) that precedes it on that line
  4. + +
  5. Before any open curly brace + ({), with two exceptions: +
      +
    • @SomeAnnotation({a, b}) (no space is used)
    • + +
    • String[][] x = {{"foo"}}; (no space is required + between {{, by item 8 below)
    • +
    +
  6. + +
  7. On both sides of any binary or ternary operator. This also applies to the following + "operator-like" symbols: +
      +
    • the ampersand in a conjunctive type bound: + <T extends Foo & Bar>
    • + +
    • the pipe for a catch block that handles multiple exceptions: + catch (FooException | BarException e)
    • + +
    • the colon (:) in an enhanced + for ("foreach") statement
    • + +
    • the arrow in a lambda expression: + (String str) -> str.length()
    • +
    + but not + +
      +
    • the two colons (::) of a method reference, which + is written like Object::toString
    • +
    • the dot separator (.), which is written like + object.toString()
    • +
    +
  8. + +
  9. After ,:; or the closing parenthesis + ()) of a cast
  10. + +
  11. On both sides of the double slash (//) that + begins an end-of-line comment. Here, multiple spaces are allowed, but not required.
  12. + +
  13. Between the type and variable of a declaration: + List<String> list
  14. + +
  15. Optional just inside both braces of an array initializer +
      +
    • new int[] {5, 6} and + new int[] { 5, 6 } are both valid
    • +
    +
  16. +
+ +This rule is never interpreted as requiring or forbidding additional space at the start or +end of a line; it addresses only interior space. + +

4.6.3 Horizontal alignment: never required

+ +

Terminology Note: Horizontal alignment is the +practice of adding a variable number of additional spaces in your code with the goal of making +certain tokens appear directly below certain other tokens on previous lines.

+ +

This practice is permitted, but is never required by Google Style. It is not +even required to maintain horizontal alignment in places where it was already used.

+ +

Here is an example without alignment, then using alignment:

+ +
private int x; // this is fine
+private Color color; // this too
+
+private int   x;      // permitted, but future edits
+private Color color;  // may leave it unaligned
+
+ +

Tip: Alignment can aid readability, but it creates problems for +future maintenance. Consider a future change that needs to touch just one line. This change may +leave the formerly-pleasing formatting mangled, and that is allowed. More often +it prompts the coder (perhaps you) to adjust whitespace on nearby lines as well, possibly +triggering a cascading series of reformattings. That one-line change now has a "blast radius." +This can at worst result in pointless busywork, but at best it still corrupts version history +information, slows down reviewers and exacerbates merge conflicts.

+ + +

4.7 Grouping parentheses: recommended

+ +

Optional grouping parentheses are omitted only when author and reviewer agree that there is no +reasonable chance the code will be misinterpreted without them, nor would they have made the code +easier to read. It is not reasonable to assume that every reader has the entire Java +operator precedence table memorized.

+ +

4.8 Specific constructs

+ +

4.8.1 Enum classes

+ +

After each comma that follows an enum constant, a line break is optional. Additional blank +lines (usually just one) are also allowed. This is one possibility: + +

private enum Answer {
+  YES {
+    @Override public String toString() {
+      return "yes";
+    }
+  },
+
+  NO,
+  MAYBE
+}
+
+ +

An enum class with no methods and no documentation on its constants may optionally be formatted +as if it were an array initializer (see Section 4.8.3.1 on +array initializers).

+ +
private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS }
+
+ +

Since enum classes are classes, all other rules for formatting classes apply.

+ + +

4.8.2 Variable declarations

+ +
4.8.2.1 One variable per declaration
+ +

Every variable declaration (field or local) declares only one variable: declarations such as +int a, b; are not used.

+ +

Exception: Multiple variable declarations are acceptable in the header of a +for loop.

+ +
4.8.2.2 Declared when needed
+ +

Local variables are not habitually declared at the start of their containing +block or block-like construct. Instead, local variables are declared close to the point they are +first used (within reason), to minimize their scope. Local variable declarations typically have +initializers, or are initialized immediately after declaration.

+ +

4.8.3 Arrays

+ +
4.8.3.1 Array initializers: can be "block-like"
+ +

Any array initializer may optionally be formatted as if it were a "block-like +construct." For example, the following are all valid (not an exhaustive +list):

+ +
new int[] {           new int[] {
+  0, 1, 2, 3            0,
+}                       1,
+                        2,
+new int[] {             3,
+  0, 1,               }
+  2, 3
+}                     new int[]
+                          {0, 1, 2, 3}
+
+ +
4.8.3.2 No C-style array declarations
+ +

The square brackets form a part of the type, not the variable: +String[] args, not +String args[].

+ +

4.8.4 Switch statements

+ + + +

Terminology Note: Inside the braces of a +switch block are one or more statement groups. Each statement group consists of +one or more switch labels (either case FOO: or +default:), followed by one or more statements (or, for +the last statement group, zero or more statements).

+ +
4.8.4.1 Indentation
+ +

As with any other block, the contents of a switch block are indented +2.

+ +

After a switch label, there is a line break, and the indentation level is increased +2, exactly +as if a block were being opened. The following switch label returns to the previous indentation +level, as if a block had been closed.

+ + +
4.8.4.2 Fall-through: commented
+ +

Within a switch block, each statement group either terminates abruptly (with a +break, +continue, +return or thrown exception), or is marked with a comment +to indicate that execution will or might continue into the next statement group. Any +comment that communicates the idea of fall-through is sufficient (typically +// fall through). This special comment is not required in +the last statement group of the switch block. Example:

+ +
switch (input) {
+  case 1:
+  case 2:
+    prepareOneOrTwo();
+    // fall through
+  case 3:
+    handleOneTwoOrThree();
+    break;
+  default:
+    handleLargeNumber(input);
+}
+
+ +

Notice that no comment is needed after case 1:, only +at the end of the statement group.

+ +
4.8.4.3 The default case is present
+ +

Each switch statement includes a default statement +group, even if it contains no code.

+ +

Exception: A switch statement for an enum type may omit +the default statement group, if it includes +explicit cases covering all possible values of that type. This enables IDEs or other static +analysis tools to issue a warning if any cases were missed. + +

+ + +

4.8.5 Annotations

+ +

Annotations applying to a class, method or constructor appear immediately after the +documentation block, and each annotation is listed on a line of its own (that is, one annotation +per line). These line breaks do not constitute line-wrapping (Section +4.5, Line-wrapping), so the indentation level is not +increased. Example:

+ +
@Override
+@Nullable
+public String getNameIfPresent() { ... }
+
+ +

Exception: A single parameterless annotation +may instead appear together with the first line of the signature, for example:

+ +
@Override public int hashCode() { ... }
+
+ +

Annotations applying to a field also appear immediately after the documentation block, but in +this case, multiple annotations (possibly parameterized) may be listed on the same line; +for example:

+ +
@Partial @Mock DataLoader loader;
+
+ +

There are no specific rules for formatting annotations on parameters, local variables, or types. +

+ + +

4.8.6 Comments

+ +

This section addresses implementation comments. Javadoc is addressed separately in +Section 7, Javadoc.

+ +

Any line break may be preceded by arbitrary whitespace followed by an implementation comment. +Such a comment renders the line non-blank.

+ +
4.8.6.1 Block comment style
+ +

Block comments are indented at the same level as the surrounding code. They may be in +/* ... */ style or +// ... style. For multi-line +/* ... */ comments, subsequent lines must start with +* aligned with the * on the previous line.

+ +
/*
+ * This is          // And so           /* Or you can
+ * okay.            // is this.          * even do this. */
+ */
+
+ + +

Comments are not enclosed in boxes drawn with asterisks or other characters.

+ +

Tip: When writing multi-line comments, use the +/* ... */ style if you want automatic code formatters to +re-wrap the lines when necessary (paragraph-style). Most formatters don't re-wrap lines in +// ... style comment blocks.

+ + + + +

4.8.7 Modifiers

+ +

Class and member modifiers, when present, appear in the order +recommended by the Java Language Specification: +

+ +
public protected private abstract default static final transient volatile synchronized native strictfp
+
+ +

4.8.8 Numeric Literals

+ +

long-valued integer literals use an uppercase L suffix, never +lowercase (to avoid confusion with the digit 1). For example, 3000000000L +rather than 3000000000l.

+ + +

5 Naming

+ +

5.1 Rules common to all identifiers

+ +

Identifiers use only ASCII letters and digits, and, in a small number of cases noted below, +underscores. Thus each valid identifier name is matched by the regular expression +\w+ .

+ +

In Google Style special prefixes or +suffixes, like those seen in the examples name_, +mName, s_name and +kName, are not used.

+ +

5.2 Rules by identifier type

+ +

5.2.1 Package names

+ +

Package names are all lowercase, with consecutive words simply concatenated together (no +underscores). For example, com.example.deepspace, not +com.example.deepSpace or +com.example.deep_space.

+ +

5.2.2 Class names

+ +

Class names are written in UpperCamelCase.

+ +

Class names are typically nouns or noun phrases. For example, +Character or +ImmutableList. Interface names may also be nouns or +noun phrases (for example, List), but may sometimes be +adjectives or adjective phrases instead (for example, +Readable).

+ +

There are no specific rules or even well-established conventions for naming annotation types.

+ +

Test classes are named starting with the name of the class they are testing, and ending +with Test. For example, +HashTest or +HashIntegrationTest.

+ +

5.2.3 Method names

+ +

Method names are written in lowerCamelCase.

+ +

Method names are typically verbs or verb phrases. For example, +sendMessage or +stop.

+ +

Underscores may appear in JUnit test method names to separate logical components of the +name, with each component written in lowerCamelCase. +One typical pattern is <methodUnderTest>_<state>, +for example pop_emptyStack. There is no One Correct +Way to name test methods.

+ + +

5.2.4 Constant names

+ +

Constant names use CONSTANT_CASE: all uppercase +letters, with each word separated from the next by a single underscore. But what is a +constant, exactly?

+ +

Constants are static final fields whose contents are deeply immutable and whose methods have no +detectable side effects. This includes primitives, Strings, immutable types, and immutable +collections of immutable types. If any of the instance's observable state can change, it is not a +constant. Merely intending to never mutate the object is not enough. Examples:

+ +
// Constants
+static final int NUMBER = 5;
+static final ImmutableList<String> NAMES = ImmutableList.of("Ed", "Ann");
+static final ImmutableMap<String, Integer> AGES = ImmutableMap.of("Ed", 35, "Ann", 32);
+static final Joiner COMMA_JOINER = Joiner.on(','); // because Joiner is immutable
+static final SomeMutableType[] EMPTY_ARRAY = {};
+enum SomeEnum { ENUM_CONSTANT }
+
+// Not constants
+static String nonFinal = "non-final";
+final String nonStatic = "non-static";
+static final Set<String> mutableCollection = new HashSet<String>();
+static final ImmutableSet<SomeMutableType> mutableElements = ImmutableSet.of(mutable);
+static final ImmutableMap<String, SomeMutableType> mutableValues =
+    ImmutableMap.of("Ed", mutableInstance, "Ann", mutableInstance2);
+static final Logger logger = Logger.getLogger(MyClass.getName());
+static final String[] nonEmptyArray = {"these", "can", "change"};
+
+ +

These names are typically nouns or noun phrases.

+ +

5.2.5 Non-constant field names

+ +

Non-constant field names (static or otherwise) are written +in lowerCamelCase.

+ +

These names are typically nouns or noun phrases. For example, +computedValues or +index.

+ +

5.2.6 Parameter names

+ +

Parameter names are written in lowerCamelCase.

+ +

One-character parameter names in public methods should be avoided.

+ +

5.2.7 Local variable names

+ +

Local variable names are written in lowerCamelCase.

+ +

Even when final and immutable, local variables are not considered to be constants, and should not +be styled as constants.

+ +

5.2.8 Type variable names

+ +

Each type variable is named in one of two styles:

+ +
    +
  • A single capital letter, optionally followed by a single numeral (such as + E, T, + X, T2) +
  • + +
  • A name in the form used for classes (see Section 5.2.2, + Class names), followed by the capital letter + T (examples: + RequestT, + FooBarT).
  • +
+ + + +

5.3 Camel case: defined

+ +

Sometimes there is more than one reasonable way to convert an English phrase into camel case, +such as when acronyms or unusual constructs like "IPv6" or "iOS" are present. To improve +predictability, Google Style specifies the following (nearly) deterministic scheme.

+ +

Beginning with the prose form of the name:

+ +
    +
  1. Convert the phrase to plain ASCII and remove any apostrophes. For example, "Müller's + algorithm" might become "Muellers algorithm".
  2. + +
  3. Divide this result into words, splitting on spaces and any remaining punctuation (typically + hyphens). + +
      +
    • Recommended: if any word already has a conventional camel-case appearance in common + usage, split this into its constituent parts (e.g., "AdWords" becomes "ad words"). Note + that a word such as "iOS" is not really in camel case per se; it defies any + convention, so this recommendation does not apply.
    • +
    +
  4. + +
  5. Now lowercase everything (including acronyms), then uppercase only the first + character of: +
      +
    • ... each word, to yield upper camel case, or
    • +
    • ... each word except the first, to yield lower camel case
    • +
    +
  6. + +
  7. Finally, join all the words into a single identifier.
  8. +
+ +

Note that the casing of the original words is almost entirely disregarded. Examples:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Prose formCorrectIncorrect
"XML HTTP request"XmlHttpRequestXMLHTTPRequest
"new customer ID"newCustomerIdnewCustomerID
"inner stopwatch"innerStopwatchinnerStopWatch
"supports IPv6 on iOS?"supportsIpv6OnIossupportsIPv6OnIOS
"YouTube importer"YouTubeImporter
+ YoutubeImporter*
+ +

*Acceptable, but not recommended.

+ +

Note: Some words are ambiguously hyphenated in the English +language: for example "nonempty" and "non-empty" are both correct, so the method names +checkNonempty and +checkNonEmpty are likewise both correct.

+ + +

6 Programming Practices

+ +

6.1 @Override: always used

+ +

A method is marked with the @Override annotation +whenever it is legal. This includes a class method overriding a superclass method, a class method +implementing an interface method, and an interface method respecifying a superinterface +method.

+ +

Exception: +@Override may be omitted when the parent method is +@Deprecated.

+ + +

6.2 Caught exceptions: not ignored

+ +

Except as noted below, it is very rarely correct to do nothing in response to a caught +exception. (Typical responses are to log it, or if it is considered "impossible", rethrow it as an +AssertionError.)

+ +

When it truly is appropriate to take no action whatsoever in a catch block, the reason this is +justified is explained in a comment.

+ +
try {
+  int i = Integer.parseInt(response);
+  return handleNumericResponse(i);
+} catch (NumberFormatException ok) {
+  // it's not numeric; that's fine, just continue
+}
+return handleTextResponse(response);
+
+ +

Exception: In tests, a caught exception may be ignored +without comment if its name is or begins with expected. The +following is a very common idiom for ensuring that the code under test does throw an +exception of the expected type, so a comment is unnecessary here.

+ +
try {
+  emptyStack.pop();
+  fail();
+} catch (NoSuchElementException expected) {
+}
+
+ +

6.3 Static members: qualified using class

+ +

When a reference to a static class member must be qualified, it is qualified with that class's +name, not with a reference or expression of that class's type.

+ +
Foo aFoo = ...;
+Foo.aStaticMethod(); // good
+aFoo.aStaticMethod(); // bad
+somethingThatYieldsAFoo().aStaticMethod(); // very bad
+
+ + +

6.4 Finalizers: not used

+ +

It is extremely rare to override Object.finalize.

+ +

Tip: Don't do it. If you absolutely must, first read and understand + + + Effective Java Item 7, + +"Avoid Finalizers," very carefully, and then don't do it.

+ + + +

7 Javadoc

+ + + +

7.1 Formatting

+ +

7.1.1 General form

+ +

The basic formatting of Javadoc blocks is as seen in this example:

+ +
/**
+ * Multiple lines of Javadoc text are written here,
+ * wrapped normally...
+ */
+public int method(String p1) { ... }
+
+ +

... or in this single-line example:

+ +
/** An especially short bit of Javadoc. */
+
+ +

The basic form is always acceptable. The single-line form may be substituted when the entirety +of the Javadoc block (including comment markers) can fit on a single line. Note that this only +applies when there are no block tags such as @return. + +

7.1.2 Paragraphs

+ +

One blank line—that is, a line containing only the aligned leading asterisk +(*)—appears between paragraphs, and before the group of block tags if +present. Each paragraph but the first has <p> immediately before the first word, +with no space after.

+ + + +

7.1.3 Block tags

+ +

Any of the standard "block tags" that are used appear in the order @param, +@return, @throws, @deprecated, and these four types never +appear with an empty description. When a block tag doesn't fit on a single line, continuation lines +are indented four (or more) spaces from the position of the @. +

+ +

7.2 The summary fragment

+ +

Each Javadoc block begins with a brief summary fragment. This +fragment is very important: it is the only part of the text that appears in certain contexts such as +class and method indexes.

+ +

This is a fragment—a noun phrase or verb phrase, not a complete sentence. It does +not begin with A {@code Foo} is a..., or +This method returns..., nor does it form a complete imperative sentence +like Save the record.. However, the fragment is capitalized and +punctuated as if it were a complete sentence.

+ +

Tip: A common mistake is to write simple Javadoc in the form +/** @return the customer ID */. This is incorrect, and should be +changed to /** Returns the customer ID. */.

+ + +

7.3 Where Javadoc is used

+ +

At the minimum, Javadoc is present for every +public class, and every +public or +protected member of such a class, with a few exceptions +noted below.

+ +

Additional Javadoc content may also be present, as explained in Section 7.3.4, +Non-required Javadoc.

+ +

7.3.1 Exception: self-explanatory methods

+ +

Javadoc is optional for "simple, obvious" methods like +getFoo, in cases where there really and truly is +nothing else worthwhile to say but "Returns the foo".

+ +

Important: it is not appropriate to cite this exception to justify +omitting relevant information that a typical reader might need to know. For example, for a method +named getCanonicalName, don't omit its documentation +(with the rationale that it would say only +/** Returns the canonical name. */) if a typical reader may have no idea +what the term "canonical name" means!

+ +

7.3.2 Exception: overrides

+ +

Javadoc is not always present on a method that overrides a supertype method. + +

+ + + +

7.3.4 Non-required Javadoc

+ +

Other classes and members have Javadoc as needed or desired. + +

Whenever an implementation comment would be used to define the overall purpose or behavior of a +class or member, that comment is written as Javadoc instead (using /**).

+ +

Non-required Javadoc is not strictly required to follow the formatting rules of Sections +7.1.2, 7.1.3, and 7.2, though it is of course recommended.

+ + + +
+
+ + diff --git a/javaguidelink.png b/javaguidelink.png new file mode 100644 index 000000000..75d5c7ba8 Binary files /dev/null and b/javaguidelink.png differ diff --git a/javascriptguide.xml b/javascriptguide.xml new file mode 100644 index 000000000..aba5a1eb2 --- /dev/null +++ b/javascriptguide.xml @@ -0,0 +1,3629 @@ + + + +

+ Please note: there's a newer version of this guide that includes + ECMAScript 6th Edition features. It lives here. + You should probably be using that for new code. + + Revision 2.93 +

+ +
+ Aaron Whyte
+ Bob Jervis
+ Dan Pupius
+ Erik Arvidsson
+ Fritz Schneider
+ Robby Walker
+
+ + + + + This style guide contains many details that are initially + hidden from view. They are marked by the triangle icon, which you + see here on your left. Click it now. + You should see "Hooray" appear below. + + +

+ Hooray! Now you know you can expand points to get more + details. Alternatively, there's a "toggle all" at the + top of this document. +

+ +
+
+ +

+ JavaScript is the main client-side scripting language used + + by many of Google's open-source + projects. + This style guide is a list of dos and don'ts for + JavaScript programs. +

+ + + + + +
+
+ + + + + + + + Declarations with var: Always + + + + When you fail to specify var, + the variable gets placed in the global context, potentially clobbering + existing values. Also, if there's no declaration, it's hard to tell in + what scope a variable lives (e.g., it could be in the Document or + Window just as easily as in the local scope). So always declare with + var. + + + + + + +
    +
  • Use NAMES_LIKE_THIS for constant values.
  • +
  • Use @const to indicate a constant (non-overwritable) + pointer (a variable or property).
  • +
  • Never use the + + const keyword + as it's not supported in Internet Explorer.
  • +
+
+ + + + +

If a value is intended to be constant + and immutable, it should be given a name + in CONSTANT_VALUE_CASE. + ALL_CAPS additionally implies @const + (that the value is not overwritable). +

+ +

Primitive types (number, string, + boolean) are constant values.

+ +

Objects' + immutability is more subjective — objects should be + considered immutable only if they do not demonstrate observable + state change. This is not enforced by the compiler.

+ + +
+ + +

The @const annotation on a variable or property + implies that it is not overwritable. This is enforced by the + compiler at build time. This behavior is consistent with the + + const keyword (which we do not use due to the + lack of support in Internet Explorer).

+ +

A @const annotation on a method additionally + implies that the method cannot not be overridden in subclasses. +

+ +

A @const annotation on a constructor implies the + class cannot be subclassed (akin to final in Java). +

+ +
+ + + +

Note that @const does not necessarily imply + CONSTANT_VALUES_CASE. + + However, CONSTANT_VALUES_CASE + does imply @const. +

+ + + /** + * Request timeout in milliseconds. + * @type {number} + */ + goog.example.TIMEOUT_IN_MILLISECONDS = 60; + + +

The number of seconds in a minute never changes. It is a + constant value. ALL_CAPS + also implies @const, so the constant cannot be + overwritten. +

+ +

The open source compiler will allow the symbol to be + overwritten because the constant is + not marked as @const.

+ + + /** + * Map of URL to response string. + * @const + */ + MyClass.fetchedUrlCache_ = new goog.structs.Map(); + + + + /** + * Class that cannot be subclassed. + * @const + * @constructor + */ + sloth.MyFinalClass = function() {}; + + +

In this case, the pointer can never be overwritten, but + value is highly mutable and not constant (and thus in + camelCase, not ALL_CAPS).

+
+ +
+ +
+ + + + Always use semicolons. + + +

Relying on implicit insertion can cause subtle, hard to debug + problems. Don't do it. You're better than that.

+

There are a couple places where missing semicolons are particularly + dangerous:

+ + // 1. + MyClass.prototype.myMethod = function() { + return 42; + } // No semicolon here. + + (function() { + // Some initialization code wrapped in a function to create a scope for locals. + })(); + + + var x = { + 'i': 1, + 'j': 2 + } // No semicolon here. + + // 2. Trying to do one thing on Internet Explorer and another on Firefox. + // I know you'd never write code like this, but throw me a bone. + [ffVersion, ieVersion][isIE](); + + + var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No semicolon here. + + // 3. conditional execution a la bash + -1 == resultOfOperation() || die(); + + +
    +
  1. JavaScript error - first the function returning 42 is called + with the second function as a parameter, then the number 42 is + "called" resulting in an error.
  2. +
  3. You will most likely get a 'no such property in undefined' + error at runtime as it tries to call + x[ffVersion, ieVersion][isIE]().
  4. +
  5. die is always called since the array minus 1 is + NaN which is never equal to anything (not even if + resultOfOperation() returns NaN) and + THINGS_TO_EAT gets assigned the result of + die().
  6. +
+
+ +

JavaScript requires statements to end with a semicolon, except when + it thinks it can safely infer their existence. In each of these + examples, a function declaration or object or array literal is used + inside a statement. The closing brackets are not enough to signal + the end of the statement. Javascript never ends a statement if the + next token is an infix or bracket operator.

+

This has really surprised people, so make sure your assignments end + with semicolons.

+
+ +

Semicolons should be included at the end of function expressions, + but not at the end of function declarations. The distinction is + best illustrated with an example:

+ + var foo = function() { + return true; + }; // semicolon here. + + function foo() { + return true; + } // no semicolon here. + +
+ +
+ + + Yes + +

Nested functions can be very useful, for example in the creation of + continuations and for the task of hiding helper functions. Feel free + to use them.

+ +
+ + + No + +

Do not do this:

+ + if (x) { + function foo() {} + } + + +

While most script engines support Function Declarations within blocks + it is not part of ECMAScript (see + ECMA-262, + clause 13 and 14). Worse implementations are inconsistent with each + other and with future EcmaScript proposals. ECMAScript only allows for + Function Declarations in the root statement list of a script or + function. Instead use a variable initialized with a Function + Expression to define a function within a block:

+ + if (x) { + var foo = function() {}; + } + + +
+ + + Yes + +

You basically can't avoid exceptions if you're doing something + non-trivial (using an application development framework, etc.). + Go for it.

+ +
+ + + Yes + +

Without custom exceptions, returning error information from a + function that also returns a value can be tricky, not to mention + inelegant. Bad solutions include passing in a reference type to hold + error information or always returning Objects with a potential + error member. These basically amount to a primitive exception + handling hack. Feel free to use custom exceptions when + appropriate.

+ +
+ + + Always preferred over non-standards features + +

For maximum portability and compatibility, always prefer standards + features over non-standards features (e.g., + string.charAt(3) over string[3] and element + access with DOM functions instead of using an application-specific + shorthand).

+ +
+ + + No + +

There's no reason to use wrapper objects for primitive types, plus + they're dangerous:

+ + var x = new Boolean(false); + if (x) { + alert('hi'); // Shows 'hi'. + } + +

Don't do it!

+

However type casting is fine.

+ + var x = Boolean(0); + if (x) { + alert('hi'); // This will never be alerted. + } + typeof Boolean(0) == 'boolean'; + typeof new Boolean(0) == 'object'; + +

This is very useful for casting things to + number, string and boolean.

+ +
+ + + Not preferred + +

Multi-level prototype hierarchies are how JavaScript implements + inheritance. You have a multi-level hierarchy if you have a + user-defined class D with another user-defined class B as its + prototype. These hierarchies are much harder to get right than they + first appear!

+ +

For that reason, it is best to use goog.inherits() from + + the Closure Library + + or a similar library function. +

+ + function D() { + goog.base(this) + } + goog.inherits(D, B); + + D.prototype.method = function() { + ... + }; + + +
+ + + /** @constructor */ + function SomeConstructor() { + this.someProperty = 1; + } + Foo.prototype.someMethod = function() { ... }; + +

While there are several ways to attach methods and properties to an + object created via "new", the preferred style for methods + is:

+ + Foo.prototype.bar = function() { + /* ... */ + }; + +

The preferred style for other properties is to initialize the field + in the constructor:

+ + /** @constructor */ + function Foo() { + this.bar = value; + } + + +

Current JavaScript engines optimize based on the "shape" + of an object, + adding a property to an object (including overriding + a value set on the prototype) changes the shape and can degrade + performance.

+
+ +
+ + + Prefer this.foo = null. + + + Foo.prototype.dispose = function() { + this.property_ = null; + }; + +

Instead of:

+ + Foo.prototype.dispose = function() { + delete this.property_; + }; + +

In modern JavaScript engines, changing the number of properties on an + object is much slower than reassigning the values. The delete keyword + should be avoided except when it is necessary to remove a property + from an object's iterated list of keys, or to change the result of + if (key in obj).

+ +
+ + + Yes, but be careful. + +

The ability to create closures is perhaps the most useful and often + overlooked feature of JS. Here is + + a good description of how closures work.

+

One thing to keep in mind, however, is that a closure keeps a pointer + to its enclosing scope. As a result, attaching a closure to a DOM + element can create a circular reference and thus, a memory leak. For + example, in the following code:

+ + function foo(element, a, b) { + element.onclick = function() { /* uses a and b */ }; + } + +

the function closure keeps a reference to element, + a, and b even if it never uses + element. Since element also keeps a + reference to the closure, we have a cycle that won't be cleaned up by + garbage collection. In these situations, the code can be structured + as follows:

+ + function foo(element, a, b) { + element.onclick = bar(a, b); + } + + function bar(a, b) { + return function() { /* uses a and b */ }; + } + + +
+ + + + Only for code loaders and REPL (Read–eval–print loop) + + +

eval() makes for confusing semantics and is dangerous + to use if the string being eval()'d contains user input. + There's usually a better, clearer, and safer way to write your code, + so its use is generally not permitted.

+ +

For RPC you can always use JSON and read the result using + JSON.parse() instead of eval().

+ +

Let's assume we have a server that returns something like this:

+ + + { + "name": "Alice", + "id": 31502, + "email": "looking_glass@example.com" + } + + + + var userInfo = eval(feed); + var email = userInfo['email']; + + +

If the feed was modified to include malicious JavaScript code, then + if we use eval then that code will be executed.

+ + + var userInfo = JSON.parse(feed); + var email = userInfo['email']; + + +

With JSON.parse, invalid JSON (including all executable + JavaScript) will cause an exception to be thrown.

+ + +
+ + + No + +

Using with clouds the semantics of your program. + Because the object of the with can have properties that + collide with local variables, it can drastically change the meaning + of your program. For example, what does this do?

+ + with (foo) { + var x = 3; + return x; + } + +

Answer: anything. The local variable x could be + clobbered by a property of foo and perhaps it even has + a setter, in which case assigning 3 could cause lots of + other code to execute. Don't use with.

+ +
+ + + + Only in object constructors, methods, and in setting up closures + + +

The semantics of this can be tricky. At times it refers + to the global object (in most places), the scope of the caller (in + eval), a node in the DOM tree (when attached using an + event handler HTML attribute), a newly created object (in a + constructor), or some other object (if function was + call()ed or apply()ed).

+

Because this is so easy to get wrong, limit its use to those places + where it is required:

+
    +
  • in constructors
  • +
  • in methods of objects (including in the creation of closures)
  • +
+ +
+ + + + Only for iterating over keys in an object/map/hash + + +

for-in loops are often incorrectly used to loop over + the elements in an Array. This is however very error + prone because it does not loop from 0 to + length - 1 but over all the present keys in the object + and its prototype chain. Here are a few cases where it fails:

+ + function printArray(arr) { + for (var key in arr) { + print(arr[key]); + } + } + + printArray([0,1,2,3]); // This works. + + var a = new Array(10); + printArray(a); // This is wrong. + + a = document.getElementsByTagName('*'); + printArray(a); // This is wrong. + + a = [0,1,2,3]; + a.buhu = 'wine'; + printArray(a); // This is wrong again. + + a = new Array; + a[3] = 3; + printArray(a); // This is wrong again. + +

Always use normal for loops when using arrays.

+ + function printArray(arr) { + var l = arr.length; + for (var i = 0; i < l; i++) { + print(arr[i]); + } + } + + +
+ + + + Never use Array as a map/hash/associative array + + +

Associative Arrays are not allowed... or more precisely + you are not allowed to use non number indexes for arrays. If you need + a map/hash use Object instead of Array in + these cases because the features that you want are actually features + of Object and not of Array. + Array just happens to extend Object (like + any other object in JS and therefore you might as well have used + Date, RegExp or String).

+ +
+ + + No + +

Do not do this:

+ + var myString = 'A rather long string of English text, an error message \ + actually that just keeps going and going -- an error \ + message to make the Energizer bunny blush (right through \ + those Schwarzenegger shades)! Where was I? Oh yes, \ + you\'ve got an error and all the extraneous whitespace is \ + just gravy. Have a nice day.'; + +

The whitespace at the beginning of each line can't be safely stripped + at compile time; whitespace after the slash will result in tricky + errors.

+

Use string concatenation instead:

+ + var myString = 'A rather long string of English text, an error message ' + + 'actually that just keeps going and going -- an error ' + + 'message to make the Energizer bunny blush (right through ' + + 'those Schwarzenegger shades)! Where was I? Oh yes, ' + + 'you\'ve got an error and all the extraneous whitespace is ' + + 'just gravy. Have a nice day.'; + + +
+ + + Yes + +

Use Array and Object literals instead of + Array and Object constructors.

+

Array constructors are error-prone due to their arguments.

+ + // Length is 3. + var a1 = new Array(x1, x2, x3); + + // Length is 2. + var a2 = new Array(x1, x2); + + // If x1 is a number and it is a natural number the length will be x1. + // If x1 is a number but not a natural number this will throw an exception. + // Otherwise the array will have one element with x1 as its value. + var a3 = new Array(x1); + + // Length is 0. + var a4 = new Array(); + +

Because of this, if someone changes the code to pass 1 argument + instead of 2 arguments, the array might not have the expected + length.

+

To avoid these kinds of weird cases, always use the more readable + array literal.

+ + var a = [x1, x2, x3]; + var a2 = [x1, x2]; + var a3 = [x1]; + var a4 = []; + +

Object constructors don't have the same problems, but for readability + and consistency object literals should be used.

+ + var o = new Object(); + + var o2 = new Object(); + o2.a = 0; + o2.b = 1; + o2.c = 2; + o2['strange key'] = 3; + +

Should be written as:

+ + var o = {}; + + var o2 = { + a: 0, + b: 1, + c: 2, + 'strange key': 3 + }; + + +
+ + + No + +

Modifying builtins like Object.prototype and + Array.prototype are strictly forbidden. Modifying other + builtins like Function.prototype is less dangerous but + still leads to hard to debug issues in production and should be + avoided.

+ +
+ + + No + +

Don't do this:

+ + var f = function () { + /*@cc_on if (@_jscript) { return 2* @*/ 3; /*@ } @*/ + }; + +

Conditional Comments hinder automated tools as they can vary the + JavaScript syntax tree at runtime.

+ +
+
+ + + + +

In general, use + functionNamesLikeThis, + variableNamesLikeThis, + ClassNamesLikeThis, + EnumNamesLikeThis, + methodNamesLikeThis, + CONSTANT_VALUES_LIKE_THIS, + foo.namespaceNamesLikeThis.bar, and + filenameslikethis.js. +

+
+ + +
    +
  • Private properties and methods should be named with a + trailing underscore. +
  • +
  • Protected properties and methods should be + named without a trailing underscore (like public ones).
  • +
+

For more information on private and protected, + read the section on + + visibility. +

+ + + + +
+ + +

Optional function arguments start with opt_.

+

Functions that take a variable number of arguments should have the + last argument named var_args. You may not refer to + var_args in the code; use the arguments + array.

+

Optional and variable arguments can also be specified in + @param annotations. Although either convention is + acceptable to the compiler, using both together is preferred.

+ +
+ + +

EcmaScript 5 getters and setters for properties are discouraged. + However, if they are used, then getters must not change observable + state.

+ + /** + * WRONG -- Do NOT do this. + */ + var foo = { get next() { return this.nextId++; } }; + +
+ + +

Getters and setters methods for properties are not required. + However, if they are used, then getters must be named + getFoo() and setters must be named + setFoo(value). (For boolean getters, + isFoo() is also acceptable, and often sounds more + natural.)

+
+ + +

JavaScript has no inherent packaging or namespacing support.

+

Global name conflicts are difficult to debug, and can cause + intractable problems when two projects try to integrate. In order + to make it possible to share common JavaScript code, we've adopted + conventions to prevent collisions.

+ +

ALWAYS prefix identifiers in the global scope with a + unique pseudo namespace related to the project or library. If you + are working on "Project Sloth", a reasonable pseudo namespace + would be sloth.*.

+ + var sloth = {}; + + sloth.sleep = function() { + ... + }; + + + +

Many JavaScript libraries, including + + the Closure Library + + and + + Dojo toolkit + + give you high-level functions for declaring your namespaces. + Be consistent about how you declare your namespaces.

+ + goog.provide('sloth'); + + sloth.sleep = function() { + ... + }; + +
+ +

When choosing a child-namespace, make sure that the owners of the + parent namespace know what you are doing. If you start a project + that creates hats for sloths, make sure that the Sloth team knows + that you're using sloth.hats.

+ +
+ +

"External code" is code that comes from outside your codebase, + and is compiled independently. Internal and external names should + be kept strictly separate. If you're using an external library + that makes things available in foo.hats.*, your + internal code should not define all its symbols in + foo.hats.*, because it will break if the other + team defines new symbols.

+ + foo.require('foo.hats'); + + /** + * WRONG -- Do NOT do this. + * @constructor + * @extends {foo.hats.RoundHat} + */ + foo.hats.BowlerHat = function() { + }; + +

If you need to define new APIs on an external namespace, then you + should explicitly export the public API functions, and only those + functions. Your internal code should call the internal APIs by + their internal names, for consistency and so that the compiler + can optimize them better.

+ + foo.provide('googleyhats.BowlerHat'); + + foo.require('foo.hats'); + + /** + * @constructor + * @extends {foo.hats.RoundHat} + */ + googleyhats.BowlerHat = function() { + ... + }; + + goog.exportSymbol('foo.hats.BowlerHat', googleyhats.BowlerHat); + + + +
+ +

Use local aliases for fully-qualified types if doing so improves + readability. The name of a local alias should match the last part + of the type.

+ + /** + * @constructor + */ + some.long.namespace.MyClass = function() { + }; + + /** + * @param {some.long.namespace.MyClass} a + */ + some.long.namespace.MyClass.staticHelper = function(a) { + ... + }; + + myapp.main = function() { + var MyClass = some.long.namespace.MyClass; + var staticHelper = some.long.namespace.MyClass.staticHelper; + staticHelper(new MyClass()); + }; + +

Do not create local aliases of namespaces. Namespaces should only + be aliased using goog.scope.

+ + myapp.main = function() { + var namespace = some.long.namespace; + namespace.MyClass.staticHelper(new namespace.MyClass()); + }; + +

Avoid accessing properties of an aliased type, unless it is an + enum.

+ + /** @enum {string} */ + some.long.namespace.Fruit = { + APPLE: 'a', + BANANA: 'b' + }; + + myapp.main = function() { + var Fruit = some.long.namespace.Fruit; + switch (fruit) { + case Fruit.APPLE: + ... + case Fruit.BANANA: + ... + } + }; + + + myapp.main = function() { + var MyClass = some.long.namespace.MyClass; + MyClass.staticHelper(null); + }; + +

Never create aliases in the global scope. Use them only in + function blocks.

+
+
+ +

Filenames should be all lowercase in order to avoid confusion on + case-sensitive platforms. Filenames should end in .js, + and should contain no punctuation except for - or + _ (prefer - to _).

+
+ + +
+ + + + Must always succeed without side effects. + + +

You can control how your objects string-ify themselves by defining a + custom toString() method. This is fine, but you need + to ensure that your method (1) always succeeds and (2) does not have + side-effects. If your method doesn't meet these criteria, it's very + easy to run into serious problems. For example, if + toString() calls a method that does an + assert, assert might try to output the name + of the object in which it failed, which of course requires calling + toString().

+ +
+ + + OK + +

It isn't always possible to initialize variables at the point of + declaration, so deferred initialization is fine.

+ +
+ + + Always + +

Always use explicit scope - doing so increases portability and + clarity. For example, don't rely on window being in the + scope chain. You might want to use your function in another + application for which window is not the content + window.

+ +
+ + + Expand for more information. + +

We follow the C++ formatting + rules in spirit, with the following additional clarifications.

+ +

Because of implicit semicolon insertion, always start your curly + braces on the same line as whatever they're opening. For + example:

+ + if (something) { + // ... + } else { + // ... + } + +
+ +

Single-line array and object initializers are allowed when they + fit on a line:

+ + var arr = [1, 2, 3]; // No space after [ or before ]. + var obj = {a: 1, b: 2, c: 3}; // No space after { or before }. + +

Multiline array initializers and object initializers are indented + 2 spaces, with the braces on their own line, just like blocks.

+ + // Object initializer. + var inset = { + top: 10, + right: 20, + bottom: 15, + left: 12 + }; + + // Array initializer. + this.rows_ = [ + '"Slartibartfast" <fjordmaster@magrathea.com>', + '"Zaphod Beeblebrox" <theprez@universe.gov>', + '"Ford Prefect" <ford@theguide.com>', + '"Arthur Dent" <has.no.tea@gmail.com>', + '"Marvin the Paranoid Android" <marv@googlemail.com>', + 'the.mice@magrathea.com' + ]; + + // Used in a method call. + goog.dom.createDom(goog.dom.TagName.DIV, { + id: 'foo', + className: 'some-css-class', + style: 'display:none' + }, 'Hello, world!'); + +

Long identifiers or values present problems for aligned + initialization lists, so always prefer non-aligned initialization. + For example:

+ + CORRECT_Object.prototype = { + a: 0, + b: 1, + lengthyName: 2 + }; + +

Not like this:

+ + WRONG_Object.prototype = { + a : 0, + b : 1, + lengthyName: 2 + }; + +
+ +

When possible, all function arguments should be listed on the same + line. If doing so would exceed the 80-column limit, the arguments + must be line-wrapped in a readable way. To save space, you may wrap + as close to 80 as possible, or put each argument on its own line to + enhance readability. The indentation may be either four spaces, or + aligned to the parenthesis. Below are the most common patterns for + argument wrapping:

+ + // Four-space, wrap at 80. Works with very long function names, survives + // renaming without reindenting, low on space. + goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( + veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { + // ... + }; + + // Four-space, one argument per line. Works with long function names, + // survives renaming, and emphasizes each argument. + goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( + veryDescriptiveArgumentNumberOne, + veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, + artichokeDescriptorAdapterIterator) { + // ... + }; + + // Parenthesis-aligned indentation, wrap at 80. Visually groups arguments, + // low on space. + function foo(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { + // ... + } + + // Parenthesis-aligned, one argument per line. Emphasizes each + // individual argument. + function bar(veryDescriptiveArgumentNumberOne, + veryDescriptiveArgumentTwo, + tableModelEventHandlerProxy, + artichokeDescriptorAdapterIterator) { + // ... + } + +

When the function call is itself indented, you're free to start the + 4-space indent relative to the beginning of the original statement + or relative to the beginning of the current function call. + The following are all acceptable indentation styles.

+ + if (veryLongFunctionNameA( + veryLongArgumentName) || + veryLongFunctionNameB( + veryLongArgumentName)) { + veryLongFunctionNameC(veryLongFunctionNameD( + veryLongFunctioNameE( + veryLongFunctionNameF))); + } + +
+ +

When declaring an anonymous function in the list of arguments for + a function call, the body of the function is indented two spaces + from the left edge of the statement, or two spaces from the left + edge of the function keyword. This is to make the body of the + anonymous function easier to read (i.e. not be all squished up into + the right half of the screen).

+ + prefix.something.reallyLongFunctionName('whatever', function(a1, a2) { + if (a1.equals(a2)) { + someOtherLongFunctionName(a1); + } else { + andNowForSomethingCompletelyDifferent(a2.parrot); + } + }); + + var names = prefix.something.myExcellentMapFunction( + verboselyNamedCollectionOfItems, + function(item) { + return item.name; + }); + +
+ + +

+ goog.scope + may be used to shorten references to + namespaced symbols in programs using + the Closure + Library.

+

Only one goog.scope invocation may be added per + file. Always place it in the global scope.

+

The opening goog.scope(function() { invocation + must be preceded by exactly one blank line and follow any + goog.provide statements, goog.require + statements, or top-level comments. The invocation must be closed on + the last line in the file. Append // goog.scope to the + closing statement of the scope. Separate the comment from the + semicolon by two spaces.

+

Similar to C++ namespaces, do not indent under goog.scope + declarations. Instead, continue from the 0 column.

+

Only alias names that will not be re-assigned to another object + (e.g., most constructors, enums, and namespaces). Do not do + this (see below for how to alias a constructor):

+ + + goog.scope(function() { + var Button = goog.ui.Button; + + Button = function() { ... }; + ... + + +

Names must be the same as the last property of the global that they + are aliasing.

+ + + goog.provide('my.module.SomeType'); + + goog.require('goog.dom'); + goog.require('goog.ui.Button'); + + goog.scope(function() { + var Button = goog.ui.Button; + var dom = goog.dom; + + // Alias new types after the constructor declaration. + my.module.SomeType = function() { ... }; + var SomeType = my.module.SomeType; + + // Declare methods on the prototype as usual: + SomeType.prototype.findButton = function() { + // Button as aliased above. + this.button = new Button(dom.getElement('my-button')); + }; + ... + }); // goog.scope + +
+ +

Except for array literals, + object literals, and anonymous functions, all wrapped lines + should be indented either left-aligned to a sibling expression + above, or four spaces (not two spaces) deeper than a parent + expression (where "sibling" and "parent" refer to parenthesis + nesting level). +

+ + + someWonderfulHtml = '
' + + getEvenMoreHtml(someReallyInterestingValues, moreValues, + evenMoreParams, 'a duck', true, 72, + slightlyMoreMonkeys(0xfff)) + + '
'; + + thisIsAVeryLongVariableName = + hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine(); + + thisIsAVeryLongVariableName = siblingOne + siblingTwo + siblingThree + + siblingFour + siblingFive + siblingSix + siblingSeven + + moreSiblingExpressions + allAtTheSameIndentationLevel; + + thisIsAVeryLongVariableName = operandOne + operandTwo + operandThree + + operandFour + operandFive * ( + aNestedChildExpression + shouldBeIndentedMore); + + someValue = this.foo( + shortArg, + 'Some really long string arg - this is a pretty common case, actually.', + shorty2, + this.bar()); + + if (searchableCollection(allYourStuff).contains(theStuffYouWant) && + !ambientNotification.isActive() && (client.isAmbientSupported() || + client.alwaysTryAmbientAnyways())) { + ambientNotification.activate(); + } +
+
+ +

Use newlines to group logically related pieces of code. + For example:

+ + doSomethingTo(x); + doSomethingElseTo(x); + andThen(x); + + nowDoSomethingWith(y); + + andNowWith(z); + +
+ +

Always put the operator on the preceding line. Otherwise, + line breaks and indentation follow the same rules as in other + Google style guides. This operator placement was initially agreed + upon out of concerns about automatic semicolon insertion. In fact, + semicolon insertion cannot happen before a binary operator, but new + code should stick to this style for consistency.

+ + var x = a ? b : c; // All on one line if it will fit. + + // Indentation +4 is OK. + var y = a ? + longButSimpleOperandB : longButSimpleOperandC; + + // Indenting to the line position of the first operand is also OK. + var z = a ? + moreComplicatedB : + moreComplicatedC; + +

This includes the dot operator.

+ + var x = foo.bar(). + doSomething(). + doSomethingElse(); + +
+ +
+ + + Only where required + +

Use sparingly and in general only where required by the syntax + and semantics.

+

Never use parentheses for unary operators such as + delete, typeof and void or + after keywords such as return, throw as + well as others (case, in or + new).

+ +
+ + + Prefer ' over " + +

For consistency single-quotes (') are preferred to double-quotes ("). + This is helpful when creating strings that include HTML:

+ + var msg = 'This is some HTML'; + + +
+ + + Encouraged, use JSDoc annotations @private and + @protected + +

We recommend the use of the JSDoc annotations @private and + @protected to indicate visibility levels for classes, + functions, and properties.

+

The --jscomp_warning=visibility compiler flag turns on compiler + warnings for visibility violations. See + + Closure Compiler + Warnings. +

+

@private global variables and functions are only + accessible to code in the same file.

+

Constructors marked @private may only be instantiated by + code in the same file and by their static and instance members. + @private constructors may also be accessed anywhere in the + same file for their public static properties and by the + instanceof operator.

+

Global variables, functions, and constructors should never be + annotated @protected.

+ + // File 1. + // AA_PrivateClass_ and AA_init_ are accessible because they are global + // and in the same file. + + /** + * @private + * @constructor + */ + AA_PrivateClass_ = function() { + }; + + /** @private */ + function AA_init_() { + return new AA_PrivateClass_(); + } + + AA_init_(); + +

@private properties are accessible to all code in the + same file, plus all static methods and instance methods of that class + that "owns" the property, if the property belongs to a class. They + cannot be accessed or overridden from a subclass in a different file.

+

@protected properties are accessible to all code in the + same file, plus any static methods and instance methods of any subclass + of a class that "owns" the property.

+

Note that these semantics differ from those of C++ and Java, in that + they grant private and protected access to all code in the same file, + not just in the same class or class hierarchy. Also, unlike in C++, + private properties cannot be overridden by a subclass. +

+ + // File 1. + + /** @constructor */ + AA_PublicClass = function() { + /** @private */ + this.privateProp_ = 2; + + /** @protected */ + this.protectedProp = 4; + }; + + /** @private */ + AA_PublicClass.staticPrivateProp_ = 1; + + /** @protected */ + AA_PublicClass.staticProtectedProp = 31; + + /** @private */ + AA_PublicClass.prototype.privateMethod_ = function() {}; + + /** @protected */ + AA_PublicClass.prototype.protectedMethod = function() {}; + + // File 2. + + /** + * @return {number} The number of ducks we've arranged in a row. + */ + AA_PublicClass.prototype.method = function() { + // Legal accesses of these two properties. + return this.privateProp_ + AA_PublicClass.staticPrivateProp_; + }; + + // File 3. + + /** + * @constructor + * @extends {AA_PublicClass} + */ + AA_SubClass = function() { + // Legal access of a protected static property. + AA_PublicClass.staticProtectedProp = this.method(); + }; + goog.inherits(AA_SubClass, AA_PublicClass); + + /** + * @return {number} The number of ducks we've arranged in a row. + */ + AA_SubClass.prototype.method = function() { + // Legal access of a protected instance property. + return this.protectedProp; + }; + + +

Notice that in JavaScript, there is no distinction between a type + (like AA_PrivateClass_) and the constructor for that + type. There is no way to express both that a type is public and its + constructor is private (because the constructor could easily be aliased + in a way that would defeat the privacy check).

+ +
+ + + Encouraged and enforced by the compiler. + + +

When documenting a type in JSDoc, be as specific and accurate as + possible. The types we support are based on the + + EcmaScript 4 spec.

+ +

The ES4 proposal contained a language for specifying JavaScript + types. We use this language in JsDoc to express the types of + function parameters and return values.

+ +

As the ES4 proposal has evolved, this language has changed. The + compiler still supports old syntaxes for types, but those syntaxes + are deprecated.

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Syntax NameSyntaxDescriptionDeprecated Syntaxes
Primitive Type + There are 5 primitive types in JavaScript: + {null}, + {undefined}, + {boolean}, + {number}, and + {string}. + Simply the name of a type. +
Instance Type + {Object}
+ An instance of Object or null.

+ {Function}
+ An instance of Function or null.

+ {EventTarget}
+ An instance of a constructor that implements the EventTarget + interface, or null. +

An instance of a constructor or interface function.

+ + Constructor functions are functions defined with the + @constructor JSDoc tag. + Interface functions are functions defined with the + @interface JSDoc tag.

+ + By default, instance types will accept null. This is the only + type syntax that makes the type nullable. Other type syntaxes + in this table will not accept null. +

+
Enum Type + {goog.events.EventType}
+ One of the properties of the object literal initializer + of goog.events.EventType. +
An enum must be initialized as an object literal, or as + an alias of another enum, annotated with the @enum + JSDoc tag. The properties of this literal are the instances + of the enum. The syntax of the enum is defined + below.

+ + Note that this is one of the few things in our type system + that were not in the ES4 spec. +

+
Type Application + {Array.<string>}
An array of strings.

+ {Object.<string, number>} +
An object in which the keys are strings and the values + are numbers. +

Parameterizes a type, by applying a set of type arguments + to that type. The idea is analogous to generics in Java. + +
Type Union + {(number|boolean)}
A number or a boolean. +
Indicates that a value might have type A OR type B.

+ + The parentheses may be omitted at the top-level + expression, but the parentheses should be included in + sub-expressions to avoid ambiguity.
+ {number|boolean}
+ {function(): (number|boolean)} +

+ {(number,boolean)},
+ {(number||boolean)} +
Nullable type + {?number}
A number or null. +
Shorthand for the union of the null type with any + other type. This is just syntactic sugar. + + {number?} +
Non-nullable type + {!Object}
An Object, but never the + null value. +
Filters null out of nullable types. Most often used + with instance types, which are nullable by default. + + {Object!} +
Record Type + {{myNum: number, myObject}} +
An anonymous type with the given type members. +
+

Indicates that the value has the specified members with the + specified types. In this case, myNum with a + type number and myObject with any + type.

+

Notice that the braces are part of the type syntax. For + example, to denote an Array of objects that + have a length property, you might write + Array.<{length}>.

+
+
Function Type + {function(string, boolean)}
+ A function that takes two arguments (a string and a boolean), + and has an unknown return value.
+
Specifies a function. +
Function Return Type + {function(): number}
+ A function that takes no arguments and returns a number.
+
Specifies a function return type. +
Function this Type + {function(this:goog.ui.Menu, string)}
+ A function that takes one argument (a string), and executes + in the context of a goog.ui.Menu. +
Specifies the context type of a function type. +
Function new Type + {function(new:goog.ui.Menu, string)}
+ A constructor that takes one argument (a string), and + creates a new instance of goog.ui.Menu when called + with the 'new' keyword. +
Specifies the constructed type of a constructor. +
Variable arguments + {function(string, ...[number]): number}
+ A function that takes one argument (a string), and then a + variable number of arguments that must be numbers. +
Specifies variable arguments to a function. +
+ + Variable arguments (in @param annotations) + + @param {...number} var_args
+ A variable number of arguments to an annotated function. +
+ Specifies that the annotated function accepts a variable + number of arguments. + +
Function optional arguments + {function(?string=, number=)}
+ A function that takes one optional, nullable string and one + optional number as arguments. The = syntax is + only for function type declarations. +
Specifies optional arguments to a function. +
+ + Function optional arguments + (in @param annotations) + + @param {number=} opt_argument
+ An optional parameter of type number. +
Specifies that the annotated function accepts an optional + argument. +
The ALL type{*}Indicates that the variable can take on any type. +
The UNKNOWN type{?}Indicates that the variable can take on any type, + and the compiler should not type-check any uses of it. +
+ + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type ExampleValue ExamplesDescription
number + + 1 + 1.0 + -5 + 1e5 + Math.PI + + +
Number + + new Number(true) + + + + Number object + +
string + + 'Hello' + "World" + String(42) + + + String value +
String + + new String('Hello') + new String(42) + + + + String object + +
boolean + + true + false + Boolean(0) + + + Boolean value +
Boolean + + new Boolean(true) + + + + Boolean object + +
RegExp + + new RegExp('hello') + /world/g + +
Date + + new Date + new Date() + +
+ + null + + + + null + + +
+ + undefined + + + + undefined + + +
void + + function f() { + return; + } + + No return value
Array + + ['foo', 0.3, null] + [] + + Untyped Array
Array.<number> + + [11, 22, 33] + + + An Array of numbers +
Array.<Array.<string>> + + [['one', 'two', 'three'], ['foo', 'bar']] + + Array of Arrays of strings
Object + + {} + {foo: 'abc', bar: 123, baz: null} + + +
Object.<string> + + {'foo': 'bar'} + + + An Object in which the values are strings. +
Object.<number, string> + + var obj = {}; + obj[1] = 'bar'; + + + An Object in which the keys are numbers and the values are + strings.

Note that in JavaScript, the keys are always + implicitly converted to strings, so + obj['1'] == obj[1]. + So the key will always be a string in for...in loops. But the + compiler will verify the type of the key when indexing into + the object. +

Function + + function(x, y) { + return x * y; + } + + + + Function object + +
function(number, number): number + + function(x, y) { + return x * y; + } + + function value
SomeClass + + /** @constructor */ + function SomeClass() {} + + new SomeClass(); + + +
SomeInterface + + /** @interface */ + function SomeInterface() {} + + SomeInterface.prototype.draw = function() {}; + + +
project.MyClass + + /** @constructor */ + project.MyClass = function () {} + + new project.MyClass() + + +
project.MyEnum + + /** @enum {string} */ + project.MyEnum = { + /** The color blue. */ + BLUE: '#0000dd', + /** The color red. */ + RED: '#dd0000' + }; + + Enumeration

+ JSDoc comments on enum values are optional. +

Element + + document.createElement('div') + + Elements in the DOM.
Node + + document.body.firstChild + + Nodes in the DOM.
HTMLInputElement + + htmlDocument.getElementsByTagName('input')[0] + + A specific type of DOM element.
+ + + +

In cases where type-checking doesn't accurately infer the type of + an expression, it is possible to add a type cast comment by adding a + type annotation comment and enclosing the expression in + parentheses. The parentheses are required.

+ + + /** @type {number} */ (x) + +
+ + + +

Because JavaScript is a loosely-typed language, it is very + important to understand the subtle differences between optional, + nullable, and undefined function parameters and class + properties.

+ +

Instances of classes and interfaces are nullable by default. + For example, the following declaration

+ + + /** + * Some class, initialized with a value. + * @param {Object} value Some value. + * @constructor + */ + function MyClass(value) { + /** + * Some value. + * @type {Object} + * @private + */ + this.myValue_ = value; + } + + +

tells the compiler that the myValue_ property holds + either an Object or null. If myValue_ must never be + null, it should be declared like this:

+ + + /** + * Some class, initialized with a non-null value. + * @param {!Object} value Some value. + * @constructor + */ + function MyClass(value) { + /** + * Some value. + * @type {!Object} + * @private + */ + this.myValue_ = value; + } + + +

This way, if the compiler can determine that somewhere in the code + MyClass is initialized with a null value, it will issue + a warning.

+ + + +

Optional parameters to functions may be undefined at runtime, so if + they are assigned to class properties, those properties must be + declared accordingly:

+ + + /** + * Some class, initialized with an optional value. + * @param {Object=} opt_value Some value (optional). + * @constructor + */ + function MyClass(opt_value) { + /** + * Some value. + * @type {Object|undefined} + * @private + */ + this.myValue_ = opt_value; + } + + +

This tells the compiler that myValue_ may hold an + Object, null, or remain undefined.

+ +

Note that the optional parameter opt_value is declared + to be of type {Object=}, not + {Object|undefined}. This is because optional + parameters may, by definition, be undefined. While there is no harm + in explicitly declaring an optional parameter as possibly undefined, + it is both unnecessary and makes the code harder to read.

+ +

Finally, note that being nullable and being optional are orthogonal + properties. The following four declarations are all different:

+ + + /** + * Takes four arguments, two of which are nullable, and two of which are + * optional. + * @param {!Object} nonNull Mandatory (must not be undefined), must not be null. + * @param {Object} mayBeNull Mandatory (must not be undefined), may be null. + * @param {!Object=} opt_nonNull Optional (may be undefined), but if present, + * must not be null! + * @param {Object=} opt_mayBeNull Optional (may be undefined), may be null. + */ + function strangeButTrue(nonNull, mayBeNull, opt_nonNull, opt_mayBeNull) { + // ... + }; + +
+ + + +

Sometimes types can get complicated. A function that accepts + content for an Element might look like:

+ + + /** + * @param {string} tagName + * @param {(string|Element|Text|Array.<Element>|Array.<Text>)} contents + * @return {!Element} + */ + goog.createElement = function(tagName, contents) { + ... + }; + + +

You can define commonly used type expressions with a + @typedef tag. For example,

+ + + /** @typedef {(string|Element|Text|Array.<Element>|Array.<Text>)} */ + goog.ElementContent; + + /** + * @param {string} tagName + * @param {goog.ElementContent} contents + * @return {!Element} + */ + goog.createElement = function(tagName, contents) { + ... + }; + + + + +
+

The compiler has limited support for template types. It can only + infer the type of this inside an anonymous function + literal from the type of the this argument and whether the + this argument is missing.

+ + + /** + * @param {function(this:T, ...)} fn + * @param {T} thisObj + * @param {...*} var_args + * @template T + */ + goog.bind = function(fn, thisObj, var_args) { + ... + }; + // Possibly generates a missing property warning. + goog.bind(function() { this.someProperty; }, new SomeClass()); + // Generates an undefined this warning. + goog.bind(function() { this.someProperty; }); + + + +
+ + + Use JSDoc + +

+ We follow the + + C++ style for comments in spirit. +

+ +

All files, classes, methods and properties should be documented with + JSDoc + comments with the appropriate tags + and types. Textual descriptions for properties, + methods, method parameters and method return values should be included + unless obvious from the property, method, or parameter name. +

+ +

Inline comments should be of the // variety.

+ +

Complete sentences are recommended but not required. + Complete sentences should use appropriate capitalization + and punctuation.

+ + +

The JSDoc syntax is based on + + JavaDoc. Many tools extract metadata from JSDoc comments to + perform code validation and optimizations. These comments must be + well-formed.

+ + + /** + * A JSDoc comment should begin with a slash and 2 asterisks. + * Inline tags should be enclosed in braces like {@code this}. + * @desc Block tags should always start on their own line. + */ + +
+ + +

If you have to line break a block tag, you should treat this as + breaking a code statement and indent it four spaces.

+ + + /** + * Illustrates line wrapping for long param/return descriptions. + * @param {string} foo This is a param with a description too long to fit in + * one line. + * @return {number} This returns something that has a description too long to + * fit in one line. + */ + project.MyClass.prototype.method = function(foo) { + return 5; + }; + + +

You should not indent the @fileoverview command. You do not have to + indent the @desc command.

+ +

Even though it is not preferred, it is also acceptable to line up + the description.

+ + + /** + * This is NOT the preferred indentation method. + * @param {string} foo This is a param with a description too long to fit in + * one line. + * @return {number} This returns something that has a description too long to + * fit in one line. + */ + project.MyClass.prototype.method = function(foo) { + return 5; + }; + +
+ + +

Like JavaDoc, JSDoc supports many HTML tags, like <code>, + <pre>, <tt>, <strong>, <ul>, <ol>, + <li>, <a>, and others.

+ +

This means that plaintext formatting is not respected. So, don't + rely on whitespace to format JSDoc:

+ + + /** + * Computes weight based on three factors: + * items sent + * items received + * last timestamp + */ + + +

It'll come out like this:

+ + + Computes weight based on three factors: items sent items received last timestamp + + +

Instead, do this:

+ + + /** + * Computes weight based on three factors: + * <ul> + * <li>items sent + * <li>items received + * <li>last timestamp + * </ul> + */ + + + The + JavaDoc style guide is a useful resource on how to write + well-formed doc comments. +
+ + +

+ + A copyright notice and author information are optional. + File overviews are generally recommended whenever a file consists of + more than a single class definition. The top level comment is + designed to orient readers unfamiliar with the code to what is in + this file. If present, it should provide a description of the + file's contents and any dependencies or compatibility information. + As an example: +

+ + + /** + * @fileoverview Description of file, its uses and information + * about its dependencies. + */ + + + +
+ + +

Classes must be documented with a description and a + type tag that + identifies the constructor. +

+ + + /** + * Class making something fun and easy. + * @param {string} arg1 An argument that makes this more interesting. + * @param {Array.<number>} arg2 List of numbers to be processed. + * @constructor + * @extends {goog.Disposable} + */ + project.MyClass = function(arg1, arg2) { + // ... + }; + goog.inherits(project.MyClass, goog.Disposable); + +
+ + +

Parameter and return types should be documented. The method + description may be omitted if it is obvious from the parameter + or return type descriptions. Method descriptions should start + with a sentence written in the third person declarative voice.

+ + /** + * Operates on an instance of MyClass and returns something. + * @param {project.MyClass} obj Instance of MyClass which leads to a long + * comment that needs to be wrapped to two lines. + * @return {boolean} Whether something occurred. + */ + function PR_someMethod(obj) { + // ... + } + +
+ + + + /** @constructor */ + project.MyClass = function() { + /** + * Maximum number of things per pane. + * @type {number} + */ + this.someProperty = 4; + } + + + + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TagTemplate & ExamplesDescription
+ @author + + + @author username@google.com (first last) +

For example:

+ + /** + * @fileoverview Utilities for handling textareas. + * @author kuth@google.com (Uthur Pendragon) + */ + +
+ Document the author of a file or the owner of a test, + generally only used in the @fileoverview comment. + +
@code + {@code ...} +

For example:

+ + /** + * Moves to the next position in the selection. + * Throws {@code goog.iter.StopIteration} when it + * passes the end of the range. + * @return {Node} The node at the next position. + */ + goog.dom.RangeIterator.prototype.next = function() { + // ... + }; + +
+ Indicates that a term in a JSDoc description is code so it may + be correctly formatted in generated documentation. +
@const + @const
+ @const {type} +

For example:

+ + /** @const */ var MY_BEER = 'stout'; + + /** + * My namespace's favorite kind of beer. + * @const {string} + */ + mynamespace.MY_BEER = 'stout'; + + /** @const */ MyClass.MY_BEER = 'stout'; + + /** + * Initializes the request. + * @const + */ + mynamespace.Request.prototype.initialize = function() { + // This method cannot be overridden in a subclass. + }; + +
+

Marks a variable (or property) as read-only and suitable + for inlining.

+ +

A @const variable is an immutable pointer to + a value. If a variable or property marked as + @const is overwritten, JSCompiler will give + warnings.

+ +

The type declaration of a constant value can be omitted + if it can be clearly inferred. An additional comment about + the variable is optional.

+ +

When @const is applied to a method, it + implies the method is not only not overwritable, but also + that the method is finalized — + not overridable in subclasses.

+ +

For more on @const, see the + Constants section.

+ +
@constructor + @constructor +

For example:

+ + /** + * A rectangle. + * @constructor + */ + function GM_Rect() { + ... + } + +
+ Used in a class's documentation to indicate the constructor. +
@define + @define {Type} description +

For example:

+ + /** @define {boolean} */ + var TR_FLAGS_ENABLE_DEBUG = true; + + /** + * @define {boolean} Whether we know at compile-time that + * the browser is IE. + */ + goog.userAgent.ASSUME_IE = false; + +
+ Indicates a constant that can be overridden by the compiler at + compile-time. In the example, the compiler flag + --define='goog.userAgent.ASSUME_IE=true' + could be specified in the BUILD file to indicate that the + constant goog.userAgent.ASSUME_IE should be replaced + with true. +
@deprecated + @deprecated Description +

For example:

+ + /** + * Determines whether a node is a field. + * @return {boolean} True if the contents of + * the element are editable, but the element + * itself is not. + * @deprecated Use isField(). + */ + BN_EditUtil.isTopEditableField = function(node) { + // ... + }; + +
+ Used to tell that a function, method or property should not be + used any more. Always provide instructions on what callers + should use instead. +
@dict + @dict Description +

For example:

+ + /** + * @constructor + * @dict + */ + function Foo(x) { + this['x'] = x; + } + var obj = new Foo(123); + var num = obj.x; // warning + + (/** @dict */ { x: 1 }).x = 123; // warning + +
+ When a constructor (Foo in the example) is + annotated with @dict, you can only use the + bracket notation to access the properties of Foo + objects. + The annotation can also be used directly on object literals. +
@enum + @enum {Type} +

For example:

+ + /** + * Enum for tri-state values. + * @enum {number} + */ + project.TriState = { + TRUE: 1, + FALSE: -1, + MAYBE: 0 + }; + +
@export + @export +

For example:

+ + /** @export */ + foo.MyPublicClass.prototype.myPublicMethod = function() { + // ... + }; + +
+

Given the code on the left, when the compiler is run with + the --generate_exports flag, it will generate the + code:

+ + goog.exportSymbol('foo.MyPublicClass.prototype.myPublicMethod', + foo.MyPublicClass.prototype.myPublicMethod); + +

which will export the symbols to uncompiled code. + Code that uses the @export annotation must either

+
    +
  1. include //javascript/closure/base.js, or
  2. +
  3. define both goog.exportSymbol and + goog.exportProperty with the same method + signature in their own codebase.
  4. +
+
@expose + @expose +

For example:

+ + /** @expose */ + MyClass.prototype.exposedProperty = 3; + +
+

+ Declares an exposed property. Exposed properties + will not be removed, or renamed, or collapsed, + or optimized in any way by the compiler. No properties + with the same name will be able to be optimized either. +

+ +

+ @expose should never be used in library code, + because it will prevent that property from ever getting + removed. +

+
@extends + + @extends Type
+ @extends {Type} +
+

For example:

+ + /** + * Immutable empty node list. + * @constructor + * @extends goog.ds.BasicNodeList + */ + goog.ds.EmptyNodeList = function() { + ... + }; + +
+ Used with @constructor to indicate that a class + inherits from another class. Curly braces around the type are + optional. +
@externs + @externs +

For example:

+ + /** + * @fileoverview This is an externs file. + * @externs + */ + + var document; + +
+

+ Declares an + + externs file. +

+ + +
@fileoverview + @fileoverview Description +

For example:

+ + /** + * @fileoverview Utilities for doing things that require this very long + * but not indented comment. + * @author kuth@google.com (Uthur Pendragon) + */ + +
Makes the comment block provide file level information.
@implements + + @implements Type
+ @implements {Type} +
+

For example:

+ + /** + * A shape. + * @interface + */ + function Shape() {}; + Shape.prototype.draw = function() {}; + + /** + * @constructor + * @implements {Shape} + */ + function Square() {}; + Square.prototype.draw = function() { + ... + }; + +
+ Used with @constructor to indicate that a class + implements an interface. Curly braces around the type are + optional. +
@inheritDoc + @inheritDoc +

For example:

+ + /** @inheritDoc */ + project.SubClass.prototype.toString() { + // ... + }; + +
+

Deprecated. Use + @override instead.

+ + Indicates that a method or property of a subclass + intentionally hides a method or property of the superclass, + and has exactly the same documentation. Notice that + @inheritDoc implies @override +
@interface + @interface +

For example:

+ + /** + * A shape. + * @interface + */ + function Shape() {}; + Shape.prototype.draw = function() {}; + + /** + * A polygon. + * @interface + * @extends {Shape} + */ + function Polygon() {}; + Polygon.prototype.getSides = function() {}; + +
+ Used to indicate that the function defines an interface. +
@lends + @lends objectName
+ @lends {objectName} +

For example:

+ + goog.object.extend( + Button.prototype, + /** @lends {Button.prototype} */ { + isButton: function() { return true; } + }); + +
+ Indicates that the keys of an object literal should + be treated as properties of some other object. This annotation + should only appear on object literals.

+ + Notice that the name in braces is not a type name like + in other annotations. It's an object name. It names + the object on which the properties are "lent". + For example, @type {Foo} means "an instance of Foo", + but @lends {Foo} means "the constructor Foo".

+ + The + JSDoc Toolkit docs have more information on this + annotation. +

@license or + @preserve + @license Description +

For example:

+ + /** + * @preserve Copyright 2009 SomeThirdParty. + * Here is the full license text and copyright + * notice for this file. Note that the notice can span several + * lines and is only terminated by the closing star and slash: + */ + +
+ Anything marked by @license or + @preserve will be retained by the compiler and + output at the top of the compiled code for that file. This + annotation allows important notices (such as legal licenses or + copyright text) to survive compilation unchanged. Line breaks + are preserved. +
@noalias + @noalias +

For example:

+ + /** @noalias */ + function Range() {} + +
+ Used in an externs file to indicate to the compiler that the + variable or function should not be aliased as part of the + alias externals pass of the compiler. +
@nocompile + @nocompile +

For example:

+ + /** @nocompile */ + + // JavaScript code + +
+ Used at the top of a file to tell the compiler to parse this + file but not compile it. + Code that is not meant for compilation and should be omitted + from compilation tests (such as bootstrap code) uses this + annotation. + Use sparingly. +
@nosideeffects + @nosideeffects +

For example:

+ + /** @nosideeffects */ + function noSideEffectsFn1() { + // ... + } + + /** @nosideeffects */ + var noSideEffectsFn2 = function() { + // ... + }; + + /** @nosideeffects */ + a.prototype.noSideEffectsFn3 = function() { + // ... + }; + +
+ This annotation can be used as part of function and + constructor declarations to indicate that calls to the + declared function have no side-effects. This annotation + allows the compiler to remove calls to these functions if the + return value is not used. +
@override + @override +

For example:

+ + /** + * @return {string} Human-readable representation of project.SubClass. + * @override + */ + project.SubClass.prototype.toString = function() { + // ... + }; + +
+ Indicates that a method or property of a subclass + intentionally hides a method or property of the superclass. If + no other documentation is included, the method or property + also inherits documentation from its superclass. +
@param + @param {Type} varname Description +

For example:

+ + /** + * Queries a Baz for items. + * @param {number} groupNum Subgroup id to query. + * @param {string|number|null} term An itemName, + * or itemId, or null to search everything. + */ + goog.Baz.prototype.query = function(groupNum, term) { + // ... + }; + +
+ Used with method, function and constructor calls to document + the arguments of a function.

+ + Type + names must be enclosed in curly braces. If the type + is omitted, the compiler will not type-check the parameter. +

@private + @private
+ @private {type} +

For example:

+ + /** + * Handlers that are listening to this logger. + * @private {!Array.<Function>} + */ + this.handlers_ = []; + +
+ Used in conjunction with a trailing underscore on the method + or property name to indicate that the member is + private and final. +
@protected + @protected
+ @protected {type} +

For example:

+ + /** + * Sets the component's root element to the given element. + * @param {Element} element Root element for the component. + * @protected + */ + goog.ui.Component.prototype.setElementInternal = function(element) { + // ... + }; + +
+ Used to indicate that the member or property is + protected. + Should be used in conjunction with names with no trailing + underscore. +
@public + @public
+ @public {type} +

For example:

+ + /** + * Whether to cancel the event in internal capture/bubble processing. + * @public {boolean} + * @suppress {visiblity} Referencing this outside this package is strongly + * discouraged. + */ + goog.events.Event.prototype.propagationStopped_ = false; + +
+ Used to indicate that the member or property is public. Variables and + properties are public by default, so this annotation is rarely necessary. + Should only be used in legacy code that cannot be easily changed to + override the visibility of members that were named as private variables. +
@return + @return {Type} Description +

For example:

+ + /** + * @return {string} The hex ID of the last item. + */ + goog.Baz.prototype.getLastId = function() { + // ... + return id; + }; + +
+ Used with method and function calls to document the return + type. When writing descriptions for boolean parameters, + prefer "Whether the component is visible" to "True if the + component is visible, false otherwise". If there is no return + value, do not use an @return tag.

+ + Type + names must be enclosed in curly braces. If the type + is omitted, the compiler will not type-check the return value. +

@see + @see Link +

For example:

+ + /** + * Adds a single item, recklessly. + * @see #addSafely + * @see goog.Collect + * @see goog.RecklessAdder#add + ... + +
Reference a lookup to another class function or method.
@struct + @struct Description +

For example:

+ + /** + * @constructor + * @struct + */ + function Foo(x) { + this.x = x; + } + var obj = new Foo(123); + var num = obj['x']; // warning + obj.y = "asdf"; // warning + + Foo.prototype = /** @struct */ { + method1: function() {} + }; + Foo.prototype.method2 = function() {}; // warning + +
+ When a constructor (Foo in the example) is + annotated with @struct, you can only use the dot + notation to access the properties of Foo objects. + Also, you cannot add new properties to Foo + objects after they have been created. + The annotation can also be used directly on object literals. +
@supported + @supported Description +

For example:

+ + /** + * @fileoverview Event Manager + * Provides an abstracted interface to the + * browsers' event systems. + * @supported So far tested in IE6 and FF1.5 + */ + +
+ Used in a fileoverview to indicate what browsers are supported + by the file. +
@suppress + + @suppress {warning1|warning2} + + + @suppress {warning1,warning2} + +

For example:

+ + /** + * @suppress {deprecated} + */ + function f() { + deprecatedVersionOfF(); + } + +
+ Suppresses warnings from tools. Warning categories are + separated by | or ,. + +
@template + @template +

For example:

+ + /** + * @param {function(this:T, ...)} fn + * @param {T} thisObj + * @param {...*} var_args + * @template T + */ + goog.bind = function(fn, thisObj, var_args) { + ... + }; + +
+ This annotation can be used to declare a + template typename. +
@this + + @this Type
+ @this {Type} +
+

For example:

+ + pinto.chat.RosterWidget.extern('getRosterElement', + /** + * Returns the roster widget element. + * @this pinto.chat.RosterWidget + * @return {Element} + */ + function() { + return this.getWrappedComponent_().getElement(); + }); + +
+ The type of the object in whose context a particular method is + called. Required when the this keyword is referenced + from a function that is not a prototype method. +
@type + + @type Type
+ @type {Type} +
+

For example:

+ + /** + * The message hex ID. + * @type {string} + */ + var hexId = hexId; + +
+ Identifies the type of a variable, + property, or expression. Curly braces are not required around + most types, but some projects mandate them for all types, for + consistency. +
@typedef + @typedef +

For example:

+ + /** @typedef {(string|number)} */ + goog.NumberLike; + + /** @param {goog.NumberLike} x A number or a string. */ + goog.readNumber = function(x) { + ... + } + +
+ This annotation can be used to declare an alias of a more + complex type. +
+ + + +

+ You may also see other types of JSDoc annotations in third-party + code. These annotations appear in the + + JSDoc Toolkit Tag Reference + + but are currently discouraged in Google code. You should consider + them "reserved" names for future use. These include: +

    +
  • @augments
  • +
  • @argument
  • +
  • @borrows
  • +
  • @class
  • +
  • @constant
  • +
  • @constructs
  • +
  • @default
  • +
  • @event
  • +
  • @example
  • +
  • @field
  • +
  • @function
  • +
  • @ignore
  • +
  • @inner
  • +
  • @link
  • +
  • @memberOf
  • +
  • @name
  • +
  • @namespace
  • +
  • @property
  • +
  • @public
  • +
  • @requires
  • +
  • @returns
  • +
  • @since
  • +
  • @static
  • +
  • @version
  • +
+

+
+ + + + + + Only provide top-level symbols. + + +

+ All members defined on a class should be in the same file. So, only + top-level classes should be provided in a file that contains multiple + members defined on the same class (e.g. enums, inner classes, etc). +

+

Do this:

+ + goog.provide('namespace.MyClass'); + +

Not this:

+ + goog.provide('namespace.MyClass'); + goog.provide('namespace.MyClass.Enum'); + goog.provide('namespace.MyClass.InnerClass'); + goog.provide('namespace.MyClass.TypeDef'); + goog.provide('namespace.MyClass.CONSTANT'); + goog.provide('namespace.MyClass.staticMethod'); + +

+ Members on namespaces may also be provided: +

+ + goog.provide('foo.bar'); + goog.provide('foo.bar.method'); + goog.provide('foo.bar.CONSTANT'); + + +
+ + + Required + + + +

Use of JS compilers such as the + Closure Compiler + is required for all customer-facing code.

+ + + + + +
+ + + JavaScript tidbits + + +

The following are all false in boolean expressions:

+
    +
  • null
  • +
  • undefined
  • +
  • '' the empty string
  • +
  • 0 the number
  • +
+

But be careful, because these are all true:

+
    +
  • '0' the string
  • +
  • [] the empty array
  • +
  • {} the empty object
  • +
+ +

This means that instead of this:

+ + while (x != null) { + +

you can write this shorter code (as long as you don't expect x to + be 0, or the empty string, or false):

+ + while (x) { + + +

And if you want to check a string to see if it is null or empty, + you could do this:

+ + if (y != null && y != '') { + +

But this is shorter and nicer:

+ + if (y) { + + +

Caution: There are many unintuitive things about + boolean expressions. Here are some of them:

+
    +
  • + Boolean('0') == true
    + '0' != true
  • +
  • + 0 != null
    + 0 == []
    + 0 == false
  • +
  • + Boolean(null) == false
    + null != true
    + null != false
  • +
  • + Boolean(undefined) == false
    + undefined != true
    + undefined != false
  • +
  • + Boolean([]) == true
    + [] != true
    + [] == false
  • +
  • + Boolean({}) == true
    + {} != true
    + {} != false
  • +
+
+ + +

Instead of this:

+ + if (val) { + return foo(); + } else { + return bar(); + } + +

you can write this:

+ + return val ? foo() : bar(); + + +

The ternary conditional is also useful when generating HTML:

+ + var html = '<input type="checkbox"' + + (isChecked ? ' checked' : '') + + (isEnabled ? '' : ' disabled') + + ' name="foo">'; + +
+ + +

These binary boolean operators are short-circuited, and evaluate + to the last evaluated term.

+ +

"||" has been called the 'default' operator, because instead of + writing this:

+ + /** @param {*=} opt_win */ + function foo(opt_win) { + var win; + if (opt_win) { + win = opt_win; + } else { + win = window; + } + // ... + } + +

you can write this:

+ + /** @param {*=} opt_win */ + function foo(opt_win) { + var win = opt_win || window; + // ... + } + + +

"&&" is also useful for shortening code. For instance, + instead of this:

+ + if (node) { + if (node.kids) { + if (node.kids[index]) { + foo(node.kids[index]); + } + } + } + + +

you could do this:

+ + if (node && node.kids && node.kids[index]) { + foo(node.kids[index]); + } + + +

or this:

+ + var kid = node && node.kids && node.kids[index]; + if (kid) { + foo(kid); + } + + +

However, this is going a little too far:

+ + node && node.kids && node.kids[index] && foo(node.kids[index]); + +
+ + +

Node lists are often implemented as node iterators with a filter. + This means that getting a property like length is O(n), and + iterating over the list by re-checking the length will be + O(n^2).

+ + var paragraphs = document.getElementsByTagName('p'); + for (var i = 0; i < paragraphs.length; i++) { + doSomething(paragraphs[i]); + } + + +

It is better to do this instead:

+ + var paragraphs = document.getElementsByTagName('p'); + for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) { + doSomething(paragraph); + } + + +

This works well for all collections and arrays as long as the array + does not contain things that are treated as boolean false.

+ +

In cases where you are iterating over the childNodes you can also + use the firstChild and nextSibling properties.

+ + var parentNode = document.getElementById('foo'); + for (var child = parentNode.firstChild; child; child = child.nextSibling) { + doSomething(child); + } + +
+ +
+
+ + + + +

+ BE CONSISTENT. +

+ +

+ If you're editing code, take a few minutes to look at the code + around you and determine its style. If they use spaces around + all their arithmetic operators, you should too. If their + comments have little boxes of hash marks around them, make your + comments have little boxes of hash marks around them too. +

+ +

+ The point of having style guidelines is to have a common vocabulary + of coding so people can concentrate on what you're saying rather + than on how you're saying it. We present global style rules here so + people know the vocabulary, but local style is also important. If + code you add to a file looks drastically different from the existing + code around it, it throws readers out of their rhythm when they go to + read it. Avoid this. +

+ +
+ +

+ Revision 2.93 +

+ + +
+ Aaron Whyte
+ Bob Jervis
+ Dan Pupius
+ Erik Arvidsson
+ Fritz Schneider
+ Robby Walker
+
+
diff --git a/jsguide.html b/jsguide.html new file mode 100644 index 000000000..c931a6950 --- /dev/null +++ b/jsguide.html @@ -0,0 +1,2816 @@ + + + + +Google JavaScript Style Guide + + + + + + +
+

Google JavaScript Style Guide

+

1 Introduction

+ +

This document serves as the complete definition of Google’s coding standards +for source code in the JavaScript programming language. A JavaScript source file +is described as being in Google Style if and only if it adheres to the rules +herein.

+ +

Like other programming style guides, the issues covered span not only aesthetic +issues of formatting, but other types of conventions or coding standards as +well. However, this document focuses primarily on the hard-and-fast rules that +we follow universally, and avoids giving advice that isn't clearly enforceable +(whether by human or tool).

+ +

1.1 Terminology notes

+ +

In this document, unless otherwise clarified:

+ +
    +
  1. The term comment always refers to implementation comments. We do not use +the phrase documentation comments, instead using the common term “JSDoc” +for both human-readable text and machine-readable annotations within +/** … */.

  2. +
  3. This Style Guide uses RFC 2119 terminology when using the phrases must, +must not, should, should not, and may. The terms prefer and +avoid correspond to should and should not, respectively. Imperative +and declarative statements are prescriptive and correspond to must.

  4. +
+ +

Other terminology notes will appear occasionally throughout the document.

+ +

1.2 Guide notes

+ +

Example code in this document is non-normative. That is, while the examples +are in Google Style, they may not illustrate the only stylish way to represent +the code. Optional formatting choices made in examples must not be enforced as +rules.

+ +

2 Source file basics

+ +

2.1 File name

+ +

File names must be all lowercase and may include underscores (_) or dashes +(-), but no additional punctuation. Follow the convention that your project +uses. Filenames’ extension must be .js.

+ +

2.2 File encoding: UTF-8

+ +

Source files are encoded in UTF-8.

+ +

2.3 Special characters

+ +

2.3.1 Whitespace characters

+ +

Aside from the line terminator sequence, the ASCII horizontal space character +(0x20) is the only whitespace character that appears anywhere in a source +file. This implies that

+ +
    +
  1. All other whitespace characters in string literals are escaped, and

  2. +
  3. Tab characters are not used for indentation.

  4. +
+ +

2.3.2 Special escape sequences

+ +

For any character that has a special escape sequence (\', \", \\, \b, +\f, \n, \r, \t, \v), that sequence is used rather than the +corresponding numeric escape (e.g \x0a, \u000a, or \u{a}). Legacy octal +escapes are never used.

+ +

2.3.3 Non-ASCII characters

+ +

For the remaining non-ASCII characters, either the actual Unicode character +(e.g. ) or the equivalent hex or Unicode escape (e.g. \u221e) is used, +depending only on which makes the code easier to read and understand.

+ +

Tip: In the Unicode escape case, and occasionally even when actual Unicode +characters are used, an explanatory comment can be very helpful.

+ + + + + + + + + + +
Example + Discussion +
const units = 'μs'; + Best: perfectly clear even without a comment. +
+ const units = '\u03bcs'; // 'μs' + + Allowed, but there’s no reason to do this. +
+ const units = '\u03bcs'; // Greek letter mu, 's' + + Allowed, but awkward and prone to mistakes. +
const units = '\u03bcs'; + Poor: the reader has no idea what this is. +
+ return '\ufeff' + content; // byte order mark + + + Good: use escapes for non-printable characters, and comment if + necessary. +
+ +

Tip: Never make your code less readable simply out of fear that some programs +might not handle non-ASCII characters properly. If that happens, those programs +are broken and they must be fixed.

+ +

3 Source file structure

+ +

A source file consists of, in order:

+ +
    +
  1. License or copyright information, if present
  2. +
  3. @fileoverview JSDoc, if present
  4. +
  5. goog.module statement
  6. +
  7. goog.require statements
  8. +
  9. The file’s implementation
  10. +
+ +

Exactly one blank line separates each section that is present, except the +file's implementation, which may be preceded by 1 or 2 blank lines.

+ + + +

If license or copyright information belongs in a file, it belongs here.

+ +

3.2 @fileoverview JSDoc, if present

+ +

See ?? for formatting rules.

+ +

3.3 goog.module statement

+ +

All files must declare exactly one goog.module name on a single line: lines +containing a goog.module declaration must not be wrapped, and are therefore an +exception to the 80-column limit.

+ +

The entire argument to goog.module is what defines a namespace. It is the +package name (an identifier that reflects the fragment of the directory +structure where the code lives) plus, optionally, the main class/enum/interface +that it defines concatenated to the end.

+ +

Example

+ +
goog.module('search.urlHistory.UrlHistoryService');
+
+ +

3.3.1 Hierarchy

+ +

Module namespaces may never be named as a direct child of another module's +namespace.

+ +

Illegal:

+ +
goog.module('foo.bar');   // 'foo.bar.qux' would be fine, though
+goog.module('foo.bar.baz');
+
+ +

The directory hierarchy reflects the namespace hierarchy, so that deeper-nested +children are subdirectories of higher-level parent directories. Note that this +implies that owners of “parent” namespace groups are necessarily aware of all +child namespaces, since they exist in the same directory.

+ +

3.3.2 goog.setTestOnly

+ +

The single goog.module statement may optionally be followed by a call to +goog.setTestOnly().

+ +

3.3.3 goog.module.declareLegacyNamespace

+ +

The single goog.module statement may optionally be followed by a call to +goog.module.declareLegacyNamespace();. Avoid +goog.module.declareLegacyNamespace() when possible.

+ +

Example:

+ +
goog.module('my.test.helpers');
+goog.module.declareLegacyNamespace();
+goog.setTestOnly();
+
+ +

goog.module.declareLegacyNamespace exists to ease the transition from +traditional object hierarchy-based namespaces but comes with some naming +restrictions. As the child module name must be created after the parent +namespace, this name must not be a child or parent of any other +goog.module (for example, goog.module('parent'); and +goog.module('parent.child'); cannot both exist safely, nor can +goog.module('parent'); and goog.module('parent.child.grandchild');).

+ +

3.3.4 ES6 Modules

+ +

Do not use ES6 modules yet (i.e. the export and import keywords), as their +semantics are not yet finalized. Note that this policy will be revisited once +the semantics are fully-standard.

+ +

3.4 goog.require statements

+ +

Imports are done with goog.require statements, grouped together immediately +following the module declaration. Each goog.require is assigned to a single +constant alias, or else destructured into several constant aliases. These +aliases are the only acceptable way to refer to the required dependency, +whether in code or in type annotations: the fully qualified name is never used +except as the argument to goog.require. Alias names should match the final +dot-separated component of the imported module name when possible, though +additional components may be included (with appropriate casing such that the +alias' casing still correctly identifies its type) if necessary to +disambiguate, or if it significantly improves readability. goog.require +statements may not appear anywhere else in the file.

+ +

If a module is imported only for its side effects, the assignment may be +omitted, but the fully qualified name may not appear anywhere else in the file. +A comment is required to explain why this is needed and suppress a compiler +warning.

+ + + +

The lines are sorted according to the following rules: All requires with a name +on the left hand side come first, sorted alphabetically by those names. Then +destructuring requires, again sorted by the names on the left hand side. +Finally, any goog.require calls that are standalone (generally these are for +modules imported just for their side effects).

+ +

Tip: There’s no need to memorize this order and enforce it manually. You can +rely on your IDE to report requires +that are not sorted correctly.

+ +

If a long alias or module name would cause a line to exceed the 80-column limit, +it must not be wrapped: goog.require lines are an exception to the 80-column +limit.

+ +

Example:

+ +
const MyClass = goog.require('some.package.MyClass');
+const NsMyClass = goog.require('other.ns.MyClass');
+const googAsserts = goog.require('goog.asserts');
+const testingAsserts = goog.require('goog.testing.asserts');
+const than80columns = goog.require('pretend.this.is.longer.than80columns');
+const {clear, forEach, map} = goog.require('goog.array');
+/** @suppress {extraRequire} Initializes MyFramework. */
+goog.require('my.framework.initialization');
+
+ +

Illegal:

+ +
const randomName = goog.require('something.else'); // name must match
+
+const {clear, forEach, map} = // don't break lines
+    goog.require('goog.array');
+
+function someFunction() {
+  const alias = goog.require('my.long.name.alias'); // must be at top level
+  // …
+}
+
+ +

3.4.1 goog.forwardDeclare

+ +

goog.forwardDeclare is not needed very often, but is a valuable tool to break +circular dependencies or to reference late loaded code. These statements are +grouped together and immediately follow any goog.require statements. A +goog.forwardDeclare statement must follow the same style rules as a +goog.require statement.

+ +

3.5 The file’s implementation

+ +

The actual implementation follows after all dependency information is declared +(separated by at least one blank line).

+ +

This may consist of any module-local declarations (constants, variables, +classes, functions, etc), as well as any exported symbols. +

+ +

4 Formatting

+ +

Terminology Note: block-like construct refers to the body of a class, +function, method, or brace-delimited block of code. Note that, by +?? and ??, any array or +object literal may optionally be treated as if it were a block-like construct.

+ +

Tip: Use clang-format. The JavaScript community has invested effort to make +sure clang-format does the right thing on JavaScript files. clang-format has +integration with several popular +editors.

+ +

4.1 Braces

+ +

4.1.1 Braces are used for all control structures

+ +

Braces are required for all control structures (i.e. if, else, for, do, +while, as well as any others), even if the body contains only a single +statement. The first statement of a non-empty block must begin on its own line.

+ +

Illegal:

+ +
if (someVeryLongCondition())
+  doSomething();
+
+for (let i = 0; i < foo.length; i++) bar(foo[i]);
+
+ +

Exception: A simple if statement that can fit entirely on a single line with +no wrapping (and that doesn’t have an else) may be kept on a single line with no +braces when it improves readability. This is the only case in which a control +structure may omit braces and newlines.

+ +
if (shortCondition()) return;
+
+ +

4.1.2 Nonempty blocks: K&R style

+ +

Braces follow the Kernighan and Ritchie style (Egyptian brackets) for +nonempty blocks and block-like constructs:

+ +
    +
  • No line break before the opening brace.
  • +
  • Line break after the opening brace.
  • +
  • Line break before the closing brace.
  • +
  • Line break after the closing brace if that brace terminates a statement or +the body of a function or class statement, or a class method. Specifically, +there is no line break after the brace if it is followed by else, catch, +while, or a comma, semicolon, or right-parenthesis.
  • +
+ +

Example:

+ +
class InnerClass {
+  constructor() {}
+
+  /** @param {number} foo */
+  method(foo) {
+    if (condition(foo)) {
+      try {
+        // Note: this might fail.
+        something();
+      } catch (err) {
+        recover();
+      }
+    }
+  }
+}
+
+ +

4.1.3 Empty blocks: may be concise

+ +

An empty block or block-like construct may be closed immediately after it is +opened, with no characters, space, or line break in between (i.e. {}), +unless it is a part of a multi-block statement (one that directly contains +multiple blocks: if/else or try/catch/finally).

+ +

Example:

+ +
function doNothing() {}
+
+ +

Illegal:

+ +
if (condition) {
+  // …
+} else if (otherCondition) {} else {
+  // …
+}
+
+try {
+  // …
+} catch (e) {}
+
+ +

4.2 Block indentation: +2 spaces

+ +

Each time a new block or block-like construct is opened, the indent increases by +two spaces. When the block ends, the indent returns to the previous indent +level. The indent level applies to both code and comments throughout the +block. (See the example in ??).

+ +

4.2.1 Array literals: optionally block-like

+ +

Any array literal may optionally be formatted as if it were a “block-like +construct.” For example, the following are all valid (not an exhaustive +list):

+ +
const a = [
+  0,
+  1,
+  2,
+];
+
+const b =
+    [0, 1, 2];
+
+
+ +
const c = [0, 1, 2];
+
+someMethod(foo, [
+  0, 1, 2,
+], bar);
+
+ +

Other combinations are allowed, particularly when emphasizing semantic groupings +between elements, but should not be used only to reduce the vertical size of +larger arrays.

+ +

4.2.2 Object literals: optionally block-like

+ +

Any object literal may optionally be formatted as if it were a “block-like +construct.” The same examples apply as ??. For +example, the following are all valid (not an exhaustive list):

+ +
const a = {
+  a: 0,
+  b: 1,
+};
+
+const b =
+    {a: 0, b: 1};
+
+ +
const c = {a: 0, b: 1};
+
+someMethod(foo, {
+  a: 0, b: 1,
+}, bar);
+
+ +

4.2.3 Class literals

+ +

Class literals (whether declarations or expressions) are indented as blocks. Do +not add semicolons after methods, or after the closing brace of a class +declaration (statements—such as assignments—that contain class expressions +are still terminated with a semicolon). Use the extends keyword, but not the +@extends JSDoc annotation unless the class extends a templatized type.

+ +

Example:

+ +
class Foo {
+  constructor() {
+    /** @type {number} */
+    this.x = 42;
+  }
+
+  /** @return {number} */
+  method() {
+    return this.x;
+  }
+}
+Foo.Empty = class {};
+
+ +
/** @extends {Foo<string>} */
+foo.Bar = class extends Foo {
+  /** @override */
+  method() {
+    return super.method() / 2;
+  }
+};
+
+/** @interface */
+class Frobnicator {
+  /** @param {string} message */
+  frobnicate(message) {}
+}
+
+ +

4.2.4 Function expressions

+ +

When declaring an anonymous function in the list of arguments for a function +call, the body of the function is indented two spaces more than the preceding +indentation depth.

+ +

Example:

+ +
prefix.something.reallyLongFunctionName('whatever', (a1, a2) => {
+  // Indent the function body +2 relative to indentation depth
+  // of the 'prefix' statement one line above.
+  if (a1.equals(a2)) {
+    someOtherLongFunctionName(a1);
+  } else {
+    andNowForSomethingCompletelyDifferent(a2.parrot);
+  }
+});
+
+some.reallyLongFunctionCall(arg1, arg2, arg3)
+    .thatsWrapped()
+    .then((result) => {
+      // Indent the function body +2 relative to the indentation depth
+      // of the '.then()' call.
+      if (result) {
+        result.use();
+      }
+    });
+
+ +

4.2.5 Switch statements

+ +

As with any other block, the contents of a switch block are indented +2.

+ + + +

After a switch label, a newline appears, and the indentation level is increased ++2, exactly as if a block were being opened. An explicit block may be used if +required by lexical scoping. The following switch label returns to the previous +indentation level, as if a block had been closed.

+ +

A blank line is optional between a break and the following case.

+ +

Example:

+ +
switch (animal) {
+  case Animal.BANDERSNATCH:
+    handleBandersnatch();
+    break;
+
+  case Animal.JABBERWOCK:
+    handleJabberwock();
+    break;
+
+  default:
+    throw new Error('Unknown animal');
+}
+
+ +

4.3 Statements

+ +

4.3.1 One statement per line

+ +

Each statement is followed by a line-break.

+ +

4.3.2 Semicolons are required

+ +

Every statement must be terminated with a semicolon. Relying on automatic +semicolon insertion is forbidden.

+ +

4.4 Column limit: 80

+ +

JavaScript code has a column limit of 80 characters. Except as noted below, any +line that would exceed this limit must be line-wrapped, as explained in +??.

+ +

Exceptions:

+ +
    +
  1. Lines where obeying the column limit is not possible (for example, a long URL +in JSDoc or a shell command intended to be copied-and-pasted).
  2. +
  3. goog.module and goog.require statements (see ?? and +??).
  4. +
+ +

4.5 Line-wrapping

+ +

Terminology Note: Line-wrapping is defined as breaking a single expression +into multiple lines.

+ +

There is no comprehensive, deterministic formula showing exactly how to +line-wrap in every situation. Very often there are several valid ways to +line-wrap the same piece of code.

+ +

Note: While the typical reason for line-wrapping is to avoid overflowing the +column limit, even code that would in fact fit within the column limit may be +line-wrapped at the author's discretion.

+ +

Tip: Extracting a method or local variable may solve the problem without the +need to line-wrap.

+ +

4.5.1 Where to break

+ +

The prime directive of line-wrapping is: prefer to break at a higher syntactic +level.

+ +

Preferred:

+ +
currentEstimate =
+    calc(currentEstimate + x * currentEstimate) /
+        2.0f;
+
+ +

Discouraged:

+ +
currentEstimate = calc(currentEstimate + x *
+    currentEstimate) / 2.0f;
+
+ +

In the preceding example, the syntactic levels from highest to lowest are as +follows: assignment, division, function call, parameters, number constant.

+ +

Operators are wrapped as follows:

+ +
    +
  1. When a line is broken at an operator the break comes after the symbol. (Note +that this is not the same practice used in Google style for Java.) +
      +
    1. This does not apply to the dot (.), which is not actually an +operator.
    2. +
  2. +
  3. A method or constructor name stays attached to the open parenthesis (() +that follows it.
  4. +
  5. A comma (,) stays attached to the token that precedes it.
  6. +
+ +
+

Note: The primary goal for line wrapping is to have clear code, not +necessarily code that fits in the smallest number of lines.

+
+ +

4.5.2 Indent continuation lines at least +4 spaces

+ +

When line-wrapping, each line after the first (each continuation line) is +indented at least +4 from the original line, unless it falls under the rules of +block indentation.

+ +

When there are multiple continuation lines, indentation may be varied beyond +4 +as appropriate. In general, continuation lines at a deeper syntactic level are +indented by larger multiples of 4, and two lines use the same indentation level +if and only if they begin with syntactically parallel elements.

+ +

?? addresses the discouraged practice of +using a variable number of spaces to align certain tokens with previous lines.

+ +

4.6 Whitespace

+ +

4.6.1 Vertical whitespace

+ +

A single blank line appears:

+ +
    +
  1. Between consecutive methods in a class or object literal +
      +
    1. Exception: A blank line between two consecutive properties definitions in +an object literal (with no other code between them) is optional. Such +blank lines are used as needed to create logical groupings of fields.
    2. +
  2. +
  3. Within method bodies, sparingly to create logical groupings of statements. +Blank lines at the start or end of a function body are not allowed.
  4. +
  5. Optionally before the first or after the last method in a class or object +literal (neither encouraged nor discouraged).
  6. +
  7. As required by other sections of this document (e.g. +??).
  8. +
+ +

Multiple consecutive blank lines are permitted, but never required (nor +encouraged).

+ +

4.6.2 Horizontal whitespace

+ +

Use of horizontal whitespace depends on location, and falls into three broad +categories: leading (at the start of a line), trailing (at the end of a +line), and internal. Leading whitespace (i.e., indentation) is addressed +elsewhere. Trailing whitespace is forbidden.

+ +

Beyond where required by the language or other style rules, and apart from +literals, comments, and JSDoc, a single internal ASCII space also appears in the +following places only.

+ +
    +
  1. Separating any reserved word (such as if, for, or catch) from an open +parenthesis (() that follows it on that line.
  2. +
  3. Separating any reserved word (such as else or catch) from a closing +curly brace (}) that precedes it on that line.
  4. +
  5. Before any open curly brace ({), with two exceptions: +
      +
    1. Before an object literal that is the first argument of a function or the +first element in an array literal (e.g. foo({a: [{c: d}]})).
    2. +
    3. In a template expansion, as it is forbidden by the language +(e.g. abc${1 + 2}def).
    4. +
  6. +
  7. On both sides of any binary or ternary operator.
  8. +
  9. After a comma (,) or semicolon (;). Note that spaces are never allowed +before these characters.
  10. +
  11. After the colon (:) in an object literal.
  12. +
  13. On both sides of the double slash (//) that begins an end-of-line +comment. Here, multiple spaces are allowed, but not required.
  14. +
  15. After an open-JSDoc comment character and on both sides of close characters +(e.g. for short-form type declarations or casts: this.foo = /** @type +{number} */ (bar); or function(/** string */ foo) {).
  16. +
+ +

4.6.3 Horizontal alignment: discouraged

+ +

Terminology Note: Horizontal alignment is the practice of adding a +variable number of additional spaces in your code with the goal of making +certain tokens appear directly below certain other tokens on previous lines.

+ +

This practice is permitted, but it is generally discouraged by Google +Style. It is not even required to maintain horizontal alignment in places +where it was already used.

+ +

Here is an example without alignment, followed by one with alignment. Both are +allowed, but the latter is discouraged:

+ +
{
+  tiny: 42, // this is great
+  longer: 435, // this too
+};
+
+{
+  tiny:   42,  // permitted, but future edits
+  longer: 435, // may leave it unaligned
+};
+
+ +

Tip: Alignment can aid readability, but it creates problems for future +maintenance. Consider a future change that needs to touch just one line. This +change may leave the formerly-pleasing formatting mangled, and that is +allowed. More often it prompts the coder (perhaps you) to adjust whitespace on +nearby lines as well, possibly triggering a cascading series of +reformattings. That one-line change now has a blast radius. This can at worst +result in pointless busywork, but at best it still corrupts version history +information, slows down reviewers and exacerbates merge conflicts.

+ +

4.6.4 Function arguments

+ +

Prefer to put all function arguments on the same line as the function name. If doing so would exceed the 80-column limit, the arguments must be line-wrapped in a readable way. To save space, you may wrap as close to 80 as possible, or put each argument on its own line to enhance readability. Indentation should be four spaces. Aligning to the parenthesis is allowed, but discouraged. Below are the most common patterns for argument wrapping:

+ +
// Arguments start on a new line, indented four spaces. Preferred when the
+// arguments don't fit on the same line with the function name (or the keyword
+// "function") but fit entirely on the second line. Works with very long
+// function names, survives renaming without reindenting, low on space.
+doSomething(
+    descriptiveArgumentOne, descriptiveArgumentTwo, descriptiveArgumentThree) {
+  // …
+}
+
+// If the argument list is longer, wrap at 80. Uses less vertical space,
+// but violates the rectangle rule and is thus not recommended.
+doSomething(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo,
+    tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) {
+  // …
+}
+
+// Four-space, one argument per line.  Works with long function names,
+// survives renaming, and emphasizes each argument.
+doSomething(
+    veryDescriptiveArgumentNumberOne,
+    veryDescriptiveArgumentTwo,
+    tableModelEventHandlerProxy,
+    artichokeDescriptorAdapterIterator) {
+  // …
+}
+
+ +

4.7 Grouping parentheses: recommended

+ +

Optional grouping parentheses are omitted only when the author and reviewer +agree that there is no reasonable chance that the code will be misinterpreted +without them, nor would they have made the code easier to read. It is not +reasonable to assume that every reader has the entire operator precedence table +memorized.

+ +

Do not use unnecessary parentheses around the entire expression following +delete, typeof, void, return, throw, case, in, of, or yield.

+ +

Parentheses are required for type casts: /** @type {!Foo} */ (foo).

+ +

4.8 Comments

+ +

This section addresses implementation comments. JSDoc is addressed separately +in ??.

+ +

4.8.1 Block comment style

+ +

Block comments are indented at the same level as the surrounding code. They may +be in /* … */ or //-style. For multi-line /* … */ comments, subsequent +lines must start with * aligned with the * on the previous line, to make +comments obvious with no extra context. “Parameter name” comments should appear +after values whenever the value and method name do not sufficiently convey the +meaning.

+ +
/*
+ * This is
+ * okay.
+ */
+
+// And so
+// is this.
+
+/* This is fine, too. */
+
+someFunction(obviousParam, true /* shouldRender */, 'hello' /* name */);
+
+ +

Comments are not enclosed in boxes drawn with asterisks or other characters.

+ +

Do not use JSDoc (/** … */) for any of the above implementation comments.

+ +

5 Language features

+ +

JavaScript includes many dubious (and even dangerous) features. This section +delineates which features may or may not be used, and any additional constraints +on their use.

+ +

5.1 Local variable declarations

+ +

5.1.1 Use const and let

+ +

Declare all local variables with either const or let. Use const by default, +unless a variable needs to be reassigned. The var +keyword must not be used.

+ +

5.1.2 One variable per declaration

+ +

Every local variable declaration declares only one variable: declarations such +as let a = 1, b = 2; are not used.

+ +

5.1.3 Declared when needed, initialized as soon as possible

+ +

Local variables are not habitually declared at the start of their containing +block or block-like construct. Instead, local variables are declared close to +the point they are first used (within reason), to minimize their scope.

+ +

5.1.4 Declare types as needed

+ +

JSDoc type annotations may be added either on the line above the declaration, or +else inline before the variable name.

+ +

Example:

+ +
const /** !Array<number> */ data = [];
+
+/** @type {!Array<number>} */
+const data = [];
+
+ +

Tip: There are many cases where the compiler can infer a templatized type but +not its parameters. This is particularly the case when the initializing literal +or constructor call does not include any values of the template parameter type +(e.g., empty arrays, objects, Maps, or Sets), or if the variable is modified +in a closure. Local variable type annotations are particularly helpful in these +cases since otherwise the compiler will infer the template parameter as unknown.

+ +

5.2 Array literals

+ +

5.2.1 Use trailing commas

+ + + +

Include a trailing comma whenever there is a line break between the final +element and the closing bracket.

+ +

Example:

+ +
const values = [
+  'first value',
+  'second value',
+];
+
+ +

5.2.2 Do not use the variadic Array constructor

+ +

The constructor is error-prone if arguments are added or removed. Use a literal +instead.

+ +

Illegal:

+ +
const a1 = new Array(x1, x2, x3);
+const a2 = new Array(x1, x2);
+const a3 = new Array(x1);
+const a4 = new Array();
+
+ +

This works as expected except for the third case: if x1 is a whole number then +a3 is an array of size x1 where all elements are undefined. If x1 is any +other number, then an exception will be thrown, and if it is anything else then +it will be a single-element array.

+ +

Instead, write

+ +
const a1 = [x1, x2, x3];
+const a2 = [x1, x2];
+const a3 = [x1];
+const a4 = [];
+
+ +

Explicitly allocating an array of a given length using new Array(length) is +allowed when appropriate.

+ +

5.2.3 Non-numeric properties

+ +

Do not define or use non-numeric properties on an array (other than +length). Use a Map (or Object) instead.

+ +

5.2.4 Destructuring

+ +

Array literals may be used on the left-hand side of an assignment to perform +destructuring (such as when unpacking multiple values from a single array or +iterable). A final rest element may be included (with no space between the +... and the variable name). Elements should be omitted if they are unused.

+ +
const [a, b, c, ...rest] = generateResults();
+let [, b,, d] = someArray;
+
+ +

Destructuring may also be used for function parameters (note that a parameter +name is required but ignored). Always specify [] as the default value if a +destructured array parameter is optional, and provide default values on the left +hand side:

+ +
/** @param {!Array<number>=} param1 */
+function optionalDestructuring([a = 4, b = 2] = []) { … };
+
+ +

Illegal:

+ +
function badDestructuring([a, b] = [4, 2]) { … };
+
+ +

Tip: For (un)packing multiple values into a function’s parameter or return, +prefer object destructuring to array destructuring when possible, as it allows +naming the individual elements and specifying a different type for each.*

+ +

5.2.5 Spread operator

+ +

Array literals may include the spread operator (...) to flatten elements out +of one or more other iterables. The spread operator should be used instead of +more awkward constructs with Array.prototype. There is no space after the +....

+ +

Example:

+ +
[...foo]   // preferred over Array.prototype.slice.call(foo)
+[...foo, ...bar]   // preferred over foo.concat(bar)
+
+ +

5.3 Object literals

+ +

5.3.1 Use trailing commas

+ +

Include a trailing comma whenever there is a line break between the final +property and the closing brace.

+ +

5.3.2 Do not use the Object constructor

+ +

While Object does not have the same problems as Array, it is still +disallowed for consistency. Use an object literal ({} or {a: 0, b: 1, c: 2}) +instead.

+ +

5.3.3 Do not mix quoted and unquoted keys

+ +

Object literals may represent either structs (with unquoted keys and/or +symbols) or dicts (with quoted and/or computed keys). Do not mix these key +types in a single object literal.

+ +

Illegal:

+ +
{
+  a: 42, // struct-style unquoted key
+  'b': 43, // dict-style quoted key
+}
+
+ +

5.3.4 Computed property names

+ +

Computed property names (e.g., {['key' + foo()]: 42}) are allowed, and are +considered dict-style (quoted) keys (i.e., must not be mixed with non-quoted +keys) unless the computed property is a symbol (e.g., [Symbol.iterator]). +Enum values may also be used for computed keys, but should not be mixed with +non-enum keys in the same literal.

+ +

5.3.5 Method shorthand

+ +

Methods can be defined on object literals using the method shorthand ({method() +{… }}) in place of a colon immediately followed by a function or arrow +function literal.

+ +

Example:

+ +
return {
+  stuff: 'candy',
+  method() {
+    return this.stuff;  // Returns 'candy'
+  },
+};
+
+ +

Note that this in a method shorthand or function refers to the object +literal itself whereas this in an arrow function refers to the scope outside +the object literal.

+ +

Example:

+ +
class {
+  getObjectLiteral() {
+    this.stuff = 'fruit';
+    return {
+      stuff: 'candy',
+      method: () => this.stuff,  // Returns 'fruit'
+    };
+  }
+}
+
+ +

5.3.6 Shorthand properties

+ +

Shorthand properties are allowed on object literals.

+ +

Example:

+ +
const foo = 1;
+const bar = 2;
+const obj = {
+  foo,
+  bar,
+  method() { return this.foo + this.bar; },
+};
+assertEquals(3, obj.method());
+
+ +

5.3.7 Destructuring

+ +

Object destructuring patterns may be used on the left-hand side of an assignment +to perform destructuring and unpack multiple values from a single object.

+ +

Destructured objects may also be used as function parameters, but should be kept +as simple as possible: a single level of unquoted shorthand properties. Deeper +levels of nesting and computed properties may not be used in parameter +destructuring. Specify any default values in the left-hand-side of the +destructured parameter ({str = 'some default'} = {}, rather than {str} = {str: 'some default'}), and if a destructured +object is itself optional, it must default to {}. The JSDoc for the +destructured parameter may be given any name (the name is unused but is required +by the compiler).

+ +

Example:

+ +
/**
+ * @param {string} ordinary
+ * @param {{num: (number|undefined), str: (string|undefined)}=} param1
+ *     num: The number of times to do something.
+ *     str: A string to do stuff to.
+ */
+function destructured(ordinary, {num, str = 'some default'} = {})
+
+ +

Illegal:

+ +
/** @param {{x: {num: (number|undefined), str: (string|undefined)}}} param1 */
+function nestedTooDeeply({x: {num, str}}) {};
+/** @param {{num: (number|undefined), str: (string|undefined)}=} param1 */
+function nonShorthandProperty({num: a, str: b} = {}) {};
+/** @param {{a: number, b: number}} param1 */
+function computedKey({a, b, [a + b]: c}) {};
+/** @param {{a: number, b: string}=} param1 */
+function nontrivialDefault({a, b} = {a: 2, b: 4}) {};
+
+ +

Destructuring may also be used for goog.require statements, and in this case +must not be wrapped: the entire statement occupies one line, regardless of how +long it is (see ??).

+ +

5.3.8 Enums

+ +

Enumerations are defined by adding the @enum annotation to an object literal. +Additional properties may not be added to an enum after it is defined. Enums +must be constant, and all enum values must be deeply immutable.

+ +
/**
+ * Supported temperature scales.
+ * @enum {string}
+ */
+const TemperatureScale = {
+  CELSIUS: 'celsius',
+  FAHRENHEIT: 'fahrenheit',
+};
+
+/**
+ * An enum with two options.
+ * @enum {number}
+ */
+const Option = {
+  /** The option used shall have been the first. */
+  FIRST_OPTION: 1,
+  /** The second among two options. */
+  SECOND_OPTION: 2,
+};
+
+ +

5.4 Classes

+ +

5.4.1 Constructors

+ +

Constructors are optional for concrete classes. Subclass constructors must call +super() before setting any fields or otherwise accessing this. Interfaces +must not define a constructor.

+ +

5.4.2 Fields

+ +

Set all of a concrete object’s fields (i.e. all properties other than methods) +in the constructor. Annotate fields that are never reassigned with @const +(these need not be deeply immutable). Private fields must be annotated with +@private and their names must end with a trailing underscore. Fields are never +set on a concrete class' prototype.

+ +

Example:

+ +
class Foo {
+  constructor() {
+    /** @private @const {!Bar} */
+    this.bar_ = computeBar();
+  }
+}
+
+ +

Tip: Properties should never be added to or removed from an instance after the +constructor is finished, since it significantly hinders VMs’ ability to +optimize. If necessary, fields that are initialized later should be explicitly +set to undefined in the constructor to prevent later shape changes. Adding +@struct to an object will check that undeclared properties are not +added/accessed. Classes have this added by default.

+ +

5.4.3 Computed properties

+ + + +

Computed properties may only be used in classes when the property is a +symbol. Dict-style properties (that is, quoted or computed non-symbol keys, as +defined in ??) are not allowed. A +[Symbol.iterator] method should be defined for any classes that are logically +iterable. Beyond this, Symbol should be used sparingly.

+ +

Tip: be careful of using any other built-in symbols (e.g., Symbol.isConcatSpreadable) as they are not polyfilled by the compiler and will therefore not work in older browsers.

+ +

5.4.4 Static methods

+ + + +

Where it does not interfere with readability, prefer module-local functions over +private static methods.

+ +

Static methods should only be called on the base class itself. Static methods +should not be called on variables containing a dynamic instance that may be +either the constructor or a subclass constructor (and must be defined with +@nocollapse if this is done), and must not be called directly on a subclass +that doesn’t define the method itself.

+ +

Illegal:

+ +
class Base { /** @nocollapse */ static foo() {} }
+class Sub extends Base {}
+function callFoo(cls) { cls.foo(); }  // discouraged: don't call static methods dynamically
+Sub.foo();  // illegal: don't call static methods on subclasses that don't define it themselves
+
+ +

5.4.5 Old-style class declarations

+ +

While ES6 classes are preferred, there are cases where ES6 classes may not be +feasible. For example:

+ +
    +
  1. If there exist or will exist subclasses, including frameworks that create +subclasses, that cannot be immediately changed to use ES6 class syntax. If +such a class were to use ES6 syntax, all downstream subclasses not using ES6 +class syntax would need to be modified.

  2. +
  3. Frameworks that require a known this value before calling the superclass +constructor, since constructors with ES6 super classes do not have +access to the instance this value until the call to super returns.

  4. +
+ +

In all other ways the style guide still applies to this code: let, const, +default parameters, rest, and arrow functions should all be used when +appropriate.

+ +

goog.defineClass allows for a class-like definition similar to ES6 class +syntax:

+ +
let C = goog.defineClass(S, {
+  /**
+   * @param {string} value
+   */
+  constructor(value) {
+    S.call(this, 2);
+    /** @const */
+    this.prop = value;
+  },
+
+  /**
+   * @param {string} param
+   * @return {number}
+   */
+  method(param) {
+    return 0;
+  },
+});
+
+ +

Alternatively, while goog.defineClass should be preferred for all new code, +more traditional syntax is also allowed.

+ +
/**
+  * @constructor @extends {S}
+  * @param {string} value
+  */
+function C(value) {
+  S.call(this, 2);
+  /** @const */
+  this.prop = value;
+}
+goog.inherits(C, S);
+
+/**
+ * @param {string} param
+ * @return {number}
+ */
+C.prototype.method = function(param) {
+  return 0;
+};
+
+ +

Per-instance properties should be defined in the constructor after the call to the super class constructor, if there is a super class. Methods should be defined on the prototype of the constructor.

+ +

Defining constructor prototype hierarchies correctly is harder than it first appears! For that reason, it is best to use goog.inherits from the Closure Library .

+ +

5.4.6 Do not manipulate prototypes directly

+ +

The class keyword allows clearer and more readable class definitions than +defining prototype properties. Ordinary implementation code has no business +manipulating these objects, though they are still useful for defining @record +interfaces and classes as defined in ??. Mixins +and modifying the prototypes of builtin objects are +explicitly forbidden.

+ +

Exception: Framework code (such as Polymer, or Angular) may need to use prototypes, and should not +resort to even-worse workarounds to avoid doing so.

+ +

Exception: Defining fields in interfaces (see ??).

+ +

5.4.7 Getters and Setters

+ +

Do not use JavaScript getter and setter properties. They are potentially +surprising and difficult to reason about, and have limited support in the +compiler. Provide ordinary methods instead.

+ +

Exception: when working with data binding frameworks (such as Angular and +Polymer), getters and setters may be used sparingly. Note, however, that +compiler support is limited. When they are used, they must be defined either +with get foo() and set foo(value) in the class or object literal, or if that +is not possible, with Object.defineProperties. Do not use +Object.defineProperty, which interferes with property renaming. Getters +must not change observable state.

+ +

Illegal:

+ +
class Foo {
+  get next() { return this.nextId++; }
+}
+
+ +

5.4.8 Overriding toString

+ +

The toString method may be overridden, but must always succeed and never have +visible side effects.

+ +

Tip: Beware, in particular, of calling other methods from toString, since +exceptional conditions could lead to infinite loops.

+ +

5.4.9 Interfaces

+ +

Interfaces may be declared with @interface or @record. Interfaces declared +with @record can be explicitly (i.e. via @implements) or implicitly +implemented by a class or object literal.

+ +

All non-static method bodies on an interface must be empty blocks. Fields must +be defined after the interface body as stubs on the prototype.

+ +

Example:

+ +
/**
+ * Something that can frobnicate.
+ * @record
+ */
+class Frobnicator {
+  /**
+   * Performs the frobnication according to the given strategy.
+   * @param {!FrobnicationStrategy} strategy
+   */
+  frobnicate(strategy) {}
+}
+
+/** @type {number} The number of attempts before giving up. */
+Frobnicator.prototype.attempts;
+
+ +

5.5 Functions

+ +

5.5.1 Top-level functions

+ +

Exported functions may be defined directly on the exports object, or else +declared locally and exported separately. Non-exported functions are encouraged +and should not be declared @private.

+ +

Examples:

+ +
/** @return {number} */
+function helperFunction() {
+  return 42;
+}
+/** @return {number} */
+function exportedFunction() {
+  return helperFunction() * 2;
+}
+/**
+ * @param {string} arg
+ * @return {number}
+ */
+function anotherExportedFunction(arg) {
+  return helperFunction() / arg.length;
+}
+/** @const */
+exports = {exportedFunction, anotherExportedFunction};
+
+ +
/** @param {string} arg */
+exports.foo = (arg) => {
+  // do some stuff ...
+};
+
+ +

5.5.2 Nested functions and closures

+ +

Functions may contain nested function definitions. If it is useful to give the +function a name, it should be assigned to a local const.

+ +

5.5.3 Arrow functions

+ +

Arrow functions provide a concise syntax and fix a number of difficulties with +this. Prefer arrow functions over the function keyword, particularly for +nested functions (but see ??).

+ +

Prefer using arrow functions over f.bind(this), and especially over +goog.bind(f, this). Avoid writing const self = this. Arrow functions are +particularly useful for callbacks, which sometimes pass unexpected additional +arguments.

+ +

The right-hand side of the arrow may be a single expression or a block. +Parentheses around the arguments are optional if there is only a single +non-destructured argument.

+ +

Tip: It is a good practice to use parentheses even for single-argument arrows, +since the code may still parse reasonably (but incorrectly) if the parentheses +are forgotten when an additional argument is added.

+ +

5.5.4 Generators

+ +

Generators enable a number of useful abstractions and may be used as needed.

+ +

When defining generator functions, attach the * to the function keyword when +present, and separate it with a space from the name of the function. When using +delegating yields, attach the * to the yield keyword.

+ +

Example:

+ +
/** @return {!Iterator<number>} */
+function* gen1() {
+  yield 42;
+}
+
+/** @return {!Iterator<number>} */
+const gen2 = function*() {
+  yield* gen1();
+}
+
+class SomeClass {
+  /** @return {!Iterator<number>} */
+  * gen() {
+    yield 42;
+  }
+}
+
+ +

5.5.5 Parameters

+ +

Function parameters must be typed with JSDoc annotations in the JSDoc preceding +the function’s definition, except in the case of same-signature @overrides, +where all types are omitted.

+ +

Parameter types may be specified inline, immediately before the parameter name +(as in (/** number */ foo, /** string */ bar) => foo + bar). Inline and +@param type annotations must not be mixed in the same function definition.

+ +
5.5.5.1 Default parameters
+ +

Optional parameters are permitted using the equals operator in the parameter +list. Optional parameters must include spaces on both sides of the equals +operator, be named exactly like required parameters (i.e., not prefixed with +opt_), use the = suffix in their JSDoc type, come after required parameters, +and not use initializers that produce observable side effects. All optional +parameters must have a default value in the function declaration, even if that +value is undefined.

+ +

Example:

+ +
/**
+ * @param {string} required This parameter is always needed.
+ * @param {string=} optional This parameter can be omitted.
+ * @param {!Node=} node Another optional parameter.
+ */
+function maybeDoSomething(required, optional = '', node = undefined) {}
+
+ +

Use default parameters sparingly. Prefer destructuring (as in +??) to create readable APIs when there +are more than a small handful of optional parameters that do not have a natural +order.

+ +

Note: Unlike Python's default parameters, it is okay to use initializers that +return new mutable objects (such as {} or []) because the initializer is +evaluated each time the default value is used, so a single object won't be +shared across invocations.

+ +

Tip: While arbitrary expressions including function calls may be used as +initializers, these should be kept as simple as possible. Avoid initializers +that expose shared mutable state, as that can easily introduce unintended +coupling between function calls.

+ +
5.5.5.2 Rest parameters
+ +

Use a rest parameter instead of accessing arguments. Rest parameters are +typed with a ... prefix in their JSDoc. The rest parameter must be the last +parameter in the list. There is no space between the ... and the parameter +name. Do not name the rest parameter var_args. Never name a local variable or +parameter arguments, which confusingly shadows the built-in name.

+ +

Example:

+ +
/**
+ * @param {!Array<string>} array This is an ordinary parameter.
+ * @param {...number} numbers The remainder of arguments are all numbers.
+ */
+function variadic(array, ...numbers) {}
+
+ +

5.5.6 Returns

+ +

Function return types must be specified in the JSDoc directly above the function +definition, except in the case of same-signature @overrides where all types +are omitted.

+ +

5.5.7 Generics

+ +

Declare generic functions and methods when necessary with @template TYPE in +the JSDoc above the class definition.

+ +

5.5.8 Spread operator

+ +

Function calls may use the spread operator (...). Prefer the spread operator +to Function.prototype.apply when an array or iterable is unpacked into +multiple parameters of a variadic function. There is no space after the ....

+ +

Example:

+ +
function myFunction(...elements) {}
+myFunction(...array, ...iterable, ...generator());
+
+ +

5.6 String literals

+ +

5.6.1 Use single quotes

+ +

Ordinary string literals are delimited with single quotes ('), rather than +double quotes (").

+ +

Tip: if a string contains a single quote character, consider using a template +string to avoid having to escape the quote.

+ +

Ordinary string literals may not span multiple lines.

+ +

5.6.2 Template strings

+ +

Use template strings (delimited with `) over complex string +concatenation, particularly if multiple string literals are involved. Template +strings may span multiple lines.

+ +

If a template string spans multiple lines, it does not need to follow the +indentation of the enclosing block, though it may if the added whitespace does +not matter.

+ +

Example:

+ +
function arithmetic(a, b) {
+  return `Here is a table of arithmetic operations:
+${a} + ${b} = ${a + b}
+${a} - ${b} = ${a - b}
+${a} * ${b} = ${a * b}
+${a} / ${b} = ${a / b}`;
+}
+
+ +

5.6.3 No line continuations

+ +

Do not use line continuations (that is, ending a line inside a string literal +with a backslash) in either ordinary or template string literals. Even though +ES5 allows this, it can lead to tricky errors if any trailing whitespace comes +after the slash, and is less obvious to readers.

+ +

Illegal:

+ +
const longString = 'This is a very long string that far exceeds the 80 \
+    column limit. It unfortunately contains long stretches of spaces due \
+    to how the continued lines are indented.';
+
+ +

Instead, write

+ +
const longString = 'This is a very long string that far exceeds the 80 ' +
+    'column limit. It does not contain long stretches of spaces since ' +
+    'the concatenated strings are cleaner.';
+
+ +

5.7 Number literals

+ +

Numbers may be specified in decimal, hex, octal, or binary. Use exactly 0x, +0o, and 0b prefixes, with lowercase letters, for hex, octal, and binary, +respectively. Never include a leading zero unless it is immediately followed by +x, o, or b.

+ +

5.8 Control structures

+ +

5.8.1 For loops

+ +

With ES6, the language now has three different kinds of for loops. All may be +used, though for-of loops should be preferred when possible.

+ +

for-in loops may only be used on dict-style objects (see +??), and should not be used to iterate over an +array. Object.prototype.hasOwnProperty should be used in for-in loops to +exclude unwanted prototype properties. Prefer for-of and Object.keys over +for-in when possible.

+ +

5.8.2 Exceptions

+ +

Exceptions are an important part of the language and should be used whenever +exceptional cases occur. Always throw Errors or subclasses of Error: never +throw string literals or other objects. Always use new when constructing an +Error.

+ +

Custom exceptions provide a great way to convey additional error information +from functions. They should be defined and used wherever the native Error +type is insufficient.

+ +

Prefer throwing exceptions over ad-hoc error-handling approaches (such as +passing an error container reference type, or returning an object with an error +property).

+ +
5.8.2.1 Empty catch blocks
+ +

It is very rarely correct to do nothing in response to a caught exception. When +it truly is appropriate to take no action whatsoever in a catch block, the +reason this is justified is explained in a comment.

+ +
try {
+  return handleNumericResponse(response);
+} catch (ok) {
+  // it's not numeric; that's fine, just continue
+}
+return handleTextResponse(response);
+
+ +

Illegal:

+ +
   try {
+    shouldFail();
+    fail('expected an error');
+  }
+  catch (expected) {}
+
+ +

Tip: Unlike in some other languages, patterns like the above simply don’t work +since this will catch the error thrown by fail. Use assertThrows() instead.

+ +

5.8.3 Switch statements

+ +

Terminology Note: Inside the braces of a switch block are one or more statement groups. Each statement group consists of one or more switch labels (either case FOO: or default:), followed by one or more statements.

+ +
5.8.3.1 Fall-through: commented
+ +

Within a switch block, each statement group either terminates abruptly (with a +break, return or thrown exception), or is marked with a comment to +indicate that execution will or might continue into the next statement +group. Any comment that communicates the idea of fall-through is sufficient +(typically // fall through). This special comment is not required in the last +statement group of the switch block.

+ +

Example:

+ +
switch (input) {
+  case 1:
+  case 2:
+    prepareOneOrTwo();
+  // fall through
+  case 3:
+    handleOneTwoOrThree();
+    break;
+  default:
+    handleLargeNumber(input);
+}
+
+ +
5.8.3.2 The default case is present
+ +

Each switch statement includes a default statement group, even if it contains +no code.

+ +

5.9 this

+ +

Only use this in class constructors and methods, or in arrow functions defined +within class constructors and methods. Any other uses of this must have an +explicit @this declared in the immediately-enclosing function’s JSDoc.

+ +

Never use this to refer to the global object, the context of an eval, the +target of an event, or unnecessarily call()ed or apply()ed functions.

+ +

5.10 Disallowed features

+ +

5.10.1 with

+ +

Do not use the with keyword. It makes your code harder to understand and has +been banned in strict mode since ES5.

+ +

5.10.2 Dynamic code evaluation

+ +

Do not use eval or the Function(...string) constructor (except for code +loaders). These features are potentially dangerous and simply do not work in +CSP environments.

+ +

5.10.3 Automatic semicolon insertion

+ +

Always terminate statements with semicolons (except function and class +declarations, as noted above).

+ +

5.10.4 Non-standard features

+ +

Do not use non-standard features. This includes old features that have been +removed (e.g., WeakMap.clear), new features that are not yet standardized +(e.g., the current TC39 working draft, proposals at any stage, or proposed but +not-yet-complete web standards), or proprietary features that are only +implemented in some browsers. Use only features defined in the current ECMA-262 +or WHATWG standards. (Note that projects writing against specific APIs, such as +Chrome extensions or Node.js, can obviously use those APIs). Non-standard +language “extensions” (such as those provided by some external transpilers) are +forbidden.

+ +

5.10.5 Wrapper objects for primitive types

+ +

Never use new on the primitive object wrappers (Boolean, Number, String, +Symbol), nor include them in type annotations.

+ +

Illegal:

+ +
const /** Boolean */ x = new Boolean(false);
+if (x) alert(typeof x);  // alerts 'object' - WAT?
+
+ +

The wrappers may be called as functions for coercing (which is preferred over +using + or concatenating the empty string) or creating symbols.

+ +

Example:

+ +
const /** boolean */ x = Boolean(0);
+if (!x) alert(typeof x);  // alerts 'boolean', as expected
+
+ +

5.10.6 Modifying builtin objects

+ +

Never modify builtin types, either by adding methods to their constructors or to +their prototypes. Avoid depending on libraries that do this. Note that the +JSCompiler’s runtime library will provide standards-compliant polyfills where +possible; nothing else may modify builtin objects.

+ +

Do not add symbols to the global object unless absolutely necessary +(e.g. required by a third-party API).

+ +

6 Naming

+ +

6.1 Rules common to all identifiers

+ +

Identifiers use only ASCII letters and digits, and, in a small number of cases +noted below, underscores and very rarely (when required by frameworks like +Angular) dollar signs.

+ +

Give as descriptive a name as possible, within reason. Do not worry about saving +horizontal space as it is far more important to make your code immediately +understandable by a new reader. Do not use abbreviations that are ambiguous or +unfamiliar to readers outside your project, and do not abbreviate by deleting +letters within a word.

+ +
priceCountReader      // No abbreviation.
+numErrors             // "num" is a widespread convention.
+numDnsConnections     // Most people know what "DNS" stands for.
+
+ +

Illegal:

+ +
n                     // Meaningless.
+nErr                  // Ambiguous abbreviation.
+nCompConns            // Ambiguous abbreviation.
+wgcConnections        // Only your group knows what this stands for.
+pcReader              // Lots of things can be abbreviated "pc".
+cstmrId               // Deletes internal letters.
+kSecondsPerDay        // Do not use Hungarian notation.
+
+ +

6.2 Rules by identifier type

+ +

6.2.1 Package names

+ +

Package names are all lowerCamelCase. For example, +my.exampleCode.deepSpace, but not my.examplecode.deepspace or my.example_code.deep_space.

+ +

6.2.2 Class names

+ +

Class, interface, record, and typedef names are written in UpperCamelCase. +Unexported classes are simply locals: they are not marked @private and +therefore are not named with a trailing underscore.

+ +

Type names are typically nouns or noun phrases. For example, Request, +ImmutableList, or VisibilityMode. Additionally, interface names may +sometimes be adjectives or adjective phrases instead (for example, Readable).

+ +

6.2.3 Method names

+ +

Method names are written in lowerCamelCase. Private methods’ names must end +with a trailing underscore.

+ +

Method names are typically verbs or verb phrases. For example, sendMessage or +stop_. Getter and setter methods for properties are never required, but if +they are used they should be named getFoo (or optionally isFoo or hasFoo +for booleans), or setFoo(value) for setters.

+ +

Underscores may also appear in JsUnit test method names to separate logical +components of the name. One typical pattern is test<MethodUnderTest>_<state>, +for example testPop_emptyStack. There is no One Correct Way to name test +methods.

+ +

6.2.4 Enum names

+ +

Enum names are written in UpperCamelCase, similar to classes, and should +generally be singular nouns. Individual items within the enum are named in +CONSTANT_CASE.

+ +

6.2.5 Constant names

+ +

Constant names use CONSTANT_CASE: all uppercase letters, with words separated +by underscores. There is no reason for a constant to be named with a trailing +underscore, since private static properties can be replaced by (implicitly +private) module locals.

+ +
6.2.5.1 Definition of “constant”
+ +

Every constant is a @const static property or a module-local const +declaration, but not all @const static properties and module-local consts +are constants. Before choosing constant case, consider whether the field really +feels like a deeply immutable constant. For example, if any of that instance's +observable state can change, it is almost certainly not a constant. Merely +intending to never mutate the object is generally not enough.

+ +

Examples:

+ +
// Constants
+const NUMBER = 5;
+/** @const */ exports.NAMES = ImmutableList.of('Ed', 'Ann');
+/** @enum */ exports.SomeEnum = { ENUM_CONSTANT: 'value' };
+
+// Not constants
+let letVariable = 'non-const';
+class MyClass { constructor() { /** @const */ this.nonStatic = 'non-static'; } };
+/** @type {string} */ MyClass.staticButMutable = 'not @const, can be reassigned';
+const /** Set<String> */ mutableCollection = new Set();
+const /** ImmutableSet<SomeMutableType> */ mutableElements = ImmutableSet.of(mutable);
+const Foo = goog.require('my.Foo');  // mirrors imported name
+const logger = log.getLogger('loggers.are.not.immutable');
+
+ +

Constants’ names are typically nouns or noun phrases.

+ +
6.2.5.1 Local aliases
+ +

Local aliases should be used whenever they improve readability over +fully-qualified names. Follow the same rules as goog.requires +(??), maintaining the last part of the aliased name. +Aliases may also be used within functions. Aliases must be const.

+ +

Examples:

+ +
const staticHelper = importedNamespace.staticHelper;
+const CONSTANT_NAME = ImportedClass.CONSTANT_NAME;
+const {assert, assertInstanceof} = asserts;
+
+ +

6.2.6 Non-constant field names

+ +

Non-constant field names (static or otherwise) are written in lowerCamelCase, +with a trailing underscore for private fields.

+ +

These names are typically nouns or noun phrases. For example, computedValues +or index_.

+ +

6.2.7 Parameter names

+ +

Parameter names are written in lowerCamelCase. Note that this applies even if +the parameter expects a constructor.

+ +

One-character parameter names should not be used in public methods.

+ +

Exception: When required by a third-party framework, parameter names may +begin with a $. This exception does not apply to any other identifiers +(e.g. local variables or properties).

+ +

6.2.8 Local variable names

+ +

Local variable names are written in lowerCamelCase, except for module-local +(top-level) constants, as described above. Constants in function scopes are +still named in lowerCamelCase. Note that lowerCamelCase applies even if the +variable holds a constructor.

+ +

6.2.9 Template parameter names

+ +

Template parameter names should be concise, single-word or single-letter +identifiers, and must be all-caps, such as TYPE or THIS.

+ +

6.3 Camel case: defined

+ +

Sometimes there is more than one reasonable way to convert an English phrase +into camel case, such as when acronyms or unusual constructs like IPv6 or +iOS are present. To improve predictability, Google Style specifies the +following (nearly) deterministic scheme.

+ +

Beginning with the prose form of the name:

+ +
    +
  1. Convert the phrase to plain ASCII and remove any apostrophes. For example, +Müller's algorithm might become Muellers algorithm.
  2. +
  3. Divide this result into words, splitting on spaces and any remaining +punctuation (typically hyphens). +
      +
    1. Recommended: if any word already has a conventional camel case +appearance in common usage, split this into its constituent parts (e.g., +AdWords becomes ad words). Note that a word such as iOS is not +really in camel case per se; it defies any convention, so this +recommendation does not apply.
    2. +
  4. +
  5. Now lowercase everything (including acronyms), then uppercase only the first +character of: +
      +
    1. … each word, to yield upper camel case, or
    2. +
    3. … each word except the first, to yield lower camel case
    4. +
  6. +
  7. Finally, join all the words into a single identifier.
  8. +
+ +

Note that the casing of the original words is almost entirely disregarded.

+ +

Examples:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Prose formCorrectIncorrect
XML HTTP requestXmlHttpRequestXMLHTTPRequest
new customer IDnewCustomerIdnewCustomerID
inner stopwatchinnerStopwatchinnerStopWatch
supports IPv6 on iOS?supportsIpv6OnIossupportsIPv6OnIOS
YouTube importerYouTubeImporterYoutubeImporter*
+ +

*Acceptable, but not recommended.

+ +

Note: Some words are ambiguously hyphenated in the English language: for example nonempty and non-empty are both correct, so the method names checkNonempty and checkNonEmpty are likewise both correct.

+ +

7 JSDoc

+ +

JSDoc is used on all classes, fields, and methods.

+ +

7.1 General form

+ +

The basic formatting of JSDoc blocks is as seen in this example:

+ +
/**
+ * Multiple lines of JSDoc text are written here,
+ * wrapped normally.
+ * @param {number} arg A number to do something to.
+ */
+function doSomething(arg) { … }
+
+ +

or in this single-line example:

+ +
/** @const @private {!Foo} A short bit of JSDoc. */
+this.foo_ = foo;
+
+ +

If a single-line comment overflows into multiple lines, it must use the +multi-line style with /** and */ on their own lines.

+ +

Many tools extract metadata from JSDoc comments to perform code validation and +optimization. As such, these comments must be well-formed.

+ +

7.2 Markdown

+ +

JSDoc is written in Markdown, though it may include HTML when necessary.

+ +

Note that tools that automatically extract JSDoc (e.g. JsDossier) will often +ignore plain text formatting, so if you did this:

+ +
/**
+ * Computes weight based on three factors:
+ *   items sent
+ *   items received
+ *   last timestamp
+ */
+
+ +

it would come out like this:

+ +
Computes weight based on three factors: items sent items received last timestamp
+
+ +

Instead, write a Markdown list:

+ +
/**
+ * Computes weight based on three factors:
+ *  - items sent
+ *  - items received
+ *  - last timestamp
+ */
+
+ +

7.3 JSDoc tags

+ +

Google style allows a subset of JSDoc tags. See +?? for the complete list. Most tags must +occupy their own line, with the tag at the beginning of the line.

+ +

Illegal:

+ +
/**
+ * The "param" tag must occupy its own line and may not be combined.
+ * @param {number} left @param {number} right
+ */
+function add(left, right) { ... }
+
+ +

Simple tags that do not require any additional data (such as @private, +@const, @final, @export) may be combined onto the same line, along with an +optional type when appropriate.

+ +
/**
+ * Place more complex annotations (like "implements" and "template")
+ * on their own lines.  Multiple simple tags (like "export" and "final")
+ * may be combined in one line.
+ * @export @final
+ * @implements {Iterable<TYPE>}
+ * @template TYPE
+ */
+class MyClass {
+  /**
+   * @param {!ObjType} obj Some object.
+   * @param {number=} num An optional number.
+   */
+  constructor(obj, num = 42) {
+    /** @private @const {!Array<!ObjType|number>} */
+    this.data_ = [obj, num];
+  }
+}
+
+ +

There is no hard rule for when to combine tags, or in which order, but be +consistent.

+ +

For general information about annotating types in JavaScript see +Annotating JavaScript for the Closure Compiler and Types in the Closure Type +System.

+ +

7.4 Line wrapping

+ +

Line-wrapped block tags are indented four spaces. Wrapped description text may +be lined up with the description on previous lines, but this horizontal +alignment is discouraged.

+ +
/**
+ * Illustrates line wrapping for long param/return descriptions.
+ * @param {string} foo This is a param with a description too long to fit in
+ *     one line.
+ * @return {number} This returns something that has a description too long to
+ *     fit in one line.
+ */
+exports.method = function(foo) {
+  return 5;
+};
+
+ +

Do not indent when wrapping a @fileoverview description.

+ +

7.5 Top/file-level comments

+ +

A file may have a top-level file overview. A copyright notice , author information, and +default visibility level are optional. File overviews are generally recommended whenever a +file consists of more than a single class definition. The top level comment is +designed to orient readers unfamiliar with the code to what is in this file. If +present, it may provide a description of the file's contents and any +dependencies or compatibility information. Wrapped lines are not indented.

+ +

Example:

+ +
/**
+ * @fileoverview Description of file, its uses and information
+ * about its dependencies.
+ * @package
+ */
+
+ +

7.6 Class comments

+ +

Classes, interfaces and records must be documented with a description and any +template parameters, implemented interfaces, visibility, or other appropriate +tags. The class description should provide the reader with enough information to +know how and when to use the class, as well as any additional considerations +necessary to correctly use the class. Textual descriptions may be omitted on the +constructor. @constructor and @extends annotations are not used with the +class keyword unless the class is being used to declare an @interface or +it extends a generic class.

+ +
/**
+ * A fancier event target that does cool things.
+ * @implements {Iterable<string>}
+ */
+class MyFancyTarget extends EventTarget {
+  /**
+   * @param {string} arg1 An argument that makes this more interesting.
+   * @param {!Array<number>} arg2 List of numbers to be processed.
+   */
+  constructor(arg1, arg2) {
+    // ...
+  }
+};
+
+/**
+ * Records are also helpful.
+ * @extends {Iterator<TYPE>}
+ * @record
+ * @template TYPE
+ */
+class Listable {
+  /** @return {TYPE} The next item in line to be returned. */
+  next() {}
+}
+
+ +

7.7 Enum and typedef comments

+ +

Enums and typedefs must be documented. Public enums and typedefs must have a +non-empty description. Individual enum items may be documented with a JSDoc +comment on the preceding line.

+ +
/**
+ * A useful type union, which is reused often.
+ * @typedef {!Bandersnatch|!BandersnatchType}
+ */
+let CoolUnionType;
+
+
+/**
+ * Types of bandersnatches.
+ * @enum {string}
+ */
+const BandersnatchType = {
+  /** This kind is really frumious. */
+  FRUMIOUS: 'frumious',
+  /** The less-frumious kind. */
+  MANXOME: 'manxome',
+};
+
+ +

Typedefs are useful for defining short record types, or aliases for unions, +complex functions, or generic types. +Typedefs should be avoided for record types with many fields, since they do not +allow documenting individual fields, nor using templates or recursive +references. +For large record types, prefer @record.

+ +

7.8 Method and function comments

+ +

Parameter and return types must be documented. The this type should be +documented when necessary. Method, parameter, and return descriptions (but not +types) may be omitted if they are obvious from the rest of the method’s JSDoc or +from its signature. Method descriptions should start with a sentence written in +the third person declarative voice. If a method overrides a superclass method, +it must include an @override annotation. Overridden methods must include all +@param and @return annotations if any types are refined, but should omit +them if the types are all the same.

+ +
/** This is a class. */
+class SomeClass extends SomeBaseClass {
+  /**
+   * Operates on an instance of MyClass and returns something.
+   * @param {!MyClass} obj An object that for some reason needs detailed
+   *     explanation that spans multiple lines.
+   * @param {!OtherClass} obviousOtherClass
+   * @return {boolean} Whether something occurred.
+   */
+  someMethod(obj, obviousOtherClass) { ... }
+
+  /** @override */
+  overriddenMethod(param) { ... }
+}
+
+/**
+ * Demonstrates how top-level functions follow the same rules.  This one
+ * makes an array.
+ * @param {TYPE} arg
+ * @return {!Array<TYPE>}
+ * @template TYPE
+ */
+function makeArray(arg) { ... }
+
+ + + +

Anonymous functions do not require JSDoc, though parameter types may be specified inline if the automatic type inference is insufficient.

+ +
promise.then(
+    (/** !Array<number|string> */ items) => {
+      doSomethingWith(items);
+      return /** @type {string} */ (items[0]);
+    });
+
+ +

7.9 Property comments

+ +

Property types must be documented. The description may be omitted for private +properties, if name and type provide enough documentation for understanding the +code.

+ +

Publicly exported constants are commented the same way as properties. Explicit +types may be omitted for @const properties initialized from an expression with +an obviously known type.

+ +

Tip: A @const property’s type can be considered “obviously known” if it is +assigned directly from a constructor parameter with a declared type, or directly +from a function call with a declared return type. Non-const properties and +properties assigned from more complex expressions should have their types +declared explicitly.

+ +
/** My class. */
+class MyClass {
+  /** @param {string=} someString */
+  constructor(someString = 'default string') {
+    /** @private @const */
+    this.someString_ = someString;
+
+    /** @private @const {!OtherType} */
+    this.someOtherThing_ = functionThatReturnsAThing();
+
+    /**
+     * Maximum number of things per pane.
+     * @type {number}
+     */
+    this.someProperty = 4;
+  }
+}
+
+/**
+ * The number of times we'll try before giving up.
+ * @const
+ */
+MyClass.RETRY_COUNT = 33;
+
+ +

7.10 Type annotations

+ +

Type annotations are found on @param, @return, @this, and @type tags, +and optionally on @const, @export, and any visibility tags. Type +annotations attached to JSDoc tags must always be enclosed in braces.

+ +

7.10.1 Nullability

+ +

The type system defines modifiers ! and ? for non-null and nullable, +respectively. Primitive types (undefined, string, number, boolean, +symbol, and function(...): ...) and record literals ({foo: string, bar: +number}) are non-null by default. Do not add an explicit ! to these types. +Object types (Array, Element, MyClass, etc) are nullable by default, but +cannot be immediately distinguished from a name that is @typedef’d to a +non-null-by-default type. As such, all types except primitives and record +literals must be annotated explicitly with either ? or ! to indicate whether +they are nullable or not.

+ +

7.10.2 Type Casts

+ +

In cases where type checking doesn't accurately infer the type of an expression, +it is possible to tighten the type by adding a type annotation comment and +enclosing the expression in parentheses. Note that the parentheses are required.

+ +
/** @type {number} */ (x)
+
+ +

7.10.3 Template Parameter Types

+ +

Always specify template parameters. This way compiler can do a better job and it +makes it easier for readers to understand what code does.

+ +

Bad:

+ +
const /** !Object */ users = {};
+const /** !Array */ books = [];
+const /** !Promise */ response = ...;
+
+ +

Good:

+ +
const /** !Object<string, !User> */ users = {};
+const /** !Array<string> */ books = [];
+const /** !Promise<!Response> */ response = ...;
+
+const /** !Promise<undefined> */ thisPromiseReturnsNothingButParameterIsStillUseful = ...;
+const /** !Object<string, *> */ mapOfEverything = {};
+
+ +

Cases when template parameters should not be used:

+ +
    +
  • Object is used for type hierarchy and not as map-like structure.
  • +
+ +

7.11 Visibility annotations

+ +

Visibility annotations (@private, @package, @protected) may be specified +in a @fileoverview block, or on any exported symbol or property. Do not +specify visibility for local variables, whether within a function or at the top +level of a module. All @private names must end with an underscore.

+ +

8 Policies

+ +

8.1 Issues unspecified by Google Style: Be Consistent!

+ +

For any style question that isn't settled definitively by this specification, +prefer to do what the other code in the same file is already doing. If that +doesn't resolve the question, consider emulating the other files in the same +package.

+ +

8.2 Compiler warnings

+ +

8.2.1 Use a standard warning set

+ +

+As far as possible projects should use --warning_level=VERBOSE. +

+ +

8.2.2 How to handle a warning

+ +

Before doing anything, make sure you understand exactly what the warning is +telling you. If you're not positive why a warning is appearing, ask for help +.

+ +

Once you understand the warning, attempt the following solutions in order:

+ +
    +
  1. First, fix it or work around it. Make a strong attempt to actually +address the warning, or find another way to accomplish the task that avoids +the situation entirely.
  2. +
  3. Otherwise, determine if it's a false alarm. If you are convinced that +the warning is invalid and that the code is actually safe and correct, add a +comment to convince the reader of this fact and apply the @suppress +annotation.
  4. +
  5. Otherwise, leave a TODO comment. This is a last resort. If you do +this, do not suppress the warning. The warning should be visible until +it can be taken care of properly.
  6. +
+ +

8.2.3 Suppress a warning at the narrowest reasonable scope

+ +

Warnings are suppressed at the narrowest reasonable scope, usually that of a single local variable or very small method. Often a variable or method is extracted for that reason alone.

+ +

Example

+ +
/** @suppress {uselessCode} Unrecognized 'use asm' declaration */
+function fn() {
+  'use asm';
+  return 0;
+}
+
+ +

Even a large number of suppressions in a class is still better than blinding the +entire class to this type of warning.

+ +

8.3 Deprecation

+ +

Mark deprecated methods, classes or interfaces with @deprecated annotations. A +deprecation comment must include simple, clear directions for people to fix +their call sites.

+ +

8.4 Code not in Google Style

+ +

You will occasionally encounter files in your codebase that are not in proper +Google Style. These may have come from an acquisition, or may have been written +before Google Style took a position on some issue, or may be in non-Google Style +for any other reason.

+ +

8.4.1 Reformatting existing code

+ +

When updating the style of existing code, follow these guidelines.

+ +
    +
  1. It is not required to change all existing code to meet current style +guidelines. Reformatting existing code is a trade-off between code churn +and consistency. Style rules evolve over time and these kinds of tweaks to +maintain compliance would create unnecessary churn. However, if significant +changes are being made to a file it is expected that the file will be in +Google Style.
  2. +
  3. Be careful not to allow opportunistic style fixes to muddle the focus of a +CL. If you find yourself making a lot of style changes that aren’t critical +to the central focus of a CL, promote those changes to a separate CL.
  4. +
+ +

8.4.2 Newly added code: use Google Style

+ +

Brand new files use Google Style, regardless of the style choices of other files +in the same package.

+ +

When adding new code to a file that is not in Google Style, reformatting the +existing code first is recommended, subject to the advice in +??.

+ +

If this reformatting is not done, then new code should be as consistent as +possible with existing code in the same file, but must not violate the style +guide.

+ +

8.5 Local style rules

+ +

Teams and projects may adopt additional style rules beyond those in this +document, but must accept that cleanup changes may not abide by these additional +rules, and must not block such cleanup changes due to violating any additional +rules. Beware of excessive rules which serve no purpose. The style guide does +not seek to define style in every possible scenario and neither should you.

+ +

8.6 Generated code: mostly exempt

+ +

Source code generated by the build process is not required to be in Google +Style. However, any generated identifiers that will be referenced from +hand-written source code must follow the naming requirements. As a special +exception, such identifiers are allowed to contain underscores, which may help +to avoid conflicts with hand-written identifiers.

+ +

9 Appendices

+ +

9.1 JSDoc tag reference

+ +

JSDoc serves multiple purposes in JavaScript. In addition to being used to +generate documentation it is also used to control tooling. The best known are +the Closure Compiler type annotations.

+ +

9.1.1 Type annotations and other Closure Compiler annotations

+ +

Documentation for JSDoc used by the Closure Compiler is described in +Annotating JavaScript for the Closure Compiler and Types in the Closure Type +System.

+ +

9.1.2 Documentation annotations

+ +

In addition to the JSDoc described in Annotating JavaScript for the Closure +Compiler the following tags are common and well supported by various +documentation generations tools (such as JsDossier) for purely documentation +purposes. + + + + + + + + + + +
Tag + Template & Examples + Description +
@author or @owner + @author username@google.com (First Last) +

For example: +

+/**
+ * @fileoverview Utilities for handling textareas.
+ * @author kuth@google.com (Uthur Pendragon)
+ */
+ 
+
Document the author of a file or the owner of a test, generally only + used in the @fileoverview comment. The @owner tag is used by the + unit test dashboard to determine who owns the test results. +

Not recommended. +

@bug + @bug bugnumber +

For example: +

+/** @bug 1234567 */
+function testSomething() {
+  // …
+}
+
+

/** + * @bug 1234568 + * @bug 1234569 + */ +function testTwoBugs() { + // … +} +

+
Indicates what bugs the given test function regression tests. +

Multiple bugs should each have their own @bug line, to make + searching for regression tests as easy as possible. +

@code + {@code ...} +

For example: +

+/**
+ * Moves to the next position in the selection.
+ * Throws {@code goog.iter.StopIteration} when it
+ * passes the end of the range.
+ * @return {!Node} The node at the next position.
+ */
+goog.dom.RangeIterator.prototype.next = function() {
+  // …
+};
+
+
Indicates that a term in a JSDoc description is code so it may be + correctly formatted in generated documentation. +
@see + @see Link +

For example: +

+/**
+ * Adds a single item, recklessly.
+ * @see #addSafely
+ * @see goog.Collect
+ * @see goog.RecklessAdder#add
+ */
+ 
+
Reference a lookup to another class function or method. +
@supported + @supported Description +

For example: +

+/**
+ * @fileoverview Event Manager
+ * Provides an abstracted interface to the
+ * browsers' event systems.
+ * @supported IE10+, Chrome, Safari
+ */
+
+
Used in a fileoverview to indicate what browsers are supported by + the file. +
@desc + @desc Message description +

For example: +

+/** @desc Notifying a user that their account has been created. */
+exports.MSG_ACCOUNT_CREATED = goog.getMsg(
+    'Your account has been successfully created.');
+ 
+

+ +

You may also see other types of JSDoc annotations in third-party code. These +annotations appear in the JSDoc Toolkit Tag Reference but are not considered +part of valid Google style.

+ +

9.1.3 Framework specific annotations

+ +

The following annotations are specific to a particular framework. + + + + + + +
Framework + Tag + Documentation +
Angular 1 + @ngInject +
Polymer + @polymerBehavior + + + https://github.com/google/closure-compiler/wiki/Polymer-Pass + +

+ +

9.1.4 Notes about standard Closure Compiler annotations

+ +

The following tags used to be standard but are now deprecated. + + + + + + +
Tag + Template & Examples + Description +
@expose + @expose + Deprecated. Do not use. Use @export and/or @nocollapse + instead. +
@inheritDoc + @inheritDoc + Deprecated. Do not use. Use @override instead. +

+ +

9.2 Commonly misunderstood style rules

+ +

Here is a collection of lesser-known or commonly misunderstood facts about +Google Style for JavaScript. (The following are true statements; this is not a +list of myths.)

+ +
    +
  • Neither a copyright statement nor @author credit is required in a source +file. (Neither is explicitly recommended, either.)
  • +
  • Aside from the constructor coming first +(??), there is no hard and fast rule +governing how to order the members of a class (??).
  • +
  • Empty blocks can usually be represented concisely as {}, as detailed in +(??).
  • +
  • The prime directive of line-wrapping is: prefer to break at a higher +syntactic level (??).
  • +
  • Non-ASCII characters are allowed in string literals, comments and Javadoc, +and in fact are recommended when they make the code easier to read than the +equivalent Unicode escape would (??).
  • +
+ + + +

The following tools exist to support various aspects of Google Style.

+ +

9.3.1 Closure Compiler

+ +

This program performs type checking and other checks, +optimizations and other transformations (such as ECMAScript 6 to ECMAScript 5 +code lowering).

+ +

9.3.2 clang-format

+ +

This program reformats +JavaScript source code into Google Style, and also follows a number of +non-required but frequently readability-enhancing formatting practices.

+ +

clang-format is not required. Authors are allowed to change its output, and +reviewers are allowed to ask for such changes; disputes are worked out in the +usual way. However, subtrees may choose to opt in to such enforcement locally.

+ +

9.3.3 Closure compiler linter

+ +

This program checks for a +variety of missteps and anti-patterns. +

+ +

9.3.4 Conformance framework

+ +

The JS Conformance Framework is a tool that is part of the Closure Compiler that +provides developers a simple means to specify a set of additional checks to be +run against their code base above the standard checks. Conformance checks can, +for example, forbid access to a certain property, or calls to a certain +function, or missing type information (unknowns).

+ +

These rules are commonly used to enforce critical restrictions (such as defining +globals, which could break the codebase) and security patterns (such as using +eval or assigning to innerHTML), or more loosely to improve code quality.

+ +

For additional information see the official documentation for the +JS Conformance Framework.

+ +

9.4 Exceptions for legacy platforms

+ +

9.4.1 Overview

+ +

This section describes exceptions and additional rules to be followed when +modern ECMAScript 6 syntax is not available to the code authors. Exceptions to +the recommended style are required when ECMAScript 6 syntax is not possible and +are outlined here:

+ +
    +
  • Use of var declarations is allowed
  • +
  • Use of arguments is allowed
  • +
  • Optional parameters without default values are allowed
  • +
+ +

9.4.2 Use var

+ +
9.4.2.1 var declarations are NOT block-scoped
+ +

var declarations are scoped to the beginning of the nearest enclosing +function, script or module, which can cause unexpected behavior, especially with +function closures that reference var declarations inside of loops. The +following code gives an example:

+ +
for (var i = 0; i < 3; ++i) {
+  var iteration = i;
+  setTimeout(function() { console.log(iteration); }, i*1000);
+}
+
+// logs 2, 2, 2 -- NOT 0, 1, 2
+// because `iteration` is function-scoped, not local to the loop.
+
+
+ +
9.4.2.2 Declare variables as close as possible to first use
+ +

Even though var declarations are scoped to the beginning of the enclosing +function, var declarations should be as close as possible to their first use, +for readability purposes. However, do not put a var declaration inside a block +if that variable is referenced outside the block. For example:

+ +
function sillyFunction() {
+  var count = 0;
+  for (var x in y) {
+    // "count" could be declared here, but don't do that.
+    count++;
+  }
+  console.log(count + ' items in y');
+}
+
+ +
9.4.2.3 Use @const for constants variables
+ +

For global declarations where the const keyword would be used, if it were +available, annotate the var declaration with @const instead (this is optional +for local variables).

+ +

9.4.3 Do not use block scoped functions declarations

+ +

Do not do this:

+ +
if (x) {
+  function foo() {}
+}
+
+ +

While most JavaScript VMs implemented before ECMAScript 6 support function +declarations within blocks it was not standardized. Implementations were +inconsistent with each other and with the now-standard ECMAScript 6 behavior for +block scoped function declaration. ECMAScript 5 and prior only allow for +function declarations in the root statement list of a script or function and +explicitly ban them in block scopes in strict mode.

+ +

To get consistent behavior, instead use a var initialized with a function +expression to define a function within a block:

+ +
if (x) {
+  var foo = function() {};
+}
+
+ +

9.4.4 Dependency management with goog.provide/goog.require

+ +

goog.provide is deprecated. All new files should use goog.module, even in +projects with existing goog.provide usage. The following rules are for +pre-existing goog.provide files, only.

+ +
9.4.4.1 Summary
+ +
    +
  • Place all goog.provides first, goog.requires second. Separate provides +from requires with an empty line.
  • +
  • Sort the entries alphabetically (uppercase first).
  • +
  • Don't wrap goog.provide and goog.require statements. Exceed 80 columns +if necessary.
  • +
  • Only provide top-level symbols.
  • +
+ +

As of Oct 2016, goog.provide/goog.require dependency management is +deprecated. All new files, even in projects using goog.provide for older +files, should use +goog.module.

+ +

goog.provide statements should be grouped together and placed first. All +goog.require statements should follow. The two lists should be separated with +an empty line.

+ +

Similar to import statements in other languages, goog.provide and +goog.require statements should be written in a single line, even if they +exceed the 80 column line length limit.

+ +

The lines should be sorted alphabetically, with uppercase letters coming first:

+ +
goog.provide('namespace.MyClass');
+goog.provide('namespace.helperFoo');
+
+goog.require('an.extremelyLongNamespace.thatSomeoneThought.wouldBeNice.andNowItIsLonger.Than80Columns');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classes');
+goog.require('goog.dominoes');
+
+
+ +

All members defined on a class should be in the same file. Only top-level +classes should be provided in a file that contains multiple members defined on +the same class (e.g. enums, inner classes, etc).

+ +

Do this:

+ +
goog.provide('namespace.MyClass');
+
+ +

Not this:

+ +
goog.provide('namespace.MyClass');
+goog.provide('namespace.MyClass.CONSTANT');
+goog.provide('namespace.MyClass.Enum');
+goog.provide('namespace.MyClass.InnerClass');
+goog.provide('namespace.MyClass.TypeDef');
+goog.provide('namespace.MyClass.staticMethod');
+
+ +

Members on namespaces may also be provided:

+ +
goog.provide('foo.bar');
+goog.provide('foo.bar.CONSTANT');
+goog.provide('foo.bar.method');
+
+ +
9.4.4.2 Aliasing with goog.scope
+ +

goog.scope is deprecated. New files should not use goog.scope even in +projects with existing goog.scope usage.

+ +

goog.scope may be used to shorten references to namespaced symbols in +code using goog.provide/goog.require dependency management.

+ +

Only one goog.scope invocation may be added per file. Always place it in +the global scope.

+ +

The opening goog.scope(function() { invocation must be preceded by exactly one +blank line and follow any goog.provide statements, goog.require statements, +or top-level comments. The invocation must be closed on the last line in the +file. Append // goog.scope to the closing statement of the scope. Separate the +comment from the semicolon by two spaces.

+ +

Similar to C++ namespaces, do not indent under goog.scope declarations. +Instead, continue from the 0 column.

+ +

Only make aliases for names that will not be re-assigned to another object +(e.g., most constructors, enums, and namespaces). Do not do this (see below for +how to alias a constructor):

+ +
goog.scope(function() {
+var Button = goog.ui.Button;
+
+Button = function() { ... };
+...
+
+ +

Names must be the same as the last property of the global that they are aliasing.

+ +
goog.provide('my.module.SomeType');
+
+goog.require('goog.dom');
+goog.require('goog.ui.Button');
+
+goog.scope(function() {
+var Button = goog.ui.Button;
+var dom = goog.dom;
+
+// Alias new types after the constructor declaration.
+my.module.SomeType = function() { ... };
+var SomeType = my.module.SomeType;
+
+// Declare methods on the prototype as usual:
+SomeType.prototype.findButton = function() {
+  // Button as aliased above.
+  this.button = new Button(dom.getElement('my-button'));
+};
+...
+});  // goog.scope
+
+ +
+ + diff --git a/jsoncstyleguide.html b/jsoncstyleguide.html new file mode 100644 index 000000000..1bef466bf --- /dev/null +++ b/jsoncstyleguide.html @@ -0,0 +1,18 @@ + + + + + + + Redirecting + + + + Redirecting you to jsoncstyleguide.xml. + + diff --git a/jsoncstyleguide.xml b/jsoncstyleguide.xml new file mode 100644 index 000000000..3a2ac2543 --- /dev/null +++ b/jsoncstyleguide.xml @@ -0,0 +1,1187 @@ + + + + +

+Revision 0.9 +

+ +
+
+ + + + + +This style guide contains many details that are initially hidden from view. They are marked by the triangle icon, which you see here on your left. Click it now. You should see "Hooray" appear below. + + +

Hooray! Now you know you can expand points to get more details. Alternatively, there's an "expand all" at the top of this document.

+ +
+
+ +

This style guide documents guidelines and recommendations for building JSON APIs at Google. In general, JSON APIs should follow the spec found at JSON.org. This style guide clarifies and standardizes specific cases so that JSON APIs from Google have a standard look and feel. These guidelines are applicable to JSON requests and responses in both RPC-based and REST-based APIs.

+
+ +

For the purposes of this style guide, we define the following terms:

  • property - a name/value pair inside a JSON object.
  • property name - the name (or key) portion of the property.
  • property value - the value portion of the property.
+ +{ + // The name/value pair together is a "property". + "propertyName": "propertyValue" +} + + +

Javascript's number type encompasses all floating-point numbers, which is a broad designation. In this guide, number will refer to JavaScript's number type, while integer will refer to integers.

+
+
+ + + +No comments in JSON objects. + + +

Comments should not be included in JSON objects. Some of the examples in this style guide include comments. However this is only to clarify the examples.

+ +{ + // You may see comments in the examples below, + // But don't include comments in your JSON. + "propertyName": "propertyValue" +} + + + +
+ + +Use double quotes. + + +

If a property requires quotes, double quotes must be used. All property names must be surrounded by double quotes. Property values of type string must be surrounded by double quotes. Other value types (like boolean or number) should not be surrounded by double quotes.

+ +
+ + +Data should not be arbitrarily grouped for convenience. + + +

Data elements should be "flattened" in the JSON representation. Data should not be arbitrarily grouped for convenience.

In some cases, such as a collection of properties that represents a single structure, it may make sense to keep the structured hierarchy. These cases should be carefully considered, and only used if it makes semantic sense. For example, an address could be represented two ways, but the structured way probably makes more sense for developers:

+

Flattened Address:

+ +{ + "company": "Google", + "website": "https://www.google.com/", + "addressLine1": "111 8th Ave", + "addressLine2": "4th Floor", + "state": "NY", + "city": "New York", + "zip": "10011" +} + +

Structured Address:

+ +{ + "company": "Google", + "website": "https://www.google.com/", + "address": { + "line1": "111 8th Ave", + "line2": "4th Floor", + "state": "NY", + "city": "New York", + "zip": "10011" + } +} + + +
+
+ + + +Choose meaningful property names. + + +

Property names must conform to the following guidelines:

  • Property names should be meaningful names with defined semantics.
  • Property names must be camel-cased, ascii strings.
  • The first character must be a letter, an underscore (_) or a dollar sign ($).
  • Subsequent characters can be a letter, a digit, an underscore, or a dollar sign.
  • Reserved JavaScript keywords should be avoided (A list of reserved JavaScript keywords can be found below).

These guidelines mirror the guidelines for naming JavaScript identifiers. This allows JavaScript clients to access properties using dot notation. (for example, result.thisIsAnInstanceVariable). Here's an example of an object with one property:

+ +{ + "thisPropertyIsAnIdentifier": "identifier value" +} + + + +
+ + +JSON maps can use any Unicode character in key names. + + +

The property name naming rules do not apply when a JSON object is used as a map. A map (also referred to as an associative array) is a data type with arbitrary key/value pairs that use the keys to access the corresponding values. JSON objects and JSON maps look the same at runtime; this distinction is relevant to the design of the API. The API documentation should indicate when JSON objects are used as maps.

The keys of a map do not have to obey the naming guidelines for property names. Map keys may contain any Unicode characters. Clients can access these properties using the square bracket notation familiar for maps (for example, result.thumbnails["72"]).

+ +{ + // The "address" property is a sub-object + // holding the parts of an address. + "address": { + "addressLine1": "123 Anystreet", + "city": "Anytown", + "state": "XX", + "zip": "00000" + }, + // The "thumbnails" property is a map that maps + // a pixel size to the thumbnail url of that size. + "thumbnails": { + "72": "http://url.to.72px.thumbnail", + "144": "http://url.to.144px.thumbnail" + } +} + + + +
+ + +Certain property names are reserved for consistent use across services. + + +

Details about reserved property names, along with the full list, can be found later on in this guide. Services should avoid using these property names for anything other than their defined semantics.

+ +
+ + +Array types should have plural property names. All other property names should be singular. + + +

Arrays usually contain multiple items, and a plural property name reflects this. An example of this can be seen in the reserved names below. The items property name is plural because it represents an array of item objects. Most of the other fields are singular.

There may be exceptions to this, especially when referring to numeric property values. For example, in the reserved names, totalItems makes more sense than totalItem. However, technically, this is not violating the style guide, since totalItems can be viewed as totalOfItems, where total is singular (as per the style guide), and OfItems serves to qualify the total. The field name could also be changed to itemCount to look singular.

+ +{ + // Singular + "author": "lisa", + // An array of siblings, plural + "siblings": [ "bart", "maggie"], + // "totalItem" doesn't sound right + "totalItems": 10, + // But maybe "itemCount" is better + "itemCount": 10, +} + + + +
+ + +Avoid naming conflicts by choosing a new property name or versioning the API. + + +

New properties may be added to the reserved list in the future. There is no concept of JSON namespacing. If there is a naming conflict, these can usually be resolved by choosing a new property name or by versioning. For example, suppose we start with the following JSON object:

+ +{ + "apiVersion": "1.0", + "data": { + "recipeName": "pizza", + "ingredients": ["tomatoes", "cheese", "sausage"] + } +} + + +

If in the future we wish to make ingredients a reserved word, we can do one of two things:

1) Choose a different name:

+ +{ + "apiVersion": "1.0", + "data": { + "recipeName": "pizza", + "ingredientsData": "Some new property", + "ingredients": ["tomatoes", "cheese", "sausage"] + } +} + + +

2) Rename the property on a major version boundary:

+ +{ + "apiVersion": "2.0", + "data": { + "recipeName": "pizza", + "ingredients": "Some new property", + "recipeIngredients": ["tomatos", "cheese", "sausage"] + } +} + + + +
+
+ + + +Property values must be Unicode booleans, numbers, strings, objects, arrays, or null. + + +

The spec at JSON.org specifies exactly what type of data is allowed in a property value. This includes Unicode booleans, numbers, strings, objects, arrays, and null. JavaScript expressions are not allowed. APIs should support that spec for all values, and should choose the data type most appropriate for a particular property (numbers to represent numbers, etc.).

Good:

+ +{ + "canPigsFly": null, // null + "areWeThereYet": false, // boolean + "answerToLife": 42, // number + "name": "Bart", // string + "moreData": {}, // object + "things": [] // array +} + + +

Bad:

+ +{ + "aVariableName": aVariableName, // Bad - JavaScript identifier + "functionFoo": function() { return 1; } // Bad - JavaScript function +} + + + +
+ + +Consider removing empty or null values. + + +

If a property is optional or has an empty or null value, consider dropping the property from the JSON, unless there's a strong semantic reason for its existence.

+ +{ + "volume": 10, + + // Even though the "balance" property's value is zero, it should be left in, + // since "0" signifies "even balance" (the value could be "-1" for left + // balance and "+1" for right balance. + "balance": 0, + + // The "currentlyPlaying" property can be left out since it is null. + // "currentlyPlaying": null +} + + + +
+ + +Enum values should be represented as strings. + + +

As APIs grow, enum values may be added, removed or changed. Using strings as enum values ensures that downstream clients can gracefully handle changes to enum values.

Java code:

+ +public enum Color { + WHITE, + BLACK, + RED, + YELLOW, + BLUE +} + + +

JSON object:

+ +{ + "color": "WHITE" +} + + + +
+
+ +

As mentioned above, property value types must be booleans, numbers, strings, objects, arrays, or null. However, it is useful define a set of standard data types when dealing with certain values. These data types will always be strings, but they will be formatted in a specific manner so that they can be easily parsed.

+ + +Dates should be formatted as recommended by RFC 3339. + + +

Dates should be strings formatted as recommended by RFC 3339

+ +{ + "lastUpdate": "2007-11-06T16:34:41.000Z" +} + + + +
+ + +Time durations should be formatted as recommended by ISO 8601. + + +

Time duration values should be strings formatted as recommended by ISO 8601.

+ +{ + // three years, six months, four days, twelve hours, + // thirty minutes, and five seconds + "duration": "P3Y6M4DT12H30M5S" +} + + + +
+ + +Latitudes/Longitudes should be formatted as recommended by ISO 6709. + + +

Latitude/Longitude should be strings formatted as recommended by ISO 6709. Furthermore, they should favor the ±DD.DDDD±DDD.DDDD degrees format.

+ +{ + // The latitude/longitude location of the statue of liberty. + "statueOfLiberty": "+40.6894-074.0447" +} + + + +
+
+ +

In order to maintain a consistent interface across APIs, JSON objects should follow the structure outlined below. This structure applies to both requests and responses made with JSON. Within this structure, there are certain property names that are reserved for specific uses. These properties are NOT required; in other words, each reserved property may appear zero or one times. But if a service needs these properties, this naming convention is recommend. Here is a schema of the JSON structure, represented in Orderly format (which in turn can be compiled into a JSONSchema). You can few examples of the JSON structure at the end of this guide.

+ +object { + string apiVersion?; + string context?; + string id?; + string method?; + object { + string id? + }* params?; + object { + string kind?; + string fields?; + string etag?; + string id?; + string lang?; + string updated?; # date formatted RFC 3339 + boolean deleted?; + integer currentItemCount?; + integer itemsPerPage?; + integer startIndex?; + integer totalItems?; + integer pageIndex?; + integer totalPages?; + string pageLinkTemplate /^https?:/ ?; + object {}* next?; + string nextLink?; + object {}* previous?; + string previousLink?; + object {}* self?; + string selfLink?; + object {}* edit?; + string editLink?; + array [ + object {}*; + ] items?; + }* data?; + object { + integer code?; + string message?; + array [ + object { + string domain?; + string reason?; + string message?; + string location?; + string locationType?; + string extendedHelp?; + string sendReport?; + }*; + ] errors?; + }* error?; +}*; + + +

The JSON object has a few top-level properties, followed by either a data object or an error object, but not both. An explanation of each of these properties can be found below.

+
+ +

The top-level of the JSON object may contain the following properties.

+ + +Property Value Type: string
Parent: - +
+ +

Represents the desired version of the service API in a request, and the version of the service API that's served in the response. apiVersion should always be present. This is not related to the version of the data. Versioning of data should be handled through some other mechanism such as etags.

Example:

+ +{ "apiVersion": "2.1" } + + + +
+ + +Property Value Type: string
Parent: - +
+ +

Client sets this value and server echos data in the response. This is useful in JSON-P and batch situations , where the user can use the context to correlate responses with requests. This property is a top-level property because the context should present regardless of whether the response was successful or an error. context differs from id in that context is specified by the user while id is assigned by the service.

Example:

Request #1:

+ +https://www.google.com/myapi?context=bart + + +

Request #2:

+ +https://www.google.com/myapi?context=lisa + + +

Response #1:

+ +{ + "context": "bart", + "data": { + "items": [] + } +} + + +

Response #2:

+ +{ + "context": "lisa", + "data": { + "items": [] + } +} + + +

Common JavaScript handler code to process both responses:

+ +function handleResponse(response) { + if (response.result.context == "bart") { + // Update the "Bart" section of the page. + } else if (response.result.context == "lisa") { + // Update the "Lisa" section of the page. + } +} + + + +
+ + +Property Value Type: string
Parent: - +
+ +

A server supplied identifier for the response (regardless of whether the response is a success or an error). This is useful for correlating server logs with individual responses received at a client.

Example:

+ +{ "id": "1" } + + + +
+ + +Property Value Type: string
Parent: - +
+ +

Represents the operation to perform, or that was performed, on the data. In the case of a JSON request, the method property can be used to indicate which operation to perform on the data. In the case of a JSON response, the method property can indicate the operation performed on the data.

One example of this is in JSON-RPC requests, where method indicates the operation to perform on the params property:

+ +{ + "method": "people.get", + "params": { + "userId": "@me", + "groupId": "@self" + } +} + + + +
+ + +Property Value Type: object
Parent: - +
+ +

This object serves as a map of input parameters to send to an RPC request. It can be used in conjunction with the method property to execute an RPC function. If an RPC function does not need parameters, this property can be omitted.

Example:

+ +{ + "method": "people.get", + "params": { + "userId": "@me", + "groupId": "@self" + } +} + + + +
+ + +Property Value Type: object
Parent: - +
+ +

Container for all the data from a response. This property itself has many reserved property names, which are described below. Services are free to add their own data to this object. A JSON response should contain either a data object or an error object, but not both. If both data and error are present, the error object takes precedence.

+ +
+ + +Property Value Type: object
Parent: - +
+ +

Indicates that an error has occurred, with details about the error. The error format supports either one or more errors returned from the service. A JSON response should contain either a data object or an error object, but not both. If both data and error are present, the error object takes precedence.

Example:

+ +{ + "apiVersion": "2.0", + "error": { + "code": 404, + "message": "File Not Found", + "errors": [{ + "domain": "Calendar", + "reason": "ResourceNotFoundException", + "message": "File Not Found + }] + } +} + + + +
+
+ +

The data property of the JSON object may contain the following properties.

+ + +Property Value Type: string
Parent: data +
+ +

The kind property serves as a guide to what type of information this particular object stores. It can be present at the data level, or at the items level, or in any object where its helpful to distinguish between various types of objects. If the kind object is present, it should be the first property in the object (See the "Property Ordering" section below for more details).

Example:

+ +// "Kind" indicates an "album" in the Picasa API. +{"data": {"kind": "album"}} + + + +
+ + +Property Value Type: string
Parent: data +
+ +

Represents the fields present in the response when doing a partial GET, or the fields present in a request when doing a partial PATCH. This property should only exist during a partial GET/PATCH, and should not be empty.

Example:

+ +{ + "data": { + "kind": "user", + "fields": "author,id", + "id": "bart", + "author": "Bart" + } +} + + + +
+ + +Property Value Type: string
Parent: data +
+ +

Represents the etag for the response. Details about ETags in the GData APIs can be found here: https://code.google.com/apis/gdata/docs/2.0/reference.html#ResourceVersioning

Example:

+ +{"data": {"etag": "W/"C0QBRXcycSp7ImA9WxRVFUk.""}} + + + +
+ + +Property Value Type: string
Parent: data +
+ +

A globally unique string used to reference the object. The specific details of the id property are left up to the service.

Example:

+ +{"data": {"id": "12345"}} + + + +
+ + +Property Value Type: string (formatted as specified in BCP 47)
Parent: data (or any child element) +
+ +

Indicates the language of the rest of the properties in this object. This property mimics HTML's lang property and XML's xml:lang properties. The value should be a language value as defined in BCP 47. If a single JSON object contains data in multiple languages, the service is responsible for developing and documenting an appropriate location for the lang property.

Example:

+ +{"data": { + "items": [ + { "lang": "en", + "title": "Hello world!" }, + { "lang": "fr", + "title": "Bonjour monde!" } + ]} +} + + +
+ + +Property Value Type: string (formatted as specified in RFC 3339)
Parent: data +
+ +

Indicates the last date/time (RFC 3339) the item was updated, as defined by the service.

Example:

+ +{"data": {"updated": "2007-11-06T16:34:41.000Z"}} + + + +
+ + +Property Value Type: boolean
Parent: data (or any child element) +
+ +

A marker element, that, when present, indicates the containing entry is deleted. If deleted is present, its value must be true; a value of false can cause confusion and should be avoided.

Example:

+ +{"data": { + "items": [ + { "title": "A deleted entry", + "deleted": true + } + ]} +} + + + +
+ + +Property Value Type: array
Parent: data +
+ +

The property name items is reserved to represent an array of items (for example, photos in Picasa, videos in YouTube). This construct is intended to provide a standard location for collections related to the current result. For example, the JSON output could be plugged into a generic pagination system that knows to page on the items array. If items exists, it should be the last property in the data object (See the "Property Ordering" section below for more details).

Example:

+ +{ + "data": { + "items": [ + { /* Object #1 */ }, + { /* Object #2 */ }, + ... + ] + } +} + + + +
+
+ +

The following properties are located in the data object, and help page through a list of items. Some of the language and concepts are borrowed from the OpenSearch specification.

The paging properties below allow for various styles of paging, including:

  • Previous/Next paging - Allows user's to move forward and backward through a list, one page at a time. The nextLink and previousLink properties (described in the "Reserved Property Names for Links" section below) are used for this style of paging.
  • Index-based paging - Allows user's to jump directly to a specific item position within a list of items. For example, to load 10 items starting at item 200, the developer may point the user to a url with the query string ?startIndex=200.
  • Page-based paging - Allows user's to jump directly to a specific page within the items. This is similar to index-based paging, but saves the developer the extra step of having to calculate the item index for a new page of items. For example, rather than jump to item number 200, the developer could jump to page 20. The urls during page-based paging could use the query string ?page=1 or ?page=20. The pageIndex and totalPages properties are used for this style of paging.

An example of how to use these properties to implement paging can be found at the end of this guide.

+ + +Property Value Type: integer
Parent: data +
+ +

The number of items in this result set. Should be equivalent to items.length, and is provided as a convenience property. For example, suppose a developer requests a set of search items, and asks for 10 items per page. The total set of that search has 14 total items. The first page of items will have 10 items in it, so both itemsPerPage and currentItemCount will equal "10". The next page of items will have the remaining 4 items; itemsPerPage will still be "10", but currentItemCount will be "4".

Example:

+ +{ + "data": { + // "itemsPerPage" does not necessarily match "currentItemCount" + "itemsPerPage": 10, + "currentItemCount": 4 + } +} + + + +
+ + +Property Value Type: integer
Parent: data +
+ +

The number of items in the result. This is not necessarily the size of the data.items array; if we are viewing the last page of items, the size of data.items may be less than itemsPerPage. However the size of data.items should not exceed itemsPerPage.

Example:

+ +{ + "data": { + "itemsPerPage": 10 + } +} + + + +
+ + +Property Value Type: integer
Parent: data +
+ +

The index of the first item in data.items. For consistency, startIndex should be 1-based. For example, the first item in the first set of items should have a startIndex of 1. If the user requests the next set of data, the startIndex may be 10.

Example:

+ +{ + "data": { + "startIndex": 1 + } +} + + + +
+ + +Property Value Type: integer
Parent: data +
+ +

The total number of items available in this set. For example, if a user has 100 blog posts, the response may only contain 10 items, but the totalItems would be 100.

Example:

+ +{ + "data": { + "totalItems": 100 + } +} + + + +
+ + +Property Value Type: string
Parent: data +
+ +

A URI template indicating how users can calculate subsequent paging links. The URI template also has some reserved variable names: {index} representing the item number to load, and {pageIndex}, representing the page number to load.

Example:

+ +{ + "data": { + "pagingLinkTemplate": "https://www.google.com/search/hl=en&q=chicago+style+pizza&start={index}&sa=N" + } +} + + + +
+ + +Property Value Type: integer
Parent: data +
+ +

The index of the current page of items. For consistency, pageIndex should be 1-based. For example, the first page of items has a pageIndex of 1. pageIndex can also be calculated from the item-based paging properties: pageIndex = floor(startIndex / itemsPerPage) + 1.

Example:

+ +{ + "data": { + "pageIndex": 1 + } +} + + + +
+ + +Property Value Type: integer
Parent: data +
+ +

The total number of pages in the result set. totalPages can also be calculated from the item-based paging properties above: totalPages = ceiling(totalItems / itemsPerPage).

Example:

+ +{ + "data": { + "totalPages": 50 + } +} + + + +
+
+ +

The following properties are located in the data object, and represent references to other resources. There are two forms of link properties: 1) objects, which can contain any sort of reference (such as a JSON-RPC object), and 2) URI strings, which represent URIs to resources (and will always be suffixed with "Link").

+ + +Property Value Type: object / string
Parent: data +
+ +

The self link can be used to retrieve the item's data. For example, in a list of a user's Picasa album, each album object in the items array could contain a selfLink that can be used to retrieve data related to that particular album.

Example:

+ +{ + "data": { + "self": { }, + "selfLink": "https://www.google.com/feeds/album/1234" + } +} + + + +
+ + +Property Value Type: object / string
Parent: data +
+ +

The edit link indicates where a user can send update or delete requests. This is useful for REST-based APIs. This link need only be present if the user can update/delete this item.

Example:

+ +{ + "data": { + "edit": { }, + "editLink": "https://www.google.com/feeds/album/1234/edit" + } +} + + + +
+ + +Property Value Type: object / string
Parent: data +
+ +

The next link indicates how more data can be retrieved. It points to the location to load the next set of data. It can be used in conjunction with the itemsPerPage, startIndex and totalItems properties in order to page through data.

Example:

+ +{ + "data": { + "next": { }, + "nextLink": "https://www.google.com/feeds/album/1234/next" + } +} + + + +
+ + +Property Value Type: object / string
Parent: data +
+ +

The previous link indicates how more data can be retrieved. It points to the location to load the previous set of data. It can be used in conjunction with the itemsPerPage, startIndex and totalItems properties in order to page through data.

Example:

+ +{ + "data": { + "previous": { }, + "previousLink": "https://www.google.com/feeds/album/1234/next" + } +} + + + +
+
+ +

The error property of the JSON object may contain the following properties.

+ + +Property Value Type: integer
Parent: error +
+ +

Represents the code for this error. This property value will usually represent the HTTP response code. If there are multiple errors, code will be the error code for the first error.

Example:

+ +{ + "error":{ + "code": 404 + } +} + + + +
+ + +Property Value Type: string
Parent: error +
+ +

A human readable message providing more details about the error. If there are multiple errors, message will be the message for the first error.

Example:

+ +{ + "error":{ + "message": "File Not Found" + } +} + + + +
+ + +Property Value Type: array
Parent: error +
+ +

Container for any additional information regarding the error. If the service returns multiple errors, each element in the errors array represents a different error.

Example:

+ +{ "error": { "errors": [] } } + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

Unique identifier for the service raising this error. This helps distinguish service-specific errors (i.e. error inserting an event in a calendar) from general protocol errors (i.e. file not found).

Example:

+ +{ + "error":{ + "errors": [{"domain": "Calendar"}] + } +} + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

Unique identifier for this error. Different from the error.code property in that this is not an http response code.

Example:

+ +{ + "error":{ + "errors": [{"reason": "ResourceNotFoundException"}] + } +} + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

A human readable message providing more details about the error. If there is only one error, this field will match error.message.

Example:

+ +{ + "error":{ + "code": 404 + "message": "File Not Found", + "errors": [{"message": "File Not Found"}] + } +} + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

The location of the error (the interpretation of its value depends on locationType).

Example:

+ +{ + "error":{ + "errors": [{"location": ""}] + } +} + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

Indicates how the location property should be interpreted.

Example:

+ +{ + "error":{ + "errors": [{"locationType": ""}] + } +} + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

A URI for a help text that might shed some more light on the error.

Example:

+ +{ + "error":{ + "errors": [{"extendedHelper": "http://url.to.more.details.example.com/"}] + } +} + + + +
+ + +Property Value Type: string
Parent: error.errors +
+ +

A URI for a report form used by the service to collect data about the error condition. This URI should be preloaded with parameters describing the request.

Example:

+ +{ + "error":{ + "errors": [{"sendReport": "https://report.example.com/"}] + } +} + + + +
+
+ +

Properties can be in any order within the JSON object. However, in some cases the ordering of properties can help parsers quickly interpret data and lead to better performance. One example is a pull parser in a mobile environment, where performance and memory are critical, and unnecessary parsing should be avoided.

+ + +kind should be the first property + + +

Suppose a parser is responsible for parsing a raw JSON stream into a specific object. The kind property guides the parser to instantiate the appropriate object. Therefore it should be the first property in the JSON object. This only applies when objects have a kind property (usually found in the data and items properties).

+ +
+ + +items should be the last property in the data object + + +

This allows all of the collection's properties to be read before reading each individual item. In cases where there are a lot of items, this avoids unnecessarily parsing those items when the developer only needs fields from the data.

+ +
+ + + +// The "kind" property distinguishes between an "album" and a "photo". +// "Kind" is always the first property in its parent object. +// The "items" property is the last property in the "data" object. +{ + "data": { + "kind": "album", + "title": "My Photo Album", + "description": "An album in the user's account", + "items": [ + { + "kind": "photo", + "title": "My First Photo" + } + ] + } +} + + + + +
+ + + +Here's an example of the YouTube JSON API's response object. You can learn more about YouTube's JSON API here: https://code.google.com/apis/youtube/2.0/developers_guide_jsonc.html. + + + +{ + "apiVersion": "2.0", + "data": { + "updated": "2010-02-04T19:29:54.001Z", + "totalItems": 6741, + "startIndex": 1, + "itemsPerPage": 1, + "items": [ + { + "id": "BGODurRfVv4", + "uploaded": "2009-11-17T20:10:06.000Z", + "updated": "2010-02-04T06:25:57.000Z", + "uploader": "docchat", + "category": "Animals", + "title": "From service dog to SURFice dog", + "description": "Surf dog Ricochets inspirational video ...", + "tags": [ + "Surf dog", + "dog surfing", + "dog", + "golden retriever", + ], + "thumbnail": { + "default": "https://i.ytimg.com/vi/BGODurRfVv4/default.jpg", + "hqDefault": "https://i.ytimg.com/vi/BGODurRfVv4/hqdefault.jpg" + }, + "player": { + "default": "https://www.youtube.com/watch?v=BGODurRfVv4&feature=youtube_gdata", + "mobile": "https://m.youtube.com/details?v=BGODurRfVv4" + }, + "content": { + "1": "rtsp://v5.cache6.c.youtube.com/CiILENy73wIaGQn-Vl-0uoNjBBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp", + "5": "https://www.youtube.com/v/BGODurRfVv4?f=videos&app=youtube_gdata", + "6": "rtsp://v7.cache7.c.youtube.com/CiILENy73wIaGQn-Vl-0uoNjBBMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp" + }, + "duration": 315, + "rating": 4.96, + "ratingCount": 2043, + "viewCount": 1781691, + "favoriteCount": 3363, + "commentCount": 1007, + "commentsAllowed": true + } + ] + } +} + + + + + + +This example demonstrates how the Google search items could be represented as a JSON object, with special attention to the paging variables. + + +

This sample is for illustrative purposes only. The API below does not actually exist.

Here's a sample Google search results page:

Here's a sample JSON representation of this page:

+ +{ + "apiVersion": "2.1", + "id": "1", + "data": { + "query": "chicago style pizza", + "time": "0.1", + "currentItemCount": 10, + "itemsPerPage": 10, + "startIndex": 11, + "totalItems": 2700000, + "nextLink": "https://www.google.com/search?hl=en&q=chicago+style+pizza&start=20&sa=N" + "previousLink": "https://www.google.com/search?hl=en&q=chicago+style+pizza&start=0&sa=N", + "pagingLinkTemplate": "https://www.google.com/search/hl=en&q=chicago+style+pizza&start={index}&sa=N", + "items": [ + { + "title": "Pizz'a Chicago Home Page" + // More fields for the search results + } + // More search results + ] + } +} + + +

Here's how each of the colored boxes from the screenshot would be represented (the background colors correspond to the colors in the images above):

  • Results 11 - 20 of about 2,700,000 = startIndex
  • Results 11 - 20 of about 2,700,000 = startIndex + currentItemCount - 1
  • Results 11 - 20 of about 2,700,000 = totalItems
  • Search results = items (formatted appropriately)
  • Previous/Next = previousLink / nextLink
  • Numbered links in "Gooooooooooogle" = Derived from "pageLinkTemplate". The developer is responsible for calculating the values for {index} and substituting those values into the "pageLinkTemplate". The pageLinkTemplate's {index} variable is calculated as follows:
    • Index #1 = 0 * itemsPerPage = 0
    • Index #2 = 2 * itemsPerPage = 10
    • Index #3 = 3 * itemsPerPage = 20
    • Index #N = N * itemsPerPage
+ +
+
+ + + +A list of reserved JavaScript words that should be avoided in property names. + + +

The words below are reserved by the JavaScript language and cannot be referred to using dot notation. The list represents best knowledge of keywords at this time; the list may change or vary based on your specific execution environment.

From the ECMAScript Language Specification 5th Edition

+ +abstract +boolean break byte +case catch char class const continue +debugger default delete do double +else enum export extends +false final finally float for function +goto +if implements import in instanceof int interface +let long +native new null +package private protected public +return +short static super switch synchronized +this throw throws transient true try typeof +var volatile void +while with +yield + + +
+
+
+ +

+Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the Apache 2.0 License. +

+

+Revision 0.9 +

+ +
+
+ +
diff --git a/jsoncstyleguide_example_01.png b/jsoncstyleguide_example_01.png new file mode 100644 index 000000000..d7a86ee55 Binary files /dev/null and b/jsoncstyleguide_example_01.png differ diff --git a/jsoncstyleguide_example_02.png b/jsoncstyleguide_example_02.png new file mode 100644 index 000000000..d3e82432c Binary files /dev/null and b/jsoncstyleguide_example_02.png differ diff --git a/lispguide.xml b/lispguide.xml new file mode 100644 index 000000000..519e1a0ba --- /dev/null +++ b/lispguide.xml @@ -0,0 +1,3887 @@ + + + + + +

+ +Revision 1.28 +

+ + +
+Robert Brown +
+
+ François-René Rideau +
+ +
+ In memoriam Dan Weinreb +
+ +

+Patterns mean "I have run out of language." — Rich Hickey +

+ + + + + + + This style guide contains many details + that are initially hidden from view. + They are marked by the triangle icon, which you see here on your left. + Click it now. You should see "Hooray" appear below. + + +

+ Hooray! Now you know you can expand points to get more details. + Alternatively, there's an "expand all" at the top of this document. +

+ +
+
+ +

+ Common Lisp is a powerful multiparadigm programming language. + With great power comes great responsibility. +

+

+ This guide recommends formatting and stylistic choices + designed to make your code easier for other people to understand. + For those internal applications and free software libraries that + we develop at Google, + you should keep within these guidelines when making changes. + Note however that each project has its own rules and customs + that complement or override these general guidelines; + the speed-oriented QPX low fare search engine notably + has a very different style and feel from the QRes reservation system. +

+

+ If you're writing Common Lisp code outside Google, + we invite you to consider these guidelines. + You may find some of them useful + where they don't conflict with other priorities you have. + We welcome remarks and constructive feedback + on how to improve our guide, and + on what alternate styles work for you and why. +

+ +

+ This guide is not a Common Lisp tutorial. + For basic information about the language, please consult + Practical Common Lisp. + For a language reference, please consult the + Common Lisp HyperSpec. + For more detailed style guidance, take (with a pinch of salt) + a look at Peter Norvig and Kent Pitman's + style guide. +

+
+
+ + + + Each guideline's level of importance is indicated + by use of the following keywords and phrases, adapted from + RFC 2119. + + + + + + + + + + + + + + + + + + + + + + + +
MUST +

+ This word, or the terms "REQUIRED" or "SHALL", + means that the guideline is an absolute requirement. + You must ask permission to violate a MUST. +

+
MUST NOT +

+ This phrase, or the phrase "SHALL NOT", + means that the guideline is an absolute prohibition. + You must ask permission to violate a MUST NOT. +

+
SHOULD +

+ This word, or the adjective "RECOMMENDED", means that + there may exist valid reasons in particular circumstances + to ignore the demands of the guideline, but + the full implications must be understood and carefully weighed + before choosing a different course. + You must ask forgiveness for violating a SHOULD. +

+
SHOULD NOT +

+ This phrase, or the phrase "NOT RECOMMENDED", means that + there may exist valid reasons in particular circumstances + to ignore the prohibitions of this guideline, but + the full implications should be understood and carefully weighed + before choosing a different course. + You must ask forgiveness for violating a SHOULD NOT. +

+
MAY +

+ This word, or the adjective "OPTIONAL", + means that an item is truly optional. +

+
+

+ Unlike RFCs, we don't capitalize every instance of one of the above + keywords when it is used. +

+ +
+ + + There are cases where transgression of some of these rules + is useful or even necessary. + In some cases, you must seek permission or obtain forgiveness + from the proper people. + + +

+ Permission comes from the owners of your project. +

+ +

+ Forgiveness is requested in a comment + near the point of guideline violation, + and is granted by your code reviewer. + The original comment should be signed by you, and + the reviewer should add a signed approval to the comment at review time. +

+ + +
+ + + You MUST follow conventions. They are not optional. + + +

+ Some of these guidelines are motivated by universal principles of good programming. + Some guidelines are motivated by technical peculiarities of Common Lisp. + Some guidelines were once motivated by a technical reason, + but the guideline remained after the reason subsided. + Some guidelines, such those about as comments and indentation, + are based purely on convention, rather than on clear technical merit. + Whatever the case may be, you must still follow these guidelines, + as well as other conventional guidelines + that have not been formalized in this document. +

+

+ You MUST follow conventions. + They are important for readability. + When conventions are followed by default, + violations of the convention are a signal + that something notable is happening and deserves attention. + When conventions are systematically violated, + violations of the convention are a distracting noise + that needs to be ignored. +

+

+ Conventional guidelines are indoctrination. + Their purpose is to make you follow the mores of the community, + + so you can more effectively cooperate with existing members. + It is still useful to distinguish the parts that are technically motivated + from the parts that are mere conventions, + so you know when best to defy conventions for good effect, + and when not to fall into the pitfalls that the conventions are there to help avoid. +

+ +
+ + + Fix old code as you go. + + +

+ A lot of our code was written before these guidelines existed. + You should fix violations as you encounter them + in the course of your normal coding. +

+

+ You must not fix violations en masse + without warning other developers and coordinating with them, + so as not to make the merging of large branches + more difficult than it already is. +

+ +
+ + + There are many topics for additional standardization + not covered by current version of this document, + but deferred to future versions. + + +
    +
  • + File and directory structure +
  • +
  • + Packages and modularity +
  • +
  • + Threads and locking +
  • +
  • + How to add configurable components +
  • +
  • + CLOS style: initforms, slot and accessor names, etc. +
  • +
  • + Recommendations on max number of slots per class. +
  • +
  • + More concrete examples of good code: +
      +
    • + exceptions +
    • +
    • + transactions, with retry +
    • +
    • + XML +
    • +
    • + typing +
    • +
    • + encapsulation / abstraction +
    • +
    • + class and slot names +
    • +
    • + etc. +
    • +
    +
  • +
  • + When (not) to use conditional compilation: +
      +
    • + modifying the product +
    • +
    • + conditional debugging/console output/etc. +
    • +
    • + "temporarily" commenting-out blocks of code +
    • +
    • + etc. +
    • +
    +
  • +
+ +
+
+ + + + There are some basic principles for team software development + that every developer must keep in mind. + Whenever the detailed guidelines are inadequate, confusing or contradictory, + refer back to these principles for guidance: +
    +
  • + Every developer's code must be easy for another developer + to read, understand, and modify + — even if the first developer isn't around to explain it. + (This is the "hit by a truck" principle.) +
  • +
  • + Everybody's code should look the same. + Ideally, there should be no way to look at lines of code + and recognize it as "Fred's code" by its style. +
  • +
  • + Be precise. +
  • +
  • + Be concise. +
  • +
  • + KISS — Keep It Simple, Stupid. +
  • +
  • + Use the smallest hammer for the job. +
  • +
  • + Use common sense. +
  • +
  • + Keep related code together. + Minimize the amount of jumping around + someone has to do to understand an area of code. +
  • +
+
+ + +
+ + +

+ When making decisions about how to write a given piece of + code, aim for the following -ilities in this priority order: +

+
    +
  • + Usability by the customer +
  • +
  • + Debuggability/Testability +
  • +
  • + Readability/Comprehensibility +
  • +
  • + Extensibility/Modifiability +
  • +
  • + Efficiency (of the Lisp code at runtime) +
  • +
+
+ +

+ Most of these are obvious. +

+

+ Usability by the customer means that the system has to do what the + customer requires; it has to handle the customer's transaction + volumes, uptime requirements; etc. +

+

+ For the Lisp efficiency point, + given two options of equivalent complexity, + pick the one that performs better. + (This is often the same as the one that conses less, + i.e. allocates less storage from the heap.) +

+

+ Given two options where one is more complex than the other, + pick the simpler option and revisit the decision only if + profiling shows it to be a performance bottleneck. +

+

+ However, avoid premature optimization. + Don't add complexity to speed up something that runs rarely, + since in the long run, it matters less whether such code is fast. +

+ +
+ + + To build code that is robust and maintainable, + it matters a lot how the code is divided into components, + how these components communicate, + how changes propagate as they evolve, + and more importantly + how the programmers who develop these components communicate + as these components evolve. + + +

+ If your work affects other groups, might be reusable across groups, + adds new components, has an impact on other groups + (including QA or Ops), or otherwise isn't purely local, + you must write it up using at least a couple of paragraphs, + and get a design approval from the other parties involved + before starting to write code — or be ready to scratch what you have + when they object. +

+

+ If you don't know or don't care about these issues, + ask someone who does. +

+ +
+ + + Often, the smallest hammer is to use an existing library. + Or one that doesn't exist yet. + In such cases, you are encouraged to use or develop such a library, + but you must take appropriate precautions. + + +
    +
  • + You MUST NOT start a new library + unless you established that none is already available + that can be fixed or completed into becoming what you need. + That's a rule against the NIH syndrome ("Not Invented Here"), + which is particularly strong amongst Lisp hackers. +
  • +
  • + Whichever library, old or new, you pick, you MUST get permission + to incorporate third-party code into the code base. + You must discuss the use of such library + in the appropriate mailing-list, + and have your code reviewed by people knowledgeable in the domain + and/or the Lisp library ecosystem (if any). + Please be ready to argue why this particular solution makes sense + as compared to other available libraries. +
  • +
  • + Some libraries are distributed under licenses not compatible + with the software you're writing, and + must not be considered available for use. + Be aware of these issues, or consult with people who are. +
  • +
+ + +
+ + +

+ If you write a general-purpose library, + or modify an existing open-source library, + you are encouraged to publish the result + separate from your main project and then + have your project import it like any other open-source library. +

+ +
+ +

+ Use your judgment to distinguish + general-purpose versus business-specific code, + and open-source the general-purpose parts, + while keeping the business-specific parts a trade secret. +

+ +

+ Open-Sourcing code has many advantages, + including being able to leverage third parties for development, + letting the development of features be user-directed, + and keeping you honest with respect to code quality. + Whatever code you write, you will have to maintain anyway, + and make sure its quality is high enough to sustain use in production. + There should therefore be no additional burden to Open-Sourcing, + even of code that (at least initially) + is not directly usable by third parties. +

+ + +
+ + + Development process is outside the scope of this document. + However, developers should remember at least these bits: + get reviewed, write tests, eliminate warnings, run tests, avoid mass-changes. + + +

+

+
    +
  • + All code changes must be reviewed. + You should expect that your code will be reviewed by other hackers, + and that you will be assigned other hackers' code to review. + Part of the review criteria will be that code obeys + the coding standards in this document. +
  • +
  • + You must write and check-in tests for new code that you write and old bugs you fix. + There must be a unit test for every API function, + and any previously failing case. + Your work is not truly done until this activity is complete. + Estimating tasks must include the time it takes to produce such tests. +
  • +
  • + Your code must compile + without any compilation error or warning messages whatsoever. + If the compiler issues warnings that should be ignored, + muffle those warnings using the + UIOP:WITH-MUFFLED-COMPILER-CONDITIONS and + UIOP:*UNINTERESTING-COMPILER-CONDITIONS* + framework (part of UIOP, part of ASDF 3), + either around the entire project, or around individual files + (using ASDF's :around-compile hooks). +
  • +
  • + All code should be checked in an appropriate source control system, + in a way that allows for complete reproducibility of + build, test and execution of + the code that is, has been or may be deployed. +
  • +
  • + You must run the "precheckin" tests, and each component must pass + its unit tests successfully before you commit any code. +
  • +
  • + You should incorporate code coverage into your testing process. + Tests are not sufficient + if they do not cover all new and updated code; + code that for whatever reason cannot be included in coverage results + should be clearly marked as such including the reason. +
  • +
  • + Many people develop on branches. + You must get permission to undertake mass-changes + (e.g. mass reindentations) + so that we can coordinate in advance, + and give branch residents time to get back on the mainline +
  • +
+ +
+
+ + + +

+ You must use correct spelling in your comments, + and most importantly in your identifiers. +

+

+ When several correct spellings exist (including American vs English), + and there isn't a consensus amongst developers as which to use, + you should choose the shorter spelling. +

+

+ You must use only common and domain-specific abbreviations, and + must be consistent with these abbreviations. You may abbreviate + lexical variables of limited scope in order to avoid overly-long + symbol names. +

+
+ +

+ If you're not sure, consult a dictionary, + Google for alternative spellings, + or ask a local expert. +

+

+ Here are examples of choosing the correct spelling: +

+
    +
  • + Use "complimentary" in the sense of a meal or beverage + that is not paid for by the recipient, not "complementary". +
  • +
  • + Use "existent" and "nonexistent", not "existant". + Use "existence", not "existance". +
  • +
  • + Use "hierarchy" not "heirarchy". +
  • +
  • + Use "precede" not "preceed". +
  • +
  • + Use "weird", not "wierd". +
  • +
+

+ Here are examples of choosing the shorter spelling: +

+
    +
  • + Use "canceled", not "cancelled" +
  • +
  • + Use "queuing", not "queueing". +
  • +
  • + Use "signaled", not "signalled"; +
  • +
  • + Use "traveled", not "travelled". +
  • +
  • + Use "aluminum", not "aluminium" +
  • +
  • + Use "oriented", not "orientated" +
  • +
  • + Use "color", not "colour" +
  • +
  • + Use "behavior", not "behaviour" +
  • +
+

+ Make appropriate exceptions for industry standard nomenclature/jargon, + including plain misspellings. + For instance: +

+
    +
  • + Use "referer", not "referrer", in the context of the HTTP protocol. +
  • +
+ + +
+ + + You should format source code so that no line is longer than 100 characters. + + +

+ Some line length restriction is better than none at all. + While old text terminals used to make 80 columns the standard, + these days, allowing 100 columns seems better, + since good style encourages the use of + descriptive variables and function names. +

+ + +
+ + +

+ Indent your code the way a properly configured GNU Emacs does. +

+

+ Maintain a consistent indentation style throughout a project. +

+

+ Indent carefully to make the code easier to understand. +

+
+ +

+ Common Lisp indentation in Emacs is provided by the cl-indent library. + The latest version of cl-indent is packaged with + SLIME + (under contrib/slime-cl-indent.el). After installing SLIME, set up Emacs + to load SLIME automatically using + these instructions, adding slime-indentation to the list of + contrib libraries to be loaded in the call to slime-setup. +

+

+ Ideally, use the default indentation settings provided by + slime-indentation. If necessary, customize indentation parameters to + maintain a consistent indentation style throughout an existing project. + Parameters can be customized using the :variables setting in + define-common-lisp-style. Indentation of specific forms can be + customized using the :indentation setting of define-common-lisp-style. + This is particularly useful when creating forms that behave like macros + or special operators that are indented differently than standard + function calls (e.g. defun, labels, or let). Add a + hook to 'lisp-mode-hook that calls common-lisp-set-style to set + the appropriate style automatically. +

+ + +

+ Use indentation to make complex function applications easier to read. + When an application does not fit on one line + or the function takes many arguments, + consider inserting newlines between the arguments + so that each one is on a separate line. + However, do not insert newlines in a way that makes it hard to tell + how many arguments the function takes + or where an argument form starts and ends. +

+ + ;; Bad + (do-something first-argument second-argument (lambda (x) + (frob x)) fourth-argument last-argument) + + + ;; Better + (do-something first-argument + second-argument + #'(lambda (x) (frob x)) + fourth-argument + last-argument) + + +
+ + +

+ You should include a description at the top of each source file. +

+

+ You should include neither authorship nor copyright information in a source file. +

+
+ +

+ Every source file should begin with a brief description + of the contents of that file. +

+

+ After that description, every file should start the code itself with an + (in-package :package-name) form. +

+

+ After that in-package form, + every file should follow with any file-specific + (declaim (optimize ...)) declaration + that is not covered by an ASDF :around-compile hook. +

+ + ;;;; Variable length encoding for integers and floating point numbers. + + (in-package #:varint) + (declaim #.*optimize-default*) + +

+ You should not include authorship information at the top of a file: + better information is available from version control, + and such a mention will only cause confusion and grief. + Indeed, whoever was the main author at the time such a mention was included + might not be who eventually made the most significant contributions to the file, + and even less who is responsible for the file at the moment. + +

+

+ You should not include copyright information in individual source code files. + An exception is made for files meant to be disseminated as standalone. +

+ + + +
+ + + Vertical white space: one blank line between top-level forms. + + +

+ You should include one blank line between top-level forms, + such as function definitions. + Exceptionally, blank lines can be omitted + between simple, closely related defining forms of the same kind, + such as a group of related type declarations or constant definitions. +

+ + (defconstant +mix32+ #x12b9b0a1 "pi, an arbitrary number") + (defconstant +mix64+ #x2b992ddfa23249d6 "more digits of pi") + + (defconstant +golden-ratio32+ #x9e3779b9 "the golden ratio") + (defconstant +golden-ratio64+ #xe08c1d668b756f82 "more digits of the golden ratio") + + (defmacro incf32 (x y) + "Like INCF, but for integers modulo 2**32" + `(setf ,x (logand (+ ,x ,y) #xffffffff))) + (defmacro incf64 (x y) + "Like INCF, but for integers modulo 2**64" + `(setf ,x (logand (+ ,x ,y) #xffffffffffffffff))) + +

+ Blank lines can be used to separate parts of a complicated function. + Generally, however, you should break a large function into smaller ones + instead of trying to make it more readable by adding vertical space. + If you can't, you should document with a ;; comment + what each of the separated parts of the function does. +

+

+ You should strive to keep top-level forms, + including comments but excluding the documentation string, of + appropriate length; preferrably short. Forms extending beyond a + single page should be rare and their use should be justfied. + This applies to each of the forms in an eval-when, + rather than to the eval-when itself. + Additionally, defpackage forms may be longer, + since they may include long lists of symbols. +

+ +
+ + + Horizontal white space: none around parentheses. No tabs. + + +

+ You must not include extra horizontal whitespace + before or after parentheses or around symbols. +

+

+ You must not place right parentheses by themselves on a line. + A set of consecutive trailing parentheses must appear on the same line. +

+ + ;; Very Bad + ( defun factorial ( limit ) + ( let (( product 1 )) + ( loop for i from 1 upto limit + do (setf product ( * product i ) ) ) + product + ) + ) + + + ;; Better + (defun factorial (limit) + (let ((product 1)) + (loop for i from 1 upto limit + do (setf product (* product i))) + product)) + +

+ You should use only one space between forms. +

+

+ You should not use spaces to vertically align forms + in the middle of consecutive lines. + An exception is made when the code possesses + an important yet otherwise not visible symmetry + that you want to emphasize. +

+ + ;; Bad + (let* ((low 1) + (high 2) + (sum (+ (* low low) (* high high)))) + ...) + + + ;; Better + (let* ((low 1) + (high 2) + (sum (+ (* low low) (* high high)))) + ...)) + +

+ You must align nested forms if they occur across more than one line. +

+ + ;; Bad + (defun munge (a b c) + (* (+ a b) + c)) + + + ;; Better + (defun munge (a b c) + (* (+ a b) + c)) + +

+ The convention is that the body of a binding form + is indented two spaces after the form. + Any binding data before the body is usually indented four spaces. + Arguments to a function call are aligned with the first argument; + if the first argument is on its own line, + it is aligned with the function name. +

+ + (multiple-value-bind (a b c d) + (function-returning-four-values x y) + (declare (ignore c)) + (something-using a) + (also-using b d)) + +

+ An exception to the rule against lonely parentheses + is made for an eval-when form around several definitions; + in this case, include a comment ; eval-when + after the closing parenthesis. +

+

+ You must set your editor to + avoid inserting tab characters in the files you edit. + Tabs cause confusion when editors disagree + on how many spaces they represent. + In Emacs, do (setq-default indent-tabs-mode nil). +

+ +
+
+ + + + + You should use document strings on all visible functions + to explain how to use your code. + + +

+ Unless some bit of code is painfully self-explanatory, + document it with a documentation string (also known as docstring). +

+

+ Documentation strings are destined to be read + by the programmers who use your code. + They can be extracted from functions, types, classes, variables and macros, + and displayed by programming tools, such as IDEs, + or by REPL queries such as (describe 'foo); + web-based documentation or other reference works + can be created based on them. + Documentation strings are thus the perfect locus to document your API. + They should describe how to use the code + (including what pitfalls to avoid), + as opposed to how the code works (and where more work is needed), + which is what you'll put in comments. +

+

+ Supply a documentation string when defining + top-level functions, types, classes, variables and macros. + Generally, add a documentation string wherever the language allows. +

+

+ For functions, the docstring should describe the function's contract: + what the function does, + what the arguments mean, + what values are returned, + what conditions the function can signal. + It should be expressed at the appropriate level of abstraction, + explaining the intended meaning rather than, say, just the syntax. + In documentation strings, capitalize the names of Lisp symbols, + such as function arguments. + For example, "The value of LENGTH should be an integer." +

+ + (defun small-prime-number-p (n) + "Return T if N, an integer, is a prime number. Otherwise, return NIL." + (cond ((or (< n 2)) + nil) + ((= n 2) + t) + ((divisorp 2 n) + nil) + (t + (loop for i from 3 upto (sqrt n) by 2 + never (divisorp i n))))) + + + (defgeneric table-clear (table) + (:documentation + "Like clrhash, empties the TABLE of all + associations, and returns the table itself.")) + +

+ A long docstring may usefully + begin with a short, single-sentence summary, + followed by the larger body of the docstring. +

+

+ When the name of a type is used, + the symbol may be quoted by surrounding it with + a back quote at the beginning and a single quote at the end. + Emacs will highlight the type, and the highlighting serves + as a cue to the reader that M-. + will lead to the symbol's definition. +

+ + (defun bag-tag-expected-itinerary (bag-tag) + "Return a list of `legacy-pnr-pax-segment' objects representing + the expected itinerary of the `bag-tag' object, BAG-TAG." + ...) + +

+ Every method of a generic function should be independently documented + when the specialization affects what the method does, + beyond what is described in its generic function's docstring. +

+

+ When you fix a bug, + consider whether what the fixed code does is obviously correct or not; + if not, you must add a comment explaining + the reason for the code in terms of fixing the bug. + Adding the bug number, if any, is also recommended. +

+ +
+ + + You must use the appropriate number of semicolons to introduce comments. + + +

+ Comments are explanations to the future maintainers of the code. + Even if you're the only person who will ever see and touch the code, + even if you're either immortal and never going to quit, + or unconcerned with what happens after you leave + (and have your code self-destruct in such an eventuality), + you may find it useful to comment your code. + Indeed, by the time you revisit your code, + weeks, months or years later, + you will find yourself a different person from the one who wrote it, + and you will be grateful to that previous self + for making the code readable. +

+

+ You must comment anything complicated + so that the next developer can understand what's going on. + (Again, the "hit by a truck" principle.) +

+

+ Also use comments as a way to guide those who read the code, + so they know what to find where. +

+
    +
  • + File headers and important comments + that apply to large sections of code in a source file + should begin with four semicolons. +
  • +
  • + You should use three semicolons + to begin comments that apply to just + one top-level form or small group of top-level forms. +
  • +
  • + Inside a top-level form, you should use two semicolons + to begin a comment if it appears between lines. +
  • +
  • + You should use one semicolon if it is a parenthetical remark + and occurs at the end of a line. + You should use spaces to separate the comment + from the code it refers to so the comment stands out. + You should try to vertically align + consecutive related end-of-line comments. +
  • +
+ + ;;;; project-euler.lisp + ;;;; File-level comments or comments for large sections of code. + + ;;; Problems are described in more detail here: https://projecteuler.net/ + + ;;; Divisibility + ;;; Comments that describe a group of definitions. + + (defun divisorp (d n) + (zerop (mod n d))) + + (defun proper-divisors (n) + ...) + + (defun divisors (n) + (cons n (proper-divisors n))) + + ;;; Prime numbers + + (defun small-prime-number-p (n) + (cond ((or (< n 2)) + nil) + ((= n 2) ; parenthetical remark here + t) ; continuation of the remark + ((divisorp 2 n) + nil) ; different remark + ;; Comment that applies to a section of code. + (t + (loop for i from 3 upto (sqrt n) by 2 + never (divisorp i n))))) + +

+ You should include a space between the semicolon and the text of the comment. +

+ +
+ + + You should punctuate documentation correctly. + + +

+ When a comment is a full sentence, + you should capitalize the initial letter of the first word + and end the comment with a period. + In general, you should use correct punctuation. +

+ +
+ + + You must follow the convention of using TODO comments + for code requiring special attention. + For code using unobvious forms, you must include a comment. + + +

+ For comments requiring special attention, such as + incomplete code, todo items, questions, breakage, and danger, + include a TODO comment indicating the type of problem, + its nature, and any notes on how it may be addressed. +

+

+ The comments begin with TODO in all capital letters, + followed by the + + name, e-mail address, or other identifier + of the person + with the best context about the problem referenced by the TODO. + The main purpose is to have a consistent TODO that + can be searched to find out how to get more details upon + request. A TODO is not a commitment that the + person referenced will fix the problem. Thus when you create + a TODO, + it is almost always your + name + that is given. +

+

+ When signing comments, + you should use your username (for code within the company) + or full email address (for code visible outside the company), + not just initials. + +

+ + ;;--- TODO(george@gmail.com): Refactor to provide a better API. + +

+ Be specific when indicating times or software releases + in a TODO comment and use + YYYY-MM-DD + format for dates to make automated processing of such dates easier, + e.g., 2038-01-20 for the end of the 32-bit signed time_t. +

+ + ;;--- TODO(brown): Remove this code after release 1.7 or before 2012-11-30. + +

+ For code that uses unobvious forms to accomplish a task, you must include a comment + stating the purpose of the form and the task it accomplishes. +

+ +
+ + + You should document DSLs and + any terse program in a DSL. + + +

+ You should design your Domain Specific Language + to be easy to read and understand by people familiar with the domain. +

+

+ You must properly document all your Domain Specific Language. +

+

+ Sometimes, your DSL is designed for terseness. + In that case, it is important to document what each program does, + if it's not painfully obvious from the context. +

+

+ Notably, when you use regular expressions + (e.g. with the CL-PPCRE package), + you MUST ALWAYS put in a comment + (usually a two-semicolon comment on the previous line) + explaining, at least basically, what the regular expression does, + or what the purpose of using it is. + The comment need not spell out every bit of the syntax, but + it should be possible for someone to follow the logic of the code + without actually parsing the regular expression. +

+ +
+ +
+ + + + + You should use lower case. + You should follow the rules for Spelling and Abbreviations + You should follow punctuation conventions. + + +

+ Use lower case for all symbols. + Consistently using lower case makes searching for symbol names easier + and is more readable. +

+

+ Note that Common Lisp is case-converting, + and that the symbol-name of your symbols + will be upper case. + Because of this case-converting, + attempts to distinguish symbols by case are defeated, + and only result in confusion. + While it is possible to escape characters in symbols + to force lower case, + you should not use this capability + unless this is somehow necessary + to interoperate with third-party software. +

+

+ Place hyphens between all the words in a symbol. + If you can't easily say an identifier out loud, + it is probably badly named. +

+

+ You must not use "/" or "." + instead of "-" + unless you have a well-documented overarching reason to, + and permission from other hackers who review your proposal. +

+

+ See the section on Spelling and Abbreviations + for guidelines on using abbreviations. +

+ + ;; Bad + (defvar *default-username* "Ann") + (defvar *max-widget-cnt* 200) + + + ;; Better + (defvar *default-user-name* "Ann") + (defvar *maximum-widget-count* 200) + +

+ There are conventions in Common Lisp + for the use of punctuation in symbols. + You should not use punctuation in symbols outside these conventions. +

+

+ Unless the scope of a variable is very small, + do not use overly short names like + i and zq. +

+ +
+ + + Name your variables according to their intent, + not their content. + + +

+ You should name a variable according + to the high-level concept that it represents, + not according to the low-level implementation details + of how the concept is represented. +

+

+ Thus, you should avoid embedding + data structure or aggregate type names, + such as list, array, or + hash-table inside variable names, + unless you're writing a generic algorithm that applies to + arbitrary lists, arrays, hash-tables, etc. + In that case it's perfectly OK to name a variable + list or array. +

+

+ Indeed, you should be introducing new abstract data types + with DEFCLASS or DEFTYPE, + whenever a new kind of intent appears for objects in your protocols. + Functions that manipulate such objects generically may then + use variables the name of which reflect that abstract type. +

+

+ For example, if a variable's value is always a row + (or is either a row or NIL), + it's good to call it row or first-row + or something like that. + It is alright is row has been + DEFTYPE'd to STRING — + precisely because you have abstracted the detail away, + and the remaining salient point is that it is a row. + You should not name the variable STRING in this context, + except possibly in low-level functions that specifically manipulate + the innards of rows to provide the suitable abstraction. +

+

+ Be consistent. + If a variable is named row in one function, + and its value is being passed to a second function, + then call it row rather than, say, value + (this was a real case). +

+ +
+ + + Name globals according to convention. + + +

+ The names of global constants should start and end + with plus characters. +

+

+ Global variable names should start and end with asterisks + (also known in this context as earmuffs). +

+

+ In some projects, parameters that are not meant + to be usually modified or bound under normal circumstances + (but may be during experimentation or exceptional situations) + should start (but do not end) with a dollar sign. + If such a convention exists within your project, + you should follow it consistently. + Otherwise, you should avoid naming variables like this. +

+

+ Common Lisp does not have global lexical variables, + so a naming convention is used to ensure that globals, + which are dynamically bound, + never have names that overlap with local variables. + It is possible to fake global lexical variables + with a differently named global variable + and a DEFINE-SYMBOL-MACRO. + You should not use this trick, + unless you first publish a library that abstracts it away. +

+ + (defconstant +hash-results+ #xbd49d10d10cbee50) + + (defvar *maximum-search-depth* 100) + + +
+ + + Names of predicate functions and variables end with a "P". + + +

+ You should name boolean-valued functions and variables with a + trailing "P" or "-P", + to indicate they are predicates. + Generally, you should use + "P" when the rest of the function name is one word + and "-P" when it is more than one word. +

+

+ A rationale for this convention is given in + the CLtL2 chapter on predicates. +

+

+ For uniformity, you should follow the convention above, + and not one of the alternatives below. +

+

+ An alternative rule used in some existing packages + is to always use "-P". + Another alternative rule used in some existing packages + is to always use "?". + When you develop such a package, + you must be consistent with the rest of the package. + When you start a new package, + you should not use such an alternative rule + without a very good documented reason. +

+ +
+ + + You should not include a library or package name + as a prefix within the name of symbols. + + +

+ When naming a symbol (external or internal) in a package, + you should not include the package name + as a prefix within the name of the symbol. + Naming a symbol this way makes it awkward to use + from a client package accessing the symbol + by qualifying it with a package prefix, + where the package name then appears twice + (once as a package prefix, + another time as a prefix within the symbol name). +

+ + ;; Bad + (in-package #:varint) + (defun varint-length64 () ... ) + + (in-package #:client-code) + (defconst +padding+ (varint:varint-length64 +end-token+)) + + + ;; Better + (in-package #:varint) + (defun length64 () ... ) + + (in-package #:client-code) + (defconst +padding+ (varint:length64 +end-token+)) + +

+ An exception to the above rule would be to include a prefix + for the names of variables that would otherwise be expected to clash + with variables in packages that use the current one. + For instance, ASDF exports a variable *ASDF-VERBOSE* + that controls the verbosity of ASDF only, + rather than of the entire Lisp program. +

+ +
+ + + Use packages appropriately. + + +

+ Lisp packages are used to demarcate namespaces. + Usually, each system has its own namespace. + A package has a set of external symbols, + which are intended to be used from outside the package, + in order to allow other modules to use this module's facilities. +

+

+ The internal symbols of a package + should never be referred to from other packages. + That is, you should never have to use + the double-colon :: construct. + (e.g. QUAKE::HIDDEN-FUNCTION). + If you need to use double-colons to write real production code, + something is wrong and needs to be fixed. +

+

+ As an exception, + unit tests may use the internals of the package being tested. + So when you refactor, watch out for + internals used by the package's unit tests. +

+

+ The :: construct is also useful for very temporary hacks, + and at the REPL. + But if the symbol really is part of + the externally-visible definition of the package, + export it. +

+

+ You may find that some internal symbols represent concepts + you usually want to abstract away and hide under the hood, + yet at times are necessary to expose for various extensions. + For the former reason, you do not want to export them, + yet for the latter reason, you have to export them. + The solution is to have two different packages, + one for your normal users to use, and + another for the implementation and its extenders to use. +

+

+ Each package is one of two types: +

+
    +
  • + Intended to be included + in the :use specification of other packages. + If package A "uses" package B, + then the external symbols of package B + can be referenced from within package A + without a package prefix. + We mainly use this for low-level modules + that provide widely-used facilities. +
  • +
  • + Not intended to be "used". + To reference a facility provided by package B, + code in package A must use an explicit package prefix, + e.g. B:DO-THIS. +
  • +
+

+ If you add a new package, it should always be of the second type, + unless you have a special reason and get permission. + Usually a package is designed to be one or the other, + by virtue of the names of the functions. + For example, if you have an abstraction called FIFO, + and it were in a package of the first type + you'd have functions named things like + FIFO-ADD-TO and FIFO-CLEAR-ALL. + If you used a package of the second type, + you'd have names like ADD-TO and CLEAR-ALL, + because the callers would be saying + FIFO:ADD-TO and FIFO:CLEAR-ALL. + (FIFO:FIFO-CLEAR-ALL is redundant and ugly.) +

+

+ Another good thing about packages is that + your symbol names won't "collide" with the names of other packages, + except the ones your packages "uses". + So you have to stay away from symbols + that are part of the Lisp implementation (since you always "use" that) + and that are part of any other packages you "use", + but otherwise you are free to make up your own names, + even short ones, and not worry about some else + having used the same name. + You're isolated from each other. +

+

+ Your package must not shadow (and thus effectively redefine) + symbols that are part of the Common Lisp language. + There are certain exceptions, + but they should be very well-justified and extremely rare: +

+
    +
  • + If you are explicitly replacing a Common Lisp symbol + by a safer or more featureful version. +
  • +
  • + If you are defining a package not meant to be "used", + and have a good reason to export a symbol + that clashes with Common Lisp, + such as log:error and log:warn + and so on. +
  • +
+ +
+
+ + + + + You should avoid side-effects when they are not necessary. + + +

+ Lisp is best used as a "mostly functional" language. +

+

+ Avoid modifying local variables, try rebinding instead. +

+

+ Avoid creating objects and the SETFing their slots. + It's better to set the slots during initialization. +

+

+ Make classes as immutable as possible, that is, avoid giving slots + setter functions if at all possible. +

+

+ Using a mostly functional style makes it much easier + to write concurrent code that is thread-safe. + It also makes it easier to test the code. +

+ +
+ + + You should favor iteration over recursion. + + +

+ Common Lisp systems are not required to implement + function calls from tail positions without leaking stack space + — which is known as proper tail calls (PTC), + tail call elimination (TCE), + or tail call optimization (TCO). + This means that indefinite recursion through tail calls + may quickly blow out the stack, + which hampers functional programming. + Still, most serious implementations (including SBCL and CCL) + do implement proper tail calls, but with restrictions: +

+
    +
  • + The (DECLARE (OPTIMIZE ...)) settings + must favor SPEED enough and + not favor DEBUG too much, + for some compiler-dependent meanings of "enough" and "too much". + (For instance, in SBCL, you should avoid (SPEED 0) + and (DEBUG 3) to achieve proper tail calls.) +
  • +
  • + There should not be dynamic bindings around the call + (even though some Scheme compilers are able to properly treat + such dynamic bindings, called parameters in Scheme parlance). +
  • +
+

+ For compatibility with all compilers and optimization settings, + and to avoid stack overflow when debugging, + you should prefer iteration or the built in mapping functions + to relying on proper tail calls. +

+

+ If you do rely on proper tail calls, + you must prominently document the fact, + and take appropriate measures to ensure an appropriate compiler is used + with appropriate optimization settings. + For fully portable code, you may have to use trampolines instead. +

+ +
+ + + Use special variables sparingly. + + +

+ Using Lisp "special" (dynamically bound) variables + as implicit arguments to functions should be used sparingly, + and only in cases where it won't surprise the person reading the code, + and where it offers significant benefits. +

+

+ Indeed, each special variable constitutes state. + Developers have to mentally track the state of all relevant variables + when trying to understand what the code does and how it does it; + tests have to be written and run with all relevant combinations; + to isolate some activity, care has to be taken to locally bind + all relevant variables, including those of indirectly used modules. + They can hide precious information from being printed in a backtrace. + Not only is there overhead associated to each new variable, + but interactions between variables + can make the code exponentially more complex + as the number of such variables increases. + The benefits have to match the costs. +

+

+ Note though that a Lisp special variable is not a global variable + in the sense of a global variable in, say, BASIC or C. + As special variables can be dynamically bound to a local value, + they are much more powerful than + global value cells where all users necessarily interfere with each other. +

+

+ Good candidates for such special variables + are items for which "the current" can be naturally used as prefix, + such as "the current database connection" or + "the current business data source". + They are singletons as far as the rest of the code is concerned, + and often passing them as an explicit argument + does not add anything to the readability or maintainability + of the source code in question. +

+

+ They can make it easier to write code that can be refactored. + If you have a request processing chain, + with a number of layers that all operate upon a "current" request, + passing the request object explicitly to every function + requires that every function in the chain have a request argument. + Factoring out code into new functions often requires + that these functions also have this argument, + which clutters the code with boilerplate. +

+

+ You should treat special variables + as though they are per-thread variables. + By default, you should leave a special variable + with no top-level binding at all, + and each thread of control + that needs the variable should bind it explicitly. + This will mean that any incorrect use of the variable + will result in an "unbound variable" error, and + each thread will see its own value for the variable. + Variables with a default global value should usually be + locally bound at thread creation time. + You should use suitable infrastructure + to automate the appropriate declaration of such variables. +

+ + +
+ + + Be consistent in assignment forms. + + +

+ There are several styles for dealing with assignment and side-effects; + whichever a given package is using, + keep using the same consistently when hacking said package. + Pick a style that makes sense when starting a new package. +

+

+ Regarding multiple assignment in a same form, there are two schools: + the first style groups as many assignments as possible into a single + SETF or PSETF form + thus minimizing the number of forms with side-effects; + the second style splits assignments into as many individual + SETF (or SETQ, see below) forms as possible, + to maximize the chances of locating forms that modify a kind of place + by grepping for (setf (foo .... + A grep pattern must actually contain as many place-modifying forms + as you may use in your programs, which may make this rationale either + convincing or moot depending on the rest of the style of your code. + You should follow the convention used in the package you are hacking. + We recommend the first convention for new packages. +

+

+ Regarding SETF and SETQ, + there are two schools: + this first regards SETQ + as an archaic implementation detail, + and avoids it entirely in favor of SETF; + the second regards SETF + as an additional layer of complexity, + and avoids it in favor of SETQ whenever possible + (i.e. whenever the assigned place is a variable or symbol-macro). + You should follow the convention used in the package you are hacking. + We recommend the first convention for new packages. +

+

+ In the spirit of a mostly pure functional style, + which makes testing and maintenance easier, + we invite you to consider how to do things with the fewest assignments required. +

+ +
+ + + You must make proper usage of assertions and conditions. + + +
    +
  • + ASSERT should be used ONLY to detect internal bugs. + Code should ASSERT invariants whose failure indicates + that the software is itself broken. + Incorrect input should be handled properly at runtime, + and must not cause an assertion violation. + The audience for an ASSERT failure is a developer. + Do not use the data-form and argument-form in ASSERT + to specify a condition to signal. + It's fine to use them to print out a message for debugging purposes + (and since it's only for debugging, there's no issue of + internationalization). +
  • +
  • + CHECK-TYPE, + ETYPECASE are also forms of assertion. + When one of these fails, that's a detected bug. + You should prefer to use CHECK-TYPE + over (DECLARE (TYPE ...)) + for the inputs of functions. +
  • +
  • + Your code should use assertions and type checks liberally. + The sooner a bug is discovered, the better! + Only code in the critical path for performance + and internal helpers should eschew + explicit assertions and type checks. +
  • +
  • + Invalid input, such as files that are read + but do not conform to the expected format, + should not be treated as assertion violations. + Always check to make sure that input is valid, + and take appropriate action if it is not, + such as signalling a real error. +
  • +
  • + ERROR should be used + to detect problems with user data, requests, permissions, etc., + or to report "unusual outcomes" to the caller. +
  • +
  • + ERROR should always be called + with an explicit condition type; + it should never simply be called with a string. + This enables internationalization. +
  • +
  • + Functions that report unusual outcomes + by signaling a condition should say so explicitly in their contracts + (their textual descriptions, in documentation and docstrings etc.). + When a function signals a condition + that is not specified by its contract, that's a bug. + The contract should specify the condition class(es) clearly. + The function may then signal any condition + that is a type-of any of those conditions. + That is, signaling instances of subclasses + of the documented condition classes is fine. +
  • +
  • + Complex bug-checks may need to use ERROR + instead of ASSERT. + +
  • +
  • + When writing a server, you must not call WARN. + Instead, you should use the appropriate logging framework. + +
  • +
  • + Code must not call SIGNAL. + Instead, use ERROR or ASSERT. +
  • +
  • + Code should not use THROW and CATCH; + instead use the restart facility. +
  • +
  • + Code should not generically handle all conditions, + e.g. type T, or use IGNORE-ERRORS. + Instead, let unknown conditions propagate to + the standard ultimate handler for processing. + +
  • +
  • + There are a few places where handling all conditions is appropriate, + but they are rare. + The problem is that handling all conditions can mask program bugs. + If you do need to handle "all conditions", + you MUST handle only ERROR, not T + and not SERIOUS-CONDITION. + (This is notably because CCL's process shutdown + depends on being able to signal process-reset + and have it handled by CCL's handler, + so we must not interpose our own handler.) +
  • +
  • + (error (make-condition 'foo-error ...)) + is equivalent to (error 'foo-error ...) — + code must use the shorter form. +
  • +
  • + Code should not signal conditions from inside the cleanup form of + UNWIND-PROTECT + (unless they are always handled inside the cleanup form), + or otherwise do non-local exits from cleanup handlers + outside of the handler e.g. INVOKE-RESTART. +
  • +
  • + Do not clean up by resignaling. + If you do that, and the condition is not handled, + the stack trace will halt at the point of the resignal, + hiding the rest. + And the rest is the part we really care about! + + ;; Bad + (handler-case + (catch 'ticket-at + (etd-process-blocks)) + (error (c) + (reset-parser-values) + (error c))) + + + ;; Better + (unwind-protect + (catch 'ticket-at + (etd-process-blocks)) + (reset-parser-values)) + +
  • +
+ +
+ + + If you know the type of something, you should make it explicit + in order to enable compile-time and run-time sanity-checking. + + + +

+ If your function is using a special variable as an implicit argument, + it's good to put in a CHECK-TYPE for the special variable, + for two reasons: + to clue in the person reading the code + that this variable is being used implicitly as an argument, + and also to help detect bugs. +

+ +

+ Using (declare (type ...)) + is the least-desirable mechanism to use + because, as Scott McKay puts it: +

+
+

+ The fact is, (declare (type ...)) does different things + depending on the compiler settings of speed, safety, etc. + In some compilers, when speed is greater than safety, + (declare (type ...)) will tell the compiler + "please assume that these variables have these types" + without generating any type-checks. + That is, if some variable has the value 1432 in it, + and you declare it to be of type string, + the compiler might just go ahead and use it as though it's a string. +

+

+ Moral: don't use (declare (type ...)) + to declare the contract of any API functions, + it's not the right thing. + Sure, use it for "helper" functions, but not API functions. +

+
+

+ You should, of course, use appropriate declarations + in internal low-level functions + where these declarations are used for optimization. + When you do, however, see our recommendations for + Unsafe Operations. +

+ +
+ + + Use CLOS appropriately. + + +

+ When a generic function is intended to be called from other + modules (other parts of the code), there should be an + explicit DEFGENERIC form, + with a :DOCUMENTATION string + explaining the generic contract of the function + (as opposed to its behavior for some specific class). + It's generally good to do explicit DEFGENERIC forms, + but for module entry points it is mandatory. +

+

+ When the argument list of a generic function includes + &KEY, + the DEFGENERIC should always explicitly list + all of the keyword arguments that are acceptable, + and explain what they mean. + (Common Lisp does not require this, but it is good form, + and it may avoid spurious warnings on SBCL.) +

+

+ You should avoid SLOT-VALUE and WITH-SLOTS, + unless you absolutely intend to circumvent + any sort of method combination that might be in effect for the slot. + Rare exceptions include INITIALIZE-INSTANCE + and PRINT-OBJECT methods and + accessing normally hidden slots in the low-level implementation of + methods that provide user-visible abstractions. + Otherwise, you should use accessors, + WITH-ACCESSORS +

+ +

+ Accessor names generally follow a convention of + <protocol-name>-<slot-name>, + where a "protocol" in this case loosely indicates + a set of functions with well-defined behavior. +

+

+ No implication of a formal "protocol" concept is necessarily intended, + much less first-class "protocol" objects. + However, there may indeed be an abstract CLOS class + or an + Interface-Passing Style interface + that embodies the protocol. + Further (sub)classes or (sub)interfaces may then implement + all or part of a protocol by defining + some methods for (generic) functions in the protocol, + including readers and writers. +

+

+ For example, if there were a notional protocol called + is pnr with accessors pnr-segments + and pnr-passengers, then + the classes air-pnr, hotel-pnr and + car-pnr could each reasonably implement + methods for pnr-segments and pnr-passengers + as accessors. +

+

+ By default, an abstract base class name is used + as the notional protocol name, so accessor names default + to <class-name>-<slot-name>; + while such names are thus quite prevalent, + this form is neither required nor even preferred. + In general, it contributes to "symbol bloat", + and in many cases has led to a proliferation of "trampoline" methods. +

+

+ Accessors named <slot-name>-of should not be used. +

+

+ Explicit DEFGENERIC forms should be used when there are + (or it is anticipated that there will be) + more than one DEFMETHOD for that generic function. + The reason is that the documentation for the generic function + explains the abstract contract for the function, + as opposed to explaining what an individual method does for + some specific class(es). +

+

+ You must not use generic functions where there is no notional protocol. + To put it more concretely, + if you have more than one generic function that specializes its Nth argument, + the specializing classes should all be descendants of a single class. + Generic functions must not be used for "overloading", + i.e. simply to use the same name for two entirely unrelated types. +

+

+ More precisely, it's not really + whether they descend from a common superclass, + but whether they obey the same "protocol". + That is, the two classes should handle the same set of generic functions, + as if there were an explicit DEFGENERIC for each method. +

+

+ Here's another way to put it. + Suppose you have two classes, A and B, and a generic function F. + There are two methods for F, + which dispatch on an argument being of types A and B. + Is it plausible that there might be a function call somewhere + in the program that calls F, + in which the argument might sometimes, at runtime, + be of class A and other times be of class B? + If not, you probably are overloading and + should not be using a single generic function. +

+

+ We allow one exception to this rule: + it's OK to do overloading + if the corresponding argument "means" the same thing. + Typically one overloading allows an X object, + and the other allows the name of an X object, + which might be a symbol or something. +

+

+ You must not use MOP "intercessory" operations at runtime. + You should not use MOP "intercessory" operations at compile-time. + At runtime, they are at worst a danger, at best a performance issue. + At compile-time, it is usually cleaner that + macros should set things up the right way in one pass + than have to require a second pass of fixups through intercession; + but sometimes, fixups are necessary to resolve forward references, + and intercession is allowed then. + MOP intercession is a great tool for interactive development, + and you may enjoy it while developping and debugging; + but you should not use it in normal applications. +

+

+ If a class definition creates a method + as a :READER, :WRITER, + or :ACCESSOR, + do not redefine that method. + It's OK to add :BEFORE, :AFTER, + and :AROUND methods, + but don't override the primary method. +

+

+ In methods with keyword arguments, + you must always use &KEY, + even if the method does not care about the values of any keys, + and you should never use &ALLOW-OTHER-KEYS. + As long as a keyword is accepted by any method of a generic function, + it's OK to use it in the generic function, + even if the other methods of the same generic function + don't mention it explicitly. + This is particularly important + for INITIALIZE-INSTANCE methods, + since if you did use &ALLOW-OTHER-KEYS, + it would disable error checking for misspelled or wrong keywords + in MAKE-INSTANCE calls! +

+ +

+ A typical PRINT-OBJECT method might look like this: +

+ + (defmethod print-object ((p person) stream) + (print-unprintable-object (p stream :type t :identity t) + (with-slots (first-name last-name) p + (safe-format stream "~a ~a" first-name last-name)))) + + +
+
+ + + + + Use macros when appropriate, which is often. + Define macros when appropriate, which is seldom. + + +

+ Macros bring syntactic abstraction, which is a wonderful thing. + It helps make your code clearer, by describing your intent + without getting bogged in implementation details + (indeed abstracting those details away). + It helps make your code more concise and more readable, + by eliminating both redundancy and irrelevant details. + But it comes at a cost to the reader, + which is learning a new syntactic concept for each macro. + And so it should not be abused. +

+

+ The general conclusion is that there shouldn't be + any recognizable design pattern + in a good Common Lisp program. + The one and only pattern is: use the language, + which includes defining and using syntactic abstractions. +

+

+ Existing macros must be used + whenever they make code clearer + by conveying intent in a more concise way, + which is often. + When a macro is available in your project + that expresses the concept you're using, + you must not write the expansion rather than use the macro. +

+

+ New macros should be defined as appropriate, + which should be seldom, + for common macros have already been provided + by the language and its various libraries, + and your program typically only needs few new ones + relative to its size. +

+

+ You should follow the OAOOM rule of thumb + for deciding when to create a new abstraction, + whether syntactic or not: + if a particular pattern is used more than twice, + it should probably be abstracted away. + A more refined rule to decide when to use abstraction + should take into account + the benefit in term of number of uses and gain at each use, + to the costs in term of having to get used to reading the code. + For syntactic abstractions, costs and benefits to the reader + is usually more important than costs and benefits to the writer, + because good code is usually written once + and read many times by many people + (including the same programmer + who has to maintain the program after having forgotten it). + Yet the cost to the writer of the macro + should also be taken into account; + however, in doing so it should rather be compared + to the cost of the programmer writing other code instead + that may have higher benefits. +

+

+ Using Lisp macros properly requires taste. + Avoid writing complicated macros + unless the benefit clearly outweighs the cost. + It takes more effort for your fellow developers to learn your macro, + so you should only use a macro if the gain in expressiveness + is big enough to justify that cost. + As usual, feel free to consult your colleagues if you're not sure, + since without a lot of Lisp experience, + it can be hard to make this judgment. +

+

+ You must never use a macro where a function will do. + That is, if the semantics of what you are writing + conforms to the semantics of a function, + then you must write it as a function rather than a macro. +

+

+ You must not transform a function into a macro for performance reasons. + If profiling shows that you have a performance problem + with a specific function FOO, + document the need and profiling-results appropriately, + and + (declaim (inline foo)). +

+ +

+ You can also use a compiler-macro + as a way to speed up function execution + by specifying a source-to-source transformation. + Beware that it interferes with tracing the optimized function. +

+

+ When you write a macro-defining macro + (a macro that generates macros), + document and comment it particularly clearly, + since these are harder to understand. +

+

+ You must not install new reader macros + without a consensus among the developers of your system. + Reader macros must not leak out of the system that uses them + to clients of that system or other systems used in the same project. + You must use software such as + cl-syntax or named-readtables + to control how reader macros are used. + This clients who desire it may use the same reader macros as you do. + In any case, your system must be usable + even to clients who do not use these reader macros. +

+

+ If your macro has a parameter that is a Lisp form + that will be evaluated when the expanded code is run, + you should name the parameter with the suffix -form. + This convention helps make it clearer to the macro's user + which parameters are Lisp forms to be evaluated, and which are not. + The common names body and end are + exceptions to this rule. +

+

+ You should follow the so-called CALL-WITH style when it applies. + This style is explained at length in + http://random-state.net/log/3390120648.html. + The general principle is that the macro is strictly limited to processing the syntax, + and as much of the semantics as possible is kept in normal functions. + Therefore, a macro WITH-FOO is often limited to + generating a call to an auxiliary function + CALL-WITH-FOO + with arguments deduced from the macro arguments. + Macro &body arguments are typically + wrapped into a lambda expression of which they become the body, + which is passed as one of the arguments of the auxiliary function. +

+

+ The separation of syntactic and semantic concerns + is a general principle of style that applies + beyond the case of WITH- macros. + Its advantages are many. + By keeping semantics outside the macro, + the macro is made simpler, easier to get right, and less subject to change, + which makes it easier to develop and maintain. + The semantics is written in a simpler language — one without staging — + which also makes it easier to develop and maintain. + It becomes possible to debug and update the semantic function + without having to recompile all clients of the macro. + The semantic function appears in the stack trace + which also helps debug client functions. + The macro expansion is made shorter and + each expansion shares more code with other expansions, + which reduces memory pressure which in turn usually makes things faster. + It also makes sense to write the semantic functions first, + and write the macros last as syntactic sugar on top. + You should use this style unless the macro is used + in tight loops where performance matters; + and even then, see our rules regarding optimization. +

+

+ Any functions (closures) created by the macro should be named, + which can be done using FLET. + + This also allows you to declare the function to be of dynamic extent + (if it is — and often it is; yet see below regarding + DYNAMIC-EXTENT). +

+

+ If a macro call contains a form, + and the macro expansion includes more than one copy of that form, + the form can be evaluated more than once, + and code it contains macro-expanded and compiled more than once. + If someone uses the macro and calls it + with a form that has side effects or that takes a long time to compute, + the behavior will be undesirable + (unless you're intentionally writing + a control structure such as a loop). + A convenient way to avoid this problem + is to evaluate the form only once, + and bind a (generated) variable to the result. + There is a very useful macro called ALEXANDRIA:ONCE-ONLY + that generates code to do this. + See also ALEXANDRIA:WITH-GENSYMS, + to make some temporary variables in the generated code. + Note that if you follow our CALL-WITH style, + you typically expand the code only once, as either + an argument to the auxiliary function, or + the body of a lambda passed as argument to it; + you therefore avoid the above complexity. +

+

+ When you write a macro with a body, + such as a WITH-xxx macro, + even if there aren't any parameters, + you should leave space for them anyway. + For example, if you invent WITH-LIGHTS-ON, + do not make the call to it look like + (defmacro with-lights-on (&body b) ...). + Instead, do (defmacro with-lights-on (() &body b) ...). + That way, if parameters are needed in the future, + you can add them without necessarily having to change + all the uses of the macro. +

+ +
+ + + When using EVAL-WHEN, you should almost always use all of + (:compile-toplevel :load-toplevel :execute). + + +

+ Lisp evaluation happens at several times, + some of them interleaved. + Be aware of them when writing macros. + EVAL-WHEN considered harmful to your mental health. +

+

+ In summary of the article linked above, + unless you're doing truly advanced macrology, + the only valid combination in an EVAL-WHEN + is to include all of + (eval-when (:compile-toplevel :load-toplevel :execute) ...) +

+

+ You must use + (eval-when (:compile-toplevel :load-toplevel :execute) ...) + whenever you define functions, types, classes, constants, variables, etc., + that are going to be used in macros. +

+

+ It is usually an error to omit the :execute, + because it prevents LOADing the source rather than the fasl. + It is usually an error to omit the :load-toplevel + (except to modify e.g. readtables and compile-time settings), + because it prevents LOADing future files + or interactively compiling code + that depends on the effects that happen at compile-time, + unless the current file was COMPILE-FILEd + within the same Lisp session. +

+

+ Regarding variables, note that because macros may or may not + be expanded in the same process that runs the expanded code, + you must not depend on compile-time and runtime effects + being either visible or invisible at the other time. + There are still valid uses of variables in macros: +

+
    +
  • + Some variables may hold dictionaries + for some new kind of definition and other meta-data. + If such meta-data is to be visible at runtime and/or in other files, + you must make sure that the macro expands into code that + will register the definitions to those meta-data structures + at load-time, + in addition to effecting the registration at compile-time. + Typically, your top-level definitions expand + to code that does the registration. + if your code doesn't expand at the top-level, + you can sometimes use LOAD-TIME-VALUE for good effect. + In extreme cases, you may have to use + ASDF-FINALIZERS:EVAL-AT-TOPLEVEL. +
  • +
  • + Some variables may hold temporary data + that is only used at compile-time in the same file, + and can be cleaned up at the end of the file's compilation. + Predefined such variables would include *readtable* + or compiler-internal variables holding + the current optimization settings. + You can often manage existing and new such variables using + the :AROUND-COMPILE hooks of ASDF. +
  • +
+ +
+ + + You should use #. sparingly, + and you must avoid read-time side-effects. + + +

+ The #. standard read-macro + will read one object, evaluate the object, and + have the reader return the resulting value. +

+

+ You must not use it where other idioms will do, such as + using EVAL-WHEN to evaluate side-effects at compile-time, + using a regular macro to return an expression computed at compile-time, + using LOAD-TIME-VALUE to compute it at load-time. +

+

+ Read-time evaluation is often used as a quick way + to get something evaluated at compile time + (actually "read time" but it amounts to the same thing). + If you use this, the evaluation MUST NOT have any side effects + and MUST NOT depend on any variable global state. + The #. should be treated as a way + to force "constant-folding" + that a sufficiently-clever compiler + could have figure out all by itself, + when the compiler isn't sufficiently-clever + and the difference matters. +

+

+ Another use of #. is to expand the equivalent of macros + in places that are neither expressions nor (quasi)quotations, + such as lambda-lists. However, if you find yourself using it a lot, + it might be time to instead define macros to replace your consumers + of lambda-lists with something that recognizes an extension. +

+

+ Whenever you are going to use #., + you should consider using DEFCONSTANT and its variants, + possibly in an EVAL-WHEN, + to give the value a name explaining what it means. +

+ +
+ + + You must not use EVAL at runtime. + + +

+ Places where it is actually appropriate to use EVAL + are so few and far between that you must consult with your reviewers; + it's easily misused. +

+

+ If your code manipulates symbols at runtime + and needs to get the value of a symbol, + use SYMBOL-VALUE, not EVAL. +

+

+ Often, what you really need is to write a macro, + not to use EVAL. +

+

+ You may be tempted to use EVAL as a shortcut + to evaluating expressions in a safe subset of the language. + But it often requires more scrutiny to properly check and sanitize + all possible inputs to such use of EVAL + than to build a special-purpose evaluator. + You must not use EVAL in this way at runtime. +

+

+ Places where it is OK to use EVAL are: +

+
    +
  • + The implementation of an interactive development tool. +
  • +
  • + The build infrastructure. +
  • +
  • + Backdoors that are part of testing frameworks. + (You MUST NOT have such backdoors in production code.) +
  • +
  • + Macros that fold constants at compile-time. +
  • +
  • + Macros that register definitions to meta-data structures; + the registration form is sometimes evaluated at compile-time + as well as included in the macro-expansion, + so it is immediately available to other macros. +
  • +
+

+ Note that in the latter case, + if the macro isn't going to be used at the top-level, + it might not be possible to make these definitions available + as part of the expansion. + The same phenomenon may happen in a DEFTYPE expansion, + or in helper functions used by macros. + In these cases, you may actually have to use + ASDF-FINALIZERS:EVAL-AT-TOPLEVEL in your macro. + It will not only EVAL your definitions + at macro-expansion time for immediate availability, + it will also save the form aside, for inclusion in a + (ASDF-FINALIZERS:FINAL-FORMS) + that you need to include at the end of the file being compiled + (or before the form is needed). + This way, the side-effects are present when loading the fasl + without having compiled it as well as while compiling it; + in either case, the form is made available at load-time. + ASDF-FINALIZERS ensures that the form is present, + by throwing an error if you omit it. +

+ +
+ + + You must not use INTERN or UNINTERN at runtime. + + +

+ You must not use INTERN at runtime. + Not only does it cons, + it either creates a permanent symbol that won't be collected + or gives access to internal symbols. + This creates opportunities for memory leaks, denial of service attacks, + unauthorized access to internals, clashes with other symbols. +

+

+ You must not INTERN a string + just to compare it to a keyword; + use STRING= or STRING-EQUAL. +

+ + (member (intern str :keyword) $keys) ; Bad + + + (member str $keys :test #'string-equal) ; Better + +

+ You must not use UNINTERN at runtime. + It can break code that relies on dynamic binding. + It makes things harder to debug. + You must not dynamically intern any new symbol, + and therefore you need not dynamically unintern anything. +

+

+ You may of course use INTERN at compile-time, + in the implementation of some macros. + Even so, it is usually more appropriate + to use abstractions on top of it, such as + ALEXANDRIA:SYMBOLICATE or + ALEXANDRIA:FORMAT-SYMBOL + to create the symbols you need. +

+ + +
+
+ + + + + Appropriately use or avoid using NIL. + + +

+ NIL can have several different interpretations: +

+
    +
  • + "False." + In this case, use NIL. + You should test for false NIL + using the operator NOT or + using the predicate function NULL. +
  • +
  • + "Empty-list." + In this case, use '(). + (Be careful about quoting the empty-list when calling macros.) + You should use ENDP to test for the empty list + when the argument is known to be a proper list, + or with NULL otherwise. +
  • +
  • + A statement about some value being unspecified. + In this case, you may use NIL + if there is no risk of ambiguity anywhere in your code; + otherwise you should use an explicit, descriptive symbol. +
  • +
  • + A statement about some value being known not to exist. + In this case, you should use an explicit, descriptive symbol + instead of NIL. +
  • +
+

+ You must not introduce ambiguity in your data representations + that will cause headaches for whoever has to debug code. + If there is any risk of ambiguity, + you should use an explicit, descriptive symbol or keyword + for each case, + instead of using NIL for either. + If you do use NIL, + you must make sure that the distinction is well documented. +

+

+ In many contexts, + instead of representing "I don't know" as a particular value, + you should instead use multiple values, + one for the value that is known if any, + and one to denote whether the value was known or found. +

+ +

+ When working with database classes, keep in mind that + NIL need not always map to 'NULL' + (and vice-versa)! + The needs of the database may differ from the needs of the Lisp. +

+ +
+ + + You must select proper data representation. + You must not abuse the LIST data structure. + + +

+ Even though back in 1958, LISP was short for "LISt Processing", + its successor Common Lisp has been a modern programming language + with modern data structures since the 1980s. + You must use the proper data structures in your programs. +

+

+ You must not abuse the builtin (single-linked) LIST + data structure where it is not appropriate, + even though Common Lisp makes it especially easy to use it. +

+

+ You must only use lists + when their performance characteristics + is appropriate for the algorithm at hand: + sequential iteration over the entire contents of the list. +

+

+ An exception where it is appropriate to use lists + is when it is known in advance + that the size of the list will remain very short + (say, less than 16 elements). +

+

+ List data structures are often (but not always) + appropriate for macros and functions used by macros at compile-time: + indeed, not only is source code passed as lists in Common Lisp, + but the macro-expansion and compilation processes + will typically walk over the entire source code, sequentially, once. + (Note that advanced macro systems don't directly use lists, but instead + use abstract syntax objects that track source code location and scope; + however there is no such advanced macro system + in Common Lisp at this time.) +

+

+ Another exception where it is appropriate to use lists is + for introducing literal constants + that will be transformed into more appropriate data structures + at compile-time or load-time. + It is a good to have a function with a relatively short name + to build your program's data structures from such literals. +

+

+ In the many cases when lists are not the appropriate data structure, + various libraries such as + cl-containers or + lisp-interface-library + provide plenty of different data structures + that should fulfill all the basic needs of your programs. + If the existing libraries are not satisfactory, see above about + Using Libraries and + Open-Sourcing Code. +

+ +
+ + + You should use the appropriate representation for product types. + + +

+ You should avoid using a list as anything + besides a container of elements of like type. + You must not use a list as method of passing + multiple separate values of different types + in and out of function calls. + Sometimes it is convenient to use a list + as a little ad hoc structure, + i.e. "the first element of the list is a FOO, and the second is a BAR", + but this should be used minimally + since it gets harder to remember the little convention. + You must only use a list that way + when destructuring the list of arguments from a function, + or creating a list of arguments + to which to APPLY a function. +

+

+ The proper way to pass around an object + comprising several values of heterogeneous types + is to use a structure as defined by DEFSTRUCT + or DEFCLASS. +

+

+ You should use multiple values only + when function returns a small number of values + that are meant to be destructured immediately by the caller, + rather than passed together as arguments to further functions. +

+

+ You should not return a condition object + as one of a set of multiple values. + Instead, you should signal the condition to denote an unusual outcome. +

+

+ You should signal a condition to denote an unusual outcome, + rather than relying on a special return type. +

+ +
+ + + Use the appropriate functions when manipulating lists. + + +

+ Use FIRST to access the first element of a list, + SECOND to access the second element, etc. + Use REST to access the tail of a list. + Use ENDP to test for the end of the list. +

+

+ Use CAR and CDR + when the cons cell is not being used to implement a proper list + and is instead being treated as a pair of more general objects. + Use NULL to test for NIL in this context. +

+

+ The latter case should be rare outside of alists, + since you should be using structures and classes where they apply, + and data structure libraries when you want trees. +

+

+ Exceptionally, you may use CDADR and other variants + on lists when manually destructuring them, + instead of using a combination of several list accessor functions. + In this context, using CAR and CDR + instead of FIRST and REST also makes sense. + However, keep in mind that it might be more appropriate in such cases + to use higher-level constructs such as + DESTRUCTURING-BIND or OPTIMA:MATCH. +

+ +
+ + + You should use arrays rather than lists where random access matters. + + +

+ ELT has O(n) behavior when used on lists. + If you are to use random element access on an object, + use arrays and AREF instead. +

+

+ The exception is for code outside the critical path + where the list is known to be small anyway. +

+ +
+ + + You should only use lists as sets for very small lists. + + +

+ Using lists as representations of sets is a bad idea + unless you know the lists will be small, + for accessors are O(n) instead of O(log n). + For arbitrary big sets, use balanced binary trees, + for instance using lisp-interface-library. +

+

+ If you still use lists as sets, + you should not UNION lists just to search them. +

+ + (member foo (union list-1 list-2)) ; Bad + + + (or (member foo list-1) (member foo list-2)) ; Better + +

+ Indeed, UNION not only conses unnecessarily, + but it can be O(n^2) on some implementations, + and is rather slow even when it's O(n). +

+ +
+
+ + +

+ You must follow the proper usage regarding + well-known functions, macros and special forms. +

+ + + You must use proper defining forms for constant values. + + +

+ The Lisp system we primarily use, SBCL, is very picky and + signals a condition whenever a constant is redefined to a value not + EQL to its previous setting. + You must not use DEFCONSTANT + when defining variables that are not + numbers, characters, or symbols (including booleans and keywords). + Instead, consistently use whichever alternative + is recommended for your project. +

+ + ;; Bad + (defconstant +google-url+ "https://www.google.com/") + (defconstant +valid-colors+ '(red green blue)) + + + + + +

+ Open-Source libraries may use + ALEXANDRIA:DEFINE-CONSTANT + for constants other than numbers, characters and symbols + (including booleans and keywords). + You may use the :TEST keyword argument + to specify an equality predicate. +

+ + ;; Better, for Open-Source code: + (define-constant +google-url+ "https://www.google.com/" :test #'string=) + (define-constant +valid-colors+ '(red green blue)) + +

+ Note that with optimizing implementations, such as SBCL or CMUCL, + defining constants this way precludes any later redefinition + short of UNINTERNing the symbol + and recompiling all its clients. + This may make it "interesting" to debug things at the REPL + or to deploy live code upgrades. + If there is a chance that your "constants" are not going to be constant + over the lifetime of your server processes + after taking into consideration scheduled and unscheduled code patches, + you should consider using + DEFPARAMETER or DEFVAR instead, + or possibly a variant of DEFINE-CONSTANT + that builds upon some future library implementing global lexicals + rather than DEFCONSTANT. + You may keep the +plus+ convention in these cases + to document the intent of the parameter as a constant. +

+

+ Also note that LOAD-TIME-VALUE may help you + avoid the need for defined constants. +

+ +
+ + + You should make proper use of + &OPTIONAL and + &KEY arguments. + You should not use &AUX arguments. + + +

+ You should avoid using &ALLOW-OTHER-KEYS, + since it blurs the contract of a function. + Almost any real function (generic or not) allows a certain + fixed set of keywords, as far as its caller is concerned, + and those are part of its contract. + If you are implementing a method of a generic function, + and it does not need to know + the values of some of the keyword arguments, + you should explicitly (DECLARE (IGNORE ...)) + all the arguments that you are not using. + You must not use &ALLOW-OTHER-KEYS + unless you explicitly want to disable checking of allowed keys + for all methods when invoking the generic function on arguments + that match this particular method. + Note that the contract of a generic function belongs in + the DEFGENERIC, not in the DEFMETHOD + which is basically an "implementation detail" of the generic function + as far as the caller of the generic is concerned. +

+

+ A case where &ALLOW-OTHER-KEYS is appropriate + is when you write a wrapper function to other some other functions + that may vary (within the computation or during development), + and pass around a plist as a &REST argument. +

+

+ You should avoid using &AUX arguments. +

+

+ You should avoid having both &OPTIONAL + and &KEY arguments, + unless it never makes sense to specify keyword arguments + when the optional arguments are not all specified. + You must not have non-NIL defaults + to your &OPTIONAL arguments + when your function has both &OPTIONAL + and &KEY arguments. +

+

+ For maximum portability of a library, it is good form + that DEFMETHOD definitions should + (DECLARE (IGNORABLE ...)) + all the required arguments that they are not using. + Indeed, some implementations will issue a warning + if you (DECLARE (IGNORE ...)) those arguments, + whereas other implementations will issue a warning + if you fail to (DECLARE (IGNORE ...)) them. + (DECLARE (IGNORABLE ...)) works on all implementations. +

+

+ You should avoid excessive nesting of binding forms inside a function. + If your function ends up with massive nesting, + you should probably break it up into several functions or macros. + If it is really a single conceptual unit, + consider using a macro such as FARE-UTILS:NEST + to at least reduce the amount of indentation required. + It is bad form to use NEST in typical short functions + with 4 or fewer levels of nesting, + but also bad form not to use it in the exceptional long functions + with 10 or more levels of nesting. + Use your judgment and consult your reviewers. +

+ + +
+ + + Use the appropriate conditional form. + + +

+ Use WHEN and UNLESS + when there is only one alternative. + Use IF when there are two alternatives + and COND when there are several. +

+

+ However, don't use PROGN for an IF clause + — use COND, WHEN, or UNLESS. +

+

+ Note that in Common Lisp, + WHEN and UNLESS return NIL + when the condition is not met. + You may take advantage of it. + Nevertheless, you may use an IF + to explicitly return NIL + if you have a specific reason to insist on the return value. + You may similarly include a fall-through clause (t nil) + as the last in your COND, + or (otherwise nil) as the last in your CASE, + to insist on the fact that the value returned by the conditional matters + and that such a case is going to be used. + You should omit the fall-through clause + when the conditional is used for side-effects. +

+

+ You should prefer AND and OR + when it leads to more concise code than using + IF, COND, + WHEN or UNLESS, + and there are no side-effects involved. + You may also use an ERROR + as a side-effect in the final clause of an OR. +

+

+ You should only use CASE and ECASE + to compare numbers, characters or symbols + (including booleans and keywords). + Indeed, CASE uses EQL for comparisons, + so strings, pathnames and structures may not compare the way you expect, + and 1 will differ from 1.0. +

+

+ You should use ECASE and ETYPECASE + in preference to CASE and TYPECASE. + It is better to catch erroneous values early. +

+

+ You should not use CCASE or CTYPECASE at all. + At least, you should not use them in server processes, + unless you have quite robust error handling infrastructure + and make sure not to leak sensitive data this way. + These are meant for interactive use, + and can cause interesting damage + if they cause data or control to leak to attackers. +

+

+ You must not use gratuitous single quotes in CASE forms. + This is a common error: +

+ + (case x ; Bad: silently returns NIL on mismatch + ('bar :bar) ; Bad: catches QUOTE + ('baz :baz)) ; Bad: also would catch QUOTE + + + (ecase x ; Better: will error on mismatch + ((bar) :bar) ; Better: won't match QUOTE + ((baz) :baz)) ; Better: same reason + +

+ 'BAR there is (QUOTE BAR), + meaning this leg of the case will be executed + if X is QUOTE... + and ditto for the second leg + (though QUOTE will be caught by the first clause). + This is unlikely to be what you really want. +

+

+ In CASE forms, + you must use otherwise instead of t + when you mean "execute this clause if the others fail". + You must use ((t) ...) + when you mean "match the symbol T" rather than "match anything". + You must also use ((nil) ...) + when you mean "match the symbol NIL" rather than "match nothing". +

+

+ Therefore, if you want to map booleans NIL and T + to respective symbols :BAR and :QUUX, + you should avoid the former way and do it the latter way: +

+ + (ecase x ; Bad: has no actual error case! + (nil :bar)) ; Bad: matches nothing + (t :quux)) ; Bad: matches anything + + + (ecase x ; Better: will actually catch non-booleans + ((nil) :bar)) ; Better: matches NIL + ((t) :quux)) ; Better: matches T + + +
+ + + You should the appropriate predicates when comparing objects. + + +

+ Lisp provides four general equality predicates: + EQ, EQL, EQUAL, + and EQUALP, + which subtly vary in semantics. + Additionally, Lisp provides the type-specific predicates + =, CHAR=, CHAR-EQUAL, + STRING=, and STRING-EQUAL. + Know the distinction! +

+

+ You should use EQL to compare objects and symbols + for identity. +

+

+ You must not use EQ to compare numbers or characters. + Two numbers or characters that are EQL + are not required by Common Lisp to be EQ. +

+

+ When choosing between EQ and EQL, + you should use EQL unless you are writing + performance-critical low-level code. + EQL reduces the opportunity + for a class of embarrassing errors + (i.e. if numbers or characters are ever compared). + There may a tiny performance cost relative to EQ, + although under SBCL, it often compiles away entirely. + EQ is equivalent to EQL and type declarations, + and use of it for optimization should be treated just like + any such unsafe operations. +

+

+ You should use CHAR= + for case-dependent character comparisons, + and CHAR-EQUAL for case-ignoring character comparisons. +

+

+ You should use STRING= + for case-dependent string comparisons, + and STRING-EQUAL for case-ignoring string comparisons. +

+

+ A common mistake when using SEARCH on strings + is to provide STRING= or STRING-EQUAL + as the :TEST function. + The :TEST function + is given two sequence elements to compare. + If the sequences are strings, + the :TEST function is called on two characters, + so the correct tests are CHAR= or CHAR-EQUAL. + If you use STRING= or STRING-EQUAL, + the result is what you expect, + but in some Lisp implementations it's much slower. + CCL (at least as of 8/2008) + creates a one-character string upon each comparison, for example, + which is very expensive. +

+

+ Also, you should use :START and :END arguments + to STRING= or STRING-EQUAL + instead of using SUBSEQ; + e.g. (string-equal (subseq s1 2 6) s2) should instead be + (string-equal s1 s2 :start1 2 :end1 6) + This is preferable because it does not cons. +

+

+ You should use ZEROP, + PLUSP, or MINUSP, + instead of comparing a value to 0 or 0.0. +

+

+ You must not use exact comparison on floating point numbers, + since the vague nature of floating point arithmetic + can produce little "errors" in numeric value. + You should compare absolute values to a threshhold. +

+

+ You must use = to compare numbers, + unless you really mean for 0, + 0.0 and -0.0 to compare unequal, + in which case you should use EQL. + Then again, you must not usually use exact comparison + on floating point numbers. +

+

+ Monetary amounts should be using decimal (rational) numbers + to avoid the complexities and rounding errors + of floating-point arithmetic. + Libraries such as + wu-decimal + may help you; + once again, if this library is not satisfactory, see above about + Using Libraries and + Open-Sourcing Code. +

+ + +
+ + + Use the appropriate form for iteration. + + +

+ You should use simpler forms such as + DOLIST or DOTIMES + instead of LOOP + in simple cases when you're not going to use any + of the LOOP facilities such as + bindings, collection or block return. +

+

+ Use the WITH clause of LOOP + when it will avoid a level of nesting with LET. + You may use LET if it makes it clearer + to return one of bound variables after the LOOP, + rather than use a clumsy FINALLY (RETURN ...) form. +

+

+ In the body of a DOTIMES, + do not set the iteration variable. + (CCL will issue a compiler warning if you do.) +

+

+ Most systems use unadorned symbols in the current package + as LOOP keywords. + Other systems use actual :keywords + from the KEYWORD package + as LOOP keywords. + You must be consistent with the convention used in your system. +

+ +
+ + + Use the appropriate I/O functions. + + +

+ When writing a server, + code must not send output to the standard streams such as + *STANDARD-OUTPUT* or *ERROR-OUTPUT*. + Instead, code must use the proper logging framework + to output messages for debugging. + We are running as a server, so there is no console! +

+

+ Code must not use PRINT-OBJECT + to communicate with a user — + PRINT-OBJECT is for debugging purposes only. + Modifying any PRINT-OBJECT method + must not break any public interfaces. +

+

+ You should not use a sequence of WRITE-XXX + where a single FORMAT string could be used. + Using format allows you + to parameterize the format control string in the future + if the need arises. +

+

+ You should use WRITE-CHAR to emit a character + rather than WRITE-STRING + to emit a single-character string. +

+

+ You should not use (format nil "~A" value); + you should use PRINC-TO-STRING instead. +

+

+ You should use ~<Newline> + or ~@<Newline> in format strings + to keep them from wrapping in 100-column editor windows, + or to indent sections or clauses to make them more readable. +

+

+ You should not use STRING-UPCASE + or STRING-DOWNCASE + on format control parameters; + instead, it should use "~:@(~A~)" or "~(~A~)". +

+

+ Be careful when using the FORMAT conditional directive. + The parameters are easy to forget. +

+
+
No parameters, e.g. "~[Siamese~;Manx~;Persian~] Cat"
+
+ Take one format argument, which should be an integer. + Use it to choose a clause. Clause numbers are zero-based. + If the number is out of range, just print nothing. + You can provide a default value + by putting a ":" in front of the last ";". + E.g. in "~[Siamese~;Manx~;Persian~:;Alley~] Cat", + an out-of-range arg prints "Alley". +
+
: parameter, e.g. "~:[Siamese~;Manx~]"
+
+ Take one format argument. If it's NIL, + use the first clause, otherwise use the second clause. +
+
@ parameter, e.g. "~@[Siamese ~a~]"
+
+ If the next format argument is true, + use the choice, but do NOT take the argument. + If it's false, take one format argument and print nothing. + (Normally the clause uses the format argument.) +
+
# parameter, e.g. "~#[ none~; ~s~; ~s and ~s~]"
+
+ Use the number of arguments to format + as the number to choose a clause. + The same as no parameters in all other ways. + Here's the full hairy example: + "Items:~#[ none~; ~S~; ~S and ~S~:;~@{~#[~; and~] ~S~^ ,~}~]." +
+
+ +
+
+ + + + + You should avoid unnecessary allocation of memory. + + +

+ In a language with automatic storage management (such as Lisp or Java), + the colloquial phrase "memory leak" refers to situation + where storage that is not actually needed + nevertheless does not get deallocated, + because it is still reachable. +

+

+ You should be careful that when you create objects, + you don't leave them reachable after they are no longer needed! +

+

+ Here's a particular trap-for-the-unwary in Common Lisp. + If you make an array with a fill pointer, and put objects in it, + and then set the fill pointer back to zero, + those objects are still reachable as far as Lisp goes + (the Common Lisp spec says that it's still OK + to refer to the array entries past the end of the fill pointer). +

+

+ Don't cons (i.e., allocate) unnecessarily. + Garbage collection is not magic. + Excessive allocation is usually a performance problem. +

+ +
+ + + You must only use faster unsafe operations + when there is a clear performance need + and you can document why it's correct. + + +

+ Common Lisp implementations often provide backdoors + to compute some operations faster in an unsafe way. + For instance, some libraries provide arithmetic operations + that are designed to be used with fixnums only, + and yield the correct result faster if provided proper arguments. + The downside is that the result of such operations + is incorrect in case of overflow, and can + have undefined behavior when called with anything but fixnums. +

+ +

+ More generally, unsafe operations + will yield the correct result faster + than would the equivalent safe operation + if the arguments satisfy some invariant such as + being of the correct type and small enough; + however if the arguments fail to satisfy the required invariants, + then the operation may have undefined behavior, + such as crashing the software, or, + which is sometimes worse, silently giving wrong answers. + Depending on whether the software is piloting an aircraft + or other life-critical device, + or whether it is accounting for large amounts money, + such undefined behavior can kill or bankrupt people. + Yet proper speed can sometimes make the difference between + software that's unusably slow and software that does its job, + or between software that is a net loss + and software that can yield a profit. +

+

+ You must not define or use unsafe operations without both + profiling results indicating the need for this optimization, + and careful documentation explaining why it is safe to use them. + Unsafe operations should be restricted to internal functions; + you should carefully documented how unsafe it is + to use these functions with the wrong arguments. + You should only use unsafe operations + inside functions internal to a package and + you should document the use of the declarations, + since calling the functions with arguments of the wrong type + can lead to undefined behavior. + Use check-type in functions exported from a package + to sanitize input arguments, + so that internal functions are never passed illegal values. +

+

+ On some compilers, + new unsafe operations + can usually be defined by combining + type declarations with an OPTIMIZE declaration + that has sufficiently high SPEED and low SAFETY. + In addition to providing more speed for production code, + such declarations may more helpful + than check-type assertions + for finding bugs at compile-time, + on compilers that have type inference. + These compilers may interpret those declarations as assertions + if you switch to safer and slower optimize settings; + this is good to locate a dynamic error in your code during development, + but is not to be used for production code since + it defeats the purpose of declarations as a performance trick. +

+ + +
+ + + You should only use DYNAMIC-EXTENT + where it matters for performance, + and you can document why it is correct. + + +

+ DYNAMIC-EXTENT declarations are + a particular case of + unsafe operations. +

+

+ The purpose of a DYNAMIC-EXTENT declaration + is to improve performance by reducing garbage collection + in cases where it appears to be obvious that an object's lifetime + is within the "dynamic extent" of a function. + That means the object is created at some point + after the function is called, and + the object is always inaccessible after the function exits by any means. +

+

+ By declaring a variable or a local function DYNAMIC-EXTENT, + the programmer asserts to Lisp + that any object that is ever a value of that variable + or the closure that is the definition of the function + has a lifetime within the dynamic extent of the (innermost) function + that declares the variable. +

+

+ The Lisp implementation is then free to use that information + to make the program faster. + Typically, Lisp implementations can take advantage of this knowledge + to stack-allocate: +

+
    +
  • + The lists created to store &REST parameters. +
  • +
  • + Lists, vectors and structures allocated within a function. +
  • +
  • + Closures. +
  • +
+

+ If the assertion is wrong, i.e. if the programmer's claim is not true, + the results can be catastrophic: + Lisp can terminate any time after the function returns, + or it can hang forever, or — worst of all — + it can produce incorrect results without any runtime error! +

+

+ Even if the assertion is correct, + future changes to the function might introduce + a violation of the assertion. + This increases the danger. +

+

+ In most cases, such objects are ephemeral. + Modern Lisp implementations use generational garbage collectors, + which are quite efficient under these circumstances. +

+

+ Therefore, DYNAMIC-EXTENT declarations + should be used sparingly. You must only use them if: +

+
    +
  1. + There is some good reason to think that the overall effect + on performance is noticeable, and +
  2. +
  3. + It is absolutely clear that the assertion is true. +
  4. +
  5. + It is quite unlikely that the code will be changed + in ways that cause the declaration to become false. +
  6. +
+

+ Point (1) is a special case of + the principle of avoiding premature optimization. + An optimization like this only matters if such objects + are allocated at a very high rate, e.g. "inside an inner loop". +

+

+ Note that is relatively easy to ascertain that + a function will not escape the dynamic extent of the current call frame + by analyzing where the function is called and + what other functions it is passed to; + therefore, you should somewhat wary of declaring a function + DYNAMIC-EXTENT, but this is not a high-stress declaration. + On the other hand, it is much harder to ascertain that + none of the objects ever bound or assigned to that variable + and none of their sub-objects + will escape the dynamic extent of the current call frame, + and that they still won't in any future modification of a function. + Therefore, you should be extremely wary + of declaring a variable DYNAMIC-EXTENT. +

+

+ It's usually hard to predict the effect of such optimization on performance. + When writing a function or macro + that is part of a library of reusable code, + there's no a priori way to know how often the code will run. + Ideally, tools would be available to discover + the availability and suitability of using such an optimization + based on running simulations and test cases, but + in practice this isn't as easy as it ought to be. + It's a tradeoff. + If you're very, very sure that the assertion is true + (that any object bound to the variable and any of its sub-objects + are only used within the dynamic extent of the specified scope), + and it's not obvious how much time will be saved + and it's not easy to measure, + then it may be better to put in the declaration than to leave it out. + (Ideally it would be easier to make such measurements + than it actually is.) +

+ +
+ + + You should use REDUCE + instead of APPLY where appropriate. + + +

+ You should use REDUCE + instead of APPLY and a consed-up list, + where the semantics of the first operator argument + otherwise guarantees the same semantics. + Of course, you must use APPLY + if it does what you want and REDUCE doesn't. + For instance: +

+ + ;; Bad + (apply #'+ (mapcar #'acc frobs)) + + + ;; Better + (reduce #'+ frobs :key #'acc :initial-value 0) + +

+ This is preferable because it does not do extra consing, + and does not risk going beyond CALL-ARGUMENTS-LIMIT + on implementations where that limit is small, + which could blow away the stack on long lists + (we want to avoid gratuitous non-portability in our code). +

+

+ However, you must be careful not to use REDUCE + in ways that needlessly increase + the complexity class of the computation. + For instance, (REDUCE 'STRCAT ...) is O(n^2) + when an appropriate implementation is only O(n). + Moreover, (REDUCE 'APPEND ...) + is also O(n^2) unless you specify :FROM-END T. + In such cases, you MUST NOT use REDUCE, + and you MUST NOT use (APPLY 'STRCAT ...) + or (APPLY 'APPEND ...) either. + Instead you MUST use proper abstractions + from a suitable library (that you may have to contribute to) + that properly handles those cases + without burdening users with implementation details. + See for instance UIOP:REDUCE/STRCAT. +

+ + +
+ + + You should not use NCONC; + you should use APPEND instead, + or better, better data structures. + + +

+ You should almost never use NCONC. + You should use APPEND + when you don't depend on any side-effect. + You should use ALEXANDRIA:APPENDF + when you need to update a variable. + You should probably not depend on games + being played with the CDR + of the current CONS cell + (which some might argue is suggested but not guaranteed by the specification); + if you do, you must include a prominent + comment explaining the use of NCONC; + and you should probably reconsider your data representation strategy. +

+

+ By extension, you should avoid MAPCAN + or the NCONC feature of LOOP. + You should instead respectively use + ALEXANDRIA:MAPPEND + and the APPEND feature of LOOP. +

+

+ NCONC is very seldom a good idea, + since its time complexity class is no better than APPEND, + its space complexity class also is no better than APPEND + in the common case where no one else is sharing the side-effected list, + and its bug complexity class is way higher than APPEND. +

+

+ If the small performance hit due + to APPEND vs. NCONC + is a limiting factor in your program, + you have a big problem and are probably using the wrong data structure: + you should be using sequences with constant-time append + (see Okasaki's book, and add them to lisp-interface-library), + or more simply you should be accumulating data in a tree + that will get flattened once in linear time + after the accumulation phase is complete. +

+

+ You may only use NCONC, MAPCAN + or the NCONC feature of LOOP + in low-level functions where performance matters, + where the use of lists as a data structure has been vetted + because these lists are known to be short, + and when the function or expression the result of which are accumulated + explicitly promises in its contract that it only returns fresh lists + (in particular, it can't be a constant quote or backquote expression). + Even then, the use of such primitives must be rare, + and accompanied by justifying documentation. +

+ +
+
+ + + + + You should usually refer to a function as #'FUN rather than 'FUN. + + +

+ The former, which reads as (FUNCTION FUN), + refers to the function object, and is lexically scoped. + The latter, which reads as (QUOTE FUN), + refers to the symbol, which when called + uses the global FDEFINITION of the symbol. +

+

+ When using functions that take a functional argument + (e.g., MAPCAR, APPLY, + :TEST and :KEY arguments), + you should use the #' to refer to the function, + not just single quote. +

+

+ An exception is when you explicitly want dynamic linking, + because you anticipate that + the global function binding will be updated. +

+

+ Another exception is when you explicitly want to access + a global function binding, + and avoid a possible shadowing lexical binding. + This shouldn't happen often, as it is usually a bad idea + to shadow a function when you will want to use the shadowed function; + just use a different name for the lexical function. +

+

+ You must consistently use either #'(lambda ...) + or (lambda ...) without #' everywhere. + Unlike the case of #'symbol vs 'symbol, + it is only a syntactic difference with no semantic impact, + except that the former works on Genera and the latter doesn't. + + You must use the former style if your code is intended as a library + with maximal compatibility to all Common Lisp implementations; + otherwise, it is optional which style you use. + #' may be seen as a hint + that you're introducing a function in expression context; + but the lambda itself is usually sufficient hint, + and concision is good. + Choose wisely, but above all, + consistently with yourself and other developers, + within a same file, package, system, project, etc. +

+

+ Note that if you start writing a new system + in a heavily functional style, + you may consider using + lambda-reader, + a system that lets you use the unicode character λ + instead of LAMBDA. + But you must not start using such a syntactic extension + in an existing system without getting permission from other developers. +

+ +
+ + + Common Lisp pathnames are tricky. Be aware of pitfalls. Use UIOP. + + +

+ It is surprisingly hard to properly deal with pathnames in Common Lisp. +

+

+ ASDF 3 comes with a portability library UIOP + that makes it much easier to deal with pathnames + portably — and correctly — in Common Lisp. + You should use it when appropriate. +

+

+ First, be aware of the discrepancies between + the syntax of Common Lisp pathnames, + which depends on which implementation and operating system + you are using, + and the native syntax of pathnames on your operating system. + The Lisp syntax may involves quoting of special characters + such as #\. and #\*, etc., + in addition to the quoting of + #\\ and #\" within strings. + By contrast, your operating system's other + system programming languages + (shell, C, scripting languages) + may only have one layer of quoting, into strings. +

+

+ Second, when using MERGE-PATHNAMES, + be wary of the treatment of the HOST component, + which matters a lot on non-Unix platforms + (and even on some Unix implementations). + You probably should be using + UIOP:MERGE-PATHNAMES* or UIOP:SUBPATHNAME + instead of MERGE-PATHNAMES, + especially if your expectations for relative pathnames + are informed by the way they work in Unix or Windows; + otherwise you might hit weird bugs whereby on some implementations, + merging a relative pathnames with an absolute pathname + results in overriding the absolute pathname's host + and replace it with the host from the value of + *DEFAULT-PATHNAME-DEFAULTS* + at the time the relative pathname was created. +

+

+ Third, be aware that DIRECTORY + is not portable across implementations + in how it handles wildcards, sub-directories, symlinks, etc. + There again, UIOP provides several + common abstractions to deal with pathnames, + but only does so good a job. + For a complete portable solution, use IOLib — + though its Windows support lags behind. +

+

+ LOGICAL-PATHNAMEs are not a portable abstraction, + and should not be used in portable code. + Many implementations have bugs in them, when they are supported at all. + SBCL implements them very well, + but strictly enforces the limitations on characters + allowed by the standard, which restricts their applicability. + Other implementations allow arbitrary characters in such pathnames, + but in doing so are not being conformant, + and are still incompatible with each other in many ways. + You should use other pathname abstractions, + such as ASDF:SYSTEM-RELATIVE-PATHNAME or + the underlying UIOP:SUBPATHNAME and + UIOP:PARSE-UNIX-NAMESTRING. +

+ +

+ Finally, be aware that paths may change between + the time you build the Lisp image for your application, + and the time you run the application from its image. + You should be careful to reset your image + to forget irrelevant build-time paths and + reinitialize any search path from current environment variables. + ASDF for instance requires you to reset its paths + with UIOP:CLEAR-CONFIGURATION. + UIOP provides hooks + to call functions before an image is dumped, + from which to reset or makunbound relevant variables. +

+ + +
+ + + You must be careful when using a SATISFIES clause in a type specifier. + + +

+ Most Common Lisp implementations can't optimize + based on a SATISFIES type, + but many of them offer simple optimizations + based on a type of the form + (AND FOO (SATISFIES BAR-P)) + where the first term of the AND clause + describes the structure of the object + without any SATISFIES + and the second term is the SATISFIES. +

+ + (deftype prime-number () (satisfies prime-number-p)) ; Bad + + + (deftype prime-number () (and integer (satisfies prime-number-p)) ; Better + +

+ However, AND in the DEFTYPE language + isn't a left-to-right short-circuit operator + as in the expression language; + it is a symmetrical connector that allows for reordering subterms + and doesn't guarantee short-circuiting. + Therefore, in the above example, + you cannot rely on the test for INTEGERness + to protect the function PRIME-NUMBER-P + from being supplied non-integer arguments + to test for being of instances of the type. + Implementations may, and some will, + invoke SATISFIES-specified function + at compile-time to test various relevant objects. +

+

+ That is why any function specified in a SATISFIES clause + MUST accept objects of any type as argument to the function, + and MUST be defined within an EVAL-WHEN + (as well as any variable it uses or function it calls): +

+ + (defun prime-number-p (n) ; Doubly bad! + (let ((m (abs n))) + (if (<= m *prime-number-cutoff*) + (small-prime-number-p m) + (big-prime-number-p m)))) + + + (eval-when (:compile-toplevel :load-toplevel :execute) ; Better + (defun prime-number-p (n) + (when (integerp n) ; Better + (let ((m (abs n))) + (if (<= m *prime-number-cutoff*) + (small-prime-number-p m) + (big-prime-number-p m)))))) + +

+ In particular, the above means that the + example + used in the Common Lisp Standard is erroneous: + (and integer (satisfies evenp)) + is not a safe, conformant type specifier to use, + because EVENP will throw an error + rather than return NIL + when passed a non-integer as an argument. +

+

+ Finally, there is a catch when your DEFTYPE code expands + to a SATISFIES with a dynamically generated function: +

+
    +
  • + You cannot control when implementations will or will not + expand a DEFTYPE. +
  • +
  • + The expansion itself cannot contain a function definition + or any code in the expression language. +
  • +
  • + You cannot control when the expansion is used, + it may happen in a different process + that didn't expand the definition. +
  • +
+

+ Therefore, you cannot merely create the function + as a side-effect of expansion + using EVAL at type-expansion time. + The solution is to use + ASDF-FINALIZERS:EVAL-AT-TOPLEVEL instead. + See the very last point + in the discussion about EVAL. +

+

+ Common Lisp is hard to satisfy. +

+ +
+
+ +
+ +Credits: + Adam Worrall, Dan Pierson, Matt Marjanovic, Matt Reklaitis, + Paul Weiss, Scott McKay, Sundar Narasimhan, + and several other people contributed. + Special thanks to Steve Hain, + and to the previous editors, + in reverse chronological order Dan Weinreb and Jeremy Brown. + + +

+Revision 1.28 +

+ + +
+Robert Brown +
+ +
+ François-René Rideau +
+ + + +
diff --git a/objcguide.md b/objcguide.md new file mode 100644 index 000000000..7d965ce67 --- /dev/null +++ b/objcguide.md @@ -0,0 +1,1661 @@ +# Google Objective-C Style Guide + + +> Objective-C is a dynamic, object-oriented extension of C. It's designed to be +> easy to use and read, while enabling sophisticated object-oriented design. It +> is the primary development language for applications on OS X and on iOS. +> +> Apple has already written a very good, and widely accepted, [Cocoa Coding +> Guidelines](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html) +> for Objective-C. Please read it in addition to this guide. +> +> +> The purpose of this document is to describe the Objective-C (and +> Objective-C++) coding guidelines and practices that should be used for iOS and +> OS X code. These guidelines have evolved and been proven over time on other +> projects and teams. +> Open-source projects developed by Google conform to the requirements in this guide. +> +> Note that this guide is not an Objective-C tutorial. We assume that the reader +> is familiar with the language. If you are new to Objective-C or need a +> refresher, please read [Programming with +> Objective-C](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html). + + +## Principles + +### Optimize for the reader, not the writer + +Codebases often have extended lifetimes and more time is spent reading the code +than writing it. We explicitly choose to optimize for the experience of our +average software engineer reading, maintaining, and debugging code in our +codebase rather than the ease of writing said code. For example, when something +surprising or unusual is happening in a snippet of code, leaving textual hints +for the reader is valuable. + +### Be consistent + +When the style guide allows multiple options it is preferable to pick one option +over mixed usage of multiple options. Using one style consistently throughout a +codebase lets engineers focus on other (more important) issues. Consistency also +enables better automation because consistent code allows more efficient +development and operation of tools that format or refactor code. In many cases, +rules that are attributed to "Be Consistent" boil down to "Just pick one and +stop worrying about it"; the potential value of allowing flexibility on these +points is outweighed by the cost of having people argue over them. + +### Be consistent with Apple SDKs + +Consistency with the way Apple SDKs use Objective-C has value for the same +reasons as consistency within our code base. If an Objective-C feature solves a +problem that's an argument for using it. However, sometimes language features +and idioms are flawed, or were just designed with assumptions that are not +universal. In those cases it is appropriate to constrain or ban language +features or idioms. + +### Style rules should pull their weight + +The benefit of a style rule must be large enough to justify asking engineers to +remember it. The benefit is measured relative to the codebase we would get +without the rule, so a rule against a very harmful practice may still have a +small benefit if people are unlikely to do it anyway. This principle mostly +explains the rules we don’t have, rather than the rules we do: for example, goto +contravenes many of the following principles, but is not discussed due to its +extreme rarity. + +## Example + +They say an example is worth a thousand words, so let's start off with an +example that should give you a feel for the style, spacing, naming, and so on. + +Here is an example header file, demonstrating the correct commenting and spacing +for an `@interface` declaration. + +```objectivec +// GOOD: + +#import + +@class Bar; + +/** + * A sample class demonstrating good Objective-C style. All interfaces, + * categories, and protocols (read: all non-trivial top-level declarations + * in a header) MUST be commented. Comments must also be adjacent to the + * object they're documenting. + */ +@interface Foo : NSObject + +/** The retained Bar. */ +@property(nonatomic) Bar *bar; + +/** The current drawing attributes. */ +@property(nonatomic, copy) NSDictionary *attributes; + +/** + * Convenience creation method. + * See -initWithBar: for details about @c bar. + * + * @param bar The string for fooing. + * @return An instance of Foo. + */ ++ (instancetype)fooWithBar:(Bar *)bar; + +/** + * Designated initializer. + * + * @param bar A string that represents a thing that does a thing. + */ +- (instancetype)initWithBar:(Bar *)bar; + +/** + * Does some work with @c blah. + * + * @param blah + * @return YES if the work was completed; NO otherwise. + */ +- (BOOL)doWorkWithBlah:(NSString *)blah; + +@end +``` + +An example source file, demonstrating the correct commenting and spacing for the +`@implementation` of an interface. + +```objectivec +// GOOD: + +#import "Shared/Util/Foo.h" + +@implementation Foo { + /** The string used for displaying "hi". */ + NSString *_string; +} + ++ (instancetype)fooWithBar:(Bar *)bar { + return [[self alloc] initWithBar:bar]; +} + +- (instancetype)init { + // Classes with a custom designated initializer should always override + // the superclass's designated initializer. + return [self initWithBar:nil]; +} + +- (instancetype)initWithBar:(Bar *)bar { + self = [super init]; + if (self) { + _bar = [bar copy]; + _string = [[NSString alloc] initWithFormat:@"hi %d", 3]; + _attributes = @{ + @"color" : [UIColor blueColor], + @"hidden" : @NO + }; + } + return self; +} + +- (BOOL)doWorkWithBlah:(NSString *)blah { + // Work should be done here. + return NO; +} + +@end +``` + +## Spacing and Formatting + +### Spaces vs. Tabs + +Use only spaces, and indent 2 spaces at a time. We use spaces for indentation. +Do not use tabs in your code. + +You should set your editor to emit spaces when you hit the tab key, and to trim +trailing spaces on lines. + +### Line Length + +The maximum line length for Objective-C files is 100 columns. + +You can make violations easier to spot by enabling *Preferences > Text Editing > +Page guide at column: 100* in Xcode. + +### Method Declarations and Definitions + +One space should be used between the `-` or `+` and the return type, and no +spacing in the parameter list except between parameters. + +Methods should look like this: + +```objectivec +// GOOD: + +- (void)doSomethingWithString:(NSString *)theString { + ... +} +``` + +The spacing before the asterisk is optional. When adding new code, be consistent +with the surrounding file's style. + +If you have too many parameters to fit on one line, giving each its own line is +preferred. If multiple lines are used, align each using the colon before the +parameter. + +```objectivec +// GOOD: + +- (void)doSomethingWithFoo:(GTMFoo *)theFoo + rect:(NSRect)theRect + interval:(float)theInterval { + ... +} +``` + +When the second or later parameter name is longer than the first, indent the +second and later lines by at least four spaces, maintaining colon alignment: + +```objectivec +// GOOD: + +- (void)short:(GTMFoo *)theFoo + longKeyword:(NSRect)theRect + evenLongerKeyword:(float)theInterval + error:(NSError **)theError { + ... +} +``` + +### Conditionals + +Include a space after `if`, `while`, `for`, and `switch`, and around comparison +operators. + +```objectivec +// GOOD: + +for (int i = 0; i < 5; ++i) { +} + +while (test) {}; +``` + +Braces may be omitted when a loop body or conditional statement fits on a single +line. + +```objectivec +// GOOD: + +if (hasSillyName) LaughOutLoud(); + +for (int i = 0; i < 10; i++) { + BlowTheHorn(); +} +``` + +```objectivec +// AVOID: + +if (hasSillyName) + LaughOutLoud(); // AVOID. + +for (int i = 0; i < 10; i++) + BlowTheHorn(); // AVOID. +``` + +If an `if` clause has an `else` clause, both clauses should use braces. + +```objectivec +// GOOD: + +if (hasBaz) { + foo(); +} else { + bar(); +} +``` + +```objectivec +// AVOID: + +if (hasBaz) foo(); +else bar(); // AVOID. + +if (hasBaz) { + foo(); +} else bar(); // AVOID. +``` + +Intentional fall-through to the next case should be documented with a comment +unless the case has no intervening code before the next case. + +```objectivec +// GOOD: + +switch (i) { + case 1: + ... + break; + case 2: + j++; + // Falls through. + case 3: { + int k; + ... + break; + } + case 4: + case 5: + case 6: break; +} +``` + +### Expressions + +Use a space around binary operators and assignments. Omit a space for a unary +operator. Do not add spaces inside parentheses. + +```objectivec +// GOOD: + +x = 0; +v = w * x + y / z; +v = -y * (x + z); +``` + +Factors in an expression may omit spaces. + +```objectivec +// GOOD: + +v = w*x + y/z; +``` + +### Method Invocations + +Method invocations should be formatted much like method declarations. + +When there's a choice of formatting styles, follow the convention already used +in a given source file. Invocations should have all arguments on one line: + +```objectivec +// GOOD: + +[myObject doFooWith:arg1 name:arg2 error:arg3]; +``` + +or have one argument per line, with colons aligned: + +```objectivec +// GOOD: + +[myObject doFooWith:arg1 + name:arg2 + error:arg3]; +``` + +Don't use any of these styles: + +```objectivec +// AVOID: + +[myObject doFooWith:arg1 name:arg2 // some lines with >1 arg + error:arg3]; + +[myObject doFooWith:arg1 + name:arg2 error:arg3]; + +[myObject doFooWith:arg1 + name:arg2 // aligning keywords instead of colons + error:arg3]; +``` + +As with declarations and definitions, when the first keyword is shorter than the +others, indent the later lines by at least four spaces, maintaining colon +alignment: + +```objectivec +// GOOD: + +[myObj short:arg1 + longKeyword:arg2 + evenLongerKeyword:arg3 + error:arg4]; +``` + +Invocations containing multiple inlined blocks may have their parameter names +left-aligned at a four space indent. + +### Function Calls + +Function calls should include as many parameters as fit on each line, except +where shorter lines are needed for clarity or documentation of the parameters. + +Continuation lines for function parameters may be indented to align with the +opening parenthesis, or may have a four-space indent. + +```objectivec +// GOOD: + +CFArrayRef array = CFArrayCreate(kCFAllocatorDefault, objects, numberOfObjects, + &kCFTypeArrayCallBacks); + +NSString *string = NSLocalizedStringWithDefaultValue(@"FEET", @"DistanceTable", + resourceBundle, @"%@ feet", @"Distance for multiple feet"); + +UpdateTally(scores[x] * y + bases[x], // Score heuristic. + x, y, z); + +TransformImage(image, + x1, x2, x3, + y1, y2, y3, + z1, z2, z3); +``` + +Use local variables with descriptive names to shorten function calls and reduce +nesting of calls. + +```objectivec +// GOOD: + +double scoreHeuristic = scores[x] * y + bases[x]; +UpdateTally(scoreHeuristic, x, y, z); +``` + +### Exceptions + +Format exceptions with `@catch` and `@finally` labels on the same line as the +preceding `}`. Add a space between the `@` label and the opening brace (`{`), as +well as between the `@catch` and the caught object declaration. If you must use +Objective-C exceptions, format them as follows. However, see Avoid Throwing +Exceptions for reasons why you should not be using exceptions. + +```objectivec +// GOOD: + +@try { + foo(); +} @catch (NSException *ex) { + bar(ex); +} @finally { + baz(); +} +``` + +### Function Length + +Prefer small and focused functions. + +Long functions and methods are occasionally appropriate, so no hard limit is +placed on function length. If a function exceeds about 40 lines, think about +whether it can be broken up without harming the structure of the program. + +Even if your long function works perfectly now, someone modifying it in a few +months may add new behavior. This could result in bugs that are hard to find. +Keeping your functions short and simple makes it easier for other people to read +and modify your code. + +When updating legacy code, consider also breaking long functions into smaller +and more manageable pieces. + +### Vertical Whitespace + +Use vertical whitespace sparingly. + +To allow more code to be easily viewed on a screen, avoid putting blank lines +just inside the braces of functions. + +Limit blank lines to one or two between functions and between logical groups of +code. + +## Naming + +Names should be as descriptive as possible, within reason. Follow standard +[Objective-C naming +rules](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html). + +Avoid non-standard abbreviations. Don't worry about saving horizontal space as +it is far more important to make your code immediately understandable by a new +reader. For example: + +```objectivec +// GOOD: + +// Good names. +int numberOfErrors = 0; +int completedConnectionsCount = 0; +tickets = [[NSMutableArray alloc] init]; +userInfo = [someObject object]; +port = [network port]; +NSDate *gAppLaunchDate; +``` + +```objectivec +// AVOID: + +// Names to avoid. +int w; +int nerr; +int nCompConns; +tix = [[NSMutableArray alloc] init]; +obj = [someObject object]; +p = [network port]; +``` + +Any class, category, method, function, or variable name should use all capitals +for acronyms and +[initialisms](https://en.wikipedia.org/wiki/Initialism) +within the name. This follows Apple's standard of using all capitals within a +name for acronyms such as URL, ID, TIFF, and EXIF. + +Names of C functions and typedefs should be capitalized and use camel case as +appropriate for the surrounding code. + +### File Names + +File names should reflect the name of the class implementation that they +contain—including case. + +Follow the convention that your project uses. +File extensions should be as follows: + +Extension | Type +--------- | --------------------------------- +.h | C/C++/Objective-C header file +.m | Objective-C implementation file +.mm | Objective-C++ implementation file +.cc | Pure C++ implementation file +.c | C implementation file + +Files containing code that may be shared across projects or used in a large +project should have a clearly unique name, typically including the project or +class prefix. + +File names for categories should include the name of the class being extended, +like GTMNSString+Utils.h or NSTextView+GTMAutocomplete.h + +### Class Names + +Class names (along with category and protocol names) should start as uppercase +and use mixed case to delimit words. + +When designing code to be shared across multiple applications, prefixes are +acceptable and recommended (e.g. GTMSendMessage). Prefixes are also recommended +for classes of large applications that depend on external libraries. + +### Category Names + +Category names should start with a 3 character prefix identifying the category +as part of a project or open for general use. + +The category name should incorporate the name of the class it's extending. For +example, if we want to create a category on `NSString` for parsing, we would put +the category in a file named `NSString+GTMParsing.h`, and the category itself +would be named `GTMNSStringParsingAdditions`. The file name and the category may +not match, as this file could have many separate categories related to parsing. +Methods in that category should share the prefix +(`gtm_myCategoryMethodOnAString:`) in order to prevent collisions in +Objective-C's global namespace. + +There should be a single space between the class name and the opening +parenthesis of the category. + +```objectivec +// GOOD: + +/** A category that adds parsing functionality to NSString. */ +@interface NSString (GTMNSStringParsingAdditions) +- (NSString *)gtm_parsedString; +@end +``` + +### Objective-C Method Names + +Method and parameter names typically start as lowercase and then use mixed case. + +Proper capitalization should be respected, including at the beginning of names. + +```objectivec +// GOOD: + ++ (NSURL *)URLWithString:(NSString *)URLString; +``` + +The method name should read like a sentence if possible, meaning you should +choose parameter names that flow with the method name. Objective-C method names +tend to be very long, but this has the benefit that a block of code can almost +read like prose, thus rendering many implementation comments unnecessary. + +Use prepositions and conjunctions like "with", "from", and "to" in the second +and later parameter names only where necessary to clarify the meaning or +behavior of the method. + +```objectivec +// GOOD: + +- (void)addTarget:(id)target action:(SEL)action; // GOOD; no conjunction needed +- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view; // GOOD; conjunction clarifies parameter +- (void)replaceCharactersInRange:(NSRange)aRange + withAttributedString:(NSAttributedString *)attributedString; // GOOD. +``` + +A method that returns an object should have a name beginning with a noun +identifying the object returned: + +```objectivec +// GOOD: + +- (Sandwich *)sandwich; // GOOD. +``` + +```objectivec +// AVOID: + +- (Sandwich *)makeSandwich; // AVOID. +``` + +An accessor method should be named the same as the object it's getting, but it +should not be prefixed with the word `get`. For example: + +```objectivec +// GOOD: + +- (id)delegate; // GOOD. +``` + +```objectivec +// AVOID: + +- (id)getDelegate; // AVOID. +``` + +Accessors that return the value of boolean adjectives have method names +beginning with `is`, but property names for those methods omit the `is`. + +Dot notation is used only with property names, not with method names. + +```objectivec +// GOOD: + +@property(nonatomic, getter=isGlorious) BOOL glorious; +- (BOOL)isGlorious; + +BOOL isGood = object.glorious; // GOOD. +BOOL isGood = [object isGlorious]; // GOOD. +``` + +```objectivec +// AVOID: + +BOOL isGood = object.isGlorious; // AVOID. +``` + +```objectivec +// GOOD: + +NSArray *frogs = [NSArray arrayWithObject:frog]; +NSEnumerator *enumerator = [frogs reverseObjectEnumerator]; // GOOD. +``` + +```objectivec +// AVOID: + +NSEnumerator *enumerator = frogs.reverseObjectEnumerator; // AVOID. +``` + +See [Apple's Guide to Naming +Methods](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.html#//apple_ref/doc/uid/20001282-BCIGIJJF) +for more details on Objective-C naming. + +These guidelines are for Objective-C methods only. C++ method names continue to +follow the rules set in the C++ style guide. + +### Function Names + +Regular functions have mixed case. + +Ordinarily, functions should start with a capital letter and have a capital +letter for each new word (a.k.a. "[Camel +Case](https://en.wikipedia.org/wiki/Camel_case)" or "Pascal case"). + +```objectivec +// GOOD: + +static void AddTableEntry(NSString *tableEntry); +static BOOL DeleteFile(char *filename); +``` + +Because Objective-C does not provide namespacing, non-static functions should +have a prefix that minimizes the chance of a name collision. + +```objectivec +// GOOD: + +extern NSTimeZone *GTMGetDefaultTimeZone(); +extern NSString *GTMGetURLScheme(NSURL *URL); +``` + +### Variable Names + +Variable names typically start with a lowercase and use mixed case to delimit +words. + +Instance variables have leading underscores. File scope or global variables have +a prefix `g`. For example: `myLocalVariable`, `_myInstanceVariable`, +`gMyGlobalVariable`. + +#### Common Variable Names + +Readers should be able to infer the variable type from the name, but do not use +Hungarian notation for syntactic attributes, such as the static type of a +variable (int or pointer). + +File scope or global variables (as opposed to constants) declared outside the +scope of a method or function should be rare, and should have the prefix g. + +```objectivec +// GOOD: + +static int gGlobalCounter; +``` + +#### Instance Variables + +Instance variable names are mixed case and should be prefixed with an +underscore, like `_usernameTextField`. + +NOTE: Google's previous convention for Objective-C ivars was a trailing +underscore. Existing projects may opt to continue using trailing underscores in +new code in order to maintain consistency within the project codebase. +Consistency of prefix or suffix underscores should be maintained within each +class. + +#### Constants + +Constant symbols (const global and static variables and constants created +with #define) should use mixed case to delimit words. + +Global and file scope constants should have an appropriate prefix. + +```objectivec +// GOOD: + +extern NSString *const GTLServiceErrorDomain; + +typedef NS_ENUM(NSInteger, GTLServiceError) { + GTLServiceErrorQueryResultMissing = -3000, + GTLServiceErrorWaitTimedOut = -3001, +}; +``` + +Because Objective-C does not provide namespacing, constants with external +linkage should have a prefix that minimizes the chance of a name collision, +typically like `ClassNameConstantName` or `ClassNameEnumName`. + +For interoperability with Swift code, enumerated values should have names that +extend the typedef name: + +```objectivec +// GOOD: + +typedef NS_ENUM(NSInteger, DisplayTinge) { + DisplayTingeGreen = 1, + DisplayTingeBlue = 2, +}; +``` + +Constants may use a lowercase k prefix when appropriate: + +```objectivec +// GOOD: + +static const int kFileCount = 12; +static NSString *const kUserKey = @"kUserKey"; +``` + +## Types and Declarations + +### Local Variables + +Declare variables in the narrowest practical scopes, and close to their use. +Initialize variables in their declarations. + +```objectivec +// GOOD: + +CLLocation *location = [self lastKnownLocation]; +for (int meters = 1; meters < 10; meters++) { + reportFrogsWithinRadius(location, meters); +} +``` + +Occasionally, efficiency will make it more appropriate to declare a variable +outside the scope of its use. This example declares meters separate from +initialization, and needlessly sends the lastKnownLocation message each time +through the loop: + +```objectivec +// AVOID: + +int meters; // AVOID. +for (meters = 1; meters < 10; meters++) { + CLLocation *location = [self lastKnownLocation]; // AVOID. + reportFrogsWithinRadius(location, meters); +} +``` + +Under Automatic Reference Counting, pointers to Objective-C objects are by +default initialized to `nil`, so explicit initialization to `nil` is not +required. + +### Unsigned Integers + +Avoid unsigned integers except when matching types used by system interfaces. + +Subtle errors crop up when doing math or counting down to zero using unsigned +integers. Rely only on signed integers in math expressions except when matching +NSUInteger in system interfaces. + +```objectivec +// GOOD: + +NSUInteger numberOfObjects = array.count; +for (NSInteger counter = numberOfObjects - 1; counter > 0; --counter) +``` + +```objectivec +// AVOID: + +for (NSUInteger counter = numberOfObjects - 1; counter > 0; --counter) // AVOID. +``` + +Unsigned integers may be used for flags and bitmasks, though often NS_OPTIONS or +NS_ENUM will be more appropriate. + +### Types with Inconsistent Sizes + +Due to sizes that differ in 32- and 64-bit builds, avoid types long, NSInteger, +NSUInteger, and CGFloat except when matching system interfaces. + +Types long, NSInteger, NSUInteger, and CGFloat vary in size between 32- and +64-bit builds. Use of these types is appropriate when handling values exposed by +system interfaces, but they should be avoided for most other computations. + +```objectivec +// GOOD: + +int32_t scalar1 = proto.intValue; + +int64_t scalar2 = proto.longValue; + +NSUInteger numberOfObjects = array.count; + +CGFloat offset = view.bounds.origin.x; +``` + +```objectivec +// AVOID: + +NSInteger scalar2 = proto.longValue; // AVOID. +``` + +File and buffer sizes often exceed 32-bit limits, so they should be declared +using `int64_t`, not with `long`, `NSInteger`, or `NSUInteger`. + +## Comments + +Comments are absolutely vital to keeping our code readable. The following rules +describe what you should comment and where. But remember: while comments are +important, the best code is self-documenting. Giving sensible names to types and +variables is much better than using obscure names and then trying to explain +them through comments. + +Pay attention to punctuation, spelling, and grammar; it is easier to read +well-written comments than badly written ones. + +Comments should be as readable as narrative text, with proper capitalization and +punctuation. In many cases, complete sentences are more readable than sentence +fragments. Shorter comments, such as comments at the end of a line of code, can +sometimes be less formal, but use a consistent style. +When writing your comments, write for your audience: the next contributor who will need to understand your code. Be generous—the next one may be you! + +### File Comments + +A file may optionally start with a description of its contents. +Every file may contain the following items, in order: + * License boilerplate if necessary. Choose the appropriate boilerplate for the license used by the project. + * A basic description of the contents of the file if necessary. + +If you make significant changes to a file with an author line, consider deleting +the author line since revision history already provides a more detailed and +accurate record of authorship. + + +### Declaration Comments + +Every non-trivial interface, public and private, should have an accompanying +comment describing its purpose and how it fits into the larger picture. + +Comments should be used to document classes, properties, ivars, functions, +categories, protocol declarations, and enums. + +```objectivec +// GOOD: + +/** + * A delegate for NSApplication to handle notifications about app + * launch and shutdown. Owned by the main app controller. + */ +@interface MyAppDelegate : NSObject { + /** + * The background task in progress, if any. This is initialized + * to the value UIBackgroundTaskInvalid. + */ + UIBackgroundTaskIdentifier _backgroundTaskID; +} + +/** The factory that creates and manages fetchers for the app. */ +@property(nonatomic) GTMSessionFetcherService *fetcherService; + +@end +``` + +Doxygen-style comments are encouraged for interfaces as they are parsed by Xcode +to display formatted documentation. There is a wide variety of Doxygen commands; +use them consistently within a project. + +If you have already described an interface in detail in the comments at the top +of your file, feel free to simply state, "See comment at top of file for a +complete description", but be sure to have some sort of comment. + +Additionally, each method should have a comment explaining its function, +arguments, return value, thread or queue assumptions, and any side effects. +Documentation comments should be in the header for public methods, or +immediately preceding the method for non-trivial private methods. + +Use descriptive form ("Opens the file") rather than imperative form ("Open the +file") for method and function comments. The comment describes the function; it +does not tell the function what to do. + +Document the thread usage assumptions the class, properties, or methods make, if +any. If an instance of the class can be accessed by multiple threads, take extra +care to document the rules and invariants surrounding multithreaded use. + +Any sentinel values for properties and ivars, such as `NULL` or `-1`, should be +documented in comments. + +Declaration comments explain how a method or function is used. Comments +explaining how a method or function is implemented should be with the +implementation rather than with the declaration. + +### Implementation Comments + +Provide comments explaining tricky, subtle, or complicated sections of code. + +```objectivec +// GOOD: + +// Set the property to nil before invoking the completion handler to +// avoid the risk of reentrancy leading to the callback being +// invoked again. +CompletionHandler handler = self.completionHandler; +self.completionHandler = nil; +handler(); +``` + +When useful, also provide comments about implementation approaches that were +considered or abandoned. + +End-of-line comments should be separated from the code by at least 2 spaces. If +you have several comments on subsequent lines, it can often be more readable to +line them up. + +```objectivec +// GOOD: + +[self doSomethingWithALongName]; // Two spaces before the comment. +[self doSomethingShort]; // More spacing to align the comment. +``` + +### Disambiguating Symbols + +Where needed to avoid ambiguity, use backticks or vertical bars to quote +variable names and symbols in comments in preference to using quotation marks +or naming the symbols inline. + +In Doxygen-style comments, prefer demarcating symbols with a monospace text +command, such as `@c`. + +Demarcation helps provide clarity when a symbol is a common word that might make +the sentence read like it was poorly constructed. A common example is the symbol +`count`: + +```objectivec +// GOOD: + +// Sometimes `count` will be less than zero. +``` + +or when quoting something which already contains quotes + +```objectivec +// GOOD: + +// Remember to call `StringWithoutSpaces("foo bar baz")` +``` + +Backticks or vertical bars are not needed when a symbol is self-apparent. + +```objectivec +// GOOD: + +// This class serves as a delegate to GTMDepthCharge. +``` + +Doxygen formatting is also suitable for identifying symbols. + +```objectivec +// GOOD: + +/** @param maximum The highest value for @c count. */ +``` + +### Object Ownership + +For objects not managed by ARC, make the pointer ownership model as explicit as +possible when it falls outside the most common Objective-C usage idioms. + +#### Manual Reference Counting + +Instance variables for NSObject-derived objects are presumed to be retained; if +they are not retained, they should be either commented as weak or declared with +the `__weak` lifetime qualifier. + +An exception is in Mac software for instance variables labeled as `@IBOutlets`, +which are presumed to not be retained. + +Where instance variables are pointers to Core Foundation, C++, and other +non-Objective-C objects, they should always be declared with strong and weak +comments to indicate which pointers are and are not retained. Core Foundation +and other non-Objective-C object pointers require explicit memory management, +even when building for automatic reference counting. + +Examples of strong and weak declarations: + +```objectivec +// GOOD: + +@interface MyDelegate : NSObject + +@property(nonatomic) NSString *doohickey; +@property(nonatomic, weak) NSString *parent; + +@end + + +@implementation MyDelegate { + IBOutlet NSButton *_okButton; // Normal NSControl; implicitly weak on Mac only + + AnObjcObject *_doohickey; // My doohickey + __weak MyObjcParent *_parent; // To send messages back (owns this instance) + + // non-NSObject pointers... + CWackyCPPClass *_wacky; // Strong, some cross-platform object + CFDictionaryRef *_dict; // Strong +} +@end +``` + +#### Automatic Reference Counting + +Object ownership and lifetime are explicit when using ARC, so no additional +comments are required for automatically retained objects. + +## C Language Features + +### Macros + +Avoid macros, especially where `const` variables, enums, XCode snippets, or C +functions may be used instead. + +Macros make the code you see different from the code the compiler sees. Modern C +renders traditional uses of macros for constants and utility functions +unnecessary. Macros should only be used when there is no other solution +available. + +Where a macro is needed, use a unique name to avoid the risk of a symbol +collision in the compilation unit. If practical, keep the scope limited by +`#undefining` the macro after its use. + +Macro names should use `SHOUTY_SNAKE_CASE`—all uppercase letters with +underscores between words. Function-like macros may use C function naming +practices. Do not define macros that appear to be C or Objective-C keywords. + +```objectivec +// GOOD: + +#define GTM_EXPERIMENTAL_BUILD ... // GOOD + +// Assert unless X > Y +#define GTM_ASSERT_GT(X, Y) ... // GOOD, macro style. + +// Assert unless X > Y +#define GTMAssertGreaterThan(X, Y) ... // GOOD, function style. +``` + +```objectivec +// AVOID: + +#define kIsExperimentalBuild ... // AVOID + +#define unless(X) if(!(X)) // AVOID +``` + +Avoid macros that expand to unbalanced C or Objective-C constructs. Avoid macros +that introduce scope, or may obscure the capturing of values in blocks. + +Avoid macros that generate class, property, or method definitions in +headers to be used as public API. These only make the code hard to +understand, and the language already has better ways of doing this. + +Avoid macros that generate method implementations, or that generate declarations +of variables that are later used outside of the macro. Macros shouldn't make +code hard to understand by hiding where and how a variable is declared. + +```objectivec +// AVOID: + +#define ARRAY_ADDER(CLASS) \ + -(void)add ## CLASS ## :(CLASS *)obj toArray:(NSMutableArray *)array + +ARRAY_ADDER(NSString) { + if (array.count > 5) { // AVOID -- where is 'array' defined? + ... + } +} +``` + +Examples of acceptable macro use include assertion and debug logging macros +that are conditionally compiled based on build settings—often, these are +not compiled into release builds. + +### Nonstandard Extensions + +Nonstandard extensions to C/Objective-C may not be used unless otherwise +specified. + +Compilers support various extensions that are not part of standard C. Examples +include compound statement expressions (e.g. `foo = ({ int x; Bar(&x); x }))` +and variable-length arrays. + +`__attribute__` is an approved exception, as it is used in Objective-C API +specifications. + +The binary form of the conditional operator, `A ?: B`, is an approved exception. + +## Cocoa and Objective-C Features + +### Identify Designated Initializer + +Clearly identify your designated initializer. + +It is important for those who might be subclassing your class that the +designated initializer be clearly identified. That way, they only need to +override a single initializer (of potentially several) to guarantee the +initializer of their subclass is called. It also helps those debugging your +class in the future understand the flow of initialization code if they need to +step through it. Identify the designated initializer using comments or the +`NS_DESIGNATED_INITIALIZER` macro. If you use `NS_DESIGNATED_INITIALIZER`, mark +unsupported initializers with `NS_UNAVAILABLE`. + +### Override Designated Initializer + +When writing a subclass that requires an `init...` method, make sure you +override the designated initializer of the superclass. + +If you fail to override the designated initializer of the superclass, your +initializer may not be called in all cases, leading to subtle and very difficult +to find bugs. + +### Overridden NSObject Method Placement + +Put overridden methods of NSObject at the top of an `@implementation`. + +This commonly applies to (but is not limited to) the `init...`, `copyWithZone:`, +and `dealloc` methods. The `init...` methods should be grouped together, +followed by other typical `NSObject` methods such as `description`, `isEqual:`, +and `hash`. + +Convenience class factory methods for creating instances may precede the +`NSObject` methods. + +### Initialization + +Don't initialize instance variables to `0` or `nil` in the `init` method; doing +so is redundant. + +All instance variables for a newly allocated object are [initialized +to](https://developer.apple.com/library/mac/documentation/General/Conceptual/CocoaEncyclopedia/ObjectAllocation/ObjectAllocation.html) +`0` (except for isa), so don't clutter up the init method by re-initializing +variables to `0` or `nil`. + +### Instance Variables In Headers Should Be @protected or @private + +Instance variables should typically be declared in implementation files or +auto-synthesized by properties. When ivars are declared in a header file, they +should be marked `@protected` or `@private`. + +```objectivec +// GOOD: + +@interface MyClass : NSObject { + @protected + id _myInstanceVariable; +} +@end +``` + +### Avoid +new + +Do not invoke the `NSObject` class method `new`, nor override it in a subclass. +Instead, use `alloc` and `init` methods to instantiate retained objects. + +Modern Objective-C code explicitly calls `alloc` and an `init` method to create +and retain an object. As the `new` class method is rarely used, it makes +reviewing code for correct memory management more difficult. + +### Keep the Public API Simple + +Keep your class simple; avoid "kitchen-sink" APIs. If a method doesn't need to +be public, keep it out of the public interface. + +Unlike C++, Objective-C doesn't differentiate between public and private +methods; any message may be sent to an object. As a result, avoid placing +methods in the public API unless they are actually expected to be used by a +consumer of the class. This helps reduce the likelihood they'll be called when +you're not expecting it. This includes methods that are being overridden from +the parent class. + +Since internal methods are not really private, it's easy to accidentally +override a superclass's "private" method, thus making a very difficult bug to +squash. In general, private methods should have a fairly unique name that will +prevent subclasses from unintentionally overriding them. + +### #import and #include + +`#import` Objective-C and Objective-C++ headers, and `#include` C/C++ headers. + +Choose between `#import` and `#include` based on the language of the header that +you are including. + + +When including a header that uses Objective-C or Objective-C++, use `#import`. +When including a standard C or C++ header, use `#include`. +The header should provide its own `#define` guard. + +### Order of Includes + +The standard order for header inclusion is the related header, operating system +headers, language library headers, and finally groups of headers for other +dependencies. + +The related header precedes others to ensure it has no hidden dependencies. +For implementation files the related header is the header file. +For test files the related header is the header containing the tested interface. + +A blank line may separate logically distinct groups of included headers. + +Import headers using their path relative to the project's source directory. + +```objectivec +// GOOD: + +#import "ProjectX/BazViewController.h" + +#import + +#include +#include + +#include "base/basictypes.h" +#include "base/integral_types.h" +#include "util/math/mathutil.h" + +#import "ProjectX/BazModel.h" +#import "Shared/Util/Foo.h" +``` + +### Use Umbrella Headers for System Frameworks + +Import umbrella headers for system frameworks and system libraries rather than +include individual files. + +While it may seem tempting to include individual system headers from a framework +such as Cocoa or Foundation, in fact it's less work on the compiler if you +include the top-level root framework. The root framework is generally +pre-compiled and can be loaded much more quickly. In addition, remember to use +`@import` or `#import` rather than `#include` for Objective-C frameworks. + +```objectivec +// GOOD: + +@import UIKit; // GOOD. +#import // GOOD. +``` + +```objectivec +// AVOID: + +#import // AVOID. +#import +... +``` + +### Avoid Messaging the Current Object Within Initializers and `-dealloc` + +Code in initializers and `-dealloc` should avoid invoking instance methods. + +Superclass initialization completes before subclass initialization. Until all +classes have had a chance to initialize their instance state any method +invocation on self may lead to a subclass operating on uninitialized instance +state. + +A similar issue exists for `-dealloc`, where a method invocation may cause a +class to operate on state that has been deallocated. + +One case where this is less obvious is property accessors. These can be +overridden just like any other selector. Whenever practical, directly assign to +and release ivars in initializers and `-dealloc`, rather than rely on accessors. + +```objectivec +// GOOD: + +- (instancetype)init { + self = [super init]; + if (self) { + _bar = 23; // GOOD. + } + return self; +} +``` + +Beware of factoring common initialization code into helper methods: + +- Methods can be overridden in subclasses, either deliberately, or + accidentally due to naming collisions. +- When editing a helper method, it may not be obvious that the code is being + run from an initializer. + +```objectivec +// AVOID: + +- (instancetype)init { + self = [super init]; + if (self) { + self.bar = 23; // AVOID. + [self sharedMethod]; // AVOID. Fragile to subclassing or future extension. + } + return self; +} +``` + +```objectivec +// GOOD: + +- (void)dealloc { + [_notifier removeObserver:self]; // GOOD. +} +``` + +```objectivec +// AVOID: + +- (void)dealloc { + [self removeNotifications]; // AVOID. +} +``` + +### Setters copy NSStrings + +Setters taking an `NSString` should always copy the string it accepts. This is +often also appropriate for collections like `NSArray` and `NSDictionary`. + +Never just retain the string, as it may be a `NSMutableString`. This avoids the +caller changing it under you without your knowledge. + +Code receiving and holding collection objects should also consider that the +passed collection may be mutable, and thus the collection could be more safely +held as a copy or mutable copy of the original. + +```objectivec +// GOOD: + +@property(nonatomic, copy) NSString *name; + +- (void)setZigfoos:(NSArray *)zigfoos { + // Ensure that we're holding an immutable collection. + _zigfoos = [zigfoos copy]; +} +``` + +### Use Lightweight Generics to Document Contained Types + +All projects compiling on Xcode 7 or newer versions should make use of the +Objective-C lightweight generics notation to type contained objects. + +Every `NSArray`, `NSDictionary`, or `NSSet` reference should be declared using +lightweight generics for improved type safety and to explicitly document usage. + +```objectivec +// GOOD: + +@property(nonatomic, copy) NSArray *locations; +@property(nonatomic, copy, readonly) NSSet *identifiers; + +NSMutableArray *mutableLocations = [otherObject.locations mutableCopy]; +``` + +If the fully-annotated types become complex, consider using a typedef to +preserve readability. + +```objectivec +// GOOD: + +typedef NSSet *> TimeZoneMappingSet; +TimeZoneMappingSet *timeZoneMappings = [TimeZoneMappingSet setWithObjects:...]; +``` + +Use the most descriptive common superclass or protocol available. In the most +generic case when nothing else is known, declare the collection to be explicitly +heterogenous using id. + +```objectivec +// GOOD: + +@property(nonatomic, copy) NSArray *unknowns; +``` + +### Avoid Throwing Exceptions + +Don't `@throw` Objective-C exceptions, but you should be prepared to catch them +from third-party or OS calls. + +This follows the recommendation to use error objects for error delivery in +[Apple's Introduction to Exception Programming Topics for +Cocoa](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html). + +We do compile with `-fobjc-exceptions` (mainly so we get `@synchronized`), but +we don't `@throw`. Use of `@try`, `@catch`, and `@finally` are allowed when +required to properly use 3rd party code or libraries. If you do use them, please +document exactly which methods you expect to throw. + +### `nil` Checks + +Use `nil` checks for logic flow only. + +Use `nil` pointer checks for logic flow of the application, not for preventing +crashes when sending messages. Sending a message to `nil` [reliably +returns](http://www.sealiesoftware.com/blog/archive/2012/2/29/objc_explain_return_value_of_message_to_nil.html) +`nil` as a pointer, zero as an integer or floating-point value, structs +initialized to `0`, and `_Complex` values equal to `{0, 0}`. + +Note that this applies to `nil` as a message target, not as a parameter value. +Individual methods may or may not safely handle `nil` parameter values. + +Note too that this is distinct from checking C/C++ pointers and block pointers +against `NULL`, which the runtime does not handle and will cause your +application to crash. You still need to make sure you do not dereference a +`NULL` pointer. + +### BOOL Pitfalls + +Be careful when converting general integral values to `BOOL`. Avoid comparing +directly with `YES`. + +`BOOL` in OS X and in 32-bit iOS builds is defined as a signed `char`, so it may +have values other than `YES` (`1`) and `NO` (`0`). Do not cast or convert +general integral values directly to `BOOL`. + +Common mistakes include casting or converting an array's size, a pointer value, +or the result of a bitwise logic operation to a `BOOL` that could, depending on +the value of the last byte of the integer value, still result in a `NO` value. +When converting a general integral value to a `BOOL` use ternary operators to +return a `YES` or `NO` value. + +You can safely interchange and convert `BOOL`, `_Bool` and `bool` (see C++ Std +4.7.4, 4.12 and C99 Std 6.3.1.2). Use `BOOL` in Objective-C method signatures. + +Using logical operators (`&&`, `||` and `!`) with `BOOL` is also valid and will +return values that can be safely converted to `BOOL` without the need for a +ternary operator. + +```objectivec +// AVOID: + +- (BOOL)isBold { + return [self fontTraits] & NSFontBoldTrait; // AVOID. +} +- (BOOL)isValid { + return [self stringValue]; // AVOID. +} +``` + +```objectivec +// GOOD: + +- (BOOL)isBold { + return ([self fontTraits] & NSFontBoldTrait) ? YES : NO; +} +- (BOOL)isValid { + return [self stringValue] != nil; +} +- (BOOL)isEnabled { + return [self isValid] && [self isBold]; +} +``` + +Also, don't directly compare `BOOL` variables directly with `YES`. Not only is +it harder to read for those well-versed in C, but the first point above +demonstrates that return values may not always be what you expect. + +```objectivec +// AVOID: + +BOOL great = [foo isGreat]; +if (great == YES) { // AVOID. + // ...be great! +} +``` + +```objectivec +// GOOD: + +BOOL great = [foo isGreat]; +if (great) { // GOOD. + // ...be great! +} +``` + +### Interfaces Without Instance Variables + +Omit the empty set of braces on interfaces that do not declare any instance +variables. + +```objectivec +// GOOD: + +@interface MyClass : NSObject +// Does a lot of stuff. +- (void)fooBarBam; +@end +``` + +```objectivec +// AVOID: + +@interface MyClass : NSObject { +} +// Does a lot of stuff. +- (void)fooBarBam; +@end +``` + +## Cocoa Patterns + +### Delegate Pattern + +Delegates, target objects, and block pointers should not be retained when doing +so would create a retain cycle. + +To avoid causing a retain cycle, a delegate or target pointer should be released +as soon as it is clear there will no longer be a need to message the object. + +If there is no clear time at which the delegate or target pointer is no longer +needed, the pointer should only be retained weakly. + +Block pointers cannot be retained weakly. To avoid causing retain cycles in the +client code, block pointers should be used for callbacks only where they can be +explicitly released after they have been called or once they are no longer +needed. Otherwise, callbacks should be done via weak delegate or target +pointers. + +## Objective-C++ + +### Style Matches the Language + +Within an Objective-C++ source file, follow the style for the language of the +function or method you're implementing. In order to minimize clashes between the +differing naming styles when mixing Cocoa/Objective-C and C++, follow the style +of the method being implemented. + +For code in an `@implementation` block, use the Objective-C naming rules. For +code in a method of a C++ class, use the C++ naming rules. + +For code in an Objective-C++ file outside of a class implementation, be +consistent within the file. + +```objectivec++ +// GOOD: + +// file: cross_platform_header.h + +class CrossPlatformAPI { + public: + ... + int DoSomethingPlatformSpecific(); // impl on each platform + private: + int an_instance_var_; +}; + +// file: mac_implementation.mm +#include "cross_platform_header.h" + +// A typical Objective-C class, using Objective-C naming. +@interface MyDelegate : NSObject { + @private + int _instanceVar; + CrossPlatformAPI* _backEndObject; +} + +- (void)respondToSomething:(id)something; + +@end + +@implementation MyDelegate + +- (void)respondToSomething:(id)something { + // bridge from Cocoa through our C++ backend + _instanceVar = _backEndObject->DoSomethingPlatformSpecific(); + NSString* tempString = [NSString stringWithFormat:@"%d", _instanceVar]; + NSLog(@"%@", tempString); +} + +@end + +// The platform-specific implementation of the C++ class, using +// C++ naming. +int CrossPlatformAPI::DoSomethingPlatformSpecific() { + NSString* temp_string = [NSString stringWithFormat:@"%d", an_instance_var_]; + NSLog(@"%@", temp_string); + return [temp_string intValue]; +} +``` + +Projects may opt to use an 80 column line length limit for consistency with +Google's C++ style guide. + +## Objective-C Style Exceptions + +### Indicating style exceptions + +Lines of code that are not expected to adhere to these style recommendations +require `// NOLINT` at the end of the line or `// NOLINTNEXTLINE` at the end of +the previous line. Sometimes it is required that parts of Objective-C code must +ignore these style recommendations (for example code may be machine generated or +code constructs are such that its not possible to style correctly). + +A `// NOLINT` comment on that line or `// NOLINTNEXTLINE` on the previous line +can be used to indicate to the reader that code is intentionally ignoring style +guidelines. In addition these annotations can also be picked up by automated +tools such as linters and handle code correctly. Note that there is a single +space between `//` and `NOLINT*`. diff --git a/objcguide.xml b/objcguide.xml new file mode 100644 index 000000000..3beca74b4 --- /dev/null +++ b/objcguide.xml @@ -0,0 +1,8 @@ + + + +

+ The style guide has moved to + objcguide.md +

+
diff --git a/pyguide.html b/pyguide.html new file mode 100644 index 000000000..6987f2b68 --- /dev/null +++ b/pyguide.html @@ -0,0 +1,2310 @@ + + +Google Python Style Guide + + + + + + +

Google Python Style Guide

+

+ + Revision 2.59 +

+ +
+ Amit Patel
+ Antoine Picard
+ Eugene Jhong
+ Jeremy Hylton
+ Matt Smart
+ Mike Shields
+
+
+

+ Each style point has a summary for which additional information is available + by toggling the accompanying arrow button that looks this way: + . + You may toggle all summaries with the big arrow button: +

+
+ + Toggle all summaries +
+
+ +
+

Important Note

+
+

Displaying Hidden Details in this Guide

+ + link + +
+ This style guide contains many details that are initially + hidden from view. They are marked by the triangle icon, which you + see here on your left. Click it now. + You should see "Hooray" appear below. +
+
+
+
+
+

Background

+

+ Python is the main scripting language used at Google. This + style guide is a list of dos and don'ts for Python + programs. +

+ +

+ To help you format code correctly, we've created a settings + file for Vim. For Emacs, the default settings should be fine. +

+ + +
+ +
+

Python Language Rules

+
+

Lint

+ + link + +
+ Run pylint over your code. +
+
+
+
+

Imports

+ + link + +
+ Use imports for packages and modules only. +
+
+
+
+

Packages

+ + link + +
+ Import each module using the full pathname location of the module. +
+
+
+
+

Exceptions

+ + link + +
+ Exceptions are allowed but must be used carefully. +
+
+
+
+

Global variables

+ + link + +
+ Avoid global variables. +
+
+
+
+

Nested/Local/Inner Classes and Functions

+ + link + +
+ Nested/local/inner classes and functions are fine. +
+
+
+
+

List Comprehensions

+ + link + +
+ Okay to use for simple cases. +
+
+
+
+

Default Iterators and Operators

+ + link + +
+ Use default iterators and operators for types that support them, + like lists, dictionaries, and files. +
+
+
+
+

Generators

+ + link + +
+ Use generators as needed. +
+
+
+
+

Lambda Functions

+ + link + +
+ Okay for one-liners. +
+
+
+
+

Conditional Expressions

+ + link + +
+ Okay for one-liners. +
+
+
+
+

Default Argument Values

+ + link + +
+ Okay in most cases. +
+
+
+
+

Properties

+ + link + +
+ Use properties for accessing or setting data where you would + normally have used simple, lightweight accessor or setter methods. +
+
+
+
+

True/False evaluations

+ + link + +
+ Use the "implicit" false if at all possible. +
+
+
+
+

Deprecated Language Features

+ + link + +
+ Use string methods instead of the string module + where possible. Use function call syntax instead + of apply. Use list comprehensions + and for loops instead of filter and + map when the function argument would have been an + inlined lambda anyway. Use for loops instead of + reduce. +
+
+
+
+

Lexical Scoping

+ + link + +
+ Okay to use. +
+
+
+
+

Function and Method Decorators

+ + link + +
+ Use decorators judiciously when there is a clear advantage. +
+
+
+
+

Threading

+ + link + +
+ Do not rely on the atomicity of built-in types. +
+
+
+
+

Power Features

+ + link + +
+ Avoid these features. +
+
+
+
+
+

Python Style Rules

+
+

Semicolons

+ + link + +
+ Do not terminate your lines with semi-colons and do not use + semi-colons to put two commands on the same line. +
+
+
+
+

Line length

+ + link + +
+ Maximum line length is 80 characters. +
+
+
+
+

Parentheses

+ + link + +
+ Use parentheses sparingly. +
+
+
+
+

Indentation

+ + link + +
+ Indent your code blocks with 4 spaces. +
+
+
+
+

Blank Lines

+ + link + +
+ Two blank lines between top-level definitions, one blank line + between method definitions. +
+
+
+
+

Whitespace

+ + link + +
+ Follow standard typographic rules for the use of spaces around + punctuation. +
+
+
+ + +
+

Shebang Line

+ + link + +
+ Most .py files do not need to start with a + #! line. Start the main file of a + program with + #!/usr/bin/env python with an optional single digit + 2 or 3 suffix. +
+
+
+ +
+

Comments

+ + link + +
+ Be sure to use the right style for module, function, method and in-line + comments. +
+
+
+
+

Classes

+ + link + +
+ If a class inherits from no other base classes, explicitly inherit + from object. This also applies to nested classes. +
+
+
+
+

Strings

+ + link + +
+ Use the format method or the % operator for + formatting strings, even when the parameters are all strings. Use your + best judgement to decide between + and % + (or format) though. +
+
+
+
+

Files and Sockets

+ + link + +
+ Explicitly close files and sockets when done with them. +
+
+
+
+

TODO Comments

+ + link + +
+ Use TODO comments for code that is temporary, a + short-term solution, or good-enough but not perfect. +
+
+
+
+

Imports formatting

+ + link + +
+ Imports should be on separate lines. +
+
+
+
+

Statements

+ + link + +
+ Generally only one statement per line. +
+
+
+
+

Access Control

+ + link + +
+ If an accessor function would be trivial you should use public variables + instead of accessor functions to avoid the extra cost of function + calls in Python. When more functionality is added you can use + property to keep the syntax consistent. +
+
+
+
+

Naming

+ + link + +
+ module_name, package_name, ClassName, + method_name, ExceptionName, + function_name, GLOBAL_CONSTANT_NAME, + global_var_name, instance_var_name, function_parameter_name, + local_var_name. +
+
+
+
+

Main

+ + link + +
+ Even a file meant to be used as a script should be importable and a + mere import should not have the side effect of executing the script's + main functionality. The main functionality should be in a main() + function. +
+
+
+
+ +

Parting Words

+

+ BE CONSISTENT. +

+ +

+ If you're editing code, take a few minutes to look at the code + around you and determine its style. If they use spaces around + all their arithmetic operators, you should too. If their + comments have little boxes of hash marks around them, make your + comments have little boxes of hash marks around them too. +

+ +

+ The point of having style guidelines is to have a common vocabulary + of coding so people can concentrate on what you're saying rather + than on how you're saying it. We present global style rules here so + people know the vocabulary, but local style is also important. If + code you add to a file looks drastically different from the existing + code around it, it throws readers out of their rhythm when they go to + read it. Avoid this. +

+ + + +

+Revision 2.59 +

+ + +
+ Amit Patel
+ Antoine Picard
+ Eugene Jhong
+ Gregory P. Smith
+ Jeremy Hylton
+ Matt Smart
+ Mike Shields
+ Shane Liebling
+
+ + diff --git a/pyguide.md b/pyguide.md deleted file mode 100644 index 0e45ead6d..000000000 --- a/pyguide.md +++ /dev/null @@ -1,2568 +0,0 @@ - - -# Google Python Style Guide - - - -## 1 Background - -Python is the main dynamic language used at Google. This style guide is a list -of *dos and don'ts* for Python programs. - -To help you format code correctly, we've created a [settings file for -Vim](google_python_style.vim). For Emacs, the default settings should be fine. - -Many teams use the [yapf](https://github.com/google/yapf/) -auto-formatter to avoid arguing over formatting. - - - - -## 2 Python Language Rules - - - -### 2.1 Lint - -Run `pylint` over your code. - - -#### 2.1.1 Definition - -`pylint` is a tool for finding bugs and style problems in Python source -code. It finds problems that are typically caught by a compiler for less dynamic -languages like C and C++. Because of the dynamic nature of Python, some -warnings may be incorrect; however, spurious warnings should be fairly -infrequent. - - -#### 2.1.2 Pros - -Catches easy-to-miss errors like typos, using-vars-before-assignment, etc. - - -#### 2.1.3 Cons - -`pylint` isn't perfect. To take advantage of it, we'll need to sometimes: a) -Write around it b) Suppress its warnings or c) Improve it. - - -#### 2.1.4 Decision - -Make sure you run `pylint` on your code. - - -Suppress warnings if they are inappropriate so that other issues are not hidden. -To suppress warnings, you can set a line-level comment: - -```python {.good} -dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin -``` - -`pylint` warnings are each identified by symbolic name (`empty-docstring`) -Google-specific warnings start with `g-`. - -If the reason for the suppression is not clear from the symbolic name, add an -explanation. - -Suppressing in this way has the advantage that we can easily search for -suppressions and revisit them. - -You can get a list of `pylint` warnings by doing: - -```shell -pylint --list-msgs -``` - -To get more information on a particular message, use: - -```shell -pylint --help-msg=C6409 -``` - -Prefer `pylint: disable` to the deprecated older form `pylint: disable-msg`. - -Unused argument warnings can be suppressed by deleting the variables at the -beginning of the function. Always include a comment explaining why you are -deleting it. "Unused." is sufficient. For example: - -```python {.good} -def viking_cafe_order(spam, beans, eggs=None): - del beans, eggs # Unused by vikings. - return spam + spam + spam -``` - -Other common forms of suppressing this warning include using '`_`' as the -identifier for the unused argument, prefixing the argument name with -'`unused_`', or assigning them to '`_`'. These forms are allowed but no longer -encouraged. The first two break callers that pass arguments by name, while the -latter does not enforce that the arguments are actually unused. - - - -### 2.2 Imports - -Use `import`s for packages and modules only, not for individual classes or -functions. - - -#### 2.2.1 Definition - -Reusability mechanism for sharing code from one module to another. - - -#### 2.2.2 Pros - -The namespace management convention is simple. The source of each identifier is -indicated in a consistent way; `x.Obj` says that object `Obj` is defined in -module `x`. - - -#### 2.2.3 Cons - -Module names can still collide. Some module names are inconveniently long. - - -#### 2.2.4 Decision - -* Use `import x` for importing packages and modules. -* Use `from x import y` where `x` is the package prefix and `y` is the module -name with no prefix. -* Use `from x import y as z` if two modules named `y` are to be imported or if -`y` is an inconveniently long name. -* Use `import y as z` only when `z` is a standard abbreviation (e.g., `np` for -`numpy`). - -For example the module `sound.effects.echo` may be imported as follows: - -```python {.good} -from sound.effects import echo -... -echo.EchoFilter(input, output, delay=0.7, atten=4) -``` - -Do not use relative names in imports. Even if the module is in the same package, -use the full package name. This helps prevent unintentionally importing a -package twice. - -Note that there is an explicit exemption for imports from the [typing -module](#typing-imports). - - - -### 2.3 Packages - -Import each module using the full pathname location of the module. - - -#### 2.3.1 Pros - -Avoids conflicts in module names. Makes it easier to find modules. - - -#### 2.3.2 Cons - -Makes it harder to deploy code because you have to replicate the package -hierarchy. - - -#### 2.3.3 Decision - -All new code should import each module by its full package name. - -Imports should be as follows: - -```python {.good} -# Reference in code with complete name. -import absl.flags - -# Reference in code with just module name (preferred). -from absl import flags -``` - - - -### 2.4 Exceptions - -Exceptions are allowed but must be used carefully. - - -#### 2.4.1 Definition - -Exceptions are a means of breaking out of the normal flow of control of a code -block to handle errors or other exceptional conditions. - - -#### 2.4.2 Pros - -The control flow of normal operation code is not cluttered by error-handling -code. It also allows the control flow to skip multiple frames when a certain -condition occurs, e.g., returning from N nested functions in one step instead of -having to carry-through error codes. - - -#### 2.4.3 Cons - -May cause the control flow to be confusing. Easy to miss error cases when making -library calls. - - -#### 2.4.4 Decision - -Exceptions must follow certain conditions: - -- Raise exceptions like this: `raise MyError('Error message')` or `raise - MyError()`. Do not use the two-argument form (`raise MyError, 'Error - message'`). - -- Make use of built-in exception classes when it makes sense. For example, - raise a `ValueError` if you were passed a negative number but were expecting - a positive one. Do not use `assert` statements for validating argument - values of a public API. `assert` is used to ensure internal correctness, not - to enforce correct usage nor to indicate that some unexpected event - occurred. If an exception is desired in the latter cases, use a raise - statement. For example: - - - ```python {.good} - Yes: - def ConnectToNextPort(self, minimum): - """Connects to the next available port. Returns the new minimum port.""" - if minimum <= 1024: - raise ValueError('Minimum port must be greater than 1024.') - port = self._FindNextOpenPort(minimum) - if not port: - raise ConnectionError('Could not connect to service on %d or higher.' % (minimum,)) - assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum) - return port - ``` - - ```python {.bad} - No: - def ConnectToNextPort(self, minimum): - """Connects to the next available port. Returns the new minimum port.""" - assert minimum > 1024, 'Minimum port must be greater than 1024.' - port = self._FindNextOpenPort(minimum) - assert port is not None - return port - ``` - -- Libraries or packages may define their own exceptions. When doing so they - must inherit from an existing exception class. Exception names should end in - `Error` and should not introduce stutter (`foo.FooError`). - -- Never use catch-all `except:` statements, or catch `Exception` or - `StandardError`, unless you are re-raising the exception or in the outermost - block in your thread (and printing an error message). Python is very - tolerant in this regard and `except:` will really catch everything including - misspelled names, sys.exit() calls, Ctrl+C interrupts, unittest failures and - all kinds of other exceptions that you simply don't want to catch. - -- Minimize the amount of code in a `try`/`except` block. The larger the body - of the `try`, the more likely that an exception will be raised by a line of - code that you didn't expect to raise an exception. In those cases, the - `try`/`except` block hides a real error. - -- Use the `finally` clause to execute code whether or not an exception is - raised in the `try` block. This is often useful for cleanup, i.e., closing a - file. - -- When capturing an exception, use `as` rather than a comma. For example: - - - ```python {.good} - try: - raise Error - except Error as error: - pass - ``` - - - -### 2.5 Global variables - -Avoid global variables. - - -#### 2.5.1 Definition - -Variables that are declared at the module level or as class attributes. - - -#### 2.5.2 Pros - -Occasionally useful. - - -#### 2.5.3 Cons - -Has the potential to change module behavior during the import, because -assignments to global variables are done when the module is first imported. - - -#### 2.5.4 Decision - -Avoid global variables. - -While they are technically variables, module-level constants are permitted and -encouraged. For example: `MAX_HOLY_HANDGRENADE_COUNT = 3`. Constants must be -named using all caps with underscores. See [Naming](#s3.16-naming) below. - -If needed, globals should be declared at the module level and made internal to -the module by prepending an `_` to the name. External access must be done -through public module-level functions. See [Naming](#s3.16-naming) below. - - - -### 2.6 Nested/Local/Inner Classes and Functions - -Nested local functions or classes are fine when used to close over a local -variable. Inner classes are fine. - - -#### 2.6.1 Definition - -A class can be defined inside of a method, function, or class. A function can be -defined inside a method or function. Nested functions have read-only access to -variables defined in enclosing scopes. - - -#### 2.6.2 Pros - -Allows definition of utility classes and functions that are only used inside of -a very limited scope. Very -[ADT](http://www.google.com/url?sa=D&q=http://en.wikipedia.org/wiki/Abstract_data_type)-y. - - -#### 2.6.3 Cons - -Instances of nested or local classes cannot be pickled. Nested functions and -classes cannot be directly tested. Nesting can make your outer function longer -and less readable. - - -#### 2.6.4 Decision - -They are fine with some caveats: Avoid nested functions or classes except when -closing over a local value for easier future comprehension. Do not nest a -function just to hide it from users of a module. Instead, prefix its name with -an \_ at the module level so that it can still be accessed by tests. - - - - -### 2.7 Comprehensions & Generator Expressions - -Okay to use for simple cases. - - -#### 2.7.1 Definition - -List, Dict, and Set comprehensions as well as generator expressions provide a -concise and efficient way to create container types and iterators without -resorting to the use of traditional loops, `map()`, `filter()`, or `lambda`. - - -#### 2.7.2 Pros - -Simple comprehensions can be clearer and simpler than other dict, list, or set -creation techniques. Generator expressions can be very efficient, since they -avoid the creation of a list entirely. - - -#### 2.7.3 Cons - -Complicated comprehensions or generator expressions can be hard to read. - - -#### 2.7.4 Decision - -Okay to use for simple cases. Each portion must fit on one line: mapping -expression, `for` clause, filter expression. Multiple `for` clauses or filter -expressions are not permitted. Use loops instead when things get more -complicated. - -```python {.good} -Yes: - result = [] - for x in range(10): - for y in range(5): - if x * y > 10: - result.append((x, y)) - - for x in xrange(5): - for y in xrange(5): - if x != y: - for z in xrange(5): - if y != z: - yield (x, y, z) - - return ((x, complicated_transform(x)) - for x in long_generator_function(parameter) - if x is not None) - - squares = [x * x for x in range(10)] - - eat(jelly_bean for jelly_bean in jelly_beans - if jelly_bean.color == 'black') -``` - -```python {.bad} -No: - result = [(x, y) for x in range(10) for y in range(5) if x * y > 10] - - return ((x, y, z) - for x in xrange(5) - for y in xrange(5) - if x != y - for z in xrange(5) - if y != z) -``` - - - -### 2.8 Default Iterators and Operators - -Use default iterators and operators for types that support them, like lists, -dictionaries, and files. - - -#### 2.8.1 Definition - -Container types, like dictionaries and lists, define default iterators and -membership test operators ("in" and "not in"). - - -#### 2.8.2 Pros - -The default iterators and operators are simple and efficient. They express the -operation directly, without extra method calls. A function that uses default -operators is generic. It can be used with any type that supports the operation. - - -#### 2.8.3 Cons - -You can't tell the type of objects by reading the method names (e.g. has\_key() -means a dictionary). This is also an advantage. - - -#### 2.8.4 Decision - -Use default iterators and operators for types that support them, like lists, -dictionaries, and files. The built-in types define iterator methods, too. Prefer -these methods to methods that return lists, except that you should not mutate a -container while iterating over it. - -```python {.good} -Yes: for key in adict: ... - if key not in adict: ... - if obj in alist: ... - for line in afile: ... - for k, v in dict.iteritems(): ... -``` - -```python {.bad} -No: for key in adict.keys(): ... - if not adict.has_key(key): ... - for line in afile.readlines(): ... -``` - - - -### 2.9 Generators - -Use generators as needed. - - -#### 2.9.1 Definition - -A generator function returns an iterator that yields a value each time it -executes a yield statement. After it yields a value, the runtime state of the -generator function is suspended until the next value is needed. - - -#### 2.9.2 Pros - -Simpler code, because the state of local variables and control flow are -preserved for each call. A generator uses less memory than a function that -creates an entire list of values at once. - - -#### 2.9.3 Cons - -None. - - -#### 2.9.4 Decision - -Fine. Use "Yields:" rather than "Returns:" in the docstring for generator -functions. - - - -### 2.10 Lambda Functions - -Okay for one-liners. - - -#### 2.10.1 Definition - -Lambdas define anonymous functions in an expression, as opposed to a statement. -They are often used to define callbacks or operators for higher-order functions -like `map()` and `filter()`. - - -#### 2.10.2 Pros - -Convenient. - - -#### 2.10.3 Cons - -Harder to read and debug than local functions. The lack of names means stack -traces are more difficult to understand. Expressiveness is limited because the -function may only contain an expression. - - -#### 2.10.4 Decision - -Okay to use them for one-liners. If the code inside the lambda function is any -longer than 60-80 chars, it's probably better to define it as a regular (nested) -function. - -For common operations like multiplication, use the functions from the `operator` -module instead of lambda functions. For example, prefer `operator.mul` to -`lambda x, y: x * y`. - - - -### 2.11 Conditional Expressions - -Okay for one-liners. - - -#### 2.11.1 Definition - -Conditional expressions (sometimes called a “ternary operator”) are mechanisms -that provide a shorter syntax for if statements. For example: -`x = 1 if cond else 2`. - - -#### 2.11.2 Pros - -Shorter and more convenient than an if statement. - - -#### 2.11.3 Cons - -May be harder to read than an if statement. The condition may be difficult to -locate if the expression is long. - - -#### 2.11.4 Decision - -Okay to use for one-liners. In other cases prefer to use a complete if -statement. - - - -### 2.12 Default Argument Values - -Okay in most cases. - - -#### 2.12.1 Definition - -You can specify values for variables at the end of a function's parameter list, -e.g., `def foo(a, b=0):`. If `foo` is called with only one argument, -`b` is set to 0. If it is called with two arguments, `b` has the value of the -second argument. - - -#### 2.12.2 Pros - -Often you have a function that uses lots of default values, but-rarely-you want -to override the defaults. Default argument values provide an easy way to do -this, without having to define lots of functions for the rare exceptions. Also, -Python does not support overloaded methods/functions and default arguments are -an easy way of "faking" the overloading behavior. - - -#### 2.12.3 Cons - -Default arguments are evaluated once at module load time. This may cause -problems if the argument is a mutable object such as a list or a dictionary. If -the function modifies the object (e.g., by appending an item to a list), the -default value is modified. - - -#### 2.12.4 Decision - -Okay to use with the following caveat: - -Do not use mutable objects as default values in the function or method -definition. - -```python {.good} -Yes: def foo(a, b=None): - if b is None: - b = [] -Yes: def foo(a, b: Optional[Sequence] = None): - if b is None: - b = [] -``` - -```python {.bad} -No: def foo(a, b=[]): - ... -No: def foo(a, b=time.time()): # The time the module was loaded??? - ... -No: def foo(a, b=FLAGS.my_thing): # sys.argv has not yet been parsed... - ... -``` - - - -### 2.13 Properties - -Use properties for accessing or setting data where you would normally have used -simple, lightweight accessor or setter methods. - - -#### 2.13.1 Definition - -A way to wrap method calls for getting and setting an attribute as a standard -attribute access when the computation is lightweight. - - -#### 2.13.2 Pros - -Readability is increased by eliminating explicit get and set method calls for -simple attribute access. Allows calculations to be lazy. Considered the Pythonic -way to maintain the interface of a class. In terms of performance, allowing -properties bypasses needing trivial accessor methods when a direct variable -access is reasonable. This also allows accessor methods to be added in the -future without breaking the interface. - - -#### 2.13.3 Cons - -Must inherit from `object` in Python 2. Can hide side-effects much like operator -overloading. Can be confusing for subclasses. - - -#### 2.13.4 Decision - -Use properties in new code to access or set data where you would normally have -used simple, lightweight accessor or setter methods. Properties should be -created with the `@property` [decorator](#s2.17-function-and-method-decorators). - -Inheritance with properties can be non-obvious if the property itself is not -overridden. Thus one must make sure that accessor methods are called indirectly -to ensure methods overridden in subclasses are called by the property (using the -Template Method DP). - -```python {.good} -Yes: import math - - class Square(object): - """A square with two properties: a writable area and a read-only perimeter. - - To use: - >>> sq = Square(3) - >>> sq.area - 9 - >>> sq.perimeter - 12 - >>> sq.area = 16 - >>> sq.side - 4 - >>> sq.perimeter - 16 - """ - - def __init__(self, side): - self.side = side - - @property - def area(self): - """Gets or sets the area of the square.""" - return self._get_area() - - @area.setter - def area(self, area): - return self._set_area(area) - - def _get_area(self): - """Indirect accessor to calculate the 'area' property.""" - return self.side ** 2 - - def _set_area(self, area): - """Indirect setter to set the 'area' property.""" - self.side = math.sqrt(area) - - @property - def perimeter(self): - return self.side * 4 -``` - - - -### 2.14 True/False evaluations - -Use the "implicit" false if at all possible. - - -#### 2.14.1 Definition - -Python evaluates certain values as `False` when in a boolean context. A quick -"rule of thumb" is that all "empty" values are considered false, so -`0, None, [], {}, ''` all evaluate as false in a boolean context. - - -#### 2.14.2 Pros - -Conditions using Python booleans are easier to read and less error-prone. In -most cases, they're also faster. - - -#### 2.14.3 Cons - -May look strange to C/C++ developers. - - -#### 2.14.4 Decision - -Use the "implicit" false if at all possible, e.g., `if foo:` rather than -`if foo != []:`. There are a few caveats that you should keep in mind though: - -- Never use `==` or `!=` to compare singletons like `None`. Use `is` or - `is not`. - -- Beware of writing `if x:` when you really mean `if x is not None:`-e.g., - when testing whether a variable or argument that defaults to `None` was set - to some other value. The other value might be a value that's false in a - boolean context! - -- Never compare a boolean variable to `False` using `==`. Use `if not x:` - instead. If you need to distinguish `False` from `None` then chain the - expressions, such as `if not x and x is not None:`. - -- For sequences (strings, lists, tuples), use the fact that empty sequences - are false, so `if seq:` and `if not seq:` are preferable to `if len(seq):` - and `if not len(seq):` respectively. - -- When handling integers, implicit false may involve more risk than benefit - (i.e., accidentally handling `None` as 0). You may compare a value which is - known to be an integer (and is not the result of `len()`) against the - integer 0. - - ```python {.good} - Yes: if not users: - print('no users') - - if foo == 0: - self.handle_zero() - - if i % 10 == 0: - self.handle_multiple_of_ten() - - def f(x=None): - if x is None: - x = [] - ``` - - ```python {.bad} - No: if len(users) == 0: - print('no users') - - if foo is not None and not foo: - self.handle_zero() - - if not i % 10: - self.handle_multiple_of_ten() - - def f(x=None): - x = x or [] - ``` - -- Note that `'0'` (i.e., `0` as string) evaluates to true. - - - -### 2.15 Deprecated Language Features - -Use string methods instead of the `string` module where possible. Use function -call syntax instead of `apply`. Use list comprehensions and `for` loops instead -of `filter` and `map` when the function argument would have been an inlined -lambda anyway. Use `for` loops instead of `reduce`. - - -#### 2.15.1 Definition - -Current versions of Python provide alternative constructs that people find -generally preferable. - - -#### 2.15.2 Decision - -We do not use any Python version which does not support these features, so there -is no reason not to use the new styles. - -```python {.good} -Yes: words = foo.split(':') - - [x[1] for x in my_list if x[2] == 5] - - map(math.sqrt, data) # Ok. No inlined lambda expression. - - fn(*args, **kwargs) -``` - -```python {.bad} -No: words = string.split(foo, ':') - - map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list)) - - apply(fn, args, kwargs) -``` - - - -### 2.16 Lexical Scoping - -Okay to use. - - -#### 2.16.1 Definition - -A nested Python function can refer to variables defined in enclosing functions, -but can not assign to them. Variable bindings are resolved using lexical -scoping, that is, based on the static program text. Any assignment to a name in -a block will cause Python to treat all references to that name as a local -variable, even if the use precedes the assignment. If a global declaration -occurs, the name is treated as a global variable. - -An example of the use of this feature is: - -```python {.good} -def get_adder(summand1): - """Returns a function that adds numbers to a given number.""" - def adder(summand2): - return summand1 + summand2 - - return adder -``` - - -#### 2.16.2 Pros - -Often results in clearer, more elegant code. Especially comforting to -experienced Lisp and Scheme (and Haskell and ML and ...) programmers. - - -#### 2.16.3 Cons - -Can lead to confusing bugs. Such as this example based on -[PEP-0227](http://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0227/): - -```python {.bad} -i = 4 -def foo(x): - def bar(): - print(i, end='') - # ... - # A bunch of code here - # ... - for i in x: # Ah, i *is* local to foo, so this is what bar sees - print(i, end='') - bar() -``` - -So `foo([1, 2, 3])` will print `1 2 3 3`, not `1 2 3 -4`. - - -#### 2.16.4 Decision - -Okay to use. - - - -### 2.17 Function and Method Decorators - -Use decorators judiciously when there is a clear advantage. Avoid -`@staticmethod` and limit use of `@classmethod`. - - -#### 2.17.1 Definition - -[Decorators for Functions and -Methods](https://docs.python.org/2/whatsnew/2.4.html#pep-318-decorators-for-functions-and-methods) -(a.k.a "the `@` notation"). One common decorator is `@property`, used for -converting ordinary methods into dynamically computed attributes. However, the -decorator syntax allows for user-defined decorators as well. Specifically, for -some function `my_decorator`, this: - -```python {.good} -class C(object): - @my_decorator - def method(self): - # method body ... -``` - -is equivalent to: - -```python {.good} -class C(object): - def Methodmethod(self): - # method body ... - Methodmethod = MyDecoratormy_decorator(Methodmethod) -``` - - -#### 2.17.2 Pros - -Elegantly specifies some transformation on a method; the transformation might -eliminate some repetitive code, enforce invariants, etc. - - -#### 2.17.3 Cons - -Decorators can perform arbitrary operations on a function's arguments or return -values, resulting in surprising implicit behavior. Additionally, decorators -execute at import time. Failures in decorator code are pretty much impossible to -recover from. - - -#### 2.17.4 Decision - -Use decorators judiciously when there is a clear advantage. Decorators should -follow the same import and naming guidelines as functions. Decorator pydoc -should clearly state that the function is a decorator. Write unit tests for -decorators. - -Avoid external dependencies in the decorator itself (e.g. don't rely on files, -sockets, database connections, etc.), since they might not be available when the -decorator runs (at import time, perhaps from `pydoc` or other tools). A -decorator that is called with valid parameters should (as much as possible) be -guaranteed to succeed in all cases. - -Decorators are a special case of "top level code" - see [main](#s3.17-main) for -more discussion. - -Never use `@staticmethod` unless forced to in order to integrate with an API -defined in an existing library. Write a module level function instead. - -Use `@classmethod` only when writing a named constructor or a class-specific -routine that modifies necessary global state such as a process-wide cache. - - - -### 2.18 Threading - -Do not rely on the atomicity of built-in types. - -While Python's built-in data types such as dictionaries appear to have atomic -operations, there are corner cases where they aren't atomic (e.g. if `__hash__` -or `__eq__` are implemented as Python methods) and their atomicity should not be -relied upon. Neither should you rely on atomic variable assignment (since this -in turn depends on dictionaries). - -Use the Queue module's `Queue` data type as the preferred way to communicate -data between threads. Otherwise, use the threading module and its locking -primitives. Learn about the proper use of condition variables so you can use -`threading.Condition` instead of using lower-level locks. - - - -### 2.19 Power Features - -Avoid these features. - - -#### 2.19.1 Definition - -Python is an extremely flexible language and gives you many fancy features such -as custom metaclasses, access to bytecode, on-the-fly compilation, dynamic -inheritance, object reparenting, import hacks, reflection, modification of -system internals, etc. - - -#### 2.19.2 Pros - -These are powerful language features. They can make your code more compact. - - -#### 2.19.3 Cons - -It's very tempting to use these "cool" features when they're not absolutely -necessary. It's harder to read, understand, and debug code that's using unusual -features underneath. It doesn't seem that way at first (to the original author), -but when revisiting the code, it tends to be more difficult than code that is -longer but is straightforward. - - -#### 2.19.4 Decision - -Avoid these features in your code. - -Standard library modules and classes that internally use these features are okay -to use (for example, `abc.ABCMeta`, `collections.namedtuple`, and `enum`). - - - -### 2.20 Modern Python: Python 3 and from \_\_future\_\_ imports {#modern-python} - -Python 3 is here. While not every project is ready to use it yet, all code should be written with an eye towards the future. - - -#### 2.20.1 Definition - -Python 3 is a significant change in the Python language. While existing code is -often written with 2.7 in mind there are some simple things to do to make code -more explicit about its intentions and thus better prepared for use under Python -3 without modification. - - -#### 2.20.2 Pros - -Code written with Python 3 in mind is more explicit and easier to get running -under Python 3 once all of the dependencies of your project are ready. - - -#### 2.20.3 Cons - -Some people find the additional boilerplate to be ugly. Others say "but I don't -use that feature in this file" and want to clean-up. Please don't. It is better -to always have the future imports in all files so that they are not forgotten -during later edits when someone starts using such a feature. - - -#### 2.20.4 Decision - -##### from \_\_future\_\_ imports - -Use of `from __future__ import` statements is encouraged. All new code should -contain the following and existing code should be updated to be compatible when -possible: - -```python {.good} -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -``` - -If you are not already familiar with those, read up on each here: [absolute -imports](https://www.python.org/dev/peps/pep-0328/), [new `/` division -behavior](https://www.python.org/dev/peps/pep-0238/), and [the print -function](https://www.python.org/dev/peps/pep-3105/). - -There are other `from __future__` import statements. Use them as you see fit. We -do not include `unicode_literals` in our recommendations as it is not a clear -win due to implicit default codec conversion consequences it introduces in many -places within Python 2.7. Most code is better off with explicit use of `b''` and -`u''` bytes and unicode string literals as necessary. - -##### The six, future, or past libraries. - -When your project needs to actively support use under both Python 2 and 3, use -of these libraries is encouraged as you see fit. They exist to make your code -cleaner and life easier. - - - -### 2.21 Type Annotated Code - -You can annotate Python 3 code with type hints according to -[PEP-484](https://www.python.org/dev/peps/pep-0484/), and type-check the code at -build time with a type checking tool like -[pytype](https://github.com/google/pytype). - - -Type annotations can be in the source or in a [stub pyi -file](https://www.python.org/dev/peps/pep-0484/#stub-files). Whenever possible, -annotations should be in the source. Use pyi files for third-party or extension -modules. - - - -#### 2.21.1 Definition - -Type annotations (or "type hints") are for function or method arguments and -return values: - -```python {.good} -def func(a: int) -> List[int]: -``` - -You can also declare the type of a variable using a special comment: - -```python {.good} -a = SomeFunc() # type: SomeType -``` - - -#### 2.21.2 Pros - -Type annotations improve the readability and maintainability of your code. The -type checker will convert many runtime errors to build-time errors, and reduce -your ability to use [Power Features](#power-features). - - -#### 2.21.3 Cons - -You will have to keep the type declarations up to date. You might see type errors that you think are valid code. Use of a [type checker](https://github.com/google/pytype) -may reduce your ability to use [Power Features](#power-features). - - -#### 2.21.4 Decision - -This highly depends on the complexity of your project. Give it a try. - - - - -## 3 Python Style Rules - - - -### 3.1 Semicolons - -Do not terminate your lines with semi-colons and do not use semi-colons to put -two statements on the same line. - - - -### 3.2 Line length - -Maximum line length is *80 characters*. - -Exceptions: - -- Long import statements. -- URLs, pathnames, or long flags in comments. -- Long string module level constants not containing whitespace that would be - inconvenient to split across lines such as URLs or pathnames. -- Pylint disable comments. (e.g.: `# pylint: disable=invalid-name`) - -Do not use backslash line continuation except for `with` statements requiring -three or more context managers. - -Make use of Python's [implicit line joining inside parentheses, brackets and -braces](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining). -If necessary, you can add an extra pair of parentheses around an expression. - -```python {.good} -Yes: foo_bar(self, width, height, color='black', design=None, x='foo', - emphasis=None, highlight=0) - - if (width == 0 and height == 0 and - color == 'red' and emphasis == 'strong'): -``` - -When a literal string won't fit on a single line, use parentheses for implicit -line joining. - -```python {.good} -x = ('This will build a very long long ' - 'long long long long long long string') -``` - -Within comments, put long URLs on their own line if necessary. - -```python {.good} -Yes: # See details at - # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html -``` - -```python {.bad} -No: # See details at - # http://www.example.com/us/developer/documentation/api/content/\ - # v2.0/csv_file_name_extension_full_specification.html -``` - -It is permissible to use backslash continuation when defining a `with` statement -whose expressions span three or more lines. For two lines of expressions, use a -nested `with` statement: - -```python {.good} -Yes: with very_long_first_expression_function() as spam, \ - very_long_second_expression_function() as beans, \ - third_thing() as eggs: - place_order(eggs, beans, spam, beans) -``` - -```python {.bad} -No: with VeryLongFirstExpressionFunction() as spam, \ - VeryLongSecondExpressionFunction() as beans: - PlaceOrder(eggs, beans, spam, beans) -``` - -```python {.good} -Yes: with very_long_first_expression_function() as spam: - with very_long_second_expression_function() as beans: - place_order(beans, spam) -``` - -Make note of the indentation of the elements in the line continuation examples -above; see the [indentation](#s3.4-indentation) section for explanation. - - - -### 3.3 Parentheses - -Use parentheses sparingly. - -It is fine, though not required, to use parentheses around tuples. Do not use -them in return statements or conditional statements unless using parentheses for -implied line continuation or to indicate a tuple. - -```python {.good} -Yes: if foo: - bar() - while x: - x = bar() - if x and y: - bar() - if not x: - bar() - # For a 1 item tuple the ()s are more visually obvious than the comma. - onesie = (foo,) - return foo - return spam, beans - return (spam, beans) - for (x, y) in dict.items(): ... -``` - -```python {.bad} -No: if (x): - bar() - if not(x): - bar() - return (foo) -``` - - - - -### 3.4 Indentation - -Indent your code blocks with *4 spaces*. - -Never use tabs or mix tabs and spaces. In cases of implied line continuation, -you should align wrapped elements either vertically, as per the examples in the -[line length](#s3.2-line-length) section; or using a hanging indent of 4 spaces, -in which case there should be nothing after the open parenthesis or bracket on -the first line. - -```python {.good} -Yes: # Aligned with opening delimiter - foo = long_function_name(var_one, var_two, - var_three, var_four) - meal = (spam, - beans) - - # Aligned with opening delimiter in a dictionary - foo = { - long_dictionary_key: value1 + - value2, - ... - } - - # 4-space hanging indent; nothing on first line - foo = long_function_name( - var_one, var_two, var_three, - var_four) - meal = ( - spam, - beans) - - # 4-space hanging indent in a dictionary - foo = { - long_dictionary_key: - long_dictionary_value, - ... - } -``` - -```python {.bad} -No: # Stuff on first line forbidden - foo = long_function_name(var_one, var_two, - var_three, var_four) - meal = (spam, - beans) - - # 2-space hanging indent forbidden - foo = long_function_name( - var_one, var_two, var_three, - var_four) - - # No hanging indent in a dictionary - foo = { - long_dictionary_key: - long_dictionary_value, - ... - } -``` - - - -### 3.5 Blank Lines - -Two blank lines between top-level definitions, one blank line between method -definitions. - -Two blank lines between top-level definitions, be they function or class -definitions. One blank line between method definitions and between the `class` -line and the first method. Use single blank lines as you judge appropriate -within functions or methods. - - - -### 3.6 Whitespace - -Follow standard typographic rules for the use of spaces around punctuation. - -No whitespace inside parentheses, brackets or braces. - -```python {.good} -Yes: spam(ham[1], {eggs: 2}, []) -``` - -```python {.bad} -No: spam( ham[ 1 ], { eggs: 2 }, [ ] ) -``` - -No whitespace before a comma, semicolon, or colon. Do use whitespace after a -comma, semicolon, or colon except at the end of the line. - -```python {.good} -Yes: if x == 4: - print(x, y) - x, y = y, x -``` - -```python {.bad} -No: if x == 4 : - print(x , y) - x , y = y , x -``` - -No whitespace before the open paren/bracket that starts an argument list, -indexing or slicing. - -```python {.good} -Yes: spam(1) -``` - -```python {.bad} -No: spam (1) -``` - - -```python {.good} -Yes: dict['key'] = list[index] -``` - -```python {.bad} -No: dict ['key'] = list [index] -``` - -Surround binary operators with a single space on either side for assignment -(`=`), comparisons (`==, <, >, !=, <>, <=, >=, in, not in, is, is not`), and -Booleans (`and, or, not`). Use your better judgment for the insertion of spaces -around arithmetic operators but always be consistent about whitespace on either -side of a binary operator. - -```python {.good} -Yes: x == 1 -``` - -```python {.bad} -No: x<1 -``` - -Never use spaces around the '=' sign when passing keyword arguments. -Only use spaces around the '=' sign defining a default parameter value -[when a type annotation is present](#typing-default-values), -do not use spaces around '=' for default parameter values otherwise. - -```python {.good} -Yes: def complex(real, imag=0.0): return Magic(r=real, i=imag) -Yes: def complex(real, imag: float = 0.0): return Magic(r=real, i=imag) -``` - -```python {.bad} -No: def complex(real, imag = 0.0): return Magic(r = real, i = imag) -No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag) -``` - -Don't use spaces to vertically align tokens on consecutive lines, since it -becomes a maintenance burden (applies to `:`, `#`, `=`, etc.): - -```python {.good} -Yes: - foo = 1000 # comment - long_name = 2 # comment that should not be aligned - - dictionary = { - 'foo': 1, - 'long_name': 2, - } -``` - -```python {.bad} -No: - foo = 1000 # comment - long_name = 2 # comment that should not be aligned - - dictionary = { - 'foo' : 1, - 'long_name': 2, - } -``` - - - - - -### 3.7 Shebang Line - -Most `.py` files do not need to start with a `#!` line. Start the main file of a -program with -`#!/usr/bin/python` with an optional single digit `2` or `3` suffix per -[PEP-394](https://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0394/). - -This line is used by the kernel to find the Python interpreter, but is ignored -by Python when importing modules. It is only necessary on a file that will be -executed directly. - - - -### 3.8 Comments and Docstrings - -Be sure to use the right style for module, function, method docstrings and -in-line comments. - - - -#### 3.8.1 Docstrings - -Python uses docstrings for commenting code. A doc string is a string that is the -first statement in a package, module, class or function. These strings can be -extracted automatically through the `__doc__` member of the object and are used -by `pydoc`. -(Try running `pydoc` on your module to see how it looks.) Always use the three -double-quote `"""` format for docstrings (per [PEP -257](https://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0257/)). -A docstring should be organized as a summary line (one physical line) terminated -by a period, question mark, or exclamation point, followed by a blank line, -followed by the rest of the docstring starting at the same cursor position as -the first quote of the first line. There are more formatting guidelines for -docstrings below. - - - -#### 3.8.2 Modules - -Every file should contain license boilerplate. Choose the appropriate -boilerplate for the license used by the project (for example, Apache 2.0, BSD, -LGPL, GPL) - - - -#### 3.8.3 Functions and Methods - -As used in this section "function" applies to methods, functions, and -generators. - -A function must have a docstring, unless it meets all of the following criteria: - -- not externally visible -- very short -- obvious - -A docstring should give enough information to write a call to the function -without reading the function's code. The docstring should be descriptive -(`"""Fetches rows from a Bigtable."""`) rather than imperative -(`"""Fetch rows from a Bigtable."""`). A docstring should describe the -function's calling syntax and its semantics, not its implementation. For tricky -code, comments alongside the code are more appropriate than using docstrings. - -A method that overrides a method from a base class may have a simple docstring -sending the reader to its overridden method's docstring, such as -`"""See base class."""`. The rationale is that there is no need to repeat in -many places documentation that is already present in the base method's -docstring. However, if the overriding method's behavior is substantially -different than that of the overridden method or details need to be provided -about it (e.g., documenting additional side-effects), a docstring is required on -the overriding method, with at least those differences. - -Certain aspects of a function should be documented in special sections, listed -below. Each section begins with a heading line, which ends with a colon. -Sections should be indented two spaces, except for the heading. - -*Args:* -: List each parameter by name. A description should follow the name, and be -: separated by a colon and a space. If the description is too long to fit on a -: single 80-character line, use a hanging indent of 2 or 4 spaces (be -: consistent with the rest of the file).
-: The description should include required type(s) if the code does not contain -: a corresponding type annotation.
-: If a function accepts `*foo` (variable length argument lists) and/or `**bar` -: (arbitrary keyword arguments), they should be listed as `*foo` and `**bar`. - -*Returns:* (or *Yields:* for generators) -: Describe the type and semantics of the return value. If the function only -: returns None, this section is not required. It may also be omitted if the -: docstring starts with Returns (or Yields) (e.g. -: `"""Returns row from Bigtable as a tuple of strings."""`) and the opening -: sentence is sufficient to describe return value. - -*Raises:* -: List all exceptions that are relevant to the interface. - -```python {.good} -def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): - """Fetches rows from a Bigtable. - - Retrieves rows pertaining to the given keys from the Table instance - represented by big_table. Silly things may happen if - other_silly_variable is not None. - - Args: - big_table: An open Bigtable Table instance. - keys: A sequence of strings representing the key of each table row - to fetch. - other_silly_variable: Another optional variable, that has a much - longer name than the other args, and which does nothing. - - Returns: - A dict mapping keys to the corresponding table row data - fetched. Each row is represented as a tuple of strings. For - example: - - {'Serak': ('Rigel VII', 'Preparer'), - 'Zim': ('Irk', 'Invader'), - 'Lrrr': ('Omicron Persei 8', 'Emperor')} - - If a key from the keys argument is missing from the dictionary, - then that row was not found in the table. - - Raises: - IOError: An error occurred accessing the bigtable.Table object. - """ -``` - - - -#### 3.8.4 Classes - -Classes should have a docstring below the class definition describing the class. -If your class has public attributes, they should be documented here in an -Attributes section and follow the same formatting as a function's Args section. - -```python {.good} -class SampleClass(object): - """Summary of class here. - - Longer class information.... - Longer class information.... - - Attributes: - likes_spam: A boolean indicating if we like SPAM or not. - eggs: An integer count of the eggs we have laid. - """ - - def __init__(self, likes_spam=False): - """Inits SampleClass with blah.""" - self.likes_spam = likes_spam - self.eggs = 0 - - def public_method(self): - """Performs operation blah.""" -``` - - - -#### 3.8.5 Block and Inline Comments - -The final place to have comments is in tricky parts of the code. If you're going -to have to explain it at the next [code -review](http://en.wikipedia.org/wiki/Code_review), you should comment it -now. Complicated operations get a few lines of comments before the operations -commence. Non-obvious ones get comments at the end of the line. - -```python {.good} -# We use a weighted dictionary search to find out where i is in -# the array. We extrapolate position based on the largest num -# in the array and the array size and then do binary search to -# get the exact number. - -if i & (i-1) == 0: # True if i is 0 or a power of 2. -``` - -To improve legibility, these comments should be at least 2 spaces away from the -code. - -On the other hand, never describe the code. Assume the person reading the code -knows Python (though not what you're trying to do) better than you do. - -```python {.bad} -# BAD COMMENT: Now go through the b array and make sure whenever i occurs -# the next element is i+1 -``` - - - - -#### 3.8.6 Punctuation, Spelling and Grammar - -Pay attention to punctuation, spelling, and grammar; it is easier to read -well-written comments than badly written ones. - -Comments should be as readable as narrative text, with proper capitalization and -punctuation. In many cases, complete sentences are more readable than sentence -fragments. Shorter comments, such as comments at the end of a line of code, can -sometimes be less formal, but you should be consistent with your style. - -Although it can be frustrating to have a code reviewer point out that you are -using a comma when you should be using a semicolon, it is very important that -source code maintain a high level of clarity and readability. Proper -punctuation, spelling, and grammar help with that goal. - - - -### 3.9 Classes - -If a class inherits from no other base classes, explicitly inherit from -`object`. This also applies to nested classes. - -```python {.good} -Yes: class SampleClass(object): - pass - - - class OuterClass(object): - - class InnerClass(object): - pass - - - class ChildClass(ParentClass): - """Explicitly inherits from another class already.""" - -``` - -```python {.bad} -No: class SampleClass: - pass - - - class OuterClass: - - class InnerClass: - pass -``` - -Inheriting from `object` is needed to make properties work properly in Python 2, -and can protect your code from some potential incompatibility with Python 3. It -also defines special methods that implement the default semantics of objects -including `__new__`, `__init__`, `__delattr__`, `__getattribute__`, -`__setattr__`, `__hash__`, `__repr__`, and `__str__`. - - - -### 3.10 Strings - -Use the `format` method or the `%` operator for formatting strings, even when -the parameters are all strings. Use your best judgement to decide between `+` -and `%` (or `format`) though. - -```python {.good} -Yes: x = a + b - x = '%s, %s!' % (imperative, expletive) - x = '{}, {}'.format(first, second) - x = 'name: %s; score: %d' % (name, n) - x = 'name: {}; score: {}'.format(name, n) - x = f'name: {name}; score: {n}' # Python 3.6+ -``` - -```python {.bad} -No: x = '%s%s' % (a, b) # use + in this case - x = '{}{}'.format(a, b) # use + in this case - x = first + ', ' + second - x = 'name: ' + name + '; score: ' + str(n) -``` - -Avoid using the `+` and `+=` operators to accumulate a string within a loop. -Since strings are immutable, this creates unnecessary temporary objects and -results in quadratic rather than linear running time. Instead, add each -substring to a list and `''.join` the list after the loop terminates (or, write -each substring to a `io.BytesIO` buffer). - -```python {.good} -Yes: items = [''] - for last_name, first_name in employee_list: - items.append('' % (last_name, first_name)) - items.append('
%s, %s
') - employee_table = ''.join(items) -``` - -```python {.bad} -No: employee_table = '' - for last_name, first_name in employee_list: - employee_table += '' % (last_name, first_name) - employee_table += '
%s, %s
' -``` - -Be consistent with your choice of string quote character within a file. Pick `'` -or `"` and stick with it. It is okay to use the other quote character on a -string to avoid the need to `\\` escape within the string. `gpylint` enforces -this. - -```python {.good} -Yes: - Python('Why are you hiding your eyes?') - Gollum("I'm scared of lint errors.") - Narrator('"Good!" thought a happy Python reviewer.') -``` - -```python {.bad} -No: - Python("Why are you hiding your eyes?") - Gollum('The lint. It burns. It burns us.') - Gollum("Always the great lint. Watching. Watching.") -``` - -Prefer `"""` for multi-line strings rather than `'''`. Projects may choose to -use `'''` for all non-docstring multi-line strings if and only if they also use -`'` for regular strings. Docstrings must use `"""` regardless. Note that it is -often cleaner to use implicit line joining since multi-line strings do not flow -with the indentation of the rest of the program: - -```python {.good} - Yes: - print("This is much nicer.\n" - "Do it this way.\n") -``` - -```python {.bad} - No: - print("""This is pretty ugly. -Don't do this. -""") -``` - - - -### 3.11 Files and Sockets - -Explicitly close files and sockets when done with them. - -Leaving files, sockets or other file-like objects open unnecessarily has many -downsides, including: - -- They may consume limited system resources, such as file descriptors. Code - that deals with many such objects may exhaust those resources unnecessarily - if they're not returned to the system promptly after use. -- Holding files open may prevent other actions being performed on them, such - as moves or deletion. -- Files and sockets that are shared throughout a program may inadvertently be - read from or written to after logically being closed. If they are actually - closed, attempts to read or write from them will throw exceptions, making - the problem known sooner. - -Furthermore, while files and sockets are automatically closed when the file -object is destructed, tying the life-time of the file object to the state of the -file is poor practice, for several reasons: - -- There are no guarantees as to when the runtime will actually run the file's - destructor. Different Python implementations use different memory management - techniques, such as delayed Garbage Collection, which may increase the - object's lifetime arbitrarily and indefinitely. -- Unexpected references to the file may keep it around longer than intended - (e.g. in tracebacks of exceptions, inside globals, etc). - -The preferred way to manage files is using the ["with" -statement](http://docs.python.org/reference/compound_stmts.html#the-with-statement): - -```python {.good} -with open("hello.txt") as hello_file: - for line in hello_file: - print(line) -``` - -For file-like objects that do not support the "with" statement, use -`contextlib.closing()`: - -```python {.good} -import contextlib - -with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page: - for line in front_page: - print(line) -``` - - - -### 3.12 TODO Comments - -Use `TODO` comments for code that is temporary, a short-term solution, or -good-enough but not perfect. - -`TODO`s should include the string `TODO` in all caps, followed by the -name, e-mail address, or other identifier -of the person or issue with the best context about the problem referenced by the -`TODO`, in parentheses. A comment explaining what there is to do is required. -The main purpose is to have a consistent `TODO` format that can be searched to -find out how to get more details upon request. A `TODO` is not a commitment that -the person referenced will fix the problem. Thus when you create a `TODO`, it is almost always your name that is given. - -```python {.good} -# TODO(kl@gmail.com): Use a "*" here for string repetition. -# TODO(Zeke) Change this to use relations. -``` - -If your `TODO` is of the form "At a future date do something" make sure that you -either include a very specific date ("Fix by November 2009") or a very specific -event ("Remove this code when all clients can handle XML responses."). - - - -### 3.13 Imports formatting - -Imports should be on separate lines. - -E.g.: - -```python {.good} -Yes: import os - import sys -``` - -```python {.bad} -No: import os, sys -``` - -Imports are always put at the top of the file, just after any module comments -and docstrings and before module globals and constants. Imports should be -grouped with the order being most generic to least generic: - -1. Python standard library imports. For example: - - ```python {.good} - import sys - ``` - -2. [third-party](https://pypi.python.org/pypi) - module or package imports. For example: - - - ```python {.good} - import tensorflow as tf - ``` - -3. Code repository - sub-package imports. For example: - - - ```python {.good} - from otherproject.ai import mind - ``` - -4. application-specific imports that are part of the same - top level - sub-package as this file. For example: - - - ```python {.good} - from myproject.backend.hgwells import time_machine - ``` - -Within each grouping, imports should be sorted lexicographically, ignoring case, -according to each module's full package path. Code may optionally place a blank -line between import sections. - -```python {.good} -import collections -import Queue -import sys - -import argcomplete -import BeautifulSoup -import cryptography -import tensorflow as tf - -from otherproject.ai import body -from otherproject.ai import mind -from otherproject.ai import soul - -from myproject.backend.hgwells import time_machine -from myproject.backend.state_machine import main_loop -``` - - - - -### 3.14 Statements - -Generally only one statement per line. - -However, you may put the result of a test on the same line as the test only if -the entire statement fits on one line. In particular, you can never do so with -`try`/`except` since the `try` and `except` can't both fit on the same line, and -you can only do so with an `if` if there is no `else`. - -```python {.good} -Yes: - - if foo: bar(foo) -``` - -```python {.bad} -No: - - if foo: bar(foo) - else: baz(foo) - - try: bar(foo) - except ValueError: baz(foo) - - try: - bar(foo) - except ValueError: baz(foo) -``` - - - -### 3.15 Access Control - -If an accessor function would be trivial you should use public variables instead -of accessor functions to avoid the extra cost of function calls in Python. When -more functionality is added you can use `property` to keep the syntax -consistent. - -On the other hand, if access is more complex, or the cost of accessing the -variable is significant, you should use function calls (following the -[Naming](#s3.16-naming) guidelines) such as `get_foo()` and -`set_foo()`. If the past behavior allowed access through a property, do not -bind the new accessor functions to the property. Any code still attempting to -access the variable by the old method should break visibly so they are made -aware of the change in complexity. - - - -### 3.16 Naming - -`module_name`, -`package_name`, -`ClassName`, -`method_name`, -`ExceptionName`, -`function_name`, -`GLOBAL_CONSTANT_NAME`, -`global_var_name`, -`instance_var_name`, -`function_parameter_name`, -`local_var_name`. - -Function names, variable names, and filenames should be descriptive; eschew -abbreviation. In particular, do not use abbreviations that are ambiguous or -unfamiliar to readers outside your project, and do not abbreviate by deleting -letters within a word. - -Always use a `.py` filename extension. Never use dashes. - - - -#### 3.16.1 Names to Avoid - -- single character names except for counters or iterators. You may use "e" as - an exception identifier in try/except statements. -- dashes (`-`) in any package/module name -- `__double_leading_and_trailing_underscore__` names (reserved by Python) - - - -#### 3.16.2 Naming Convention - -- "Internal" means internal to a module or protected or private within a - class. - -- Prepending a single underscore (`_`) has some support for protecting module - variables and functions (not included with `from module import *`). While - prepending a double underscore (`__` aka "dunder") to an instance variable - or method effectively makes the variable or method private to its class - (using name mangling) we discourage its use as it impacts readability and - testability and isn't *really* private. - -- Place related classes and top-level functions together in a - module. - Unlike Java, there is no need to limit yourself to one class per module. - -- Use CapWords for class names, but lower\_with\_under.py for module names. - Although there are some old modules named CapWords.py, this is now - discouraged because it's confusing when the module happens to be named after - a class. ("wait -- did I write `import StringIO` or - `from StringIO import StringIO`?") - -- Underscores may appear in *unittest* method names starting with `test` to - separate logical components of the name, even if those components use - CapWords. One possible pattern is `test_`; for - example `testPop_EmptyStack` is okay. There is no One Correct Way to name - test methods. - - - -#### 3.16.3 File Naming {#s3.16.3-file-naming} - -Python filenames must have a `.py` extension and must not contain dashes (`-`). -This allows them to be imported and unittested. If you want an executable to be -accessible without the extension, use a symbolic link or a simple bash wrapper -containing `exec "$0.py" "$@"`. - - - -#### 3.16.4 Guidelines derived from Guido's Recommendations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypePublicInternal
Packageslower_with_under
Moduleslower_with_under_lower_with_under
ClassesCapWords_CapWords
ExceptionsCapWords
Functionslower_with_under()_lower_with_under()
Global/Class ConstantsCAPS_WITH_UNDER_CAPS_WITH_UNDER
Global/Class Variableslower_with_under_lower_with_under
Instance Variableslower_with_under_lower_with_under (protected)
Method Nameslower_with_under()_lower_with_under() (protected)
Function/Method Parameterslower_with_under
Local Variableslower_with_under
- -While Python supports making things private by using a leading double underscore -`__` (aka. "dunder") prefix on a name their use is discouraged. Prefer the use -of a single underscore. They are much easier to type, read, and to access from -small unittests. Lint warnings take care of invalid access to protected members. - - - - -### 3.17 Main - -Even a file meant to be used as an executable should be importable and a mere -import should not have the side effect of executing the program's main -functionality. The main functionality should be in a `main()` function. - -In Python, `pydoc` as well as unit tests require modules to be importable. Your -code should always check `if __name__ == '__main__'` before executing your main -program so that the main program is not executed when the module is imported. - -```python {.good} -def main(): - ... - -if __name__ == '__main__': - main() -``` - -All code at the top level will be executed when the module is imported. Be -careful not to call functions, create objects, or perform other operations that -should not be executed when the file is being `pydoc`ed. - - - -### 3.18 Function length - -Prefer small and focused functions. - -We recognize that long functions are sometimes appropriate, so no hard limit is -placed on function length. If a function exceeds about 40 lines, think about -whether it can be broken up without harming the structure of the program. - -Even if your long function works perfectly now, someone modifying it in a few -months may add new behavior. This could result in bugs that are hard to find. -Keeping your functions short and simple makes it easier for other people to read -and modify your code. - -You could find long and complicated functions when working with -some code. Do not be intimidated by modifying existing code: if working with such -a function proves to be difficult, you find that errors are hard to debug, or -you want to use a piece of it in several different contexts, consider breaking -up the function into smaller and more manageable pieces. - - - -### 3.19 Type Annotations - - - -#### 3.19.1 General Rules - -* Familiarize yourself with [PEP-484](https://www.python.org/dev/peps/pep-0484/). -* In methods, never annotate `self`, or `cls`. -* If any other variable or a returned type should not be expressed, use `Any`. -* You are not required to annotate all the functions in a module. - - At least annotate your public APIs. - - Use judgment to get to a good balance between safety and clarity on the - one hand, and flexibility on the other. - - Annotate code that is prone to type-related errors (previous bugs or - complexity). - - Annotate code that is hard to understand. - - Annotate code as it becomes stable from a types perspective. In many - cases, you can annotate all the functions in mature code without losing - too much flexibility. - - - - -#### 3.19.2 Line Breaking - -Try to follow the existing [indentation](#indentation) rules. Always prefer -breaking between variables. - -After annotating, many of the functions will become "one parameter per line". - -```python {.good} -def my_method(self, - first_var: int, - second_var: Foo, - third_var: Optional[Bar]) -> int: - ... -``` - -However, if everything fits on the same line, go for it. - -```python {.good} -def my_method(self, first_var: int) -> int: - ... -``` - -If the combination of the function name, the last parameter, and the return type -is too long, indent by 4 in a new line. - -```python {.good} -def my_method( - self, first_var: int) -> Tuple[MyLongType1, MyLongType1]: - ... -``` - -When the return type does not fit on the same line as the last parameter, the -preferred way is to indent the parameters by 4 on a new line and align the -closing parenthesis with the def. - -```python {.good} -Yes: -def my_method( - self, **kw_args: Optional[MyLongType] -) -> Dict[OtherLongType, MyLongType]: - ... -``` - -`pylint` allows you to move the closing parenthesis to a new line and align -with the opening one, but this is less readable. - -```python {.bad} -No: -def my_method(self, - **kw_args: Optional[MyLongType] - ) -> Dict[OtherLongType, MyLongType]: - ... -``` - -As in the examples above, prefer not to break types. However, sometimes they are -too long to be on a single line (try to keep sub-types unbroken). - -```python {.good} -def my_method( - self, - first_var: Tuple[List[MyLongType1], - List[MyLongType2]], - second_var: List[Dict[ - MyLongType3, MyLongType4]]) -> None: - ... -``` - -If a single name and type is too long, consider using an -[alias](#typing-aliases) for the type. The last resort is to break after the -colon and indent by 4. - -```python {.good} -Yes: -def my_function( - long_variable_name: - long_module_name.LongTypeName, -) -> None: - ... -``` - -```python {.bad} -No: -def my_function( - long_variable_name: long_module_name. - LongTypeName, -) -> None: - ... -``` - - - -#### 3.19.3 Forward Declarations - -If you need to use a class name from the same module that is not yet defined -- -for example, if you need the class inside the class declaration, or if you use a -class that is defined below -- use a string for the class name. - -```python {.good} -class MyClass(object): - - def __init__(self, - stack: List["MyClass"]) -> None: -``` - - - -#### 3.19.4 Default Values - -As per [PEP-008](https://www.python.org/dev/peps/pep-0008/#other-recommendations) -when combining an argument annotation with a default value, use spaces around -the = sign (but only for those arguments that have both an annotation and a -default). - -```python {.good} -Yes: -def func(a: int = 0) -> int: - ... -``` -```python {.bad} -No: -def func(a:int=0) -> int: - ... -``` - - - -#### 3.19.5 NoneType - -In the Python type system, `NoneType` is a "first class" type, and for typing -purposes, `None` is an alias for `NoneType`. If an argument can be `None`, it -has to be declared! You can use `Union`, but if there is only one other type, -`Optional` is a shortcut. - -```python {.good} -Yes: -def func(a: Optional[str]) -> str: - ... -``` - -```python {.bad} -No: -def func(a: Union[None, str]) -> str: - ... -``` - -If the default value of an argument is `None`, marking the variable `Optional` -is optional. - -```python {.good} -Yes: -def func(a: Optional[str] = None) -> str: - ... -def func(a: str = None) -> str: - ... -``` - - - -#### 3.19.6 Type Aliases - -You can declare aliases of complex types. The name of an alias should be -CapWorded; try to describe the composed type and end with "Type" (or "Types" for -returned tuples). If the alias is used only in this module, it should be -\_Private. - -For example, if the name of module together with the type is too long: - -```python {.good} -SomeType = module_with_long_name.TypeWithLongName -``` - -Other examples are complex nested types and multiple return variables from a -function (as a tuple). - - - -#### 3.19.7 Ignoring Types - -You can disable type checking on a line with the special comment -`# type: ignore`. - -`pytype` has a disable option for specific errors (similar to lint): - -```python {.good} -# pytype: disable=attribute-error -``` - - - -#### 3.19.8 Typing internal variables - -If an internal variable has a type that is hard or impossible to infer, you can -supply it as a special comment: - -```python {.good} -a = SomeUndecoratedFunction() # type: Foo -``` - - -#### 3.19.9 Tuples vs Lists - -Unlike Lists, which can only have a single type, Tuples can have either a single -repeated type or a set number of elements with different types. The latter is -commonly used as return type from a function. - -```python {.good} -a = [1, 2, 3] # type: List[int] -b = (1, 2, 3) # type: Tuple[int, ...] -c = (1, "2", 3.5) # type Tuple[int, str, float] -``` - - - -#### 3.19.10 TypeVar - -The Python type system has -[generics](https://www.python.org/dev/peps/pep-0484/#generics). The factory -function `TypeVar` is a common way to use them. - -Example: - -```python {.good} -from typing import List, TypeVar -T = TypeVar("T") -... -def next(l: List[T]) -> T: - return l.pop() -``` - -A TypeVar can be constrained: - -```python {.good} -AddableType = TypeVar("AddableType", int, float, str) -def add(a: AddableType, b: AddableType) -> AddableType: - return a + b -``` - -A common predefined type variable in the `typing` module is `AnyStr`. Use it for -arguments that can be `bytes` or `unicode`. - -```python {.good} -AnyStr = TypeVar("AnyStr", bytes, unicode) -``` - - -#### 3.19.11 Strings types - -When annotating functions that take or return strings, avoid using `str`, -because it means different things in Python 2 and Python 3. In Python 2, `str` -is `bytes`; in Python 3, it is `unicode`. Whenever possible, it is best to be -explicit: - -```python {.bad} -No: -def f(x: str) -> str: - ... -``` - -For code that deals with byte arrays, use `bytes`. - -```python {.good} -def f(x: bytes) -> bytes: - ... -``` - -For code that processes Unicode data, use `Text`. - -```python {.good} -from typing import Text -... -def f(x: Text) -> Text: - ... -``` - -If the type can be either bytes or unicode, use `Union`. - -```python {.good} -from typing import Text, Union -... -def f(x: Union[bytes, Text]) -> Union[bytes, Text]: - ... -``` - -If all the string types of a function are always the same, for example if the -return type is the same as the argument type in the code above, use -[AnyStr](#typing-type-var). - -Writing it like this will simplify the process of porting the code to Python 3. - - - -#### 3.19.12 Imports For Typing - -For classes from the `typing` module, always import the class itself. You are -explicitly allowed to import multiple specific classes on one line from the -`typing` module. Ex: - -```python {.good} -from typing import Any, Dict, Optional -``` - -Given that this way of importing from `typing` adds items to the local -namespace, any names in `typing` should be treated similarly to keywords, and -not be defined in your Python code, typed or not. If there is a collision -between a type and an existing name in a module, import it using -`import x as y`. - -```python {.good} -from typing import Any as AnyType -``` - -If the additional imports needed for type checking need to be avoided at -runtime, conditional imports may be used. This pattern is discouraged and -alternatives such as refactoring the code to allow top level imports should be -preferred. If this pattern is used at all, conditionally imported types need to -be referenced as strings `'sketch.Sketch'` rather than `sketch.Sketch`, to be -forward compatible with Python 3 where the annotation expressions are actually -evaluated. Imports that are needed only for type annotations can be placed -within an `if typing.TYPE_CHECKING:` block. - -- Only entities that are used solely for typing should be defined here; this - includes aliases. Otherwise it will be a runtime error, as the module will - not be imported at runtime. -- The block should be right after all the normal imports. -- There should be no empty lines in the typing imports list. -- Sort this list as if it were a regular imports list, but put the import from - the typing module at the end. -- The `google3` module also has a `TYPE_CHECKING` constant. You can use that - instead if you do you not want to import `typing` at runtime. - - -```python {.good} -import typing -... -if typing.TYPE_CHECKING: - import types - from MySQLdb import connections - from google3.path.to.my.project import my_proto_pb2 - from typing import Any, Dict, Optional -``` - - - -#### 3.19.13 Circular Dependencies - -Circular dependencies that are caused by typing are code smells. Such code is a -good candidate for refactoring. Although technically it is possible to keep -circular dependencies, the [build system](#typing-build-deps) will not let you -do so because each module has to depend on the other. - -Replace modules that create circular dependency imports with `Any`. Set an -[alias](#typing-aliases) with a meaningful name, and use the real type name from -this module (any attribute of Any is Any). Alias definitions should be separated -from the last import by one line. - -```python {.good} -from typing import Any - -some_mod = Any # some_mod.py imports this module. -... - -def my_method(self, var: some_mod.SomeType) -> None: - ... -``` - - -## 4 Parting Words - -*BE CONSISTENT*. - -If you're editing code, take a few minutes to look at the code around you and -determine its style. If they use spaces around all their arithmetic operators, -you should too. If their comments have little boxes of hash marks around them, -make your comments have little boxes of hash marks around them too. - -The point of having style guidelines is to have a common vocabulary of coding so -people can concentrate on what you're saying rather than on how you're saying -it. We present global style rules here so people know the vocabulary, but local -style is also important. If code you add to a file looks drastically different -from the existing code around it, it throws readers out of their rhythm when -they go to read it. Avoid this. - diff --git a/shell.xml b/shell.xml new file mode 100644 index 000000000..79f39f903 --- /dev/null +++ b/shell.xml @@ -0,0 +1,1152 @@ + + + + +

+ +Revision 1.26 +

+ + +
+ Paul Armstrong
+ Too many more to mention
+
+ + + + + + + + + + Bash is the only shell scripting language permitted for + executables. + + +

+ Executables must start with #!/bin/bash and a minimum + number of flags. Use set to set shell options so that + calling your script as bash <script_name> + does not break its functionality. +

+

+ Restricting all executable shell scripts to bash + gives us a consistent shell language that's installed on all our + machines. +

+

+ The only exception to this is where you're forced to by whatever + you're coding for. One example of this is Solaris SVR4 packages which + require plain Bourne shell for any scripts. +

+ +
+ + + + Shell should only be used for small utilities or simple wrapper + scripts. + + +

+ While shell scripting isn't a development language, it is used for + writing various utility scripts throughout Google. This + style guide is more a recognition of its use rather than + a suggestion that it be used for widespread deployment. +

+

+ Some guidelines: +

    +
  • + If you're mostly calling other utilities and are doing relatively + little data manipulation, shell is an acceptable choice for the + task. +
  • +
  • + If performance matters, use something other than shell. +
  • +
  • + If you find you need to use arrays for anything more than + assignment of ${PIPESTATUS}, you should use Python. +
  • +
  • + If you are writing a script that is more than 100 lines long, you + should probably be writing it in Python instead. Bear in mind + that scripts grow. Rewrite your script in another language + early to avoid a time-consuming rewrite at a later date. +
  • +
+

+ +
+
+ +
+ + + + + + Executables should have no extension (strongly preferred) or a + .sh extension. + Libraries must have a .sh extension and should not be + executable. + + +

+ It is not necessary to know what language a program is written in when + executing it and shell doesn't require an extension so we prefer not to + use one for executables. +

+

+ However, for libraries it's important to know what language it is and + sometimes there's a need to have similar libraries in different + languages. This allows library files with identical purposes but + different languages to be identically named except for the + language-specific suffix. +

+ +
+ + + + SUID and SGID are forbidden on shell scripts. + + +

+ There are too many security issues with shell that make it nearly + impossible to secure sufficiently to allow SUID/SGID. While bash does + make it difficult to run SUID, it's still possible on some platforms + which is why we're being explicit about banning it. +

+

+ Use sudo to provide elevated access if you need it. +

+ +
+ +
+ + + + + + All error messages should go to STDERR. + + +

+ This makes it easier + to separate normal status from actual issues. +

+

+ A function to print out error messages along with other status + information is recommended. + + err() { + echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $@" >&2 + } + + if ! do_something; then + err "Unable to do_something" + exit "${E_DID_NOTHING}" + fi + +

+ +
+ +
+ + + + + + Start each file with a description of its contents. + + +

+ Every file must have a top-level comment including a brief overview of + its contents. + A + copyright notice + and author information are optional. +

+

+ Example: + + #!/bin/bash + # + # Perform hot backups of Oracle databases. + +

+ + + +
+ + + + Any function that is not both obvious and short must be commented. Any + function in a library must be commented regardless of length or + complexity. + + +

+ It should be possible for someone else to learn how to use your + program or to use a function in your library by reading the comments + (and self-help, if provided) without reading the code. +

+

+ All function comments should contain: +

    +
  • + Description of the function +
  • +
  • + Global variables used and modified +
  • +
  • + Arguments taken +
  • +
  • + Returned values other than the default exit status of the last + command run +
  • +
+

+

+ Example: + + #!/bin/bash + # + # Perform hot backups of Oracle databases. + + export PATH='/usr/xpg4/bin:/usr/bin:/opt/csw/bin:/opt/goog/bin' + + ####################################### + # Cleanup files from the backup dir + # Globals: + # BACKUP_DIR + # ORACLE_SID + # Arguments: + # None + # Returns: + # None + ####################################### + cleanup() { + ... + } + +

+ +
+ + + + Comment tricky, non-obvious, interesting or important parts of your code. + + +

+ This follows general Google coding comment practice. Don't comment + everything. If there's a complex algorithm or you're doing something + out of the ordinary, put a short comment in. +

+ +
+ + + + Use TODO comments for code that is temporary, a short-term solution, or + good-enough but not perfect. + + +

+ This matches the convention in the C++ + Guide. +

+

+ TODOs should include the string TODO in all caps, followed by your + username in parentheses. A colon is optional. It's preferable to put a + bug/ticket number next to the TODO item as well. +

+

+ Examples: + + + # TODO(mrmonkey): Handle the unlikely edge cases (bug ####) + +

+ +
+ +
+ + +

+ While you should follow the style that's already there for files that + you're modifying, the following are required for any new code. +

+ + + + Indent 2 spaces. No tabs. + + +

+ Use blank lines between blocks to improve readability. Indentation is + two spaces. Whatever you do, don't use tabs. For existing files, stay + faithful to the existing indentation. +

+ +
+ + + + Maximum line length is 80 characters. + + +

+ If you have to write strings that are longer than 80 characters, this + should be done with a here document or an embedded newline if possible. + Literal strings that have to be longer than 80 chars and can't sensibly + be split are ok, but it's strongly preferred to find a way to make it + shorter. +

+

+ + # DO use 'here document's + cat <<END; + I am an exceptionally long + string. + END + + # Embedded newlines are ok too + long_string="I am an exceptionally + long string." + +

+ +
+ + + + Pipelines should be split one per line if they don't all fit on one line. + + +

+ If a pipeline all fits on one line, it should be on one line. +

+

+ If not, it should be split at one pipe segment per line with the pipe + on the newline and a 2 space indent for the next section of the pipe. + This applies to a chain of commands combined using '|' as well as to + logical compounds using '||' and '&&'. + + # All fits on one line + command1 | command2 + + # Long commands + command1 \ + | command2 \ + | command3 \ + | command4 + +

+ +
+ + + + Put ; do and ; then on the same line as the + while, for or if. + + +

+ Loops in shell are a bit different, but we follow the same principles + as with braces when declaring functions. That is: ; then + and ; do should be on the same line as the if/for/while. + else should be on its own line and closing statements + should be on their own line vertically aligned with the opening + statement. +

+

+ Example: + + for dir in ${dirs_to_cleanup}; do + if [[ -d "${dir}/${ORACLE_SID}" ]]; then + log_date "Cleaning up old files in ${dir}/${ORACLE_SID}" + rm "${dir}/${ORACLE_SID}/"* + if [[ "$?" -ne 0 ]]; then + error_message + fi + else + mkdir -p "${dir}/${ORACLE_SID}" + if [[ "$?" -ne 0 ]]; then + error_message + fi + fi + done + +

+ +
+ + + +
    +
  • + Indent alternatives by 2 spaces. +
  • +
  • + A one-line alternative needs a space after the close parenthesis of + the pattern and before the ;;. +
  • +
  • + Long or multi-command alternatives should be split over multiple + lines with the pattern, actions, and ;; on separate + lines. +
  • +
+
+ +

+ The matching expressions are indented one level from the 'case' and + 'esac'. Multiline actions are indented another level. In general, + there is no need to quote match expressions. Pattern expressions + should not be preceded by an open parenthesis. Avoid the + ;& and ;;& notations. +

+ + case "${expression}" in + a) + variable="..." + some_command "${variable}" "${other_expr}" ... + ;; + absolute) + actions="relative" + another_command "${actions}" "${other_expr}" ... + ;; + *) + error "Unexpected expression '${expression}'" + ;; + esac + +

+ Simple commands may be put on the same line as the pattern and + ;; as long as the expression remains readable. This is + often appropriate for single-letter option processing. When the + actions don't fit on a single line, put the pattern on a line on its + own, then the actions, then ;; also on a line of its own. + When on the same line as the actions, use a space after the close + parenthesis of the pattern and another before the ;;. +

+ + verbose='false' + aflag='' + bflag='' + files='' + while getopts 'abf:v' flag; do + case "${flag}" in + a) aflag='true' ;; + b) bflag='true' ;; + f) files="${OPTARG}" ;; + v) verbose='true' ;; + *) error "Unexpected option ${flag}" ;; + esac + done + + +
+ + + + In order of precedence: Stay consistent with what you find; + quote your variables; + prefer "${var}" over "$var", but see details. + + +

+ These are meant to be guidelines, as the topic seems too controversial for + a mandatory regulation. +
+ They are listed in order of precedence. +

+
    +
  1. + Stay consistent with what you find for existing code. +
  2. +
  3. + Quote variables, see Quoting section below. +
  4. +
  5. +

    + Don't brace-quote single character shell + specials / positional parameters, unless strictly necessary + or avoiding deep confusion. +
    + Prefer brace-quoting all other variables. + + # Section of recommended cases. + + # Preferred style for 'special' variables: + echo "Positional: $1" "$5" "$3" + echo "Specials: !=$!, -=$-, _=$_. ?=$?, #=$# *=$* @=$@ \$=$$ ..." + + # Braces necessary: + echo "many parameters: ${10}" + + # Braces avoiding confusion: + # Output is "a0b0c0" + set -- a b c + echo "${1}0${2}0${3}0" + + # Preferred style for other variables: + echo "PATH=${PATH}, PWD=${PWD}, mine=${some_var}" + while read f; do + echo "file=${f}" + done < <(ls -l /tmp) + + # Section of discouraged cases + + # Unquoted vars, unbraced vars, brace-quoted single letter + # shell specials. + echo a=$avar "b=$bvar" "PID=${$}" "${1}" + + # Confusing use: this is expanded as "${1}0${2}0${3}0", + # not "${10}${20}${30} + set -- a b c + echo "$10$20$30" + +

    +
  6. +
+ +
+ + + +
    +
  • + Always quote strings containing variables, command substitutions, + spaces or shell meta characters, unless careful unquoted expansion + is required. +
  • +
  • + Prefer quoting strings that are "words" + (as opposed to command options or path names). +
  • +
  • + Never quote literal integers. +
  • +
  • + Be aware of the quoting rules for + pattern matches in [[. +
  • +
  • + Use "$@" unless you have a specific reason to use $*. +
  • +
+
+ +

+ + # 'Single' quotes indicate that no substitution is desired. + # "Double" quotes indicate that substitution is required/tolerated. + + # Simple examples + # "quote command substitutions" + flag="$(some_command and its args "$@" 'quoted separately')" + + # "quote variables" + echo "${flag}" + + # "never quote literal integers" + value=32 + # "quote command substitutions", even when you expect integers + number="$(generate_number)" + + # "prefer quoting words", not compulsory + readonly USE_INTEGER='true' + + # "quote shell meta characters" + echo 'Hello stranger, and well met. Earn lots of $$$' + echo "Process $$: Done making \$\$\$." + + # "command options or path names" + # ($1 is assumed to contain a value here) + grep -li Hugo /dev/null "$1" + + # Less simple examples + # "quote variables, unless proven false": ccs might be empty + git send-email --to "${reviewers}" ${ccs:+"--cc" "${ccs}"} + + # Positional parameter precautions: $1 might be unset + # Single quotes leave regex as-is. + grep -cP '([Ss]pecial|\|?characters*)$' ${1:+"$1"} + + # For passing on arguments, + # "$@" is right almost everytime, and + # $* is wrong almost everytime: + # + # * $* and $@ will split on spaces, clobbering up arguments + # that contain spaces and dropping empty strings; + # * "$@" will retain arguments as-is, so no args + # provided will result in no args being passed on; + # This is in most cases what you want to use for passing + # on arguments. + # * "$*" expands to one argument, with all args joined + # by (usually) spaces, + # so no args provided will result in one empty string + # being passed on. + # (Consult 'man bash' for the nit-grits ;-) + + set -- 1 "2 two" "3 three tres"; echo $# ; set -- "$*"; echo "$#, $@") + set -- 1 "2 two" "3 three tres"; echo $# ; set -- "$@"; echo "$#, $@") + +

+ +
+ +
+ + + + + + Use $(command) instead of backticks. + + +

+ Nested backticks require escaping the inner ones with \. + The $(command) format doesn't change when nested and is + easier to read. +

+

+ Example: + + # This is preferred: + var="$(command "$(command1)")" + + # This is not: + var="`command \`command1\``" + +

+ +
+ + + + [[ ... ]] is preferred over [, + test and /usr/bin/[. + + +

+ [[ ... ]] reduces errors as no pathname expansion or word + splitting takes place between [[ and ]] and + [[ ... ]] allows for regular expression matching where + [ ... ] does not. + + # This ensures the string on the left is made up of characters in the + # alnum character class followed by the string name. + # Note that the RHS should not be quoted here. + # For the gory details, see + # E14 at https://tiswww.case.edu/php/chet/bash/FAQ + if [[ "filename" =~ ^[[:alnum:]]+name ]]; then + echo "Match" + fi + + # This matches the exact pattern "f*" (Does not match in this case) + if [[ "filename" == "f*" ]]; then + echo "Match" + fi + + # This gives a "too many arguments" error as f* is expanded to the + # contents of the current directory + if [ "filename" == f* ]; then + echo "Match" + fi + +

+ +
+ + + + Use quotes rather than filler characters where possible. + + +

+ Bash is smart enough to deal with an empty string in a test. So, given + that the code is much easier to read, use tests for empty/non-empty + strings or empty strings rather than filler characters. + + # Do this: + if [[ "${my_var}" = "some_string" ]]; then + do_something + fi + + # -z (string length is zero) and -n (string length is not zero) are + # preferred over testing for an empty string + if [[ -z "${my_var}" ]]; then + do_something + fi + + # This is OK (ensure quotes on the empty side), but not preferred: + if [[ "${my_var}" = "" ]]; then + do_something + fi + + # Not this: + if [[ "${my_var}X" = "some_stringX" ]]; then + do_something + fi + +

+

+ To avoid confusion about what you're testing for, explicitly use + -z or -n. + + # Use this + if [[ -n "${my_var}" ]]; then + do_something + fi + + # Instead of this as errors can occur if ${my_var} expands to a test + # flag + if [[ "${my_var}" ]]; then + do_something + fi + +

+ +
+ + + + Use an explicit path when doing wildcard expansion of filenames. + + +

+ As filenames can begin with a -, it's a lot safer to + expand wildcards with ./* instead of *. + + # Here's the contents of the directory: + # -f -r somedir somefile + + # This deletes almost everything in the directory by force + psa@bilby$ rm -v * + removed directory: `somedir' + removed `somefile' + + # As opposed to: + psa@bilby$ rm -v ./* + removed `./-f' + removed `./-r' + rm: cannot remove `./somedir': Is a directory + removed `./somefile' + +

+ +
+ + + + eval should be avoided. + + +

+ Eval munges the input when used for assignment to variables and can set + variables without making it possible to check what those variables + were. + + # What does this set? + # Did it succeed? In part or whole? + eval $(set_my_variables) + + # What happens if one of the returned values has a space in it? + variable="$(eval some_function)" + +

+ +
+ + + + Use process substitution or for loops in preference to piping to while. + Variables modified in a while loop do not propagate to the parent + because the loop's commands run in a subshell. + + +

+ The implicit subshell in a pipe to while can make it difficult to track + down bugs. + + last_line='NULL' + your_command | while read line; do + last_line="${line}" + done + + # This will output 'NULL' + echo "${last_line}" + +

+

+ Use a for loop if you are confident that the input will not contain + spaces or special characters (usually, this means not user input). + + total=0 + # Only do this if there are no spaces in return values. + for value in $(command); do + total+="${value}" + done + +

+

+ Using process substitution allows redirecting output but puts the + commands in an explicit subshell rather than the implicit subshell that + bash creates for the while loop. + + total=0 + last_file= + while read count filename; do + total+="${count}" + last_file="${filename}" + done < <(your_command | uniq -c) + + # This will output the second field of the last line of output from + # the command. + echo "Total = ${total}" + echo "Last one = ${last_file}" + +

+

+ Use while loops where it is not necessary to pass complex results + to the parent shell - this is typically where some more complex + "parsing" is required. Beware that simple examples are probably + more easily done with a tool such as awk. This may also be useful + where you specifically don't want to change the parent scope variables. + + # Trivial implementation of awk expression: + # awk '$3 == "nfs" { print $2 " maps to " $1 }' /proc/mounts + cat /proc/mounts | while read src dest type opts rest; do + if [[ ${type} == "nfs" ]]; then + echo "NFS ${dest} maps to ${src}" + fi + done + +

+ +
+ +
+ + + + + + Lower-case, with underscores to separate words. Separate libraries + with ::. Parentheses are required after the function name. + The keyword function is optional, but must be used + consistently throughout a project. + + +

+ If you're writing single functions, use lowercase and separate words + with underscore. If you're writing a package, separate package names + with ::. Braces must be on the same line as the function + name (as with other languages at Google) and no space between the + function name and the parenthesis. + + # Single function + my_func() { + ... + } + + # Part of a package + mypackage::my_func() { + ... + } + +

+

+ The function keyword is extraneous when "()" is present + after the function name, but enhances quick identification of + functions. +

+ +
+ + + + As for function names. + + +

+ Variables names for loops should be similarly named for any variable + you're looping through. + + for zone in ${zones}; do + something_with "${zone}" + done + +

+ +
+ + + + All caps, separated with underscores, declared at the top of the file. + + +

+ Constants and anything exported to the environment should be + capitalized. + + # Constant + readonly PATH_TO_FILES='/some/path' + + # Both constant and environment + declare -xr ORACLE_SID='PROD' + +

+

+ Some things become constant at their first setting (for example, via + getopts). Thus, it's OK to set a constant in getopts or based on a + condition, but it should be made readonly immediately afterwards. + Note that declare doesn't operate on global variables + within functions, so readonly or export is + recommended instead. +

+ + VERBOSE='false' + while getopts 'v' flag; do + case "${flag}" in + v) VERBOSE='true' ;; + esac + done + readonly VERBOSE + + +
+ + + + Lowercase, with underscores to separate words if desired. + + +

+ This is for consistency with other code styles in Google: + maketemplate or make_template but not + make-template. +

+ +
+ + + + Use readonly or declare -r to ensure they're + read only. + + +

+ As globals are widely used in shell, it's important to catch errors + when working with them. When you declare a variable that is + meant to be read-only, make this explicit. + + zip_version="$(dpkg --status zip | grep Version: | cut -d ' ' -f 2)" + if [[ -z "${zip_version}" ]]; then + error_message + else + readonly zip_version + fi + +

+ +
+ + + + Declare function-specific variables with local. Declaration + and assignment should be on different lines. + + +

+ Ensure that local variables are only seen inside a function and its + children by using local when declaring them. This avoids + polluting the global name space and inadvertently setting variables + that may have significance outside the function. +

+

+ Declaration and assignment must be separate statements when + the assignment value is provided by a command substitution; as + the 'local' builtin does not propagate the exit code from the + command substitution. + + my_func2() { + local name="$1" + + # Separate lines for declaration and assignment: + local my_var + my_var="$(my_func)" || return + + # DO NOT do this: $? contains the exit code of 'local', not my_func + local my_var="$(my_func)" + [[ $? -eq 0 ]] || return + + ... + } + +

+ +
+ + + + Put all functions together in the file just below constants. Don't hide + executable code between functions. + + +

+ If you've got functions, put them all together near the top of the + file. Only includes, set statements and setting constants + may be done before declaring functions. +

+

+ Don't hide executable code between functions. Doing so makes the code + difficult to follow and results in nasty surprises when debugging. +

+ +
+ + + + A function called main is required for scripts long enough + to contain at least one other function. + + +

+ In order to easily find the start of the program, put the main + program in a function called main as the bottom most + function. This provides consistency with the rest of the code base as + well as allowing you to define more variables as local + (which can't be done if the main code is not a function). The last + non-comment line in the file should be a call to main: + + main "$@" + +

+

+ Obviously, for short scripts where it's just a linear flow, + main is overkill and so is not required. +

+ +
+ +
+ + + + + + Always check return values and give informative return values. + + +

+ For unpiped commands, use $? or check directly via an + if statement to keep it simple. +

+

+ Example: + + if ! mv "${file_list}" "${dest_dir}/" ; then + echo "Unable to move ${file_list} to ${dest_dir}" >&2 + exit "${E_BAD_MOVE}" + fi + + # Or + mv "${file_list}" "${dest_dir}/" + if [[ "$?" -ne 0 ]]; then + echo "Unable to move ${file_list} to ${dest_dir}" >&2 + exit "${E_BAD_MOVE}" + fi + + +

+

+ Bash also has the PIPESTATUS variable that allows checking + of the return code from all parts of a pipe. If it's only necessary to + check success or failure of the whole pipe, then the following is + acceptable: + + tar -cf - ./* | ( cd "${dir}" && tar -xf - ) + if [[ "${PIPESTATUS[0]}" -ne 0 || "${PIPESTATUS[1]}" -ne 0 ]]; then + echo "Unable to tar files to ${dir}" >&2 + fi + +

+

+ However, as PIPESTATUS will be overwritten as soon as you + do any other command, if you need to act differently on errors based on + where it happened in the pipe, you'll need to assign + PIPESTATUS to another variable immediately after running + the command (don't forget that [ is a command and will + wipe out PIPESTATUS). + + tar -cf - ./* | ( cd "${DIR}" && tar -xf - ) + return_codes=(${PIPESTATUS[*]}) + if [[ "${return_codes[0]}" -ne 0 ]]; then + do_something + fi + if [[ "${return_codes[1]}" -ne 0 ]]; then + do_something_else + fi + +

+ +
+ + + + Given the choice between invoking a shell builtin and invoking a separate + process, choose the builtin. + + +

+ We prefer the use of builtins such as the Parameter Expansion + functions in bash(1) as it's more robust and portable + (especially when compared to things like sed). +

+

+ Example: + + # Prefer this: + addition=$((${X} + ${Y})) + substitution="${string/#foo/bar}" + + # Instead of this: + addition="$(expr ${X} + ${Y})" + substitution="$(echo "${string}" | sed -e 's/^foo/bar/')" + +

+ +
+ +
+ + +

+ Use common sense and BE CONSISTENT. +

+

+ Please take a few minutes to read the Parting Words section at the bottom + of the C++ Guide. +

+
+ +

+Revision 1.26 +

+ +
diff --git a/styleguide.css b/styleguide.css new file mode 100644 index 000000000..adba8f3cc --- /dev/null +++ b/styleguide.css @@ -0,0 +1,147 @@ +body { + background-color: #fff; + color: #333; + font-family: sans-serif; + font-size: 10pt; + margin-right: 100px; + margin-left: 100px; +} + +h1, h2, h3, h4, h5, h6, .toc_title { + color: #06c; + margin-top: 2em; + margin-bottom: 1em; +} + +h1 { + text-align: center; + font-size: 18pt; +} + +h2, .toc_title { + font-weight: bold; + font-size: 12pt; + margin-left: -40px; +} + +h3, h4, h5, h6 { + font-size: 10pt; + margin-left: -20px; +} + +.toc_category, .toc_stylepoint { + font-size: 10pt; + padding-top: .3em; + padding-bottom: .3em; +} + +table { + border-collapse: collapse; +} + +td, th { + border: 1px solid #ccc; + padding: 2px 12px; + font-size: 10pt; +} + +.toc td, .toc th { + border-width: 1px 5px; +} + +code, samp, var { + color: #060; +} + +pre { + font-size: 10pt; + display: block; + color: #060; + background-color: #f8fff8; + border-color: #f0fff0; + border-style: solid; + border-top-width: 1px; + border-bottom-width: 1px; + border-right-width: 1px; + border-left-width: 5px; + padding-left: 12px; + padding-right: 12px; + padding-top: 4px; + padding-bottom: 4px; +} + +pre.badcode { + color: #c00; + background-color: #fff8f8; + border-color: #fff0f0; +} + +.showhide_button { + float: left; + cursor: pointer; + border-width: 1px; + border-style: solid; + border-color: #ddd #aaa #aaa #ddd; + padding: 0 3px 1px; + margin: 0 4px 8px 0; + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; +} + +.link_button { + float: left; + display: none; + background-color: #f8f8ff; + border-color: #f0f0ff; + border-style: solid; + border-width: 1px; + font-size: 75%; + margin-top: 0; + margin-left: -50px; + padding: 4px; + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; +} + +address { + text-align: right; +} + +hr { + margin-top: 3.5em; + border-width: 1px; + color: #fff; +} + +.stylepoint_section { + display: block; + margin-bottom: 1em; + color: #5588ff; + font-family: sans-serif; + font-size: 90%; + font-weight: bold; + margin-left: -2%; +} + +.stylepoint_subsection { + color: #667799; + font-family: sans-serif; + font-size: 90%; + font-weight: bold; + margin-left: -1%; +} + +.stylepoint_subsubsection { + color: #667799; + font-family: sans-serif; + font-size: 80%; + font-weight: bold; + margin-left: 0; +} + +.revision { + text-align: right; +} + diff --git a/styleguide.xsl b/styleguide.xsl new file mode 100644 index 000000000..dfdc598d6 --- /dev/null +++ b/styleguide.xsl @@ -0,0 +1,924 @@ + + + + + + + + + + + + + + + + + + <xsl:value-of select="@title"/> + + + + + + + +

+ + + +
+ + + + + + + + + + + + +
+

+ Each style point has a summary for which additional information is available + by toggling the accompanying arrow button that looks this way: + + . + You may toggle all summaries with the big arrow button: +

+
+ + + + + + + Toggle all summaries +
+
+ + + + +
+ + +

Parting Words

+ +
+ + +
+ +

+ + + + + + + + +

+ +
+
+ + +
+ + + + + + + + + + + + + + + + +

+ + + + + +

+ + + + + javascript:ShowHideByName(' + + ') + + + + ?showone=# + link + + + + + + + + + + + +
+
+ + + +
+ + +
+
+ + + +
+ +
+ + + + + display: inline + display: none + + + +
+
+
+ + +

+ + Definition: + +

+
+ + +

+ + Pros: + +

+
+ + +

+ + Cons: + +

+
+ + +

+ + Decision: + +

+
+ + +

+ +

TODO: + +
+

+
+ + +

+ + + +

+
+ + +

+ + + +

+
+ + +
+ +

+           
+           
+           
+           
+             
+               
+               
+             
+           
+         
+
+
+ + +
+ +

+           
+           
+           
+           
+             
+               
+               
+             
+           
+         
+
+
+ + +
+ +

+             
+           
+
+
+ + +
+ +

+                             
+                           
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Table of Contents
+ + + + + + + +
+ + +
+ + + + + + # + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _ + + + + + + + + + + + + + + +
+ diff --git a/vimscriptfull.xml b/vimscriptfull.xml new file mode 100644 index 000000000..fa7e34393 --- /dev/null +++ b/vimscriptfull.xml @@ -0,0 +1,1534 @@ + + + +

+ + Revision 1.1 +

+ + +
+ Nate Soares
+ Joshua Hoak
+ David Barnett
+
+ + + +

+ This is the in-depth vimscript guide. If you're just a casual user + looking to write a plugin, the + abbreviated style guide is for you. +

+

+ This rather rotund guide dives into justifications and clarifications. + It provides an idealized set of rules that are rather too draconian to + push on casual scripters. +

+ +

+ It's for users who want to know why certain decisions were made in the + abbreviated guide and who want to learn a thing or two about using + vimscript safely. +

+

+ Fair warning: Vimscript is a maddening abyss. When you gaze into it, it + gazes also into you. Proceed with caution. +

+
+
+ + +

+ Vim is highly configurable. Users can change many of the default + settings, including the case sensitivity, the regular expression rules, + the substitution rules, and more. In order for your vimscript to work + for all users, follow these guidelines: +

+
    +
  • + Always prefix regular expressions with one of \m, + \v, \M, or \V (prefer + tersity) +
      +
    • + Users can change the global "magic level" of regular expressions. + This changes how atoms are parsed in regular expressions, + including ., *, and {. +
    • +
    • + Even if your regular expression does not contain characters which + are affected by the magic setting you must prefix it + with one of the magic control atoms. This future-proofs your + regular expression against other devs modifying it and forgetting + to add the control atom. +
    • +
    • + If you have no opinion about what type of regular expression to + use, prefer the one which makes your regular expression most + concise. +
    • +
    +
  • +
  • + Avoid using :s[ubstitute] in scripts. +
      +
    • + :substitute moves the cursor. +
    • +
    • + :substitute outputs an error message when the match + does not exist. +
    • +
    • + The meaning of the g flag depends upon the + gdefault setting. If you do use + :substitute you must save gdefault, set + it to 0 or 1, perform the substitution, + and then restore it. +
    • +
    • + Script authors who want a safe way to replace text in the buffer + are encouraged to use maktaba#buffer#Replace. +
    • +
    +
  • +
  • + Always use case-explicit operators for strings (=~# and + =~?, never =~). +
      +
    • + This also applies to !~ == != > >= < and + <= +
    • +
    • + This only applies for strings. == and + >= are fine for numbers, but ==# and + >=# must be used for strings. +
    • +
    • + The behavior of =~ and friends is dependant upon the + ignorecase setting. +
    • +
    • + You may break this rule when you explicitly want to obey the + user's ignorecase setting. Be prepared to justify + your reasoning. +
    • +
    +
  • +
  • + When using regular expressions as arguments to functions, prepend them + with \c or \C. +
      +
    • + This forces case to be either explicitly matched or ignored. +
    • +
    • + This is recommended, but not required, when comparing regexes with + operators that specify case sensitivity (=~#, etc.). +
    • +
    • + This rule applies when your regexes are matching syntax, external + APIs, external messages, and most other cases. +
    • +
    • + It does not apply when matching text in the buffer. When matching + text in the buffer you should honor the ignorecase + setting. +
    • +
    • + You may also ignore this rule any time that you explicitly want to + honor the ignorecase setting. Be prepared to justify + your reasoning. +
    • +
    +
  • +
  • + Always use normal! instead of normal. +
      +
    • + If you forgo the ! the command will use the user's + key mappings and you have literally no idea what your macro will + do. +
    • +
    +
  • +
  • + Always use the noremap family of commands. +
      +
    • + Your plugins generally shouldn't introduce mappings, but if they + do, the map command respects the users existing + mappings and could do anything. +
    • +
    +
  • +
  • + When using catch, match the error code rather than the + error text. +
      +
    • + The error text may be locale-dependant. +
    • +
    • + See :help error-messages. +
    • +
    +
  • +
+

+ In general, guard all commands and functions against user settings. +

+ +
+ +
    + + +
  • + Line continuations: Yes +
      + +
    • + Plugins that support vi compatibility mode must save and restore + compatibility options as described in the + Errata section so line continuations work properly. +
    • +
    +
  • +
  • + Exceptions: Yes, with caution +
      +
    • + Always use an error code in thrown exception messages. +
    • +
    • + Prefer the maktaba#error codes found in + maktaba. +
    • +
    • + Fall back to the vim error codes. See + :help error-messages. +
    • +
    • + Generate custom error messages using + maktaba#error#Message. +
    • +
    +
  • +
  • + Global Variables: As configuration only +
      +
    • + See the plugin guide. +
    • +
    +
  • +
  • + Messaging: As little as possible. +
      +
    • + Loud scripts are annoying. +
    • +
    • + Message the user when an error has occured. +
    • +
    • + Message the user when an operation which takes a long time has + begun work. +
    • +
    • + Avoid messaging otherwise. +
    • +
    +
  • +
  • + Type checking: + Use strict and explicit checks where possible. +
      +
    • + Vimscript has unsafe, unintuitive behavior when dealing with some + types. For instance, 0 == 'foo' evaluates to true. +
    • +
    • + Use strict comparison operators where possible. When comparing + against a string literal, use the is# operator. + Otherwise, prefer maktaba#value#IsEqual or check + type() explicitly. +
    • +
    • + Check variable types explicitly before using them. Use functions + from maktaba#ensure, or check + maktaba#value or type() and throw your own + errors. +
    • +
    • + Use :unlet for variables that may change types, + particularly those assigned inside loops. +
    • +
    +
  • +
  • + FuncRefs: No in most cases. +
      +
    • + FuncRefs have inconsistently enforced naming restrictions. + (Functions can have names that FuncRefs can not.) +
    • +
    • + FuncRefs have inconsistent ability to be reassigned (in Vim + 7.2 and before you must unlet a FuncRef before assigning it). +
    • +
    • + In most instances where a FuncRef is needed a string works + just as well: just pass the string that you would use to make + the FuncRef. +
    • +
    • + Consider using maktaba#function instead to create and + manipulate handles to functions. +
    • +
    +
  • +
  • + Python: Sparingly +
      + +
    • + Hurts code reuse since python code embedded in python plugins is + awkward to share between plugins. +
    • +
    • + Using python introduces python language version dependencies, which + are likely to get stale. +
    • +
    • + Exception: It's reasonable to use python for plugin functionality + that needs to do work in the background, as vimscript can not do + this. +
    • +
    +
  • +
  • + Ruby: No +
      +
    • + We can not assume ruby interoperability. +
    • +
    • + You shouldn't depend upon the version of the ruby language that the + user has installed. +
    • +
    +
  • +
  • + Lua: No +
      +
    • + For the same reasons an Ruby. +
    • +
    +
  • +
  • + Dict Functions: Encouraged +
      +
    • + Vimscript can attach functions to dictionaries. Such functions + have access to the self parameter which access + the dict state. +
    • +
    • + Use these where you would use a class in python. +
    • +
    • + Do not over-use this feature; it is not necessary for helper + functions or API functions, only for encapsulated objects. +
    • +
    +
  • +
+

+ All other language features are fair game. +

+
+ +
    +
  • + Provided functionality should be packed into modular plugins. +
      +
    • + Every function in your plugin should be specific to your + plugin. +
    • +
    • + General utility functions should be abstracted into library plugins. +
    • +
    • + Manage dependencies with maktaba. +
    • +
    +
  • +
  • + plugin-names-like-this +
      +
    • + Plugin names should be descriptive and concise. +
    • + + +
    +
  • +
  • + Each plugin must consist of one directory (or code repository), sharing + a name with the plugin (with a "vim-" prefix or ".vim" suffix if + desired). +
  • +
  • + Plugin metadata should be declared in the addon-info.json format (see + the VAM documentation for details). +
  • +
  • + Functions should go in the autoload/ subdirectory of + your plugin. +
      +
    • + This allows them to be late-loaded, which speeds up startup + time. +
    • +
    • + This helps vim enforce namespacing conventions. +
    • +
    +
  • +
  • + Each file in the plugin/ or instant/ directory + should begin with the boilerplate + + let [s:plugin, s:enter] = maktaba#plugin#Enter(expand('<sfile>:p')) + if !s:enter + finish + endif + + (This prevents re-entry and allows users to selectively disable + functionality.) +
  • +
  • + User configuration should be via plugin flags defined in + instant/flags.vim. +
      +
    • + Define flags with + call s:plugin.Flag('FLAGNAME', DEFAULT_VALUE). +
    • +
    • + Users can configure these flags using the :Glaive + command (see glaive). +
    • +
    +
  • +
  • + Commands, autocommands, mappings, and settings changes should + occur either in the plugin/ or the + ftplugin/ subdirectories. +
      +
    • + All commands should be defined in plugin/commands.vim + or ftplugin/ files. +
    • +
    • + Autocommands should be defined in plugin/autocmds.vim, + inside an augroup. +
    • +
    • + Mappings should be defined in plugin/mappings.vim and + will be disabled unless explicitly enabled by users. +
    • +
    • + If the plugin configures any standard vim settings, those should be + configured in plugin/settings.vim or + instant/settings.vim. +
    • +
    +
  • +
  • + Avoid using the after/ subdirectory. +
      +
    • + after/ should be reserved for the user. +
    • +
    • + It is difficult for the user to add their own overrides when + plugins use after/. +
    • +
    +
  • +
+ + + + Separate library-providing plugins from command-providing plugins. + + +

+ Many plugins provide either user functionality (commands, + autocommands, etc) or an API (of autoloaded functions) but not both. + This separation is encouraged, as it allows other plugins to pull in a + library without also pulling in commands, setting changes, and other + plugin functionality that affects the end user. +

+ +
+ + + + Don't clobber user settings. Provide as much configurability as + possible: that's what Vim's all about. + + +
    +
  • + Use maktaba flags for plugin configuration. Users can configure them + using the :Glaive command. + +
  • +
  • + Check if configuration variables exist before setting them. + + if !exists('g:myplugin_option') + let g:myplugin_option = 1 + endif + +
  • +
+ +
+
+ +

+ Follow google-wide style conventions. Mimic google python style when + in doubt. +

+ + + + + + Use vimdoc. + + +

+ Provide help files generated by + vimdoc. Write + documentation in .vim files in conformance with the vimdoc standards + and include fields like "description" and "author" in the + addon-info.json file (see the + VAM documentation). +

+ +
+ + + + Follow google-wide conventions. + + +
    +
  • + Use two spaces for indents. +
  • +
  • + Do not use tabs. +
  • +
  • + Use spaces around operators except for arguments to commands. +
      +
    • + Using spaces around operators for commands is often invalid + syntax. This is inconsistently enforced by vimscript. To be + safe, always omit whitespace around arguments to commands. +
    • +
    • + + let s:variable = "concatenated " . "strings" + command -range=% MyCommand + + + let s:variable="concatenated "."strings" + command -range = % MyCommand + +
    • +
    +
  • +
  • + Do not introduce trailing whitespace. +
      +
    • + You need not go out of your way to remove it. +
    • +
    +
  • +
  • + Restrict lines to 80 columns wide. +
  • +
  • + Indent continued lines by two tabs (four spaces). +
  • +
  • + Do not waste whitespace aligning common segments of similar + commands. It is both difficult and expensive to maintain. +
      +
    • + + command -bang MyCommand call myplugin#foo() + command MyCommand2 call myplugin#bar() + + + command -bang MyCommand call myplugin#foo() + command MyCommand2 call myplugin#bar() + +
    • +
    +
  • +
+ +
    +
  • + Prefer line continuations on semantic boundaries. +
      +
    • + + command SomeLongCommand + \ call some#function() + + + command SomeLongCommand call + \ some#function() + +
    • +
    • + Use your best judgement. +
    • +
    +
  • +
  • + Place one space after the backslash denoting a line continuation. +
      +
    • + When continuing a multi-line command a pipe can be substituted + for this space as necessary, as follows: + + autocommand BufEnter <buffer> + \ if !empty(s:var) + \| call some#function() + \|else + \| call some#function(s:var) + \|endif + +
    • +
    +
  • +
  • + Do not continue multi-line commands when you can avoid it. Prefer + function calls. +
  • +
+
+ +
    +
  • + Place a space after the " before the comment text. +
      +
    • + + " I am a line comment. + call call(s:my_function) + +
    • +
    +
  • +
  • + Do not use inline comments. +
      +
    • + Some commands treat them as comments and others as unclosed + quotes. There are many edge cases. It's difficult to get + right and difficult to maintain. +
    • +
    • + Where you would use an inline comment, put a line comment on + the line above. +
    • +
    +
  • +
  • + When leaving blank lines in comments, include the quote in the + blank line. +
      +
    • + + " I am one continuous + " + " comment block + +
    • +
    +
  • +
+
+ +
+ + + +

+ plugin-names-like-this, + FunctionNamesLikeThis, + CommandNamesLikeThis, + augroup_names_like_this, + variable_names_like_this. +

+

+ Prefix all variables with their scope. +

+
+ +
    +
  • + variable_names_like_this +
      +
    • + FuncRef variables count as functions and should be named like + functions. +
    • +
    • + This (pathological) convention is enforced by vim itself. +
    • +
    +
  • +
  • + Prefix global variables with g: +
      +
    • + Vimscript allows you to create global variables without + prefixing them. +
    • +
    • + It is very bad practice to introduce non-prefixed global + variables into scope. +
    • +
    • + Global variables should only be used for plugin configuration. +
    • +
    • + This does not apply to functions defined in + autoload directories. +
    • +
    +
  • +
  • + Prefix script-local variables with s: +
      +
    • + This prevents namespace collisions between plugins. +
    • +
    • + This also applies to script-local functions. +
    • +
    +
  • +
  • + Prefix function arguments with a: +
      +
    • + This is enforced by vim itself. +
    • +
    +
  • +
  • + Prefix function-local variables with l: +
      +
    • + This is not enforced by vimscript but is good practice. +
    • +
    • + It helps you remember that all other variables must be + prefixed with scope. +
    • +
    • + l: disambiguates between function-local and + vim-predefined variables. For example, count + refers to + v:count, not l:count. +
    • +
    • + It future proofs your scripts against the introduction of new + vim-predefined variables. +
    • +
    +
  • +
  • + Prefix pre-defined vim variables with v: +
      +
    • + This is not enforced by vimscript but is good practice. +
    • +
    • + It provides context as to where the (undeclared) variable is + coming from. +
    • +
    • + It reminds you that the variable can not be assigned to. +
    • +
    +
  • +
  • + Prefix buffer-local variables with b: +
      +
    • + This is useful for plugins that keep per-buffer state. +
    • +
    +
  • +
+ +
+ + + + Prefer single quotes. + + +

+ Prefer single quoted strings. Specifically, in order of precedence: +

+
    +
  • + Always use single quotes for regular expressions. +
      +
    • + '\s*' is not the same as "\s*" +
    • +
    • + Single quotes will prevent the need for excessive backslashes. +
    • +
    • + Double single quotes escape to one single quote in single + quoted strings: 'example ('')' represents the + string + example (') +
    • +
    +
  • +
  • + If your string requires escape characters (\n, + \t, etc.) use double quotes. +
      +
    • + Escapes can not be expressed in single quoted strings. +
    • +
    • + Remember that '\n' in a regex does not represent a + newline, but rather "\n". You only need to use double quotes + when you want to embed the represented character itself (e.g. a + newline) in the string. +
    • +
    +
  • +
  • + If your string contains no escapes nor single quotes, use single + quoted strings. +
      +
    • + Most strings in vimscript are regexes, so this provides maximum + consistency. +
    • +
    +
  • +
  • + If your non-regex string contains single quotes but no double + quotes, use double quotes. +
      +
    • + Don't bother escaping strings if you don't have to. +
    • +
    • + This is similar to the python string rules. +
    • +
    +
  • +
  • + If your string contains both single and double quotes, use whichever + quoting style requires less escaping. +
      +
    • + Break ties in favor of single quotes. +
    • +
    +
  • +
+ +
+ + + + Prefer long names. Set settings locally. + + +
    +
  • + Prefer long names of built in settings (i.e. tabstop + over + ts). +
  • +
  • + Set local settings unless you explicitly want to set global + settings. +
      +
    • + Use setlocal and &l: instead of + set and &. +
    • +
    +
  • +
+ +
+
+ +

+ Vim plugins should provide any or all of the following: + Commands, Autocommands, + Functions, Statusline Flags, and + Mappings. +

+ + + +
    +
  • Define in plugin/commands.vim.
  • +
  • CommandNamesLikeThis.
  • +
  • Prefer semantic names to a unified prefix.
  • +
  • Do not use [!]
  • +
  • Extract logic into functions.
  • +
+
+ +
    +
  • + CommandNamesLikeThis +
  • +
  • + Commands should be defined in one block with no whitespace between + them. +
      +
    • + Name commands semantically at the expense of a common prefix. +
    • +
    • + + command WhitespaceFixTrailing + command WhitespaceFixIndentation + + + command FixTrailingWhitespace + command FixIndentation + +
    • +
    +
  • +
  • + Use command without a bang. +
      +
    • + This notifies users to command name conflicts immediately at + startup. +
    • +
    • + Command name collisions are an error and should not fail + silently. +
    • +
    • + Plugins are guarded against re-entry, so a single vim session + should never attempt to re-define defined commands. +
    • +
    +
  • +
  • + Do not put logic in commands. +
      +
    • + Delegate to functions instead. +
    • +
    • + Pass non-argument command parameters (<bang>, + <register>, etc.) before argument parameters + (<f-args>, etc.). +
    • +
    • + Otherwise variable-length argument functions are difficult to + implement. +
    • +
    +
  • +
  • + Do not autoload commands. +
      +
    • + Autoloaded commands will not be available until after a function + in the same file is called. +
    • +
    • + Commands intended to be used in the .vimrc should be defined in + a instant/commands.vim file in plugins using + maktaba, or explicitly installed via an autoload function in + non-maktaba plugins. +
    • +
    +
  • +
+ +
    +
  • + Pass <bang> to functions with + '<bang>' == '!'. +
      +
    • + The function should receive a boolean parameter, not a string. +
    • +
    +
  • +
+
+ +
+ + + +
    +
  • Define in plugin/autocmds.vim.
  • +
  • Use augroups.
  • +
  • augroup_names_like_this.
  • +
  • Clear the augroup first.
  • +
  • Extract logic into functions.
  • +
+
+ +
    +
  • + All autocommands should be defined in the + plugin/autocmds.vim file. +
      +
    • + This allows users to disable your autocommands with + Glaive myplugin !plugin[autocmds]. +
    • +
    +
  • +
  • + Declare all autocommands in an augroup block. +
      +
    • + This allows your autocommands to be cleared with + autocmd!. +
    • +
    • + If your plugin only has one augroup, the + augroup name should be the same as your plugin + name, with underscores in place of any hyphens. +
    • +
    • + Otherwise augroup names should start with your + plugin name followed by an underscore. +
    • +
    +
  • +
  • + Do not put logic in autocommands. +
      +
    • + Delegate to functions instead. +
    • +
    +
  • +
  • + When creating a new augroup, clear it with + autocmd! +
      +
    • + This allows your plugins to be re-enterable. +
    • +
    +
  • +
+ +
+ + + +
    +
  • FunctionNamesLikeThis.
  • +
  • Autoload all functions.
  • +
  • Prefix script-local functions with s:
  • +
  • Use [!].
  • +
  • Use [abort].
  • +
+
+ +
    +
  • + FunctionNamesLikeThis +
  • +
  • + Prefix all script-local functions with s: +
  • +
  • + Do not provide global functions. Use autoloaded functions instead. +
  • +
  • + Place two blank lines between top-level functions. +
  • +
  • + Declare all functions with abort. +
      +
    • + If you do not do this, the function's behavior depends upon + whether it is called within a try..endtry block + somewhere on the stack. +
    • +
    • + The abort keyword forces the function to act + consistently. +
    • +
    • + Without it, the function may (or may not) attempt to continue + execution after an error occurs. +
    • +
    +
  • +
  • + Use function! with a bang. +
      +
    • + This allows developers to re-source their scripts and have the + functions reloaded without complaint. +
    • +
    • + Function names should never collide because functions should + always be either script-local or defined in an + autoload directory. +
    • +
    • + Failing to use a bang in any function in an autoload file will + lead to cryptic errors if vim tries to re-source the file + (e.g., if you refer to an nonexistent autoload function). +
    • +
    +
  • +
  • + Use ... for optional arguments, not for lists of + arguments. +
      +
    • + Vimscript functions take at most 20 arguments. +
    • +
    • + Lists have no such length restriction. +
    • +
    • + Your function is likely to break when given too many arguments + if you use ... for a list of arguments. +
    • +
    +
  • +
  • + Throw exceptions rather than printing errors. +
      +
    • + Printed errors can not be caught. +
    • +
    • + Top-level functions expecting errors may catch them and print + error messages, but even those should throw their own errors + when they choke. +
    • +
    +
  • +
+ +
+ + + +
    +
  • + Provide opt-in key mappings in plugin/mappings.vim. +
  • +
  • + <Plug> mappings can be defined in + plugin/plugs.vim (unlike mappings.vim, plugs.vim is + opt-out). +
  • +
+
+ +
    +
  • + Define key mappings in plugin/mappings.vim, using + maktaba#plugin#MapPrefix to get a prefix. +
      +
    • + Mappings defined in the special plugin/mappings.vim + file will be disabled by default (by the standard + maktaba#plugin#Enter() boilerplate). +
    • +
    • + Users can enable key mappings with + Glaive myplugin plugin[mappings]. +
    • +
    +
  • +
  • + Make all mappings with <unique>. +
      +
    • + This will inform the user when they have a mapping conflict + instead of silently clobbering their existing mappings. +
    • +
    +
  • +
  • + You may provide pseudo-mappings using <Plug> and + your plugin's name in plugin/plugs.vim (separate from + standard key mappings). +
      +
    • + <Plug> is a sequence which can not be typed. +
    • +
    • + You can do something like + noremap <Plug>namespace#MappingName + some_key_sequence + and then users can do + noremap <leader>x + <Plug>namespace#MappingName + to take advantage of your pseudo-mapping. +
    • +
    • + Pseudo-mappings should not be in + plugin/mappings.vim or they will be disabled by + default. +
    • +
    • + Such pseudo-mappings should be named <Plug> + followed by your plugin name, a pound sign, and a unique mapping + name (CamelCased like a function). +
    • +
    +
  • +
  • + Always use the noremap family of commands. Never use + the map family. +
      +
    • + map depends upon the user's existing mappings, and + could do anything. +
    • +
    +
  • +
  • + Only use noremap for commands that both make a motion + and take a range. +
      +
    • + noremap makes mappings in normal, visual, and + operator-pending modes. +
    • +
    • + If you don't want all these use nnoremap + onoremap or vnoremap explicitly. +
    • +
    +
  • +
  • + Always use <SID> in place of s: when + accessing script locals in mappings. +
      +
    • + Using s: will often fail as the mapping attempts to + type a literal s and colon. +
    • +
    +
  • +
+ +
+
+ + + + Declare dependencies in addon-info.json and use maktaba. + + +

+ Declaring dependencies in addon-info.json allows conformant plugin + managers (like VAM) to ensure dependencies are installed. See the + VAM documentation for details. +

+

+ Calling maktaba#library#Require from dependent code at + runtime ensures that dependencies have been installed and that they + don't include unsafe non-library files. +

+ +
+ + + + Use <plugin-name>#status#Status() or its + finer-grained variants to provide statusline flags. + + +

+ Following is a convention for exposing statusline flags to the user. A + plugin should never modify the user's statusline except for when that + is the only purpose of the plugin (powerline, etc.). +

+
    +
  • + Provide the + Info, + Alert, + Warning, and + Error functions under the + <plugin-name>#status namespace. +
  • +
  • + Info should provide information about the + state of the buffer. +
      +
    • + Example: The current git branch. +
    • +
    +
  • +
  • + Alert should provide a quiet reminder + that the buffer is non-standard. +
      +
    • + Example: The readonly setting is on. +
    • +
    +
  • +
  • + Warning should provide a warning about + the current state of the buffer. +
      +
    • + Example: The file has been edited elsewhere. +
    • +
    +
  • +
  • + Error should bring to attention a loud + issue with the buffer. +
      +
    • + Example: The file does not pass the syntax checker. +
    • +
    +
  • +
  • + By following these conventions, users can easily build up their own + statusline customizing the verbosity and colors to their tastes. +
  • +
  • + All functions should take no arguments and should return either + empty strings or strings enclosed by square brackets, e.g. + [Google]. For example: +
      +
    • + A trailing whitespace plugin might return [$] if + the file contains trailing whitespace +
    • +
    • + A prose writing plugin might return [write] if vim + is in writing mode. +
    • +
    +
  • +
  • + Consider providing the + <plugin-name>#status#Status function. +
      +
    • + It should return the first non-empty of Error, + Warning, Alert, or Info. +
    • +
    • + This is useful for users who want only the most relevant flag + and do not have a colored statusline. +
    • +
    +
  • +
+ +
+
+ +

+ These are commands which can only be used by a limited number of + plugins, and should not in general be used by yours. +

+
    +
  • + Do not use :match :2match or :3match +
      +
    • + These are reserved for the user and for vim itself. +
    • +
    • + Use matchadd() to create a matchlevel unique to your + plugin. +
    • +
    +
  • +
  • + Do not use echoerr. +
      +
    • + echoerr does not print the red error message that you + might think it does. +
    • +
    • + echoerr prints an error message as well as context + about the code where echoerr was called. +
    • +
    • + echoerr is best suited for debugging. +
    • +
    • + Use echohl in tandem with echomsg if + you want the red error bar. +
    • +
    +
  • +
  • + Use echomsg instead of echo. +
      +
    • + echomsg messages can be reviewed with the + :messages command. +
    • +
    • + echo messages disappear permanently on redraw, which + can be very annoying to users who failed to read the message in + time. +
    • +
    +
  • +
+
+ +

+ Lay out plugin/ files in the following sections, if + applicable, separated by two blank lines: +

+
    +
  • + Declaration of script constants +
  • +
  • + Declaration of configuration variables +
  • +
  • + Other declarations (commands in commands.vim file, + autocommands in autocmds.vim file, etc.) +
  • +
+

+ Lay out autoload/ files in the following sections, if + applicable, separated by two blank lines: +

+
    +
  • + maktaba#library#Require calls +
  • +
  • + Script-local variables +
  • +
  • + Script-local functions +
  • +
  • + Private autoloaded functions +
  • +
  • + Public autoloaded functions +
  • +
+

+ This is recommended convention and is not enforced. +

+ +
+ + +

+ Use the following shortcuts: +

+
    +
  • + catch over catch /.*/ +
  • +
  • + return over return 0 when the return value + has no semantic purpose. +
  • +
+ +
+ +

+ This section plumbs some of the darker corners of vimscript, explaining + the language pathologies that you wish you didn't have to know. + +

+ + + + If you don't support vi-compatibility mode, fail gracefully. + + +

+ When compatible is set, many vim features are not + available. The vim feature which most commonly affects vimscript + authors is line continuations. +

+

+ If you want your plugin to work in vim with vi compatibility on, you + will need to save the compatibility options at the beginning of each + plugin file, clear them, and restore them at the end of each plugin + file. See :help use-cpo-save for details. +

+

+ Plugins that depend on maktaba generally don't need to worry about + compatible mode since maktaba currently just disables it, printing a + warning. +

+ +
+
+ +

+ Revision 1.1 +

+ + +
+ Nate Soares
+ Joshua Hoak
+ David Barnett
+
+
diff --git a/vimscriptguide.xml b/vimscriptguide.xml new file mode 100644 index 000000000..2baf3fd61 --- /dev/null +++ b/vimscriptguide.xml @@ -0,0 +1,412 @@ + + + +

+ + Revision 1.1 +

+ + +
+ Nate Soares
+ Joshua Hoak
+ David Barnett
+
+ + + +

+ This is a casual version of the vimscript style guide, because + vimscript is a casual language. When submitting vim plugin code, you + must adhere to these rules. For clarifications, justifications, and + explanations about the finer points of vimscript, please refer to the + heavy guide. +

+
+
+ + +

+ It's hard to get vimscript right. Many commands depend upon the user's + settings. By following these guidelines, you can hope to make your + scripts portable. +

+ + Prefer single quoted strings + +

+ Double quoted strings are semantically different in vimscript, and + you probably don't want them (they break regexes). +

+

+ Use double quoted strings when you need an escape sequence (such as + "\n") or if you know it doesn't matter and you need to + embed single quotes. +

+ +
+ + + Use the =~# or =~? operator families over the + =~ family. + + +

+ The matching behavior depends upon the user's ignorecase and smartcase + settings and on whether you compare them with the =~, + =~#, or =~? family of operators. Use the + =~# and =~? operator families explicitly + when comparing strings unless you explicitly need to honor the user's + case sensitivity settings. +

+ +
+ + Prefix all regexes with \m\C. + +

+ In addition to the case sensitivity settings, regex behavior depends + upon the user's nomagic setting. To make regexes act like nomagic and + noignorecase are set, prepend all regexes with \m\C. +

+

+ You are welcome to use other magic levels (\v) and case + sensitivities (\c) so long as they are intentional and + explicit. +

+ +
+ + Avoid commands with unintended side effects. + +

+ Avoid using :s[ubstitute] as it moves the cursor and + prints error messages. Prefer functions (such as + search()) better suited to scripts. +

+

+ For many vim commands, functions exist that do the same thing with + fewer side effects. See :help functions() for a list of + built-in functions. +

+ +
+ + Avoid commands that rely on user settings. + +

+ Always use normal! instead of normal. The + latter depends upon the user's key mappings and could do anything. +

+

+ Avoid :s[ubstitute], as its behavior depends upon a + number of local settings. +

+

+ The same applies to other commands not listed here. +

+ +
+ + Match error codes, not error text. + +

Error text may be locale dependant.

+ +
+
+ + + + + + Message the user infrequently. + +

+ Loud scripts are annoying. Message the user only when: +

    +
  • A long-running process has kicked off.
  • +
  • An error has occurred.
  • +
+

+ +
+ + Use strict and explicit checks where possible. + +

+ Vimscript has unsafe, unintuitive behavior when dealing with some + types. For instance, 0 == 'foo' evaluates to true. +

+

+ Use strict comparison operators where possible. When comparing against + a string literal, use the is# operator. Otherwise, prefer + maktaba#value#IsEqual or check type() + explicitly. +

+

+ Check variable types explicitly before using them. Use functions from + maktaba#ensure, or check maktaba#value or + type() and throw your own errors. +

+

+ Use :unlet for variables that may change types, + particularly those assigned inside loops. +

+ +
+ + Use sparingly. + +

+ Use python only when it provides critical functionality, for example + when writing threaded code. +

+ +
+ + Use vimscript instead. + +

+ Avoid using other scripting languages such as ruby and lua. We can + not guarantee that the end user's vim has been compiled with support + for non-vimscript languages. +

+ +
+ + + Use maktaba. + + +

+ maktaba removes boilerplate, including: +

    +
  • Plugin creation
  • +
  • Error handling
  • +
  • Dependency checking
  • +
+

+ +
+ + Organize functionality into modular plugins + +

+ Group your functionality as a plugin, unified in one directory (or + code repository) which shares your plugin's name (with a "vim-" prefix + or ".vim" suffix if desired). It should be split into plugin/, + autoload/, etc. subdirectories as necessary, and it should declare + metadata in the addon-info.json format (see the + VAM documentation for details). +

+ +
+ + + In the autoload/ directory, defined with [!] and + [abort]. + + +

+ Autoloading allows functions to be loaded on demand, which makes + startuptime faster and enforces function namespacing. +

+

+ Script-local functions are welcome, but should also live in autoload/ + and be called by autoloaded functions. +

+

+ Non-library plugins should expose commands instead of functions. + Command logic should be extracted into functions and autoloaded. +

+

+ [!] allows developers to reload their functions + without complaint. +

+

+ [abort] forces the function to halt when it encounters + an error. +

+ +
+ + + In the plugin/commands.vim or under the ftplugin/ directory, defined + without [!]. + + +

+ General commands go in plugin/commands.vim. + Filetype-specific commands go in ftplugin/. +

+

+ Excluding [!] prevents your plugin from silently + clobbering existing commands. Command conflicts should be resolved by + the user. +

+ +
+ + + Place them in plugin/autocmds.vim, within augroups. + + +

+ Place all autocommands in augroups. +

+

+ The augroup name should be unique. It should either be, or be prefixed + with, the plugin name. +

+

+ Clear the augroup with autocmd! before defining new + autocommands in the augroup. This makes your plugin re-entrable. +

+ +
+ + + Place them in plugin/mappings.vim, using + maktaba#plugin#MapPrefix to get a prefix. + + +

+ All key mappings should be defined in + plugin/mappings.vim. +

+

+ Partial mappings (see :help using-<Plug>.) should be defined in + plugin/plugs.vim. +

+ +
+ + Change settings locally + +

+ Use :setlocal and &l: instead of + :set and & unless you have explicit + reason to do otherwise. +

+ +
+
+ + +

+ Follow google style conventions. When in doubt, treat vimscript style + like python style. +

+ + + + Similar to python. + +
+
+
+ +
    +
  • Use two spaces for indents
  • +
  • Do not use tabs
  • +
  • Use spaces around operators +

    This does not apply to arguments to commands.

    + + let s:variable = "concatenated " . "strings" + command -range=% MyCommand + +
  • +
  • Do not introduce trailing whitespace +

    You need not go out of your way to remove it.

    +

    + Trailing whitespace is allowed in mappings which prep commands + for user input, such as + "noremap <leader>gf :grep -f ". +

    +
  • +
  • Restrict lines to 80 columns wide
  • +
  • Indent continued lines by four spaces
  • +
  • Do not align arguments of commands + + command -bang MyCommand call myplugin#foo() + command MyCommand2 call myplugin#bar() + + + command -bang MyCommand call myplugin#foo() + command MyCommand2 call myplugin#bar() + +
  • +
+ +
+ + + +

+ In general, use + plugin-names-like-this, + FunctionNamesLikeThis, + CommandNamesLikeThis, + augroup_names_like_this, + variable_names_like_this. +

+

Always prefix variables with their scope.

+
+ + +

Keep them short and sweet.

+ +
+ +

Prefix script-local functions with s:

+

Autoloaded functions may not have a scope prefix.

+

+ Do not create global functions. Use autoloaded functions + instead. +

+
+ +

Prefer succinct command names over common command prefixes.

+
+ +

Augroup names count as variables for naming purposes.

+
+ +
    +
  • Global variables with g:
  • +
  • Script-local variables with s:
  • +
  • Function arguments with a:
  • +
  • Function-local variables with l:
  • +
  • Vim-predefined variables with v:
  • +
  • Buffer-local variables with b:
  • +
+

+ g:, s:, and a: must always + be used. +

+

+ b: changes the variable semantics; use it when you + want buffer-local semantics. +

+

+ l: and v: should be used for consistency, + future proofing, and to avoid subtle bugs. They are not strictly + required. Add them in new code but don’t go out of your way to add + them elsewhere. +

+
+ +
+
+ +

+ Revision 1.1 +

+ + +
+ Nate Soares
+ Joshua Hoak
+ David Barnett
+
+
diff --git a/xmlstyle.html b/xmlstyle.html new file mode 100644 index 000000000..7566f7e13 --- /dev/null +++ b/xmlstyle.html @@ -0,0 +1,681 @@ + + + + + +
+
+ +

+Google XML Document Format Style Guide

Version 1.0
Copyright Google 2008

Introduction

This document provides a set of guidelines for general use when designing new XML document formats (and to some extent XML documents as well; see Section 11).  Document formats usually include both formal parts (DTDs, schemas) and parts expressed in normative English prose.

These guidelines apply to new designs, and are not intended to force retroactive changes in existing designs.  When participating in the creation of public or private document format designs, the guidelines may be helpful but should not control the group consensus.

This guide is meant for the design of XML that is to be generated and consumed by machines rather than human beings.  Its rules are not applicable to formats such as XHTML (which should be formatted as much like HTML as possible) or ODF which are meant to express rich text.  A document that includes embedded content in XHTML or some other rich-text format, but also contains purely machine-interpretable portions, SHOULD follow this style guide for the machine-interpretable portions.  It also does not affect XML document formats that are created by translations from proto buffers or through some other type of format.

Brief rationales have been added to most of the guidelines.  They are maintained in the same document in hopes that they won't get out of date, but they are not considered normative.

The terms MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are used in this document in the sense of RFC 2119.
 

1. To design or not to design, that is the question

  1. Attempt to reuse existing XML formats whenever possible, especially those which allow extensions.  Creating an entirely new format should be done only with care and consideration; read Tim Bray's warnings first.  Try to get wide review of your format, from outside your organization as well, if possible.  [Rationale: New document formats have a cost: they must be reviewed, documented, and learned by users.]

  2. If you are reusing or extending an existing format, make sensible + +use of the prescribed elements and attributes, especially any that are +required.  Don't completely repurpose them, but do try to see how they +might be used in creative ways if the vanilla semantics aren't +suitable.  As a last resort when an element or attribute is required by the format but is not appropriate for your use case, use some +fixed string as its value.  [Rationale:  Markup reuse is good, markup abuse is bad.]

  3. When extending formats, use the implicit style of the existing format, even if it contradicts this guide.  [Rationale: Consistency.]

2. Schemas

  1. Document formats SHOULD be expressed using a schema language.  [Rationale: Clarity and machine-checkability.]

  2. The schema language SHOULD be RELAX NG compact syntax.  Embedded Schematron rules MAY be added to the schema for additional fine control.  [Rationale: + +RELAX NG is the most flexible schema language, with very few arbitrary +restrictions on designs.  The compact syntax is quite easy to read and +learn, and can be converted one-to-one to and from the XML syntax when +necessary.  Schematron handles arbitrary cross-element and +cross-attribute constraints nicely.]

  3. Schemas SHOULD use the "Salami Slice" style (one rule per element).  Schemas MAY use the "Russian Doll" style (schema resembles document) if they are short and simple.  The "Venetian Blind" style (one rule per element type) is unsuited to RELAX NG and SHOULD NOT be used.

  4. Regular expressions SHOULD be provided to assist in validating complex values.

  5. DTDs and/or W3C XML Schemas MAY be provided for compatibility with existing products, tools, or users.  [Rationale: We can't change the world all at once.]

3. Namespaces

  1. Element names MUST be in a namespace, except +when extending pre-existing document types that do not use namespaces.  + +A default namespace SHOULD be used.  [Rationale: Namespace-free +documents are obsolete; every set of names should be in some +namespace.  Using a default namespace improves readability.]

  2. Attribute +names SHOULD NOT be in a namespace unless they are drawn from a foreign +document type or are meant to be used in foreign document types.  [Rationale: Attribute names in a namespace must always have a prefix, which is annoying to type and hard to read.]

    +
  3. Namespace names are HTTP URIs.  Namespace names SHOULD take the form https://example.com/whatever/year, where whatever is a unique value based on the name of the document type, and year + +is the year the namespace was created.  There may be additional URI-path parts +before the year.  [Rationale: Existing convention.  Providing the year allows for the possible recycling of code names.]

  4. Namespaces MUST NOT be changed unless the semantics of particular elements or attributes has changed in drastically incompatible ways.  [Rationale: Changing the namespace requires changing all client code.]

  5. Namespace prefixes SHOULD be short (but not so short that they are likely to be conflict with another project).  Single-letter prefixes MUST NOT be used. Prefixes SHOULD contain only lower-case ASCII letters.  [Rationale: Ease of typing and absence of encoding compatibility problems.]

+ +

4. Names and enumerated values

Note: "Names" refers to the names of elements, attributes, and enumerated values.

  1. All names MUST use lowerCamelCase. That is, they start with an initial lower-case letter, then each new word within the name starts with an initial capital letter. [Rationale: Adopting a single style provides consistency, which helps when referring to names since the capitalization is known and so does not have to be remembered.  It matches Java style, and other languages can be dealt with using automated name conversion.]

  2. Names MUST contain only ASCII letters and digits.  +[Rationale: Ease of typing and absence of encoding compatibility problems.]

  3. Names SHOULD NOT exceed 25 characters. Longer names SHOULD be +avoided by devising concise and informative names.  If a name can only remain within this limit by becoming obscure, the limit SHOULD be ignored.  [Rationale: Longer names are awkward to use and require additional bandwidth.]

  4. Published standard abbreviations, if sufficiently well-known, MAY be employed in constructing names. Ad hoc abbreviations MUST NOT be used.  Acronyms MUST be treated as words for camel-casing purposes: informationUri, not informationURI. [Rationale:  An abbreviation that is well known +to one community is often incomprehensible to others who need to use +the same document format (and who do understand the full name); treating an acronym as a word makes it easier to see where the word boundaries are.]


+ +

+5. Elements

  1. All elements MUST contain either nothing, character content, or child elements.  Mixed content MUST NOT be used.  [Rationale: Many XML data models don't handle mixed content properly, and its use makes the element order-dependent.  As always, textual formats are not covered by this rule.]

  2. XML elements that merely wrap repeating child elements SHOULD NOT be used.  [Rationale: They are not used in Atom and add nothing.]
+ +


6. Attributes

  1. Document formats MUST NOT depend on the order of attributes in a start-tag.  [Rationale: Few XML parsers report the order, and it is not part of the XML Infoset.]

  2. Elements SHOULD NOT be overloaded with too many attributes (no more +than 10 as a rule of thumb).  Instead, use child elements to +encapsulate closely related attributes.  [Rationale: This +approach maintains the built-in extensibility that XML provides with +elements, and is useful for providing forward compatibility as a +specification evolves.]

  3. Attributes MUST NOT be used to hold values in which line breaks are significant.  [Rationale: Such line breaks are converted to spaces by conformant XML parsers.]

  4. Document formats MUST allow either single or double quotation marks around attribute values.  [Rationale:  XML parsers don't report the difference.]
+ +


+

+

+7. Values

  1. Numeric values SHOULD be 32-bit signed integers, 64-bit signed integers, or 64-bit IEEE doubles, all expressed in base 10.  These correspond to the XML Schema types xsd:int, xsd:long, and xsd:double respectively.  If required in particular cases, xsd:integer (unlimited-precision integer) values MAY also be used.  [Rationale: There are far too many numeric types in XML Schema: these provide a reasonable subset.] 

  2. + +Boolean values SHOULD NOT be used (use enumerations instead).  If they must be used, they MUST be expressed as true or false, corresponding to a subset of the XML Schema type xsd:boolean.  The alternative xsd:boolean values 1 and 0 MUST NOT be used.  [Rationale: Boolean arguments are not extensible.  The additional flexibility of allowing numeric values is not abstracted away by any parser.]

  3. Dates should be represented using RFC 3339 format, a subset of both +ISO 8601 format and XML Schema xsd:dateTime format.  UTC times SHOULD be used rather than local times.  + +[Rationale: There are far too many date formats and time zones, although it is recognized that sometimes local time preserves important information.]

  4. Embedded syntax in character content and attribute values SHOULD NOT be +used.  Syntax in values means XML tools are largely useless.  Syntaxes such as  dates, URIs, and +XPath expressions are exceptions.  [Rationale:  +Users should be able to process XML documents using only an XML parser +without requiring additional special-purpose parsers, which are easy to +get wrong.]

  5. Be careful with whitespace in values.  XML parsers don't strip whitespace in elements, but do convert newlines to spaces in attributes.  However, application frameworks may do more aggressive whitespace stripping.  Your document format SHOULD give rules for whitespace stripping.
+ +


+

+

+

8. Key-value pairs

  1. +Simple key-value pairs SHOULD be represented with an empty element whose name represents the key, with the value attribute containing the value. Elements that have a value attribute MAY also have a unit attribute to specify the unit of a measured value.  For physical measurements, the SI system SHOULD be used.  [Rationale: + +Simplicity and design consistency.  Keeping the value in an attribute +hides it from the user, since displaying just the value without the key is not useful.]

  2. If the number of possible keys is very large or unbounded, key-value pairs MAY be represented by a single generic element with key, value, and optional unit and scheme +attributes (which serve to discriminate keys from different domains).  +In that case, also provide (not necessarily in the same document) a +list of keys with human-readable explanations.

9. Binary data

Note: There are no hard and fast rules about whether binary data should be included as part of an XML document or not.  If it's too large, it's probably better to link to it.


  1. Binary data MUST NOT be included directly as-is in XML documents, but MUST be encoded using Base64 encoding.  [Rationale: XML does not allow arbitrary binary bytes.]

  2. + +The line breaks required by Base64 MAY be omitted.  [Rationale: The line breaks are meant to keep plain text lines short, but XML is not really plain text.]

  3. An attribute named xsi:type with value xs:base64Binary MAY be attached to this element to signal that the Base64 format is in use.  [Rationale: Opaque blobs should have decoding instructions attached.]

+

10. Processing instructions

  1. New processing instructions MUST NOT be created except in order to specify purely local processing conventions, and SHOULD be avoided altogether.  Existing standardized processing instructions MAY be used.  [Rationale: Processing instructions fit awkwardly into XML data models and can always be replaced by elements; they exist primarily to avoid breaking backward compatibility.]

 

+ +

+

 

11. Representation of XML document instances

Note:  These points are only guidelines, as the format of program-created instances will often be outside the programmer's control (for example, when an XML serialization library is being used).  In no case should XML parsers rely on these guidelines being followed.  Use standard XML parsers, not hand-rolled hacks.


  1. The character encoding used SHOULD be UTF-8.  Exceptions should require extremely compelling circumstances.  [Rationale: UTF-8 is universal and in common use.]

  2. Namespaces SHOULD be declared in the root element of a document wherever possible.  [Rationale: Clarity and consistency.]

  3. The mapping of namespace URIs to prefixes SHOULD remain constant throughout the document, and SHOULD also be used in documentation of the design.  [Rationale: Clarity and consistency.]

  4. Well-known prefixes such as html: (for XHTML), dc: (for Dublin Core metadata), and xs: (for XML Schema) should be used for standard namespaces.  [Rationale: Human readability.]

  5. Redundant whitespace in a tag SHOULD NOT be +used.  Use one space before each attribute in a start-tag; if the start +tag is too long, the space MAY be replaced by a newline.  [Rationale: Consistency and conciseness.]

  6. Empty elements MAY be expressed as empty tags or a start-tag +immediately followed by an end-tag. No distinction should be made +between these two formats by any application.  [Rationale: They are not distinguished by XML parsers.]

  7. Documents MAY be pretty-printed using 2-space indentation for child +elements.  Elements that contain character content SHOULD NOT be +wrapped.  Long start-tags MAY be broken using newlines (possibly with extra indentation) after any attribute value except the last.  [Rationale: General compatibility with our style.  Wrapping character content affects its value.]

  8. Attribute values MAY be surrounded with either quotation marks or apostrophes. +Specifications MUST NOT require or forbid the use of either form.  &apos; and &quot; may be freely used to escape each type of quote.  [Rationale: No XML parsers report the distinction.]

    + +
  9. Comments MUST NOT be used to carry real data.  Comments MAY be used to contain TODOs in hand-written XML.  Comments SHOULD NOT be used at all in publicly transmitted documents. [Rationale:  Comments are often discarded by parsers.]

  10. If comments are nevertheless used, they SHOULD appear only in the document prolog or in elements that +contain child elements.  If pretty-printing is required, pretty-print +comments like elements, but with line wrapping.  Comments SHOULD NOT +appear in elements that contain character content.  [Rationale:  Whitespace in and around comments improves readability, but embedding a +comment in character content can lead to confusion about what +whitespace is or is not in the content.]

  11. Comments SHOULD have whitespace following <!-- and preceding -->.  [Rationale: Readability.]

  12. CDATA sections MAY be used; they are equivalent to the use of &amp; and &lt;.  Specifications MUST NOT require or forbid the use of CDATA sections.  [Rationale: Few XML parsers report the distinction, and combinations of CDATA and text are often reported as single objects anyway.]

  13. Entity references other than the XML standard entity references &amp;, &lt;, &gt;, &quot;, and &apos; MUST NOT be used.  Character references MAY be used, but actual characters are preferred, unless the character encoding is not UTF-8.  As usual, textual formats are exempt from this rule.
+ +

 

+

+

+



+12. Elements vs. Attributes +

+

+Note:  There are no hard and fast rules for deciding when to use attributes and when to use elements.  Here are some of the considerations that designers should take into account; no rationales are given. +

+

+12.1. General points:
+

+ +
    +
  1. +

    +Attributes are more restrictive than elements, and all designs have some elements, so an all-element design is simplest -- which is not the same as best. +

    +

    +
    +

    +
  2. +
  3. +

    +In a tree-style data model, elements are typically represented internally as nodes, which use more memory than the strings used to represent attributes.  Sometimes the nodes are of different application-specific classes, which in many languages also takes up memory to represent the classes. +

    +

    +
    + +

    +
  4. +
  5. +

    +When streaming, elements are processed one at a time (possibly even piece by piece, depending on the XML parser you are using), whereas all the attributes of an element and their values are reported at once, which costs memory, particularly if some attribute values are very long. +

    +

    +
    +

    +
  6. +
  7. +

    +Both element content and attribute values need to be escaped appropriately, so escaping should not be a consideration in the design. +

    +

    +
    +

    + +
  8. +
  9. +

    +In some programming languages and libraries, processing elements is easier; in others, processing attributes is easier.  Beware of using ease of processing as a criterion.  In particular, XSLT can handle either with equal facility. +

    +

    +
    +

    +
  10. +
  11. +

    +If a piece of data should usually be shown to the user, consider using an element; if not, consider using an attribute.  (This rule is often violated for one reason or another.) + +

    +

    +
    +

    +
  12. +
  13. +

    +If you are extending an existing schema, do things by analogy to how things are done in that schema. +

    +

    +
    +

    +
  14. +
  15. +

    +Sensible schema languages, meaning RELAX NG and Schematron, treat elements and attributes symmetrically.  Older and cruder schema languages such as DTDs and XML Schema, tend to have better support for elements. + +

    +
  16. +
+

+

+

+12.2 Using elements
+

+
    +
  1. +

    +If something might appear more than once in a data model, use an element rather than introducing attributes with names like foo1, foo2, foo3 .... +

    + +

    +
    +

    +
  2. +
  3. +

    +Use elements to represent a piece of information that can be considered an independent object and when the information is related via a parent/child relationship to another piece of information. +

    +

    +
    +

    +
  4. +
  5. +

    +Use elements when data incorporates strict typing or relationship rules. +

    +

    + +
    +

    +
  6. +
  7. +

    +If order matters between two pieces of data, use elements for them: attributes are inherently unordered. +

    +

    +
    +

    +
  8. +
  9. +

    +If a piece of data has, or might have, its own substructure, use it in an element: getting substructure into an attribute is always messy.  Similarly, if the data is a constituent part of some larger piece of data, put it in an element. +

    + +

    +
    +

    +
  10. +
  11. +

    +An exception to the previous rule: multiple whitespace-separated tokens can safely be put in an attribute.  In principle, the separator can be anything, but schema-language validators are currently only able to handle whitespace, so it's best to stick with that. +

    +

    +
    +

    +
  12. +
  13. +

    +If a piece of data extends across multiple lines, use an element: XML parsers will change newlines in attribute values into spaces. + +

  14. If a piece of data is very large, use an element so that its content can be streamed.

  15. +
  16. +

    +If a piece of data is in a natural language, put it in an element so you can use the xml:lang attribute to label the language being used.  Some kinds of natural-language text, like Japanese, often make use annotations that are conventionally represented using child elements; right-to-left languages like Hebrew and Arabic may similarly require child elements to manage bidirectionality properly. +

    + +

    +

    +
  17. +
+

+12.3 Using attributes
+

+
    +
  1. +

    +If the data is a code from an enumeration, code list, or controlled vocabulary, put it in an attribute if possible.  For example, language tags, currency codes, medical diagnostic codes, etc. are best handled as attributes. +

    +

    +
    + +

    +
  2. +
  3. +

    +If a piece of data is really metadata on some other piece of data (for example, representing a class or role that the main data serves,  or specifying a method of processing it), put it in an attribute if possible. +

    +

    +
    +

    +
  4. +
  5. +

    +In particular, if a piece of data is an ID for some other piece of data, or a reference to such an ID, put the identifying piece in an attribute.  When it's an ID, use the name xml:id for the attribute. + +

    +

    +
    +

    +
  6. +
  7. +

    +Hypertext references are conventionally put in href attributes. +

    +

    +
    +

    +
  8. +
  9. + +

    +If a piece of data is applicable to an element and any descendant elements unless it is overridden in some of them, it is conventional to put it in an attribute.  Well-known examples are xml:lang, xml:space, xml:base, and namespace declarations. +

    +

    +
    +

    +
  10. +
  11. +

    + +If terseness is really the most important thing, use attributes, but consider gzip compression instead -- it works very well on documents with highly repetitive structures.

  12. +

+

13. Parting words +

+

+

+Use common sense and BE CONSISTENT.   Design for extensibility.  You are gonna need it.  [Rationale: Long and painful experience.]


+ +

+When designing XML formats, take a few minutes to look at other formats and determine their style.  The point of having style guidelines is so that people can concentrate on what you are +saying, rather than on how you are saying it.

+
+Break ANY OR ALL of these rules (yes, even the ones that say MUST) rather than create a crude, arbitrary, disgusting mess of a design if that's what following them slavishly would give you.  In particular, random mixtures of attributes and child elements are hard to follow and hard to use, though it often makes good sense to use both when the data clearly fall into two different groups such as simple/complex or metadata/data. +

+

+
+Newbies always ask: +

+ +

+    "Elements or attributes? +

+

+Which will serve me best?" +

+

+    Those who know roar like lions; +

+

+    Wise hackers smile like tigers. +

+

+                    --a tanka, or extended haiku + +

+
+

+
+

+
[TODO: if a registry of schemas is set up, add a link to it]




+
+