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.
- 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
|