WebKitTools/Scripts/webkitpy/style/error_handlers.py
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
       
     2 #
       
     3 # Redistribution and use in source and binary forms, with or without
       
     4 # modification, are permitted provided that the following conditions
       
     5 # are met:
       
     6 # 1.  Redistributions of source code must retain the above copyright
       
     7 #     notice, this list of conditions and the following disclaimer.
       
     8 # 2.  Redistributions in binary form must reproduce the above copyright
       
     9 #     notice, this list of conditions and the following disclaimer in the
       
    10 #     documentation and/or other materials provided with the distribution.
       
    11 #
       
    12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
       
    13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    16 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    17 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    18 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
       
    19 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    20 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    21 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    22 
       
    23 """Defines style error handler classes.
       
    24 
       
    25 A style error handler is a function to call when a style error is
       
    26 found. Style error handlers can also have state. A class that represents
       
    27 a style error handler should implement the following methods.
       
    28 
       
    29 Methods:
       
    30 
       
    31   __call__(self, line_number, category, confidence, message):
       
    32 
       
    33     Handle the occurrence of a style error.
       
    34 
       
    35     Check whether the error is reportable. If so, increment the total
       
    36     error count and report the details. Note that error reporting can
       
    37     be suppressed after reaching a certain number of reports.
       
    38 
       
    39     Args:
       
    40       line_number: The integer line number of the line containing the error.
       
    41       category: The name of the category of the error, for example
       
    42                 "whitespace/newline".
       
    43       confidence: An integer between 1 and 5 inclusive that represents the
       
    44                   application's level of confidence in the error. The value
       
    45                   5 means that we are certain of the problem, and the
       
    46                   value 1 means that it could be a legitimate construct.
       
    47       message: The error message to report.
       
    48 
       
    49 """
       
    50 
       
    51 
       
    52 import sys
       
    53 
       
    54 
       
    55 class DefaultStyleErrorHandler(object):
       
    56 
       
    57     """The default style error handler."""
       
    58 
       
    59     def __init__(self, file_path, configuration, increment_error_count,
       
    60                  line_numbers=None):
       
    61         """Create a default style error handler.
       
    62 
       
    63         Args:
       
    64           file_path: The path to the file containing the error. This
       
    65                      is used for reporting to the user.
       
    66           configuration: A StyleProcessorConfiguration instance.
       
    67           increment_error_count: A function that takes no arguments and
       
    68                                  increments the total count of reportable
       
    69                                  errors.
       
    70           line_numbers: An array of line numbers of the lines for which
       
    71                         style errors should be reported, or None if errors
       
    72                         for all lines should be reported.  When it is not
       
    73                         None, this array normally contains the line numbers
       
    74                         corresponding to the modified lines of a patch.
       
    75 
       
    76         """
       
    77         if line_numbers is not None:
       
    78             line_numbers = set(line_numbers)
       
    79 
       
    80         self._file_path = file_path
       
    81         self._configuration = configuration
       
    82         self._increment_error_count = increment_error_count
       
    83         self._line_numbers = line_numbers
       
    84 
       
    85         # A string to integer dictionary cache of the number of reportable
       
    86         # errors per category passed to this instance.
       
    87         self._category_totals = {}
       
    88 
       
    89     # Useful for unit testing.
       
    90     def __eq__(self, other):
       
    91         """Return whether this instance is equal to another."""
       
    92         if self._configuration != other._configuration:
       
    93             return False
       
    94         if self._file_path != other._file_path:
       
    95             return False
       
    96         if self._increment_error_count != other._increment_error_count:
       
    97             return False
       
    98         if self._line_numbers != other._line_numbers:
       
    99             return False
       
   100 
       
   101         return True
       
   102 
       
   103     # Useful for unit testing.
       
   104     def __ne__(self, other):
       
   105         # Python does not automatically deduce __ne__ from __eq__.
       
   106         return not self.__eq__(other)
       
   107 
       
   108     def _add_reportable_error(self, category):
       
   109         """Increment the error count and return the new category total."""
       
   110         self._increment_error_count() # Increment the total.
       
   111 
       
   112         # Increment the category total.
       
   113         if not category in self._category_totals:
       
   114             self._category_totals[category] = 1
       
   115         else:
       
   116             self._category_totals[category] += 1
       
   117 
       
   118         return self._category_totals[category]
       
   119 
       
   120     def _max_reports(self, category):
       
   121         """Return the maximum number of errors to report."""
       
   122         if not category in self._configuration.max_reports_per_category:
       
   123             return None
       
   124         return self._configuration.max_reports_per_category[category]
       
   125 
       
   126     def __call__(self, line_number, category, confidence, message):
       
   127         """Handle the occurrence of a style error.
       
   128 
       
   129         See the docstring of this module for more information.
       
   130 
       
   131         """
       
   132         if (self._line_numbers is not None and
       
   133             line_number not in self._line_numbers):
       
   134             # Then the error occurred in a line that was not modified, so
       
   135             # the error is not reportable.
       
   136             return
       
   137 
       
   138         if not self._configuration.is_reportable(category=category,
       
   139                                                  confidence_in_error=confidence,
       
   140                                                  file_path=self._file_path):
       
   141             return
       
   142 
       
   143         category_total = self._add_reportable_error(category)
       
   144 
       
   145         max_reports = self._max_reports(category)
       
   146 
       
   147         if (max_reports is not None) and (category_total > max_reports):
       
   148             # Then suppress displaying the error.
       
   149             return
       
   150 
       
   151         self._configuration.write_style_error(category=category,
       
   152                                               confidence_in_error=confidence,
       
   153                                               file_path=self._file_path,
       
   154                                               line_number=line_number,
       
   155                                               message=message)
       
   156 
       
   157         if category_total == max_reports:
       
   158             self._configuration.stderr_write("Suppressing further [%s] reports "
       
   159                                              "for this file.\n" % category)