libv8 5.0.71.48.3 → 5.1.281.59.0beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/ext/libv8/location.rb +12 -9
  4. data/ext/libv8/patcher.rb +1 -1
  5. data/ext/libv8/paths.rb +1 -1
  6. data/lib/libv8/version.rb +1 -1
  7. data/patches/0001-Build-standalone-static-library.patch +26 -0
  8. data/patches/{disable-building-tests.patch → 0002-Disable-building-tests.patch} +17 -5
  9. data/patches/0003-Use-the-fPIC-flag-for-the-static-library.patch +25 -0
  10. data/spec/location_spec.rb +1 -1
  11. data/vendor/depot_tools/.gitignore +1 -0
  12. data/vendor/depot_tools/PRESUBMIT.py +3 -1
  13. data/vendor/depot_tools/README +1 -6
  14. data/vendor/depot_tools/apply_issue.py +6 -0
  15. data/vendor/depot_tools/bootstrap/win/README.md +2 -2
  16. data/vendor/depot_tools/bootstrap/win/git.template.bat +1 -1
  17. data/vendor/depot_tools/bootstrap/win/win_tools.bat +12 -11
  18. data/vendor/depot_tools/codereview.settings +1 -1
  19. data/vendor/depot_tools/cpplint.py +353 -592
  20. data/vendor/depot_tools/fetch.py +10 -3
  21. data/vendor/depot_tools/fetch_configs/infra.py +4 -2
  22. data/vendor/depot_tools/fetch_configs/ios_internal.py +49 -0
  23. data/vendor/depot_tools/gclient.py +33 -7
  24. data/vendor/depot_tools/gclient_scm.py +14 -11
  25. data/vendor/depot_tools/gclient_utils.py +14 -3
  26. data/vendor/depot_tools/git-gs +3 -3
  27. data/vendor/depot_tools/git_cache.py +8 -4
  28. data/vendor/depot_tools/git_cl.py +221 -98
  29. data/vendor/depot_tools/git_footers.py +76 -39
  30. data/vendor/depot_tools/git_map_branches.py +12 -10
  31. data/vendor/depot_tools/infra/config/cq.cfg +0 -11
  32. data/vendor/depot_tools/infra/config/recipes.cfg +1 -1
  33. data/vendor/depot_tools/presubmit_canned_checks.py +31 -19
  34. data/vendor/depot_tools/presubmit_support.py +0 -13
  35. data/vendor/depot_tools/recipe_modules/bot_update/resources/bot_update.py +19 -2
  36. data/vendor/depot_tools/recipe_modules/depot_tools/api.py +4 -0
  37. data/vendor/depot_tools/recipe_modules/depot_tools/example.expected/basic.json +49 -0
  38. data/vendor/depot_tools/recipe_modules/depot_tools/example.expected/win.json +49 -0
  39. data/vendor/depot_tools/recipe_modules/depot_tools/example.py +38 -0
  40. data/vendor/depot_tools/recipe_modules/gclient/api.py +1 -0
  41. data/vendor/depot_tools/recipe_modules/gclient/config.py +19 -0
  42. data/vendor/depot_tools/recipe_modules/gclient/example.expected/basic.json +1 -0
  43. data/vendor/depot_tools/recipe_modules/gclient/example.expected/revision.json +1 -0
  44. data/vendor/depot_tools/recipe_modules/gclient/example.expected/tryserver.json +1 -0
  45. data/vendor/depot_tools/recipe_modules/gclient/example.py +3 -0
  46. data/vendor/depot_tools/recipe_modules/git_cl/api.py +22 -6
  47. data/vendor/depot_tools/recipe_modules/git_cl/example.expected/basic.json +27 -9
  48. data/vendor/depot_tools/recipe_modules/git_cl/example.py +9 -7
  49. data/vendor/depot_tools/recipe_modules/presubmit/api.py +5 -2
  50. data/vendor/depot_tools/recipe_modules/tryserver/__init__.py +1 -0
  51. data/vendor/depot_tools/recipe_modules/tryserver/api.py +31 -0
  52. data/vendor/depot_tools/recipe_modules/tryserver/example.expected/basic_tags.json +59 -0
  53. data/vendor/depot_tools/recipe_modules/tryserver/example.expected/with_rietveld_patch.json +26 -0
  54. data/vendor/depot_tools/recipe_modules/tryserver/example.expected/with_rietveld_patch_new.json +26 -0
  55. data/vendor/depot_tools/recipe_modules/tryserver/example.py +32 -3
  56. data/vendor/depot_tools/roll_dep.py +6 -2
  57. data/vendor/depot_tools/third_party/upload.py +17 -9
  58. data/vendor/depot_tools/update_depot_tools +11 -0
  59. data/vendor/depot_tools/update_depot_tools.bat +11 -0
  60. data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +52 -9
  61. data/vendor/depot_tools/win_toolchain/package_from_installed.py +64 -57
  62. metadata +12 -10
  63. data/patches/build-standalone-static-library.patch +0 -14
  64. data/patches/fPIC-for-static.patch +0 -13
  65. data/vendor/depot_tools/git-lkgr +0 -208
  66. data/vendor/depot_tools/hammer +0 -28
  67. data/vendor/depot_tools/hammer.bat +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0556cfcdb9a5a566c15fd47b0b74a1d20881606
4
- data.tar.gz: 5cc39182c89e7f0e7185227b3861f7f3c71d19fb
3
+ metadata.gz: 41cbaf11fa4edba84e871c58099ed8243019b2b1
4
+ data.tar.gz: 958c801dae727821359a0004ebac3b35b654e527
5
5
  SHA512:
6
- metadata.gz: 786c7ce66fd644d92104dceacf45421898bf1f26802e79bb0775ec3b4ce0f0f64f9a76ee7e8d7460decf359bc9dd8774646cb6b579a82d60f1760d5c21e975c4
7
- data.tar.gz: 7ea6c6a4013e5239bbfdd902c1c805c68608017cd41d47f0e018385a1e21eb17cab88986bc2640ef5fa032654f3283d859a538c150cd93d537f55481b9fec60b
6
+ metadata.gz: 3ee57388f66c9f06452560879ab5bc7fec7fb58a76a36eebf36d18de8f25dcd54b0c1eec391dbfb50d1cae63a7bc898a7fc91121bd704a6bd341499d2c72a48f
7
+ data.tar.gz: 3837b26a28511330199c8f31e1296ff6d1eab8bd018415b606e53cb9e1978e7eec059ef932f10600a4514cb5937f0e2efcff4a75887bd2e848768b46bc03f854
@@ -1,5 +1,9 @@
1
1
  ### Unreleased
2
2
 
3
+ ### 5.0.71.48.4, 5.0.71.48.5 - 2016-05-13:
4
+
5
+ * Enable the -fPIC flag for ARM
6
+
3
7
  ### 5.0.71.48.2, 5.0.71.48.3 - 2016-05-13:
4
8
 
5
9
  * Upgrade upstream v8 version to 5.0.71.45
@@ -26,21 +26,24 @@ module Libv8
26
26
  verify_installation!
27
27
  return exit_status
28
28
  end
29
+
29
30
  def configure(context = MkmfContext.new)
30
- context.incflags.insert 0, Libv8::Paths.include_paths.map{|p| "-I#{p}"}.join(" ") + " "
31
+ context.incflags.insert 0, Libv8::Paths.include_paths.map{ |p| "-I#{p}" }.join(" ") + " "
31
32
  context.ldflags.insert 0, Libv8::Paths.object_paths.join(" ") + " "
32
33
  end
33
34
 
34
35
  def verify_installation!
35
36
  include_paths = Libv8::Paths.include_paths
36
- unless include_paths.detect { |p| Pathname(p).join('include/v8.h').exist? }
37
- fail HeaderNotFound, "Unable to locate 'include/v8.h' in the libv8 header paths: #{include_paths.inspect}"
37
+ unless include_paths.detect { |p| Pathname(p).join('v8.h').exist? }
38
+ fail HeaderNotFound, "Unable to locate 'v8.h' in the libv8 header paths: #{include_paths.inspect}"
38
39
  end
39
40
  Libv8::Paths.object_paths.each do |p|
40
41
  fail ArchiveNotFound, p unless File.exist? p
41
42
  end
42
43
  end
44
+
43
45
  class HeaderNotFound < StandardError; end
46
+
44
47
  class ArchiveNotFound < StandardError
45
48
  def initialize(filename)
46
49
  super "libv8 did not install properly, expected binary v8 archive '#{filename}'to exist, but it was not found"
@@ -59,14 +62,14 @@ module Libv8
59
62
  class NotFoundError < StandardError
60
63
  def initialize(*args)
61
64
  super(<<-EOS)
62
- By using --with-system-v8, you have chosen to use the version
63
- of V8 found on your system and *not* the one that is bundled with
64
- the libv8 rubygem.
65
+ By using --with-system-v8, you have chosen to use the version
66
+ of V8 found on your system and *not* the one that is bundled with
67
+ the libv8 rubygem.
65
68
 
66
- However, your system version of v8 could not be located.
69
+ However, your system version of v8 could not be located.
67
70
 
68
- Please make sure your system version of v8 that is compatible
69
- with #{Libv8::VERSION} installed. You may need to use the
71
+ Please make sure your system version of v8 that is compatible
72
+ with #{Libv8::VERSION} installed. You may need to use the
70
73
  --with-v8-dir option if it is installed in a non-standard location
71
74
  EOS
72
75
  end
@@ -6,7 +6,7 @@ module Libv8
6
6
 
7
7
  def patch!
8
8
  File.open(".applied_patches", File::RDWR|File::CREAT) do |f|
9
- available_patches = Dir.glob(File.join(PATCH_DIRECTORY, '*.patch'))
9
+ available_patches = Dir.glob(File.join(PATCH_DIRECTORY, '*.patch')).sort
10
10
  applied_patches = f.readlines.map(&:chomp)
11
11
 
12
12
  (available_patches - applied_patches).each do |patch|
@@ -7,7 +7,7 @@ module Libv8
7
7
  module_function
8
8
 
9
9
  def include_paths
10
- [Shellwords.escape(vendored_source_path)]
10
+ [Shellwords.escape(File.join(vendored_source_path, 'include'))]
11
11
  end
12
12
 
13
13
  def object_paths
@@ -1,3 +1,3 @@
1
1
  module Libv8
2
- VERSION = "5.0.71.48.3"
2
+ VERSION = "5.1.281.59.0beta3"
3
3
  end
