WebKitTools/Scripts/webkitpy/style/error_handlers.py
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebKitTools/Scripts/webkitpy/style/error_handlers.py	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,159 @@
+# 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 sys
+
+
+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 __call__(self, line_number, category, confidence, message):
+        """Handle the occurrence of a style error.
+
+        See the docstring of this module for more information.
+
+        """
+        if (self._line_numbers is not None and
+            line_number not in self._line_numbers):
+            # Then the error occurred in a line that was not modified, so
+            # the error is not reportable.
+            return
+
+        if not self._configuration.is_reportable(category=category,
+                                                 confidence_in_error=confidence,
+                                                 file_path=self._file_path):
+            return
+
+        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
+
+        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:
+            self._configuration.stderr_write("Suppressing further [%s] reports "
+                                             "for this file.\n" % category)