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 |