@@ -0,0 +1,26 @@
1
+ From 91326a79ff71b9f856585bf8dfdc112527801e68 Mon Sep 17 00:00:00 2001
2
+ From: Petko Bordjukov <bordjukov@gmail.com>
3
+ Date: Fri, 10 Jun 2016 08:51:08 +0300
4
+ Subject: [PATCH 1/3] Build standalone static library
5
+
6
+ ---
7
+ build/standalone.gypi | 3 +++
8
+ 1 file changed, 3 insertions(+)
9
+
10
+ diff --git a/build/standalone.gypi b/build/standalone.gypi
11
+ index 6c88409..4f10909 100644
12
+ --- a/build/standalone.gypi
13
+ +++ b/build/standalone.gypi
14
+ @@ -471,6 +471,9 @@
15
+ }], # fastbuild!=0
16
+ ],
17
+ 'target_conditions': [
18
+ + ['_type=="static_library"', {
19
+ + 'standalone_static_library': 1,
20
+ + }],
21
+ ['v8_code == 0', {
22
+ 'defines!': [
23
+ 'DEBUG',
24
+ --
25
+ 2.8.3
26
+
@@ -1,18 +1,27 @@
1
+ From a27a92cbe9db50bceedfffeb43d12345209e4d75 Mon Sep 17 00:00:00 2001
2
+ From: Petko Bordjukov <bordjukov@gmail.com>
3
+ Date: Fri, 10 Jun 2016 08:57:29 +0300
4
+ Subject: [PATCH 2/3] Disable building tests
5
+
6
+ ---
7
+ Makefile | 6 ++----
8
+ build/all.gyp | 27 ---------------------------
9
+ 2 files changed, 2 insertions(+), 31 deletions(-)
10
+
1
11
  diff --git a/Makefile b/Makefile
2
- index 4fb6ee0..549ae58 100644
12
+ index a0c08a6..10b2924 100644
3
13
  --- a/Makefile
4
14
  +++ b/Makefile
5
- @@ -251,11 +251,9 @@ NACL_ARCHES = nacl_ia32 nacl_x64
15
+ @@ -258,11 +258,9 @@ NACL_ARCHES = nacl_ia32 nacl_x64
6
16
  GYPFILES = third_party/icu/icu.gypi third_party/icu/icu.gyp \
7
17
  build/shim_headers.gypi build/features.gypi build/standalone.gypi \
8
18
  build/toolchain.gypi build/all.gyp build/mac/asan.gyp \
9
19
  - test/cctest/cctest.gyp test/fuzzer/fuzzer.gyp \
10
20
  - test/unittests/unittests.gyp tools/gyp/v8.gyp \
11
21
  - tools/parser-shell.gyp testing/gmock.gyp testing/gtest.gyp \
12
- - buildtools/third_party/libc++abi/libc++abi.gyp \
13
- - buildtools/third_party/libc++/libc++.gyp samples/samples.gyp \
14
22
  + tools/gyp/v8.gyp tools/parser-shell.gyp \
15
- + buildtools/third_party/libc++abi/libc++abi.gyp \
23
+ buildtools/third_party/libc++abi/libc++abi.gyp \
24
+ - buildtools/third_party/libc++/libc++.gyp samples/samples.gyp \
16
25
  + buildtools/third_party/libc++/libc++.gyp \
17
26
  src/third_party/vtune/v8vtune.gyp src/d8.gyp
18
27
 
@@ -63,3 +72,6 @@ index feaf4fe..96820a0 100644
63
72
  ]
64
73
  }
65
74
  ]
75
+ --
76
+ 2.8.3
77
+
@@ -0,0 +1,25 @@
1
+ From 8c92844ee381fc2074204dd52ca3668e3c6fe89f Mon Sep 17 00:00:00 2001
2
+ From: Petko Bordjukov <bordjukov@gmail.com>
3
+ Date: Fri, 10 Jun 2016 08:58:29 +0300
4
+ Subject: [PATCH 3/3] Use the -fPIC flag for the static library
5
+
6
+ ---
7
+ build/standalone.gypi | 2 +-
8
+ 1 file changed, 1 insertion(+), 1 deletion(-)
9
+
10
+ diff --git a/build/standalone.gypi b/build/standalone.gypi
11
+ index 4f10909..3a67af3 100644
12
+ --- a/build/standalone.gypi
13
+ +++ b/build/standalone.gypi
14
+ @@ -728,7 +728,7 @@
15
+ [ 'visibility=="hidden" and v8_enable_backtrace==0', {
16
+ 'cflags': [ '-fvisibility=hidden' ],
17
+ }],
18
+ - [ 'component=="shared_library"', {
19
+ + [ 'component=="shared_library" or component=="static_library" and (v8_target_arch=="x64" or v8_target_arch=="arm64" or v8_target_arch=="arm")', {
20
+ 'cflags': [ '-fPIC', ],
21
+ }],
22
+ [ 'clang==0 and coverage==1', {
23
+ --
24
+ 2.8.3
25
+
@@ -60,7 +60,7 @@ describe "libv8 locations" do
60
60
  end
61
61
 
62
62
  it "prepends its own incflags before any pre-existing ones" do
63
- expect(@context.incflags).to eql "-I/foo\\ bar/v8 -I/usr/include -I/usr/local/include"
63
+ expect(@context.incflags).to eql "-I/foo\\ bar/v8/include -I/usr/include -I/usr/local/include"
64
64
  end
65
65
 
66
66
  it "prepends the locations of any libv8 objects on the the ldflags" do
@@ -43,6 +43,7 @@
43
43
  /tags
44
44
 
45
45
  # Ignore unittest related files.
46
+ /testing_support/_infra
46
47
  /testing_support/_rietveld
47
48
  /tests/git-svn-submodule/
48
49
  /tests/subversion_config/README.txt
@@ -25,7 +25,9 @@ def CommonChecks(input_api, output_api, tests_to_black_list):
25
25
  r'^recipes\.py$',
26
26
  r'^site-packages-py[0-9]\.[0-9][\/\\].+',
27
27
  r'^svn_bin[\/\\].+',
28
- r'^testing_support[\/\\]_rietveld[\/\\].+']
28
+ r'^testing_support[\/\\]_rietveld[\/\\].+',
29
+ r'^testing_support[\/\\]_infra[\/\\].+',
30
+ ]
29
31
  if os.path.exists('.gitignore'):
30
32
  with open('.gitignore') as fh:
31
33
  lines = [l.strip() for l in fh.readlines()]
@@ -3,7 +3,7 @@ This package contains tools for working with Chromium development.
3
3
  The "gclient" wrapper knows how to keep this repository updated to
4
4
  the latest versions of these tools as found at:
5
5
 
6
- http://src.chromium.org/svn/trunk/tools/depot_tools
6
+ https://chromium.googlesource.com/chromium/tools/depot_tools/+/master/gclient.py
7
7
 
8
8
  This package contains:
9
9
 
@@ -25,11 +25,6 @@ This package contains:
25
25
  More info at:
26
26
  http://code.google.com/p/gclient/
27
27
 
28
- hammer
29
- A wrapper script for building Chromium with the SCons software
30
- construction tool. More info at:
31
- http://www.scons.org/
32
-
33
28
  Note: svn and python will be installed automatically if not accessible (on
34
29
  Windows only).
35
30
 
@@ -92,6 +92,10 @@ def _get_arg_parser():
92
92
  help='Don\'t patch specified file(s).')
93
93
  parser.add_option('-d', '--ignore_deps', action='store_true',
94
94
  help='Don\'t run gclient sync on DEPS changes.')
95
+ parser.add_option('--extra_patchlevel', type='int',
96
+ help='Number of directories the patch level number should '
97
+ 'be incremented (useful for patches from repos with '
98
+ 'different directory hierarchies).')
95
99
 
96
100
  auth.add_auth_options(parser)
97
101
  return parser
@@ -255,6 +259,8 @@ def main():
255
259
  if patch.filename not in options.blacklist]
256
260
  for patch in patchset.patches:
257
261
  print(patch)
262
+ if options.extra_patchlevel:
263
+ patch.patchlevel += options.extra_patchlevel
258
264
  full_dir = os.path.abspath(options.root_dir)
259
265
  scm_type = scm.determine_scm(full_dir)
260
266
  if scm_type == 'svn':
@@ -53,14 +53,14 @@ than the rest of this README.
53
53
 
54
54
  ### Python
55
55
 
56
- Python installs are sourced from https://src.chromium.org/viewvc/chrome/trunk/tools/ .
56
+ Python installs are sourced from gs://chrome-infra/python276_bin.zip .
57
57
 
58
58
  The process to create them is sort-of-documented in the README of the python
59
59
  zip file.
60
60
 
61
61
  ### Subversion
62
62
 
63
- Subversion installs are sourced from https://src.chromium.org/viewvc/chrome/trunk/tools/ .
63
+ Subversion installs are sourced from gs://chrome-infra/svn_bin.zip .
64
64
 
65
65
  There will likely never be an update to SVN in `depot_tools` from the current
66
66
  version.
@@ -1,5 +1,5 @@
1
1
  @echo off
2
2
  setlocal
3
3
  if not defined EDITOR set EDITOR=notepad
4
- set PATH=%~dp0GIT_BIN_DIR\cmd;%PATH%
4
+ set PATH=%~dp0GIT_BIN_DIR\cmd;%~dp0;%PATH%
5
5
  "%~dp0GIT_BIN_DIR\GIT_PROGRAM" %*
@@ -9,7 +9,7 @@
9
9
  :: Sadly, we can't use SETLOCAL here otherwise it ERRORLEVEL is not correctly
10
10
  :: returned.
11
11
 
12
- set WIN_TOOLS_ROOT_URL=https://src.chromium.org/svn/trunk/tools
12
+ set CHROME_INFRA_URL=https://storage.googleapis.com/chrome-infra/
13
13
  :: It used to be %~dp0 but ADODB.Stream may fail to write to this directory if
14
14
  :: the directory DACL is set to elevated integrity level.
15
15
  set ZIP_DIR=%TEMP%
@@ -35,10 +35,11 @@ goto :GIT_CHECK
35
35
  :PY27_INSTALL
36
36
  echo Installing python 2.7.6...
37
37
  :: Cleanup python directory if it was existing.
38
+ set PYTHON_URL=%CHROME_INFRA_URL%python276_bin.zip
38
39
  if exist "%WIN_TOOLS_ROOT_DIR%\python276_bin\." rd /q /s "%WIN_TOOLS_ROOT_DIR%\python276_bin"
39
40
  if exist "%ZIP_DIR%\python276.zip" del "%ZIP_DIR%\python276.zip"
40
- echo Fetching from %WIN_TOOLS_ROOT_URL%/third_party/python276_bin.zip
41
- cscript //nologo //e:jscript "%~dp0get_file.js" %WIN_TOOLS_ROOT_URL%/third_party/python276_bin.zip "%ZIP_DIR%\python276_bin.zip"
41
+ echo Fetching from %PYTHON_URL%
42
+ cscript //nologo //e:jscript "%~dp0get_file.js" %PYTHON_URL% "%ZIP_DIR%\python276_bin.zip"
42
43
  if errorlevel 1 goto :PYTHON_FAIL
43
44
  :: Will create python276_bin\...
44
45
  cscript //nologo //e:jscript "%~dp0unzip.js" "%ZIP_DIR%\python276_bin.zip" "%WIN_TOOLS_ROOT_DIR%"
@@ -52,7 +53,7 @@ goto :GIT_CHECK
52
53
 
53
54
  :PYTHON_FAIL
54
55
  echo ... Failed to checkout python automatically.
55
- echo You should get the "prebaked" version at %WIN_TOOLS_ROOT_URL%/third_party/
56
+ echo You should get the "prebaked" version at %PYTHON_URL%
56
57
  set ERRORLEVEL=1
57
58
  goto :END
58
59
 
@@ -67,13 +68,13 @@ set FIND_EXE=%SYSTEMROOT%\System32\find.exe
67
68
  reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | %FIND_EXE% /i "x86" > NUL && (set OS_BITS=32) || (set OS_BITS=64)
68
69
 
69
70
  if not exist "%WIN_TOOLS_ROOT_DIR%\.git_bleeding_edge" (
70
- set GIT_VERSION=2.7.4
71
+ set GIT_VERSION=2.8.3
71
72
  ) else (
72
- set GIT_VERSION=2.8.1
73
+ set GIT_VERSION=2.8.3
73
74
  )
74
75
  set GIT_VERSION=%GIT_VERSION%-%OS_BITS%
75
76
 
76
- set GIT_FETCH_URL=https://storage.googleapis.com/chrome-infra/PortableGit-%GIT_VERSION%-bit.7z.exe
77
+ set GIT_FETCH_URL=%CHROME_INFRA_URL%PortableGit-%GIT_VERSION%-bit.7z.exe
77
78
  set GIT_DOWNLOAD_PATH=%ZIP_DIR%\git.7z.exe
78
79
  set GIT_BIN_DIR=git-%GIT_VERSION%_bin
79
80
  set GIT_INST_DIR=%WIN_TOOLS_ROOT_DIR%\%GIT_BIN_DIR%
@@ -190,9 +191,10 @@ goto :END
190
191
  :SVN_INSTALL
191
192
  echo Installing subversion ...
192
193
  :: svn is not accessible; check it out and create 'proxy' files.
194
+ set SVN_URL=%CHROME_INFRA_URL%svn_bin.zip
193
195
  if exist "%ZIP_DIR%\svn.zip" del "%ZIP_DIR%\svn.zip"
194
- echo Fetching from %WIN_TOOLS_ROOT_URL%/third_party/svn_bin.zip
195
- cscript //nologo //e:jscript "%~dp0get_file.js" %WIN_TOOLS_ROOT_URL%/third_party/svn_bin.zip "%ZIP_DIR%\svn.zip"
196
+ echo Fetching from %SVN_URL%
197
+ cscript //nologo //e:jscript "%~dp0get_file.js" %SVN_URL% "%ZIP_DIR%\svn.zip"
196
198
  if errorlevel 1 goto :SVN_FAIL
197
199
  :: Cleanup svn directory if it was existing.
198
200
  if exist "%WIN_TOOLS_ROOT_DIR%\svn\." rd /q /s "%WIN_TOOLS_ROOT_DIR%\svn"
@@ -210,13 +212,12 @@ goto :END
210
212
 
211
213
  :SVN_FAIL
212
214
  echo ... Failed to checkout svn automatically.
213
- echo You should get the "prebaked" version at %WIN_TOOLS_ROOT_URL%/third_party/
215
+ echo You should get the "prebaked" version at %SVN_URL%
214
216
  set ERRORLEVEL=1
215
217
  goto :END
216
218
 
217
219
 
218
220
  :returncode
219
- set WIN_TOOLS_ROOT_URL=
220
221
  set WIN_TOOLS_ROOT_DIR=
221
222
  exit /b %ERRORLEVEL%
222
223
 
@@ -1,5 +1,5 @@
1
1
  # This file is used by gcl to get repository specific information.
2
2
  CODE_REVIEW_SERVER: codereview.chromium.org
3
3
  CC_LIST: chromium-reviews@chromium.org
4
- VIEW_VC: http://src.chromium.org/viewvc/chrome?view=rev&revision=
4
+ VIEW_VC: https://chromium.googlesource.com/chromium/tools/depot_tools/+/
5
5
  PROJECT: depot_tools
@@ -60,7 +60,7 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
60
60
  <file> [file] ...
61
61
 
62
62
  The style guidelines this tries to follow are those in
63
- http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
63
+ https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
64
64
 
65
65
  Every problem is given a confidence score from 1-5, with 5 meaning we are
66
66
  certain of the problem, and 1 meaning it could be a legitimate construct.
@@ -177,6 +177,8 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
177
177
  _ERROR_CATEGORIES = [
178
178
  'build/class',
179
179
  'build/c++11',
180
+ 'build/c++14',
181
+ 'build/c++tr1',
180
182
  'build/deprecated',
181
183
  'build/endif_comment',
182
184
  'build/explicit_make_pair',
@@ -196,7 +198,6 @@ _ERROR_CATEGORIES = [
196
198
  'readability/check',
197
199
  'readability/constructors',
198
200
  'readability/fn_size',
199
- 'readability/function',
200
201
  'readability/inheritance',
201
202
  'readability/multiline_comment',
202
203
  'readability/multiline_string',
@@ -227,6 +228,7 @@ _ERROR_CATEGORIES = [
227
228
  'whitespace/comma',
228
229
  'whitespace/comments',
229
230
  'whitespace/empty_conditional_body',
231
+ 'whitespace/empty_if_body',
230
232
  'whitespace/empty_loop_body',
231
233
  'whitespace/end_of_line',
232
234
  'whitespace/ending_newline',
@@ -245,6 +247,7 @@ _ERROR_CATEGORIES = [
245
247
  # compatibility they may still appear in NOLINT comments.
246
248
  _LEGACY_ERROR_CATEGORIES = [
247
249
  'readability/streams',
250
+ 'readability/function',
248
251
  ]
249
252
 
250
253
  # The default state of the category filter. This is overridden by the --filter=
@@ -253,6 +256,16 @@ _LEGACY_ERROR_CATEGORIES = [
253
256
  # All entries here should start with a '-' or '+', as in the --filter= flag.
254
257
  _DEFAULT_FILTERS = ['-build/include_alpha']
255
258
 
259
+ # The default list of categories suppressed for C (not C++) files.
260
+ _DEFAULT_C_SUPPRESSED_CATEGORIES = [
261
+ 'readability/casting',
262
+ ]
263
+
264
+ # The default list of categories suppressed for Linux Kernel files.
265
+ _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [
266
+ 'whitespace/tab',
267
+ ]
268
+
256
269
  # We used to check for high-bit characters, but after much discussion we
257
270
  # decided those were OK, as long as they were in UTF-8 and didn't represent
258
271
  # hard-coded international strings, which belong in a separate i18n file.
@@ -346,6 +359,7 @@ _CPP_HEADERS = frozenset([
346
359
  'random',
347
360
  'ratio',
348
361
  'regex',
362
+ 'scoped_allocator',
349
363
  'set',
350
364
  'sstream',
351
365
  'stack',
@@ -393,6 +407,19 @@ _CPP_HEADERS = frozenset([
393
407
  'cwctype',
394
408
  ])
395
409
 
410
+ # Type names
411
+ _TYPES = re.compile(
412
+ r'^(?:'
413
+ # [dcl.type.simple]
414
+ r'(char(16_t|32_t)?)|wchar_t|'
415
+ r'bool|short|int|long|signed|unsigned|float|double|'
416
+ # [support.types]
417
+ r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|'
418
+ # [cstdint.syn]
419
+ r'(u?int(_fast|_least)?(8|16|32|64)_t)|'
420
+ r'(u?int(max|ptr)_t)|'
421
+ r')$')
422
+
396
423
 
397
424
  # These headers are excluded from [build/include] and [build/include_order]
398
425
  # checks:
@@ -402,16 +429,18 @@ _CPP_HEADERS = frozenset([
402
429
  _THIRD_PARTY_HEADERS_PATTERN = re.compile(
403
430
  r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
404
431
 
432
+ # Pattern for matching FileInfo.BaseName() against test file name
433
+ _TEST_FILE_SUFFIX = r'(_test|_unittest|_regtest)$'
434
+
435
+ # Pattern that matches only complete whitespace, possibly across multiple lines.
436
+ _EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL)
405
437
 
406
438
  # Assertion macros. These are defined in base/logging.h and
407
- # testing/base/gunit.h. Note that the _M versions need to come first
408
- # for substring matching to work.
439
+ # testing/base/public/gunit.h.
409
440
  _CHECK_MACROS = [
410
441
  'DCHECK', 'CHECK',
411
- 'EXPECT_TRUE_M', 'EXPECT_TRUE',
412
- 'ASSERT_TRUE_M', 'ASSERT_TRUE',
413
- 'EXPECT_FALSE_M', 'EXPECT_FALSE',
414
- 'ASSERT_FALSE_M', 'ASSERT_FALSE',
442
+ 'EXPECT_TRUE', 'ASSERT_TRUE',
443
+ 'EXPECT_FALSE', 'ASSERT_FALSE',
415
444
  ]
416
445
 
417
446
  # Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
@@ -424,16 +453,12 @@ for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
424
453
  _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
425
454
  _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
426
455
  _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
427
- _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
428
- _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
429
456
 
430
457
  for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
431
458
  ('>=', 'LT'), ('>', 'LE'),
432
459
  ('<=', 'GT'), ('<', 'GE')]:
433
460
  _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
434
461
  _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
435
- _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
436
- _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
437
462
 
438
463
  # Alternative tokens and their replacements. For full list, see section 2.5
439
464
  # Alternative tokens [lex.digraph] in the C++ standard.
@@ -482,6 +507,12 @@ _MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
482
507
  r'(?:\s+(volatile|__volatile__))?'
483
508
  r'\s*[{(]')
484
509
 
510
+ # Match strings that indicate we're working on a C (not C++) file.
511
+ _SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|'
512
+ r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))')
513
+
514
+ # Match string that indicates we're working on a Linux Kernel file.
515
+ _SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)')
485
516
 
486
517
  _regexp_compile_cache = {}
487
518
 
@@ -501,8 +532,13 @@ _line_length = 80
501
532
  # This is set by --extensions flag.
502
533
  _valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
503
534
 
535
+ # {str, bool}: a map from error categories to booleans which indicate if the
536
+ # category should be suppressed for every line.
537
+ _global_error_suppressions = {}
538
+
539
+
504
540
  def ParseNolintSuppressions(filename, raw_line, linenum, error):
505
- """Updates the global list of error-suppressions.
541
+ """Updates the global list of line error-suppressions.
506
542
 
507
543
  Parses any NOLINT comments on the current line, updating the global
508
544
  error_suppressions store. Reports an error if the NOLINT comment
@@ -533,24 +569,45 @@ def ParseNolintSuppressions(filename, raw_line, linenum, error):
533
569
  'Unknown NOLINT error category: %s' % category)
534
570
 
535
571
 
572
+ def ProcessGlobalSuppresions(lines):
573
+ """Updates the list of global error suppressions.
574
+
575
+ Parses any lint directives in the file that have global effect.
576
+
577
+ Args:
578
+ lines: An array of strings, each representing a line of the file, with the
579
+ last element being empty if the file is terminated with a newline.
580
+ """
581
+ for line in lines:
582
+ if _SEARCH_C_FILE.search(line):
583
+ for category in _DEFAULT_C_SUPPRESSED_CATEGORIES:
584
+ _global_error_suppressions[category] = True
585
+ if _SEARCH_KERNEL_FILE.search(line):
586
+ for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES:
587
+ _global_error_suppressions[category] = True
588
+
589
+
536
590
  def ResetNolintSuppressions():
537
591
  """Resets the set of NOLINT suppressions to empty."""
538
592
  _error_suppressions.clear()
593
+ _global_error_suppressions.clear()
539
594
 
540
595
 
541
596
  def IsErrorSuppressedByNolint(category, linenum):
542
597
  """Returns true if the specified error category is suppressed on this line.
543
598
 
544
599
  Consults the global error_suppressions map populated by
545
- ParseNolintSuppressions/ResetNolintSuppressions.
600
+ ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions.
546
601
 
547
602
  Args:
548
603
  category: str, the category of the error.
549
604
  linenum: int, the current line number.
550
605
  Returns:
551
- bool, True iff the error should be suppressed due to a NOLINT comment.
606
+ bool, True iff the error should be suppressed due to a NOLINT comment or
607
+ global suppression.
552
608
  """
553
- return (linenum in _error_suppressions.get(category, set()) or
609
+ return (_global_error_suppressions.get(category, False) or
610
+ linenum in _error_suppressions.get(category, set()) or
554
611
  linenum in _error_suppressions.get(None, set()))
555
612
 
556
613
 
@@ -589,6 +646,11 @@ def Search(pattern, s):
589
646
  return _regexp_compile_cache[pattern].search(s)
590
647
 
591
648
 
649
+ def _IsSourceExtension(s):
650
+ """File extension (excluding dot) matches a source file extension."""
651
+ return s in ('c', 'cc', 'cpp', 'cxx')
652
+
653
+
592
654
  class _IncludeState(object):
593
655
  """Tracks line numbers for includes, and the order in which includes appear.
594
656
 
@@ -944,6 +1006,9 @@ class _FunctionState(object):
944
1006
  filename: The name of the current file.
945
1007
  linenum: The number of the line to check.
946
1008
  """
1009
+ if not self.in_a_function:
1010
+ return
1011
+
947
1012
  if Match(r'T(EST|est)', self.current_function):
948
1013
  base_trigger = self._TEST_TRIGGER
949
1014
  else:
@@ -1058,7 +1123,7 @@ class FileInfo(object):
1058
1123
 
1059
1124
  def IsSource(self):
1060
1125
  """File has a source file extension."""
1061
- return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
1126
+ return _IsSourceExtension(self.Extension()[1:])
1062
1127
 
1063
1128
 
1064
1129
  def _ShouldPrintError(category, confidence, linenum):
@@ -1204,8 +1269,18 @@ def CleanseRawStrings(raw_lines):
1204
1269
  while delimiter is None:
1205
1270
  # Look for beginning of a raw string.
1206
1271
  # See 2.14.15 [lex.string] for syntax.
1207
- matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line)
1208
- if matched:
1272
+ #
1273
+ # Once we have matched a raw string, we check the prefix of the
1274
+ # line to make sure that the line is not part of a single line
1275
+ # comment. It's done this way because we remove raw strings
1276
+ # before removing comments as opposed to removing comments
1277
+ # before removing raw strings. This is because there are some
1278
+ # cpplint checks that requires the comments to be preserved, but
1279
+ # we don't want to check comments that are inside raw strings.
1280
+ matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line)
1281
+ if (matched and
1282
+ not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//',
1283
+ matched.group(1))):
1209
1284
  delimiter = ')' + matched.group(2) + '"'
1210
1285
 
1211
1286
  end = matched.group(3).find(delimiter)
@@ -1776,11 +1851,11 @@ def CheckHeaderFileIncluded(filename, include_state, error):
1776
1851
  """Logs an error if a .cc file does not include its header."""
1777
1852
 
1778
1853
  # Do not check test files
1779
- if filename.endswith('_test.cc') or filename.endswith('_unittest.cc'):
1854
+ fileinfo = FileInfo(filename)
1855
+ if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()):
1780
1856
  return
1781
1857
 
1782
- fileinfo = FileInfo(filename)
1783
- headerfile = filename[0:len(filename) - 2] + 'h'
1858
+ headerfile = filename[0:len(filename) - len(fileinfo.Extension())] + '.h'
1784
1859
  if not os.path.exists(headerfile):
1785
1860
  return
1786
1861
  headername = FileInfo(headerfile).RepositoryName()
@@ -1997,7 +2072,8 @@ def IsForwardClassDeclaration(clean_lines, linenum):
1997
2072
  class _BlockInfo(object):
1998
2073
  """Stores information about a generic block of code."""
1999
2074
 
2000
- def __init__(self, seen_open_brace):
2075
+ def __init__(self, linenum, seen_open_brace):
2076
+ self.starting_linenum = linenum
2001
2077
  self.seen_open_brace = seen_open_brace
2002
2078
  self.open_parentheses = 0
2003
2079
  self.inline_asm = _NO_ASM
@@ -2046,17 +2122,16 @@ class _BlockInfo(object):
2046
2122
  class _ExternCInfo(_BlockInfo):
2047
2123
  """Stores information about an 'extern "C"' block."""
2048
2124
 
2049
- def __init__(self):
2050
- _BlockInfo.__init__(self, True)
2125
+ def __init__(self, linenum):
2126
+ _BlockInfo.__init__(self, linenum, True)
2051
2127
 
2052
2128
 
2053
2129
  class _ClassInfo(_BlockInfo):
2054
2130
  """Stores information about a class."""
2055
2131
 
2056
2132
  def __init__(self, name, class_or_struct, clean_lines, linenum):
2057
- _BlockInfo.__init__(self, False)
2133
+ _BlockInfo.__init__(self, linenum, False)
2058
2134
  self.name = name
2059
- self.starting_linenum = linenum
2060
2135
  self.is_derived = False
2061
2136
  self.check_namespace_indentation = True
2062
2137
  if class_or_struct == 'struct':
@@ -2124,9 +2199,8 @@ class _NamespaceInfo(_BlockInfo):
2124
2199
  """Stores information about a namespace."""
2125
2200
 
2126
2201
  def __init__(self, name, linenum):
2127
- _BlockInfo.__init__(self, False)
2202
+ _BlockInfo.__init__(self, linenum, False)
2128
2203
  self.name = name or ''
2129
- self.starting_linenum = linenum
2130
2204
  self.check_namespace_indentation = True
2131
2205
 
2132
2206
  def CheckEnd(self, filename, clean_lines, linenum, error):
@@ -2145,7 +2219,7 @@ class _NamespaceInfo(_BlockInfo):
2145
2219
  # deciding what these nontrivial things are, so this check is
2146
2220
  # triggered by namespace size only, which works most of the time.
2147
2221
  if (linenum - self.starting_linenum < 10
2148
- and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
2222
+ and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)):
2149
2223
  return
