169 lines
6.8 KiB
Python
169 lines
6.8 KiB
Python
# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
|
|
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
"""Defines style error handler classes.
|
|
|
|
A style error handler is a function to call when a style error is
|
|
found. Style error handlers can also have state. A class that represents
|
|
a style error handler should implement the following methods.
|
|
|
|
Methods:
|
|
|
|
__call__(self, line_number, category, confidence, message):
|
|
|
|
Handle the occurrence of a style error.
|
|
|
|
Check whether the error is reportable. If so, increment the total
|
|
error count and report the details. Note that error reporting can
|
|
be suppressed after reaching a certain number of reports.
|
|
|
|
Args:
|
|
line_number: The integer line number of the line containing the error.
|
|
category: The name of the category of the error, for example
|
|
"whitespace/newline".
|
|
confidence: An integer between 1 and 5 inclusive that represents the
|
|
application's level of confidence in the error. The value
|
|
5 means that we are certain of the problem, and the
|
|
value 1 means that it could be a legitimate construct.
|
|
message: The error message to report.
|
|
|
|
"""
|
|
|
|
|
|
import logging
|
|
import sys
|
|
|
|
|
|
_log = logging.getLogger(__name__)
|
|
|
|
|
|
class DefaultStyleErrorHandler(object):
|
|
|
|
"""The default style error handler."""
|
|
|
|
def __init__(self, file_path, configuration, increment_error_count,
|
|
line_numbers=None):
|
|
"""Create a default style error handler.
|
|
|
|
Args:
|
|
file_path: The path to the file containing the error. This
|
|
is used for reporting to the user.
|
|
configuration: A StyleProcessorConfiguration instance.
|
|
increment_error_count: A function that takes no arguments and
|
|
increments the total count of reportable
|
|
errors.
|
|
line_numbers: An array of line numbers of the lines for which
|
|
style errors should be reported, or None if errors
|
|
for all lines should be reported. When it is not
|
|
None, this array normally contains the line numbers
|
|
corresponding to the modified lines of a patch.
|
|
|
|
"""
|
|
if line_numbers is not None:
|
|
line_numbers = set(line_numbers)
|
|
|
|
self._file_path = file_path
|
|
self._configuration = configuration
|
|
self._increment_error_count = increment_error_count
|
|
self._line_numbers = line_numbers
|
|
|
|
# A string to integer dictionary cache of the number of reportable
|
|
# errors per category passed to this instance.
|
|
self._category_totals = {}
|
|
|
|
# Useful for unit testing.
|
|
def __eq__(self, other):
|
|
"""Return whether this instance is equal to another."""
|
|
if self._configuration != other._configuration:
|
|
return False
|
|
if self._file_path != other._file_path:
|
|
return False
|
|
if self._increment_error_count != other._increment_error_count:
|
|
return False
|
|
if self._line_numbers != other._line_numbers:
|
|
return False
|
|
|
|
return True
|
|
|
|
# Useful for unit testing.
|
|
def __ne__(self, other):
|
|
# Python does not automatically deduce __ne__ from __eq__.
|
|
return not self.__eq__(other)
|
|
|
|
def _add_reportable_error(self, category):
|
|
"""Increment the error count and return the new category total."""
|
|
self._increment_error_count() # Increment the total.
|
|
|
|
# Increment the category total.
|
|
if not category in self._category_totals:
|
|
self._category_totals[category] = 1
|
|
else:
|
|
self._category_totals[category] += 1
|
|
|
|
return self._category_totals[category]
|
|
|
|
def _max_reports(self, category):
|
|
"""Return the maximum number of errors to report."""
|
|
if not category in self._configuration.max_reports_per_category:
|
|
return None
|
|
return self._configuration.max_reports_per_category[category]
|
|
|
|
def should_line_be_checked(self, line_number):
|
|
"Returns if a particular line should be checked"
|
|
# Was the line that was modified?
|
|
return self._line_numbers is None or line_number in self._line_numbers or line_number == 0
|
|
|
|
def turn_off_line_filtering(self):
|
|
self._line_numbers = None
|
|
|
|
def __call__(self, line_number, category, confidence, message):
|
|
"""Handle the occurrence of a style error.
|
|
|
|
See the docstring of this module for more information.
|
|
|
|
"""
|
|
if not self.should_line_be_checked(line_number):
|
|
return False
|
|
|
|
if not self._configuration.is_reportable(category=category,
|
|
confidence_in_error=confidence,
|
|
file_path=self._file_path):
|
|
return False
|
|
|
|
category_total = self._add_reportable_error(category)
|
|
|
|
max_reports = self._max_reports(category)
|
|
|
|
if (max_reports is not None) and (category_total > max_reports):
|
|
# Then suppress displaying the error.
|
|
return False
|
|
|
|
self._configuration.write_style_error(category=category,
|
|
confidence_in_error=confidence,
|
|
file_path=self._file_path,
|
|
line_number=line_number,
|
|
message=message)
|
|
if category_total == max_reports:
|
|
_log.error("Suppressing further [%s] reports "
|
|
"for this file." % category)
|
|
return True
|