aboutsummaryrefslogtreecommitdiff
path: root/tools/closure_linter-2.3.4/closure_linter/common/errorprinter.py
blob: c9754068f1f542726b51cf1bfd67b812a14ac380 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/usr/bin/env python
#
# Copyright 2008 The Closure Linter Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Linter error handler class that prints errors to stdout."""

__author__ = ('robbyw@google.com (Robert Walker)',
              'ajp@google.com (Andy Perelson)')

from closure_linter.common import error
from closure_linter.common import errorhandler

Error = error.Error


# The error message is of the format:
# Line <number>, E:<code>: message
DEFAULT_FORMAT = 1

# The error message is of the format:
# filename:[line number]:message
UNIX_FORMAT = 2


class ErrorPrinter(errorhandler.ErrorHandler):
  """ErrorHandler that prints errors to stdout."""

  def __init__(self, new_errors=None):
    """Initializes this error printer.

    Args:
      new_errors: A sequence of error codes representing recently introduced
        errors, defaults to None.
    """
    # Number of errors
    self._error_count = 0

    # Number of new errors
    self._new_error_count = 0

    # Number of files checked
    self._total_file_count = 0

    # Number of files with errors
    self._error_file_count = 0

    # Dict of file name to number of errors
    self._file_table = {}

    # List of errors for each file
    self._file_errors = None

    # Current file
    self._filename = None

    self._format = DEFAULT_FORMAT

    if new_errors:
      self._new_errors = frozenset(new_errors)
    else:
      self._new_errors = frozenset(set())

  def SetFormat(self, format):
    """Sets the print format of errors.

    Args:
      format: One of {DEFAULT_FORMAT, UNIX_FORMAT}.
    """
    self._format = format

  def HandleFile(self, filename, first_token):
    """Notifies this ErrorPrinter that subsequent errors are in filename.

    Sets the current file name, and sets a flag stating the header for this file
    has not been printed yet.

    Should be called by a linter before a file is style checked.

    Args:
      filename: The name of the file about to be checked.
      first_token: The first token in the file, or None if there was an error
          opening the file
    """
    if self._filename and self._file_table[self._filename]:
      print

    self._filename = filename
    self._file_table[filename] = 0
    self._total_file_count += 1
    self._file_errors = []

  def HandleError(self, error):
    """Prints a formatted error message about the specified error.

    The error message is of the format:
    Error #<code>, line #<number>: message

    Args:
      error: The error object
    """
    self._file_errors.append(error)
    self._file_table[self._filename] += 1
    self._error_count += 1

    if self._new_errors and error.code in self._new_errors:
      self._new_error_count += 1

  def _PrintError(self, error):
    """Prints a formatted error message about the specified error.

    Args:
      error: The error object
    """
    new_error = self._new_errors and error.code in self._new_errors
    if self._format == DEFAULT_FORMAT:
      line = ''
      if error.token:
        line = 'Line %d, ' % error.token.line_number

      code = 'E:%04d' % error.code
      if new_error:
        print '%s%s: (New error) %s' % (line, code, error.message)
      else:
        print '%s%s: %s' % (line, code, error.message)
    else:
      # UNIX format
      filename = self._filename
      line = ''
      if error.token:
        line = '%d' % error.token.line_number

      error_code = '%04d' % error.code
      if new_error:
        error_code = 'New Error ' + error_code
      print '%s:%s:(%s) %s' % (filename, line, error_code, error.message)

  def FinishFile(self):
    """Finishes handling the current file."""
    if self._file_errors:
      self._error_file_count += 1

      if self._format != UNIX_FORMAT:
        print '----- FILE  :  %s -----' % (self._filename)

      self._file_errors.sort(Error.Compare)

      for error in self._file_errors:
        self._PrintError(error)

  def HasErrors(self):
    """Whether this error printer encountered any errors.

    Returns:
        True if the error printer encountered any errors.
    """
    return self._error_count

  def HasNewErrors(self):
    """Whether this error printer encountered any new errors.

    Returns:
        True if the error printer encountered any new errors.
    """
    return self._new_error_count

  def HasOldErrors(self):
    """Whether this error printer encountered any old errors.

    Returns:
        True if the error printer encountered any old errors.
    """
    return self._error_count - self._new_error_count

  def PrintSummary(self):
    """Print a summary of the number of errors and files."""
    if self.HasErrors() or self.HasNewErrors():
      print ('Found %d errors, including %d new errors, in %d files '
             '(%d files OK).' % (
                 self._error_count,
                 self._new_error_count,
                 self._error_file_count,
                 self._total_file_count - self._error_file_count))
    else:
      print '%d files checked, no errors found.' % self._total_file_count

  def PrintFileSummary(self):
    """Print a detailed summary of the number of errors in each file."""
    keys = self._file_table.keys()
    keys.sort()
    for filename in keys:
      print '%s: %d' % (filename, self._file_table[filename])