2150
2224
 
2151
2225
  # Look for matching comment at end of namespace.
@@ -2162,18 +2236,18 @@ class _NamespaceInfo(_BlockInfo):
2162
2236
  # expected namespace.
2163
2237
  if self.name:
2164
2238
  # Named namespace
2165
- if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
2166
- r'[\*/\.\\\s]*$'),
2239
+ if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' +
2240
+ re.escape(self.name) + r'[\*/\.\\\s]*$'),
2167
2241
  line):
2168
2242
  error(filename, linenum, 'readability/namespace', 5,
2169
2243
  'Namespace should be terminated with "// namespace %s"' %
2170
2244
  self.name)
2171
2245
  else:
2172
2246
  # Anonymous namespace
2173
- if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
2247
+ if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
2174
2248
  # If "// namespace anonymous" or "// anonymous namespace (more text)",
2175
2249
  # mention "// anonymous namespace" as an acceptable form
2176
- if Match(r'}.*\b(namespace anonymous|anonymous namespace)\b', line):
2250
+ if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line):
2177
2251
  error(filename, linenum, 'readability/namespace', 5,
2178
2252
  'Anonymous namespace should be terminated with "// namespace"'
2179
2253
  ' or "// anonymous namespace"')
@@ -2512,9 +2586,9 @@ class NestingState(object):
2512
2586
  if not self.SeenOpenBrace():
