| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # | |
| 3 # Copyright 2008 The Closure Linter Authors. All Rights Reserved. | |
| 4 # | |
| 5 # Licensed under the Apache License, Version 2.0 (the "License"); | |
| 6 # you may not use this file except in compliance with the License. | |
| 7 # You may obtain a copy of the License at | |
| 8 # | |
| 9 # http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 # | |
| 11 # Unless required by applicable law or agreed to in writing, software | |
| 12 # distributed under the License is distributed on an "AS-IS" BASIS, | |
| 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 # See the License for the specific language governing permissions and | |
| 15 # limitations under the License. | |
| 16 | |
| 17 """Base classes for writing checkers that operate on tokens.""" | |
| 18 | |
| 19 # Allow non-Google copyright | |
| 20 # pylint: disable=g-bad-file-header | |
| 21 | |
| 22 __author__ = ('robbyw@google.com (Robert Walker)', | |
| 23 'ajp@google.com (Andy Perelson)', | |
| 24 'jacobr@google.com (Jacob Richman)') | |
| 25 | |
| 26 from closure_linter import errorrules | |
| 27 from closure_linter.common import error | |
| 28 | |
| 29 | |
| 30 class LintRulesBase(object): | |
| 31 """Base class for all classes defining the lint rules for a language.""" | |
| 32 | |
| 33 def __init__(self): | |
| 34 self.__checker = None | |
| 35 | |
| 36 def Initialize(self, checker, limited_doc_checks, is_html): | |
| 37 """Initializes to prepare to check a file. | |
| 38 | |
| 39 Args: | |
| 40 checker: Class to report errors to. | |
| 41 limited_doc_checks: Whether doc checking is relaxed for this file. | |
| 42 is_html: Whether the file is an HTML file with extracted contents. | |
| 43 """ | |
| 44 self.__checker = checker | |
| 45 self._limited_doc_checks = limited_doc_checks | |
| 46 self._is_html = is_html | |
| 47 | |
| 48 def _HandleError(self, code, message, token, position=None, | |
| 49 fix_data=None): | |
| 50 """Call the HandleError function for the checker we are associated with.""" | |
| 51 if errorrules.ShouldReportError(code): | |
| 52 self.__checker.HandleError(code, message, token, position, fix_data) | |
| 53 | |
| 54 def _SetLimitedDocChecks(self, limited_doc_checks): | |
| 55 """Sets whether doc checking is relaxed for this file. | |
| 56 | |
| 57 Args: | |
| 58 limited_doc_checks: Whether doc checking is relaxed for this file. | |
| 59 """ | |
| 60 self._limited_doc_checks = limited_doc_checks | |
| 61 | |
| 62 def CheckToken(self, token, parser_state): | |
| 63 """Checks a token, given the current parser_state, for warnings and errors. | |
| 64 | |
| 65 Args: | |
| 66 token: The current token under consideration. | |
| 67 parser_state: Object that indicates the parser state in the page. | |
| 68 | |
| 69 Raises: | |
| 70 TypeError: If not overridden. | |
| 71 """ | |
| 72 raise TypeError('Abstract method CheckToken not implemented') | |
| 73 | |
| 74 def Finalize(self, parser_state): | |
| 75 """Perform all checks that need to occur after all lines are processed. | |
| 76 | |
| 77 Args: | |
| 78 parser_state: State of the parser after parsing all tokens | |
| 79 | |
| 80 Raises: | |
| 81 TypeError: If not overridden. | |
| 82 """ | |
| 83 raise TypeError('Abstract method Finalize not implemented') | |
| 84 | |
| 85 | |
| 86 class CheckerBase(object): | |
| 87 """This class handles checking a LintRules object against a file.""" | |
| 88 | |
| 89 def __init__(self, error_handler, lint_rules, state_tracker): | |
| 90 """Initialize a checker object. | |
| 91 | |
| 92 Args: | |
| 93 error_handler: Object that handles errors. | |
| 94 lint_rules: LintRules object defining lint errors given a token | |
| 95 and state_tracker object. | |
| 96 state_tracker: Object that tracks the current state in the token stream. | |
| 97 | |
| 98 """ | |
| 99 self._error_handler = error_handler | |
| 100 self._lint_rules = lint_rules | |
| 101 self._state_tracker = state_tracker | |
| 102 | |
| 103 self._has_errors = False | |
| 104 | |
| 105 def HandleError(self, code, message, token, position=None, | |
| 106 fix_data=None): | |
| 107 """Prints out the given error message including a line number. | |
| 108 | |
| 109 Args: | |
| 110 code: The error code. | |
| 111 message: The error to print. | |
| 112 token: The token where the error occurred, or None if it was a file-wide | |
| 113 issue. | |
| 114 position: The position of the error, defaults to None. | |
| 115 fix_data: Metadata used for fixing the error. | |
| 116 """ | |
| 117 self._has_errors = True | |
| 118 self._error_handler.HandleError( | |
| 119 error.Error(code, message, token, position, fix_data)) | |
| 120 | |
| 121 def HasErrors(self): | |
| 122 """Returns true if the style checker has found any errors. | |
| 123 | |
| 124 Returns: | |
| 125 True if the style checker has found any errors. | |
| 126 """ | |
| 127 return self._has_errors | |
| 128 | |
| 129 def Check(self, start_token, limited_doc_checks=False, is_html=False, | |
| 130 stop_token=None): | |
| 131 """Checks a token stream, reporting errors to the error reporter. | |
| 132 | |
| 133 Args: | |
| 134 start_token: First token in token stream. | |
| 135 limited_doc_checks: Whether doc checking is relaxed for this file. | |
| 136 is_html: Whether the file being checked is an HTML file with extracted | |
| 137 contents. | |
| 138 stop_token: If given, check should stop at this token. | |
| 139 """ | |
| 140 | |
| 141 self._lint_rules.Initialize(self, limited_doc_checks, is_html) | |
| 142 self._ExecutePass(start_token, self._LintPass, stop_token=stop_token) | |
| 143 self._lint_rules.Finalize(self._state_tracker) | |
| 144 | |
| 145 def _LintPass(self, token): | |
| 146 """Checks an individual token for lint warnings/errors. | |
| 147 | |
| 148 Used to encapsulate the logic needed to check an individual token so that it | |
| 149 can be passed to _ExecutePass. | |
| 150 | |
| 151 Args: | |
| 152 token: The token to check. | |
| 153 """ | |
| 154 self._lint_rules.CheckToken(token, self._state_tracker) | |
| 155 | |
| 156 def _ExecutePass(self, token, pass_function, stop_token=None): | |
| 157 """Calls the given function for every token in the given token stream. | |
| 158 | |
| 159 As each token is passed to the given function, state is kept up to date and, | |
| 160 depending on the error_trace flag, errors are either caught and reported, or | |
| 161 allowed to bubble up so developers can see the full stack trace. If a parse | |
| 162 error is specified, the pass will proceed as normal until the token causing | |
| 163 the parse error is reached. | |
| 164 | |
| 165 Args: | |
| 166 token: The first token in the token stream. | |
| 167 pass_function: The function to call for each token in the token stream. | |
| 168 stop_token: The last token to check (if given). | |
| 169 | |
| 170 Raises: | |
| 171 Exception: If any error occurred while calling the given function. | |
| 172 """ | |
| 173 | |
| 174 self._state_tracker.Reset() | |
| 175 while token: | |
| 176 # When we are looking at a token and decided to delete the whole line, we | |
| 177 # will delete all of them in the "HandleToken()" below. So the current | |
| 178 # token and subsequent ones may already be deleted here. The way we | |
| 179 # delete a token does not wipe out the previous and next pointers of the | |
| 180 # deleted token. So we need to check the token itself to make sure it is | |
| 181 # not deleted. | |
| 182 if not token.is_deleted: | |
| 183 # End the pass at the stop token | |
| 184 if stop_token and token is stop_token: | |
| 185 return | |
| 186 | |
| 187 self._state_tracker.HandleToken( | |
| 188 token, self._state_tracker.GetLastNonSpaceToken()) | |
| 189 pass_function(token) | |
| 190 self._state_tracker.HandleAfterToken(token) | |
| 191 | |
| 192 token = token.next | |
| OLD | NEW |