libv8 5.0.71.48.3 → 5.1.281.59.0beta3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/ext/libv8/location.rb +12 -9
- data/ext/libv8/patcher.rb +1 -1
- data/ext/libv8/paths.rb +1 -1
- data/lib/libv8/version.rb +1 -1
- data/patches/0001-Build-standalone-static-library.patch +26 -0
- data/patches/{disable-building-tests.patch → 0002-Disable-building-tests.patch} +17 -5
- data/patches/0003-Use-the-fPIC-flag-for-the-static-library.patch +25 -0
- data/spec/location_spec.rb +1 -1
- data/vendor/depot_tools/.gitignore +1 -0
- data/vendor/depot_tools/PRESUBMIT.py +3 -1
- data/vendor/depot_tools/README +1 -6
- data/vendor/depot_tools/apply_issue.py +6 -0
- data/vendor/depot_tools/bootstrap/win/README.md +2 -2
- data/vendor/depot_tools/bootstrap/win/git.template.bat +1 -1
- data/vendor/depot_tools/bootstrap/win/win_tools.bat +12 -11
- data/vendor/depot_tools/codereview.settings +1 -1
- data/vendor/depot_tools/cpplint.py +353 -592
- data/vendor/depot_tools/fetch.py +10 -3
- data/vendor/depot_tools/fetch_configs/infra.py +4 -2
- data/vendor/depot_tools/fetch_configs/ios_internal.py +49 -0
- data/vendor/depot_tools/gclient.py +33 -7
- data/vendor/depot_tools/gclient_scm.py +14 -11
- data/vendor/depot_tools/gclient_utils.py +14 -3
- data/vendor/depot_tools/git-gs +3 -3
- data/vendor/depot_tools/git_cache.py +8 -4
- data/vendor/depot_tools/git_cl.py +221 -98
- data/vendor/depot_tools/git_footers.py +76 -39
- data/vendor/depot_tools/git_map_branches.py +12 -10
- data/vendor/depot_tools/infra/config/cq.cfg +0 -11
- data/vendor/depot_tools/infra/config/recipes.cfg +1 -1
- data/vendor/depot_tools/presubmit_canned_checks.py +31 -19
- data/vendor/depot_tools/presubmit_support.py +0 -13
- data/vendor/depot_tools/recipe_modules/bot_update/resources/bot_update.py +19 -2
- data/vendor/depot_tools/recipe_modules/depot_tools/api.py +4 -0
- data/vendor/depot_tools/recipe_modules/depot_tools/example.expected/basic.json +49 -0
- data/vendor/depot_tools/recipe_modules/depot_tools/example.expected/win.json +49 -0
- data/vendor/depot_tools/recipe_modules/depot_tools/example.py +38 -0
- data/vendor/depot_tools/recipe_modules/gclient/api.py +1 -0
- data/vendor/depot_tools/recipe_modules/gclient/config.py +19 -0
- data/vendor/depot_tools/recipe_modules/gclient/example.expected/basic.json +1 -0
- data/vendor/depot_tools/recipe_modules/gclient/example.expected/revision.json +1 -0
- data/vendor/depot_tools/recipe_modules/gclient/example.expected/tryserver.json +1 -0
- data/vendor/depot_tools/recipe_modules/gclient/example.py +3 -0
- data/vendor/depot_tools/recipe_modules/git_cl/api.py +22 -6
- data/vendor/depot_tools/recipe_modules/git_cl/example.expected/basic.json +27 -9
- data/vendor/depot_tools/recipe_modules/git_cl/example.py +9 -7
- data/vendor/depot_tools/recipe_modules/presubmit/api.py +5 -2
- data/vendor/depot_tools/recipe_modules/tryserver/__init__.py +1 -0
- data/vendor/depot_tools/recipe_modules/tryserver/api.py +31 -0
- data/vendor/depot_tools/recipe_modules/tryserver/example.expected/basic_tags.json +59 -0
- data/vendor/depot_tools/recipe_modules/tryserver/example.expected/with_rietveld_patch.json +26 -0
- data/vendor/depot_tools/recipe_modules/tryserver/example.expected/with_rietveld_patch_new.json +26 -0
- data/vendor/depot_tools/recipe_modules/tryserver/example.py +32 -3
- data/vendor/depot_tools/roll_dep.py +6 -2
- data/vendor/depot_tools/third_party/upload.py +17 -9
- data/vendor/depot_tools/update_depot_tools +11 -0
- data/vendor/depot_tools/update_depot_tools.bat +11 -0
- data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +52 -9
- data/vendor/depot_tools/win_toolchain/package_from_installed.py +64 -57
- metadata +12 -10
- data/patches/build-standalone-static-library.patch +0 -14
- data/patches/fPIC-for-static.patch +0 -13
- data/vendor/depot_tools/git-lkgr +0 -208
- data/vendor/depot_tools/hammer +0 -28
- data/vendor/depot_tools/hammer.bat +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41cbaf11fa4edba84e871c58099ed8243019b2b1
|
|
4
|
+
data.tar.gz: 958c801dae727821359a0004ebac3b35b654e527
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ee57388f66c9f06452560879ab5bc7fec7fb58a76a36eebf36d18de8f25dcd54b0c1eec391dbfb50d1cae63a7bc898a7fc91121bd704a6bd341499d2c72a48f
|
|
7
|
+
data.tar.gz: 3837b26a28511330199c8f31e1296ff6d1eab8bd018415b606e53cb9e1978e7eec059ef932f10600a4514cb5937f0e2efcff4a75887bd2e848768b46bc03f854
|
data/CHANGELOG.md
CHANGED
data/ext/libv8/location.rb
CHANGED
|
@@ -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('
|
|
37
|
-
fail HeaderNotFound, "Unable to locate '
|
|
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
|
data/ext/libv8/patcher.rb
CHANGED
|
@@ -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|
|
data/ext/libv8/paths.rb
CHANGED
data/lib/libv8/version.rb
CHANGED
|
@@ -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
|
|
12
|
+
index a0c08a6..10b2924 100644
|
|
3
13
|
--- a/Makefile
|
|
4
14
|
+++ b/Makefile
|
|
5
|
-
@@ -
|
|
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
|
-
|
|
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
|
+
|
data/spec/location_spec.rb
CHANGED
|
@@ -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
|
|
@@ -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()]
|
data/vendor/depot_tools/README
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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.
|
|
@@ -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
|
|
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 %
|
|
41
|
-
cscript //nologo //e:jscript "%~dp0get_file.js" %
|
|
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 %
|
|
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.
|
|
71
|
+
set GIT_VERSION=2.8.3
|
|
71
72
|
) else (
|
|
72
|
-
set GIT_VERSION=2.8.
|
|
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
|
|
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 %
|
|
195
|
-
cscript //nologo //e:jscript "%~dp0get_file.js" %
|
|
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 %
|
|
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:
|
|
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
|
-
|
|
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.
|
|
408
|
-
# for substring matching to work.
|
|
439
|
+
# testing/base/public/gunit.h.
|
|
409
440
|
_CHECK_MACROS = [
|
|
410
441
|
'DCHECK', 'CHECK',
|
|
411
|
-
'
|
|
412
|
-
'
|
|
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 (
|
|
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:]
|
|
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
|
-
|
|
1208
|
-
|
|
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
|
-
|
|
1854
|
+
fileinfo = FileInfo(filename)
|
|
1855
|
+
if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()):
|
|
1780
1856
|
return
|
|
1781
1857
|
|
|
1782
|
-
|
|
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+' +
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
3178
|
-
#
|
|
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
|
|
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
|
|
3330
|
-
#
|
|
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
|
-
|
|
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_]
|
|
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
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
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
|
-
|
|
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
|
-
'
|
|
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 +
|
|
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
|
|
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(
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
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
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
5322
|
+
fileinfo = FileInfo(filename_cc)
|
|
5323
|
+
if not fileinfo.IsSource():
|
|
5561
5324
|
return (False, '')
|
|
5562
|
-
filename_cc = filename_cc[:-len(
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
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
|
|
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
|