2513
2587
  self.stack[-1].seen_open_brace = True
2514
2588
  elif Match(r'^extern\s*"[^"]*"\s*\{', line):
2515
- self.stack.append(_ExternCInfo())
2589
+ self.stack.append(_ExternCInfo(linenum))
2516
2590
  else:
2517
- self.stack.append(_BlockInfo(True))
2591
+ self.stack.append(_BlockInfo(linenum, True))
2518
2592
  if _MATCH_ASM.match(line):
2519
2593
  self.stack[-1].inline_asm = _BLOCK_ASM
2520
2594
 
@@ -2626,7 +2700,8 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
2626
2700
  r'\s+(register|static|extern|typedef)\b',
2627
2701
  line):
2628
2702
  error(filename, linenum, 'build/storage_class', 5,
2629
- 'Storage class (static, extern, typedef, etc) should be first.')
2703
+ 'Storage-class specifier (static, extern, typedef, etc) should be '
2704
+ 'at the beginning of the declaration.')
2630
2705
 
2631
2706
  if Match(r'\s*#\s*endif\s*[^/\s]+', line):
2632
2707
  error(filename, linenum, 'build/endif_comment', 5,
@@ -2665,9 +2740,7 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
2665
2740
  base_classname = classinfo.name.split('::')[-1]
2666
2741
 
2667
2742
  # Look for single-argument constructors that aren't marked explicit.
2668
- # Technically a valid construct, but against style. Also look for
2669
- # non-single-argument constructors which are also technically valid, but
2670
- # strongly suggest something is wrong.
2743
+ # Technically a valid construct, but against style.
2671
2744
  explicit_constructor_match = Match(
2672
2745
  r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*'
2673
2746
  r'\(((?:[^()]|\([^()]*\))*)\)'
@@ -2728,10 +2801,6 @@ def CheckForNonStandardConstructs(filename, clean_lines, linenum,
2728
2801
  if noarg_constructor:
2729
2802
  error(filename, linenum, 'runtime/explicit', 5,
2730
2803
  'Zero-parameter constructors should not be marked explicit.')
2731
- else:
2732
- error(filename, linenum, 'runtime/explicit', 0,
2733
- 'Constructors that require multiple arguments '
2734
- 'should not be marked explicit.')
2735
2804
 
2736
2805
 
2737
2806
  def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
@@ -2786,6 +2855,7 @@ def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
2786
2855
  error(filename, linenum, 'whitespace/parens', 2,
2787
2856
  'Extra space after (')
2788
2857
  if (Search(r'\w\s+\(', fncall) and
2858
+ not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and
2789
2859
  not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and
2790
2860
  not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and
2791
2861
  not Search(r'\bcase\s+\(', fncall)):
@@ -2844,7 +2914,7 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
2844
2914
  """Reports for long function bodies.
2845
2915
 
2846
2916
  For an overview why this is done, see:
2847
- http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
2917
+ https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
2848
2918
 
2849
2919
  Uses a simplistic algorithm assuming other style guidelines
2850
2920
  (especially spacing) are followed.
@@ -2923,9 +2993,7 @@ def CheckComment(line, filename, linenum, next_line_start, error):
2923
2993
  commentpos = line.find('//')
2924
2994
  if commentpos != -1:
2925
2995
  # Check if the // may be in quotes. If so, ignore it
2926
- # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
2927
- if (line.count('"', 0, commentpos) -
2928
- line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes
2996
+ if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0:
2929
2997
  # Allow one space for new scopes, two spaces otherwise:
2930
2998
  if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and
2931
2999
  ((commentpos >= 1 and
@@ -3174,8 +3242,8 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error):
3174
3242
  # macro context and don't do any checks. This avoids false
3175
3243
  # positives.
3176
3244
  #
3177
- # Note that && is not included here. Those are checked separately
3178
- # in CheckRValueReference
3245
+ # Note that && is not included here. This is because there are too
3246
+ # many false positives due to RValue references.
3179
3247
  match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line)
3180
3248
  if match:
3181
3249
  error(filename, linenum, 'whitespace/operators', 3,
@@ -3209,7 +3277,7 @@ def CheckOperatorSpacing(filename, clean_lines, linenum, error):
3209
3277
  #
3210
3278
  # We also allow operators following an opening parenthesis, since
3211
3279
  # those tend to be macros that deal with operators.
3212
- match = Search(r'(operator|[^\s(<])(?:L|UL|ULL|l|ul|ull)?<<([^\s,=<])', line)
3280
+ match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line)
3213
3281
  if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and
3214
3282
  not (match.group(1) == 'operator' and match.group(2) == ';')):
3215
3283
  error(filename, linenum, 'whitespace/operators', 3,
@@ -3313,22 +3381,90 @@ def CheckCommaSpacing(filename, clean_lines, linenum, error):
3313
3381
  'Missing space after ;')
3314
3382
 
3315
3383
 
3316
- def CheckBracesSpacing(filename, clean_lines, linenum, error):
3384
+ def _IsType(clean_lines, nesting_state, expr):
3385
+ """Check if expression looks like a type name, returns true if so.
3386
+
3387
+ Args:
3388
+ clean_lines: A CleansedLines instance containing the file.
3389
+ nesting_state: A NestingState instance which maintains information about
3390
+ the current stack of nested blocks being parsed.
3391
+ expr: The expression to check.
3392
+ Returns:
3393
+ True, if token looks like a type.
3394
+ """
3395
+ # Keep only the last token in the expression
3396
+ last_word = Match(r'^.*(\b\S+)$', expr)
3397
+ if last_word:
3398
+ token = last_word.group(1)
3399
+ else:
3400
+ token = expr
3401
+
3402
+ # Match native types and stdint types
3403
+ if _TYPES.match(token):
3404
+ return True
3405
+
3406
+ # Try a bit harder to match templated types. Walk up the nesting
3407
+ # stack until we find something that resembles a typename
3408
+ # declaration for what we are looking for.
3409
+ typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) +
3410
+ r'\b')
3411
+ block_index = len(nesting_state.stack) - 1
3412
+ while block_index >= 0:
3413
+ if isinstance(nesting_state.stack[block_index], _NamespaceInfo):
3414
+ return False
3415
+
3416
+ # Found where the opening brace is. We want to scan from this
3417
+ # line up to the beginning of the function, minus a few lines.
3418
+ # template <typename Type1, // stop scanning here
3419
+ # ...>
3420
+ # class C
3421
+ # : public ... { // start scanning here
3422
+ last_line = nesting_state.stack[block_index].starting_linenum
3423
+
3424
+ next_block_start = 0
3425
+ if block_index > 0:
3426
+ next_block_start = nesting_state.stack[block_index - 1].starting_linenum
3427
+ first_line = last_line
3428
+ while first_line >= next_block_start:
3429
+ if clean_lines.elided[first_line].find('template') >= 0:
3430
+ break
3431
+ first_line -= 1
3432
+ if first_line < next_block_start:
3433
+ # Didn't find any "template" keyword before reaching the next block,
3434
+ # there are probably no template things to check for this block
3435
+ block_index -= 1
3436
+ continue
3437
+
3438
+ # Look for typename in the specified range
3439
+ for i in xrange(first_line, last_line + 1, 1):
3440
+ if Search(typename_pattern, clean_lines.elided[i]):
3441
+ return True
3442
+ block_index -= 1
3443
+
3444
+ return False
3445
+
3446
+
3447
+ def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error):
3317
3448
  """Checks for horizontal spacing near commas.
3318
3449
 
3319
3450
  Args:
3320
3451
  filename: The name of the current file.
3321
3452
  clean_lines: A CleansedLines instance containing the file.
3322
3453
  linenum: The number of the line to check.
3454
+ nesting_state: A NestingState instance which maintains information about
3455
+ the current stack of nested blocks being parsed.
3323
3456
  error: The function to call with any errors found.
3324
3457
  """
3325
3458
  line = clean_lines.elided[linenum]
3326
3459
 
3327
3460
  # Except after an opening paren, or after another opening brace (in case of
3328
3461
  # an initializer list, for instance), you should have spaces before your
3329
- # braces. And since you should never have braces at the beginning of a line,
3330
- # this is an easy test.
3462
+ # braces when they are delimiting blocks, classes, namespaces etc.
3463
+ # And since you should never have braces at the beginning of a line,
3464
+ # this is an easy test. Except that braces used for initialization don't
3465
+ # follow the same rule; we often don't want spaces before those.
3331
3466
  match = Match(r'^(.*[^ ({>]){', line)
3467
+
3332
3468
  if match:
3333
3469
  # Try a bit harder to check for brace initialization. This
3334
3470
  # happens in one of the following forms:
@@ -3358,6 +3494,7 @@ def CheckBracesSpacing(filename, clean_lines, linenum, error):
3358
3494
  # There is a false negative with this approach if people inserted
3359
3495
  # spurious semicolons, e.g. "if (cond){};", but we will catch the
3360
3496
  # spurious semicolon with a separate check.
3497
+ leading_text = match.group(1)
3361
3498
  (endline, endlinenum, endpos) = CloseExpression(
3362
3499
  clean_lines, linenum, len(match.group(1)))
3363
3500
  trailing_text = ''
@@ -3366,7 +3503,11 @@ def CheckBracesSpacing(filename, clean_lines, linenum, error):
3366
3503
  for offset in xrange(endlinenum + 1,
3367
3504
  min(endlinenum + 3, clean_lines.NumLines() - 1)):
3368
3505
  trailing_text += clean_lines.elided[offset]
3369
- if not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text):
3506
+ # We also suppress warnings for `uint64_t{expression}` etc., as the style
3507
+ # guide recommends brace initialization for integral types to avoid
3508
+ # overflow/truncation.
3509
+ if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text)
3510
+ and not _IsType(clean_lines, nesting_state, leading_text)):
3370
3511
  error(filename, linenum, 'whitespace/braces', 5,
3371
3512
  'Missing space before {')
3372
3513
 
@@ -3410,405 +3551,6 @@ def IsDecltype(clean_lines, linenum, column):
3410
3551
  return False
3411
3552
 
3412
3553
 
3413
- def IsTemplateParameterList(clean_lines, linenum, column):
3414
- """Check if the token ending on (linenum, column) is the end of template<>.
3415
-
3416
- Args:
3417
- clean_lines: A CleansedLines instance containing the file.
3418
- linenum: the number of the line to check.
3419
- column: end column of the token to check.
3420
- Returns:
3421
- True if this token is end of a template parameter list, False otherwise.
3422
- """
3423
- (_, startline, startpos) = ReverseCloseExpression(
3424
- clean_lines, linenum, column)
3425
- if (startpos > -1 and
3426
- Search(r'\btemplate\s*$', clean_lines.elided[startline][0:startpos])):
3427
- return True
3428
- return False
3429
-
3430
-
3431
- def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
3432
- """Check if the token ending on (linenum, column) is a type.
3433
-
3434
- Assumes that text to the right of the column is "&&" or a function
3435
- name.
3436
-
3437
- Args:
3438
- typenames: set of type names from template-argument-list.
3439
- clean_lines: A CleansedLines instance containing the file.
3440
- nesting_state: A NestingState instance which maintains information about
3441
- the current stack of nested blocks being parsed.
3442
- linenum: the number of the line to check.
3443
- column: end column of the token to check.
3444
- Returns:
3445
- True if this token is a type, False if we are not sure.
3446
- """
3447
- prefix = clean_lines.elided[linenum][0:column]
3448
-
3449
- # Get one word to the left. If we failed to do so, this is most
3450
- # likely not a type, since it's unlikely that the type name and "&&"
3451
- # would be split across multiple lines.
3452
- match = Match(r'^(.*)(\b\w+|[>*)&])\s*$', prefix)
3453
- if not match:
3454
- return False
3455
-
3456
- # Check text following the token. If it's "&&>" or "&&," or "&&...", it's
3457
- # most likely a rvalue reference used inside a template.
3458
- suffix = clean_lines.elided[linenum][column:]
3459
- if Match(r'&&\s*(?:[>,]|\.\.\.)', suffix):
3460
- return True
3461
-
3462
- # Check for known types and end of templates:
3463
- # int&& variable
3464
- # vector<int>&& variable
3465
- #
3466
- # Because this function is called recursively, we also need to
3467
- # recognize pointer and reference types:
3468
- # int* Function()
3469
- # int& Function()
3470
- if (match.group(2) in typenames or
3471
- match.group(2) in ['char', 'char16_t', 'char32_t', 'wchar_t', 'bool',
3472
- 'short', 'int', 'long', 'signed', 'unsigned',
3473
- 'float', 'double', 'void', 'auto', '>', '*', '&']):
3474
- return True
3475
-
3476
- # If we see a close parenthesis, look for decltype on the other side.
3477
- # decltype would unambiguously identify a type, anything else is
3478
- # probably a parenthesized expression and not a type.
3479
- if match.group(2) == ')':
3480
- return IsDecltype(
3481
- clean_lines, linenum, len(match.group(1)) + len(match.group(2)) - 1)
3482
-
3483
- # Check for casts and cv-qualifiers.
3484
- # match.group(1) remainder
3485
- # -------------- ---------
3486
- # const_cast< type&&
3487
- # const type&&
3488
- # type const&&
3489
- if Search(r'\b(?:const_cast\s*<|static_cast\s*<|dynamic_cast\s*<|'
3490
- r'reinterpret_cast\s*<|\w+\s)\s*$',
3491
- match.group(1)):
3492
- return True
3493
-
3494
- # Look for a preceding symbol that might help differentiate the context.
3495
- # These are the cases that would be ambiguous:
3496
- # match.group(1) remainder
3497
- # -------------- ---------
3498
- # Call ( expression &&
3499
- # Declaration ( type&&
3500
- # sizeof ( type&&
3501
- # if ( expression &&
3502
- # while ( expression &&
3503
- # for ( type&&
3504
- # for( ; expression &&
3505
- # statement ; type&&
3506
- # block { type&&
3507
- # constructor { expression &&
3508
- start = linenum
3509
- line = match.group(1)
3510
- match_symbol = None
3511
- while start >= 0:
3512
- # We want to skip over identifiers and commas to get to a symbol.
3513
- # Commas are skipped so that we can find the opening parenthesis
3514
- # for function parameter lists.
3515
- match_symbol = Match(r'^(.*)([^\w\s,])[\w\s,]*$', line)
3516
- if match_symbol:
3517
- break
3518
- start -= 1
3519
- line = clean_lines.elided[start]
3520
-
3521
- if not match_symbol:
3522
- # Probably the first statement in the file is an rvalue reference
3523
- return True
3524
-
3525
- if match_symbol.group(2) == '}':
3526
- # Found closing brace, probably an indicate of this:
3527
- # block{} type&&
3528
- return True
3529
-
3530
- if match_symbol.group(2) == ';':
3531
- # Found semicolon, probably one of these:
3532
- # for(; expression &&
3533
- # statement; type&&
3534
-
3535
- # Look for the previous 'for(' in the previous lines.
3536
- before_text = match_symbol.group(1)
3537
- for i in xrange(start - 1, max(start - 6, 0), -1):
3538
- before_text = clean_lines.elided[i] + before_text
3539
- if Search(r'for\s*\([^{};]*$', before_text):
3540
- # This is the condition inside a for-loop
3541
- return False
3542
-
3543
- # Did not find a for-init-statement before this semicolon, so this
3544
- # is probably a new statement and not a condition.
3545
- return True
3546
-
3547
- if match_symbol.group(2) == '{':
3548
- # Found opening brace, probably one of these:
3549
- # block{ type&& = ... ; }
3550
- # constructor{ expression && expression }
3551
-
3552
- # Look for a closing brace or a semicolon. If we see a semicolon
3553
- # first, this is probably a rvalue reference.
3554
- line = clean_lines.elided[start][0:len(match_symbol.group(1)) + 1]
3555
- end = start
3556
- depth = 1
3557
- while True:
3558
- for ch in line:
3559
- if ch == ';':
3560
- return True
3561
- elif ch == '{':
3562
- depth += 1
3563
- elif ch == '}':
3564
- depth -= 1
3565
- if depth == 0:
3566
- return False
3567
- end += 1
3568
- if end >= clean_lines.NumLines():
3569
- break
3570
- line = clean_lines.elided[end]
3571
- # Incomplete program?
3572
- return False
3573
-
3574
- if match_symbol.group(2) == '(':
3575
- # Opening parenthesis. Need to check what's to the left of the
3576
- # parenthesis. Look back one extra line for additional context.
3577
- before_text = match_symbol.group(1)
3578
- if linenum > 1:
3579
- before_text = clean_lines.elided[linenum - 1] + before_text
3580
- before_text = match_symbol.group(1)
3581
-
3582
- # Patterns that are likely to be types:
3583
- # [](type&&
3584
- # for (type&&
3585
- # sizeof(type&&
3586
- # operator=(type&&
3587
- #
3588
- if Search(r'(?:\]|\bfor|\bsizeof|\boperator\s*\S+\s*)\s*$', before_text):
3589
- return True
3590
-
3591
- # Patterns that are likely to be expressions:
3592
- # if (expression &&
3593
- # while (expression &&
3594
- # : initializer(expression &&
3595
- # , initializer(expression &&
3596
- # ( FunctionCall(expression &&
3597
- # + FunctionCall(expression &&
3598
- # + (expression &&
3599
- #
3600
- # The last '+' represents operators such as '+' and '-'.
3601
- if Search(r'(?:\bif|\bwhile|[-+=%^(<!?:,&*]\s*)$', before_text):
3602
- return False
3603
-
3604
- # Something else. Check that tokens to the left look like
3605
- # return_type function_name
3606
- match_func = Match(r'^(.*\S.*)\s+\w(?:\w|::)*(?:<[^<>]*>)?\s*$',
3607
- match_symbol.group(1))
3608
- if match_func:
3609
- # Check for constructors, which don't have return types.
3610
- if Search(r'\b(?:explicit|inline)$', match_func.group(1)):
3611
- return True
3612
- implicit_constructor = Match(r'\s*(\w+)\((?:const\s+)?(\w+)', prefix)
3613
- if (implicit_constructor and
3614
- implicit_constructor.group(1) == implicit_constructor.group(2)):
3615
- return True
3616
- return IsRValueType(typenames, clean_lines, nesting_state, linenum,
3617
- len(match_func.group(1)))
3618
-
3619
- # Nothing before the function name. If this is inside a block scope,
3620
- # this is probably a function call.
3621
- return not (nesting_state.previous_stack_top and
3622
- nesting_state.previous_stack_top.IsBlockInfo())
3623
-
3624
- if match_symbol.group(2) == '>':
3625
- # Possibly a closing bracket, check that what's on the other side
3626
- # looks like the start of a template.
3627
- return IsTemplateParameterList(
3628
- clean_lines, start, len(match_symbol.group(1)))
3629
-
3630
- # Some other symbol, usually something like "a=b&&c". This is most
3631
- # likely not a type.
3632
- return False
3633
-
3634
-
3635
- def IsDeletedOrDefault(clean_lines, linenum):
3636
- """Check if current constructor or operator is deleted or default.
3637
-
3638
- Args:
3639
- clean_lines: A CleansedLines instance containing the file.
3640
- linenum: The number of the line to check.
3641
- Returns:
3642
- True if this is a deleted or default constructor.
3643
- """
3644
- open_paren = clean_lines.elided[linenum].find('(')
3645
- if open_paren < 0:
3646
- return False
3647
- (close_line, _, close_paren) = CloseExpression(
3648
- clean_lines, linenum, open_paren)
3649
- if close_paren < 0:
3650
- return False
3651
- return Match(r'\s*=\s*(?:delete|default)\b', close_line[close_paren:])
3652
-
3653
-
3654
- def IsRValueAllowed(clean_lines, linenum, typenames):
3655
- """Check if RValue reference is allowed on a particular line.
3656
-
3657
- Args:
3658
- clean_lines: A CleansedLines instance containing the file.
3659
- linenum: The number of the line to check.
3660
- typenames: set of type names from template-argument-list.
3661
- Returns:
3662
- True if line is within the region where RValue references are allowed.
3663
- """
3664
- # Allow region marked by PUSH/POP macros
3665
- for i in xrange(linenum, 0, -1):
3666
- line = clean_lines.elided[i]
3667
- if Match(r'GOOGLE_ALLOW_RVALUE_REFERENCES_(?:PUSH|POP)', line):
3668
- if not line.endswith('PUSH'):
3669
- return False
3670
- for j in xrange(linenum, clean_lines.NumLines(), 1):
3671
- line = clean_lines.elided[j]
3672
- if Match(r'GOOGLE_ALLOW_RVALUE_REFERENCES_(?:PUSH|POP)', line):
3673
- return line.endswith('POP')
3674
-
3675
- # Allow operator=
3676
- line = clean_lines.elided[linenum]
3677
- if Search(r'\boperator\s*=\s*\(', line):
3678
- return IsDeletedOrDefault(clean_lines, linenum)
3679
-
3680
- # Allow constructors
3681
- match = Match(r'\s*(?:[\w<>]+::)*([\w<>]+)\s*::\s*([\w<>]+)\s*\(', line)
3682
- if match and match.group(1) == match.group(2):
3683
- return IsDeletedOrDefault(clean_lines, linenum)
3684
- if Search(r'\b(?:explicit|inline)\s+[\w<>]+\s*\(', line):
3685
- return IsDeletedOrDefault(clean_lines, linenum)
3686
-
3687
- if Match(r'\s*[\w<>]+\s*\(', line):
3688
- previous_line = 'ReturnType'
3689
- if linenum > 0:
3690
- previous_line = clean_lines.elided[linenum - 1]
3691
- if Match(r'^\s*$', previous_line) or Search(r'[{}:;]\s*$', previous_line):
3692
- return IsDeletedOrDefault(clean_lines, linenum)
3693
-
3694
- # Reject types not mentioned in template-argument-list
3695
- while line:
3696
- match = Match(r'^.*?(\w+)\s*&&(.*)$', line)
3697
- if not match:
3698
- break
3699
- if match.group(1) not in typenames:
3700
- return False
3701
- line = match.group(2)
3702
-
3703
- # All RValue types that were in template-argument-list should have
3704
- # been removed by now. Those were allowed, assuming that they will
3705
- # be forwarded.
3706
- #
3707
- # If there are no remaining RValue types left (i.e. types that were
3708
- # not found in template-argument-list), flag those as not allowed.
3709
- return line.find('&&') < 0
3710
-
3711
-
3712
- def GetTemplateArgs(clean_lines, linenum):
3713
- """Find list of template arguments associated with this function declaration.
3714
-
3715
- Args:
3716
- clean_lines: A CleansedLines instance containing the file.
3717
- linenum: Line number containing the start of the function declaration,
3718
- usually one line after the end of the template-argument-list.
3719
- Returns:
3720
- Set of type names, or empty set if this does not appear to have
3721
- any template parameters.
3722
- """
3723
- # Find start of function
3724
- func_line = linenum
3725
- while func_line > 0:
3726
- line = clean_lines.elided[func_line]
3727
- if Match(r'^\s*$', line):
3728
- return set()
3729
- if line.find('(') >= 0:
3730
- break
3731
- func_line -= 1
3732
- if func_line == 0:
3733
- return set()
3734
-
3735
- # Collapse template-argument-list into a single string
3736
- argument_list = ''
3737
- match = Match(r'^(\s*template\s*)<', clean_lines.elided[func_line])
3738
- if match:
3739
- # template-argument-list on the same line as function name
3740
- start_col = len(match.group(1))
3741
- _, end_line, end_col = CloseExpression(clean_lines, func_line, start_col)
3742
- if end_col > -1 and end_line == func_line:
3743
- start_col += 1 # Skip the opening bracket
3744
- argument_list = clean_lines.elided[func_line][start_col:end_col]
3745
-
3746
- elif func_line > 1:
3747
- # template-argument-list one line before function name
3748
- match = Match(r'^(.*)>\s*$', clean_lines.elided[func_line - 1])
3749
- if match:
3750
- end_col = len(match.group(1))
3751
- _, start_line, start_col = ReverseCloseExpression(
3752
- clean_lines, func_line - 1, end_col)
3753
- if start_col > -1:
3754
- start_col += 1 # Skip the opening bracket
3755
- while start_line < func_line - 1:
3756
- argument_list += clean_lines.elided[start_line][start_col:]
3757
- start_col = 0
3758
- start_line += 1
3759
- argument_list += clean_lines.elided[func_line - 1][start_col:end_col]
3760
-
3761
- if not argument_list:
3762
- return set()
3763
-
3764
- # Extract type names
3765
- typenames = set()
3766
- while True:
3767
- match = Match(r'^[,\s]*(?:typename|class)(?:\.\.\.)?\s+(\w+)(.*)$',
3768
- argument_list)
3769
- if not match:
3770
- break
3771
- typenames.add(match.group(1))
3772
- argument_list = match.group(2)
3773
- return typenames
3774
-
3775
-
3776
- def CheckRValueReference(filename, clean_lines, linenum, nesting_state, error):
3777
- """Check for rvalue references.
3778
-
3779
- Args:
3780
- filename: The name of the current file.
3781
- clean_lines: A CleansedLines instance containing the file.
3782
- linenum: The number of the line to check.
3783
- nesting_state: A NestingState instance which maintains information about
3784
- the current stack of nested blocks being parsed.
3785
- error: The function to call with any errors found.
3786
- """
3787
- # Find lines missing spaces around &&.
3788
- # TODO(unknown): currently we don't check for rvalue references
3789
- # with spaces surrounding the && to avoid false positives with
3790
- # boolean expressions.
3791
- line = clean_lines.elided[linenum]
3792
- match = Match(r'^(.*\S)&&', line)
3793
- if not match:
3794
- match = Match(r'(.*)&&\S', line)
3795
- if (not match) or '(&&)' in line or Search(r'\boperator\s*$', match.group(1)):
3796
- return
3797
-
3798
- # Either poorly formed && or an rvalue reference, check the context
3799
- # to get a more accurate error message. Mostly we want to determine
3800
- # if what's to the left of "&&" is a type or not.
3801
- typenames = GetTemplateArgs(clean_lines, linenum)
3802
- and_pos = len(match.group(1))
3803
- if IsRValueType(typenames, clean_lines, nesting_state, linenum, and_pos):
3804
- if not IsRValueAllowed(clean_lines, linenum, typenames):
3805
- error(filename, linenum, 'build/c++11', 3,
3806
- 'RValue references are an unapproved C++ feature.')
3807
- else:
3808
- error(filename, linenum, 'whitespace/operators', 3,
3809
- 'Missing spaces around &&')
3810
-
3811
-
3812
3554
  def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
3813
3555
  """Checks for additional blank line issues related to sections.
3814
3556
 
@@ -3906,10 +3648,13 @@ def CheckBraces(filename, clean_lines, linenum, error):
3906
3648
  # used for brace initializers inside function calls. We don't detect this
3907
3649
  # perfectly: we just don't complain if the last non-whitespace character on
3908
3650
  # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the
3909
- # previous line starts a preprocessor block.
3651
+ # previous line starts a preprocessor block. We also allow a brace on the
3652
+ # following line if it is part of an array initialization and would not fit
3653
+ # within the 80 character limit of the preceding line.
3910
3654
  prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
3911
3655
  if (not Search(r'[,;:}{(]\s*$', prevline) and
3912
- not Match(r'\s*#', prevline)):
3656
+ not Match(r'\s*#', prevline) and
3657
+ not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)):
3913
3658
  error(filename, linenum, 'whitespace/braces', 4,
3914
3659
  '{ should almost always be at the end of the previous line')
3915
3660
 
@@ -4085,13 +3830,14 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
4085
3830
  # In addition to macros, we also don't want to warn on
4086
3831
  # - Compound literals
4087
3832
  # - Lambdas
4088
- # - alignas specifier with anonymous structs:
3833
+ # - alignas specifier with anonymous structs
3834
+ # - decltype
4089
3835
  closing_brace_pos = match.group(1).rfind(')')
4090
3836
  opening_parenthesis = ReverseCloseExpression(
4091
3837
  clean_lines, linenum, closing_brace_pos)
4092
3838
  if opening_parenthesis[2] > -1:
4093
3839
  line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
4094
- macro = Search(r'\b([A-Z_]+)\s*$', line_prefix)
3840
+ macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix)
4095
3841
  func = Match(r'^(.*\])\s*$', line_prefix)
