blob: a8a87612431ce1eb0b8e635b788800ce8f4ac420 [file] [log] [blame]
Ryan Macnakfd032192022-03-21 20:45:12 +00001#!/usr/bin/env python3
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002#
erg@google.com26970fa2009-11-17 18:07:32 +00003# Copyright (c) 2009 Google Inc. All rights reserved.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004#
erg@google.com26970fa2009-11-17 18:07:32 +00005# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00008#
erg@google.com26970fa2009-11-17 18:07:32 +00009# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000018#
erg@google.com26970fa2009-11-17 18:07:32 +000019# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000030
agablef39c3332016-09-26 09:35:42 -070031# pylint: skip-file
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000032"""Does google-lint on c++ files.
33
34The goal of this script is to identify places in the code that *may*
35be in non-compliance with google style. It does not attempt to fix
36up these problems -- the point is to educate. It does also not
37attempt to find all problems, or to ensure that everything it does
38find is legitimately a problem.
39
40In particular, we can get very confused by /* and // inside strings!
41We do a small hack, which is to ignore //'s with "'s after them on the
42same line, but it is far from perfect (in either direction).
43"""
44
45import codecs
mazda@chromium.org3fffcec2013-06-07 01:04:53 +000046import copy
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000047import getopt
48import math # for log
49import os
50import re
51import sre_compile
52import string
53import sys
54import unicodedata
55
Edward Lemur6d31ed52019-12-02 23:00:00 +000056_USAGE = r"""
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000057Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +000058 [--counting=total|toplevel|detailed] [--root=subdir]
Sergiy Byelozyorov7999d922018-06-22 09:25:54 +000059 [--linelength=digits]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000060 <file> [file] ...
61
62 The style guidelines this tries to follow are those in
Alexandr Ilinff294c32017-04-27 15:57:40 +020063 https://google.github.io/styleguide/cppguide.html
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000064
65 Every problem is given a confidence score from 1-5, with 5 meaning we are
66 certain of the problem, and 1 meaning it could be a legitimate construct.
67 This will miss some errors, and is not a substitute for a code review.
68
erg@google.com35589e62010-11-17 18:58:16 +000069 To suppress false-positive errors of a certain category, add a
70 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*)
71 suppresses errors of all categories on that line.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000072
73 The files passed in will be linted; at least one file must be provided.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +000074 Default linted extensions are .cc, .cpp, .cu, .cuh and .h. Change the
75 extensions with the --extensions flag.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +000076
77 Flags:
78
79 output=vs7
80 By default, the output is formatted to ease emacs parsing. Visual Studio
81 compatible output (vs7) may also be used. Other formats are unsupported.
82
83 verbose=#
84 Specify a number 0-5 to restrict errors to certain verbosity levels.
85
86 filter=-x,+y,...
87 Specify a comma-separated list of category-filters to apply: only
88 error messages whose category names pass the filters will be printed.
89 (Category names are printed with the message and look like
90 "[whitespace/indent]".) Filters are evaluated left to right.
91 "-FOO" and "FOO" means "do not print categories that start with FOO".
92 "+FOO" means "do print categories that start with FOO".
93
94 Examples: --filter=-whitespace,+whitespace/braces
95 --filter=whitespace,runtime/printf,+runtime/printf_format
96 --filter=-,+build/include_what_you_use
97
98 To see a list of all the categories used in cpplint, pass no arg:
99 --filter=
erg@google.com26970fa2009-11-17 18:07:32 +0000100
101 counting=total|toplevel|detailed
102 The total number of errors found is always printed. If
103 'toplevel' is provided, then the count of errors in each of
104 the top-level categories like 'build' and 'whitespace' will
105 also be printed. If 'detailed' is provided, then a count
106 is provided for each category like 'build/class'.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000107
108 root=subdir
109 The root directory used for deriving header guard CPP variable.
110 By default, the header guard CPP variable is calculated as the relative
111 path to the directory that contains .git, .hg, or .svn. When this flag
112 is specified, the relative path is calculated from the specified
113 directory. If the specified directory does not exist, this flag is
114 ignored.
115
116 Examples:
Sergiy Byelozyorov7999d922018-06-22 09:25:54 +0000117 Assuming that src/.git exists, the header guard CPP variables for
118 src/chrome/browser/ui/browser.h are:
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000119
120 No flag => CHROME_BROWSER_UI_BROWSER_H_
121 --root=chrome => BROWSER_UI_BROWSER_H_
122 --root=chrome/browser => UI_BROWSER_H_
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000123
124 linelength=digits
125 This is the allowed line length for the project. The default value is
126 80 characters.
127
128 Examples:
129 --linelength=120
130
131 extensions=extension,extension,...
132 The allowed file extensions that cpplint will check
133
134 Examples:
135 --extensions=hpp,cpp
avakulenko@google.com17449932014-07-28 22:13:33 +0000136
137 cpplint.py supports per-directory configurations specified in CPPLINT.cfg
138 files. CPPLINT.cfg file can contain a number of key=value pairs.
139 Currently the following options are supported:
140
141 set noparent
142 filter=+filter1,-filter2,...
143 exclude_files=regex
avakulenko@google.com68a4fa62014-08-25 16:26:18 +0000144 linelength=80
avakulenko@google.com17449932014-07-28 22:13:33 +0000145
146 "set noparent" option prevents cpplint from traversing directory tree
147 upwards looking for more .cfg files in parent directories. This option
148 is usually placed in the top-level project directory.
149
150 The "filter" option is similar in function to --filter flag. It specifies
151 message filters in addition to the |_DEFAULT_FILTERS| and those specified
152 through --filter command-line flag.
153
154 "exclude_files" allows to specify a regular expression to be matched against
155 a file name. If the expression matches, the file is skipped and not run
156 through liner.
157
avakulenko@google.com68a4fa62014-08-25 16:26:18 +0000158 "linelength" allows to specify the allowed line length for the project.
159
avakulenko@google.com17449932014-07-28 22:13:33 +0000160 CPPLINT.cfg has an effect on files in the same directory and all
161 sub-directories, unless overridden by a nested configuration file.
162
163 Example file:
164 filter=-build/include_order,+build/include_alpha
165 exclude_files=.*\.cc
166
167 The above example disables build/include_order warning and enables
168 build/include_alpha as well as excludes all .cc from being
169 processed by linter, in the current directory (where the .cfg
170 file is located) and all sub-directories.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000171"""
172
173# We categorize each error message we print. Here are the categories.
174# We want an explicit list so we can list them all in cpplint --filter=.
175# If you add a new error message with a new category, add it to the list
176# here! cpplint_unittest.py should tell you if you forget to do this.
erg@google.com35589e62010-11-17 18:58:16 +0000177_ERROR_CATEGORIES = [
avakulenko@google.com255f2be2014-12-05 22:19:55 +0000178 'build/class',
179 'build/c++11',
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000180 'build/c++14',
181 'build/c++tr1',
avakulenko@google.com255f2be2014-12-05 22:19:55 +0000182 'build/deprecated',
183 'build/endif_comment',
184 'build/explicit_make_pair',
185 'build/forward_decl',
186 'build/header_guard',
187 'build/include',
188 'build/include_alpha',
Fletcher Woodruff11b34152020-04-23 21:21:40 +0000189 'build/include_directory',
avakulenko@google.com255f2be2014-12-05 22:19:55 +0000190 'build/include_order',
191 'build/include_what_you_use',
192 'build/namespaces',
193 'build/printf_format',
194 'build/storage_class',
195 'legal/copyright',
196 'readability/alt_tokens',
197 'readability/braces',
198 'readability/casting',
199 'readability/check',
200 'readability/constructors',
201 'readability/fn_size',
avakulenko@google.com255f2be2014-12-05 22:19:55 +0000202 'readability/inheritance',
203 'readability/multiline_comment',
204 'readability/multiline_string',
205 'readability/namespace',
206 'readability/nolint',
207 'readability/nul',
208 'readability/strings',
209 'readability/todo',
210 'readability/utf8',
211 'runtime/arrays',
212 'runtime/casting',
213 'runtime/explicit',
214 'runtime/int',
215 'runtime/init',
216 'runtime/invalid_increment',
217 'runtime/member_string_references',
218 'runtime/memset',
219 'runtime/indentation_namespace',
220 'runtime/operator',
221 'runtime/printf',
222 'runtime/printf_format',
223 'runtime/references',
224 'runtime/string',
225 'runtime/threadsafe_fn',
226 'runtime/vlog',
227 'whitespace/blank_line',
228 'whitespace/braces',
229 'whitespace/comma',
230 'whitespace/comments',
231 'whitespace/empty_conditional_body',
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000232 'whitespace/empty_if_body',
avakulenko@google.com255f2be2014-12-05 22:19:55 +0000233 'whitespace/empty_loop_body',
234 'whitespace/end_of_line',
235 'whitespace/ending_newline',
236 'whitespace/forcolon',
237 'whitespace/indent',
238 'whitespace/line_length',
239 'whitespace/newline',
240 'whitespace/operators',
241 'whitespace/parens',
242 'whitespace/semicolon',
243 'whitespace/tab',
244 'whitespace/todo',
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000245]
avakulenko@google.com255f2be2014-12-05 22:19:55 +0000246
247# These error categories are no longer enforced by cpplint, but for backwards-
248# compatibility they may still appear in NOLINT comments.
249_LEGACY_ERROR_CATEGORIES = [
250 'readability/streams',
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000251 'readability/function',
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000252]
erg@google.com6317a9c2009-06-25 00:28:19 +0000253
avakulenko@google.comd39bbb52014-06-04 22:55:20 +0000254# The default state of the category filter. This is overridden by the --filter=
erg@google.com6317a9c2009-06-25 00:28:19 +0000255# flag. By default all errors are on, so only add here categories that should be
256# off by default (i.e., categories that must be enabled by the --filter= flags).
257# All entries here should start with a '-' or '+', as in the --filter= flag.
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +0000258_DEFAULT_FILTERS = ['-build/include_alpha']
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000259
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000260# The default list of categories suppressed for C (not C++) files.
261_DEFAULT_C_SUPPRESSED_CATEGORIES = [
262 'readability/casting',
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000263]
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000264
265# The default list of categories suppressed for Linux Kernel files.
266_DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [
267 'whitespace/tab',
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000268]
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000269
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000270# We used to check for high-bit characters, but after much discussion we
271# decided those were OK, as long as they were in UTF-8 and didn't represent
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +0000272# hard-coded international strings, which belong in a separate i18n file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000273
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000274# C++ headers
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000275_CPP_HEADERS = frozenset([
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000276 # Legacy
277 'algobase.h',
278 'algo.h',
279 'alloc.h',
280 'builtinbuf.h',
281 'bvector.h',
282 'complex.h',
283 'defalloc.h',
284 'deque.h',
285 'editbuf.h',
286 'fstream.h',
287 'function.h',
288 'hash_map',
289 'hash_map.h',
290 'hash_set',
291 'hash_set.h',
292 'hashtable.h',
293 'heap.h',
294 'indstream.h',
295 'iomanip.h',
296 'iostream.h',
297 'istream.h',
298 'iterator.h',
299 'list.h',
300 'map.h',
301 'multimap.h',
302 'multiset.h',
303 'ostream.h',
304 'pair.h',
305 'parsestream.h',
306 'pfstream.h',
307 'procbuf.h',
308 'pthread_alloc',
309 'pthread_alloc.h',
310 'rope',
311 'rope.h',
312 'ropeimpl.h',
313 'set.h',
314 'slist',
315 'slist.h',
316 'stack.h',
317 'stdiostream.h',
318 'stl_alloc.h',
319 'stl_relops.h',
320 'streambuf.h',
321 'stream.h',
322 'strfile.h',
323 'strstream.h',
324 'tempbuf.h',
325 'tree.h',
326 'type_traits.h',
327 'vector.h',
328 # 17.6.1.2 C++ library headers
329 'algorithm',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000330 'any',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000331 'array',
332 'atomic',
333 'bitset',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000334 'charconv',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000335 'chrono',
336 'codecvt',
337 'complex',
338 'condition_variable',
339 'deque',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000340 'execution',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000341 'exception',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000342 'filesystem',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000343 'forward_list',
344 'fstream',
345 'functional',
346 'future',
347 'initializer_list',
348 'iomanip',
349 'ios',
350 'iosfwd',
351 'iostream',
352 'istream',
353 'iterator',
354 'limits',
355 'list',
356 'locale',
357 'map',
358 'memory',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000359 'memory_resource',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000360 'mutex',
361 'new',
362 'numeric',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000363 'optional',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000364 'ostream',
365 'queue',
366 'random',
367 'ratio',
368 'regex',
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000369 'scoped_allocator',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000370 'set',
371 'sstream',
372 'stack',
373 'stdexcept',
374 'streambuf',
375 'string',
Jasper Chapman-Black9ab047e2019-11-07 15:51:54 +0000376 'string_view',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000377 'strstream',
378 'system_error',
379 'thread',
380 'tuple',
381 'typeindex',
382 'typeinfo',
383 'type_traits',
384 'unordered_map',
385 'unordered_set',
386 'utility',
387 'valarray',
dan sinclair9a3c4bc2022-06-17 22:58:24 +0000388 'variant',
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000389 'vector',
390 # 17.6.1.2 C++ headers for C library facilities
391 'cassert',
392 'ccomplex',
393 'cctype',
394 'cerrno',
395 'cfenv',
396 'cfloat',
397 'cinttypes',
398 'ciso646',
399 'climits',
400 'clocale',
401 'cmath',
402 'csetjmp',
403 'csignal',
404 'cstdalign',
405 'cstdarg',
406 'cstdbool',
407 'cstddef',
408 'cstdint',
409 'cstdio',
410 'cstdlib',
411 'cstring',
412 'ctgmath',
413 'ctime',
414 'cuchar',
415 'cwchar',
416 'cwctype',
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000417])
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000418
Peter Kasting00741582023-02-16 20:09:51 +0000419# List of functions from <type_traits>. See [meta.type.synop]
420_TYPE_TRAITS = [
421 # 23.15.3, helper class
422 'integral_constant',
423 # 23.15.4.1, primary type categories
424 'is_void',
425 'is_null_pointer',
426 'is_integral',
427 'is_floating_point',
428 'is_array',
429 'is_pointer',
430 'is_lvalue_reference',
431 'is_rvalue_reference',
432 'is_member_object_pointer',
433 'is_member_function_pointer',
434 'is_enum',
435 'is_union',
436 'is_class',
437 'is_function',
438 # 23.15.4.2, composite type categories
439 'is_reference',
440 'is_arithmetic',
441 'is_fundamental',
442 'is_object',
443 'is_scalar',
444 'is_compound',
445 'is_member_pointer',
446 # 23.15.4.3, type properties
447 'is_const',
448 'is_volatile',
449 'is_trivial',
450 'is_trivially_copyable',
451 'is_standard_layout',
452 'is_pod',
453 'is_empty',
454 'is_polymorphic',
455 'is_abstract',
456 'is_final',
457 'is_aggregate',
458 'is_signed',
459 'is_unsigned',
460 'is_constructible',
461 'is_default_constructible',
462 'is_copy_constructible',
463 'is_move_constructible',
464 'is_assignable',
465 'is_copy_assignable',
466 'is_move_assignable',
467 'is_swappable_with',
468 'is_swappable',
469 'is_destructible',
470 'is_trivially_constructible',
471 'is_trivially_default_constructible',
472 'is_trivially_copy_constructible',
473 'is_trivially_move_constructible',
474 'is_trivially_assignable',
475 'is_trivially_copy_assignable',
476 'is_trivially_move_assignable',
477 'is_trivially_destructible',
478 'is_nothrow_constructible',
479 'is_nothrow_default_constructible',
480 'is_nothrow_copy_constructible',
481 'is_nothrow_move_constructible',
482 'is_nothrow_assignable',
483 'is_nothrow_copy_assignable',
484 'is_nothrow_move_assignable',
485 'is_nothrow_swappable_with',
486 'is_nothrow_swappable',
487 'is_nothrow_destructible',
488 'has_virtual_destructor',
489 'has_unique_object_representations',
490 # 23.15.5, type property queries
491 'alignment_of',
492 'rank',
493 'extent',
494 # 23.15.6, type relations
495 'is_same',
496 'is_base_of',
497 'is_convertible',
498 'is_invocable',
499 'is_invocable_r',
500 'is_nothrow_invocable',
501 'is_nothrow_invocable_r',
502 # 23.15.7.1, const-volatile modifications
503 'remove_const',
504 'remove_volatile',
505 'remove_cv',
506 'add_const',
507 'add_volatile',
508 'add_cv',
509 'remove_const_t',
510 'remove_volatile_t',
511 'remove_cv_t',
512 'add_const_t',
513 'add_volatile_t',
514 'add_cv_t',
515 # 23.15.7.2, reference modifications
516 'remove_reference',
517 'add_lvalue_reference',
518 'add_rvalue_reference',
519 'remove_reference_t',
520 'add_lvalue_reference_t',
521 'add_rvalue_reference_t',
522 # 23.15.7.3, sign modifications
523 'make_signed',
524 'make_unsigned',
525 'make_signed_t',
526 'make_unsigned_t',
527 # 23.15.7.4, array modifications
528 'remove_extent',
529 'remove_all_extents',
530 'remove_extent_t',
531 'remove_all_extents_t',
532 # 23.15.7.5, pointer modifications
533 'remove_pointer',
534 'add_pointer',
535 'remove_pointer_t',
536 'add_pointer_t',
537 # 23.15.7.6, other transformations
538 'aligned_storage',
539 'aligned_union',
540 'decay',
541 'enable_if',
542 'conditional',
543 'common_type',
544 'underlying_type',
545 'invoke_result',
546 'aligned_storage_t',
547 'aligned_union_t',
548 'decay_t',
549 'enable_if_t',
550 'conditional_t',
551 'common_type_t',
552 'underlying_type_t',
553 'invoke_result_t',
554 'void_t',
555 # 23.15.8, logical operator traits
556 'conjunction',
557 'disjunction',
558 'negation',
559 # 23.15.4.1, primary type categories
560 'is_void_v',
561 'is_null_pointer_v',
562 'is_integral_v',
563 'is_floating_point_v',
564 'is_array_v',
565 'is_pointer_v',
566 'is_lvalue_reference_v',
567 'is_rvalue_reference_v',
568 'is_member_object_pointer_v',
569 'is_member_function_pointer_v',
570 'is_enum_v',
571 'is_union_v',
572 'is_class_v',
573 'is_function_v',
574 # 23.15.4.2, composite type categories
575 'is_reference_v',
576 'is_arithmetic_v',
577 'is_fundamental_v',
578 'is_object_v',
579 'is_scalar_v',
580 'is_compound_v',
581 'is_member_pointer_v',
582 # 23.15.4.3, type properties
583 'is_const_v',
584 'is_volatile_v',
585 'is_trivial_v',
586 'is_trivially_copyable_v',
587 'is_standard_layout_v',
588 'is_pod_v',
589 'is_empty_v',
590 'is_polymorphic_v',
591 'is_abstract_v',
592 'is_final_v',
593 'is_aggregate_v',
594 'is_signed_v',
595 'is_unsigned_v',
596 'is_constructible_v',
597 'is_default_constructible_v',
598 'is_copy_constructible_v',
599 'is_move_constructible_v',
600 'is_assignable_v',
601 'is_copy_assignable_v',
602 'is_move_assignable_v',
603 'is_swappable_with_v',
604 'is_swappable_v',
605 'is_destructible_v',
606 'is_trivially_constructible_v',
607 'is_trivially_default_constructible_v',
608 'is_trivially_copy_constructible_v',
609 'is_trivially_move_constructible_v',
610 'is_trivially_assignable_v',
611 'is_trivially_copy_assignable_v',
612 'is_trivially_move_assignable_v',
613 'is_trivially_destructible_v',
614 'is_nothrow_constructible_v',
615 'is_nothrow_default_constructible_v',
616 'is_nothrow_copy_constructible_v',
617 'is_nothrow_move_constructible_v',
618 'is_nothrow_assignable_v',
619 'is_nothrow_copy_assignable_v',
620 'is_nothrow_move_assignable_v',
621 'is_nothrow_swappable_with_v',
622 'is_nothrow_swappable_v',
623 'is_nothrow_destructible_v',
624 'has_virtual_destructor_v',
625 'has_unique_object_representations_v',
626 # 23.15.5, type property queries
627 'alignment_of_v',
628 'rank_v',
629 'extent_v',
630 'is_same_v',
631 'is_base_of_v',
632 'is_convertible_v',
633 'is_invocable_v',
634 'is_invocable_r_v',
635 'is_nothrow_invocable_v',
636 'is_nothrow_invocable_r_v',
637 # 23.15.8, logical operator traits
638 'conjunction_v',
639 'disjunction_v',
640 'negation_v',
641]
642_TYPE_TRAITS_RE = re.compile(r'\b::(?:' + ('|'.join(_TYPE_TRAITS)) + ')<')
643
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000644# Type names
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000645_TYPES = re.compile(r'^(?:'
646 # [dcl.type.simple]
647 r'(char(16_t|32_t)?)|wchar_t|'
648 r'bool|short|int|long|signed|unsigned|float|double|'
649 # [support.types]
650 r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|'
651 # [cstdint.syn]
652 r'(u?int(_fast|_least)?(8|16|32|64)_t)|'
653 r'(u?int(max|ptr)_t)|'
654 r')$')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +0000655
Fletcher Woodruff11b34152020-04-23 21:21:40 +0000656# These headers are excluded from [build/include], [build/include_directory],
657# and [build/include_order] checks:
avakulenko@google.com59146752014-08-11 20:20:55 +0000658# - Anything not following google file name conventions (containing an
659# uppercase character, such as Python.h or nsStringAPI.h, for example).
660# - Lua headers.
661_THIRD_PARTY_HEADERS_PATTERN = re.compile(
662 r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
663
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000664# Pattern for matching FileInfo.BaseName() against test file name
665_TEST_FILE_SUFFIX = r'(_test|_unittest|_regtest)$'
666
667# Pattern that matches only complete whitespace, possibly across multiple lines.
668_EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL)
avakulenko@google.com59146752014-08-11 20:20:55 +0000669
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000670# Assertion macros. These are defined in base/logging.h and
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000671# testing/base/public/gunit.h.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000672_CHECK_MACROS = [
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000673 'DCHECK',
674 'CHECK',
675 'EXPECT_TRUE',
676 'ASSERT_TRUE',
677 'EXPECT_FALSE',
678 'ASSERT_FALSE',
679]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000680
erg@google.com6317a9c2009-06-25 00:28:19 +0000681# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000682_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
683
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000684for op, replacement in [('==', 'EQ'), ('!=', 'NE'), ('>=', 'GE'), ('>', 'GT'),
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000685 ('<=', 'LE'), ('<', 'LT')]:
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000686 _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
687 _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
688 _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
689 _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000690
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000691for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), ('>=', 'LT'),
692 ('>', 'LE'), ('<=', 'GT'), ('<', 'GE')]:
693 _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
694 _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000695
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000696# Alternative tokens and their replacements. For full list, see section 2.5
697# Alternative tokens [lex.digraph] in the C++ standard.
698#
699# Digraphs (such as '%:') are not included here since it's a mess to
700# match those on a word boundary.
701_ALT_TOKEN_REPLACEMENT = {
702 'and': '&&',
703 'bitor': '|',
704 'or': '||',
705 'xor': '^',
706 'compl': '~',
707 'bitand': '&',
708 'and_eq': '&=',
709 'or_eq': '|=',
710 'xor_eq': '^=',
711 'not': '!',
712 'not_eq': '!='
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000713}
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000714
715# Compile regular expression that matches all the above keywords. The "[ =()]"
716# bit is meant to avoid matching these keywords outside of boolean expressions.
717#
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000718# False positives include C-style multi-line comments and multi-line strings
719# but those have always been troublesome for cpplint.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000720_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
721 r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
722
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000723# These constants define types of headers for use with
724# _IncludeState.CheckNextIncludeOrder().
725_C_SYS_HEADER = 1
726_CPP_SYS_HEADER = 2
727_LIKELY_MY_HEADER = 3
728_POSSIBLE_MY_HEADER = 4
729_OTHER_HEADER = 5
730
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000731# These constants define the current inline assembly state
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000732_NO_ASM = 0 # Outside of inline assembly block
733_INSIDE_ASM = 1 # Inside inline assembly block
734_END_ASM = 2 # Last line of inline assembly block
735_BLOCK_ASM = 3 # The whole block is an inline assembly block
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000736
737# Match start of assembly blocks
738_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
739 r'(?:\s+(volatile|__volatile__))?'
740 r'\s*[{(]')
741
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000742# Match strings that indicate we're working on a C (not C++) file.
743_SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|'
744 r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))')
745
746# Match string that indicates we're working on a Linux Kernel file.
747_SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000748
749_regexp_compile_cache = {}
750
erg@google.com35589e62010-11-17 18:58:16 +0000751# {str, set(int)}: a map from error categories to sets of linenumbers
752# on which those errors are expected and should be suppressed.
753_error_suppressions = {}
754
mazda@chromium.org3fffcec2013-06-07 01:04:53 +0000755# The root directory used for deriving header guard CPP variable.
756# This is set by --root flag.
757_root = None
David Sanders2f988472022-05-21 01:35:11 +0000758_root_debug = False
Sergiy Byelozyorov7999d922018-06-22 09:25:54 +0000759
760# The project root directory. Used for deriving header guard CPP variable.
761# This is set by --project_root flag. Must be an absolute path.
762_project_root = None
sdefresne263e9282016-07-19 02:14:22 -0700763
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000764# The allowed line length of files.
765# This is set by --linelength flag.
766_line_length = 80
767
768# The allowed extensions for file names
769# This is set by --extensions flag.
770_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
771
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000772# {str, bool}: a map from error categories to booleans which indicate if the
773# category should be suppressed for every line.
774_global_error_suppressions = {}
775
776
erg@google.com35589e62010-11-17 18:58:16 +0000777def ParseNolintSuppressions(filename, raw_line, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000778 """Updates the global list of line error-suppressions.
erg@google.com35589e62010-11-17 18:58:16 +0000779
780 Parses any NOLINT comments on the current line, updating the global
781 error_suppressions store. Reports an error if the NOLINT comment
782 was malformed.
783
784 Args:
785 filename: str, the name of the input file.
786 raw_line: str, the line of input text, with comments.
787 linenum: int, the number of the current line.
788 error: function, an error handler.
789 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000790 matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)
791 if matched:
792 if matched.group(1):
793 suppressed_line = linenum + 1
794 else:
795 suppressed_line = linenum
796 category = matched.group(2)
797 if category in (None, '(*)'): # => "suppress all"
798 _error_suppressions.setdefault(None, set()).add(suppressed_line)
799 else:
800 if category.startswith('(') and category.endswith(')'):
801 category = category[1:-1]
802 if category in _ERROR_CATEGORIES:
803 _error_suppressions.setdefault(category,
804 set()).add(suppressed_line)
805 elif category not in _LEGACY_ERROR_CATEGORIES:
806 error(filename, linenum, 'readability/nolint', 5,
807 'Unknown NOLINT error category: %s' % category)
erg@google.com35589e62010-11-17 18:58:16 +0000808
809
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000810def ProcessGlobalSuppresions(lines):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000811 """Updates the list of global error suppressions.
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000812
813 Parses any lint directives in the file that have global effect.
814
815 Args:
816 lines: An array of strings, each representing a line of the file, with the
817 last element being empty if the file is terminated with a newline.
818 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000819 for line in lines:
820 if _SEARCH_C_FILE.search(line):
821 for category in _DEFAULT_C_SUPPRESSED_CATEGORIES:
822 _global_error_suppressions[category] = True
823 if _SEARCH_KERNEL_FILE.search(line):
824 for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES:
825 _global_error_suppressions[category] = True
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000826
827
erg@google.com35589e62010-11-17 18:58:16 +0000828def ResetNolintSuppressions():
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000829 """Resets the set of NOLINT suppressions to empty."""
830 _error_suppressions.clear()
831 _global_error_suppressions.clear()
erg@google.com35589e62010-11-17 18:58:16 +0000832
833
834def IsErrorSuppressedByNolint(category, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000835 """Returns true if the specified error category is suppressed on this line.
erg@google.com35589e62010-11-17 18:58:16 +0000836
837 Consults the global error_suppressions map populated by
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000838 ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions.
erg@google.com35589e62010-11-17 18:58:16 +0000839
840 Args:
841 category: str, the category of the error.
842 linenum: int, the current line number.
843 Returns:
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000844 bool, True iff the error should be suppressed due to a NOLINT comment or
845 global suppression.
erg@google.com35589e62010-11-17 18:58:16 +0000846 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000847 return (_global_error_suppressions.get(category, False)
848 or linenum in _error_suppressions.get(category, set())
849 or linenum in _error_suppressions.get(None, set()))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000850
avakulenko@google.comd39bbb52014-06-04 22:55:20 +0000851
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000852def Match(pattern, s):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000853 """Matches the string with the pattern, caching the compiled regexp."""
854 # The regexp compilation caching is inlined in both Match and Search for
855 # performance reasons; factoring it out into a separate function turns out
856 # to be noticeably expensive.
857 if pattern not in _regexp_compile_cache:
858 _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
859 return _regexp_compile_cache[pattern].match(s)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000860
861
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000862def ReplaceAll(pattern, rep, s):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000863 """Replaces instances of pattern in a string with a replacement.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000864
865 The compiled regex is kept in a cache shared by Match and Search.
866
867 Args:
868 pattern: regex pattern
869 rep: replacement text
870 s: search string
871
872 Returns:
873 string with replacements made (or original string if no replacements)
874 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000875 if pattern not in _regexp_compile_cache:
876 _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
877 return _regexp_compile_cache[pattern].sub(rep, s)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000878
879
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000880def Search(pattern, s):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000881 """Searches the string for the pattern, caching the compiled regexp."""
882 if pattern not in _regexp_compile_cache:
883 _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
884 return _regexp_compile_cache[pattern].search(s)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000885
886
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000887def _IsSourceExtension(s):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000888 """File extension (excluding dot) matches a source file extension."""
889 return s in ('c', 'cc', 'cpp', 'cxx')
avakulenko@chromium.org764ce712016-05-06 23:03:41 +0000890
891
avakulenko@google.com59146752014-08-11 20:20:55 +0000892class _IncludeState(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000893 """Tracks line numbers for includes, and the order in which includes appear.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000894
avakulenko@google.com59146752014-08-11 20:20:55 +0000895 include_list contains list of lists of (header, line number) pairs.
896 It's a lists of lists rather than just one flat list to make it
897 easier to update across preprocessor boundaries.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000898
899 Call CheckNextIncludeOrder() once for each header in the file, passing
900 in the type constants defined above. Calls in an illegal order will
901 raise an _IncludeError with an appropriate error message.
902
903 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000904 # self._section will move monotonically through this set. If it ever
905 # needs to move backwards, CheckNextIncludeOrder will raise an error.
906 _INITIAL_SECTION = 0
907 _MY_H_SECTION = 1
908 _C_SECTION = 2
909 _CPP_SECTION = 3
910 _OTHER_H_SECTION = 4
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000911
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000912 _TYPE_NAMES = {
913 _C_SYS_HEADER: 'C system header',
914 _CPP_SYS_HEADER: 'C++ system header',
915 _LIKELY_MY_HEADER: 'header this file implements',
916 _POSSIBLE_MY_HEADER: 'header this file may implement',
917 _OTHER_HEADER: 'other header',
918 }
919 _SECTION_NAMES = {
920 _INITIAL_SECTION: "... nothing. (This can't be an error.)",
921 _MY_H_SECTION: 'a header this file implements',
922 _C_SECTION: 'C system header',
923 _CPP_SECTION: 'C++ system header',
924 _OTHER_H_SECTION: 'other header',
925 }
maruel@google.comfb2b8eb2009-04-23 21:03:42 +0000926
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000927 def __init__(self):
928 self.include_list = [[]]
929 self.ResetSection('')
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000930
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000931 def FindHeader(self, header):
932 """Check if a header has already been included.
avakulenko@google.com59146752014-08-11 20:20:55 +0000933
934 Args:
935 header: header to check.
936 Returns:
937 Line number of previous occurrence, or -1 if the header has not
938 been seen before.
939 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000940 for section_list in self.include_list:
941 for f in section_list:
942 if f[0] == header:
943 return f[1]
944 return -1
avakulenko@google.com59146752014-08-11 20:20:55 +0000945
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000946 def ResetSection(self, directive):
947 """Reset section checking for preprocessor directive.
avakulenko@google.com59146752014-08-11 20:20:55 +0000948
949 Args:
950 directive: preprocessor directive (e.g. "if", "else").
951 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000952 # The name of the current section.
953 self._section = self._INITIAL_SECTION
954 # The path of last found header.
955 self._last_header = ''
erg@google.com26970fa2009-11-17 18:07:32 +0000956
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000957 # Update list of includes. Note that we never pop from the
958 # include list.
959 if directive in ('if', 'ifdef', 'ifndef'):
960 self.include_list.append([])
961 elif directive in ('else', 'elif'):
962 self.include_list[-1] = []
avakulenko@google.com59146752014-08-11 20:20:55 +0000963
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000964 def SetLastHeader(self, header_path):
965 self._last_header = header_path
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000966
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000967 def CanonicalizeAlphabeticalOrder(self, header_path):
968 """Returns a path canonicalized for alphabetical comparison.
erg@google.com26970fa2009-11-17 18:07:32 +0000969
970 - replaces "-" with "_" so they both cmp the same.
971 - removes '-inl' since we don't require them to be after the main header.
972 - lowercase everything, just in case.
973
974 Args:
975 header_path: Path to be canonicalized.
976
977 Returns:
978 Canonicalized path.
979 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000980 return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
erg@google.com26970fa2009-11-17 18:07:32 +0000981
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000982 def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path):
983 """Check if a header is in alphabetical order with the previous header.
erg@google.com26970fa2009-11-17 18:07:32 +0000984
985 Args:
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +0000986 clean_lines: A CleansedLines instance containing the file.
987 linenum: The number of the line to check.
988 header_path: Canonicalized header to be checked.
erg@google.com26970fa2009-11-17 18:07:32 +0000989
990 Returns:
991 Returns true if the header is in alphabetical order.
992 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +0000993 # If previous section is different from current section, _last_header
994 # will be reset to empty string, so it's always less than current
995 # header.
996 #
997 # If previous line was a blank line, assume that the headers are
998 # intentionally sorted the way they are.
999 if (self._last_header > header_path and Match(
1000 r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])):
1001 return False
1002 return True
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001003
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001004 def CheckNextIncludeOrder(self, header_type):
1005 """Returns a non-empty error message if the next header is out of order.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001006
1007 This function also updates the internal state to be ready to check
1008 the next include.
1009
1010 Args:
1011 header_type: One of the _XXX_HEADER constants defined above.
1012
1013 Returns:
1014 The empty string if the header is in the right order, or an
1015 error message describing what's wrong.
1016
1017 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001018 error_message = (
1019 'Found %s after %s' %
1020 (self._TYPE_NAMES[header_type], self._SECTION_NAMES[self._section]))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001021
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001022 last_section = self._section
erg@google.com26970fa2009-11-17 18:07:32 +00001023
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001024 if header_type == _C_SYS_HEADER:
1025 if self._section <= self._C_SECTION:
1026 self._section = self._C_SECTION
1027 else:
1028 self._last_header = ''
1029 return error_message
1030 elif header_type == _CPP_SYS_HEADER:
1031 if self._section <= self._CPP_SECTION:
1032 self._section = self._CPP_SECTION
1033 else:
1034 self._last_header = ''
1035 return error_message
1036 elif header_type == _LIKELY_MY_HEADER:
1037 if self._section <= self._MY_H_SECTION:
1038 self._section = self._MY_H_SECTION
1039 else:
1040 self._section = self._OTHER_H_SECTION
1041 elif header_type == _POSSIBLE_MY_HEADER:
1042 if self._section <= self._MY_H_SECTION:
1043 self._section = self._MY_H_SECTION
1044 else:
1045 # This will always be the fallback because we're not sure
1046 # enough that the header is associated with this file.
1047 self._section = self._OTHER_H_SECTION
1048 else:
1049 assert header_type == _OTHER_HEADER
1050 self._section = self._OTHER_H_SECTION
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001051
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001052 if last_section != self._section:
1053 self._last_header = ''
erg@google.com26970fa2009-11-17 18:07:32 +00001054
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001055 return ''
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001056
1057
1058class _CppLintState(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001059 """Maintains module-wide state.."""
1060 def __init__(self):
1061 self.verbose_level = 1 # global setting.
1062 self.error_count = 0 # global count of reported errors
1063 # filters to apply when emitting error messages
1064 self.filters = _DEFAULT_FILTERS[:]
1065 # backup of filter list. Used to restore the state after each file.
1066 self._filters_backup = self.filters[:]
1067 self.counting = 'total' # In what way are we counting errors?
1068 self.errors_by_category = {} # string to int dict storing error counts
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001069
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001070 # output format:
1071 # "emacs" - format that emacs can parse (default)
1072 # "vs7" - format that Microsoft Visual Studio 7 can parse
1073 self.output_format = 'emacs'
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001074
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001075 def SetOutputFormat(self, output_format):
1076 """Sets the output format for errors."""
1077 self.output_format = output_format
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001078
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001079 def SetVerboseLevel(self, level):
1080 """Sets the module's verbosity, and returns the previous setting."""
1081 last_verbose_level = self.verbose_level
1082 self.verbose_level = level
1083 return last_verbose_level
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001084
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001085 def SetCountingStyle(self, counting_style):
1086 """Sets the module's counting options."""
1087 self.counting = counting_style
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001088
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001089 def SetFilters(self, filters):
1090 """Sets the error-message filters.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001091
1092 These filters are applied when deciding whether to emit a given
1093 error message.
1094
1095 Args:
1096 filters: A string of comma-separated filters (eg "+whitespace/indent").
1097 Each filter should start with + or -; else we die.
erg@google.com6317a9c2009-06-25 00:28:19 +00001098
1099 Raises:
1100 ValueError: The comma-separated filters did not all start with '+' or '-'.
1101 E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001102 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001103 # Default filters always have less priority than the flag ones.
1104 self.filters = _DEFAULT_FILTERS[:]
1105 self.AddFilters(filters)
avakulenko@google.com17449932014-07-28 22:13:33 +00001106
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001107 def AddFilters(self, filters):
1108 """ Adds more filters to the existing list of error-message filters. """
1109 for filt in filters.split(','):
1110 clean_filt = filt.strip()
1111 if clean_filt:
1112 self.filters.append(clean_filt)
1113 for filt in self.filters:
1114 if not (filt.startswith('+') or filt.startswith('-')):
1115 raise ValueError(
1116 'Every filter in --filters must start with + or -'
1117 ' (%s does not)' % filt)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001118
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001119 def BackupFilters(self):
1120 """ Saves the current filter list to backup storage."""
1121 self._filters_backup = self.filters[:]
avakulenko@google.com17449932014-07-28 22:13:33 +00001122
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001123 def RestoreFilters(self):
1124 """ Restores filters previously backed up."""
1125 self.filters = self._filters_backup[:]
avakulenko@google.com17449932014-07-28 22:13:33 +00001126
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001127 def ResetErrorCounts(self):
1128 """Sets the module's error statistic back to zero."""
1129 self.error_count = 0
1130 self.errors_by_category = {}
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001131
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001132 def IncrementErrorCount(self, category):
1133 """Bumps the module's error statistic."""
1134 self.error_count += 1
1135 if self.counting in ('toplevel', 'detailed'):
1136 if self.counting != 'detailed':
1137 category = category.split('/')[0]
1138 if category not in self.errors_by_category:
1139 self.errors_by_category[category] = 0
1140 self.errors_by_category[category] += 1
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001141
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001142 def PrintErrorCounts(self):
1143 """Print a summary of errors by category, and the total."""
1144 for category, count in self.errors_by_category.items():
1145 sys.stderr.write('Category \'%s\' errors found: %d\n' %
1146 (category, count))
1147 sys.stderr.write('Total errors found: %d\n' % self.error_count)
1148
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001149
1150_cpplint_state = _CppLintState()
1151
1152
1153def _OutputFormat():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001154 """Gets the module's output format."""
1155 return _cpplint_state.output_format
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001156
1157
1158def _SetOutputFormat(output_format):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001159 """Sets the module's output format."""
1160 _cpplint_state.SetOutputFormat(output_format)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001161
1162
1163def _VerboseLevel():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001164 """Returns the module's verbosity setting."""
1165 return _cpplint_state.verbose_level
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001166
1167
1168def _SetVerboseLevel(level):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001169 """Sets the module's verbosity, and returns the previous setting."""
1170 return _cpplint_state.SetVerboseLevel(level)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001171
1172
erg@google.com26970fa2009-11-17 18:07:32 +00001173def _SetCountingStyle(level):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001174 """Sets the module's counting options."""
1175 _cpplint_state.SetCountingStyle(level)
erg@google.com26970fa2009-11-17 18:07:32 +00001176
1177
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001178def _Filters():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001179 """Returns the module's list of output filters, as a list."""
1180 return _cpplint_state.filters
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001181
1182
1183def _SetFilters(filters):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001184 """Sets the module's error-message filters.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001185
1186 These filters are applied when deciding whether to emit a given
1187 error message.
1188
1189 Args:
1190 filters: A string of comma-separated filters (eg "whitespace/indent").
1191 Each filter should start with + or -; else we die.
1192 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001193 _cpplint_state.SetFilters(filters)
1194
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001195
avakulenko@google.com17449932014-07-28 22:13:33 +00001196def _AddFilters(filters):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001197 """Adds more filter overrides.
avakulenko@google.com59146752014-08-11 20:20:55 +00001198
avakulenko@google.com17449932014-07-28 22:13:33 +00001199 Unlike _SetFilters, this function does not reset the current list of filters
1200 available.
1201
1202 Args:
1203 filters: A string of comma-separated filters (eg "whitespace/indent").
1204 Each filter should start with + or -; else we die.
1205 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001206 _cpplint_state.AddFilters(filters)
1207
avakulenko@google.com17449932014-07-28 22:13:33 +00001208
1209def _BackupFilters():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001210 """ Saves the current filter list to backup storage."""
1211 _cpplint_state.BackupFilters()
1212
avakulenko@google.com17449932014-07-28 22:13:33 +00001213
1214def _RestoreFilters():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001215 """ Restores filters previously backed up."""
1216 _cpplint_state.RestoreFilters()
1217
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001218
1219class _FunctionState(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001220 """Tracks current function name and the number of lines in its body."""
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001221
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001222 _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
1223 _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001224
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001225 def __init__(self):
1226 self.in_a_function = False
1227 self.lines_in_function = 0
1228 self.current_function = ''
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001229
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001230 def Begin(self, function_name):
1231 """Start analyzing function body.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001232
1233 Args:
1234 function_name: The name of the function being tracked.
1235 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001236 self.in_a_function = True
1237 self.lines_in_function = 0
1238 self.current_function = function_name
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001239
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001240 def Count(self):
1241 """Count line in current function body."""
1242 if self.in_a_function:
1243 self.lines_in_function += 1
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001244
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001245 def Check(self, error, filename, linenum):
1246 """Report if too many lines in function body.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001247
1248 Args:
1249 error: The function to call with any errors found.
1250 filename: The name of the current file.
1251 linenum: The number of the line to check.
1252 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001253 if not self.in_a_function:
1254 return
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00001255
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001256 if Match(r'T(EST|est)', self.current_function):
1257 base_trigger = self._TEST_TRIGGER
1258 else:
1259 base_trigger = self._NORMAL_TRIGGER
1260 trigger = base_trigger * 2**_VerboseLevel()
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001261
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001262 if self.lines_in_function > trigger:
1263 error_level = int(math.log(self.lines_in_function / base_trigger,
1264 2))
1265 # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
1266 if error_level > 5:
1267 error_level = 5
1268 error(
1269 filename, linenum, 'readability/fn_size', error_level,
1270 'Small and focused functions are preferred:'
1271 ' %s has %d non-comment lines'
1272 ' (error triggered by exceeding %d lines).' %
1273 (self.current_function, self.lines_in_function, trigger))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001274
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001275 def End(self):
1276 """Stop analyzing function body."""
1277 self.in_a_function = False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001278
1279
1280class _IncludeError(Exception):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001281 """Indicates a problem with the include order in a file."""
1282 pass
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001283
1284
avakulenko@google.com59146752014-08-11 20:20:55 +00001285class FileInfo(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001286 """Provides utility functions for filenames.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001287
1288 FileInfo provides easy access to the components of a file's path
1289 relative to the project root.
1290 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001291 def __init__(self, filename):
1292 self._filename = filename
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001293
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001294 def FullName(self):
1295 """Make Windows paths like Unix."""
1296 return os.path.abspath(self._filename).replace('\\', '/')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001297
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001298 def RepositoryName(self):
1299 r"""FullName after removing the local path to the repository.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001300
1301 If we have a real absolute path name here we can try to do something smart:
1302 detecting the root of the checkout and truncating /path/to/checkout from
1303 the name so that we get header guards that don't include things like
1304 "C:\Documents and Settings\..." or "/home/username/..." in them and thus
1305 people on different computers who have checked the source out to different
1306 locations won't see bogus errors.
1307 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001308 fullname = self.FullName()
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001309
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001310 if os.path.exists(fullname):
1311 project_dir = os.path.dirname(fullname)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001312
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001313 if _project_root:
1314 prefix = os.path.commonprefix([_project_root, project_dir])
1315 return fullname[len(prefix) + 1:]
Sergiy Byelozyorov7999d922018-06-22 09:25:54 +00001316
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001317 if os.path.exists(os.path.join(project_dir, ".svn")):
1318 # If there's a .svn file in the current directory, we
1319 # recursively look up the directory tree for the top of the SVN
1320 # checkout
1321 root_dir = project_dir
1322 one_up_dir = os.path.dirname(root_dir)
1323 while os.path.exists(os.path.join(one_up_dir, ".svn")):
1324 root_dir = os.path.dirname(root_dir)
1325 one_up_dir = os.path.dirname(one_up_dir)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001326
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001327 prefix = os.path.commonprefix([root_dir, project_dir])
1328 return fullname[len(prefix) + 1:]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001329
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001330 # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory
1331 # by searching up from the current path.
1332 root_dir = os.path.dirname(fullname)
1333 while (root_dir != os.path.dirname(root_dir)
1334 and not os.path.exists(os.path.join(root_dir, ".git"))
1335 and not os.path.exists(os.path.join(root_dir, ".hg"))
1336 and not os.path.exists(os.path.join(root_dir, ".svn"))):
1337 root_dir = os.path.dirname(root_dir)
erg@google.com35589e62010-11-17 18:58:16 +00001338
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001339 if (os.path.exists(os.path.join(root_dir, ".git"))
1340 or os.path.exists(os.path.join(root_dir, ".hg"))
1341 or os.path.exists(os.path.join(root_dir, ".svn"))):
1342 prefix = os.path.commonprefix([root_dir, project_dir])
1343 return fullname[len(prefix) + 1:]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001344
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001345 # Don't know what to do; header guard warnings may be wrong...
1346 return fullname
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001347
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001348 def Split(self):
1349 """Splits the file into the directory, basename, and extension.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001350
1351 For 'chrome/browser/browser.cc', Split() would
1352 return ('chrome/browser', 'browser', '.cc')
1353
1354 Returns:
1355 A tuple of (directory, basename, extension).
1356 """
1357
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001358 googlename = self.RepositoryName()
1359 project, rest = os.path.split(googlename)
1360 return (project, ) + os.path.splitext(rest)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001361
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001362 def BaseName(self):
1363 """File base name - text after the final slash, before the final period."""
1364 return self.Split()[1]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001365
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001366 def Extension(self):
1367 """File extension - text following the final period."""
1368 return self.Split()[2]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001369
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001370 def NoExtension(self):
1371 """File has no source file extension."""
1372 return '/'.join(self.Split()[0:2])
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001373
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001374 def IsSource(self):
1375 """File has a source file extension."""
1376 return _IsSourceExtension(self.Extension()[1:])
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001377
1378
erg@google.com35589e62010-11-17 18:58:16 +00001379def _ShouldPrintError(category, confidence, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001380 """If confidence >= verbose, category passes filter and is not suppressed."""
erg@google.com35589e62010-11-17 18:58:16 +00001381
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001382 # There are three ways we might decide not to print an error message:
1383 # a "NOLINT(category)" comment appears in the source,
1384 # the verbosity level isn't high enough, or the filters filter it out.
1385 if IsErrorSuppressedByNolint(category, linenum):
1386 return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001387
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001388 if confidence < _cpplint_state.verbose_level:
1389 return False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001390
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001391 is_filtered = False
1392 for one_filter in _Filters():
1393 if one_filter.startswith('-'):
1394 if category.startswith(one_filter[1:]):
1395 is_filtered = True
1396 elif one_filter.startswith('+'):
1397 if category.startswith(one_filter[1:]):
1398 is_filtered = False
1399 else:
1400 assert False # should have been checked for in SetFilter.
1401 if is_filtered:
1402 return False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001403
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001404 return True
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001405
1406
1407def Error(filename, linenum, category, confidence, message):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001408 """Logs the fact we've found a lint error.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001409
1410 We log where the error was found, and also our confidence in the error,
1411 that is, how certain we are this is a legitimate style regression, and
1412 not a misidentification or a use that's sometimes justified.
1413
erg@google.com35589e62010-11-17 18:58:16 +00001414 False positives can be suppressed by the use of
1415 "cpplint(category)" comments on the offending line. These are
1416 parsed into _error_suppressions.
1417
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001418 Args:
1419 filename: The name of the file containing the error.
1420 linenum: The number of the line containing the error.
1421 category: A string used to describe the "category" this bug
1422 falls under: "whitespace", say, or "runtime". Categories
1423 may have a hierarchy separated by slashes: "whitespace/indent".
1424 confidence: A number from 1-5 representing a confidence score for
1425 the error, with 5 meaning that we are certain of the problem,
1426 and 1 meaning that it could be a legitimate construct.
1427 message: The error message.
1428 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001429 if _ShouldPrintError(category, confidence, linenum):
1430 _cpplint_state.IncrementErrorCount(category)
1431 if _cpplint_state.output_format == 'vs7':
1432 sys.stderr.write('%s(%s): (cpplint) %s [%s] [%d]\n' %
1433 (filename, linenum, message, category, confidence))
1434 elif _cpplint_state.output_format == 'eclipse':
1435 sys.stderr.write('%s:%s: (cpplint) warning: %s [%s] [%d]\n' %
1436 (filename, linenum, message, category, confidence))
1437 else:
1438 sys.stderr.write('%s:%s: (cpplint) %s [%s] [%d]\n' %
1439 (filename, linenum, message, category, confidence))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001440
1441
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001442# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001443_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
1444 r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001445# Match a single C style comment on the same line.
1446_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/'
1447# Matches multi-line C style comments.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001448# This RE is a little bit more complicated than one might expect, because we
1449# have to take care of space removals tools so we can handle comments inside
1450# statements better.
1451# The current rule is: We only clear spaces from both sides when we're at the
1452# end of the line. Otherwise, we try to remove spaces from the right side,
1453# if this doesn't work we try on left side but only if there's a non-character
1454# on the right.
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001455_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(r'(\s*' +
1456 _RE_PATTERN_C_COMMENTS +
1457 r'\s*$|' +
1458 _RE_PATTERN_C_COMMENTS +
1459 r'\s+|' + r'\s+' +
1460 _RE_PATTERN_C_COMMENTS +
1461 r'(?=\W)|' +
1462 _RE_PATTERN_C_COMMENTS + r')')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001463
1464
1465def IsCppString(line):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001466 """Does line terminate so, that the next symbol is in string constant.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001467
1468 This function does not consider single-line nor multi-line comments.
1469
1470 Args:
1471 line: is a partial line of code starting from the 0..n.
1472
1473 Returns:
1474 True, if next character appended to 'line' is inside a
1475 string constant.
1476 """
1477
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001478 line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
1479 return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001480
1481
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001482def CleanseRawStrings(raw_lines):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001483 """Removes C++11 raw strings from lines.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001484
1485 Before:
1486 static const char kData[] = R"(
1487 multi-line string
1488 )";
1489
1490 After:
1491 static const char kData[] = ""
1492 (replaced by blank line)
1493 "";
1494
1495 Args:
1496 raw_lines: list of raw lines.
1497
1498 Returns:
1499 list of lines with C++11 raw strings replaced by empty strings.
1500 """
1501
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001502 delimiter = None
1503 lines_without_raw_strings = []
1504 for line in raw_lines:
1505 if delimiter:
1506 # Inside a raw string, look for the end
1507 end = line.find(delimiter)
1508 if end >= 0:
1509 # Found the end of the string, match leading space for this
1510 # line and resume copying the original lines, and also insert
1511 # a "" on the last line.
1512 leading_space = Match(r'^(\s*)\S', line)
1513 line = leading_space.group(1) + '""' + line[end +
1514 len(delimiter):]
1515 delimiter = None
1516 else:
1517 # Haven't found the end yet, append a blank line.
1518 line = '""'
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001519
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001520 # Look for beginning of a raw string, and replace them with
1521 # empty strings. This is done in a loop to handle multiple raw
1522 # strings on the same line.
1523 while delimiter is None:
1524 # Look for beginning of a raw string.
1525 # See 2.14.15 [lex.string] for syntax.
1526 #
1527 # Once we have matched a raw string, we check the prefix of the
1528 # line to make sure that the line is not part of a single line
1529 # comment. It's done this way because we remove raw strings
1530 # before removing comments as opposed to removing comments
1531 # before removing raw strings. This is because there are some
1532 # cpplint checks that requires the comments to be preserved, but
1533 # we don't want to check comments that are inside raw strings.
1534 matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$',
1535 line)
1536 if (matched and
1537 not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//',
1538 matched.group(1))):
1539 delimiter = ')' + matched.group(2) + '"'
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001540
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001541 end = matched.group(3).find(delimiter)
1542 if end >= 0:
1543 # Raw string ended on same line
1544 line = (matched.group(1) + '""' +
1545 matched.group(3)[end + len(delimiter):])
1546 delimiter = None
1547 else:
1548 # Start of a multi-line raw string
1549 line = matched.group(1) + '""'
1550 else:
1551 break
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001552
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001553 lines_without_raw_strings.append(line)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001554
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001555 # TODO(unknown): if delimiter is not None here, we might want to
1556 # emit a warning for unterminated string.
1557 return lines_without_raw_strings
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001558
1559
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001560def FindNextMultiLineCommentStart(lines, lineix):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001561 """Find the beginning marker for a multiline comment."""
1562 while lineix < len(lines):
1563 if lines[lineix].strip().startswith('/*'):
1564 # Only return this marker if the comment goes beyond this line
1565 if lines[lineix].strip().find('*/', 2) < 0:
1566 return lineix
1567 lineix += 1
1568 return len(lines)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001569
1570
1571def FindNextMultiLineCommentEnd(lines, lineix):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001572 """We are inside a comment, find the end marker."""
1573 while lineix < len(lines):
1574 if lines[lineix].strip().endswith('*/'):
1575 return lineix
1576 lineix += 1
1577 return len(lines)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001578
1579
1580def RemoveMultiLineCommentsFromRange(lines, begin, end):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001581 """Clears a range of lines for multi-line comments."""
1582 # Having // dummy comments makes the lines non-empty, so we will not get
1583 # unnecessary blank line warnings later in the code.
1584 for i in range(begin, end):
1585 lines[i] = '/**/'
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001586
1587
1588def RemoveMultiLineComments(filename, lines, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001589 """Removes multiline (c-style) comments from lines."""
1590 lineix = 0
1591 while lineix < len(lines):
1592 lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
1593 if lineix_begin >= len(lines):
1594 return
1595 lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
1596 if lineix_end >= len(lines):
1597 error(filename, lineix_begin + 1, 'readability/multiline_comment',
1598 5, 'Could not find end of multi-line comment')
1599 return
1600 RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
1601 lineix = lineix_end + 1
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001602
1603
1604def CleanseComments(line):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001605 """Removes //-comments and single-line C-style /* */ comments.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001606
1607 Args:
1608 line: A line of C++ source.
1609
1610 Returns:
1611 The line with single-line comments removed.
1612 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001613 commentpos = line.find('//')
1614 if commentpos != -1 and not IsCppString(line[:commentpos]):
1615 line = line[:commentpos].rstrip()
1616 # get rid of /* ... */
1617 return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001618
1619
erg@google.com6317a9c2009-06-25 00:28:19 +00001620class CleansedLines(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001621 """Holds 4 copies of all lines with different preprocessing applied to them.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001622
avakulenko@google.com255f2be2014-12-05 22:19:55 +00001623 1) elided member contains lines without strings and comments.
1624 2) lines member contains lines without comments.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00001625 3) raw_lines member contains all the lines without processing.
avakulenko@google.com255f2be2014-12-05 22:19:55 +00001626 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw
1627 strings removed.
1628 All these members are of <type 'list'>, and of the same length.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001629 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001630 def __init__(self, lines):
1631 self.elided = []
1632 self.lines = []
1633 self.raw_lines = lines
1634 self.num_lines = len(lines)
1635 self.lines_without_raw_strings = CleanseRawStrings(lines)
1636 for linenum in range(len(self.lines_without_raw_strings)):
1637 self.lines.append(
1638 CleanseComments(self.lines_without_raw_strings[linenum]))
1639 elided = self._CollapseStrings(
1640 self.lines_without_raw_strings[linenum])
1641 self.elided.append(CleanseComments(elided))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001642
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001643 def NumLines(self):
1644 """Returns the number of lines represented."""
1645 return self.num_lines
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001646
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001647 @staticmethod
1648 def _CollapseStrings(elided):
1649 """Collapses strings and chars on a line to simple "" or '' blocks.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001650
1651 We nix strings first so we're not fooled by text like '"http://"'
1652
1653 Args:
1654 elided: The line being processed.
1655
1656 Returns:
1657 The line with collapsed strings.
1658 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001659 if _RE_PATTERN_INCLUDE.match(elided):
1660 return elided
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001661
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001662 # Remove escaped characters first to make quote/single quote collapsing
1663 # basic. Things that look like escaped characters shouldn't occur
1664 # outside of strings and chars.
1665 elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001666
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001667 # Replace quoted strings and digit separators. Both single quotes
1668 # and double quotes are processed in the same loop, otherwise
1669 # nested quotes wouldn't work.
1670 collapsed = ''
1671 while True:
1672 # Find the first quote character
1673 match = Match(r'^([^\'"]*)([\'"])(.*)$', elided)
1674 if not match:
1675 collapsed += elided
1676 break
1677 head, quote, tail = match.groups()
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001678
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001679 if quote == '"':
1680 # Collapse double quoted strings
1681 second_quote = tail.find('"')
1682 if second_quote >= 0:
1683 collapsed += head + '""'
1684 elided = tail[second_quote + 1:]
1685 else:
1686 # Unmatched double quote, don't bother processing the rest
1687 # of the line since this is probably a multiline string.
1688 collapsed += elided
1689 break
1690 else:
1691 # Found single quote, check nearby text to eliminate digit
1692 # separators.
1693 #
1694 # There is no special handling for floating point here, because
1695 # the integer/fractional/exponent parts would all be parsed
1696 # correctly as long as there are digits on both sides of the
1697 # separator. So we are fine as long as we don't see something
1698 # like "0.'3" (gcc 4.9.0 will not allow this literal).
1699 if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head):
1700 match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$',
1701 "'" + tail)
1702 collapsed += head + match_literal.group(1).replace("'", '')
1703 elided = match_literal.group(2)
1704 else:
1705 second_quote = tail.find('\'')
1706 if second_quote >= 0:
1707 collapsed += head + "''"
1708 elided = tail[second_quote + 1:]
1709 else:
1710 # Unmatched single quote
1711 collapsed += elided
1712 break
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001713
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001714 return collapsed
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001715
1716
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001717def FindEndOfExpressionInLine(line, startpos, stack):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001718 """Find the position just after the end of current parenthesized expression.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00001719
1720 Args:
1721 line: a CleansedLines line.
1722 startpos: start searching at this position.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001723 stack: nesting stack at startpos.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00001724
1725 Returns:
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001726 On finding matching end: (index just after matching end, None)
1727 On finding an unclosed expression: (-1, None)
1728 Otherwise: (-1, new stack at end of this line)
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00001729 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001730 for i in range(startpos, len(line)):
1731 char = line[i]
1732 if char in '([{':
1733 # Found start of parenthesized expression, push to expression stack
1734 stack.append(char)
1735 elif char == '<':
1736 # Found potential start of template argument list
1737 if i > 0 and line[i - 1] == '<':
1738 # Left shift operator
1739 if stack and stack[-1] == '<':
1740 stack.pop()
1741 if not stack:
1742 return (-1, None)
1743 elif i > 0 and Search(r'\boperator\s*$', line[0:i]):
1744 # operator<, don't add to stack
1745 continue
1746 else:
1747 # Tentative start of template argument list
1748 stack.append('<')
1749 elif char in ')]}':
1750 # Found end of parenthesized expression.
1751 #
1752 # If we are currently expecting a matching '>', the pending '<'
1753 # must have been an operator. Remove them from expression stack.
1754 while stack and stack[-1] == '<':
1755 stack.pop()
1756 if not stack:
1757 return (-1, None)
1758 if ((stack[-1] == '(' and char == ')')
1759 or (stack[-1] == '[' and char == ']')
1760 or (stack[-1] == '{' and char == '}')):
1761 stack.pop()
1762 if not stack:
1763 return (i + 1, None)
1764 else:
1765 # Mismatched parentheses
1766 return (-1, None)
1767 elif char == '>':
1768 # Found potential end of template argument list.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001769
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001770 # Ignore "->" and operator functions
1771 if (i > 0 and (line[i - 1] == '-'
1772 or Search(r'\boperator\s*$', line[0:i - 1]))):
1773 continue
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001774
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001775 # Pop the stack if there is a matching '<'. Otherwise, ignore
1776 # this '>' since it must be an operator.
1777 if stack:
1778 if stack[-1] == '<':
1779 stack.pop()
1780 if not stack:
1781 return (i + 1, None)
1782 elif char == ';':
1783 # Found something that look like end of statements. If we are
1784 # currently expecting a '>', the matching '<' must have been an
1785 # operator, since template argument list should not contain
1786 # statements.
1787 while stack and stack[-1] == '<':
1788 stack.pop()
1789 if not stack:
1790 return (-1, None)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001791
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001792 # Did not find end of expression or unbalanced parentheses on this line
1793 return (-1, stack)
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00001794
1795
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001796def CloseExpression(clean_lines, linenum, pos):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001797 """If input points to ( or { or [ or <, finds the position that closes it.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001798
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001799 If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001800 linenum/pos that correspond to the closing of the expression.
1801
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001802 TODO(unknown): cpplint spends a fair bit of time matching parentheses.
1803 Ideally we would want to index all opening and closing parentheses once
1804 and have CloseExpression be just a simple lookup, but due to preprocessor
1805 tricks, this is not so easy.
1806
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001807 Args:
1808 clean_lines: A CleansedLines instance containing the file.
1809 linenum: The number of the line to check.
1810 pos: A position on the line.
1811
1812 Returns:
1813 A tuple (line, linenum, pos) pointer *past* the closing brace, or
1814 (line, len(lines), -1) if we never find a close. Note we ignore
1815 strings and comments when matching; and the line we return is the
1816 'cleansed' line at linenum.
1817 """
1818
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001819 line = clean_lines.elided[linenum]
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001820 if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]):
1821 return (line, clean_lines.NumLines(), -1)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001822
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001823 # Check first line
1824 (end_pos, stack) = FindEndOfExpressionInLine(line, pos, [])
1825 if end_pos > -1:
1826 return (line, linenum, end_pos)
1827
1828 # Continue scanning forward
1829 while stack and linenum < clean_lines.NumLines() - 1:
1830 linenum += 1
1831 line = clean_lines.elided[linenum]
1832 (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack)
1833 if end_pos > -1:
1834 return (line, linenum, end_pos)
1835
1836 # Did not find end of expression before end of file, give up
1837 return (line, clean_lines.NumLines(), -1)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001838
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001839
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001840def FindStartOfExpressionInLine(line, endpos, stack):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001841 """Find position at the matching start of current expression.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001842
1843 This is almost the reverse of FindEndOfExpressionInLine, but note
1844 that the input position and returned position differs by 1.
1845
1846 Args:
1847 line: a CleansedLines line.
1848 endpos: start searching at this position.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001849 stack: nesting stack at endpos.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001850
1851 Returns:
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001852 On finding matching start: (index at matching start, None)
1853 On finding an unclosed expression: (-1, None)
1854 Otherwise: (-1, new stack at beginning of this line)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001855 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001856 i = endpos
1857 while i >= 0:
1858 char = line[i]
1859 if char in ')]}':
1860 # Found end of expression, push to expression stack
1861 stack.append(char)
1862 elif char == '>':
1863 # Found potential end of template argument list.
1864 #
1865 # Ignore it if it's a "->" or ">=" or "operator>"
1866 if (i > 0 and (line[i - 1] == '-' or Match(r'\s>=\s', line[i - 1:])
1867 or Search(r'\boperator\s*$', line[0:i]))):
1868 i -= 1
1869 else:
1870 stack.append('>')
1871 elif char == '<':
1872 # Found potential start of template argument list
1873 if i > 0 and line[i - 1] == '<':
1874 # Left shift operator
1875 i -= 1
1876 else:
1877 # If there is a matching '>', we can pop the expression stack.
1878 # Otherwise, ignore this '<' since it must be an operator.
1879 if stack and stack[-1] == '>':
1880 stack.pop()
1881 if not stack:
1882 return (i, None)
1883 elif char in '([{':
1884 # Found start of expression.
1885 #
1886 # If there are any unmatched '>' on the stack, they must be
1887 # operators. Remove those.
1888 while stack and stack[-1] == '>':
1889 stack.pop()
1890 if not stack:
1891 return (-1, None)
1892 if ((char == '(' and stack[-1] == ')')
1893 or (char == '[' and stack[-1] == ']')
1894 or (char == '{' and stack[-1] == '}')):
1895 stack.pop()
1896 if not stack:
1897 return (i, None)
1898 else:
1899 # Mismatched parentheses
1900 return (-1, None)
1901 elif char == ';':
1902 # Found something that look like end of statements. If we are
1903 # currently expecting a '<', the matching '>' must have been an
1904 # operator, since template argument list should not contain
1905 # statements.
1906 while stack and stack[-1] == '>':
1907 stack.pop()
1908 if not stack:
1909 return (-1, None)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001910
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001911 i -= 1
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001912
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001913 return (-1, stack)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001914
1915
1916def ReverseCloseExpression(clean_lines, linenum, pos):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001917 """If input points to ) or } or ] or >, finds the position that opens it.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001918
1919 If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the
1920 linenum/pos that correspond to the opening of the expression.
1921
1922 Args:
1923 clean_lines: A CleansedLines instance containing the file.
1924 linenum: The number of the line to check.
1925 pos: A position on the line.
1926
1927 Returns:
1928 A tuple (line, linenum, pos) pointer *at* the opening brace, or
1929 (line, 0, -1) if we never find the matching opening brace. Note
1930 we ignore strings and comments when matching; and the line we
1931 return is the 'cleansed' line at linenum.
1932 """
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001933 line = clean_lines.elided[linenum]
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001934 if line[pos] not in ')}]>':
1935 return (line, 0, -1)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001936
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001937 # Check last line
1938 (start_pos, stack) = FindStartOfExpressionInLine(line, pos, [])
1939 if start_pos > -1:
1940 return (line, linenum, start_pos)
1941
1942 # Continue scanning backward
1943 while stack and linenum > 0:
1944 linenum -= 1
1945 line = clean_lines.elided[linenum]
1946 (start_pos,
1947 stack) = FindStartOfExpressionInLine(line,
1948 len(line) - 1, stack)
1949 if start_pos > -1:
1950 return (line, linenum, start_pos)
1951
1952 # Did not find start of expression before beginning of file, give up
1953 return (line, 0, -1)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00001954
1955
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001956def CheckForCopyright(filename, lines, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001957 """Logs an error if no Copyright message appears at the top of the file."""
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001958
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001959 # We'll say it should occur by line 10. Don't forget there's a
1960 # dummy line at the front.
1961 for line in range(1, min(len(lines), 11)):
1962 if re.search(r'Copyright', lines[line], re.I): break
1963 else: # means no copyright line was found
1964 error(
1965 filename, 0, 'legal/copyright', 5, 'No copyright message found. '
1966 'You should have a line: "Copyright [year] <Copyright Owner>"')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00001967
1968
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001969def GetIndentLevel(line):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001970 """Return the number of leading spaces in line.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001971
1972 Args:
1973 line: A string to check.
1974
1975 Returns:
1976 An integer count of leading spaces, possibly zero.
1977 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001978 indent = Match(r'^( *)\S', line)
1979 if indent:
1980 return len(indent.group(1))
1981 else:
1982 return 0
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00001983
1984
David Sanders2f988472022-05-21 01:35:11 +00001985def PathSplitToList(path):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001986 """Returns the path split into a list by the separator.
David Sanders2f988472022-05-21 01:35:11 +00001987
1988 Args:
1989 path: An absolute or relative path (e.g. '/a/b/c/' or '../a')
1990
1991 Returns:
1992 A list of path components (e.g. ['a', 'b', 'c]).
1993 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00001994 lst = []
1995 while True:
1996 (head, tail) = os.path.split(path)
1997 if head == path: # absolute paths end
1998 lst.append(head)
1999 break
2000 if tail == path: # relative paths end
2001 lst.append(tail)
2002 break
David Sanders2f988472022-05-21 01:35:11 +00002003
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002004 path = head
2005 lst.append(tail)
David Sanders2f988472022-05-21 01:35:11 +00002006
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002007 lst.reverse()
2008 return lst
David Sanders2f988472022-05-21 01:35:11 +00002009
2010
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002011def GetHeaderGuardCPPVariable(filename):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002012 """Returns the CPP variable that should be used as a header guard.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002013
2014 Args:
2015 filename: The name of a C++ header file.
2016
2017 Returns:
2018 The CPP variable that should be used as a header guard in the
2019 named file.
2020
2021 """
2022
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002023 # Restores original filename in case that cpplint is invoked from Emacs's
2024 # flymake.
2025 filename = re.sub(r'_flymake\.h$', '.h', filename)
2026 filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
2027 # Replace 'c++' with 'cpp'.
2028 filename = filename.replace('C++', 'cpp').replace('c++', 'cpp')
skym@chromium.org3990c412016-02-05 20:55:12 +00002029
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002030 fileinfo = FileInfo(filename)
2031 file_path_from_root = fileinfo.RepositoryName()
David Sanders2f988472022-05-21 01:35:11 +00002032
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002033 def FixupPathFromRoot():
2034 if _root_debug:
2035 sys.stderr.write(
2036 "\n_root fixup, _root = '%s', repository name = '%s'\n" %
2037 (_root, fileinfo.RepositoryName()))
David Sanders2f988472022-05-21 01:35:11 +00002038
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002039 # Process the file path with the --root flag if it was set.
2040 if not _root:
2041 if _root_debug:
2042 sys.stderr.write("_root unspecified\n")
2043 return file_path_from_root
David Sanders2f988472022-05-21 01:35:11 +00002044
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002045 def StripListPrefix(lst, prefix):
2046 # f(['x', 'y'], ['w, z']) -> None (not a valid prefix)
2047 if lst[:len(prefix)] != prefix:
2048 return None
2049 # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd']
2050 return lst[(len(prefix)):]
David Sanders2f988472022-05-21 01:35:11 +00002051
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002052 # root behavior:
2053 # --root=subdir , lstrips subdir from the header guard
2054 maybe_path = StripListPrefix(PathSplitToList(file_path_from_root),
2055 PathSplitToList(_root))
David Sanders2f988472022-05-21 01:35:11 +00002056
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002057 if _root_debug:
2058 sys.stderr.write(
2059 ("_root lstrip (maybe_path=%s, file_path_from_root=%s," +
2060 " _root=%s)\n") % (maybe_path, file_path_from_root, _root))
David Sanders2f988472022-05-21 01:35:11 +00002061
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002062 if maybe_path:
2063 return os.path.join(*maybe_path)
David Sanders2f988472022-05-21 01:35:11 +00002064
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002065 # --root=.. , will prepend the outer directory to the header guard
2066 full_path = fileinfo.FullName()
2067 # adapt slashes for windows
2068 root_abspath = os.path.abspath(_root).replace('\\', '/')
David Sanders2f988472022-05-21 01:35:11 +00002069
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002070 maybe_path = StripListPrefix(PathSplitToList(full_path),
2071 PathSplitToList(root_abspath))
David Sanders2f988472022-05-21 01:35:11 +00002072
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002073 if _root_debug:
2074 sys.stderr.write(
2075 ("_root prepend (maybe_path=%s, full_path=%s, " +
2076 "root_abspath=%s)\n") % (maybe_path, full_path, root_abspath))
David Sanders2f988472022-05-21 01:35:11 +00002077
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002078 if maybe_path:
2079 return os.path.join(*maybe_path)
David Sanders2f988472022-05-21 01:35:11 +00002080
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002081 if _root_debug:
2082 sys.stderr.write("_root ignore, returning %s\n" %
2083 (file_path_from_root))
David Sanders2f988472022-05-21 01:35:11 +00002084
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002085 # --root=FAKE_DIR is ignored
2086 return file_path_from_root
David Sanders2f988472022-05-21 01:35:11 +00002087
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002088 file_path_from_root = FixupPathFromRoot()
2089 return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002090
2091
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002092def CheckForHeaderGuard(filename, clean_lines, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002093 """Checks that the file contains a header guard.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002094
erg@google.com6317a9c2009-06-25 00:28:19 +00002095 Logs an error if no #ifndef header guard is present. For other
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002096 headers, checks that the full pathname is used.
2097
2098 Args:
2099 filename: The name of the C++ header file.
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002100 clean_lines: A CleansedLines instance containing the file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002101 error: The function to call with any errors found.
2102 """
2103
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002104 # Don't check for header guards if there are error suppression
2105 # comments somewhere in this file.
2106 #
2107 # Because this is silencing a warning for a nonexistent line, we
2108 # only support the very specific NOLINT(build/header_guard) syntax,
2109 # and not the general NOLINT or NOLINT(*) syntax.
2110 raw_lines = clean_lines.lines_without_raw_strings
2111 for i in raw_lines:
2112 if Search(r'//\s*NOLINT\(build/header_guard\)', i):
2113 return
avakulenko@google.com59146752014-08-11 20:20:55 +00002114
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002115 cppvar = GetHeaderGuardCPPVariable(filename)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002116
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002117 ifndef = ''
2118 ifndef_linenum = 0
2119 define = ''
2120 endif = ''
2121 endif_linenum = 0
2122 for linenum, line in enumerate(raw_lines):
2123 linesplit = line.split()
2124 if len(linesplit) >= 2:
2125 # find the first occurrence of #ifndef and #define, save arg
2126 if not ifndef and linesplit[0] == '#ifndef':
2127 # set ifndef to the header guard presented on the #ifndef line.
2128 ifndef = linesplit[1]
2129 ifndef_linenum = linenum
2130 if not define and linesplit[0] == '#define':
2131 define = linesplit[1]
2132 # find the last occurrence of #endif, save entire line
2133 if line.startswith('#endif'):
2134 endif = line
2135 endif_linenum = linenum
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002136
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002137 if not ifndef or not define or ifndef != define:
2138 error(
2139 filename, 0, 'build/header_guard', 5,
2140 'No #ifndef header guard found, suggested CPP variable is: %s' %
2141 cppvar)
2142 return
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002143
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002144 # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
2145 # for backward compatibility.
2146 if ifndef != cppvar:
2147 error_level = 0
2148 if ifndef != cppvar + '_':
2149 error_level = 5
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002150
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002151 ParseNolintSuppressions(filename, raw_lines[ifndef_linenum],
2152 ifndef_linenum, error)
2153 error(filename, ifndef_linenum, 'build/header_guard', error_level,
2154 '#ifndef header guard has wrong style, please use: %s' % cppvar)
2155
2156 # Check for "//" comments on endif line.
2157 ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum,
erg@google.com35589e62010-11-17 18:58:16 +00002158 error)
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002159 match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002160 if match:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002161 if match.group(1) == '_':
2162 # Issue low severity warning for deprecated double trailing
2163 # underscore
2164 error(filename, endif_linenum, 'build/header_guard', 0,
2165 '#endif line should be "#endif // %s"' % cppvar)
2166 return
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002167
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002168 # Didn't find the corresponding "//" comment. If this file does not
2169 # contain any "//" comments at all, it could be that the compiler
2170 # only wants "/**/" comments, look for those instead.
2171 no_single_line_comments = True
2172 for i in range(1, len(raw_lines) - 1):
2173 line = raw_lines[i]
2174 if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//',
2175 line):
2176 no_single_line_comments = False
2177 break
2178
2179 if no_single_line_comments:
2180 match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif)
2181 if match:
2182 if match.group(1) == '_':
2183 # Low severity warning for double trailing underscore
2184 error(filename, endif_linenum, 'build/header_guard', 0,
2185 '#endif line should be "#endif /* %s */"' % cppvar)
2186 return
2187
2188 # Didn't find anything
2189 error(filename, endif_linenum, 'build/header_guard', 5,
2190 '#endif line should be "#endif // %s"' % cppvar)
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002191
2192
2193def CheckHeaderFileIncluded(filename, include_state, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002194 """Logs an error if a .cc file does not include its header."""
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002195
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002196 # Do not check test files
2197 fileinfo = FileInfo(filename)
2198 if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()):
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002199 return
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002200
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002201 headerfile = filename[0:len(filename) - len(fileinfo.Extension())] + '.h'
2202 if not os.path.exists(headerfile):
2203 return
2204 headername = FileInfo(headerfile).RepositoryName()
2205 first_include = 0
2206 for section_list in include_state.include_list:
2207 for f in section_list:
2208 if headername in f[0] or f[0] in headername:
2209 return
2210 if not first_include:
2211 first_include = f[1]
2212
2213 error(
2214 filename, first_include, 'build/include', 5,
2215 '%s should include its header file %s' %
2216 (fileinfo.RepositoryName(), headername))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002217
2218
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002219def CheckForBadCharacters(filename, lines, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002220 """Logs an error for each line containing bad characters.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002221
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002222 Two kinds of bad characters:
2223
2224 1. Unicode replacement characters: These indicate that either the file
2225 contained invalid UTF-8 (likely) or Unicode replacement characters (which
2226 it shouldn't). Note that it's possible for this to throw off line
2227 numbering if the invalid UTF-8 occurred adjacent to a newline.
2228
2229 2. NUL bytes. These are problematic for some tools.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002230
2231 Args:
2232 filename: The name of the current file.
2233 lines: An array of strings, each representing a line of the file.
2234 error: The function to call with any errors found.
2235 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002236 for linenum, line in enumerate(lines):
2237 if u'\ufffd' in line:
2238 error(
2239 filename, linenum, 'readability/utf8', 5,
2240 'Line contains invalid UTF-8 (or Unicode replacement character).'
2241 )
2242 if '\0' in line:
2243 error(filename, linenum, 'readability/nul', 5,
2244 'Line contains NUL byte.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002245
2246
2247def CheckForNewlineAtEOF(filename, lines, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002248 """Logs an error if there is no newline char at the end of the file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002249
2250 Args:
2251 filename: The name of the current file.
2252 lines: An array of strings, each representing a line of the file.
2253 error: The function to call with any errors found.
2254 """
2255
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002256 # The array lines() was created by adding two newlines to the
2257 # original file (go figure), then splitting on \n.
2258 # To verify that the file ends in \n, we just have to make sure the
2259 # last-but-two element of lines() exists and is empty.
2260 if len(lines) < 3 or lines[-2]:
2261 error(filename,
2262 len(lines) - 2, 'whitespace/ending_newline', 5,
2263 'Could not find a newline character at the end of the file.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002264
2265
2266def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002267 """Logs an error if we see /* ... */ or "..." that extend past one line.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002268
2269 /* ... */ comments are legit inside macros, for one line.
2270 Otherwise, we prefer // comments, so it's ok to warn about the
2271 other. Likewise, it's ok for strings to extend across multiple
2272 lines, as long as a line continuation character (backslash)
2273 terminates each line. Although not currently prohibited by the C++
2274 style guide, it's ugly and unnecessary. We don't do well with either
2275 in this lint program, so we warn about both.
2276
2277 Args:
2278 filename: The name of the current file.
2279 clean_lines: A CleansedLines instance containing the file.
2280 linenum: The number of the line to check.
2281 error: The function to call with any errors found.
2282 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002283 line = clean_lines.elided[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002284
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002285 # Remove all \\ (escaped backslashes) from the line. They are OK, and the
2286 # second (escaped) slash may trigger later \" detection erroneously.
2287 line = line.replace('\\\\', '')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002288
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002289 if line.count('/*') > line.count('*/'):
2290 error(
2291 filename, linenum, 'readability/multiline_comment', 5,
2292 'Complex multi-line /*...*/-style comment found. '
2293 'Lint may give bogus warnings. '
2294 'Consider replacing these with //-style comments, '
2295 'with #if 0...#endif, '
2296 'or with more clearly structured multi-line comments.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002297
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002298 if (line.count('"') - line.count('\\"')) % 2:
2299 error(
2300 filename, linenum, 'readability/multiline_string', 5,
2301 'Multi-line string ("...") found. This lint script doesn\'t '
2302 'do well with such strings, and may give bogus warnings. '
2303 'Use C++11 raw strings or concatenation instead.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002304
2305
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002306# (non-threadsafe name, thread-safe alternative, validation pattern)
2307#
2308# The validation pattern is used to eliminate false positives such as:
2309# _rand(); // false positive due to substring match.
2310# ->rand(); // some member function rand().
2311# ACMRandom rand(seed); // some variable named rand.
2312# ISAACRandom rand(); // another variable named rand.
2313#
2314# Basically we require the return value of these functions to be used
2315# in some expression context on the same line by matching on some
2316# operator before the function name. This eliminates constructors and
2317# member function calls.
2318_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)'
2319_THREADING_LIST = (
2320 ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'),
2321 ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'),
2322 ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'),
2323 ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'),
2324 ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'),
2325 ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'),
2326 ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'),
2327 ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'),
2328 ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'),
2329 ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'),
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002330 ('strtok(', 'strtok_r(', _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'),
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002331 ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'),
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002332)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002333
2334
2335def CheckPosixThreading(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002336 """Checks for calls to thread-unsafe functions.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002337
2338 Much code has been originally written without consideration of
2339 multi-threading. Also, engineers are relying on their old experience;
2340 they have learned posix before threading extensions were added. These
2341 tests guide the engineers to use thread-safe functions (when using
2342 posix directly).
2343
2344 Args:
2345 filename: The name of the current file.
2346 clean_lines: A CleansedLines instance containing the file.
2347 linenum: The number of the line to check.
2348 error: The function to call with any errors found.
2349 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002350 line = clean_lines.elided[linenum]
2351 for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST:
2352 # Additional pattern matching check to confirm that this is the
2353 # function we are looking for
2354 if Search(pattern, line):
2355 error(
2356 filename, linenum, 'runtime/threadsafe_fn', 2,
2357 'Consider using ' + multithread_safe_func + '...) instead of ' +
2358 single_thread_func + '...) for improved thread safety.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002359
2360
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002361def CheckVlogArguments(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002362 """Checks that VLOG() is only used for defining a logging level.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002363
2364 For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and
2365 VLOG(FATAL) are not.
2366
2367 Args:
2368 filename: The name of the current file.
2369 clean_lines: A CleansedLines instance containing the file.
2370 linenum: The number of the line to check.
2371 error: The function to call with any errors found.
2372 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002373 line = clean_lines.elided[linenum]
2374 if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line):
2375 error(
2376 filename, linenum, 'runtime/vlog', 5,
2377 'VLOG() should be used with numeric verbosity level. '
2378 'Use LOG() if you want symbolic severity levels.')
2379
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002380
erg@google.com26970fa2009-11-17 18:07:32 +00002381# Matches invalid increment: *count++, which moves pointer instead of
erg@google.com6317a9c2009-06-25 00:28:19 +00002382# incrementing a value.
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002383_RE_PATTERN_INVALID_INCREMENT = re.compile(r'^\s*\*\w+(\+\+|--);')
erg@google.com6317a9c2009-06-25 00:28:19 +00002384
2385
2386def CheckInvalidIncrement(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002387 """Checks for invalid increment *count++.
erg@google.com6317a9c2009-06-25 00:28:19 +00002388
2389 For example following function:
2390 void increment_counter(int* count) {
2391 *count++;
2392 }
2393 is invalid, because it effectively does count++, moving pointer, and should
2394 be replaced with ++*count, (*count)++ or *count += 1.
2395
2396 Args:
2397 filename: The name of the current file.
2398 clean_lines: A CleansedLines instance containing the file.
2399 linenum: The number of the line to check.
2400 error: The function to call with any errors found.
2401 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002402 line = clean_lines.elided[linenum]
2403 if _RE_PATTERN_INVALID_INCREMENT.match(line):
2404 error(
2405 filename, linenum, 'runtime/invalid_increment', 5,
2406 'Changing pointer instead of value (or unused value of operator*).')
erg@google.com6317a9c2009-06-25 00:28:19 +00002407
2408
avakulenko@google.com59146752014-08-11 20:20:55 +00002409def IsMacroDefinition(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002410 if Search(r'^#define', clean_lines[linenum]):
2411 return True
avakulenko@google.com59146752014-08-11 20:20:55 +00002412
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002413 if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]):
2414 return True
avakulenko@google.com59146752014-08-11 20:20:55 +00002415
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002416 return False
avakulenko@google.com59146752014-08-11 20:20:55 +00002417
2418
2419def IsForwardClassDeclaration(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002420 return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum])
avakulenko@google.com59146752014-08-11 20:20:55 +00002421
2422
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002423class _BlockInfo(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002424 """Stores information about a generic block of code."""
2425 def __init__(self, linenum, seen_open_brace):
2426 self.starting_linenum = linenum
2427 self.seen_open_brace = seen_open_brace
2428 self.open_parentheses = 0
2429 self.inline_asm = _NO_ASM
2430 self.check_namespace_indentation = False
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002431
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002432 def CheckBegin(self, filename, clean_lines, linenum, error):
2433 """Run checks that applies to text up to the opening brace.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002434
2435 This is mostly for checking the text after the class identifier
2436 and the "{", usually where the base class is specified. For other
2437 blocks, there isn't much to check, so we always pass.
2438
2439 Args:
2440 filename: The name of the current file.
2441 clean_lines: A CleansedLines instance containing the file.
2442 linenum: The number of the line to check.
2443 error: The function to call with any errors found.
2444 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002445 pass
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002446
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002447 def CheckEnd(self, filename, clean_lines, linenum, error):
2448 """Run checks that applies to text after the closing brace.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002449
2450 This is mostly used for checking end of namespace comments.
2451
2452 Args:
2453 filename: The name of the current file.
2454 clean_lines: A CleansedLines instance containing the file.
2455 linenum: The number of the line to check.
2456 error: The function to call with any errors found.
2457 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002458 pass
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002459
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002460 def IsBlockInfo(self):
2461 """Returns true if this block is a _BlockInfo.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002462
2463 This is convenient for verifying that an object is an instance of
2464 a _BlockInfo, but not an instance of any of the derived classes.
2465
2466 Returns:
2467 True for this class, False for derived classes.
2468 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002469 return self.__class__ == _BlockInfo
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002470
2471
2472class _ExternCInfo(_BlockInfo):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002473 """Stores information about an 'extern "C"' block."""
2474 def __init__(self, linenum):
2475 _BlockInfo.__init__(self, linenum, True)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002476
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002477
2478class _ClassInfo(_BlockInfo):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002479 """Stores information about a class."""
2480 def __init__(self, name, class_or_struct, clean_lines, linenum):
2481 _BlockInfo.__init__(self, linenum, False)
2482 self.name = name
2483 self.is_derived = False
2484 self.check_namespace_indentation = True
2485 if class_or_struct == 'struct':
2486 self.access = 'public'
2487 self.is_struct = True
2488 else:
2489 self.access = 'private'
2490 self.is_struct = False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002491
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002492 # Remember initial indentation level for this class. Using raw_lines
2493 # here instead of elided to account for leading comments.
2494 self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum])
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002495
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002496 # Try to find the end of the class. This will be confused by things
2497 # like: class A { } *x = { ...
2498 #
2499 # But it's still good enough for CheckSectionSpacing.
2500 self.last_line = 0
2501 depth = 0
2502 for i in range(linenum, clean_lines.NumLines()):
2503 line = clean_lines.elided[i]
2504 depth += line.count('{') - line.count('}')
2505 if not depth:
2506 self.last_line = i
2507 break
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002508
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002509 def CheckBegin(self, filename, clean_lines, linenum, error):
2510 # Look for a bare ':'
2511 if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
2512 self.is_derived = True
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00002513
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002514 def CheckEnd(self, filename, clean_lines, linenum, error):
2515 # If there is a DISALLOW macro, it should appear near the end of
2516 # the class.
2517 seen_last_thing_in_class = False
2518 for i in range(linenum - 1, self.starting_linenum, -1):
2519 match = Search(
2520 r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\('
2521 + self.name + r'\)', clean_lines.elided[i])
2522 if match:
2523 if seen_last_thing_in_class:
2524 error(
2525 filename, i, 'readability/constructors', 3,
2526 match.group(1) +
2527 ' should be the last thing in the class')
2528 break
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002529
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002530 if not Match(r'^\s*$', clean_lines.elided[i]):
2531 seen_last_thing_in_class = True
avakulenko@google.com255f2be2014-12-05 22:19:55 +00002532
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002533 # Check that closing brace is aligned with beginning of the class.
2534 # Only do this if the closing brace is indented by only whitespaces.
2535 # This means we will not check single-line class definitions.
2536 indent = Match(r'^( *)\}', clean_lines.elided[linenum])
2537 if indent and len(indent.group(1)) != self.class_indent:
2538 if self.is_struct:
2539 parent = 'struct ' + self.name
2540 else:
2541 parent = 'class ' + self.name
2542 error(
2543 filename, linenum, 'whitespace/indent', 3,
2544 'Closing brace should be aligned with beginning of %s' % parent)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00002545
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002546
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002547class _NamespaceInfo(_BlockInfo):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002548 """Stores information about a namespace."""
2549 def __init__(self, name, linenum):
2550 _BlockInfo.__init__(self, linenum, False)
2551 self.name = name or ''
2552 self.check_namespace_indentation = True
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002553
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002554 def CheckEnd(self, filename, clean_lines, linenum, error):
2555 """Check end of namespace comments."""
2556 line = clean_lines.raw_lines[linenum]
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002557
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002558 # Check how many lines is enclosed in this namespace. Don't issue
2559 # warning for missing namespace comments if there aren't enough
2560 # lines. However, do apply checks if there is already an end of
2561 # namespace comment and it's incorrect.
2562 #
2563 # TODO(unknown): We always want to check end of namespace comments
2564 # if a namespace is large, but sometimes we also want to apply the
2565 # check if a short namespace contained nontrivial things (something
2566 # other than forward declarations). There is currently no logic on
2567 # deciding what these nontrivial things are, so this check is
2568 # triggered by namespace size only, which works most of the time.
2569 if (linenum - self.starting_linenum < 10
2570 and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)):
2571 return
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002572
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002573 # Look for matching comment at end of namespace.
2574 #
2575 # Note that we accept C style "/* */" comments for terminating
2576 # namespaces, so that code that terminate namespaces inside
2577 # preprocessor macros can be cpplint clean.
2578 #
2579 # We also accept stuff like "// end of namespace <name>." with the
2580 # period at the end.
2581 #
2582 # Besides these, we don't accept anything else, otherwise we might
2583 # get false negatives when existing comment is a substring of the
2584 # expected namespace.
2585 if self.name:
2586 # Named namespace
2587 if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' +
2588 re.escape(self.name) + r'[\*/\.\\\s]*$'), line):
2589 error(
2590 filename, linenum, 'readability/namespace', 5,
2591 'Namespace should be terminated with "// namespace %s"' %
2592 self.name)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002593 else:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002594 # Anonymous namespace
2595 if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
2596 # If "// namespace anonymous" or "// anonymous namespace (more
2597 # text)", mention "// anonymous namespace" as an acceptable form
2598 if Match(
2599 r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b',
2600 line):
2601 error(
2602 filename, linenum, 'readability/namespace', 5,
2603 'Anonymous namespace should be terminated with "// namespace"'
2604 ' or "// anonymous namespace"')
2605 else:
2606 error(
2607 filename, linenum, 'readability/namespace', 5,
2608 'Anonymous namespace should be terminated with "// namespace"'
2609 )
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002610
2611
2612class _PreprocessorInfo(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002613 """Stores checkpoints of nesting stacks when #if/#else is seen."""
2614 def __init__(self, stack_before_if):
2615 # The entire nesting stack before #if
2616 self.stack_before_if = stack_before_if
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002617
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002618 # The entire nesting stack up to #else
2619 self.stack_before_else = []
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002620
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002621 # Whether we have already seen #else or #elif
2622 self.seen_else = False
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002623
2624
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002625class NestingState(object):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002626 """Holds states related to parsing braces."""
2627 def __init__(self):
2628 # Stack for tracking all braces. An object is pushed whenever we
2629 # see a "{", and popped when we see a "}". Only 3 types of
2630 # objects are possible:
2631 # - _ClassInfo: a class or struct.
2632 # - _NamespaceInfo: a namespace.
2633 # - _BlockInfo: some other type of block.
2634 self.stack = []
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002635
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002636 # Top of the previous stack before each Update().
2637 #
2638 # Because the nesting_stack is updated at the end of each line, we
2639 # had to do some convoluted checks to find out what is the current
2640 # scope at the beginning of the line. This check is simplified by
2641 # saving the previous top of nesting stack.
2642 #
2643 # We could save the full stack, but we only need the top. Copying
2644 # the full nesting stack would slow down cpplint by ~10%.
2645 self.previous_stack_top = []
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002646
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002647 # Stack of _PreprocessorInfo objects.
2648 self.pp_stack = []
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002649
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002650 def SeenOpenBrace(self):
2651 """Check if we have seen the opening brace for the innermost block.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002652
2653 Returns:
2654 True if we have seen the opening brace, False if the innermost
2655 block is still expecting an opening brace.
2656 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002657 return (not self.stack) or self.stack[-1].seen_open_brace
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002658
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002659 def InNamespaceBody(self):
2660 """Check if we are currently one level inside a namespace body.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002661
2662 Returns:
2663 True if top of the stack is a namespace block, False otherwise.
2664 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002665 return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002666
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002667 def InExternC(self):
2668 """Check if we are currently one level inside an 'extern "C"' block.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002669
2670 Returns:
2671 True if top of the stack is an extern block, False otherwise.
2672 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002673 return self.stack and isinstance(self.stack[-1], _ExternCInfo)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002674
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002675 def InClassDeclaration(self):
2676 """Check if we are currently one level inside a class or struct declaration.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002677
2678 Returns:
2679 True if top of the stack is a class/struct, False otherwise.
2680 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002681 return self.stack and isinstance(self.stack[-1], _ClassInfo)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002682
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002683 def InAsmBlock(self):
2684 """Check if we are currently one level inside an inline ASM block.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002685
2686 Returns:
2687 True if the top of the stack is a block containing inline ASM.
2688 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002689 return self.stack and self.stack[-1].inline_asm != _NO_ASM
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002690
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002691 def InTemplateArgumentList(self, clean_lines, linenum, pos):
2692 """Check if current position is inside template argument list.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002693
2694 Args:
2695 clean_lines: A CleansedLines instance containing the file.
2696 linenum: The number of the line to check.
2697 pos: position just after the suspected template argument.
2698 Returns:
2699 True if (linenum, pos) is inside template arguments.
2700 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002701 while linenum < clean_lines.NumLines():
2702 # Find the earliest character that might indicate a template
2703 # argument
2704 line = clean_lines.elided[linenum]
2705 match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:])
2706 if not match:
2707 linenum += 1
2708 pos = 0
2709 continue
2710 token = match.group(1)
2711 pos += len(match.group(0))
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002712
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002713 # These things do not look like template argument list:
2714 # class Suspect {
2715 # class Suspect x; }
2716 if token in ('{', '}', ';'): return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002717
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002718 # These things look like template argument list:
2719 # template <class Suspect>
2720 # template <class Suspect = default_value>
2721 # template <class Suspect[]>
2722 # template <class Suspect...>
2723 if token in ('>', '=', '[', ']', '.'): return True
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002724
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002725 # Check if token is an unmatched '<'.
2726 # If not, move on to the next character.
2727 if token != '<':
2728 pos += 1
2729 if pos >= len(line):
2730 linenum += 1
2731 pos = 0
2732 continue
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002733
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002734 # We can't be sure if we just find a single '<', and need to
2735 # find the matching '>'.
2736 (_, end_line, end_pos) = CloseExpression(clean_lines, linenum,
2737 pos - 1)
2738 if end_pos < 0:
2739 # Not sure if template argument list or syntax error in file
2740 return False
2741 linenum = end_line
2742 pos = end_pos
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002743 return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00002744
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002745 def UpdatePreprocessor(self, line):
2746 """Update preprocessor stack.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002747
2748 We need to handle preprocessors due to classes like this:
2749 #ifdef SWIG
2750 struct ResultDetailsPageElementExtensionPoint {
2751 #else
2752 struct ResultDetailsPageElementExtensionPoint : public Extension {
2753 #endif
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002754
2755 We make the following assumptions (good enough for most files):
2756 - Preprocessor condition evaluates to true from #if up to first
2757 #else/#elif/#endif.
2758
2759 - Preprocessor condition evaluates to false from #else/#elif up
2760 to #endif. We still perform lint checks on these lines, but
2761 these do not affect nesting stack.
2762
2763 Args:
2764 line: current line to check.
2765 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002766 if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
2767 # Beginning of #if block, save the nesting stack here. The saved
2768 # stack will allow us to restore the parsing state in the #else
2769 # case.
2770 self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
2771 elif Match(r'^\s*#\s*(else|elif)\b', line):
2772 # Beginning of #else block
2773 if self.pp_stack:
2774 if not self.pp_stack[-1].seen_else:
2775 # This is the first #else or #elif block. Remember the
2776 # whole nesting stack up to this point. This is what we
2777 # keep after the #endif.
2778 self.pp_stack[-1].seen_else = True
2779 self.pp_stack[-1].stack_before_else = copy.deepcopy(
2780 self.stack)
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002781
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002782 # Restore the stack to how it was before the #if
2783 self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
2784 else:
2785 # TODO(unknown): unexpected #else, issue warning?
2786 pass
2787 elif Match(r'^\s*#\s*endif\b', line):
2788 # End of #if or #else blocks.
2789 if self.pp_stack:
2790 # If we saw an #else, we will need to restore the nesting
2791 # stack to its former state before the #else, otherwise we
2792 # will just continue from where we left off.
2793 if self.pp_stack[-1].seen_else:
2794 # Here we can just use a shallow copy since we are the last
2795 # reference to it.
2796 self.stack = self.pp_stack[-1].stack_before_else
2797 # Drop the corresponding #if
2798 self.pp_stack.pop()
2799 else:
2800 # TODO(unknown): unexpected #endif, issue warning?
2801 pass
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002802
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002803 # TODO(unknown): Update() is too long, but we will refactor later.
2804 def Update(self, filename, clean_lines, linenum, error):
2805 """Update nesting state with current line.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002806
2807 Args:
2808 filename: The name of the current file.
2809 clean_lines: A CleansedLines instance containing the file.
2810 linenum: The number of the line to check.
2811 error: The function to call with any errors found.
2812 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002813 line = clean_lines.elided[linenum]
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002814
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002815 # Remember top of the previous nesting stack.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002816 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002817 # The stack is always pushed/popped and not modified in place, so
2818 # we can just do a shallow copy instead of copy.deepcopy. Using
2819 # deepcopy would slow down cpplint by ~28%.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002820 if self.stack:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002821 self.previous_stack_top = self.stack[-1]
2822 else:
2823 self.previous_stack_top = None
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002824
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002825 # Update pp_stack
2826 self.UpdatePreprocessor(line)
2827
2828 # Count parentheses. This is to avoid adding struct arguments to
2829 # the nesting stack.
2830 if self.stack:
2831 inner_block = self.stack[-1]
2832 depth_change = line.count('(') - line.count(')')
2833 inner_block.open_parentheses += depth_change
2834
2835 # Also check if we are starting or ending an inline assembly block.
2836 if inner_block.inline_asm in (_NO_ASM, _END_ASM):
2837 if (depth_change != 0 and inner_block.open_parentheses == 1
2838 and _MATCH_ASM.match(line)):
2839 # Enter assembly block
2840 inner_block.inline_asm = _INSIDE_ASM
2841 else:
2842 # Not entering assembly block. If previous line was
2843 # _END_ASM, we will now shift to _NO_ASM state.
2844 inner_block.inline_asm = _NO_ASM
2845 elif (inner_block.inline_asm == _INSIDE_ASM
2846 and inner_block.open_parentheses == 0):
2847 # Exit assembly block
2848 inner_block.inline_asm = _END_ASM
2849
2850 # Consume namespace declaration at the beginning of the line. Do
2851 # this in a loop so that we catch same line declarations like this:
2852 # namespace proto2 { namespace bridge { class MessageSet; } }
2853 while True:
2854 # Match start of namespace. The "\b\s*" below catches namespace
2855 # declarations even if it weren't followed by a whitespace, this
2856 # is so that we don't confuse our namespace checker. The
2857 # missing spaces will be flagged by CheckSpacing.
2858 namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$',
2859 line)
2860 if not namespace_decl_match:
2861 break
2862
2863 new_namespace = _NamespaceInfo(namespace_decl_match.group(1),
2864 linenum)
2865 self.stack.append(new_namespace)
2866
2867 line = namespace_decl_match.group(2)
2868 if line.find('{') != -1:
2869 new_namespace.seen_open_brace = True
2870 line = line[line.find('{') + 1:]
2871
2872 # Look for a class declaration in whatever is left of the line
2873 # after parsing namespaces. The regexp accounts for decorated classes
2874 # such as in:
2875 # class LOCKABLE API Object {
2876 # };
2877 class_decl_match = Match(
2878 r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?'
2879 r'(class|struct)\s+(?:[A-Z0-9_]+\s+)*(\w+(?:::\w+)*))'
2880 r'(.*)$', line)
2881 if (class_decl_match
2882 and (not self.stack or self.stack[-1].open_parentheses == 0)):
2883 # We do not want to accept classes that are actually template
2884 # arguments: template <class Ignore1, class Ignore2 = Default<Args>,
2885 # template <Args> class Ignore3> void Function() {};
2886 #
2887 # To avoid template argument cases, we scan forward and look for
2888 # an unmatched '>'. If we see one, assume we are inside a
2889 # template argument list.
2890 end_declaration = len(class_decl_match.group(1))
2891 if not self.InTemplateArgumentList(clean_lines, linenum,
2892 end_declaration):
2893 self.stack.append(
2894 _ClassInfo(class_decl_match.group(3),
2895 class_decl_match.group(2), clean_lines, linenum))
2896 line = class_decl_match.group(4)
2897
2898 # If we have not yet seen the opening brace for the innermost block,
2899 # run checks here.
2900 if not self.SeenOpenBrace():
2901 self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
2902
2903 # Update access control if we are inside a class/struct
2904 if self.stack and isinstance(self.stack[-1], _ClassInfo):
2905 classinfo = self.stack[-1]
2906 access_match = Match(
2907 r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'
2908 r':(?:[^:]|$)', line)
2909 if access_match:
2910 classinfo.access = access_match.group(2)
2911
2912 # Check that access keywords are indented +1 space. Skip this
2913 # check if the keywords are not preceded by whitespaces.
2914 indent = access_match.group(1)
2915 if (len(indent) != classinfo.class_indent + 1
2916 and Match(r'^\s*$', indent)):
2917 if classinfo.is_struct:
2918 parent = 'struct ' + classinfo.name
2919 else:
2920 parent = 'class ' + classinfo.name
2921 slots = ''
2922 if access_match.group(3):
2923 slots = access_match.group(3)
2924 error(
2925 filename, linenum, 'whitespace/indent', 3,
2926 '%s%s: should be indented +1 space inside %s' %
2927 (access_match.group(2), slots, parent))
2928
2929 # Consume braces or semicolons from what's left of the line
2930 while True:
2931 # Match first brace, semicolon, or closed parenthesis.
2932 matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
2933 if not matched:
2934 break
2935
2936 token = matched.group(1)
2937 if token == '{':
2938 # If namespace or class hasn't seen a opening brace yet, mark
2939 # namespace/class head as complete. Push a new block onto the
2940 # stack otherwise.
2941 if not self.SeenOpenBrace():
2942 self.stack[-1].seen_open_brace = True
2943 elif Match(r'^extern\s*"[^"]*"\s*\{', line):
2944 self.stack.append(_ExternCInfo(linenum))
2945 else:
2946 self.stack.append(_BlockInfo(linenum, True))
2947 if _MATCH_ASM.match(line):
2948 self.stack[-1].inline_asm = _BLOCK_ASM
2949
2950 elif token == ';' or token == ')':
2951 # If we haven't seen an opening brace yet, but we already saw
2952 # a semicolon, this is probably a forward declaration. Pop
2953 # the stack for these.
2954 #
2955 # Similarly, if we haven't seen an opening brace yet, but we
2956 # already saw a closing parenthesis, then these are probably
2957 # function arguments with extra "class" or "struct" keywords.
2958 # Also pop these stack for these.
2959 if not self.SeenOpenBrace():
2960 self.stack.pop()
2961 else: # token == '}'
2962 # Perform end of block checks and pop the stack.
2963 if self.stack:
2964 self.stack[-1].CheckEnd(filename, clean_lines, linenum,
2965 error)
2966 self.stack.pop()
2967 line = matched.group(2)
2968
2969 def InnermostClass(self):
2970 """Get class info on the top of the stack.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002971
2972 Returns:
2973 A _ClassInfo object if we are inside a class, or None otherwise.
2974 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002975 for i in range(len(self.stack), 0, -1):
2976 classinfo = self.stack[i - 1]
2977 if isinstance(classinfo, _ClassInfo):
2978 return classinfo
2979 return None
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00002980
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002981 def CheckCompletedBlocks(self, filename, error):
2982 """Checks that all classes and namespaces have been completely parsed.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00002983
2984 Call this when all lines in a file have been processed.
2985 Args:
2986 filename: The name of the current file.
2987 error: The function to call with any errors found.
2988 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00002989 # Note: This test can result in false positives if #ifdef constructs
2990 # get in the way of brace matching. See the testBuildClass test in
2991 # cpplint_unittest.py for an example of this.
2992 for obj in self.stack:
2993 if isinstance(obj, _ClassInfo):
2994 error(
2995 filename, obj.starting_linenum, 'build/class', 5,
2996 'Failed to find complete declaration of class %s' %
2997 obj.name)
2998 elif isinstance(obj, _NamespaceInfo):
2999 error(
3000 filename, obj.starting_linenum, 'build/namespaces', 5,
3001 'Failed to find complete declaration of namespace %s' %
3002 obj.name)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003003
3004
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003005def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state,
3006 error):
3007 r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003008
3009 Complain about several constructs which gcc-2 accepts, but which are
3010 not standard C++. Warning about these in lint is one way to ease the
3011 transition to new compilers.
3012 - put storage class first (e.g. "static const" instead of "const static").
3013 - "%lld" instead of %qd" in printf-type functions.
3014 - "%1$d" is non-standard in printf-type functions.
3015 - "\%" is an undefined character escape sequence.
3016 - text after #endif is not allowed.
3017 - invalid inner-style forward declaration.
3018 - >? and <? operators, and their >?= and <?= cousins.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003019
erg@google.com26970fa2009-11-17 18:07:32 +00003020 Additionally, check for constructor/destructor style violations and reference
3021 members, as it is very convenient to do so while checking for
3022 gcc-2 compliance.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003023
3024 Args:
3025 filename: The name of the current file.
3026 clean_lines: A CleansedLines instance containing the file.
3027 linenum: The number of the line to check.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003028 nesting_state: A NestingState instance which maintains information about
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00003029 the current stack of nested blocks being parsed.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003030 error: A callable to which errors are reported, which takes 4 arguments:
3031 filename, line number, error level, and message
3032 """
3033
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003034 # Remove comments from the line, but leave in strings for now.
3035 line = clean_lines.lines[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003036
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003037 if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
3038 error(filename, linenum, 'runtime/printf_format', 3,
3039 '%q in format strings is deprecated. Use %ll instead.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003040
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003041 if Search(r'printf\s*\(.*".*%\d+\$', line):
3042 error(filename, linenum, 'runtime/printf_format', 2,
3043 '%N$ formats are unconventional. Try rewriting to avoid them.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003044
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003045 # Remove escaped backslashes before looking for undefined escapes.
3046 line = line.replace('\\\\', '')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003047
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003048 if Search(r'("|\').*\\(%|\[|\(|{)', line):
3049 error(
3050 filename, linenum, 'build/printf_format', 3,
3051 '%, [, (, and { are undefined character escapes. Unescape them.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003052
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003053 # For the rest, work with both comments and strings removed.
3054 line = clean_lines.elided[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003055
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003056 if Search(
3057 r'\b(const|volatile|void|char|short|int|long'
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003058 r'|float|double|signed|unsigned'
3059 r'|schar|u?int8|u?int16|u?int32|u?int64)'
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003060 r'\s+(register|static|extern|typedef)\b', line):
3061 error(
3062 filename, linenum, 'build/storage_class', 5,
3063 'Storage-class specifier (static, extern, typedef, etc) should be '
3064 'at the beginning of the declaration.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003065
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003066 if Match(r'\s*#\s*endif\s*[^/\s]+', line):
3067 error(filename, linenum, 'build/endif_comment', 5,
3068 'Uncommented text after #endif is non-standard. Use a comment.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003069
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003070 if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
3071 error(
3072 filename, linenum, 'build/forward_decl', 5,
3073 'Inner-style forward declarations are invalid. Remove this line.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003074
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003075 if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
3076 line):
3077 error(
3078 filename, linenum, 'build/deprecated', 3,
3079 '>? and <? (max and min) operators are non-standard and deprecated.'
3080 )
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003081
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003082 if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
3083 # TODO(unknown): Could it be expanded safely to arbitrary references,
3084 # without triggering too many false positives? The first
3085 # attempt triggered 5 warnings for mostly benign code in the regtest,
3086 # hence the restriction. Here's the original regexp, for the reference:
3087 # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?' r'\s*const\s*' +
3088 # type_name + '\s*&\s*\w+\s*;'
3089 error(
3090 filename, linenum, 'runtime/member_string_references', 2,
3091 'const string& members are dangerous. It is much better to use '
3092 'alternatives, such as pointers or simple constants.')
erg@google.com26970fa2009-11-17 18:07:32 +00003093
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003094 # Everything else in this function operates on class declarations.
3095 # Return early if the top of the nesting stack is not a class, or if
3096 # the class head is not completed yet.
3097 classinfo = nesting_state.InnermostClass()
3098 if not classinfo or not classinfo.seen_open_brace:
3099 return
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003100
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003101 # The class may have been declared with namespace or classname qualifiers.
3102 # The constructor and destructor will not have those qualifiers.
3103 base_classname = classinfo.name.split('::')[-1]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003104
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003105 # Look for single-argument constructors that aren't marked explicit.
3106 # Technically a valid construct, but against style.
3107 explicit_constructor_match = Match(
3108 r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?'
3109 r'(?:(?:inline|constexpr)\s+)*%s\s*'
3110 r'\(((?:[^()]|\([^()]*\))*)\)' % re.escape(base_classname), line)
avakulenko@google.com59146752014-08-11 20:20:55 +00003111
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003112 if explicit_constructor_match:
3113 is_marked_explicit = explicit_constructor_match.group(1)
avakulenko@google.com59146752014-08-11 20:20:55 +00003114
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003115 if not explicit_constructor_match.group(2):
3116 constructor_args = []
3117 else:
3118 constructor_args = explicit_constructor_match.group(2).split(',')
avakulenko@google.com59146752014-08-11 20:20:55 +00003119
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003120 # collapse arguments so that commas in template parameter lists and
3121 # function argument parameter lists don't split arguments in two
3122 i = 0
3123 while i < len(constructor_args):
3124 constructor_arg = constructor_args[i]
3125 while (constructor_arg.count('<') > constructor_arg.count('>')
3126 or constructor_arg.count('(') > constructor_arg.count(')')):
3127 constructor_arg += ',' + constructor_args[i + 1]
3128 del constructor_args[i + 1]
3129 constructor_args[i] = constructor_arg
3130 i += 1
avakulenko@google.com59146752014-08-11 20:20:55 +00003131
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003132 defaulted_args = [arg for arg in constructor_args if '=' in arg]
3133 noarg_constructor = (
3134 not constructor_args or # empty arg list
3135 # 'void' arg specifier
3136 (len(constructor_args) == 1
3137 and constructor_args[0].strip() == 'void'))
3138 onearg_constructor = (
3139 (
3140 len(constructor_args) == 1 and # exactly one arg
3141 not noarg_constructor) or
3142 # all but at most one arg defaulted
3143 (len(constructor_args) >= 1 and not noarg_constructor
3144 and len(defaulted_args) >= len(constructor_args) - 1))
3145 initializer_list_constructor = bool(
3146 onearg_constructor
3147 and Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
3148 copy_constructor = bool(onearg_constructor and Match(
3149 r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' %
3150 re.escape(base_classname), constructor_args[0].strip()))
avakulenko@google.com59146752014-08-11 20:20:55 +00003151
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003152 if (not is_marked_explicit and onearg_constructor
3153 and not initializer_list_constructor and not copy_constructor):
3154 if defaulted_args:
3155 error(
3156 filename, linenum, 'runtime/explicit', 5,
3157 'Constructors callable with one argument '
3158 'should be marked explicit.')
3159 else:
3160 error(
3161 filename, linenum, 'runtime/explicit', 5,
3162 'Single-parameter constructors should be marked explicit.')
3163 elif is_marked_explicit and not onearg_constructor:
3164 if noarg_constructor:
3165 error(
3166 filename, linenum, 'runtime/explicit', 5,
3167 'Zero-parameter constructors should not be marked explicit.'
3168 )
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003169
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003170
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003171def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003172 """Checks for the correctness of various spacing around function calls.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003173
3174 Args:
3175 filename: The name of the current file.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003176 clean_lines: A CleansedLines instance containing the file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003177 linenum: The number of the line to check.
3178 error: The function to call with any errors found.
3179 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003180 line = clean_lines.elided[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003181
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003182 # Since function calls often occur inside if/for/while/switch
3183 # expressions - which have their own, more liberal conventions - we
3184 # first see if we should be looking inside such an expression for a
3185 # function call, to which we can apply more strict standards.
3186 fncall = line # if there's no control flow construct, look at whole line
3187 for pattern in (r'\bif\s*(?:constexpr\s*)?\((.*)\)\s*{',
3188 r'\bfor\s*\((.*)\)\s*{', r'\bwhile\s*\((.*)\)\s*[{;]',
3189 r'\bswitch\s*\((.*)\)\s*{'):
3190 match = Search(pattern, line)
3191 if match:
3192 fncall = match.group(1) # look inside the parens for function calls
3193 break
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003194
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003195 # Except in if/for/while/switch, there should never be space
3196 # immediately inside parens (eg "f( 3, 4 )"). We make an exception
3197 # for nested parens ( (a+b) + c ). Likewise, there should never be
3198 # a space before a ( when it's a function argument. I assume it's a
3199 # function argument when the char before the whitespace is legal in
3200 # a function name (alnum + _) and we're not starting a macro. Also ignore
3201 # pointers and references to arrays and functions coz they're too tricky:
3202 # we use a very simple way to recognize these:
3203 # " (something)(maybe-something)" or
3204 # " (something)(maybe-something," or
3205 # " (something)[something]"
3206 # Note that we assume the contents of [] to be short enough that
3207 # they'll never need to wrap.
3208 if ( # Ignore control structures.
3209 not Search(
3210 r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b',
3211 fncall) and
3212 # Ignore pointers/references to functions.
3213 not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
3214 # Ignore pointers/references to arrays.
3215 not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
3216 if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call
3217 error(filename, linenum, 'whitespace/parens', 4,
3218 'Extra space after ( in function call')
3219 elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
3220 error(filename, linenum, 'whitespace/parens', 2,
3221 'Extra space after (')
3222 if (Search(r'\w\s+\(', fncall) and not Search(
3223 r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall)
3224 and not Search(r'#\s*define|typedef|__except|using\s+\w+\s*=',
3225 fncall)
3226 and not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall)
3227 and not Search(r'\bcase\s+\(', fncall)):
3228 # TODO(unknown): Space after an operator function seem to be a
3229 # common error, silence those for now by restricting them to highest
3230 # verbosity.
3231 if Search(r'\boperator_*\b', line):
3232 error(filename, linenum, 'whitespace/parens', 0,
3233 'Extra space before ( in function call')
3234 else:
3235 error(filename, linenum, 'whitespace/parens', 4,
3236 'Extra space before ( in function call')
3237 # If the ) is followed only by a newline or a { + newline, assume it's
3238 # part of a control statement (if/while/etc), and don't complain
3239 if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
3240 # If the closing parenthesis is preceded by only whitespaces,
3241 # try to give a more descriptive error message.
3242 if Search(r'^\s+\)', fncall):
3243 error(filename, linenum, 'whitespace/parens', 2,
3244 'Closing ) should be moved to the previous line')
3245 else:
3246 error(filename, linenum, 'whitespace/parens', 2,
3247 'Extra space before )')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003248
3249
3250def IsBlankLine(line):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003251 """Returns true if the given line is blank.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003252
3253 We consider a line to be blank if the line is empty or consists of
3254 only white spaces.
3255
3256 Args:
3257 line: A line of a string.
3258
3259 Returns:
3260 True, if the given line is blank.
3261 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003262 return not line or line.isspace()
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003263
3264
avakulenko@google.com59146752014-08-11 20:20:55 +00003265def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
3266 error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003267 is_namespace_indent_item = (
3268 len(nesting_state.stack) > 1
3269 and nesting_state.stack[-1].check_namespace_indentation
3270 and isinstance(nesting_state.previous_stack_top, _NamespaceInfo)
3271 and nesting_state.previous_stack_top == nesting_state.stack[-2])
avakulenko@google.com59146752014-08-11 20:20:55 +00003272
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003273 if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
3274 clean_lines.elided, line):
3275 CheckItemIndentationInNamespace(filename, clean_lines.elided, line,
3276 error)
avakulenko@google.com59146752014-08-11 20:20:55 +00003277
3278
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003279def CheckForFunctionLengths(filename, clean_lines, linenum, function_state,
3280 error):
3281 """Reports for long function bodies.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003282
3283 For an overview why this is done, see:
Alexandr Ilinff294c32017-04-27 15:57:40 +02003284 https://google.github.io/styleguide/cppguide.html#Write_Short_Functions
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003285
3286 Uses a simplistic algorithm assuming other style guidelines
3287 (especially spacing) are followed.
3288 Only checks unindented functions, so class members are unchecked.
3289 Trivial bodies are unchecked, so constructors with huge initializer lists
3290 may be missed.
3291 Blank/comment lines are not counted so as to avoid encouraging the removal
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003292 of vertical space and comments just to get through a lint check.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003293 NOLINT *on the last line of a function* disables this check.
3294
3295 Args:
3296 filename: The name of the current file.
3297 clean_lines: A CleansedLines instance containing the file.
3298 linenum: The number of the line to check.
3299 function_state: Current function name and lines in body so far.
3300 error: The function to call with any errors found.
3301 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003302 lines = clean_lines.lines
3303 line = lines[linenum]
3304 joined_line = ''
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003305
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003306 starting_func = False
3307 regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ...
3308 match_result = Match(regexp, line)
3309 if match_result:
3310 # If the name is all caps and underscores, figure it's a macro and
3311 # ignore it, unless it's TEST or TEST_F.
3312 function_name = match_result.group(1).split()[-1]
3313 if function_name == 'TEST' or function_name == 'TEST_F' or (not Match(
3314 r'[A-Z_0-9]+$', function_name)):
3315 starting_func = True
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003316
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003317 if starting_func:
3318 body_found = False
3319 for start_linenum in range(linenum, clean_lines.NumLines()):
3320 start_line = lines[start_linenum]
3321 joined_line += ' ' + start_line.lstrip()
3322 if Search(r'(;|})',
3323 start_line): # Declarations and trivial functions
3324 body_found = True
3325 break # ... ignore
3326 elif Search(r'{', start_line):
3327 body_found = True
3328 function = Search(r'((\w|:)*)\(', line).group(1)
3329 if Match(r'TEST', function): # Handle TEST... macros
3330 parameter_regexp = Search(r'(\(.*\))', joined_line)
3331 if parameter_regexp: # Ignore bad syntax
3332 function += parameter_regexp.group(1)
3333 else:
3334 function += '()'
3335 function_state.Begin(function)
3336 break
3337 if not body_found:
3338 # No body for the function (or evidence of a non-function) was
3339 # found.
3340 error(filename, linenum, 'readability/fn_size', 5,
3341 'Lint failed to find start of function body.')
3342 elif Match(r'^\}\s*$', line): # function end
3343 function_state.Check(error, filename, linenum)
3344 function_state.End()
3345 elif not Match(r'^\s*$', line):
3346 function_state.Count() # Count non-blank/non-comment lines.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003347
3348
Matthias Liedtke8eac0c62023-07-06 08:09:07 +00003349_RE_PATTERN_TODO = re.compile(
3350 r'^//(\s*)TODO(?:(\(.+?\)):?|:|)(\s|$|[A-Z]*[a-z])')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003351
3352
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003353def CheckComment(line, filename, linenum, next_line_start, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003354 """Checks for common mistakes in comments.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003355
3356 Args:
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003357 line: The line in question.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003358 filename: The name of the current file.
3359 linenum: The number of the line to check.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003360 next_line_start: The first non-whitespace column of the next line.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003361 error: The function to call with any errors found.
3362 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003363 commentpos = line.find('//')
3364 if commentpos != -1:
3365 # Check if the // may be in quotes. If so, ignore it
3366 if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0:
3367 # Allow one space for new scopes, two spaces otherwise:
3368 if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos)
3369 and ((commentpos >= 1
3370 and line[commentpos - 1] not in string.whitespace) or
3371 (commentpos >= 2
3372 and line[commentpos - 2] not in string.whitespace))):
3373 error(filename, linenum, 'whitespace/comments', 2,
3374 'At least two spaces is best between code and comments')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003375
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003376 # Checks for common mistakes in TODO comments.
3377 comment = line[commentpos:]
3378 match = _RE_PATTERN_TODO.match(comment)
3379 if match:
3380 # One whitespace is correct; zero whitespace is handled
3381 # elsewhere.
3382 leading_whitespace = match.group(1)
3383 if len(leading_whitespace) > 1:
3384 error(filename, linenum, 'whitespace/todo', 2,
3385 'Too many spaces before TODO')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003386
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003387 username = match.group(2)
3388 if not username:
3389 error(
3390 filename, linenum, 'readability/todo', 2,
3391 'Missing username in TODO; it should look like '
3392 '"// TODO(my_username): Stuff."')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003393
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003394 middle_whitespace = match.group(3)
3395 # Comparisons made explicit for correctness -- pylint:
3396 # disable=g-explicit-bool-comparison
3397 if middle_whitespace != ' ' and middle_whitespace != '':
3398 error(filename, linenum, 'whitespace/todo', 2,
3399 'TODO(my_username) should be followed by a space')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003400
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003401 # If the comment contains an alphanumeric character, there
3402 # should be a space somewhere between it and the // unless
3403 # it's a /// or //! Doxygen comment.
3404 if (Match(r'//[^ ]*\w', comment)
3405 and not Match(r'(///|//\!)(\s+|$)', comment)):
3406 error(filename, linenum, 'whitespace/comments', 4,
3407 'Should have a space between // and comment')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003408
avakulenko@google.com255f2be2014-12-05 22:19:55 +00003409
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00003410def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003411 """Checks for the correctness of various spacing issues in the code.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003412
3413 Things we check for: spaces around operators, spaces after
3414 if/for/while/switch, no spaces around parens in function calls, two
3415 spaces between code and comment, don't start a block with a blank
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003416 line, don't end a function with a blank line, don't add a blank line
3417 after public/protected/private, don't have too many blank lines in a row.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003418
3419 Args:
3420 filename: The name of the current file.
3421 clean_lines: A CleansedLines instance containing the file.
3422 linenum: The number of the line to check.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003423 nesting_state: A NestingState instance which maintains information about
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00003424 the current stack of nested blocks being parsed.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003425 error: The function to call with any errors found.
3426 """
3427
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003428 # Don't use "elided" lines here, otherwise we can't check commented lines.
3429 # Don't want to use "raw" either, because we don't want to check inside
3430 # C++11 raw strings,
3431 raw = clean_lines.lines_without_raw_strings
3432 line = raw[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003433
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003434 # Before nixing comments, check if the line is blank for no good
3435 # reason. This includes the first line after a block is opened, and
3436 # blank lines at the end of a function (ie, right before a line like '}'
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003437 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003438 # Skip all the blank line checks if we are immediately inside a
3439 # namespace body. In other words, don't issue blank line warnings
3440 # for this block:
3441 # namespace {
3442 #
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003443 # }
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003444 #
3445 # A warning about missing end of namespace comments will be issued instead.
3446 #
3447 # Also skip blank line checks for 'extern "C"' blocks, which are formatted
3448 # like namespaces.
3449 if (IsBlankLine(line) and not nesting_state.InNamespaceBody()
3450 and not nesting_state.InExternC()):
3451 elided = clean_lines.elided
3452 prev_line = elided[linenum - 1]
3453 prevbrace = prev_line.rfind('{')
3454 # TODO(unknown): Don't complain if line before blank line, and line
3455 # after, both start with alnums and are indented the same amount. This
3456 # ignores whitespace at the start of a namespace block because those are
3457 # not usually indented.
3458 if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
3459 # OK, we have a blank line at the start of a code block. Before we
3460 # complain, we check if it is an exception to the rule: The previous
3461 # non-empty line has the parameters of a function header that are
3462 # indented 4 spaces (because they did not fit in a 80 column line
3463 # when placed on the same line as the function name). We also check
3464 # for the case where the previous line is indented 6 spaces, which
3465 # may happen when the initializers of a constructor do not fit into
3466 # a 80 column line.
3467 exception = False
3468 if Match(r' {6}\w', prev_line): # Initializer list?
3469 # We are looking for the opening column of initializer list,
3470 # which should be indented 4 spaces to cause 6 space indentation
3471 # afterwards.
3472 search_position = linenum - 2
3473 while (search_position >= 0
3474 and Match(r' {6}\w', elided[search_position])):
3475 search_position -= 1
3476 exception = (search_position >= 0
3477 and elided[search_position][:5] == ' :')
3478 else:
3479 # Search for the function arguments or an initializer list. We
3480 # use a simple heuristic here: If the line is indented 4 spaces;
3481 # and we have a closing paren, without the opening paren,
3482 # followed by an opening brace or colon (for initializer lists)
3483 # we assume that it is the last line of a function header. If
3484 # we have a colon indented 4 spaces, it is an initializer list.
3485 exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
3486 prev_line) or Match(r' {4}:', prev_line))
3487
3488 if not exception:
3489 error(
3490 filename, linenum, 'whitespace/blank_line', 2,
3491 'Redundant blank line at the start of a code block '
3492 'should be deleted.')
3493 # Ignore blank lines at the end of a block in a long if-else
3494 # chain, like this:
3495 # if (condition1) {
3496 # // Something followed by a blank line
3497 #
3498 # } else if (condition2) {
3499 # // Something else
3500 # }
3501 if linenum + 1 < clean_lines.NumLines():
3502 next_line = raw[linenum + 1]
3503 if (next_line and Match(r'\s*}', next_line)
3504 and next_line.find('} else ') == -1):
3505 error(
3506 filename, linenum, 'whitespace/blank_line', 3,
3507 'Redundant blank line at the end of a code block '
3508 'should be deleted.')
3509
3510 matched = Match(r'\s*(public|protected|private):', prev_line)
3511 if matched:
3512 error(filename, linenum, 'whitespace/blank_line', 3,
3513 'Do not leave a blank line after "%s:"' % matched.group(1))
3514
3515 # Next, check comments
3516 next_line_start = 0
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003517 if linenum + 1 < clean_lines.NumLines():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003518 next_line = raw[linenum + 1]
3519 next_line_start = len(next_line) - len(next_line.lstrip())
3520 CheckComment(line, filename, linenum, next_line_start, error)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003521
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003522 # get rid of comments and strings
3523 line = clean_lines.elided[linenum]
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003524
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003525 # You shouldn't have spaces before your brackets, except maybe after
3526 # 'delete []', 'return []() {};', 'auto [abc, ...] = ...;' or in the case of
3527 # c++ attributes like 'class [[clang::lto_visibility_public]] MyClass'.
3528 if (Search(r'\w\s+\[', line)
3529 and not Search(r'(?:auto&?|delete|return)\s+\[', line)
3530 and not Search(r'\s+\[\[', line)):
3531 error(filename, linenum, 'whitespace/braces', 5, 'Extra space before [')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003532
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003533 # In range-based for, we wanted spaces before and after the colon, but
3534 # not around "::" tokens that might appear.
3535 if (Search(r'for *\(.*[^:]:[^: ]', line)
3536 or Search(r'for *\(.*[^: ]:[^:]', line)):
3537 error(filename, linenum, 'whitespace/forcolon', 2,
3538 'Missing space around colon in range-based for loop')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003539
3540
3541def CheckOperatorSpacing(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003542 """Checks for horizontal spacing around operators.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003543
3544 Args:
3545 filename: The name of the current file.
3546 clean_lines: A CleansedLines instance containing the file.
3547 linenum: The number of the line to check.
3548 error: The function to call with any errors found.
3549 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003550 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003551
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003552 # Don't try to do spacing checks for operator methods. Do this by
3553 # replacing the troublesome characters with something else,
3554 # preserving column position for all other characters.
3555 #
3556 # The replacement is done repeatedly to avoid false positives from
3557 # operators that call operators.
3558 while True:
3559 match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line)
3560 if match:
3561 line = match.group(1) + ('_' * len(match.group(2))) + match.group(3)
3562 else:
3563 break
3564
3565 # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
3566 # Otherwise not. Note we only check for non-spaces on *both* sides;
3567 # sometimes people put non-spaces on one side when aligning ='s among
3568 # many lines (not that this is behavior that I approve of...)
3569 if ((Search(r'[\w.]=', line) or Search(r'=[\w.]', line))
3570 and not Search(r'\b(if|while|for) ', line)
3571 # Operators taken from [lex.operators] in C++11 standard.
3572 and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line)
3573 and not Search(r'operator=', line)):
3574 error(filename, linenum, 'whitespace/operators', 4,
3575 'Missing spaces around =')
3576
3577 # It's ok not to have spaces around binary operators like + - * /, but if
3578 # there's too little whitespace, we get concerned. It's hard to tell,
3579 # though, so we punt on this one for now. TODO.
3580
3581 # You should always have whitespace around binary operators.
3582 #
3583 # Check <= and >= first to avoid false positives with < and >, then
3584 # check non-include lines for spacing around < and >.
3585 #
3586 # If the operator is followed by a comma, assume it's be used in a
3587 # macro context and don't do any checks. This avoids false
3588 # positives.
3589 #
3590 # Note that && is not included here. This is because there are too
3591 # many false positives due to RValue references.
3592 match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003593 if match:
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003594 error(filename, linenum, 'whitespace/operators', 3,
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003595 'Missing spaces around %s' % match.group(1))
3596 elif not Match(r'#.*include', line):
3597 # Look for < that is not surrounded by spaces. This is only
3598 # triggered if both sides are missing spaces, even though
3599 # technically should should flag if at least one side is missing a
3600 # space. This is done to avoid some false positives with shifts.
3601 match = Match(r'^(.*[^\s<])<[^\s=<,]', line)
3602 if match:
3603 (_, _, end_pos) = CloseExpression(clean_lines, linenum,
3604 len(match.group(1)))
3605 if end_pos <= -1:
3606 error(filename, linenum, 'whitespace/operators', 3,
3607 'Missing spaces around <')
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00003608
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003609 # Look for > that is not surrounded by spaces. Similar to the
3610 # above, we only trigger if both sides are missing spaces to avoid
3611 # false positives with shifts.
3612 match = Match(r'^(.*[^-\s>])>[^\s=>,]', line)
3613 if match:
3614 (_, _, start_pos) = ReverseCloseExpression(clean_lines, linenum,
3615 len(match.group(1)))
3616 if start_pos <= -1:
3617 error(filename, linenum, 'whitespace/operators', 3,
3618 'Missing spaces around >')
3619
3620 # We allow no-spaces around << when used like this: 10<<20, but
3621 # not otherwise (particularly, not when used as streams)
3622 #
3623 # We also allow operators following an opening parenthesis, since
3624 # those tend to be macros that deal with operators.
3625 match = Search(
3626 r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line)
3627 if (match and not (match.group(1).isdigit() and match.group(2).isdigit())
3628 and not (match.group(1) == 'operator' and match.group(2) == ';')):
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003629 error(filename, linenum, 'whitespace/operators', 3,
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003630 'Missing spaces around <<')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003631
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003632 # We allow no-spaces around >> for almost anything. This is because
3633 # C++11 allows ">>" to close nested templates, which accounts for
3634 # most cases when ">>" is not followed by a space.
3635 #
3636 # We still warn on ">>" followed by alpha character, because that is
3637 # likely due to ">>" being used for right shifts, e.g.:
3638 # value >> alpha
3639 #
3640 # When ">>" is used to close templates, the alphanumeric letter that
3641 # follows would be part of an identifier, and there should still be
3642 # a space separating the template type and the identifier.
3643 # type<type<type>> alpha
3644 match = Search(r'>>[a-zA-Z_]', line)
3645 if match:
3646 error(filename, linenum, 'whitespace/operators', 3,
3647 'Missing spaces around >>')
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00003648
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003649 # There shouldn't be space around unary operators
3650 match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
3651 if match:
3652 error(filename, linenum, 'whitespace/operators', 4,
3653 'Extra space for operator %s' % match.group(1))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003654
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003655
3656def CheckParenthesisSpacing(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003657 """Checks for horizontal spacing around parentheses.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003658
3659 Args:
3660 filename: The name of the current file.
3661 clean_lines: A CleansedLines instance containing the file.
3662 linenum: The number of the line to check.
3663 error: The function to call with any errors found.
3664 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003665 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003666
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003667 # No spaces after an if, while, switch, or for
3668 match = Search(r' (if\(|for\(|while\(|switch\()', line)
3669 if match:
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003670 error(filename, linenum, 'whitespace/parens', 5,
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003671 'Missing space before ( in %s' % match.group(1))
3672
3673 # For if/for/while/switch, the left and right parens should be
3674 # consistent about how many spaces are inside the parens, and
3675 # there should either be zero or one spaces inside the parens.
3676 # We don't want: "if ( foo)" or "if ( foo )".
3677 # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
3678 match = Search(
3679 r'\b(if|for|while|switch)\s*'
3680 r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', line)
3681 if match:
3682 if len(match.group(2)) != len(match.group(4)):
3683 if not (match.group(3) == ';'
3684 and len(match.group(2)) == 1 + len(match.group(4)) or
3685 not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
3686 error(filename, linenum, 'whitespace/parens', 5,
3687 'Mismatching spaces inside () in %s' % match.group(1))
3688 if len(match.group(2)) not in [0, 1]:
3689 error(
3690 filename, linenum, 'whitespace/parens', 5,
3691 'Should have zero or one spaces inside ( and ) in %s' %
3692 match.group(1))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003693
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003694
3695def CheckCommaSpacing(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003696 """Checks for horizontal spacing near commas and semicolons.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003697
3698 Args:
3699 filename: The name of the current file.
3700 clean_lines: A CleansedLines instance containing the file.
3701 linenum: The number of the line to check.
3702 error: The function to call with any errors found.
3703 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003704 raw = clean_lines.lines_without_raw_strings
3705 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003706
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003707 # You should always have a space after a comma (either as fn arg or
3708 # operator)
3709 #
3710 # This does not apply when the non-space character following the
3711 # comma is another comma, since the only time when that happens is
3712 # for empty macro arguments.
3713 #
3714 # We run this check in two passes: first pass on elided lines to
3715 # verify that lines contain missing whitespaces, second pass on raw
3716 # lines to confirm that those missing whitespaces are not due to
3717 # elided comments.
3718 if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line))
3719 and Search(r',[^,\s]', raw[linenum])):
3720 error(filename, linenum, 'whitespace/comma', 3, 'Missing space after ,')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003721
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003722 # You should always have a space after a semicolon
3723 # except for few corner cases
3724 # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
3725 # space after ;
3726 if Search(r';[^\s};\\)/]', line):
3727 error(filename, linenum, 'whitespace/semicolon', 3,
3728 'Missing space after ;')
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003729
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003730
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003731def _IsType(clean_lines, nesting_state, expr):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003732 """Check if expression looks like a type name, returns true if so.
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003733
3734 Args:
3735 clean_lines: A CleansedLines instance containing the file.
3736 nesting_state: A NestingState instance which maintains information about
3737 the current stack of nested blocks being parsed.
3738 expr: The expression to check.
3739 Returns:
3740 True, if token looks like a type.
3741 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003742 # Keep only the last token in the expression
3743 last_word = Match(r'^.*(\b\S+)$', expr)
3744 if last_word:
3745 token = last_word.group(1)
3746 else:
3747 token = expr
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003748
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003749 # Match native types and stdint types
3750 if _TYPES.match(token):
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003751 return True
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003752
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003753 # Try a bit harder to match templated types. Walk up the nesting
3754 # stack until we find something that resembles a typename
3755 # declaration for what we are looking for.
3756 typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) +
3757 r'\b')
3758 block_index = len(nesting_state.stack) - 1
3759 while block_index >= 0:
3760 if isinstance(nesting_state.stack[block_index], _NamespaceInfo):
3761 return False
3762
3763 # Found where the opening brace is. We want to scan from this
3764 # line up to the beginning of the function, minus a few lines.
3765 # template <typename Type1, // stop scanning here
3766 # ...>
3767 # class C
3768 # : public ... { // start scanning here
3769 last_line = nesting_state.stack[block_index].starting_linenum
3770
3771 next_block_start = 0
3772 if block_index > 0:
3773 next_block_start = nesting_state.stack[block_index -
3774 1].starting_linenum
3775 first_line = last_line
3776 while first_line >= next_block_start:
3777 if clean_lines.elided[first_line].find('template') >= 0:
3778 break
3779 first_line -= 1
3780 if first_line < next_block_start:
3781 # Didn't find any "template" keyword before reaching the next block,
3782 # there are probably no template things to check for this block
3783 block_index -= 1
3784 continue
3785
3786 # Look for typename in the specified range
3787 for i in range(first_line, last_line + 1, 1):
3788 if Search(typename_pattern, clean_lines.elided[i]):
3789 return True
3790 block_index -= 1
3791
3792 return False
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003793
3794
3795def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003796 """Checks for horizontal spacing near commas.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003797
3798 Args:
3799 filename: The name of the current file.
3800 clean_lines: A CleansedLines instance containing the file.
3801 linenum: The number of the line to check.
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003802 nesting_state: A NestingState instance which maintains information about
3803 the current stack of nested blocks being parsed.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003804 error: The function to call with any errors found.
3805 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003806 line = clean_lines.elided[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003807
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003808 # Except after an opening paren, or after another opening brace (in case of
3809 # an initializer list, for instance), you should have spaces before your
3810 # braces when they are delimiting blocks, classes, namespaces etc.
3811 # And since you should never have braces at the beginning of a line,
3812 # this is an easy test. Except that braces used for initialization don't
3813 # follow the same rule; we often don't want spaces before those.
3814 match = Match(r'^(.*[^ ({>]){', line)
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00003815
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003816 if match:
3817 # Try a bit harder to check for brace initialization. This
3818 # happens in one of the following forms:
3819 # Constructor() : initializer_list_{} { ... }
3820 # Constructor{}.MemberFunction()
3821 # Type variable{};
3822 # FunctionCall(type{}, ...);
3823 # LastArgument(..., type{});
3824 # LOG(INFO) << type{} << " ...";
3825 # map_of_type[{...}] = ...;
3826 # ternary = expr ? new type{} : nullptr;
3827 # OuterTemplate<InnerTemplateConstructor<Type>{}>
3828 #
3829 # We check for the character following the closing brace, and
3830 # silence the warning if it's one of those listed above, i.e.
3831 # "{.;,)<>]:".
3832 #
3833 # To account for nested initializer list, we allow any number of
3834 # closing braces up to "{;,)<". We can't simply silence the
3835 # warning on first sight of closing brace, because that would
3836 # cause false negatives for things that are not initializer lists.
3837 # Silence this: But not this:
3838 # Outer{ if (...) {
3839 # Inner{...} if (...){ // Missing space before {
3840 # }; }
3841 #
3842 # There is a false negative with this approach if people inserted
3843 # spurious semicolons, e.g. "if (cond){};", but we will catch the
3844 # spurious semicolon with a separate check.
3845 leading_text = match.group(1)
3846 (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum,
3847 len(match.group(1)))
3848 trailing_text = ''
3849 if endpos > -1:
3850 trailing_text = endline[endpos:]
3851 for offset in range(endlinenum + 1,
3852 min(endlinenum + 3,
3853 clean_lines.NumLines() - 1)):
3854 trailing_text += clean_lines.elided[offset]
3855 # We also suppress warnings for `uint64_t{expression}` etc., as the
3856 # style guide recommends brace initialization for integral types to
3857 # avoid overflow/truncation.
3858 if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text)
3859 and not _IsType(clean_lines, nesting_state, leading_text)):
3860 error(filename, linenum, 'whitespace/braces', 5,
3861 'Missing space before {')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003862
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003863 # Make sure '} else {' has spaces.
3864 if Search(r'}else', line):
3865 error(filename, linenum, 'whitespace/braces', 5,
3866 'Missing space before else')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003867
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003868 # You shouldn't have a space before a semicolon at the end of the line.
3869 # There's a special case for "for" since the style guide allows space before
3870 # the semicolon there.
3871 if Search(r':\s*;\s*$', line):
3872 error(filename, linenum, 'whitespace/semicolon', 5,
3873 'Semicolon defining empty statement. Use {} instead.')
3874 elif Search(r'^\s*;\s*$', line):
3875 error(
3876 filename, linenum, 'whitespace/semicolon', 5,
3877 'Line contains only semicolon. If this should be an empty statement, '
3878 'use {} instead.')
3879 elif (Search(r'\s+;\s*$', line) and not Search(r'\bfor\b', line)):
3880 error(
3881 filename, linenum, 'whitespace/semicolon', 5,
3882 'Extra space before last semicolon. If this should be an empty '
3883 'statement, use {} instead.')
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00003884
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003885
3886def IsDecltype(clean_lines, linenum, column):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003887 """Check if the token ending on (linenum, column) is decltype().
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003888
3889 Args:
3890 clean_lines: A CleansedLines instance containing the file.
3891 linenum: the number of the line to check.
3892 column: end column of the token to check.
3893 Returns:
3894 True if this token is decltype() expression, False otherwise.
3895 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003896 (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column)
3897 if start_col < 0:
3898 return False
3899 if Search(r'\bdecltype\s*$', text[0:start_col]):
3900 return True
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003901 return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00003902
3903
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003904def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003905 """Checks for additional blank line issues related to sections.
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003906
3907 Currently the only thing checked here is blank line before protected/private.
3908
3909 Args:
3910 filename: The name of the current file.
3911 clean_lines: A CleansedLines instance containing the file.
3912 class_info: A _ClassInfo objects.
3913 linenum: The number of the line to check.
3914 error: The function to call with any errors found.
3915 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003916 # Skip checks if the class is small, where small means 25 lines or less.
3917 # 25 lines seems like a good cutoff since that's the usual height of
3918 # terminals, and any class that can't fit in one screen can't really
3919 # be considered "small".
3920 #
3921 # Also skip checks if we are on the first line. This accounts for
3922 # classes that look like
3923 # class Foo { public: ... };
3924 #
3925 # If we didn't find the end of the class, last_line would be zero,
3926 # and the check will be skipped by the first condition.
3927 if (class_info.last_line - class_info.starting_linenum <= 24
3928 or linenum <= class_info.starting_linenum):
3929 return
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003930
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003931 matched = Match(r'\s*(public|protected|private):',
3932 clean_lines.lines[linenum])
3933 if matched:
3934 # Issue warning if the line before public/protected/private was
3935 # not a blank line, but don't do this if the previous line contains
3936 # "class" or "struct". This can happen two ways:
3937 # - We are at the beginning of the class.
3938 # - We are forward-declaring an inner class that is semantically
3939 # private, but needed to be public for implementation reasons.
3940 # Also ignores cases where the previous line ends with a backslash as
3941 # can be common when defining classes in C macros.
3942 prev_line = clean_lines.lines[linenum - 1]
3943 if (not IsBlankLine(prev_line)
3944 and not Search(r'\b(class|struct)\b', prev_line)
3945 and not Search(r'\\$', prev_line)):
3946 # Try a bit harder to find the beginning of the class. This is to
3947 # account for multi-line base-specifier lists, e.g.:
3948 # class Derived
3949 # : public Base {
3950 end_class_head = class_info.starting_linenum
3951 for i in range(class_info.starting_linenum, linenum):
3952 if Search(r'\{\s*$', clean_lines.lines[i]):
3953 end_class_head = i
3954 break
3955 if end_class_head < linenum - 1:
3956 error(
3957 filename, linenum, 'whitespace/blank_line', 3,
3958 '"%s:" should be preceded by a blank line' %
3959 matched.group(1))
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00003960
3961
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003962def GetPreviousNonBlankLine(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003963 """Return the most recent non-blank line and its line number.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003964
3965 Args:
3966 clean_lines: A CleansedLines instance containing the file contents.
3967 linenum: The number of the line to check.
3968
3969 Returns:
3970 A tuple with two elements. The first element is the contents of the last
3971 non-blank line before the current line, or the empty string if this is the
3972 first non-blank line. The second is the line number of that line, or -1
3973 if this is the first non-blank line.
3974 """
3975
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003976 prevlinenum = linenum - 1
3977 while prevlinenum >= 0:
3978 prevline = clean_lines.elided[prevlinenum]
3979 if not IsBlankLine(prevline): # if not a blank line...
3980 return (prevline, prevlinenum)
3981 prevlinenum -= 1
3982 return ('', -1)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003983
3984
3985def CheckBraces(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003986 """Looks for misplaced braces (e.g. at the end of line).
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003987
3988 Args:
3989 filename: The name of the current file.
3990 clean_lines: A CleansedLines instance containing the file.
3991 linenum: The number of the line to check.
3992 error: The function to call with any errors found.
3993 """
3994
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003995 line = clean_lines.elided[linenum] # get rid of comments and strings
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00003996
Mike Frysinger124bb8e2023-09-06 05:48:55 +00003997 if Match(r'\s*{\s*$', line):
3998 # We allow an open brace to start a line in the case where someone is
3999 # using braces in a block to explicitly create a new scope, which is
4000 # commonly used to control the lifetime of stack-allocated variables.
4001 # Braces are also used for brace initializers inside function calls. We
4002 # don't detect this perfectly: we just don't complain if the last
4003 # non-whitespace character on the previous non-blank line is ',', ';',
4004 # ':', '(', '{', or '}', or if the previous line starts a preprocessor
4005 # block. We also allow a brace on the following line if it is part of an
4006 # array initialization and would not fit within the 80 character limit
4007 # of the preceding line.
4008 prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
4009 if (not Search(r'[,;:}{(]\s*$', prevline)
4010 and not Match(r'\s*#', prevline) and
4011 not (len(prevline) > _line_length - 2 and '[]' in prevline)):
4012 error(filename, linenum, 'whitespace/braces', 4,
4013 '{ should almost always be at the end of the previous line')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004014
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004015 # An else clause should be on the same line as the preceding closing brace.
4016 if Match(r'\s*else\b\s*(?:if\b|\{|$)', line):
4017 prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
4018 if Match(r'\s*}\s*$', prevline):
4019 error(filename, linenum, 'whitespace/newline', 4,
4020 'An else should appear on the same line as the preceding }')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004021
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004022 # If braces come on one side of an else, they should be on both.
4023 # However, we have to worry about "else if" that spans multiple lines!
4024 if Search(r'else if\s*(?:constexpr\s*)?\(', line): # could be multi-line if
4025 brace_on_left = bool(Search(r'}\s*else if\s*(?:constexpr\s*)?\(', line))
4026 # find the ( after the if
4027 pos = line.find('else if')
4028 pos = line.find('(', pos)
4029 if pos > 0:
4030 (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
4031 brace_on_right = endline[endpos:].find('{') != -1
4032 if brace_on_left != brace_on_right: # must be brace after if
4033 error(
4034 filename, linenum, 'readability/braces', 5,
4035 'If an else has a brace on one side, it should have it on both'
4036 )
4037 elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004038 error(filename, linenum, 'readability/braces', 5,
4039 'If an else has a brace on one side, it should have it on both')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004040
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004041 # Likewise, an else should never have the else clause on the same line
4042 if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
4043 error(filename, linenum, 'whitespace/newline', 4,
4044 'Else clause should never be on same line as else (use 2 lines)')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004045
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004046 # In the same way, a do/while should never be on one line
4047 if Match(r'\s*do [^\s{]', line):
4048 error(filename, linenum, 'whitespace/newline', 4,
4049 'do/while clauses should not be on a single line')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004050
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004051 # Check single-line if/else bodies. The style guide says 'curly braces are
4052 # not required for single-line statements'. We additionally allow
4053 # multi-line, single statements, but we reject anything with more than one
4054 # semicolon in it. This means that the first semicolon after the if should
4055 # be at the end of its line, and the line after that should have an indent
4056 # level equal to or lower than the if. We also check for ambiguous if/else
4057 # nesting without braces.
4058 if_else_match = Search(r'\b(if\s*(?:constexpr\s*)?\(|else\b)', line)
4059 if if_else_match and not Match(r'\s*#', line):
4060 if_indent = GetIndentLevel(line)
4061 endline, endlinenum, endpos = line, linenum, if_else_match.end()
4062 if_match = Search(r'\bif\s*(?:constexpr\s*)?\(', line)
4063 if if_match:
4064 # This could be a multiline if condition, so find the end first.
4065 pos = if_match.end() - 1
4066 (endline, endlinenum,
4067 endpos) = CloseExpression(clean_lines, linenum, pos)
4068 # Check for an opening brace, either directly after the if or on the
4069 # next line. If found, this isn't a single-statement conditional.
4070 if (not Match(r'\s*{', endline[endpos:])
4071 and not (Match(r'\s*$', endline[endpos:]) and endlinenum <
4072 (len(clean_lines.elided) - 1) and Match(
4073 r'\s*{', clean_lines.elided[endlinenum + 1]))):
4074 while (endlinenum < len(clean_lines.elided)
4075 and ';' not in clean_lines.elided[endlinenum][endpos:]):
4076 endlinenum += 1
4077 endpos = 0
4078 if endlinenum < len(clean_lines.elided):
4079 endline = clean_lines.elided[endlinenum]
4080 # We allow a mix of whitespace and closing braces (e.g. for
4081 # one-liner methods) and a single \ after the semicolon (for
4082 # macros)
4083 endpos = endline.find(';')
4084 if not Match(r';[\s}]*(\\?)$', endline[endpos:]):
4085 # Semicolon isn't the last character, there's something
4086 # trailing. Output a warning if the semicolon is not
4087 # contained inside a lambda expression.
4088 if not Match(
4089 r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$',
4090 endline):
4091 error(
4092 filename, linenum, 'readability/braces', 4,
4093 'If/else bodies with multiple statements require braces'
4094 )
4095 elif endlinenum < len(clean_lines.elided) - 1:
4096 # Make sure the next line is dedented
4097 next_line = clean_lines.elided[endlinenum + 1]
4098 next_indent = GetIndentLevel(next_line)
4099 # With ambiguous nested if statements, this will error out
4100 # on the if that *doesn't* match the else, regardless of
4101 # whether it's the inner one or outer one.
4102 if (if_match and Match(r'\s*else\b', next_line)
4103 and next_indent != if_indent):
4104 error(
4105 filename, linenum, 'readability/braces', 4,
4106 'Else clause should be indented at the same level as if. '
4107 'Ambiguous nested if/else chains require braces.')
4108 elif next_indent > if_indent:
4109 error(
4110 filename, linenum, 'readability/braces', 4,
4111 'If/else bodies with multiple statements require braces'
4112 )
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004113
4114
4115def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004116 """Looks for redundant trailing semicolon.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004117
4118 Args:
4119 filename: The name of the current file.
4120 clean_lines: A CleansedLines instance containing the file.
4121 linenum: The number of the line to check.
4122 error: The function to call with any errors found.
4123 """
4124
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004125 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004126
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004127 # Block bodies should not be followed by a semicolon. Due to C++11
4128 # brace initialization and C++20 concepts, there are more places
4129 # where semicolons are required than not. Places that are
4130 # recognized as true positives are listed below.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004131 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004132 # 1. Some flavor of block following closing parenthesis:
4133 # for (;;) {};
4134 # while (...) {};
4135 # switch (...) {};
4136 # Function(...) {};
4137 # if (...) {};
4138 # if (...) else if (...) {};
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004139 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004140 # 2. else block:
4141 # if (...) else {};
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004142 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004143 # 3. const member function:
4144 # Function(...) const {};
4145 #
4146 # 4. Block following some statement:
4147 # x = 42;
4148 # {};
4149 #
4150 # 5. Block at the beginning of a function:
4151 # Function(...) {
4152 # {};
4153 # }
4154 #
4155 # Note that naively checking for the preceding "{" will also match
4156 # braces inside multi-dimensional arrays, but this is fine since
4157 # that expression will not contain semicolons.
4158 #
4159 # 6. Block following another block:
4160 # while (true) {}
4161 # {};
4162 #
4163 # 7. End of namespaces:
4164 # namespace {};
4165 #
4166 # These semicolons seems far more common than other kinds of
4167 # redundant semicolons, possibly due to people converting classes
4168 # to namespaces. For now we do not warn for this case.
4169 #
4170 # Try matching case 1 first.
4171 match = Match(r'^(.*\)\s*)\{', line)
4172 if match:
4173 # Matched closing parenthesis (case 1). Check the token before the
4174 # matching opening parenthesis, and don't warn if it looks like a
4175 # macro. This avoids these false positives:
4176 # - macro that defines a base class
4177 # - multi-line macro that defines a base class
4178 # - macro that defines the whole class-head
4179 #
4180 # But we still issue warnings for macros that we know are safe to
4181 # warn, specifically:
4182 # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P
4183 # - TYPED_TEST
4184 # - INTERFACE_DEF
4185 # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
4186 #
4187 # We implement an allowlist of safe macros instead of a blocklist of
4188 # unsafe macros, even though the latter appears less frequently in
4189 # google code and would have been easier to implement. This is because
4190 # the downside for getting the allowlist wrong means some extra
4191 # semicolons, while the downside for getting the blocklist wrong
4192 # would result in compile errors.
4193 #
4194 # In addition to macros, we also don't want to warn on
4195 # - Compound literals
4196 # - Lambdas
4197 # - alignas specifier with anonymous structs
4198 # - decltype
4199 # - Type casts with parentheses, e.g.: var = (Type){value};
4200 # - Return type casts with parentheses, e.g.: return (Type){value};
4201 # - Function pointers with initializer list, e.g.: int (*f)(){};
4202 # - Requires expression, e.g. C = requires(){};
4203 closing_brace_pos = match.group(1).rfind(')')
4204 opening_parenthesis = ReverseCloseExpression(clean_lines, linenum,
4205 closing_brace_pos)
4206 if opening_parenthesis[2] > -1:
4207 line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
4208 macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix)
4209 func = Match(r'^(.*\])\s*$', line_prefix)
4210 if ((macro and macro.group(1)
4211 not in ('TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
4212 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',
4213 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
4214 (func and not Search(r'\boperator\s*\[\s*\]', func.group(1)))
4215 or Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix)
4216 or Search(r'\b(decltype|requires)$', line_prefix)
4217 or Search(r'(?:\s+=|\breturn)\s*$', line_prefix) or
4218 (Match(r'^\s*$', line_prefix) and Search(
4219 r'(?:\s+=|\breturn)\s*$', clean_lines.elided[linenum - 1]))
4220 or Search(r'\(\*\w+\)$', line_prefix)):
4221 match = None
4222 if (match and opening_parenthesis[1] > 1 and Search(
4223 r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):
4224 # Multi-line lambda-expression
4225 match = None
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004226
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004227 else:
4228 # Try matching cases 2-3.
4229 match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)
4230 if not match:
4231 # Try matching cases 4-6. These are always matched on separate
4232 # lines.
4233 #
4234 # Note that we can't simply concatenate the previous line to the
4235 # current line and do a single match, otherwise we may output
4236 # duplicate warnings for the blank line case:
4237 # if (cond) {
4238 # // blank line
4239 # }
4240 prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
4241 if prevline and Search(r'[;{}]\s*$', prevline):
4242 match = Match(r'^(\s*)\{', line)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004243
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004244 # Check matching closing brace
4245 if match:
4246 (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum,
4247 len(match.group(1)))
4248 if endpos > -1 and Match(r'^\s*;', endline[endpos:]):
4249 # Current {} pair is eligible for semicolon check, and we have found
4250 # the redundant semicolon, output warning here.
4251 #
4252 # Note: because we are scanning forward for opening braces, and
4253 # outputting warnings for the matching closing brace, if there are
4254 # nested blocks with trailing semicolons, we will get the error
4255 # messages in reversed order.
4256 error(filename, endlinenum, 'readability/braces', 4,
4257 "You don't need a ; after a }")
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004258
4259
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004260def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004261 """Look for empty loop/conditional body with only a single semicolon.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004262
4263 Args:
4264 filename: The name of the current file.
4265 clean_lines: A CleansedLines instance containing the file.
4266 linenum: The number of the line to check.
4267 error: The function to call with any errors found.
4268 """
4269
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004270 # Search for loop keywords at the beginning of the line. Because only
4271 # whitespaces are allowed before the keywords, this will also ignore most
4272 # do-while-loops, since those lines should start with closing brace.
4273 #
4274 # We also check "if" blocks here, since an empty conditional block
4275 # is likely an error.
4276 line = clean_lines.elided[linenum]
4277 matched = Match(r'\s*(for|while|if)\s*\(', line)
4278 if matched:
4279 # Find the end of the conditional expression.
4280 (end_line, end_linenum,
4281 end_pos) = CloseExpression(clean_lines, linenum, line.find('('))
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004282
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004283 # Output warning if what follows the condition expression is a
4284 # semicolon. No warning for all other cases, including whitespace or
4285 # newline, since we have a separate check for semicolons preceded by
4286 # whitespace.
4287 if end_pos >= 0 and Match(r';', end_line[end_pos:]):
4288 if matched.group(1) == 'if':
4289 error(filename, end_linenum,
4290 'whitespace/empty_conditional_body', 5,
4291 'Empty conditional bodies should use {}')
4292 else:
4293 error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
4294 'Empty loop bodies should use {} or continue')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004295
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004296 # Check for if statements that have completely empty bodies (no
4297 # comments) and no else clauses.
4298 if end_pos >= 0 and matched.group(1) == 'if':
4299 # Find the position of the opening { for the if statement.
4300 # Return without logging an error if it has no brackets.
4301 opening_linenum = end_linenum
4302 opening_line_fragment = end_line[end_pos:]
4303 # Loop until EOF or find anything that's not whitespace or opening
4304 # {.
4305 while not Search(r'^\s*\{', opening_line_fragment):
4306 if Search(r'^(?!\s*$)', opening_line_fragment):
4307 # Conditional has no brackets.
4308 return
4309 opening_linenum += 1
4310 if opening_linenum == len(clean_lines.elided):
4311 # Couldn't find conditional's opening { or any code before
4312 # EOF.
4313 return
4314 opening_line_fragment = clean_lines.elided[opening_linenum]
4315 # Set opening_line (opening_line_fragment may not be entire opening
4316 # line).
4317 opening_line = clean_lines.elided[opening_linenum]
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004318
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004319 # Find the position of the closing }.
4320 opening_pos = opening_line_fragment.find('{')
4321 if opening_linenum == end_linenum:
4322 # We need to make opening_pos relative to the start of the
4323 # entire line.
4324 opening_pos += end_pos
4325 (closing_line, closing_linenum,
4326 closing_pos) = CloseExpression(clean_lines, opening_linenum,
4327 opening_pos)
4328 if closing_pos < 0:
4329 return
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004330
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004331 # Now construct the body of the conditional. This consists of the
4332 # portion of the opening line after the {, all lines until the
4333 # closing line, and the portion of the closing line before the }.
4334 if (clean_lines.raw_lines[opening_linenum] != CleanseComments(
4335 clean_lines.raw_lines[opening_linenum])):
4336 # Opening line ends with a comment, so conditional isn't empty.
4337 return
4338 if closing_linenum > opening_linenum:
4339 # Opening line after the {. Ignore comments here since we
4340 # checked above.
4341 body = list(opening_line[opening_pos + 1:])
4342 # All lines until closing line, excluding closing line, with
4343 # comments.
4344 body.extend(clean_lines.raw_lines[opening_linenum +
4345 1:closing_linenum])
4346 # Closing line before the }. Won't (and can't) have comments.
4347 body.append(clean_lines.elided[closing_linenum][:closing_pos -
4348 1])
4349 body = '\n'.join(body)
4350 else:
4351 # If statement has brackets and fits on a single line.
4352 body = opening_line[opening_pos + 1:closing_pos - 1]
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004353
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004354 # Check if the body is empty
4355 if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body):
4356 return
4357 # The body is empty. Now make sure there's not an else clause.
4358 current_linenum = closing_linenum
4359 current_line_fragment = closing_line[closing_pos:]
4360 # Loop until EOF or find anything that's not whitespace or else
4361 # clause.
4362 while Search(r'^\s*$|^(?=\s*else)', current_line_fragment):
4363 if Search(r'^(?=\s*else)', current_line_fragment):
4364 # Found an else clause, so don't log an error.
4365 return
4366 current_linenum += 1
4367 if current_linenum == len(clean_lines.elided):
4368 break
4369 current_line_fragment = clean_lines.elided[current_linenum]
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004370
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004371 # The body is empty and there's no else clause until EOF or other
4372 # code.
4373 error(filename, end_linenum, 'whitespace/empty_if_body', 4,
4374 ('If statement had no body and no else clause'))
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004375
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004376
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004377def FindCheckMacro(line):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004378 """Find a replaceable CHECK-like macro.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004379
4380 Args:
4381 line: line to search on.
4382 Returns:
4383 (macro name, start position), or (None, -1) if no replaceable
4384 macro is found.
4385 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004386 for macro in _CHECK_MACROS:
4387 i = line.find(macro)
4388 if i >= 0:
4389 # Find opening parenthesis. Do a regular expression match here
4390 # to make sure that we are matching the expected CHECK macro, as
4391 # opposed to some other macro that happens to contain the CHECK
4392 # substring.
4393 matched = Match(r'^(.*\b' + macro + r'\s*)\(', line)
4394 if not matched:
4395 continue
4396 return (macro, len(matched.group(1)))
4397 return (None, -1)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004398
4399
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004400def CheckCheck(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004401 """Checks the use of CHECK and EXPECT macros.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004402
4403 Args:
4404 filename: The name of the current file.
4405 clean_lines: A CleansedLines instance containing the file.
4406 linenum: The number of the line to check.
4407 error: The function to call with any errors found.
4408 """
4409
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004410 # Decide the set of replacement macros that should be suggested
4411 lines = clean_lines.elided
4412 (check_macro, start_pos) = FindCheckMacro(lines[linenum])
4413 if not check_macro:
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004414 return
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004415
4416 # Find end of the boolean expression by matching parentheses
4417 (last_line, end_line, end_pos) = CloseExpression(clean_lines, linenum,
4418 start_pos)
4419 if end_pos < 0:
4420 return
4421
4422 # If the check macro is followed by something other than a
4423 # semicolon, assume users will log their own custom error messages
4424 # and don't suggest any replacements.
4425 if not Match(r'\s*;', last_line[end_pos:]):
4426 return
4427
4428 if linenum == end_line:
4429 expression = lines[linenum][start_pos + 1:end_pos - 1]
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004430 else:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004431 expression = lines[linenum][start_pos + 1:]
4432 for i in range(linenum + 1, end_line):
4433 expression += lines[i]
4434 expression += last_line[0:end_pos - 1]
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004435
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004436 # Parse expression so that we can take parentheses into account.
4437 # This avoids false positives for inputs like "CHECK((a < 4) == b)",
4438 # which is not replaceable by CHECK_LE.
4439 lhs = ''
4440 rhs = ''
4441 operator = None
4442 while expression:
4443 matched = Match(
4444 r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||'
4445 r'==|!=|>=|>|<=|<|\()(.*)$', expression)
4446 if matched:
4447 token = matched.group(1)
4448 if token == '(':
4449 # Parenthesized operand
4450 expression = matched.group(2)
4451 (end, _) = FindEndOfExpressionInLine(expression, 0, ['('])
4452 if end < 0:
4453 return # Unmatched parenthesis
4454 lhs += '(' + expression[0:end]
4455 expression = expression[end:]
4456 elif token in ('&&', '||'):
4457 # Logical and/or operators. This means the expression
4458 # contains more than one term, for example:
4459 # CHECK(42 < a && a < b);
4460 #
4461 # These are not replaceable with CHECK_LE, so bail out early.
4462 return
4463 elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'):
4464 # Non-relational operator
4465 lhs += token
4466 expression = matched.group(2)
4467 else:
4468 # Relational operator
4469 operator = token
4470 rhs = matched.group(2)
4471 break
4472 else:
4473 # Unparenthesized operand. Instead of appending to lhs one
4474 # character at a time, we do another regular expression match to
4475 # consume several characters at once if possible. Trivial benchmark
4476 # shows that this is more efficient when the operands are longer
4477 # than a single character, which is generally the case.
4478 matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression)
4479 if not matched:
4480 matched = Match(r'^(\s*\S)(.*)$', expression)
4481 if not matched:
4482 break
4483 lhs += matched.group(1)
4484 expression = matched.group(2)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004485
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004486 # Only apply checks if we got all parts of the boolean expression
4487 if not (lhs and operator and rhs):
4488 return
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004489
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004490 # Check that rhs do not contain logical operators. We already know
4491 # that lhs is fine since the loop above parses out && and ||.
4492 if rhs.find('&&') > -1 or rhs.find('||') > -1:
4493 return
4494
4495 # At least one of the operands must be a constant literal. This is
4496 # to avoid suggesting replacements for unprintable things like
4497 # CHECK(variable != iterator)
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004498 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004499 # The following pattern matches decimal, hex integers, strings, and
4500 # characters (in that order).
4501 lhs = lhs.strip()
4502 rhs = rhs.strip()
4503 match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$'
4504 if Match(match_constant, lhs) or Match(match_constant, rhs):
4505 # Note: since we know both lhs and rhs, we can provide a more
4506 # descriptive error message like:
4507 # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42)
4508 # Instead of:
4509 # Consider using CHECK_EQ instead of CHECK(a == b)
4510 #
4511 # We are still keeping the less descriptive message because if lhs
4512 # or rhs gets long, the error message might become unreadable.
4513 error(
4514 filename, linenum, 'readability/check', 2,
4515 'Consider using %s instead of %s(a %s b)' %
4516 (_CHECK_REPLACEMENT[check_macro][operator], check_macro, operator))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004517
4518
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004519def CheckAltTokens(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004520 """Check alternative keywords being used in boolean expressions.
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004521
4522 Args:
4523 filename: The name of the current file.
4524 clean_lines: A CleansedLines instance containing the file.
4525 linenum: The number of the line to check.
4526 error: The function to call with any errors found.
4527 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004528 line = clean_lines.elided[linenum]
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004529
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004530 # Avoid preprocessor lines
4531 if Match(r'^\s*#', line):
4532 return
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004533
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004534 # Last ditch effort to avoid multi-line comments. This will not help
4535 # if the comment started before the current line or ended after the
4536 # current line, but it catches most of the false positives. At least,
4537 # it provides a way to workaround this warning for people who use
4538 # multi-line comments in preprocessor macros.
4539 #
4540 # TODO(unknown): remove this once cpplint has better support for
4541 # multi-line comments.
4542 if line.find('/*') >= 0 or line.find('*/') >= 0:
4543 return
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004544
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004545 for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
4546 error(
4547 filename, linenum, 'readability/alt_tokens', 2,
4548 'Use operator %s instead of %s' %
4549 (_ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004550
4551
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004552def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004553 error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004554 """Checks rules from the 'C++ style rules' section of cppguide.html.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004555
4556 Most of these rules are hard to test (naming, comment style), but we
4557 do what we can. In particular we check for 2-space indents, line lengths,
4558 tab usage, spaces inside code, etc.
4559
4560 Args:
4561 filename: The name of the current file.
4562 clean_lines: A CleansedLines instance containing the file.
4563 linenum: The number of the line to check.
4564 file_extension: The extension (without the dot) of the filename.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004565 nesting_state: A NestingState instance which maintains information about
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00004566 the current stack of nested blocks being parsed.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004567 error: The function to call with any errors found.
4568 """
4569
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004570 # Don't use "elided" lines here, otherwise we can't check commented lines.
4571 # Don't want to use "raw" either, because we don't want to check inside
4572 # C++11 raw strings,
4573 raw_lines = clean_lines.lines_without_raw_strings
4574 line = raw_lines[linenum]
4575 prev = raw_lines[linenum - 1] if linenum > 0 else ''
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004576
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004577 if line.find('\t') != -1:
4578 error(filename, linenum, 'whitespace/tab', 1,
4579 'Tab found; better to use spaces')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004580
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004581 # One or three blank spaces at the beginning of the line is weird; it's
4582 # hard to reconcile that with 2-space indents.
4583 # NOTE: here are the conditions rob pike used for his tests. Mine aren't
4584 # as sophisticated, but it may be worth becoming so:
4585 # RLENGTH==initial_spaces if(RLENGTH > 20) complain = 0; if(match($0, "
4586 # +(error|private|public|protected):")) complain = 0; if(match(prev, "&&
4587 # *$")) complain = 0; if(match(prev, "\\|\\| *$")) complain = 0;
4588 # if(match(prev, "[\",=><] *$")) complain = 0; if(match($0, " <<")) complain
4589 # = 0; if(match(prev, " +for \\(")) complain = 0; if(prevodd &&
4590 # match(prevprev, " +for \\(")) complain = 0;
4591 scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$'
4592 classinfo = nesting_state.InnermostClass()
4593 initial_spaces = 0
4594 cleansed_line = clean_lines.elided[linenum]
4595 while initial_spaces < len(line) and line[initial_spaces] == ' ':
4596 initial_spaces += 1
4597 # There are certain situations we allow one space, notably for
4598 # section labels, and also lines containing multi-line raw strings.
4599 # We also don't check for lines that look like continuation lines
4600 # (of lines ending in double quotes, commas, equals, or angle brackets)
4601 # because the rules for how to indent those are non-trivial.
4602 if (not Search(r'[",=><] *$', prev)
4603 and (initial_spaces == 1 or initial_spaces == 3)
4604 and not Match(scope_or_label_pattern, cleansed_line)
4605 and not (clean_lines.raw_lines[linenum] != line
4606 and Match(r'^\s*""', line))):
4607 error(
4608 filename, linenum, 'whitespace/indent', 3,
4609 'Weird number of spaces at line-start. '
4610 'Are you using a 2-space indent?')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004611
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004612 if line and line[-1].isspace():
4613 error(
4614 filename, linenum, 'whitespace/end_of_line', 4,
4615 'Line ends in whitespace. Consider deleting these extra spaces.')
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004616
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004617 # Check if the line is a header guard.
4618 is_header_guard = False
4619 if file_extension == 'h':
4620 cppvar = GetHeaderGuardCPPVariable(filename)
4621 if (line.startswith('#ifndef %s' % cppvar)
4622 or line.startswith('#define %s' % cppvar)
4623 or line.startswith('#endif // %s' % cppvar)):
4624 is_header_guard = True
4625 # #include lines and header guards can be long, since there's no clean way
4626 # to split them.
4627 #
4628 # URLs can be long too. It's possible to split these, but it makes them
4629 # harder to cut&paste.
4630 #
4631 # The "$Id:...$" comment may also get very long without it being the
4632 # developers fault.
4633 if (not line.startswith('#include') and not is_header_guard
4634 and not Match(r'^\s*//.*http(s?)://\S*$', line)
4635 and not Match(r'^\s*//\s*[^\s]*$', line)
4636 and not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
4637 if len(line) > _line_length:
4638 error(filename, linenum, 'whitespace/line_length', 2,
4639 'Lines should be <= %i characters long' % _line_length)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004640
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004641 if (cleansed_line.count(';') > 1 and
4642 # for loops are allowed two ;'s (and may run over two lines).
4643 cleansed_line.find('for') == -1 and
4644 (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1
4645 or GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1)
4646 and
4647 # It's ok to have many commands in a switch case that fits in 1 line
4648 not ((cleansed_line.find('case ') != -1
4649 or cleansed_line.find('default:') != -1)
4650 and cleansed_line.find('break;') != -1)):
4651 error(filename, linenum, 'whitespace/newline', 0,
4652 'More than one command on the same line')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004653
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004654 # Some more style checks
4655 CheckBraces(filename, clean_lines, linenum, error)
4656 CheckTrailingSemicolon(filename, clean_lines, linenum, error)
4657 CheckEmptyBlockBody(filename, clean_lines, linenum, error)
4658 CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
4659 CheckOperatorSpacing(filename, clean_lines, linenum, error)
4660 CheckParenthesisSpacing(filename, clean_lines, linenum, error)
4661 CheckCommaSpacing(filename, clean_lines, linenum, error)
4662 CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error)
4663 CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
4664 CheckCheck(filename, clean_lines, linenum, error)
4665 CheckAltTokens(filename, clean_lines, linenum, error)
4666 classinfo = nesting_state.InnermostClass()
4667 if classinfo:
4668 CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004669
4670
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004671_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
4672# Matches the first component of a filename delimited by -s and _s. That is:
4673# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
4674# _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
4675# _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
4676# _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
4677_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
4678
4679
4680def _DropCommonSuffixes(filename):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004681 """Drops common suffixes like _test.cc or -inl.h from filename.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004682
4683 For example:
4684 >>> _DropCommonSuffixes('foo/foo-inl.h')
4685 'foo/foo'
4686 >>> _DropCommonSuffixes('foo/bar/foo.cc')
4687 'foo/bar/foo'
4688 >>> _DropCommonSuffixes('foo/foo_internal.h')
4689 'foo/foo'
4690 >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
4691 'foo/foo_unusualinternal'
4692
4693 Args:
4694 filename: The input filename.
4695
4696 Returns:
4697 The filename with the common suffix removed.
4698 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004699 for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', 'inl.h', 'impl.h',
4700 'internal.h'):
4701 if (filename.endswith(suffix) and len(filename) > len(suffix)
4702 and filename[-len(suffix) - 1] in ('-', '_')):
4703 return filename[:-len(suffix) - 1]
4704 return os.path.splitext(filename)[0]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004705
4706
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004707def _ClassifyInclude(fileinfo, include, is_system):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004708 """Figures out what kind of header 'include' is.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004709
4710 Args:
4711 fileinfo: The current file cpplint is running over. A FileInfo instance.
4712 include: The path to a #included file.
4713 is_system: True if the #include used <> rather than "".
4714
4715 Returns:
4716 One of the _XXX_HEADER constants.
4717
4718 For example:
4719 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
4720 _C_SYS_HEADER
4721 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
4722 _CPP_SYS_HEADER
4723 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
4724 _LIKELY_MY_HEADER
4725 >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
4726 ... 'bar/foo_other_ext.h', False)
4727 _POSSIBLE_MY_HEADER
4728 >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
4729 _OTHER_HEADER
4730 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004731 # This is a list of all standard c++ header files, except
4732 # those already checked for above.
4733 is_cpp_h = include in _CPP_HEADERS
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004734
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004735 if is_system:
4736 if is_cpp_h:
4737 return _CPP_SYS_HEADER
4738 else:
4739 return _C_SYS_HEADER
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004740
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004741 # If the target file and the include we're checking share a
4742 # basename when we drop common extensions, and the include
4743 # lives in . , then it's likely to be owned by the target file.
4744 target_dir, target_base = (os.path.split(
4745 _DropCommonSuffixes(fileinfo.RepositoryName())))
4746 include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
4747 if target_base == include_base and (
4748 include_dir == target_dir
4749 or include_dir == os.path.normpath(target_dir + '/../public')):
4750 return _LIKELY_MY_HEADER
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004751
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004752 # If the target and include share some initial basename
4753 # component, it's possible the target is implementing the
4754 # include, so it's allowed to be first, but we'll never
4755 # complain if it's not there.
4756 target_first_component = _RE_FIRST_COMPONENT.match(target_base)
4757 include_first_component = _RE_FIRST_COMPONENT.match(include_base)
4758 if (target_first_component and include_first_component
4759 and target_first_component.group(0)
4760 == include_first_component.group(0)):
4761 return _POSSIBLE_MY_HEADER
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004762
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004763 return _OTHER_HEADER
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004764
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004765
erg@google.com6317a9c2009-06-25 00:28:19 +00004766def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004767 """Check rules that are applicable to #include lines.
erg@google.com6317a9c2009-06-25 00:28:19 +00004768
4769 Strings on #include lines are NOT removed from elided line, to make
4770 certain tasks easier. However, to prevent false positives, checks
4771 applicable to #include lines in CheckLanguage must be put here.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004772
4773 Args:
4774 filename: The name of the current file.
4775 clean_lines: A CleansedLines instance containing the file.
4776 linenum: The number of the line to check.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004777 include_state: An _IncludeState instance in which the headers are inserted.
4778 error: The function to call with any errors found.
4779 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004780 fileinfo = FileInfo(filename)
4781 line = clean_lines.lines[linenum]
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004782
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004783 # "include" should use the new style "foo/bar.h" instead of just "bar.h"
4784 # Only do this check if the included header follows google naming
4785 # conventions. If not, assume that it's a 3rd party API that
4786 # requires special include conventions.
4787 #
4788 # We also make an exception for Lua headers, which follow google
4789 # naming convention but not the include convention.
4790 match = Match(r'#include\s*"([^/]+\.h)"', line)
4791 if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)):
4792 error(filename, linenum, 'build/include_directory', 4,
4793 'Include the directory when naming .h files')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004794
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004795 # we shouldn't include a file more than once. actually, there are a
4796 # handful of instances where doing so is okay, but in general it's
4797 # not.
4798 match = _RE_PATTERN_INCLUDE.search(line)
4799 if match:
4800 include = match.group(2)
4801 is_system = (match.group(1) == '<')
4802 duplicate_line = include_state.FindHeader(include)
4803 if duplicate_line >= 0:
4804 error(
4805 filename, linenum, 'build/include', 4,
4806 '"%s" already included at %s:%s' %
4807 (include, filename, duplicate_line))
4808 elif (include.endswith('.cc') and os.path.dirname(
4809 fileinfo.RepositoryName()) != os.path.dirname(include)):
4810 error(filename, linenum, 'build/include', 4,
4811 'Do not include .cc files from other packages')
4812 elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
4813 include_state.include_list[-1].append((include, linenum))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004814
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004815 # We want to ensure that headers appear in the right order:
4816 # 1) for foo.cc, foo.h (preferred location)
4817 # 2) c system files
4818 # 3) cpp system files
4819 # 4) for foo.cc, foo.h (deprecated location)
4820 # 5) other google headers
4821 #
4822 # We classify each include statement as one of those 5 types
4823 # using a number of techniques. The include_state object keeps
4824 # track of the highest type seen, and complains if we see a
4825 # lower type after that.
4826 error_message = include_state.CheckNextIncludeOrder(
4827 _ClassifyInclude(fileinfo, include, is_system))
4828 if error_message:
4829 error(
4830 filename, linenum, 'build/include_order', 4,
4831 '%s. Should be: %s.h, c system, c++ system, other.' %
4832 (error_message, fileinfo.BaseName()))
4833 canonical_include = include_state.CanonicalizeAlphabeticalOrder(
4834 include)
4835 if not include_state.IsInAlphabeticalOrder(clean_lines, linenum,
4836 canonical_include):
4837 error(filename, linenum, 'build/include_alpha', 4,
4838 'Include "%s" not in alphabetical order' % include)
4839 include_state.SetLastHeader(canonical_include)
erg@google.com6317a9c2009-06-25 00:28:19 +00004840
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004841
4842def _GetTextInside(text, start_pattern):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004843 r"""Retrieves all the text between matching open and close parentheses.
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004844
4845 Given a string of lines and a regular expression string, retrieve all the text
4846 following the expression and between opening punctuation symbols like
4847 (, [, or {, and the matching close-punctuation symbol. This properly nested
4848 occurrences of the punctuations, so for the text like
4849 printf(a(), b(c()));
4850 a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
4851 start_pattern must match string having an open punctuation symbol at the end.
4852
4853 Args:
4854 text: The lines to extract text. Its comments and strings must be elided.
4855 It can be single line and can span multiple lines.
4856 start_pattern: The regexp string indicating where to start extracting
4857 the text.
4858 Returns:
4859 The extracted text.
4860 None if either the opening string or ending punctuation could not be found.
4861 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004862 # TODO(unknown): Audit cpplint.py to see what places could be profitably
4863 # rewritten to use _GetTextInside (and use inferior regexp matching today).
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004864
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004865 # Give opening punctuations to get the matching close-punctuations.
4866 matching_punctuation = {'(': ')', '{': '}', '[': ']'}
4867 closing_punctuation = set(matching_punctuation.values())
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004868
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004869 # Find the position to start extracting text.
4870 match = re.search(start_pattern, text, re.M)
4871 if not match: # start_pattern not found in text.
4872 return None
4873 start_position = match.end(0)
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004874
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004875 assert start_position > 0, (
4876 'start_pattern must ends with an opening punctuation.')
4877 assert text[start_position - 1] in matching_punctuation, (
4878 'start_pattern must ends with an opening punctuation.')
4879 # Stack of closing punctuations we expect to have in text after position.
4880 punctuation_stack = [matching_punctuation[text[start_position - 1]]]
4881 position = start_position
4882 while punctuation_stack and position < len(text):
4883 if text[position] == punctuation_stack[-1]:
4884 punctuation_stack.pop()
4885 elif text[position] in closing_punctuation:
4886 # A closing punctuation without matching opening punctuations.
4887 return None
4888 elif text[position] in matching_punctuation:
4889 punctuation_stack.append(matching_punctuation[text[position]])
4890 position += 1
4891 if punctuation_stack:
4892 # Opening punctuations left without matching close-punctuations.
4893 return None
4894 # punctuations match.
4895 return text[start_position:position - 1]
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00004896
4897
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004898# Patterns for matching call-by-reference parameters.
4899#
4900# Supports nested templates up to 2 levels deep using this messy pattern:
4901# < (?: < (?: < [^<>]*
4902# >
4903# | [^<>] )*
4904# >
4905# | [^<>] )*
4906# >
4907_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]*
4908_RE_PATTERN_TYPE = (
4909 r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?'
4910 r'(?:\w|'
4911 r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|'
4912 r'::)+')
4913# A call-by-reference parameter ends with '& identifier'.
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004914_RE_PATTERN_REF_PARAM = re.compile(r'(' + _RE_PATTERN_TYPE +
4915 r'(?:\s*(?:\bconst\b|[*]))*\s*'
4916 r'&\s*' + _RE_PATTERN_IDENT +
4917 r')\s*(?:=[^,()]+)?[,)]')
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004918# A call-by-const-reference parameter either ends with 'const& identifier'
4919# or looks like 'const type& identifier' when 'type' is atomic.
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004920_RE_PATTERN_CONST_REF_PARAM = (r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +
4921 r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' +
4922 _RE_PATTERN_IDENT + r')')
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00004923# Stream types.
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004924_RE_PATTERN_REF_STREAM_PARAM = (r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT +
4925 r')')
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004926
4927
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004928def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state,
4929 nesting_state, error):
4930 """Checks rules from the 'C++ language rules' section of cppguide.html.
erg@google.com6317a9c2009-06-25 00:28:19 +00004931
4932 Some of these rules are hard to test (function overloading, using
4933 uint32 inappropriately), but we do the best we can.
4934
4935 Args:
4936 filename: The name of the current file.
4937 clean_lines: A CleansedLines instance containing the file.
4938 linenum: The number of the line to check.
4939 file_extension: The extension (without the dot) of the filename.
4940 include_state: An _IncludeState instance in which the headers are inserted.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00004941 nesting_state: A NestingState instance which maintains information about
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00004942 the current stack of nested blocks being parsed.
erg@google.com6317a9c2009-06-25 00:28:19 +00004943 error: The function to call with any errors found.
4944 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004945 # If the line is empty or consists of entirely a comment, no need to
4946 # check it.
4947 line = clean_lines.elided[linenum]
4948 if not line:
4949 return
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004950
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004951 match = _RE_PATTERN_INCLUDE.search(line)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004952 if match:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004953 CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
4954 return
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004955
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004956 # Reset include state across preprocessor directives. This is meant
4957 # to silence warnings for conditional includes.
4958 match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line)
4959 if match:
4960 include_state.ResetSection(match.group(1))
erg@google.com26970fa2009-11-17 18:07:32 +00004961
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004962 # Make Windows paths like Unix.
4963 fullname = os.path.abspath(filename).replace('\\', '/')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004964
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004965 # Perform other checks now that we are sure that this is not an include line
4966 CheckCasts(filename, clean_lines, linenum, error)
4967 CheckGlobalStatic(filename, clean_lines, linenum, error)
4968 CheckPrintf(filename, clean_lines, linenum, error)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004969
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004970 if file_extension == 'h':
4971 # TODO(unknown): check that 1-arg constructors are explicit.
4972 # How to tell it's a constructor?
4973 # (handled in CheckForNonStandardConstructs for now)
4974 # TODO(unknown): check that classes declare or disable copy/assign
4975 # (level 1 error)
4976 pass
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004977
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004978 # Check if people are using the verboten C basic types. The only exception
4979 # we regularly allow is "unsigned short port" for port.
4980 if Search(r'\bshort port\b', line):
4981 if not Search(r'\bunsigned short port\b', line):
4982 error(filename, linenum, 'runtime/int', 4,
4983 'Use "unsigned short" for ports, not "short"')
4984 else:
4985 match = Search(r'\b(short|long(?! +double)|long long)\b', line)
4986 if match:
4987 error(
4988 filename, linenum, 'runtime/int', 4,
4989 'Use int16/int64/etc, rather than the C type %s' %
4990 match.group(1))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00004991
Mike Frysinger124bb8e2023-09-06 05:48:55 +00004992 # Check if some verboten operator overloading is going on
4993 # TODO(unknown): catch out-of-line unary operator&:
4994 # class X {};
4995 # int operator&(const X& x) { return 42; } // unary operator&
4996 # The trick is it's hard to tell apart from binary operator&:
4997 # class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
4998 if Search(r'\boperator\s*&\s*\(\s*\)', line):
4999 error(filename, linenum, 'runtime/operator', 4,
5000 'Unary operator& is dangerous. Do not use it.')
5001
5002 # Check for suspicious usage of "if" like
5003 # } if (a == b) {
5004 if Search(r'\}\s*if\s*(?:constexpr\s*)?\(', line):
5005 error(filename, linenum, 'readability/braces', 4,
5006 'Did you mean "else if"? If not, start a new line for "if".')
5007
5008 # Check for potential format string bugs like printf(foo).
5009 # We constrain the pattern not to pick things like DocidForPrintf(foo).
5010 # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
5011 # TODO(unknown): Catch the following case. Need to change the calling
5012 # convention of the whole function to process multiple line to handle it.
5013 # printf(
5014 # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
5015 printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
5016 if printf_args:
5017 match = Match(r'([\w.\->()]+)$', printf_args)
5018 if match and match.group(1) != '__VA_ARGS__':
5019 function_name = re.search(r'\b((?:string)?printf)\s*\(', line,
5020 re.I).group(1)
5021 error(
5022 filename, linenum, 'runtime/printf', 4,
5023 'Potential format string bug. Do %s("%%s", %s) instead.' %
5024 (function_name, match.group(1)))
5025
5026 # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
5027 match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
5028 if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
5029 error(
5030 filename, linenum, 'runtime/memset', 4,
5031 'Did you mean "memset(%s, 0, %s)"?' %
5032 (match.group(1), match.group(2)))
5033
5034 if Search(r'\busing namespace\b', line):
5035 error(
5036 filename, linenum, 'build/namespaces', 5,
5037 'Do not use namespace using-directives. '
5038 'Use using-declarations instead.')
5039
5040 # Detect variable-length arrays.
5041 match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
5042 if (match and match.group(2) != 'return' and match.group(2) != 'delete'
5043 and match.group(3).find(']') == -1):
5044 # Split the size using space and arithmetic operators as delimiters.
5045 # If any of the resulting tokens are not compile time constants then
5046 # report the error.
5047 tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
5048 is_const = True
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005049 skip_next = False
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005050 for tok in tokens:
5051 if skip_next:
5052 skip_next = False
5053 continue
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005054
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005055 if Search(r'sizeof\(.+\)', tok): continue
5056 if Search(r'arraysize\(\w+\)', tok): continue
5057 if Search(r'base::size\(.+\)', tok): continue
5058 if Search(r'std::size\(.+\)', tok): continue
5059 if Search(r'std::extent<.+>', tok): continue
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005060
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005061 tok = tok.lstrip('(')
5062 tok = tok.rstrip(')')
5063 if not tok: continue
5064 if Match(r'\d+', tok): continue
5065 if Match(r'0[xX][0-9a-fA-F]+', tok): continue
5066 if Match(r'k[A-Z0-9]\w*', tok): continue
5067 if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
5068 if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
5069 # A catch all for tricky sizeof cases, including 'sizeof
5070 # expression', 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct
5071 # StructName)' requires skipping the next token because we split on
5072 # ' ' and '*'.
5073 if tok.startswith('sizeof'):
5074 skip_next = True
5075 continue
5076 is_const = False
5077 break
5078 if not is_const:
5079 error(
5080 filename, linenum, 'runtime/arrays', 1,
5081 'Do not use variable-length arrays. Use an appropriately named '
5082 "('k' followed by CamelCase) compile-time constant for the size."
5083 )
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005084
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005085 # Check for use of unnamed namespaces in header files. Registration
5086 # macros are typically OK, so we allow use of "namespace {" on lines
5087 # that end with backslashes.
5088 if (file_extension == 'h' and Search(r'\bnamespace\s*{', line)
5089 and line[-1] != '\\'):
5090 error(
5091 filename, linenum, 'build/namespaces', 4,
5092 'Do not use unnamed namespaces in header files. See '
5093 'https://google.github.io/styleguide/cppguide.html#Namespaces'
5094 ' for more information.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005095
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005096
5097def CheckGlobalStatic(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005098 """Check for unsafe global or static objects.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005099
5100 Args:
5101 filename: The name of the current file.
5102 clean_lines: A CleansedLines instance containing the file.
5103 linenum: The number of the line to check.
5104 error: The function to call with any errors found.
5105 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005106 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005107
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005108 # Match two lines at a time to support multiline declarations
5109 if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line):
5110 line += clean_lines.elided[linenum + 1].strip()
avakulenko@google.com59146752014-08-11 20:20:55 +00005111
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005112 # Check for people declaring static/global STL strings at the top level.
5113 # This is dangerous because the C++ language does not guarantee that
5114 # globals with constructors are initialized before the first access, and
5115 # also because globals can be destroyed when some threads are still running.
5116 # TODO(unknown): Generalize this to also find static unique_ptr instances.
5117 # TODO(unknown): File bugs for clang-tidy to find these.
5118 match = Match(
5119 r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +'
5120 r'([a-zA-Z0-9_:]+)\b(.*)', line)
avakulenko@google.com59146752014-08-11 20:20:55 +00005121
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005122 # Remove false positives:
5123 # - String pointers (as opposed to values).
5124 # string *pointer
5125 # const string *pointer
5126 # string const *pointer
5127 # string *const pointer
5128 #
5129 # - Functions and template specializations.
5130 # string Function<Type>(...
5131 # string Class<Type>::Method(...
5132 #
5133 # - Operators. These are matched separately because operator names
5134 # cross non-word boundaries, and trying to match both operators
5135 # and functions at the same time would decrease accuracy of
5136 # matching identifiers.
5137 # string Class::operator*()
5138 if (match and
5139 not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line)
5140 and not Search(r'\boperator\W', line) and not Match(
5141 r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))):
5142 if Search(r'\bconst\b', line):
5143 error(
5144 filename, linenum, 'runtime/string', 4,
5145 'For a static/global string constant, use a C style string '
5146 'instead: "%schar%s %s[]".' %
5147 (match.group(1), match.group(2) or '', match.group(3)))
5148 else:
5149 error(filename, linenum, 'runtime/string', 4,
5150 'Static/global string variables are not permitted.')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005151
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005152 if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line)
5153 or Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)):
5154 error(filename, linenum, 'runtime/init', 4,
5155 'You seem to be initializing a member variable with itself.')
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005156
5157
5158def CheckPrintf(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005159 """Check for printf related issues.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005160
5161 Args:
5162 filename: The name of the current file.
5163 clean_lines: A CleansedLines instance containing the file.
5164 linenum: The number of the line to check.
5165 error: The function to call with any errors found.
5166 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005167 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005168
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005169 # When snprintf is used, the second argument shouldn't be a literal.
5170 match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
5171 if match and match.group(2) != '0':
5172 # If 2nd arg is zero, snprintf is used to calculate size.
5173 error(
5174 filename, linenum, 'runtime/printf', 3,
5175 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
5176 'to snprintf.' % (match.group(1), match.group(2)))
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005177
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005178 # Check if some verboten C functions are being used.
5179 if Search(r'\bsprintf\s*\(', line):
5180 error(filename, linenum, 'runtime/printf', 5,
5181 'Never use sprintf. Use snprintf instead.')
5182 match = Search(r'\b(strcpy|strcat)\s*\(', line)
5183 if match:
5184 error(filename, linenum, 'runtime/printf', 4,
5185 'Almost always, snprintf is better than %s' % match.group(1))
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005186
5187
5188def IsDerivedFunction(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005189 """Check if current line contains an inherited function.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005190
5191 Args:
5192 clean_lines: A CleansedLines instance containing the file.
5193 linenum: The number of the line to check.
5194 Returns:
5195 True if current line contains a function with "override"
5196 virt-specifier.
5197 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005198 # Scan back a few lines for start of current function
5199 for i in range(linenum, max(-1, linenum - 10), -1):
5200 match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])
5201 if match:
5202 # Look for "override" after the matching closing parenthesis
5203 line, _, closing_paren = CloseExpression(clean_lines, i,
5204 len(match.group(1)))
5205 return (closing_paren >= 0
5206 and Search(r'\boverride\b', line[closing_paren:]))
5207 return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005208
5209
avakulenko@google.com255f2be2014-12-05 22:19:55 +00005210def IsOutOfLineMethodDefinition(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005211 """Check if current line contains an out-of-line method definition.
avakulenko@google.com255f2be2014-12-05 22:19:55 +00005212
5213 Args:
5214 clean_lines: A CleansedLines instance containing the file.
5215 linenum: The number of the line to check.
5216 Returns:
5217 True if current line contains an out-of-line method definition.
5218 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005219 # Scan back a few lines for start of current function
5220 for i in range(linenum, max(-1, linenum - 10), -1):
5221 if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):
5222 return Match(r'^[^()]*\w+::\w+\(',
5223 clean_lines.elided[i]) is not None
5224 return False
avakulenko@google.com255f2be2014-12-05 22:19:55 +00005225
5226
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005227def IsInitializerList(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005228 """Check if current line is inside constructor initializer list.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005229
5230 Args:
5231 clean_lines: A CleansedLines instance containing the file.
5232 linenum: The number of the line to check.
5233 Returns:
5234 True if current line appears to be inside constructor initializer
5235 list, False otherwise.
5236 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005237 for i in range(linenum, 1, -1):
5238 line = clean_lines.elided[i]
5239 if i == linenum:
5240 remove_function_body = Match(r'^(.*)\{\s*$', line)
5241 if remove_function_body:
5242 line = remove_function_body.group(1)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005243
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005244 if Search(r'\s:\s*\w+[({]', line):
5245 # A lone colon tend to indicate the start of a constructor
5246 # initializer list. It could also be a ternary operator, which
5247 # also tend to appear in constructor initializer lists as
5248 # opposed to parameter lists.
5249 return True
5250 if Search(r'\}\s*,\s*$', line):
5251 # A closing brace followed by a comma is probably the end of a
5252 # brace-initialized member in constructor initializer list.
5253 return True
5254 if Search(r'[{};]\s*$', line):
5255 # Found one of the following:
5256 # - A closing brace or semicolon, probably the end of the previous
5257 # function.
5258 # - An opening brace, probably the start of current class or
5259 # namespace.
5260 #
5261 # Current line is probably not inside an initializer list since
5262 # we saw one of those things without seeing the starting colon.
5263 return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005264
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005265 # Got to the beginning of the file without seeing the start of
5266 # constructor initializer list.
5267 return False
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005268
5269
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005270def CheckForNonConstReference(filename, clean_lines, linenum, nesting_state,
5271 error):
5272 """Check for non-const references.
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00005273
5274 Separate from CheckLanguage since it scans backwards from current
5275 line, instead of scanning forward.
5276
5277 Args:
5278 filename: The name of the current file.
5279 clean_lines: A CleansedLines instance containing the file.
5280 linenum: The number of the line to check.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005281 nesting_state: A NestingState instance which maintains information about
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00005282 the current stack of nested blocks being parsed.
5283 error: The function to call with any errors found.
5284 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005285 # Do nothing if there is no '&' on current line.
5286 line = clean_lines.elided[linenum]
5287 if '&' not in line:
avakulenko@google.com59146752014-08-11 20:20:55 +00005288 return
5289
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005290 # If a function is inherited, current function doesn't have much of
5291 # a choice, so any non-const references should not be blamed on
5292 # derived function.
5293 if IsDerivedFunction(clean_lines, linenum):
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005294 return
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00005295
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005296 # Don't warn on out-of-line method definitions, as we would warn on the
5297 # in-line declaration, if it isn't marked with 'override'.
5298 if IsOutOfLineMethodDefinition(clean_lines, linenum):
5299 return
5300
5301 # Long type names may be broken across multiple lines, usually in one
5302 # of these forms:
5303 # LongType
5304 # ::LongTypeContinued &identifier
5305 # LongType::
5306 # LongTypeContinued &identifier
5307 # LongType<
5308 # ...>::LongTypeContinued &identifier
5309 #
5310 # If we detected a type split across two lines, join the previous
5311 # line to current line so that we can match const references
5312 # accordingly.
5313 #
5314 # Note that this only scans back one line, since scanning back
5315 # arbitrary number of lines would be expensive. If you have a type
5316 # that spans more than 2 lines, please use a typedef.
5317 if linenum > 1:
5318 previous = None
5319 if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line):
5320 # previous_line\n + ::current_line
5321 previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$',
5322 clean_lines.elided[linenum - 1])
5323 elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line):
5324 # previous_line::\n + current_line
5325 previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$',
5326 clean_lines.elided[linenum - 1])
5327 if previous:
5328 line = previous.group(1) + line.lstrip()
5329 else:
5330 # Check for templated parameter that is split across multiple lines
5331 endpos = line.rfind('>')
5332 if endpos > -1:
5333 (_, startline,
5334 startpos) = ReverseCloseExpression(clean_lines, linenum,
5335 endpos)
5336 if startpos > -1 and startline < linenum:
5337 # Found the matching < on an earlier line, collect all
5338 # pieces up to current line.
5339 line = ''
5340 for i in range(startline, linenum + 1):
5341 line += clean_lines.elided[i].strip()
5342
5343 # Check for non-const references in function parameters. A single '&' may
5344 # found in the following places:
5345 # inside expression: binary & for bitwise AND
5346 # inside expression: unary & for taking the address of something
5347 # inside declarators: reference parameter
5348 # We will exclude the first two cases by checking that we are not inside a
5349 # function body, including one that was just introduced by a trailing '{'.
5350 # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].
5351 if (nesting_state.previous_stack_top and
5352 not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or
5353 isinstance(nesting_state.previous_stack_top, _NamespaceInfo))):
5354 # Not at toplevel, not within a class, and not within a namespace
5355 return
5356
5357 # Avoid initializer lists. We only need to scan back from the
5358 # current line for something that starts with ':'.
5359 #
5360 # We don't need to check the current line, since the '&' would
5361 # appear inside the second set of parentheses on the current line as
5362 # opposed to the first set.
5363 if linenum > 0:
5364 for i in range(linenum - 1, max(0, linenum - 10), -1):
5365 previous_line = clean_lines.elided[i]
5366 if not Search(r'[),]\s*$', previous_line):
5367 break
5368 if Match(r'^\s*:\s+\S', previous_line):
5369 return
5370
5371 # Avoid preprocessors
5372 if Search(r'\\\s*$', line):
5373 return
5374
5375 # Avoid constructor initializer lists
5376 if IsInitializerList(clean_lines, linenum):
5377 return
5378
5379 # We allow non-const references in a few standard places, like functions
5380 # called "swap()" or iostream operators like "<<" or ">>". Do not check
5381 # those function parameters.
5382 #
5383 # We also accept & in static_assert, which looks like a function but
5384 # it's actually a declaration expression.
5385 allowlisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
5386 r'operator\s*[<>][<>]|'
5387 r'static_assert|COMPILE_ASSERT'
5388 r')\s*\(')
5389 if Search(allowlisted_functions, line):
5390 return
5391 elif not Search(r'\S+\([^)]*$', line):
5392 # Don't see an allowlisted function on this line. Actually we
5393 # didn't see any function name on this line, so this is likely a
5394 # multi-line parameter list. Try a bit harder to catch this case.
5395 for i in range(2):
5396 if (linenum > i and Search(allowlisted_functions,
5397 clean_lines.elided[linenum - i - 1])):
5398 return
5399
5400 decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body
5401 for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
5402 if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter)
5403 and not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)):
5404 error(
5405 filename, linenum, 'runtime/references', 2,
5406 'Is this a non-const reference? '
5407 'If so, make const or use a pointer: ' +
5408 ReplaceAll(' *<', '<', parameter))
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005409
5410
5411def CheckCasts(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005412 """Various cast related checks.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005413
5414 Args:
5415 filename: The name of the current file.
5416 clean_lines: A CleansedLines instance containing the file.
5417 linenum: The number of the line to check.
5418 error: The function to call with any errors found.
5419 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005420 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005421
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005422 # Check to see if they're using an conversion function cast.
5423 # I just try to capture the most common basic types, though there are more.
5424 # Parameterless conversion functions, such as bool(), are allowed as they
5425 # are probably a member operator declaration or default constructor.
5426 match = Search(
5427 r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b'
5428 r'(int|float|double|bool|char|int32|uint32|int64|uint64)'
5429 r'(\([^)].*)', line)
5430 expecting_function = ExpectingFunctionArgs(clean_lines, linenum)
5431 if match and not expecting_function:
5432 matched_type = match.group(2)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005433
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005434 # matched_new_or_template is used to silence two false positives:
5435 # - New operators
5436 # - Template arguments with function types
5437 #
5438 # For template arguments, we match on types immediately following
5439 # an opening bracket without any spaces. This is a fast way to
5440 # silence the common case where the function type is the first
5441 # template argument. False negative with less-than comparison is
5442 # avoided because those operators are usually followed by a space.
5443 #
5444 # function<double(double)> // bracket + no space = false positive
5445 # value < double(42) // bracket + space = true positive
5446 matched_new_or_template = match.group(1)
5447
5448 # Avoid arrays by looking for brackets that come after the closing
5449 # parenthesis.
5450 if Match(r'\([^()]+\)\s*\[', match.group(3)):
5451 return
5452
5453 # Other things to ignore:
5454 # - Function pointers
5455 # - Casts to pointer types
5456 # - Placement new
5457 # - Alias declarations
5458 matched_funcptr = match.group(3)
5459 if (matched_new_or_template is None and not (
5460 matched_funcptr and
5461 (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', matched_funcptr)
5462 or matched_funcptr.startswith('(*)')))
5463 and not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line)
5464 and not Search(r'new\(\S+\)\s*' + matched_type, line)):
5465 error(
5466 filename, linenum, 'readability/casting', 4,
5467 'Using deprecated casting style. '
5468 'Use static_cast<%s>(...) instead' % matched_type)
5469
5470 if not expecting_function:
5471 CheckCStyleCast(filename, clean_lines, linenum, 'static_cast',
5472 r'\((int|float|double|bool|char|u?int(16|32|64))\)',
5473 error)
5474
5475 # This doesn't catch all cases. Consider (const char * const)"hello".
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005476 #
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005477 # (char *) "foo" should always be a const_cast (reinterpret_cast won't
5478 # compile).
5479 if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast',
5480 r'\((char\s?\*+\s?)\)\s*"', error):
5481 pass
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005482 else:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005483 # Check pointer casts for other than string constants
5484 CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast',
5485 r'\((\w+\s?\*+\s?)\)', error)
5486
5487 # In addition, we look for people taking the address of a cast. This
5488 # is dangerous -- casts can assign to temporaries, so the pointer doesn't
5489 # point where you think.
5490 #
5491 # Some non-identifier character is required before the '&' for the
5492 # expression to be recognized as a cast. These are casts:
5493 # expression = &static_cast<int*>(temporary());
5494 # function(&(int*)(temporary()));
5495 #
5496 # This is not a cast:
5497 # reference_type&(int* function_param);
5498 match = Search(
5499 r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'
5500 r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line)
5501 if match:
5502 # Try a better error message when the & is bound to something
5503 # dereferenced by the casted pointer, as opposed to the casted
5504 # pointer itself.
5505 parenthesis_error = False
5506 match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<',
5507 line)
5508 if match:
5509 _, y1, x1 = CloseExpression(clean_lines, linenum,
5510 len(match.group(1)))
5511 if x1 >= 0 and clean_lines.elided[y1][x1] == '(':
5512 _, y2, x2 = CloseExpression(clean_lines, y1, x1)
5513 if x2 >= 0:
5514 extended_line = clean_lines.elided[y2][x2:]
5515 if y2 < clean_lines.NumLines() - 1:
5516 extended_line += clean_lines.elided[y2 + 1]
5517 if Match(r'\s*(?:->|\[)', extended_line):
5518 parenthesis_error = True
5519
5520 if parenthesis_error:
5521 error(filename, linenum, 'readability/casting', 4,
5522 ('Are you taking an address of something dereferenced '
5523 'from a cast? Wrapping the dereferenced expression in '
5524 'parentheses will make the binding more obvious'))
5525 else:
5526 error(filename, linenum, 'runtime/casting', 4,
5527 ('Are you taking an address of a cast? '
5528 'This is dangerous: could be a temp var. '
5529 'Take the address before doing the cast, rather than after'))
raphael.kubo.da.costa@intel.com331fbc42014-05-09 08:48:20 +00005530
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005531
avakulenko@google.com59146752014-08-11 20:20:55 +00005532def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005533 """Checks for a C-style cast by looking for the pattern.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005534
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005535 Args:
5536 filename: The name of the current file.
avakulenko@google.com59146752014-08-11 20:20:55 +00005537 clean_lines: A CleansedLines instance containing the file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005538 linenum: The number of the line to check.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005539 cast_type: The string for the C++ cast to recommend. This is either
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00005540 reinterpret_cast, static_cast, or const_cast, depending.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005541 pattern: The regular expression used to find C-style casts.
5542 error: The function to call with any errors found.
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00005543
5544 Returns:
5545 True if an error was emitted.
5546 False otherwise.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005547 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005548 line = clean_lines.elided[linenum]
5549 match = Search(pattern, line)
5550 if not match:
5551 return False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005552
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005553 # Exclude lines with keywords that tend to look like casts
5554 context = line[0:match.start(1) - 1]
5555 if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context):
5556 return False
avakulenko@google.com59146752014-08-11 20:20:55 +00005557
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005558 # Try expanding current context to see if we one level of
5559 # parentheses inside a macro.
5560 if linenum > 0:
5561 for i in range(linenum - 1, max(0, linenum - 5), -1):
5562 context = clean_lines.elided[i] + context
5563 if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context):
5564 return False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005565
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005566 # operator++(int) and operator--(int)
5567 if context.endswith(' operator++') or context.endswith(' operator--'):
5568 return False
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00005569
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005570 # A single unnamed argument for a function tends to look like old style
5571 # cast. If we see those, don't issue warnings for deprecated casts.
5572 remainder = line[match.end(0):]
5573 if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)',
5574 remainder):
5575 return False
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005576
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005577 # At this point, all that should be left is actual casts.
5578 error(
5579 filename, linenum, 'readability/casting', 4,
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005580 'Using C-style cast. Use %s<%s>(...) instead' %
5581 (cast_type, match.group(1)))
5582
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005583 return True
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00005584
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005585
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005586def ExpectingFunctionArgs(clean_lines, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005587 """Checks whether where function type arguments are expected.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005588
5589 Args:
5590 clean_lines: A CleansedLines instance containing the file.
5591 linenum: The number of the line to check.
5592
5593 Returns:
5594 True if the line at 'linenum' is inside something that expects arguments
5595 of function types.
5596 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005597 line = clean_lines.elided[linenum]
5598 return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line)
5599 or _TYPE_TRAITS_RE.search(line)
5600 or (linenum >= 2 and
5601 (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$',
5602 clean_lines.elided[linenum - 1])
5603 or Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$',
5604 clean_lines.elided[linenum - 2])
5605 or Search(r'\b(::function|base::FunctionRef)\s*\<\s*$',
5606 clean_lines.elided[linenum - 1]))))
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005607
5608
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005609_HEADERS_CONTAINING_TEMPLATES = (
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005610 ('<deque>', ('deque', )),
5611 ('<functional>', (
5612 'unary_function',
5613 'binary_function',
5614 'plus',
5615 'minus',
5616 'multiplies',
5617 'divides',
5618 'modulus',
5619 'negate',
5620 'equal_to',
5621 'not_equal_to',
5622 'greater',
5623 'less',
5624 'greater_equal',
5625 'less_equal',
5626 'logical_and',
5627 'logical_or',
5628 'logical_not',
5629 'unary_negate',
5630 'not1',
5631 'binary_negate',
5632 'not2',
5633 'bind1st',
5634 'bind2nd',
5635 'pointer_to_unary_function',
5636 'pointer_to_binary_function',
5637 'ptr_fun',
5638 'mem_fun_t',
5639 'mem_fun',
5640 'mem_fun1_t',
5641 'mem_fun1_ref_t',
5642 'mem_fun_ref_t',
5643 'const_mem_fun_t',
5644 'const_mem_fun1_t',
5645 'const_mem_fun_ref_t',
5646 'const_mem_fun1_ref_t',
5647 'mem_fun_ref',
5648 )),
5649 ('<limits>', ('numeric_limits', )),
5650 ('<list>', ('list', )),
5651 ('<map>', (
5652 'map',
5653 'multimap',
5654 )),
lhchavez2d1b6da2016-07-13 10:40:01 -07005655 ('<memory>', ('allocator', 'make_shared', 'make_unique', 'shared_ptr',
5656 'unique_ptr', 'weak_ptr')),
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005657 ('<queue>', (
5658 'queue',
5659 'priority_queue',
5660 )),
5661 ('<set>', (
5662 'set',
5663 'multiset',
5664 )),
5665 ('<stack>', ('stack', )),
5666 ('<string>', (
5667 'char_traits',
5668 'basic_string',
5669 )),
5670 ('<tuple>', ('tuple', )),
lhchavez2d1b6da2016-07-13 10:40:01 -07005671 ('<unordered_map>', ('unordered_map', 'unordered_multimap')),
5672 ('<unordered_set>', ('unordered_set', 'unordered_multiset')),
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005673 ('<utility>', ('pair', )),
5674 ('<vector>', ('vector', )),
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005675
5676 # gcc extensions.
5677 # Note: std::hash is their hash, ::hash is our hash
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005678 ('<hash_map>', (
5679 'hash_map',
5680 'hash_multimap',
5681 )),
5682 ('<hash_set>', (
5683 'hash_set',
5684 'hash_multiset',
5685 )),
5686 ('<slist>', ('slist', )),
5687)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005688
skym@chromium.org3990c412016-02-05 20:55:12 +00005689_HEADERS_MAYBE_TEMPLATES = (
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005690 ('<algorithm>', (
5691 'copy',
5692 'max',
5693 'min',
5694 'min_element',
5695 'sort',
5696 'transform',
5697 )),
lhchavez2d1b6da2016-07-13 10:40:01 -07005698 ('<utility>', ('forward', 'make_pair', 'move', 'swap')),
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005699)
skym@chromium.org3990c412016-02-05 20:55:12 +00005700
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005701_RE_PATTERN_STRING = re.compile(r'\bstring\b')
5702
skym@chromium.org3990c412016-02-05 20:55:12 +00005703_re_pattern_headers_maybe_templates = []
5704for _header, _templates in _HEADERS_MAYBE_TEMPLATES:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005705 for _template in _templates:
5706 # Match max<type>(..., ...), max(..., ...), but not foo->max or foo.max.
5707 _re_pattern_headers_maybe_templates.append(
5708 (re.compile(r'(?<![>.])\b' + _template + r'(<.*?>)?\([^\)]'),
5709 _template, _header))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005710
skym@chromium.org3990c412016-02-05 20:55:12 +00005711# Other scripts may reach in and modify this pattern.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005712_re_pattern_templates = []
5713for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005714 for _template in _templates:
5715 _re_pattern_templates.append(
5716 (re.compile(r'(\<|\b)' + _template + r'\s*\<'), _template + '<>',
5717 _header))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005718
5719
erg@google.com6317a9c2009-06-25 00:28:19 +00005720def FilesBelongToSameModule(filename_cc, filename_h):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005721 """Check if these two filenames belong to the same module.
erg@google.com6317a9c2009-06-25 00:28:19 +00005722
5723 The concept of a 'module' here is a as follows:
5724 foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
5725 same 'module' if they are in the same directory.
5726 some/path/public/xyzzy and some/path/internal/xyzzy are also considered
5727 to belong to the same module here.
5728
5729 If the filename_cc contains a longer path than the filename_h, for example,
5730 '/absolute/path/to/base/sysinfo.cc', and this file would include
5731 'base/sysinfo.h', this function also produces the prefix needed to open the
5732 header. This is used by the caller of this function to more robustly open the
5733 header file. We don't have access to the real include paths in this context,
5734 so we need this guesswork here.
5735
5736 Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
5737 according to this implementation. Because of this, this function gives
5738 some false positives. This should be sufficiently rare in practice.
5739
5740 Args:
5741 filename_cc: is the path for the .cc file
5742 filename_h: is the path for the header path
5743
5744 Returns:
5745 Tuple with a bool and a string:
5746 bool: True if filename_cc and filename_h belong to the same module.
5747 string: the additional prefix needed to open the header file.
5748 """
5749
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005750 fileinfo = FileInfo(filename_cc)
5751 if not fileinfo.IsSource():
5752 return (False, '')
5753 filename_cc = filename_cc[:-len(fileinfo.Extension())]
5754 matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo.BaseName())
5755 if matched_test_suffix:
5756 filename_cc = filename_cc[:-len(matched_test_suffix.group(1))]
5757 filename_cc = filename_cc.replace('/public/', '/')
5758 filename_cc = filename_cc.replace('/internal/', '/')
erg@google.com6317a9c2009-06-25 00:28:19 +00005759
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005760 if not filename_h.endswith('.h'):
5761 return (False, '')
5762 filename_h = filename_h[:-len('.h')]
5763 if filename_h.endswith('-inl'):
5764 filename_h = filename_h[:-len('-inl')]
5765 filename_h = filename_h.replace('/public/', '/')
5766 filename_h = filename_h.replace('/internal/', '/')
erg@google.com6317a9c2009-06-25 00:28:19 +00005767
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005768 files_belong_to_same_module = filename_cc.endswith(filename_h)
5769 common_path = ''
5770 if files_belong_to_same_module:
5771 common_path = filename_cc[:-len(filename_h)]
5772 return files_belong_to_same_module, common_path
erg@google.com6317a9c2009-06-25 00:28:19 +00005773
5774
avakulenko@google.com59146752014-08-11 20:20:55 +00005775def UpdateIncludeState(filename, include_dict, io=codecs):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005776 """Fill up the include_dict with new includes found from the file.
erg@google.com6317a9c2009-06-25 00:28:19 +00005777
5778 Args:
5779 filename: the name of the header to read.
avakulenko@google.com59146752014-08-11 20:20:55 +00005780 include_dict: a dictionary in which the headers are inserted.
erg@google.com6317a9c2009-06-25 00:28:19 +00005781 io: The io factory to use to read the file. Provided for testability.
5782
5783 Returns:
avakulenko@google.com59146752014-08-11 20:20:55 +00005784 True if a header was successfully added. False otherwise.
erg@google.com6317a9c2009-06-25 00:28:19 +00005785 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005786 headerfile = None
5787 try:
5788 headerfile = io.open(filename, 'r', 'utf8', 'replace')
5789 except IOError:
5790 return False
5791 linenum = 0
5792 for line in headerfile:
5793 linenum += 1
5794 clean_line = CleanseComments(line)
5795 match = _RE_PATTERN_INCLUDE.search(clean_line)
5796 if match:
5797 include = match.group(2)
5798 include_dict.setdefault(include, linenum)
5799 return True
erg@google.com6317a9c2009-06-25 00:28:19 +00005800
5801
Peter Kasting03b187d2022-11-04 18:33:43 +00005802def UpdateRequiredHeadersForLine(patterns, line, linenum, required):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005803 for pattern, template, header in patterns:
5804 matched = pattern.search(line)
5805 if matched:
5806 # Don't warn about IWYU in non-STL namespaces:
5807 # (We check only the first match per line; good enough.)
5808 prefix = line[:matched.start()]
5809 if prefix.endswith('std::') or not prefix.endswith('::'):
5810 required[header] = (linenum, template)
5811 return required
Peter Kasting03b187d2022-11-04 18:33:43 +00005812
5813
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005814def CheckForIncludeWhatYouUse(filename,
5815 clean_lines,
5816 include_state,
5817 error,
erg@google.com6317a9c2009-06-25 00:28:19 +00005818 io=codecs):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005819 """Reports for missing stl includes.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005820
5821 This function will output warnings to make sure you are including the headers
5822 necessary for the stl containers and functions that you use. We only give one
5823 reason to include a header. For example, if you use both equal_to<> and
5824 less<> in a .h file, only one (the latter in the file) of these will be
5825 reported as a reason to include the <functional>.
5826
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005827 Args:
5828 filename: The name of the current file.
5829 clean_lines: A CleansedLines instance containing the file.
5830 include_state: An _IncludeState instance.
5831 error: The function to call with any errors found.
erg@google.com6317a9c2009-06-25 00:28:19 +00005832 io: The IO factory to use to read the header file. Provided for unittest
5833 injection.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005834 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005835 # A map of header name to linenumber and the template entity.
5836 # Example of required: { '<functional>': (1219, 'less<>') }
5837 required = {}
5838 for linenum in range(clean_lines.NumLines()):
5839 line = clean_lines.elided[linenum]
5840 if not line or line[0] == '#':
5841 continue
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005842
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005843 # String is special -- it is a non-templatized type in STL.
5844 matched = _RE_PATTERN_STRING.search(line)
5845 if matched:
5846 # Don't warn about strings in non-STL namespaces:
5847 # (We check only the first match per line; good enough.)
5848 prefix = line[:matched.start()]
5849 if prefix.endswith('std::') or not prefix.endswith('::'):
5850 required['<string>'] = (linenum, 'string')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005851
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005852 required = UpdateRequiredHeadersForLine(
5853 _re_pattern_headers_maybe_templates, line, linenum, required)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005854
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005855 # The following function is just a speed up, no semantics are changed.
5856 if not '<' in line: # Reduces the cpu time usage by skipping lines.
5857 continue
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005858
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005859 required = UpdateRequiredHeadersForLine(_re_pattern_templates, line,
5860 linenum, required)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005861
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005862 # The policy is that if you #include something in foo.h you don't need to
5863 # include it again in foo.cc. Here, we will look at possible includes.
5864 # Let's flatten the include_state include_list and copy it into a
5865 # dictionary.
5866 include_dict = dict(
5867 [item for sublist in include_state.include_list for item in sublist])
erg@google.com6317a9c2009-06-25 00:28:19 +00005868
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005869 # Did we find the header for this file (if any) and successfully load it?
5870 header_found = False
erg@google.com6317a9c2009-06-25 00:28:19 +00005871
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005872 # Use the absolute path so that matching works properly.
5873 abs_filename = FileInfo(filename).FullName()
erg@google.com6317a9c2009-06-25 00:28:19 +00005874
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005875 # For Emacs's flymake.
5876 # If cpplint is invoked from Emacs's flymake, a temporary file is generated
5877 # by flymake and that file name might end with '_flymake.cc'. In that case,
5878 # restore original file name here so that the corresponding header file can
5879 # be found. e.g. If the file name is 'foo_flymake.cc', we should search for
5880 # 'foo.h' instead of 'foo_flymake.h'
5881 abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
erg@google.com6317a9c2009-06-25 00:28:19 +00005882
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005883 # include_dict is modified during iteration, so we iterate over a copy of
5884 # the keys.
5885 header_keys = list(include_dict.keys())
5886 for header in header_keys:
5887 (same_module,
5888 common_path) = FilesBelongToSameModule(abs_filename, header)
5889 fullpath = common_path + header
5890 if same_module and UpdateIncludeState(fullpath, include_dict, io):
5891 header_found = True
erg@google.com6317a9c2009-06-25 00:28:19 +00005892
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005893 # If we can't find the header file for a .cc, assume it's because we don't
5894 # know where to look. In that case we'll give up as we're not sure they
5895 # didn't include it in the .h file.
5896 # TODO(unknown): Do a better job of finding .h files so we are confident
5897 # that not having the .h file means there isn't one.
5898 if filename.endswith('.cc') and not header_found:
5899 return
erg@google.com6317a9c2009-06-25 00:28:19 +00005900
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005901 # All the lines have been processed, report the errors found.
5902 for required_header_unstripped in required:
5903 template = required[required_header_unstripped][1]
5904 if required_header_unstripped.strip('<>"') not in include_dict:
5905 error(
5906 filename, required[required_header_unstripped][0],
5907 'build/include_what_you_use', 4, 'Add #include ' +
5908 required_header_unstripped + ' for ' + template)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00005909
5910
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00005911_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
5912
5913
5914def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005915 """Check that make_pair's template arguments are deduced.
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00005916
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00005917 G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00005918 specified explicitly, and such use isn't intended in any case.
5919
5920 Args:
5921 filename: The name of the current file.
5922 clean_lines: A CleansedLines instance containing the file.
5923 linenum: The number of the line to check.
5924 error: The function to call with any errors found.
5925 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005926 line = clean_lines.elided[linenum]
5927 match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
5928 if match:
5929 error(
5930 filename,
5931 linenum,
5932 'build/explicit_make_pair',
5933 4, # 4 = high confidence
5934 'For C++11-compatibility, omit template arguments from make_pair'
5935 ' OR use pair directly OR if appropriate, construct a pair directly'
5936 )
avakulenko@google.com59146752014-08-11 20:20:55 +00005937
5938
avakulenko@google.com59146752014-08-11 20:20:55 +00005939def CheckRedundantVirtual(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005940 """Check if line contains a redundant "virtual" function-specifier.
avakulenko@google.com59146752014-08-11 20:20:55 +00005941
5942 Args:
5943 filename: The name of the current file.
5944 clean_lines: A CleansedLines instance containing the file.
5945 linenum: The number of the line to check.
5946 error: The function to call with any errors found.
5947 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005948 # Look for "virtual" on current line.
5949 line = clean_lines.elided[linenum]
5950 virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line)
5951 if not virtual: return
avakulenko@google.com59146752014-08-11 20:20:55 +00005952
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005953 # Ignore "virtual" keywords that are near access-specifiers. These
5954 # are only used in class base-specifier and do not apply to member
5955 # functions.
5956 if (Search(r'\b(public|protected|private)\s+$', virtual.group(1))
5957 or Match(r'^\s+(public|protected|private)\b', virtual.group(3))):
5958 return
avakulenko@google.com255f2be2014-12-05 22:19:55 +00005959
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005960 # Ignore the "virtual" keyword from virtual base classes. Usually
5961 # there is a column on the same line in these cases (virtual base
5962 # classes are rare in google3 because multiple inheritance is rare).
5963 if Match(r'^.*[^:]:[^:].*$', line): return
avakulenko@google.com255f2be2014-12-05 22:19:55 +00005964
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005965 # Look for the next opening parenthesis. This is the start of the
5966 # parameter list (possibly on the next line shortly after virtual).
5967 # TODO(unknown): doesn't work if there are virtual functions with
5968 # decltype() or other things that use parentheses, but csearch suggests
5969 # that this is rare.
5970 end_col = -1
5971 end_line = -1
5972 start_col = len(virtual.group(2))
5973 for start_line in range(linenum, min(linenum + 3, clean_lines.NumLines())):
5974 line = clean_lines.elided[start_line][start_col:]
5975 parameter_list = Match(r'^([^(]*)\(', line)
5976 if parameter_list:
5977 # Match parentheses to find the end of the parameter list
5978 (_, end_line, end_col) = CloseExpression(
5979 clean_lines, start_line,
5980 start_col + len(parameter_list.group(1)))
5981 break
5982 start_col = 0
avakulenko@google.com59146752014-08-11 20:20:55 +00005983
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005984 if end_col < 0:
5985 return # Couldn't find end of parameter list, give up
avakulenko@google.com59146752014-08-11 20:20:55 +00005986
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005987 # Look for "override" or "final" after the parameter list
5988 # (possibly on the next few lines).
5989 for i in range(end_line, min(end_line + 3, clean_lines.NumLines())):
5990 line = clean_lines.elided[i][end_col:]
5991 match = Search(r'\b(override|final)\b', line)
5992 if match:
5993 error(filename, linenum, 'readability/inheritance', 4,
5994 ('"virtual" is redundant since function is '
5995 'already declared as "%s"' % match.group(1)))
avakulenko@google.com59146752014-08-11 20:20:55 +00005996
Mike Frysinger124bb8e2023-09-06 05:48:55 +00005997 # Set end_col to check whole lines after we are done with the
5998 # first line.
5999 end_col = 0
6000 if Search(r'[^\w]\s*$', line):
6001 break
avakulenko@google.com59146752014-08-11 20:20:55 +00006002
6003
6004def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006005 """Check if line contains a redundant "override" or "final" virt-specifier.
avakulenko@google.com59146752014-08-11 20:20:55 +00006006
6007 Args:
6008 filename: The name of the current file.
6009 clean_lines: A CleansedLines instance containing the file.
6010 linenum: The number of the line to check.
6011 error: The function to call with any errors found.
6012 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006013 # Look for closing parenthesis nearby. We need one to confirm where
6014 # the declarator ends and where the virt-specifier starts to avoid
6015 # false positives.
6016 line = clean_lines.elided[linenum]
6017 declarator_end = line.rfind(')')
6018 if declarator_end >= 0:
6019 fragment = line[declarator_end:]
avakulenko@google.com255f2be2014-12-05 22:19:55 +00006020 else:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006021 if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0:
6022 fragment = line
6023 else:
6024 return
avakulenko@google.com255f2be2014-12-05 22:19:55 +00006025
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006026 # Check that at most one of "override" or "final" is present, not both
6027 if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment):
6028 error(filename, linenum, 'readability/inheritance', 4,
6029 ('"override" is redundant since function is '
6030 'already declared as "final"'))
avakulenko@google.com59146752014-08-11 20:20:55 +00006031
6032
6033# Returns true if we are at a new block, and it is directly
6034# inside of a namespace.
6035def IsBlockInNameSpace(nesting_state, is_forward_declaration):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006036 """Checks that the new block is directly in a namespace.
avakulenko@google.com59146752014-08-11 20:20:55 +00006037
6038 Args:
6039 nesting_state: The _NestingState object that contains info about our state.
6040 is_forward_declaration: If the class is a forward declared class.
6041 Returns:
6042 Whether or not the new block is directly in a namespace.
6043 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006044 if is_forward_declaration:
6045 if len(nesting_state.stack) >= 1 and (isinstance(
6046 nesting_state.stack[-1], _NamespaceInfo)):
6047 return True
6048 else:
6049 return False
avakulenko@google.com59146752014-08-11 20:20:55 +00006050
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006051 return (len(nesting_state.stack) > 1
6052 and nesting_state.stack[-1].check_namespace_indentation
6053 and isinstance(nesting_state.stack[-2], _NamespaceInfo))
avakulenko@google.com59146752014-08-11 20:20:55 +00006054
6055
6056def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
6057 raw_lines_no_comments, linenum):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006058 """This method determines if we should apply our namespace indentation check.
avakulenko@google.com59146752014-08-11 20:20:55 +00006059
6060 Args:
6061 nesting_state: The current nesting state.
6062 is_namespace_indent_item: If we just put a new class on the stack, True.
6063 If the top of the stack is not a class, or we did not recently
6064 add the class, False.
6065 raw_lines_no_comments: The lines without the comments.
6066 linenum: The current line number we are processing.
6067
6068 Returns:
6069 True if we should apply our namespace indentation check. Currently, it
6070 only works for classes and namespaces inside of a namespace.
6071 """
6072
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006073 is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments,
6074 linenum)
avakulenko@google.com59146752014-08-11 20:20:55 +00006075
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006076 if not (is_namespace_indent_item or is_forward_declaration):
6077 return False
avakulenko@google.com59146752014-08-11 20:20:55 +00006078
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006079 # If we are in a macro, we do not want to check the namespace indentation.
6080 if IsMacroDefinition(raw_lines_no_comments, linenum):
6081 return False
avakulenko@google.com59146752014-08-11 20:20:55 +00006082
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006083 return IsBlockInNameSpace(nesting_state, is_forward_declaration)
avakulenko@google.com59146752014-08-11 20:20:55 +00006084
6085
6086# Call this method if the line is directly inside of a namespace.
6087# If the line above is blank (excluding comments) or the start of
6088# an inner namespace, it cannot be indented.
6089def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum,
6090 error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006091 line = raw_lines_no_comments[linenum]
6092 if Match(r'^\s+', line):
6093 error(filename, linenum, 'runtime/indentation_namespace', 4,
6094 'Do not indent within a namespace')
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006095
6096
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006097def ProcessLine(filename,
6098 file_extension,
6099 clean_lines,
6100 line,
6101 include_state,
6102 function_state,
6103 nesting_state,
6104 error,
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00006105 extra_check_functions=[]):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006106 """Processes a single line in the file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006107
6108 Args:
6109 filename: Filename of the file that is being processed.
6110 file_extension: The extension (dot not included) of the file.
6111 clean_lines: An array of strings, each representing a line of the file,
6112 with comments stripped.
6113 line: Number of line being processed.
6114 include_state: An _IncludeState instance in which the headers are inserted.
6115 function_state: A _FunctionState instance which counts function lines, etc.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006116 nesting_state: A NestingState instance which maintains information about
mazda@chromium.org3fffcec2013-06-07 01:04:53 +00006117 the current stack of nested blocks being parsed.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006118 error: A callable to which errors are reported, which takes 4 arguments:
6119 filename, line number, error level, and message
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006120 extra_check_functions: An array of additional check functions that will be
6121 run on each source line. Each function takes 4
6122 arguments: filename, clean_lines, line, error
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006123 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006124 raw_lines = clean_lines.raw_lines
6125 ParseNolintSuppressions(filename, raw_lines[line], line, error)
6126 nesting_state.Update(filename, clean_lines, line, error)
6127 CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
6128 error)
6129 if nesting_state.InAsmBlock(): return
6130 CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
6131 CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
6132 CheckStyle(filename, clean_lines, line, file_extension, nesting_state,
6133 error)
6134 CheckLanguage(filename, clean_lines, line, file_extension, include_state,
6135 nesting_state, error)
6136 CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
6137 CheckForNonStandardConstructs(filename, clean_lines, line, nesting_state,
6138 error)
6139 CheckVlogArguments(filename, clean_lines, line, error)
6140 CheckPosixThreading(filename, clean_lines, line, error)
6141 CheckInvalidIncrement(filename, clean_lines, line, error)
6142 CheckMakePairUsesDeduction(filename, clean_lines, line, error)
6143 CheckRedundantVirtual(filename, clean_lines, line, error)
6144 CheckRedundantOverrideOrFinal(filename, clean_lines, line, error)
6145 for check_fn in extra_check_functions:
6146 check_fn(filename, clean_lines, line, error)
6147
avakulenko@google.com17449932014-07-28 22:13:33 +00006148
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006149def FlagCxx11Features(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006150 """Flag those c++11 features that we only allow in certain places.
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006151
6152 Args:
6153 filename: The name of the current file.
6154 clean_lines: A CleansedLines instance containing the file.
6155 linenum: The number of the line to check.
6156 error: The function to call with any errors found.
6157 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006158 line = clean_lines.elided[linenum]
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006159
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006160 include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006161
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006162 # Flag unapproved C++ TR1 headers.
6163 if include and include.group(1).startswith('tr1/'):
6164 error(filename, linenum, 'build/c++tr1', 5,
6165 ('C++ TR1 headers such as <%s> are unapproved.') %
6166 include.group(1))
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006167
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006168 # Flag unapproved C++11 headers.
6169 if include and include.group(1) in (
6170 'cfenv',
6171 'condition_variable',
6172 'fenv.h',
6173 'future',
6174 'mutex',
6175 'thread',
6176 'chrono',
6177 'ratio',
6178 'regex',
6179 'system_error',
6180 ):
6181 error(filename, linenum, 'build/c++11', 5,
6182 ('<%s> is an unapproved C++11 header.') % include.group(1))
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006183
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006184 # The only place where we need to worry about C++11 keywords and library
6185 # features in preprocessor directives is in macro definitions.
6186 if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006187
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006188 # These are classes and free functions. The classes are always
6189 # mentioned as std::*, but we only catch the free functions if
6190 # they're not found by ADL. They're alphabetical by header.
6191 for top_name in (
6192 # type_traits
6193 'alignment_of',
6194 'aligned_union',
6195 ):
6196 if Search(r'\bstd::%s\b' % top_name, line):
6197 error(filename, linenum, 'build/c++11', 5, (
6198 'std::%s is an unapproved C++11 class or function. Send c-style '
6199 'an example of where it would make your code more readable, and '
6200 'they may let you use it.') % top_name)
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006201
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006202
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006203def FlagCxx14Features(filename, clean_lines, linenum, error):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006204 """Flag those C++14 features that we restrict.
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006205
6206 Args:
6207 filename: The name of the current file.
6208 clean_lines: A CleansedLines instance containing the file.
6209 linenum: The number of the line to check.
6210 error: The function to call with any errors found.
6211 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006212 line = clean_lines.elided[linenum]
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006213
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006214 include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006215
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006216 # Flag unapproved C++14 headers.
6217 if include and include.group(1) in ('scoped_allocator', 'shared_mutex'):
6218 error(filename, linenum, 'build/c++14', 5,
6219 ('<%s> is an unapproved C++14 header.') % include.group(1))
avakulenko@chromium.org764ce712016-05-06 23:03:41 +00006220
6221
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006222def ProcessFileData(filename,
6223 file_extension,
6224 lines,
6225 error,
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006226 extra_check_functions=[]):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006227 """Performs lint checks and reports any errors to the given error function.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006228
6229 Args:
6230 filename: Filename of the file that is being processed.
6231 file_extension: The extension (dot not included) of the file.
6232 lines: An array of strings, each representing a line of the file, with the
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006233 last element being empty if the file is terminated with a newline.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006234 error: A callable to which errors are reported, which takes 4 arguments:
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006235 filename, line number, error level, and message
6236 extra_check_functions: An array of additional check functions that will be
6237 run on each source line. Each function takes 4
6238 arguments: filename, clean_lines, line, error
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006239 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006240 lines = (['// marker so line numbers and indices both start at 1'] + lines +
6241 ['// marker so line numbers end in a known way'])
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006242
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006243 include_state = _IncludeState()
6244 function_state = _FunctionState()
6245 nesting_state = NestingState()
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006246
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006247 ResetNolintSuppressions()
erg@google.com35589e62010-11-17 18:58:16 +00006248
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006249 CheckForCopyright(filename, lines, error)
6250 ProcessGlobalSuppresions(lines)
6251 RemoveMultiLineComments(filename, lines, error)
6252 clean_lines = CleansedLines(lines)
avakulenko@google.com255f2be2014-12-05 22:19:55 +00006253
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006254 if file_extension == 'h':
6255 CheckForHeaderGuard(filename, clean_lines, error)
avakulenko@google.com255f2be2014-12-05 22:19:55 +00006256
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006257 for line in range(clean_lines.NumLines()):
6258 ProcessLine(filename, file_extension, clean_lines, line, include_state,
6259 function_state, nesting_state, error, extra_check_functions)
6260 FlagCxx11Features(filename, clean_lines, line, error)
6261 nesting_state.CheckCompletedBlocks(filename, error)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006262
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006263 CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
skym@chromium.org3990c412016-02-05 20:55:12 +00006264
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006265 # Check that the .cc file has included its header if it exists.
6266 if _IsSourceExtension(file_extension):
6267 CheckHeaderFileIncluded(filename, include_state, error)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006268
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006269 # We check here rather than inside ProcessLine so that we see raw
6270 # lines rather than "cleaned" lines.
6271 CheckForBadCharacters(filename, lines, error)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006272
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006273 CheckForNewlineAtEOF(filename, lines, error)
6274
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006275
avakulenko@google.com17449932014-07-28 22:13:33 +00006276def ProcessConfigOverrides(filename):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006277 """ Loads the configuration files and processes the config overrides.
avakulenko@google.com17449932014-07-28 22:13:33 +00006278
6279 Args:
6280 filename: The name of the file being processed by the linter.
6281
6282 Returns:
6283 False if the current |filename| should not be processed further.
6284 """
6285
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006286 abs_filename = os.path.abspath(filename)
6287 cfg_filters = []
6288 keep_looking = True
6289 while keep_looking:
6290 abs_path, base_name = os.path.split(abs_filename)
6291 if not base_name:
6292 break # Reached the root directory.
avakulenko@google.com17449932014-07-28 22:13:33 +00006293
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006294 cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
6295 abs_filename = abs_path
6296 if not os.path.isfile(cfg_file):
avakulenko@google.com17449932014-07-28 22:13:33 +00006297 continue
6298
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006299 try:
6300 with open(cfg_file) as file_handle:
6301 for line in file_handle:
6302 line, _, _ = line.partition('#') # Remove comments.
6303 if not line.strip():
6304 continue
6305
6306 name, _, val = line.partition('=')
6307 name = name.strip()
6308 val = val.strip()
6309 if name == 'set noparent':
6310 keep_looking = False
6311 elif name == 'filter':
6312 cfg_filters.append(val)
6313 elif name == 'exclude_files':
6314 # When matching exclude_files pattern, use the base_name
6315 # of the current file name or the directory name we are
6316 # processing. For example, if we are checking for lint
6317 # errors in /foo/bar/baz.cc and we found the .cfg file
6318 # at /foo/CPPLINT.cfg, then the config file's
6319 # "exclude_files" filter is meant to be checked against
6320 # "bar" and not "baz" nor "bar/baz.cc".
6321 if base_name:
6322 pattern = re.compile(val)
6323 if pattern.match(base_name):
6324 sys.stderr.write(
6325 'Ignoring "%s": file excluded by "%s". '
6326 'File path component "%s" matches '
6327 'pattern "%s"\n' %
6328 (filename, cfg_file, base_name, val))
6329 return False
6330 elif name == 'linelength':
6331 global _line_length
6332 try:
6333 _line_length = int(val)
6334 except ValueError:
6335 sys.stderr.write('Line length must be numeric.')
6336 else:
6337 sys.stderr.write(
6338 'Invalid configuration option (%s) in file %s\n' %
6339 (name, cfg_file))
6340
6341 except IOError:
avakulenko@google.com17449932014-07-28 22:13:33 +00006342 sys.stderr.write(
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006343 "Skipping config file '%s': Can't open for reading\n" %
6344 cfg_file)
6345 keep_looking = False
avakulenko@google.com17449932014-07-28 22:13:33 +00006346
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006347 # Apply all the accumulated filters in reverse order (top-level directory
6348 # config options having the least priority).
6349 for filter in reversed(cfg_filters):
6350 _AddFilters(filter)
avakulenko@google.com17449932014-07-28 22:13:33 +00006351
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006352 return True
avakulenko@google.com17449932014-07-28 22:13:33 +00006353
avakulenko@google.comd39bbb52014-06-04 22:55:20 +00006354
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006355def ProcessFile(filename, vlevel, extra_check_functions=[]):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006356 """Does google-lint on a single file.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006357
6358 Args:
6359 filename: The name of the file to parse.
6360
6361 vlevel: The level of errors to report. Every error of confidence
6362 >= verbose_level will be reported. 0 is a good default.
asvitkine@chromium.org8b8d8be2011-09-08 15:34:45 +00006363
6364 extra_check_functions: An array of additional check functions that will be
6365 run on each source line. Each function takes 4
6366 arguments: filename, clean_lines, line, error
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006367 """
6368
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006369 _SetVerboseLevel(vlevel)
6370 _BackupFilters()
avakulenko@google.com17449932014-07-28 22:13:33 +00006371
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006372 if not ProcessConfigOverrides(filename):
6373 _RestoreFilters()
6374 return
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006375
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006376 lf_lines = []
6377 crlf_lines = []
6378 try:
6379 # Support the UNIX convention of using "-" for stdin. Note that
6380 # we are not opening the file with universal newline support
6381 # (which codecs doesn't support anyway), so the resulting lines do
6382 # contain trailing '\r' characters if we are reading a file that
6383 # has CRLF endings.
6384 # If after the split a trailing '\r' is present, it is removed
6385 # below.
6386 if filename == '-':
6387 lines = codecs.StreamReaderWriter(sys.stdin,
6388 codecs.getreader('utf8'),
6389 codecs.getwriter('utf8'),
6390 'replace').read().split('\n')
6391 else:
6392 with codecs.open(filename, 'r', 'utf8', 'replace') as stream:
6393 lines = stream.read().split('\n')
6394
6395 # Remove trailing '\r'.
6396 # The -1 accounts for the extra trailing blank line we get from split()
6397 for linenum in range(len(lines) - 1):
6398 if lines[linenum].endswith('\r'):
6399 lines[linenum] = lines[linenum].rstrip('\r')
6400 crlf_lines.append(linenum + 1)
6401 else:
6402 lf_lines.append(linenum + 1)
6403
6404 except IOError:
6405 sys.stderr.write("Skipping input '%s': Can't open for reading\n" %
6406 filename)
6407 _RestoreFilters()
6408 return
6409
6410 # Note, if no dot is found, this will give the entire filename as the ext.
6411 file_extension = filename[filename.rfind('.') + 1:]
6412
6413 # When reading from stdin, the extension is unknown, so no cpplint tests
6414 # should rely on the extension.
6415 if filename != '-' and file_extension not in _valid_extensions:
6416 sys.stderr.write('Ignoring %s; not a valid file name '
6417 '(%s)\n' % (filename, ', '.join(_valid_extensions)))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006418 else:
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006419 ProcessFileData(filename, file_extension, lines, Error,
6420 extra_check_functions)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006421
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006422 # If end-of-line sequences are a mix of LF and CR-LF, issue
6423 # warnings on the lines with CR.
6424 #
6425 # Don't issue any warnings if all lines are uniformly LF or CR-LF,
6426 # since critique can handle these just fine, and the style guide
6427 # doesn't dictate a particular end of line sequence.
6428 #
6429 # We can't depend on os.linesep to determine what the desired
6430 # end-of-line sequence should be, since that will return the
6431 # server-side end-of-line sequence.
6432 if lf_lines and crlf_lines:
6433 # Warn on every line with CR. An alternative approach might be to
6434 # check whether the file is mostly CRLF or just LF, and warn on the
6435 # minority, we bias toward LF here since most tools prefer LF.
6436 for linenum in crlf_lines:
6437 Error(filename, linenum, 'whitespace/newline', 1,
6438 'Unexpected \\r (^M) found; better to use only \\n')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006439
avakulenko@google.com17449932014-07-28 22:13:33 +00006440 _RestoreFilters()
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006441
6442
6443def PrintUsage(message):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006444 """Prints a brief usage string and exits, optionally with an error message.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006445
6446 Args:
6447 message: The optional error message.
6448 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006449 sys.stderr.write(_USAGE)
6450 if message:
6451 sys.exit('\nFATAL ERROR: ' + message)
6452 else:
6453 sys.exit(1)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006454
6455
6456def PrintCategories():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006457 """Prints a list of all the error-categories used by error messages.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006458
6459 These are the categories used to filter messages via --filter.
6460 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006461 sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES))
6462 sys.exit(0)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006463
6464
6465def ParseArguments(args):
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006466 """Parses the command line arguments.
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006467
6468 This may set the output format and verbosity level as side-effects.
6469
6470 Args:
6471 args: The command line arguments:
6472
6473 Returns:
6474 The list of filenames to lint.
6475 """
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006476 try:
6477 (opts, filenames) = getopt.getopt(
6478 args,
6479 '',
6480 [
6481 'help',
6482 'output=',
6483 'verbose=',
6484 'headers=', # We understand but ignore headers.
6485 'counting=',
6486 'filter=',
6487 'root=',
6488 'linelength=',
6489 'extensions=',
6490 'project_root=',
6491 'repository='
6492 ])
6493 except getopt.GetoptError as e:
6494 PrintUsage('Invalid arguments: {}'.format(e))
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006495
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006496 verbosity = _VerboseLevel()
6497 output_format = _OutputFormat()
6498 filters = ''
6499 counting_style = ''
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006500
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006501 for (opt, val) in opts:
6502 if opt == '--help':
6503 PrintUsage(None)
6504 elif opt == '--output':
6505 if val not in ('emacs', 'vs7', 'eclipse'):
6506 PrintUsage(
6507 'The only allowed output formats are emacs, vs7 and eclipse.'
6508 )
6509 output_format = val
6510 elif opt == '--verbose':
6511 verbosity = int(val)
6512 elif opt == '--filter':
6513 filters = val
6514 if not filters:
6515 PrintCategories()
6516 elif opt == '--counting':
6517 if val not in ('total', 'toplevel', 'detailed'):
6518 PrintUsage(
6519 'Valid counting options are total, toplevel, and detailed')
6520 counting_style = val
6521 elif opt == '--root':
6522 global _root
6523 _root = val
6524 elif opt == '--project_root' or opt == "--repository":
6525 global _project_root
6526 _project_root = val
6527 if not os.path.isabs(_project_root):
6528 PrintUsage('Project root must be an absolute path.')
6529 elif opt == '--linelength':
6530 global _line_length
6531 try:
6532 _line_length = int(val)
6533 except ValueError:
6534 PrintUsage('Line length must be digits.')
6535 elif opt == '--extensions':
6536 global _valid_extensions
6537 try:
6538 _valid_extensions = set(val.split(','))
6539 except ValueError:
6540 PrintUsage('Extensions must be comma separated list.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006541
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006542 if not filenames:
6543 PrintUsage('No files were specified.')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006544
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006545 _SetOutputFormat(output_format)
6546 _SetVerboseLevel(verbosity)
6547 _SetFilters(filters)
6548 _SetCountingStyle(counting_style)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006549
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006550 return filenames
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006551
6552
6553def main():
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006554 filenames = ParseArguments(sys.argv[1:])
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006555
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006556 # Change stderr to write with replacement characters so we don't die
6557 # if we try to print something containing non-ASCII characters.
6558 # We use sys.stderr.buffer in Python 3, since StreamReaderWriter writes
6559 # bytes to the specified stream.
6560 sys.stderr = codecs.StreamReaderWriter(
6561 getattr(sys.stderr, 'buffer', sys.stderr), codecs.getreader('utf8'),
6562 codecs.getwriter('utf8'), 'replace')
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006563
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006564 _cpplint_state.ResetErrorCounts()
6565 for filename in filenames:
6566 ProcessFile(filename, _cpplint_state.verbose_level)
6567 _cpplint_state.PrintErrorCounts()
erg@google.com26970fa2009-11-17 18:07:32 +00006568
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006569 sys.exit(_cpplint_state.error_count > 0)
maruel@google.comfb2b8eb2009-04-23 21:03:42 +00006570
6571
6572if __name__ == '__main__':
Mike Frysinger124bb8e2023-09-06 05:48:55 +00006573 main()