1 # Copyright (C) 2009 Google Inc. All rights reserved.
2 # Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
3 # Copyright (C) 2010 ProFUSION embedded systems
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
9 # * 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
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.
19 # 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.
31 """Front end of some style-checker modules."""
38 from checkers.common import categories as CommonCategories
39 from checkers.common import CarriageReturnChecker
40 from checkers.changelog import ChangeLogChecker
41 from checkers.cpp import CppChecker
42 from checkers.python import PythonChecker
43 from checkers.test_expectations import TestExpectationsChecker
44 from checkers.text import TextChecker
45 from checkers.watchlist import WatchListChecker
46 from checkers.xcodeproj import XcodeProjectFileChecker
47 from checkers.xml import XMLChecker
48 from error_handlers import DefaultStyleErrorHandler
49 from filter import FilterConfiguration
50 from optparser import ArgumentParser
51 from optparser import DefaultCommandOptionValues
52 from webkitpy.common.system.logutils import configure_logging as _configure_logging
55 _log = logging.getLogger(__name__)
58 # These are default option values for the command-line option parser.
59 _DEFAULT_MIN_CONFIDENCE = 1
60 _DEFAULT_OUTPUT_FORMAT = 'emacs'
63 # FIXME: For style categories we will never want to have, remove them.
64 # For categories for which we want to have similar functionality,
65 # modify the implementation and enable them.
67 # Throughout this module, we use "filter rule" rather than "filter"
68 # for an individual boolean filter flag like "+foo". This allows us to
69 # reserve "filter" for what one gets by collectively applying all of
72 # The base filter rules are the filter rules that begin the list of
73 # filter rules used to check style. For example, these rules precede
74 # any user-specified filter rules. Since by default all categories are
75 # checked, this list should normally include only rules that begin
77 _BASE_FILTER_RULES = [
78 '-build/endif_comment',
79 '-build/include_what_you_use', # <string> for std::string
80 '-build/storage_class', # const static
82 '-readability/multiline_comment',
83 '-readability/braces', # int foo() {};
84 '-readability/fn_size',
85 '-readability/casting',
86 '-readability/function',
87 '-runtime/arrays', # variable length array
90 '-runtime/explicit', # explicit
91 '-runtime/virtual', # virtual dtor
93 '-runtime/threadsafe_fn',
95 '-whitespace/blank_line',
96 '-whitespace/end_of_line',
98 # List Python pep8 categories last.
100 # Because much of WebKit's Python code base does not abide by the
101 # PEP8 79 character limit, we ignore the 79-character-limit category
104 # FIXME: Consider bringing WebKit's Python code base into conformance
105 # with the 79 character limit, or some higher limit that is
106 # agreeable to the WebKit project.
111 # The path-specific filter rules.
113 # This list is order sensitive. Only the first path substring match
114 # is used. See the FilterConfiguration documentation in filter.py
115 # for more information on this list.
117 # Each string appearing in this nested list should have at least
118 # one associated unit test assertion. These assertions are located,
119 # for example, in the test_path_rules_specifier() unit test method of
120 # checker_unittest.py.
121 _PATH_RULES_SPECIFIER = [
122 # Files in these directories are consumers of the WebKit
123 # API and therefore do not follow the same header including
124 # discipline as WebCore.
126 ([# TestNetscapePlugIn has no config.h and uses funny names like
128 "Tools/DumpRenderTree/TestNetscapePlugIn/",
129 # The API test harnesses have no config.h and use funny macros like
131 "Tools/WebKitAPITest/",
132 "Tools/TestWebKitAPI/",
133 "Source/WebKit/qt/tests/qdeclarativewebview"],
135 "-readability/naming"]),
136 ([# There is no clean way to avoid "yy_*" names used by flex.
137 "Source/WebCore/css/CSSParser.cpp",
138 # Qt code uses '_' in some places (such as private slots
139 # and on test xxx_data methos on tests)
140 "Source/JavaScriptCore/qt/",
141 "Source/WebKit/qt/Api/",
142 "Source/WebKit/qt/tests/",
143 "Source/WebKit/qt/declarative/",
144 "Source/WebKit/qt/examples/"],
145 ["-readability/naming"]),
146 ([# Qt's MiniBrowser has no config.h
147 "Tools/MiniBrowser/qt"],
150 ([# The Qt APIs use Qt/QML naming style, which includes
151 # naming parameters in h files.
152 "Source/WebKit2/UIProcess/API/qt"],
153 ["-readability/parameter_name"]),
155 ([# The GTK+ APIs use GTK+ naming style, which includes
156 # lower-cased, underscore-separated values, whitespace before
157 # parens for function calls, and always having variable names.
158 # Also, GTK+ allows the use of NULL.
159 "Source/WebCore/bindings/scripts/test/GObject",
160 "Source/WebKit/gtk/webkit/",
161 "Tools/DumpRenderTree/gtk/"],
162 ["-readability/naming",
163 "-readability/parameter_name",
165 "-whitespace/parens"]),
166 ([# Header files in ForwardingHeaders have no header guards or
167 # exceptional header guards (e.g., WebCore_FWD_Debugger_h).
168 "/ForwardingHeaders/"],
169 ["-build/header_guard"]),
170 ([# assembler has lots of opcodes that use underscores, so
171 # we don't check for underscores in that directory.
172 "/Source/JavaScriptCore/assembler/"],
173 ["-readability/naming"]),
174 ([# JITStubs has an usual syntax which causes false alarms for a few checks.
175 "JavaScriptCore/jit/JITStubs.cpp"],
176 ["-readability/parameter_name",
177 "-whitespace/parens"]),
179 ([# The EFL APIs use EFL naming style, which includes
180 # both lower-cased and camel-cased, underscore-sparated
182 "Source/WebKit/efl/ewk/",
183 "Source/WebKit2/UIProcess/API/efl/",
184 "Tools/EWebLauncher/",
185 "Tools/MiniBrowser/efl/"],
186 ["-readability/naming",
187 "-readability/parameter_name",
188 "-whitespace/declaration"]),
191 # WebKit2 and certain directories have idiosyncracies.
192 ([# NPAPI has function names with underscores.
193 "Source/WebKit2/WebProcess/Plugins/Netscape"],
194 ["-readability/naming"]),
195 ([# The WebKit2 C API has names with underscores and whitespace-aligned
196 # struct members. Also, we allow unnecessary parameter names in
197 # WebKit2 APIs because we're matching CF's header style.
198 "Source/WebKit2/UIProcess/API/C/",
199 "Source/WebKit2/Shared/API/c/",
200 "Source/WebKit2/WebProcess/InjectedBundle/API/c/"],
201 ["-readability/naming",
202 "-readability/parameter_name",
203 "-whitespace/declaration"]),
205 # For third-party Python code, keep only the following checks--
207 # No tabs: to avoid having to set the SVN allow-tabs property.
208 # No trailing white space: since this is easy to correct.
209 # No carriage-return line endings: since this is easy to correct.
211 (["webkitpy/thirdparty/"],
214 "+pep8/W291", # Trailing white space
215 "+whitespace/carriage_return"]),
217 ([# glu's libtess is third-party code, and doesn't follow WebKit style.
218 "Source/ThirdParty/glu"],
221 "-build/header_guard",
222 "-build/include_order"]),
226 _CPP_FILE_EXTENSIONS = [
232 _PYTHON_FILE_EXTENSION = 'py'
234 _TEXT_FILE_EXTENSIONS = [
261 _XCODEPROJ_FILE_EXTENSION = 'pbxproj'
263 _XML_FILE_EXTENSIONS = [
268 # Files to skip that are less obvious.
270 # Some files should be skipped when checking style. For example,
271 # WebKit maintains some files in Mozilla style on purpose to ease
273 _SKIPPED_FILES_WITH_WARNING = [
274 "Source/WebKit/gtk/tests/",
275 # All WebKit*.h files in Source/WebKit2/UIProcess/API/gtk,
276 # except those ending in ...Private.h are GTK+ API headers,
277 # which differ greatly from WebKit coding style.
278 re.compile(r'Source/WebKit2/UIProcess/API/gtk/WebKit(?!.*Private\.h).*\.h$'),
279 'Source/WebKit2/UIProcess/API/gtk/webkit2.h']
281 # Files to skip that are more common or obvious.
283 # This list should be in addition to files with FileType.NONE. Files
284 # with FileType.NONE are automatically skipped without warning.
285 _SKIPPED_FILES_WITHOUT_WARNING = [
286 "LayoutTests" + os.path.sep,
289 # Extensions of files which are allowed to contain carriage returns.
290 _CARRIAGE_RETURN_ALLOWED_FILE_EXTENSIONS = [
295 # The maximum number of errors to report per file, per category.
296 # If a category is not a key, then it has no maximum.
297 _MAX_REPORTS_PER_CATEGORY = {
298 "whitespace/carriage_return": 1
302 def _all_categories():
303 """Return the set of all categories used by check-webkit-style."""
304 # Take the union across all checkers.
305 categories = CommonCategories.union(CppChecker.categories)
306 categories = categories.union(TestExpectationsChecker.categories)
307 categories = categories.union(ChangeLogChecker.categories)
309 # FIXME: Consider adding all of the pep8 categories. Since they
310 # are not too meaningful for documentation purposes, for
311 # now we add only the categories needed for the unit tests
312 # (which validate the consistency of the configuration
313 # settings against the known categories, etc).
314 categories = categories.union(["pep8/W191", "pep8/W291", "pep8/E501"])
319 def _check_webkit_style_defaults():
320 """Return the default command-line options for check-webkit-style."""
321 return DefaultCommandOptionValues(min_confidence=_DEFAULT_MIN_CONFIDENCE,
322 output_format=_DEFAULT_OUTPUT_FORMAT)
325 # This function assists in optparser not having to import from checker.
326 def check_webkit_style_parser():
327 all_categories = _all_categories()
328 default_options = _check_webkit_style_defaults()
329 return ArgumentParser(all_categories=all_categories,
330 base_filter_rules=_BASE_FILTER_RULES,
331 default_options=default_options)
334 def check_webkit_style_configuration(options):
335 """Return a StyleProcessorConfiguration instance for check-webkit-style.
338 options: A CommandOptionValues instance.
341 filter_configuration = FilterConfiguration(
342 base_rules=_BASE_FILTER_RULES,
343 path_specific=_PATH_RULES_SPECIFIER,
344 user_rules=options.filter_rules)
346 return StyleProcessorConfiguration(filter_configuration=filter_configuration,
347 max_reports_per_category=_MAX_REPORTS_PER_CATEGORY,
348 min_confidence=options.min_confidence,
349 output_format=options.output_format,
350 stderr_write=sys.stderr.write)
353 def _create_log_handlers(stream):
354 """Create and return a default list of logging.Handler instances.
356 Format WARNING messages and above to display the logging level, and
357 messages strictly below WARNING not to display it.
360 stream: See the configure_logging() docstring.
363 # Handles logging.WARNING and above.
364 error_handler = logging.StreamHandler(stream)
365 error_handler.setLevel(logging.WARNING)
366 formatter = logging.Formatter("%(levelname)s: %(message)s")
367 error_handler.setFormatter(formatter)
369 # Create a logging.Filter instance that only accepts messages
370 # below WARNING (i.e. filters out anything WARNING or above).
371 non_error_filter = logging.Filter()
372 # The filter method accepts a logging.LogRecord instance.
373 non_error_filter.filter = lambda record: record.levelno < logging.WARNING
375 non_error_handler = logging.StreamHandler(stream)
376 non_error_handler.addFilter(non_error_filter)
377 formatter = logging.Formatter("%(message)s")
378 non_error_handler.setFormatter(formatter)
380 return [error_handler, non_error_handler]
383 def _create_debug_log_handlers(stream):
384 """Create and return a list of logging.Handler instances for debugging.
387 stream: See the configure_logging() docstring.
390 handler = logging.StreamHandler(stream)
391 formatter = logging.Formatter("%(name)s: %(levelname)-8s %(message)s")
392 handler.setFormatter(formatter)
397 def configure_logging(stream, logger=None, is_verbose=False):
398 """Configure logging, and return the list of handlers added.
401 A list of references to the logging handlers added to the root
402 logger. This allows the caller to later remove the handlers
403 using logger.removeHandler. This is useful primarily during unit
404 testing where the caller may want to configure logging temporarily
405 and then undo the configuring.
408 stream: A file-like object to which to log. The stream must
409 define an "encoding" data attribute, or else logging
411 logger: A logging.logger instance to configure. This parameter
412 should be used only in unit tests. Defaults to the
414 is_verbose: A boolean value of whether logging should be verbose.
417 # If the stream does not define an "encoding" data attribute, the
418 # logging module can throw an error like the following:
420 # Traceback (most recent call last):
421 # File "/System/Library/Frameworks/Python.framework/Versions/2.6/...
422 # lib/python2.6/logging/__init__.py", line 761, in emit
423 # self.stream.write(fs % msg.encode(self.stream.encoding))
424 # LookupError: unknown encoding: unknown
426 logger = logging.getLogger()
429 logging_level = logging.DEBUG
430 handlers = _create_debug_log_handlers(stream)
432 logging_level = logging.INFO
433 handlers = _create_log_handlers(stream)
435 handlers = _configure_logging(logging_level=logging_level, logger=logger,
444 NONE = 0 # FileType.NONE evaluates to False.
445 # Alphabetize remaining types
455 class CheckerDispatcher(object):
457 """Supports determining whether and how to check style, based on path."""
459 def _file_extension(self, file_path):
460 """Return the file extension without the leading dot."""
461 return os.path.splitext(file_path)[1].lstrip(".")
463 def _should_skip_file_path(self, file_path, skip_array_entry):
464 if isinstance(skip_array_entry, str):
465 if file_path.find(skip_array_entry) >= 0:
467 elif skip_array_entry.match(file_path):
471 def should_skip_with_warning(self, file_path):
472 """Return whether the given file should be skipped with a warning."""
473 for skipped_file in _SKIPPED_FILES_WITH_WARNING:
474 if self._should_skip_file_path(file_path, skipped_file):
478 def should_skip_without_warning(self, file_path):
479 """Return whether the given file should be skipped without a warning."""
480 if not self._file_type(file_path): # FileType.NONE.
482 # Since "LayoutTests" is in _SKIPPED_FILES_WITHOUT_WARNING, make
483 # an exception to prevent files like "LayoutTests/ChangeLog" and
484 # "LayoutTests/ChangeLog-2009-06-16" from being skipped.
485 # Files like 'test_expectations.txt' and 'drt_expectations.txt'
486 # are also should not be skipped.
488 # FIXME: Figure out a good way to avoid having to add special logic
489 # for this special case.
490 basename = os.path.basename(file_path)
491 if basename.startswith('ChangeLog'):
493 elif basename == 'test_expectations.txt' or basename == 'drt_expectations.txt':
495 for skipped_file in _SKIPPED_FILES_WITHOUT_WARNING:
496 if self._should_skip_file_path(file_path, skipped_file):
500 def should_check_and_strip_carriage_returns(self, file_path):
501 return self._file_extension(file_path) not in _CARRIAGE_RETURN_ALLOWED_FILE_EXTENSIONS
503 def _file_type(self, file_path):
504 """Return the file type corresponding to the given file."""
505 file_extension = self._file_extension(file_path)
507 if (file_extension in _CPP_FILE_EXTENSIONS) or (file_path == '-'):
508 # FIXME: Do something about the comment below and the issue it
509 # raises since cpp_style already relies on the extension.
511 # Treat stdin as C++. Since the extension is unknown when
512 # reading from stdin, cpp_style tests should not rely on
515 elif file_extension == _PYTHON_FILE_EXTENSION:
516 return FileType.PYTHON
517 elif file_extension in _XML_FILE_EXTENSIONS:
519 elif os.path.basename(file_path).startswith('ChangeLog'):
520 return FileType.CHANGELOG
521 elif os.path.basename(file_path) == 'watchlist':
522 return FileType.WATCHLIST
523 elif file_extension == _XCODEPROJ_FILE_EXTENSION:
524 return FileType.XCODEPROJ
525 elif ((not file_extension and os.path.join("Tools", "Scripts") in file_path) or
526 file_extension in _TEXT_FILE_EXTENSIONS):
531 def _create_checker(self, file_type, file_path, handle_style_error,
533 """Instantiate and return a style checker based on file type."""
534 if file_type == FileType.NONE:
536 elif file_type == FileType.CHANGELOG:
537 should_line_be_checked = None
538 if handle_style_error:
539 should_line_be_checked = handle_style_error.should_line_be_checked
540 checker = ChangeLogChecker(file_path, handle_style_error, should_line_be_checked)
541 elif file_type == FileType.CPP:
542 file_extension = self._file_extension(file_path)
543 checker = CppChecker(file_path, file_extension,
544 handle_style_error, min_confidence)
545 elif file_type == FileType.PYTHON:
546 checker = PythonChecker(file_path, handle_style_error)
547 elif file_type == FileType.XML:
548 checker = XMLChecker(file_path, handle_style_error)
549 elif file_type == FileType.XCODEPROJ:
550 checker = XcodeProjectFileChecker(file_path, handle_style_error)
551 elif file_type == FileType.TEXT:
552 basename = os.path.basename(file_path)
553 if basename == 'test_expectations.txt' or basename == 'drt_expectations.txt':
554 checker = TestExpectationsChecker(file_path, handle_style_error)
556 checker = TextChecker(file_path, handle_style_error)
557 elif file_type == FileType.WATCHLIST:
558 checker = WatchListChecker(file_path, handle_style_error)
560 raise ValueError('Invalid file type "%(file_type)s": the only valid file types '
561 "are %(NONE)s, %(CPP)s, and %(TEXT)s."
562 % {"file_type": file_type,
563 "NONE": FileType.NONE,
565 "TEXT": FileType.TEXT})
569 def dispatch(self, file_path, handle_style_error, min_confidence):
570 """Instantiate and return a style checker based on file path."""
571 file_type = self._file_type(file_path)
573 checker = self._create_checker(file_type,
580 # FIXME: Remove the stderr_write attribute from this class and replace
581 # its use with calls to a logging module logger.
582 class StyleProcessorConfiguration(object):
584 """Stores configuration values for the StyleProcessor class.
587 min_confidence: An integer between 1 and 5 inclusive that is the
588 minimum confidence level of style errors to report.
590 max_reports_per_category: The maximum number of errors to report
591 per category, per file.
593 stderr_write: A function that takes a string as a parameter and
594 serves as stderr.write.
599 filter_configuration,
600 max_reports_per_category,
604 """Create a StyleProcessorConfiguration instance.
607 filter_configuration: A FilterConfiguration instance. The default
608 is the "empty" filter configuration, which
609 means that all errors should be checked.
611 max_reports_per_category: The maximum number of errors to report
612 per category, per file.
614 min_confidence: An integer between 1 and 5 inclusive that is the
615 minimum confidence level of style errors to report.
616 The default is 1, which reports all style errors.
618 output_format: A string that is the output format. The supported
619 output formats are "emacs" which emacs can parse
620 and "vs7" which Microsoft Visual Studio 7 can parse.
622 stderr_write: A function that takes a string as a parameter and
623 serves as stderr.write.
626 self._filter_configuration = filter_configuration
627 self._output_format = output_format
629 self.max_reports_per_category = max_reports_per_category
630 self.min_confidence = min_confidence
631 self.stderr_write = stderr_write
633 def is_reportable(self, category, confidence_in_error, file_path):
634 """Return whether an error is reportable.
636 An error is reportable if both the confidence in the error is
637 at least the minimum confidence level and the current filter
638 says the category should be checked for the given path.
641 category: A string that is a style category.
642 confidence_in_error: An integer between 1 and 5 inclusive that is
643 the application's confidence in the error.
644 A higher number means greater confidence.
645 file_path: The path of the file being checked
648 if confidence_in_error < self.min_confidence:
651 return self._filter_configuration.should_check(category, file_path)
653 def write_style_error(self,
659 """Write a style error to the configured stderr."""
660 if self._output_format == 'vs7':
661 format_string = "%s(%s): %s [%s] [%d]\n"
663 format_string = "%s:%s: %s [%s] [%d]\n"
665 self.stderr_write(format_string % (file_path,
669 confidence_in_error))
672 class ProcessorBase(object):
674 """The base class for processors of lists of lines."""
676 def should_process(self, file_path):
677 """Return whether the file at file_path should be processed.
679 The TextFileReader class calls this method prior to reading in
680 the lines of a file. Use this method, for example, to prevent
681 the style checker from reading binary files into memory.
684 raise NotImplementedError('Subclasses should implement.')
686 def process(self, lines, file_path, **kwargs):
687 """Process lines of text read from a file.
690 lines: A list of lines of text to process.
691 file_path: The path from which the lines were read.
692 **kwargs: This argument signifies that the process() method of
693 subclasses of ProcessorBase may support additional
695 For example, a style checker's check() method
696 may support a "reportable_lines" parameter that represents
697 the line numbers of the lines for which style errors
701 raise NotImplementedError('Subclasses should implement.')
704 class StyleProcessor(ProcessorBase):
706 """A ProcessorBase for checking style.
709 error_count: An integer that is the total number of reported
710 errors for the lifetime of this instance.
714 def __init__(self, configuration, mock_dispatcher=None,
715 mock_increment_error_count=None,
716 mock_carriage_checker_class=None):
717 """Create an instance.
720 configuration: A StyleProcessorConfiguration instance.
721 mock_dispatcher: A mock CheckerDispatcher instance. This
722 parameter is for unit testing. Defaults to a
723 CheckerDispatcher instance.
724 mock_increment_error_count: A mock error-count incrementer.
725 mock_carriage_checker_class: A mock class for checking and
726 transforming carriage returns.
727 This parameter is for unit testing.
728 Defaults to CarriageReturnChecker.
731 if mock_dispatcher is None:
732 dispatcher = CheckerDispatcher()
734 dispatcher = mock_dispatcher
736 if mock_increment_error_count is None:
737 # The following blank line is present to avoid flagging by pep8.py.
739 def increment_error_count():
740 """Increment the total count of reported errors."""
741 self.error_count += 1
743 increment_error_count = mock_increment_error_count
745 if mock_carriage_checker_class is None:
746 # This needs to be a class rather than an instance since the
747 # process() method instantiates one using parameters.
748 carriage_checker_class = CarriageReturnChecker
750 carriage_checker_class = mock_carriage_checker_class
754 self._carriage_checker_class = carriage_checker_class
755 self._configuration = configuration
756 self._dispatcher = dispatcher
757 self._increment_error_count = increment_error_count
759 def should_process(self, file_path):
760 """Return whether the file should be checked for style."""
761 if self._dispatcher.should_skip_without_warning(file_path):
763 if self._dispatcher.should_skip_with_warning(file_path):
764 _log.warn('File exempt from style guide. Skipping: "%s"'
769 def process(self, lines, file_path, line_numbers=None):
770 """Check the given lines for style.
773 lines: A list of all lines in the file to check.
774 file_path: The path of the file to process. If possible, the path
775 should be relative to the source root. Otherwise,
776 path-specific logic may not behave as expected.
777 line_numbers: A list of line numbers of the lines for which
778 style errors should be reported, or None if errors
779 for all lines should be reported. When not None, this
780 list normally contains the line numbers corresponding
781 to the modified lines of a patch.
784 _log.debug("Checking style: " + file_path)
786 style_error_handler = DefaultStyleErrorHandler(
787 configuration=self._configuration,
789 increment_error_count=self._increment_error_count,
790 line_numbers=line_numbers)
792 carriage_checker = self._carriage_checker_class(style_error_handler)
794 # Check for and remove trailing carriage returns ("\r").
795 if self._dispatcher.should_check_and_strip_carriage_returns(file_path):
796 lines = carriage_checker.check(lines)
798 min_confidence = self._configuration.min_confidence
799 checker = self._dispatcher.dispatch(file_path,
804 raise AssertionError("File should not be checked: '%s'" % file_path)
806 _log.debug("Using class: " + checker.__class__.__name__)