4096
3842
  if ((macro and
4097
3843
  macro.group(1) not in (
@@ -4100,6 +3846,7 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
4100
3846
  'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
4101
3847
  (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or
4102
3848
  Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or
3849
+ Search(r'\bdecltype$', line_prefix) or
4103
3850
  Search(r'\s+=\s*$', line_prefix)):
4104
3851
  match = None
4105
3852
  if (match and
@@ -4159,7 +3906,7 @@ def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
4159
3906
  line = clean_lines.elided[linenum]
4160
3907
  matched = Match(r'\s*(for|while|if)\s*\(', line)
4161
3908
  if matched:
4162
- # Find the end of the conditional expression
3909
+ # Find the end of the conditional expression.
4163
3910
  (end_line, end_linenum, end_pos) = CloseExpression(
4164
3911
  clean_lines, linenum, line.find('('))
4165
3912
 
@@ -4174,6 +3921,75 @@ def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
4174
3921
  error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
4175
3922
  'Empty loop bodies should use {} or continue')
4176
3923
 
3924
+ # Check for if statements that have completely empty bodies (no comments)
3925
+ # and no else clauses.
3926
+ if end_pos >= 0 and matched.group(1) == 'if':
3927
+ # Find the position of the opening { for the if statement.
3928
+ # Return without logging an error if it has no brackets.
3929
+ opening_linenum = end_linenum
3930
+ opening_line_fragment = end_line[end_pos:]
3931
+ # Loop until EOF or find anything that's not whitespace or opening {.
3932
+ while not Search(r'^\s*\{', opening_line_fragment):
3933
+ if Search(r'^(?!\s*$)', opening_line_fragment):
3934
+ # Conditional has no brackets.
3935
+ return
3936
+ opening_linenum += 1
3937
+ if opening_linenum == len(clean_lines.elided):
3938
+ # Couldn't find conditional's opening { or any code before EOF.
3939
+ return
3940
+ opening_line_fragment = clean_lines.elided[opening_linenum]
3941
+ # Set opening_line (opening_line_fragment may not be entire opening line).
3942
+ opening_line = clean_lines.elided[opening_linenum]
3943
+
3944
+ # Find the position of the closing }.
3945
+ opening_pos = opening_line_fragment.find('{')
3946
+ if opening_linenum == end_linenum:
3947
+ # We need to make opening_pos relative to the start of the entire line.
3948
+ opening_pos += end_pos
3949
+ (closing_line, closing_linenum, closing_pos) = CloseExpression(
3950
+ clean_lines, opening_linenum, opening_pos)
3951
+ if closing_pos < 0:
3952
+ return
3953
+
3954
+ # Now construct the body of the conditional. This consists of the portion
3955
+ # of the opening line after the {, all lines until the closing line,
3956
+ # and the portion of the closing line before the }.
3957
+ if (clean_lines.raw_lines[opening_linenum] !=
3958
+ CleanseComments(clean_lines.raw_lines[opening_linenum])):
3959
+ # Opening line ends with a comment, so conditional isn't empty.
3960
+ return
3961
+ if closing_linenum > opening_linenum:
3962
+ # Opening line after the {. Ignore comments here since we checked above.
3963
+ body = list(opening_line[opening_pos+1:])
3964
+ # All lines until closing line, excluding closing line, with comments.
3965
+ body.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum])
3966
+ # Closing line before the }. Won't (and can't) have comments.
3967
+ body.append(clean_lines.elided[closing_linenum][:closing_pos-1])
3968
+ body = '\n'.join(body)
3969
+ else:
3970
+ # If statement has brackets and fits on a single line.
3971
+ body = opening_line[opening_pos+1:closing_pos-1]
3972
+
3973
+ # Check if the body is empty
3974
+ if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body):
3975
+ return
3976
+ # The body is empty. Now make sure there's not an else clause.
3977
+ current_linenum = closing_linenum
3978
+ current_line_fragment = closing_line[closing_pos:]
3979
+ # Loop until EOF or find anything that's not whitespace or else clause.
3980
+ while Search(r'^\s*$|^(?=\s*else)', current_line_fragment):
3981
+ if Search(r'^(?=\s*else)', current_line_fragment):
3982
+ # Found an else clause, so don't log an error.
3983
+ return
3984
+ current_linenum += 1
3985
+ if current_linenum == len(clean_lines.elided):
3986
+ break
3987
+ current_line_fragment = clean_lines.elided[current_linenum]
3988
+
3989
+ # The body is empty and there's no else clause until EOF or other code.
3990
+ error(filename, end_linenum, 'whitespace/empty_if_body', 4,
3991
+ ('If statement had no body and no else clause'))
3992
+
4177
3993
 
