Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(352)

Side by Side Diff: third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py

Issue 2749513008: Remove header ordering checks from check-webkit-style (Closed)
Patch Set: Rebased Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 # 2 #
3 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved. 3 # Copyright (C) 2009, 2010, 2012 Google Inc. All rights reserved.
4 # Copyright (C) 2009 Torch Mobile Inc. 4 # Copyright (C) 2009 Torch Mobile Inc.
5 # Copyright (C) 2009 Apple Inc. All rights reserved. 5 # Copyright (C) 2009 Apple Inc. All rights reserved.
6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
7 # 7 #
8 # Redistribution and use in source and binary forms, with or without 8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions are 9 # modification, are permitted provided that the following conditions are
10 # met: 10 # met:
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement 107 _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
108 _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement 108 _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
109 109
110 _DEPRECATED_MACROS = [ 110 _DEPRECATED_MACROS = [
111 ['ASSERT', 'DCHECK or its variants'], 111 ['ASSERT', 'DCHECK or its variants'],
112 ['ASSERT_UNUSED', 'DCHECK or its variants'], 112 ['ASSERT_UNUSED', 'DCHECK or its variants'],
113 ['ASSERT_NOT_REACHED', 'NOTREACHED'], 113 ['ASSERT_NOT_REACHED', 'NOTREACHED'],
114 ['WTF_LOG', 'DVLOG'] 114 ['WTF_LOG', 'DVLOG']
115 ] 115 ]
116 116
117 # These constants define types of headers for use with
118 # _IncludeState.check_next_include_order().
119 _PRIMARY_HEADER = 0
120 _OTHER_HEADER = 1
121
122 117
123 # The regexp compilation caching is inlined in all regexp functions for 118 # The regexp compilation caching is inlined in all regexp functions for
124 # performance reasons; factoring it out into a separate function turns out 119 # performance reasons; factoring it out into a separate function turns out
125 # to be noticeably expensive. 120 # to be noticeably expensive.
126 _regexp_compile_cache = {} 121 _regexp_compile_cache = {}
127 122
128 123
129 def match(pattern, s): 124 def match(pattern, s):
130 """Matches the string with the pattern, caching the compiled regexp.""" 125 """Matches the string with the pattern, caching the compiled regexp."""
131 if not pattern in _regexp_compile_cache: 126 if not pattern in _regexp_compile_cache:
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
285 if i == 0: 280 if i == 0:
286 return s[:pos], s[pos + 1:] 281 return s[:pos], s[pos + 1:]
287 return None, None 282 return None, None
288 283
289 284
290 class _IncludeState(dict): 285 class _IncludeState(dict):
291 """Tracks line numbers for includes, and the order in which includes appear. 286 """Tracks line numbers for includes, and the order in which includes appear.
292 287
293 As a dict, an _IncludeState object serves as a mapping between include 288 As a dict, an _IncludeState object serves as a mapping between include
294 filename and line number on which that file was included. 289 filename and line number on which that file was included.
295
296 Call check_next_include_order() once for each header in the file, passing
297 in the type constants defined above. Calls in an illegal order will
298 raise an _IncludeError with an appropriate error message.
299 """ 290 """
300 # self._section will move monotonically through this set. If it ever 291 # self._section will move monotonically through this set. If it ever
301 # needs to move backwards, check_next_include_order will raise an error. 292 # needs to move backwards, check_next_include_order will raise an error.
302 _INITIAL_SECTION = 0 293 _INITIAL_SECTION = 0
303 _PRIMARY_SECTION = 1 294 _PRIMARY_SECTION = 1
304 _OTHER_SECTION = 2 295 _OTHER_SECTION = 2
305 296
306 _TYPE_NAMES = {
307 _PRIMARY_HEADER: 'header this file implements',
308 _OTHER_HEADER: 'other header',
309 }
310 _SECTION_NAMES = { 297 _SECTION_NAMES = {
311 _INITIAL_SECTION: '... nothing.', 298 _INITIAL_SECTION: '... nothing.',
312 _PRIMARY_SECTION: 'a header this file implements.', 299 _PRIMARY_SECTION: 'a header this file implements.',
313 _OTHER_SECTION: 'other header.', 300 _OTHER_SECTION: 'other header.',
314 } 301 }
315 302
316 def __init__(self): 303 def __init__(self):
317 dict.__init__(self) 304 dict.__init__(self)
318 self._section = self._INITIAL_SECTION 305 self._section = self._INITIAL_SECTION
319 self._visited_primary_section = False 306 self._visited_primary_section = False
320 self.header_types = dict() 307 self.header_types = dict()
321 308
322 def visited_primary_section(self): 309 def visited_primary_section(self):
323 return self._visited_primary_section 310 return self._visited_primary_section
324 311
325 def check_next_include_order(self, header_type, file_is_header, primary_head er_exists):
326 """Returns a non-empty error message if the next header is out of order.
327
328 This function also updates the internal state to be ready to check
329 the next include.
330
331 Args:
332 header_type: One of the _XXX_HEADER constants defined above.
333 file_is_header: Whether the file that owns this _IncludeState is itsel f a header
334
335 Returns:
336 The empty string if the header is in the right order, or an
337 error message describing what's wrong.
338 """
339 if header_type == _PRIMARY_HEADER and file_is_header:
340 return 'Header file should not contain itself.'
341
342 error_message = ''
343 if self._section != self._OTHER_SECTION:
344 before_error_message = ('Found %s before %s' %
345 (self._TYPE_NAMES[header_type],
346 self._SECTION_NAMES[self._section + 1]))
347 after_error_message = ('Found %s after %s' %
348 (self._TYPE_NAMES[header_type],
349 self._SECTION_NAMES[self._section]))
350
351 if header_type == _PRIMARY_HEADER:
352 if self._section >= self._PRIMARY_SECTION:
353 error_message = after_error_message
354 self._section = self._PRIMARY_SECTION
355 self._visited_primary_section = True
356 else:
357 assert header_type == _OTHER_HEADER
358 if not file_is_header and self._section < self._PRIMARY_SECTION:
359 if primary_header_exists:
360 error_message = before_error_message
361 self._section = self._OTHER_SECTION
362
363 return error_message
364
365 312
366 class Position(object): 313 class Position(object):
367 """Holds the position of something.""" 314 """Holds the position of something."""
368 315
369 def __init__(self, row, column): 316 def __init__(self, row, column):
370 self.row = row 317 self.row = row
371 self.column = column 318 self.column = column
372 319
373 def __str__(self): 320 def __str__(self):
374 return '(%s, %s)' % (self.row, self.column) 321 return '(%s, %s)' % (self.row, self.column)
(...skipping 2048 matching lines...) Expand 10 before | Expand all | Expand 10 after
2423 2370
2424 _RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') 2371 _RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
2425 # Matches the first component of a filename delimited by -s and _s. That is: 2372 # Matches the first component of a filename delimited by -s and _s. That is:
2426 # _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' 2373 # _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
2427 # _RE_FIRST_COMPONENT.match('foo.cpp').group(0) == 'foo' 2374 # _RE_FIRST_COMPONENT.match('foo.cpp').group(0) == 'foo'
2428 # _RE_FIRST_COMPONENT.match('foo-bar_baz.cpp').group(0) == 'foo' 2375 # _RE_FIRST_COMPONENT.match('foo-bar_baz.cpp').group(0) == 'foo'
2429 # _RE_FIRST_COMPONENT.match('foo_bar-baz.cpp').group(0) == 'foo' 2376 # _RE_FIRST_COMPONENT.match('foo_bar-baz.cpp').group(0) == 'foo'
2430 _RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') 2377 _RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
2431 2378
2432 2379
2433 def _drop_common_suffixes(filename):
2434 """Drops common suffixes like _test.cpp or -inl.h from filename.
2435
2436 For example:
2437 >>> _drop_common_suffixes('foo/foo-inl.h')
2438 'foo/foo'
2439 >>> _drop_common_suffixes('foo/bar/foo.cpp')
2440 'foo/bar/foo'
2441 >>> _drop_common_suffixes('foo/foo_internal.h')
2442 'foo/foo'
2443 >>> _drop_common_suffixes('foo/foo_unusualinternal.h')
2444 'foo/foo_unusualinternal'
2445
2446 Args:
2447 filename: The input filename.
2448
2449 Returns:
2450 The filename with the common suffix removed.
2451 """
2452 for suffix in ('test.cpp', 'regtest.cpp', 'unittest.cpp',
2453 'inl.h', 'impl.h', 'internal.h'):
2454 if (filename.endswith(suffix) and len(filename) > len(suffix)
2455 and filename[-len(suffix) - 1] in ('-', '_')):
2456 return filename[:-len(suffix) - 1]
2457 return os.path.splitext(filename)[0]
2458
2459
2460 def _classify_include(filename, include, is_system, include_state):
2461 """Figures out what kind of header 'include' is.
2462
2463 Args:
2464 filename: The current file cpp_style is running over.
2465 include: The path to a #included file.
2466 is_system: True if the #include used <> rather than "".
2467 include_state: An _IncludeState instance in which the headers are inserted .
2468
2469 Returns:
2470 One of the _XXX_HEADER constants.
2471
2472 For example:
2473 >>> _classify_include('foo.cpp', 'foo.h', False)
2474 _PRIMARY_HEADER
2475 >>> _classify_include('foo.cpp', 'bar.h', False)
2476 _OTHER_HEADER
2477 """
2478
2479 # If it is a system header we know it is classified as _OTHER_HEADER.
2480 if is_system and not include.startswith('public/'):
2481 return _OTHER_HEADER
2482
2483 # There cannot be primary includes in header files themselves. Only an
2484 # include exactly matches the header filename will be is flagged as
2485 # primary, so that it triggers the "don't include yourself" check.
2486 if filename.endswith('.h') and filename != include:
2487 return _OTHER_HEADER
2488
2489 # If the target file basename starts with the include we're checking
2490 # then we consider it the primary header.
2491 target_base = FileInfo(filename).base_name()
2492 include_base = FileInfo(include).base_name()
2493
2494 # If we haven't encountered a primary header, then be lenient in checking.
2495 if not include_state.visited_primary_section():
2496 if target_base.find(include_base) != -1:
2497 return _PRIMARY_HEADER
2498
2499 # If we already encountered a primary header, perform a strict comparison.
2500 # In case the two filename bases are the same then the above lenient check
2501 # probably was a false positive.
2502 elif include_state.visited_primary_section() and target_base == include_base :
2503 return _PRIMARY_HEADER
2504
2505 return _OTHER_HEADER
2506
2507
2508 def _does_primary_header_exist(filename):
2509 """Return a primary header file name for a file, or empty string
2510 if the file is not source file or primary header does not exist.
2511 """
2512 fileinfo = FileInfo(filename)
2513 if not fileinfo.is_source():
2514 return False
2515 primary_header = fileinfo.no_extension() + '.h'
2516 return os.path.isfile(primary_header)
2517
2518
2519 def check_include_line(filename, file_extension, clean_lines, line_number, inclu de_state, error): 2380 def check_include_line(filename, file_extension, clean_lines, line_number, inclu de_state, error):
2520 """Check rules that are applicable to #include lines. 2381 """Check rules that are applicable to #include lines.
2521 2382
2522 Strings on #include lines are NOT removed from elided line, to make 2383 Strings on #include lines are NOT removed from elided line, to make
2523 certain tasks easier. However, to prevent false positives, checks 2384 certain tasks easier. However, to prevent false positives, checks
2524 applicable to #include lines in CheckLanguage must be put here. 2385 applicable to #include lines in CheckLanguage must be put here.
2525 2386
2526 Args: 2387 Args:
2527 filename: The name of the current file. 2388 filename: The name of the current file.
2528 file_extension: The current file extension, without the leading dot. 2389 file_extension: The current file extension, without the leading dot.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
2561 'cc includes should be "CCFoo.h" instead of "cc/CCFoo.h".') 2422 'cc includes should be "CCFoo.h" instead of "cc/CCFoo.h".')
2562 2423
2563 duplicate_header = include in include_state 2424 duplicate_header = include in include_state
2564 if duplicate_header: 2425 if duplicate_header:
2565 error(line_number, 'build/include', 4, 2426 error(line_number, 'build/include', 4,
2566 '"%s" already included at %s:%s' % 2427 '"%s" already included at %s:%s' %
2567 (include, filename, include_state[include])) 2428 (include, filename, include_state[include]))
2568 else: 2429 else:
2569 include_state[include] = line_number 2430 include_state[include] = line_number
2570 2431
2571 header_type = _classify_include(filename, include, is_system, include_state)
2572 primary_header_exists = _does_primary_header_exist(filename)
2573 include_state.header_types[line_number] = header_type
2574
2575 # Only proceed if this isn't a duplicate header.
2576 if duplicate_header:
2577 return
2578
2579 # We want to ensure that headers appear in the right order:
2580 # 1) for implementation files: primary header, blank line, alphabetically so rted
2581 # 2) for header files: alphabetically sorted
2582 # The include_state object keeps track of the last type seen
2583 # and complains if the header types are out of order or missing.
2584 error_message = include_state.check_next_include_order(header_type,
2585 file_extension == 'h' ,
2586 primary_header_exists )
2587
2588 # Check to make sure we have a blank line after primary header.
2589 if not error_message and header_type == _PRIMARY_HEADER:
2590 next_line = clean_lines.raw_lines[line_number + 1]
2591 if not is_blank_line(next_line):
2592 error(line_number, 'build/include_order', 4,
2593 'You should add a blank line after implementation file\'s own header.')
2594
2595 if error_message:
2596 if file_extension == 'h':
2597 error(line_number, 'build/include_order', 4,
2598 '%s Should be: alphabetically sorted.' %
2599 error_message)
2600 else:
2601 error(line_number, 'build/include_order', 4,
2602 '%s Should be: primary header, blank line, and then alphabetic ally sorted.' %
2603 error_message)
2604
2605 2432
2606 def check_language(filename, clean_lines, line_number, file_extension, include_s tate, 2433 def check_language(filename, clean_lines, line_number, file_extension, include_s tate,
2607 file_state, error): 2434 file_state, error):
2608 """Checks rules from the 'C++ language rules' section of cppguide.html. 2435 """Checks rules from the 'C++ language rules' section of cppguide.html.
2609 2436
2610 Some of these rules are hard to test (function overloading, using 2437 Some of these rules are hard to test (function overloading, using
2611 uint32 inappropriately), but we do the best we can. 2438 uint32 inappropriately), but we do the best we can.
2612 2439
2613 Args: 2440 Args:
2614 filename: The name of the current file. 2441 filename: The name of the current file.
(...skipping 968 matching lines...) Expand 10 before | Expand all | Expand 10 after
3583 3410
3584 def check(self, lines): 3411 def check(self, lines):
3585 _process_lines(self.file_path, self.file_extension, lines, 3412 _process_lines(self.file_path, self.file_extension, lines,
3586 self.handle_style_error, self.min_confidence) 3413 self.handle_style_error, self.min_confidence)
3587 3414
3588 3415
3589 # FIXME: Remove this function (requires refactoring unit tests). 3416 # FIXME: Remove this function (requires refactoring unit tests).
3590 def process_file_data(filename, file_extension, lines, error, min_confidence, fs =None): 3417 def process_file_data(filename, file_extension, lines, error, min_confidence, fs =None):
3591 checker = CppChecker(filename, file_extension, error, min_confidence, fs) 3418 checker = CppChecker(filename, file_extension, error, min_confidence, fs)
3592 checker.check(lines) 3419 checker.check(lines)
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698