aboutsummaryrefslogtreecommitdiff
path: root/tools/closure_linter-2.3.4/closure_linter/checkerbase.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/closure_linter-2.3.4/closure_linter/checkerbase.py')
-rwxr-xr-xtools/closure_linter-2.3.4/closure_linter/checkerbase.py308
1 files changed, 308 insertions, 0 deletions
diff --git a/tools/closure_linter-2.3.4/closure_linter/checkerbase.py b/tools/closure_linter-2.3.4/closure_linter/checkerbase.py
new file mode 100755
index 0000000..592454d
--- /dev/null
+++ b/tools/closure_linter-2.3.4/closure_linter/checkerbase.py
@@ -0,0 +1,308 @@
+#!/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.
+
+"""Base classes for writing checkers that operate on tokens."""
+
+__author__ = ('robbyw@google.com (Robert Walker)',
+ 'ajp@google.com (Andy Perelson)',
+ 'jacobr@google.com (Jacob Richman)')
+
+import StringIO
+import traceback
+
+import gflags as flags
+from closure_linter import ecmametadatapass
+from closure_linter import errorrules
+from closure_linter import errors
+from closure_linter import javascripttokenizer
+from closure_linter.common import error
+from closure_linter.common import htmlutil
+
+FLAGS = flags.FLAGS
+flags.DEFINE_boolean('debug_tokens', False,
+ 'Whether to print all tokens for debugging.')
+
+flags.DEFINE_boolean('error_trace', False,
+ 'Whether to show error exceptions.')
+
+
+class LintRulesBase(object):
+ """Base class for all classes defining the lint rules for a language."""
+
+ def __init__(self):
+ self.__checker = None
+
+ def Initialize(self, checker, limited_doc_checks, is_html):
+ """Initializes to prepare to check a file.
+
+ Args:
+ checker: Class to report errors to.
+ limited_doc_checks: Whether doc checking is relaxed for this file.
+ is_html: Whether the file is an HTML file with extracted contents.
+ """
+ self.__checker = checker
+ self._limited_doc_checks = limited_doc_checks
+ self._is_html = is_html
+
+ def _HandleError(self, code, message, token, position=None,
+ fix_data=None):
+ """Call the HandleError function for the checker we are associated with."""
+ if errorrules.ShouldReportError(code):
+ self.__checker.HandleError(code, message, token, position, fix_data)
+
+ def _SetLimitedDocChecks(self, limited_doc_checks):
+ """Sets whether doc checking is relaxed for this file.
+
+ Args:
+ limited_doc_checks: Whether doc checking is relaxed for this file.
+ """
+ self._limited_doc_checks = limited_doc_checks
+
+ def CheckToken(self, token, parser_state):
+ """Checks a token, given the current parser_state, for warnings and errors.
+
+ Args:
+ token: The current token under consideration.
+ parser_state: Object that indicates the parser state in the page.
+
+ Raises:
+ TypeError: If not overridden.
+ """
+ raise TypeError('Abstract method CheckToken not implemented')
+
+ def Finalize(self, parser_state, tokenizer_mode):
+ """Perform all checks that need to occur after all lines are processed.
+
+ Args:
+ parser_state: State of the parser after parsing all tokens
+ tokenizer_mode: Mode of the tokenizer after parsing the entire page
+
+ Raises:
+ TypeError: If not overridden.
+ """
+ raise TypeError('Abstract method Finalize not implemented')
+
+
+class CheckerBase(object):
+ """This class handles checking a LintRules object against a file."""
+
+ def __init__(self, error_handler, lint_rules, state_tracker,
+ limited_doc_files=None, metadata_pass=None):
+ """Initialize a checker object.
+
+ Args:
+ error_handler: Object that handles errors.
+ lint_rules: LintRules object defining lint errors given a token
+ and state_tracker object.
+ state_tracker: Object that tracks the current state in the token stream.
+ limited_doc_files: List of filenames that are not required to have
+ documentation comments.
+ metadata_pass: Object that builds metadata about the token stream.
+ """
+ self._error_handler = error_handler
+ self._lint_rules = lint_rules
+ self._state_tracker = state_tracker
+ self._metadata_pass = metadata_pass
+ self._limited_doc_files = limited_doc_files
+ self._tokenizer = javascripttokenizer.JavaScriptTokenizer()
+ self._has_errors = False
+
+ def HandleError(self, code, message, token, position=None,
+ fix_data=None):
+ """Prints out the given error message including a line number.
+
+ Args:
+ code: The error code.
+ message: The error to print.
+ token: The token where the error occurred, or None if it was a file-wide
+ issue.
+ position: The position of the error, defaults to None.
+ fix_data: Metadata used for fixing the error.
+ """
+ self._has_errors = True
+ self._error_handler.HandleError(
+ error.Error(code, message, token, position, fix_data))
+
+ def HasErrors(self):
+ """Returns true if the style checker has found any errors.
+
+ Returns:
+ True if the style checker has found any errors.
+ """
+ return self._has_errors
+
+ def Check(self, filename, source=None):
+ """Checks the file, printing warnings and errors as they are found.
+
+ Args:
+ filename: The name of the file to check.
+ source: Optional. The contents of the file. Can be either a string or
+ file-like object. If omitted, contents will be read from disk from
+ the given filename.
+ """
+
+ if source is None:
+ try:
+ f = open(filename)
+ except IOError:
+ self._error_handler.HandleFile(filename, None)
+ self.HandleError(errors.FILE_NOT_FOUND, 'File not found', None)
+ self._error_handler.FinishFile()
+ return
+ else:
+ if type(source) in [str, unicode]:
+ f = StringIO.StringIO(source)
+ else:
+ f = source
+
+ try:
+ if filename.endswith('.html') or filename.endswith('.htm'):
+ self.CheckLines(filename, htmlutil.GetScriptLines(f), True)
+ else:
+ self.CheckLines(filename, f, False)
+ finally:
+ f.close()
+
+ def CheckLines(self, filename, lines_iter, is_html):
+ """Checks a file, given as an iterable of lines, for warnings and errors.
+
+ Args:
+ filename: The name of the file to check.
+ lines_iter: An iterator that yields one line of the file at a time.
+ is_html: Whether the file being checked is an HTML file with extracted
+ contents.
+
+ Returns:
+ A boolean indicating whether the full file could be checked or if checking
+ failed prematurely.
+ """
+ limited_doc_checks = False
+ if self._limited_doc_files:
+ for limited_doc_filename in self._limited_doc_files:
+ if filename.endswith(limited_doc_filename):
+ limited_doc_checks = True
+ break
+
+ lint_rules = self._lint_rules
+ lint_rules.Initialize(self, limited_doc_checks, is_html)
+
+ token = self._tokenizer.TokenizeFile(lines_iter)
+
+ parse_error = None
+ if self._metadata_pass:
+ try:
+ self._metadata_pass.Reset()
+ self._metadata_pass.Process(token)
+ except ecmametadatapass.ParseError, caught_parse_error:
+ if FLAGS.error_trace:
+ traceback.print_exc()
+ parse_error = caught_parse_error
+ except Exception:
+ print 'Internal error in %s' % filename
+ traceback.print_exc()
+ return False
+
+ self._error_handler.HandleFile(filename, token)
+
+ return self._CheckTokens(token, parse_error=parse_error,
+ debug_tokens=FLAGS.debug_tokens)
+
+ def _CheckTokens(self, token, parse_error, debug_tokens):
+ """Checks a token stream for lint warnings/errors.
+
+ Args:
+ token: The first token in the token stream to check.
+ parse_error: A ParseError if any errors occurred.
+ debug_tokens: Whether every token should be printed as it is encountered
+ during the pass.
+
+ Returns:
+ A boolean indicating whether the full token stream could be checked or if
+ checking failed prematurely.
+ """
+ result = self._ExecutePass(token, self._LintPass, parse_error, debug_tokens)
+
+ if not result:
+ return False
+
+ self._lint_rules.Finalize(self._state_tracker, self._tokenizer.mode)
+ self._error_handler.FinishFile()
+ return True
+
+ def _LintPass(self, token):
+ """Checks an individual token for lint warnings/errors.
+
+ Used to encapsulate the logic needed to check an individual token so that it
+ can be passed to _ExecutePass.
+
+ Args:
+ token: The token to check.
+ """
+ self._lint_rules.CheckToken(token, self._state_tracker)
+
+ def _ExecutePass(self, token, pass_function, parse_error=None,
+ debug_tokens=False):
+ """Calls the given function for every token in the given token stream.
+
+ As each token is passed to the given function, state is kept up to date and,
+ depending on the error_trace flag, errors are either caught and reported, or
+ allowed to bubble up so developers can see the full stack trace. If a parse
+ error is specified, the pass will proceed as normal until the token causing
+ the parse error is reached.
+
+ Args:
+ token: The first token in the token stream.
+ pass_function: The function to call for each token in the token stream.
+ parse_error: A ParseError if any errors occurred.
+ debug_tokens: Whether every token should be printed as it is encountered
+ during the pass.
+
+ Returns:
+ A boolean indicating whether the full token stream could be checked or if
+ checking failed prematurely.
+
+ Raises:
+ Exception: If any error occurred while calling the given function.
+ """
+ self._state_tracker.Reset()
+ while token:
+ if debug_tokens:
+ print token
+
+ if parse_error and parse_error.token == token:
+ message = ('Error parsing file at token "%s". Unable to '
+ 'check the rest of file.' % token.string)
+ self.HandleError(errors.FILE_DOES_NOT_PARSE, message, token)
+ self._error_handler.FinishFile()
+ return
+
+ try:
+ self._state_tracker.HandleToken(
+ token, self._state_tracker.GetLastNonSpaceToken())
+ pass_function(token)
+ self._state_tracker.HandleAfterToken(token)
+ except:
+ if FLAGS.error_trace:
+ raise
+ else:
+ self.HandleError(errors.FILE_DOES_NOT_PARSE,
+ ('Error parsing file at token "%s". Unable to '
+ 'check the rest of file.' % token.string),
+ token)
+ self._error_handler.FinishFile()
+ return False
+ token = token.next
+ return True