4178
3994
  def FindCheckMacro(line):
4179
3995
  """Find a replaceable CHECK-like macro.
@@ -4393,6 +4209,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
4393
4209
  # raw strings,
4394
4210
  raw_lines = clean_lines.lines_without_raw_strings
4395
4211
  line = raw_lines[linenum]
4212
+ prev = raw_lines[linenum - 1] if linenum > 0 else ''
4396
4213
 
4397
4214
  if line.find('\t') != -1:
4398
4215
  error(filename, linenum, 'whitespace/tab', 1,
@@ -4416,19 +4233,24 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
4416
4233
  cleansed_line = clean_lines.elided[linenum]
4417
4234
  while initial_spaces < len(line) and line[initial_spaces] == ' ':
4418
4235
  initial_spaces += 1
4419
- if line and line[-1].isspace():
4420
- error(filename, linenum, 'whitespace/end_of_line', 4,
4421
- 'Line ends in whitespace. Consider deleting these extra spaces.')
4422
4236
  # There are certain situations we allow one space, notably for
4423
4237
  # section labels, and also lines containing multi-line raw strings.
4424
- elif ((initial_spaces == 1 or initial_spaces == 3) and
4425
- not Match(scope_or_label_pattern, cleansed_line) and
4426
- not (clean_lines.raw_lines[linenum] != line and
4427
- Match(r'^\s*""', line))):
4238
+ # We also don't check for lines that look like continuation lines
4239
+ # (of lines ending in double quotes, commas, equals, or angle brackets)
4240
+ # because the rules for how to indent those are non-trivial.
4241
+ if (not Search(r'[",=><] *$', prev) and
4242
+ (initial_spaces == 1 or initial_spaces == 3) and
4243
+ not Match(scope_or_label_pattern, cleansed_line) and
4244
+ not (clean_lines.raw_lines[linenum] != line and
4245
+ Match(r'^\s*""', line))):
4428
4246
  error(filename, linenum, 'whitespace/indent', 3,
4429
4247
  'Weird number of spaces at line-start. '
4430
4248
  'Are you using a 2-space indent?')
4431
4249
 
4250
+ if line and line[-1].isspace():
4251
+ error(filename, linenum, 'whitespace/end_of_line', 4,
4252
+ 'Line ends in whitespace. Consider deleting these extra spaces.')
4253
+
4432
4254
  # Check if the line is a header guard.
4433
4255
  is_header_guard = False
4434
4256
  if file_extension == 'h':
@@ -4447,14 +4269,10 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
4447
4269
  # developers fault.
4448
4270
  if (not line.startswith('#include') and not is_header_guard and
4449
4271
  not Match(r'^\s*//.*http(s?)://\S*$', line) and
4272
+ not Match(r'^\s*//\s*[^\s]*$', line) and
4450
4273
  not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
4451
4274
  line_width = GetLineWidth(line)
4452
- extended_length = int((_line_length * 1.25))
4453
- if line_width > extended_length:
4454
- error(filename, linenum, 'whitespace/line_length', 4,
4455
- 'Lines should very rarely be longer than %i characters' %
4456
- extended_length)
4457
- elif line_width > _line_length:
4275
+ if line_width > _line_length:
4458
4276
  error(filename, linenum, 'whitespace/line_length', 2,
4459
4277
  'Lines should be <= %i characters long' % _line_length)
4460
4278
 
@@ -4479,9 +4297,8 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
4479
4297
  CheckOperatorSpacing(filename, clean_lines, linenum, error)
4480
4298
  CheckParenthesisSpacing(filename, clean_lines, linenum, error)
4481
4299
  CheckCommaSpacing(filename, clean_lines, linenum, error)
4482
- CheckBracesSpacing(filename, clean_lines, linenum, error)
4300
+ CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error)
4483
4301
  CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
4484
- CheckRValueReference(filename, clean_lines, linenum, nesting_state, error)
4485
4302
  CheckCheck(filename, clean_lines, linenum, error)
4486
4303
  CheckAltTokens(filename, clean_lines, linenum, error)
4487
4304
  classinfo = nesting_state.InnermostClass()
@@ -4525,23 +4342,6 @@ def _DropCommonSuffixes(filename):
4525
4342
  return os.path.splitext(filename)[0]
4526
4343
 
4527
4344
 
4528
- def _IsTestFilename(filename):
4529
- """Determines if the given filename has a suffix that identifies it as a test.
4530
-
4531
- Args:
4532
- filename: The input filename.
4533
-
4534
- Returns:
4535
- True if 'filename' looks like a test, False otherwise.
4536
- """
4537
- if (filename.endswith('_test.cc') or
4538
- filename.endswith('_unittest.cc') or
4539
- filename.endswith('_regtest.cc')):
4540
- return True
4541
- else:
4542
- return False
4543
-
4544
-
4545
4345
  def _ClassifyInclude(fileinfo, include, is_system):
4546
4346
  """Figures out what kind of header 'include' is.
