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

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

Issue 2800883004: Port cpplint's C++11 raw string support to blink's cpp style checker. (Closed)
Patch Set: Created 3 years, 8 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 671 matching lines...) Expand 10 before | Expand all | Expand 10 after
682 682
683 Returns: 683 Returns:
684 True, if next character appended to 'line' is inside a 684 True, if next character appended to 'line' is inside a
685 string constant. 685 string constant.
686 """ 686 """
687 687
688 line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" 688 line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
689 return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 689 return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
690 690
691 691
692 def cleanse_raw_strings(raw_lines):
693 """Removes C++11 raw strings from lines.
694
695 Before:
696 static const char kData[] = R"(
697 multi-line string
698 )";
699
700 After:
701 static const char kData[] = ""
702 (replaced by blank line)
703 "";
704
705 Args:
706 raw_lines: list of raw lines.
707
708 Returns:
709 list of lines with C++11 raw strings replaced by empty strings.
710 """
711
712 delimiter = None
713 lines_without_raw_strings = []
714 for line in raw_lines:
715 if delimiter:
716 # Inside a raw string, look for the end
717 end = line.find(delimiter)
718 if end >= 0:
719 # Found the end of the string, match leading space for this
720 # line and resume copying the original lines, and also insert
721 # a "" on the last line.
722 leading_space = match(r'^(\s*)\S', line)
723 line = leading_space.group(1) + '""' + line[end + len(delimiter) :]
724 delimiter = None
725 else:
726 # Haven't found the end yet, append a blank line.
727 line = '""'
728
729 # Look for beginning of a raw string, and replace them with
730 # empty strings. This is done in a loop to handle multiple raw
731 # strings on the same line.
732 while delimiter is None:
733 # Look for beginning of a raw string.
734 # See 2.14.15 [lex.string] for syntax.
735 #
736 # Once we have matched a raw string, we check the prefix of the
737 # line to make sure that the line is not part of a single line
738 # comment. It's done this way because we remove raw strings
739 # before removing comments as opposed to removing comments
740 # before removing raw strings. This is because there are some
741 # cpplint checks that requires the comments to be preserved, but
742 # we don't want to check comments that are inside raw strings.
743 matched = match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', l ine)
744 if matched and not match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")* //', matched.group(1)):
745 delimiter = ')' + matched.group(2) + '"'
746
747 end = matched.group(3).find(delimiter)
748 if end >= 0:
749 # Raw string ended on same line
750 line = (matched.group(1) + '""' +
751 matched.group(3)[end + len(delimiter):])
752 delimiter = None
753 else:
754 # Start of a multi-line raw string
755 line = matched.group(1) + '""'
756 else:
757 break
758
759 lines_without_raw_strings.append(line)
760
761 # TODO(unknown): if delimiter is not None here, we might want to
762 # emit a warning for unterminated string.
763 return lines_without_raw_strings
764
765
692 def find_next_multi_line_comment_start(lines, line_index): 766 def find_next_multi_line_comment_start(lines, line_index):
693 """Find the beginning marker for a multiline comment.""" 767 """Find the beginning marker for a multiline comment."""
694 while line_index < len(lines): 768 while line_index < len(lines):
695 if lines[line_index].strip().startswith('/*'): 769 if lines[line_index].strip().startswith('/*'):
696 # Only return this marker if the comment goes beyond this line 770 # Only return this marker if the comment goes beyond this line
697 if lines[line_index].strip().find('*/', 2) < 0: 771 if lines[line_index].strip().find('*/', 2) < 0:
698 return line_index 772 return line_index
699 line_index += 1 773 line_index += 1
700 return len(lines) 774 return len(lines)
701 775
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 The line with single-line comments removed. 817 The line with single-line comments removed.
744 """ 818 """
745 comment_position = line.find('//') 819 comment_position = line.find('//')
746 if comment_position != -1 and not is_cpp_string(line[:comment_position]): 820 if comment_position != -1 and not is_cpp_string(line[:comment_position]):
747 line = line[:comment_position] 821 line = line[:comment_position]
748 # get rid of /* ... */ 822 # get rid of /* ... */
749 return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) 823 return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
750 824
751 825
752 class CleansedLines(object): 826 class CleansedLines(object):
753 """Holds 3 copies of all lines with different preprocessing applied to them. 827 """Holds 4 copies of all lines with different preprocessing applied to them.
754 828
755 1) elided member contains lines without strings and comments, 829 1) elided member contains lines without strings and comments.
756 2) lines member contains lines without comments, and 830 2) lines member contains lines without comments.
757 3) raw member contains all the lines without processing. 831 3) raw_lines member contains all the lines without processing.
758 All these three members are of <type 'list'>, and of the same length. 832 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw
833 strings removed.
834 All these members are of <type 'list'>, and of the same length.
759 """ 835 """
760 836
761 def __init__(self, lines): 837 def __init__(self, lines):
762 self.elided = [] 838 self.elided = []
763 self.lines = [] 839 self.lines = []
764 self.raw_lines = lines 840 self.raw_lines = lines
765 self._num_lines = len(lines) 841 self._num_lines = len(lines)
766 for line_number in range(len(lines)): 842 self.lines_without_raw_strings = cleanse_raw_strings(lines)
767 self.lines.append(cleanse_comments(lines[line_number])) 843 for line_number in range(len(self.lines_without_raw_strings)):
768 elided = self.collapse_strings(lines[line_number]) 844 self.lines.append(cleanse_comments(self.lines_without_raw_strings[li ne_number]))
845 elided = self.collapse_strings(self.lines_without_raw_strings[line_n umber])
769 self.elided.append(cleanse_comments(elided)) 846 self.elided.append(cleanse_comments(elided))
770 847
771 def num_lines(self): 848 def num_lines(self):
772 """Returns the number of lines represented.""" 849 """Returns the number of lines represented."""
773 return self._num_lines 850 return self._num_lines
774 851
775 @staticmethod 852 @staticmethod
776 def collapse_strings(elided): 853 def collapse_strings(elided):
777 """Collapses strings and chars on a line to simple "" or '' blocks. 854 """Collapses strings and chars on a line to simple "" or '' blocks.
778 855
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 986
910 # If it's a full path and starts with Source/, replace Source with blink 987 # If it's a full path and starts with Source/, replace Source with blink
911 # since that will be the new style directory. 988 # since that will be the new style directory.
912 filename = sub(r'^Source\/', 'blink/', filename) 989 filename = sub(r'^Source\/', 'blink/', filename)
913 990
914 standard_name = sub(r'[-.\s\/]', '_', filename).upper() + '_' 991 standard_name = sub(r'[-.\s\/]', '_', filename).upper() + '_'
915 992
916 return standard_name 993 return standard_name
917 994
918 995
919 def check_for_header_guard(filename, lines, error): 996 def check_for_header_guard(filename, clean_lines, error):
920 """Checks that the file contains a header guard. 997 """Checks that the file contains a header guard.
921 998
922 Logs an error if no #ifndef header guard is present. For other 999 Logs an error if no #ifndef header guard is present. For other
923 headers, checks that the full pathname is used. 1000 headers, checks that the full pathname is used.
924 1001
925 Args: 1002 Args:
926 filename: The name of the C++ header file. 1003 filename: The name of the C++ header file.
927 lines: An array of strings, each representing a line of the file. 1004 lines: An array of strings, each representing a line of the file.
928 error: The function to call with any errors found. 1005 error: The function to call with any errors found.
929 """ 1006 """
1007 raw_lines = clean_lines.lines_without_raw_strings
930 1008
931 legacy_cpp_var = get_legacy_header_guard_cpp_variable(filename) 1009 legacy_cpp_var = get_legacy_header_guard_cpp_variable(filename)
932 cpp_var = get_header_guard_cpp_variable(filename) 1010 cpp_var = get_header_guard_cpp_variable(filename)
933 1011
934 ifndef = None 1012 ifndef = None
935 ifndef_line_number = 0 1013 ifndef_line_number = 0
936 define = None 1014 define = None
937 for line_number, line in enumerate(lines): 1015 for line_number, line in enumerate(raw_lines):
938 line_split = line.split() 1016 line_split = line.split()
939 if len(line_split) >= 2: 1017 if len(line_split) >= 2:
940 # find the first occurrence of #ifndef and #define, save arg 1018 # find the first occurrence of #ifndef and #define, save arg
941 if not ifndef and line_split[0] == '#ifndef': 1019 if not ifndef and line_split[0] == '#ifndef':
942 # set ifndef to the header guard presented on the #ifndef line. 1020 # set ifndef to the header guard presented on the #ifndef line.
943 ifndef = line_split[1] 1021 ifndef = line_split[1]
944 ifndef_line_number = line_number 1022 ifndef_line_number = line_number
945 if not define and line_split[0] == '#define': 1023 if not define and line_split[0] == '#define':
946 define = line_split[1] 1024 define = line_split[1]
947 if define and ifndef: 1025 if define and ifndef:
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after
1697 line, don't end a function with a blank line, don't have too many 1775 line, don't end a function with a blank line, don't have too many
1698 blank lines in a row. 1776 blank lines in a row.
1699 1777
1700 Args: 1778 Args:
1701 file_extension: The current file extension, without the leading dot. 1779 file_extension: The current file extension, without the leading dot.
1702 clean_lines: A CleansedLines instance containing the file. 1780 clean_lines: A CleansedLines instance containing the file.
1703 line_number: The number of the line to check. 1781 line_number: The number of the line to check.
1704 error: The function to call with any errors found. 1782 error: The function to call with any errors found.
1705 """ 1783 """
1706 1784
1707 line = clean_lines.elided[line_number] # get rid of comments and strings 1785 # Don't use "elided" lines here, otherwise we can't check commented lines.
1786 # Don't want to use "raw" either, because we don't want to check inside C++1 1
1787 # raw strings,
1788 raw = clean_lines.lines_without_raw_strings
1789 line = raw[line_number]
1708 1790
1709 # You shouldn't have a space before a semicolon at the end of the line. 1791 # You shouldn't have a space before a semicolon at the end of the line.
1710 # There's a special case for "for" since the style guide allows space before 1792 # There's a special case for "for" since the style guide allows space before
1711 # the semicolon there. 1793 # the semicolon there.
1712 if search(r':\s*;\s*$', line): 1794 if search(r':\s*;\s*$', line):
1713 error(line_number, 'whitespace/semicolon', 5, 1795 error(line_number, 'whitespace/semicolon', 5,
1714 'Semicolon defining empty statement. Use { } instead.') 1796 'Semicolon defining empty statement. Use { } instead.')
1715 elif search(r'^\s*;\s*$', line): 1797 elif search(r'^\s*;\s*$', line):
1716 error(line_number, 'whitespace/semicolon', 5, 1798 error(line_number, 'whitespace/semicolon', 5,
1717 'Line contains only semicolon. If this should be an empty statemen t, ' 1799 'Line contains only semicolon. If this should be an empty statemen t, '
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
2344 line_number: The number of the line to check. 2426 line_number: The number of the line to check.
2345 file_extension: The extension (without the dot) of the filename. 2427 file_extension: The extension (without the dot) of the filename.
2346 class_state: A _ClassState instance which maintains information about 2428 class_state: A _ClassState instance which maintains information about
2347 the current stack of nested class declarations being parsed. 2429 the current stack of nested class declarations being parsed.
2348 file_state: A _FileState instance which maintains information about 2430 file_state: A _FileState instance which maintains information about
2349 the state of things in the file. 2431 the state of things in the file.
2350 enum_state: A _EnumState instance which maintains the current enum state. 2432 enum_state: A _EnumState instance which maintains the current enum state.
2351 error: The function to call with any errors found. 2433 error: The function to call with any errors found.
2352 """ 2434 """
2353 2435
2354 raw_lines = clean_lines.raw_lines 2436 # Don't use "elided" lines here, otherwise we can't check commented lines.
2437 # Don't want to use "raw" either, because we don't want to check inside C++1 1
2438 # raw strings,
2439 raw_lines = clean_lines.lines_without_raw_strings
2355 line = raw_lines[line_number] 2440 line = raw_lines[line_number]
2356 2441
2357 # Some more style checks 2442 # Some more style checks
2358 check_using_std(clean_lines, line_number, file_state, error) 2443 check_using_std(clean_lines, line_number, file_state, error)
2359 check_max_min_macros(clean_lines, line_number, file_state, error) 2444 check_max_min_macros(clean_lines, line_number, file_state, error)
2360 check_ctype_functions(clean_lines, line_number, file_state, error) 2445 check_ctype_functions(clean_lines, line_number, file_state, error)
2361 check_braces(clean_lines, line_number, error) 2446 check_braces(clean_lines, line_number, error)
2362 check_exit_statement_simplifications(clean_lines, line_number, error) 2447 check_exit_statement_simplifications(clean_lines, line_number, error)
2363 check_spacing(file_extension, clean_lines, line_number, error) 2448 check_spacing(file_extension, clean_lines, line_number, error)
2364 check_check(clean_lines, line_number, error) 2449 check_check(clean_lines, line_number, error)
(...skipping 906 matching lines...) Expand 10 before | Expand all | Expand 10 after
3271 error: A callable to which errors are reported, which takes 4 arguments: 3356 error: A callable to which errors are reported, which takes 4 arguments:
3272 """ 3357 """
3273 lines = (['// marker so line numbers and indices both start at 1'] + lines + 3358 lines = (['// marker so line numbers and indices both start at 1'] + lines +
3274 ['// marker so line numbers end in a known way']) 3359 ['// marker so line numbers end in a known way'])
3275 3360
3276 include_state = _IncludeState() 3361 include_state = _IncludeState()
3277 function_state = _FunctionState(min_confidence) 3362 function_state = _FunctionState(min_confidence)
3278 class_state = _ClassState() 3363 class_state = _ClassState()
3279 3364
3280 check_for_copyright(lines, error) 3365 check_for_copyright(lines, error)
3366 remove_multi_line_comments(lines, error)
3367 clean_lines = CleansedLines(lines)
3281 3368
3282 if file_extension == 'h': 3369 if file_extension == 'h':
3283 check_for_header_guard(filename, lines, error) 3370 check_for_header_guard(filename, clean_lines, error)
3284 3371
3285 remove_multi_line_comments(lines, error)
3286 clean_lines = CleansedLines(lines)
3287 file_state = _FileState(clean_lines, file_extension) 3372 file_state = _FileState(clean_lines, file_extension)
3288 enum_state = _EnumState() 3373 enum_state = _EnumState()
3289 for line in xrange(clean_lines.num_lines()): 3374 for line in xrange(clean_lines.num_lines()):
3290 process_line(filename, file_extension, clean_lines, line, 3375 process_line(filename, file_extension, clean_lines, line,
3291 include_state, function_state, class_state, file_state, 3376 include_state, function_state, class_state, file_state,
3292 enum_state, error) 3377 enum_state, error)
3293 class_state.check_finished(error) 3378 class_state.check_finished(error)
3294 3379
3295 check_for_include_what_you_use(filename, clean_lines, include_state, error) 3380 check_for_include_what_you_use(filename, clean_lines, include_state, error)
3296 3381
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
3410 3495
3411 def check(self, lines): 3496 def check(self, lines):
3412 _process_lines(self.file_path, self.file_extension, lines, 3497 _process_lines(self.file_path, self.file_extension, lines,
3413 self.handle_style_error, self.min_confidence) 3498 self.handle_style_error, self.min_confidence)
3414 3499
3415 3500
3416 # FIXME: Remove this function (requires refactoring unit tests). 3501 # FIXME: Remove this function (requires refactoring unit tests).
3417 def process_file_data(filename, file_extension, lines, error, min_confidence, fs =None): 3502 def process_file_data(filename, file_extension, lines, error, min_confidence, fs =None):
3418 checker = CppChecker(filename, file_extension, error, min_confidence, fs) 3503 checker = CppChecker(filename, file_extension, error, min_confidence, fs)
3419 checker.check(lines) 3504 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