4547
4347
 
@@ -4756,6 +4556,9 @@ _RE_PATTERN_REF_PARAM = re.compile(
4756
4556
  _RE_PATTERN_CONST_REF_PARAM = (
4757
4557
  r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +
4758
4558
  r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')
4559
+ # Stream types.
4560
+ _RE_PATTERN_REF_STREAM_PARAM = (
4561
+ r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')')
4759
4562
 
4760
4563
 
4761
4564
  def CheckLanguage(filename, clean_lines, linenum, file_extension,
@@ -4912,7 +4715,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
4912
4715
  and line[-1] != '\\'):
4913
4716
  error(filename, linenum, 'build/namespaces', 4,
4914
4717
  'Do not use unnamed namespaces in header files. See '
4915
- 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
4718
+ 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
4916
4719
  ' for more information.')
4917
4720
 
4918
4721
 
@@ -4933,9 +4736,13 @@ def CheckGlobalStatic(filename, clean_lines, linenum, error):
4933
4736
 
4934
4737
  # Check for people declaring static/global STL strings at the top level.
4935
4738
  # This is dangerous because the C++ language does not guarantee that
4936
- # globals with constructors are initialized before the first access.
4739
+ # globals with constructors are initialized before the first access, and
4740
+ # also because globals can be destroyed when some threads are still running.
4741
+ # TODO(unknown): Generalize this to also find static unique_ptr instances.
4742
+ # TODO(unknown): File bugs for clang-tidy to find these.
4937
4743
  match = Match(
4938
- r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
4744
+ r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +'
4745
+ r'([a-zA-Z0-9_:]+)\b(.*)',
4939
4746
  line)
4940
4747
 
4941
4748
  # Remove false positives:
@@ -4955,15 +4762,20 @@ def CheckGlobalStatic(filename, clean_lines, linenum, error):
4955
4762
  # matching identifiers.
4956
4763
  # string Class::operator*()
4957
4764
  if (match and
4958
- not Search(r'\bstring\b(\s+const)?\s*\*\s*(const\s+)?\w', line) and
4765
+ not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and
4959
4766
  not Search(r'\boperator\W', line) and
4960
- not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(3))):
4961
- error(filename, linenum, 'runtime/string', 4,
4962
- 'For a static/global string constant, use a C style string instead: '
4963
- '"%schar %s[]".' %
4964
- (match.group(1), match.group(2)))
4767
+ not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))):
4768
+ if Search(r'\bconst\b', line):
4769
+ error(filename, linenum, 'runtime/string', 4,
4770
+ 'For a static/global string constant, use a C style string '
4771
+ 'instead: "%schar%s %s[]".' %
4772
+ (match.group(1), match.group(2) or '', match.group(3)))
4773
+ else:
4774
+ error(filename, linenum, 'runtime/string', 4,
4775
+ 'Static/global string variables are not permitted.')
4965
4776
 
4966
- if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
4777
+ if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or
4778
+ Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)):
4967
4779
  error(filename, linenum, 'runtime/init', 4,
4968
4780
  'You seem to be initializing a member variable with itself.')
4969
4781
 
@@ -5208,7 +5020,8 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
5208
5020
 
5209
5021
  decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body
5210
5022
  for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
5211
- if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter):
5023
+ if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and
5024
+ not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)):
5212
5025
  error(filename, linenum, 'runtime/references', 2,
5213
5026
  'Is this a non-const reference? '
5214
5027
  'If so, make const or use a pointer: ' +
@@ -5231,7 +5044,7 @@ def CheckCasts(filename, clean_lines, linenum, error):
5231
5044
  # Parameterless conversion functions, such as bool(), are allowed as they are
5232
5045
  # probably a member operator declaration or default constructor.
5233
5046
  match = Search(
5234
- r'(\bnew\s+|\S<\s*(?:const\s+)?)?\b'
5047
+ r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b'
5235
5048
  r'(int|float|double|bool|char|int32|uint32|int64|uint64)'
5236
5049
  r'(\([^)].*)', line)
5237
5050
  expecting_function = ExpectingFunctionArgs(clean_lines, linenum)
@@ -5372,63 +5185,12 @@ def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):
5372
5185
  if context.endswith(' operator++') or context.endswith(' operator--'):
5373
5186
  return False
5374
5187
 
5375
- # A single unnamed argument for a function tends to look like old
5376
- # style cast. If we see those, don't issue warnings for deprecated
5377
- # casts, instead issue warnings for unnamed arguments where
5378
- # appropriate.
5379
- #
5380
- # These are things that we want warnings for, since the style guide
5381
- # explicitly require all parameters to be named:
5382
- # Function(int);
5383
- # Function(int) {
5384
- # ConstMember(int) const;
5385
- # ConstMember(int) const {
5386
- # ExceptionMember(int) throw (...);
5387
- # ExceptionMember(int) throw (...) {
5388
- # PureVirtual(int) = 0;
5389
- # [](int) -> bool {
5390
- #
5391
- # These are functions of some sort, where the compiler would be fine
5392
- # if they had named parameters, but people often omit those
5393
- # identifiers to reduce clutter:
5394
- # (FunctionPointer)(int);
5395
- # (FunctionPointer)(int) = value;
5396
- # Function((function_pointer_arg)(int))
5397
- # Function((function_pointer_arg)(int), int param)
5398
- # <TemplateArgument(int)>;
5399
- # <(FunctionPointerTemplateArgument)(int)>;
5188
+ # A single unnamed argument for a function tends to look like old style cast.
5189
+ # If we see those, don't issue warnings for deprecated casts.
5400
5190
  remainder = line[match.end(0):]
5401
5191
  if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)',
5402
5192
  remainder):
5403
- # Looks like an unnamed parameter.
5404
-
5405
- # Don't warn on any kind of template arguments.
5406
- if Match(r'^\s*>', remainder):
5407
- return False
5408
-
5409
- # Don't warn on assignments to function pointers, but keep warnings for
5410
- # unnamed parameters to pure virtual functions. Note that this pattern
5411
- # will also pass on assignments of "0" to function pointers, but the
5412
- # preferred values for those would be "nullptr" or "NULL".
5413
- matched_zero = Match(r'^\s=\s*(\S+)\s*;', remainder)
5414
- if matched_zero and matched_zero.group(1) != '0':
5415
- return False
5416
-
5417
- # Don't warn on function pointer declarations. For this we need
5418
- # to check what came before the "(type)" string.
5419
- if Match(r'.*\)\s*$', line[0:match.start(0)]):
5420
- return False
5421
-
5422
- # Don't warn if the parameter is named with block comments, e.g.:
5423
- # Function(int /*unused_param*/);
5424
- raw_line = clean_lines.raw_lines[linenum]
5425
- if '/*' in raw_line:
5426
- return False
5427
-
5428
- # Passed all filters, issue warning here.
5429
- error(filename, linenum, 'readability/function', 3,
5430
- 'All parameters should be named in a function')
5431
- return True
5193
+ return False
5432
5194
 
5433
5195
  # At this point, all that should be left is actual casts.
5434
5196
  error(filename, linenum, 'readability/casting', 4,
@@ -5557,13 +5319,13 @@ def FilesBelongToSameModule(filename_cc, filename_h):
5557
5319
  string: the additional prefix needed to open the header file.
5558
5320
  """
5559
5321
 
5560
- if not filename_cc.endswith('.cc'):
5322
+ fileinfo = FileInfo(filename_cc)
5323
+ if not fileinfo.IsSource():
5561
5324
  return (False, '')
5562
- filename_cc = filename_cc[:-len('.cc')]
5563
- if filename_cc.endswith('_unittest'):
5564
- filename_cc = filename_cc[:-len('_unittest')]
5565
- elif filename_cc.endswith('_test'):
5566
- filename_cc = filename_cc[:-len('_test')]
5325
+ filename_cc = filename_cc[:-len(fileinfo.Extension())]
5326
+ matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo.BaseName())
5327
+ if matched_test_suffix:
5328
+ filename_cc = filename_cc[:-len(matched_test_suffix.group(1))]
5567
5329
  filename_cc = filename_cc.replace('/public/', '/')
5568
5330
  filename_cc = filename_cc.replace('/internal/', '/')
5569
5331
 
@@ -5727,31 +5489,6 @@ def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
5727
5489
  ' OR use pair directly OR if appropriate, construct a pair directly')
5728
5490
 
5729
5491
 
5730
- def CheckDefaultLambdaCaptures(filename, clean_lines, linenum, error):
5731
- """Check that default lambda captures are not used.
5732
-
5733
- Args:
5734
- filename: The name of the current file.
5735
- clean_lines: A CleansedLines instance containing the file.
5736
- linenum: The number of the line to check.
5737
- error: The function to call with any errors found.
5738
- """
5739
- line = clean_lines.elided[linenum]
5740
-
5741
- # A lambda introducer specifies a default capture if it starts with "[="
5742
- # or if it starts with "[&" _not_ followed by an identifier.
5743
- match = Match(r'^(.*)\[\s*(?:=|&[^\w])', line)
5744
- if match:
5745
- # Found a potential error, check what comes after the lambda-introducer.
5746
- # If it's not open parenthesis (for lambda-declarator) or open brace
5747
- # (for compound-statement), it's not a lambda.
5748
- line, _, pos = CloseExpression(clean_lines, linenum, len(match.group(1)))
5749
- if pos >= 0 and Match(r'^\s*[{(]', line[pos:]):
5750
- error(filename, linenum, 'build/c++11',
5751
- 4, # 4 = high confidence
5752
- 'Default lambda captures are an unapproved C++ feature.')
5753
-
5754
-
5755
5492
  def CheckRedundantVirtual(filename, clean_lines, linenum, error):
5756
5493
  """Check if line contains a redundant "virtual" function-specifier.
5757
5494
 
@@ -5950,7 +5687,6 @@ def ProcessLine(filename, file_extension, clean_lines, line,
5950
5687
  CheckPosixThreading(filename, clean_lines, line, error)
5951
5688
  CheckInvalidIncrement(filename, clean_lines, line, error)
5952
5689
  CheckMakePairUsesDeduction(filename, clean_lines, line, error)
5953
- CheckDefaultLambdaCaptures(filename, clean_lines, line, error)
5954
5690
  CheckRedundantVirtual(filename, clean_lines, line, error)
5955
5691
  CheckRedundantOverrideOrFinal(filename, clean_lines, line, error)
5956
5692
  for check_fn in extra_check_functions:
@@ -5967,8 +5703,14 @@ def FlagCxx11Features(filename, clean_lines, linenum, error):
5967
5703
  """
5968
5704
  line = clean_lines.elided[linenum]
5969
5705
 
5970
- # Flag unapproved C++11 headers.
5971
5706
  include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
5707
+
5708
+ # Flag unapproved C++ TR1 headers.
5709
+ if include and include.group(1).startswith('tr1/'):
5710
+ error(filename, linenum, 'build/c++tr1', 5,
5711
+ ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1))
5712
+
5713
+ # Flag unapproved C++11 headers.
5972
5714
  if include and include.group(1) in ('cfenv',
5973
5715
  'condition_variable',
5974
5716
  'fenv.h',
@@ -6002,6 +5744,25 @@ def FlagCxx11Features(filename, clean_lines, linenum, error):
6002
5744
  'they may let you use it.') % top_name)
6003
5745
 
6004
5746
 
5747
+ def FlagCxx14Features(filename, clean_lines, linenum, error):
5748
+ """Flag those C++14 features that we restrict.
5749
+
5750
+ Args:
5751
+ filename: The name of the current file.
5752
+ clean_lines: A CleansedLines instance containing the file.
5753
+ linenum: The number of the line to check.
5754
+ error: The function to call with any errors found.
5755
+ """
5756
+ line = clean_lines.elided[linenum]
5757
+
5758
+ include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
5759
+
5760
+ # Flag unapproved C++14 headers.
5761
+ if include and include.group(1) in ('scoped_allocator', 'shared_mutex'):
5762
+ error(filename, linenum, 'build/c++14', 5,
5763
+ ('<%s> is an unapproved C++14 header.') % include.group(1))
5764
+
5765
+
6005
5766
  def ProcessFileData(filename, file_extension, lines, error,
6006
5767
  extra_check_functions=[]):
6007
5768
  """Performs lint checks and reports any errors to the given error function.
@@ -6027,7 +5788,7 @@ def ProcessFileData(filename, file_extension, lines, error,
6027
5788
  ResetNolintSuppressions()
6028
5789
 
6029
5790
  CheckForCopyright(filename, lines, error)
6030
-
5791
+ ProcessGlobalSuppresions(lines)
6031
5792
  RemoveMultiLineComments(filename, lines, error)
6032
5793
  clean_lines = CleansedLines(lines)
6033
5794
 
@@ -6044,7 +5805,7 @@ def ProcessFileData(filename, file_extension, lines, error,
6044
5805
  CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
6045
5806
 
6046
5807
  # Check that the .cc file has included its header if it exists.
6047
- if file_extension == 'cc':
5808
+ if _IsSourceExtension(file_extension):
6048
5809
  CheckHeaderFileIncluded(filename, include_state, error)
6049
5810
 
6050
5811
  # We check here rather than inside ProcessLine so that we see raw