Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: third_party/closure_linter/closure_linter/ecmalintrules.py

Issue 2328693002: Updated linter with upstream release (2.3.19) (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2008 The Closure Linter Authors. All Rights Reserved. 3 # Copyright 2008 The Closure Linter Authors. All Rights Reserved.
4 # 4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with 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 7 # You may obtain a copy of the License at
8 # 8 #
9 # http://www.apache.org/licenses/LICENSE-2.0 9 # http://www.apache.org/licenses/LICENSE-2.0
10 # 10 #
(...skipping 23 matching lines...) Expand all
34 from closure_linter import javascripttokenizer 34 from closure_linter import javascripttokenizer
35 from closure_linter import javascripttokens 35 from closure_linter import javascripttokens
36 from closure_linter import statetracker 36 from closure_linter import statetracker
37 from closure_linter import tokenutil 37 from closure_linter import tokenutil
38 from closure_linter.common import error 38 from closure_linter.common import error
39 from closure_linter.common import position 39 from closure_linter.common import position
40 40
41 41
42 FLAGS = flags.FLAGS 42 FLAGS = flags.FLAGS
43 flags.DEFINE_list('custom_jsdoc_tags', '', 'Extra jsdoc tags to allow') 43 flags.DEFINE_list('custom_jsdoc_tags', '', 'Extra jsdoc tags to allow')
44 # TODO(user): When flipping this to True, remove logic from unit tests
45 # that overrides this flag.
46 flags.DEFINE_boolean('dot_on_next_line', False, 'Require dots to be'
47 'placed on the next line for wrapped expressions')
48
49 flags.DEFINE_boolean('check_trailing_comma', False, 'Check trailing commas'
50 ' (ES3, not needed from ES5 onwards)')
44 51
45 # TODO(robbyw): Check for extra parens on return statements 52 # TODO(robbyw): Check for extra parens on return statements
46 # TODO(robbyw): Check for 0px in strings 53 # TODO(robbyw): Check for 0px in strings
47 # TODO(robbyw): Ensure inline jsDoc is in {} 54 # TODO(robbyw): Ensure inline jsDoc is in {}
48 # TODO(robbyw): Check for valid JS types in parameter docs 55 # TODO(robbyw): Check for valid JS types in parameter docs
49 56
50 # Shorthand 57 # Shorthand
51 Context = ecmametadatapass.EcmaContext 58 Context = ecmametadatapass.EcmaContext
52 Error = error.Error 59 Error = error.Error
53 Modes = javascripttokenizer.JavaScriptModes 60 Modes = javascripttokenizer.JavaScriptModes
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 92
86 # Regex for form of author lines after the @author tag. 93 # Regex for form of author lines after the @author tag.
87 AUTHOR_SPEC = re.compile(r'(\s*)[^\s]+@[^(\s]+(\s*)\(.+\)') 94 AUTHOR_SPEC = re.compile(r'(\s*)[^\s]+@[^(\s]+(\s*)\(.+\)')
88 95
89 # Acceptable tokens to remove for line too long testing. 96 # Acceptable tokens to remove for line too long testing.
90 LONG_LINE_IGNORE = frozenset( 97 LONG_LINE_IGNORE = frozenset(
91 ['*', '//', '@see'] + 98 ['*', '//', '@see'] +
92 ['@%s' % tag for tag in statetracker.DocFlag.HAS_TYPE]) 99 ['@%s' % tag for tag in statetracker.DocFlag.HAS_TYPE])
93 100
94 JSDOC_FLAGS_DESCRIPTION_NOT_REQUIRED = frozenset([ 101 JSDOC_FLAGS_DESCRIPTION_NOT_REQUIRED = frozenset([
95 '@param', '@return', '@returns']) 102 '@fileoverview', '@param', '@return', '@returns'])
96 103
97 def __init__(self): 104 def __init__(self):
98 """Initialize this lint rule object.""" 105 """Initialize this lint rule object."""
99 checkerbase.LintRulesBase.__init__(self) 106 checkerbase.LintRulesBase.__init__(self)
100 if EcmaScriptLintRules.max_line_length == -1: 107 if EcmaScriptLintRules.max_line_length == -1:
101 EcmaScriptLintRules.max_line_length = errorrules.GetMaxLineLength() 108 EcmaScriptLintRules.max_line_length = errorrules.GetMaxLineLength()
102 109
103 def Initialize(self, checker, limited_doc_checks, is_html): 110 def Initialize(self, checker, limited_doc_checks, is_html):
104 """Initialize this lint rule object before parsing a new file.""" 111 """Initialize this lint rule object before parsing a new file."""
105 checkerbase.LintRulesBase.Initialize(self, checker, limited_doc_checks, 112 checkerbase.LintRulesBase.Initialize(self, checker, limited_doc_checks,
(...skipping 15 matching lines...) Expand all
121 # and DOC_FLAG tokens. 128 # and DOC_FLAG tokens.
122 line_number = last_token.line_number 129 line_number = last_token.line_number
123 token = last_token 130 token = last_token
124 131
125 # Build a representation of the string where spaces indicate potential 132 # Build a representation of the string where spaces indicate potential
126 # line-break locations. 133 # line-break locations.
127 line = [] 134 line = []
128 while token and token.line_number == line_number: 135 while token and token.line_number == line_number:
129 if state.IsTypeToken(token): 136 if state.IsTypeToken(token):
130 line.insert(0, 'x' * len(token.string)) 137 line.insert(0, 'x' * len(token.string))
131 elif token.type in (Type.IDENTIFIER, Type.NORMAL): 138 elif token.type in (Type.IDENTIFIER, Type.OPERATOR):
132 # Dots are acceptable places to wrap. 139 # Dots are acceptable places to wrap (may be tokenized as identifiers).
133 line.insert(0, token.string.replace('.', ' ')) 140 line.insert(0, token.string.replace('.', ' '))
134 else: 141 else:
135 line.insert(0, token.string) 142 line.insert(0, token.string)
136 token = token.previous 143 token = token.previous
137 144
138 line = ''.join(line) 145 line = ''.join(line)
139 line = line.rstrip('\n\r\f') 146 line = line.rstrip('\n\r\f')
140 try: 147 try:
141 length = len(unicode(line, 'utf-8')) 148 length = len(unicode(line, 'utf-8'))
142 except (LookupError, UnicodeDecodeError): 149 except (LookupError, UnicodeDecodeError):
(...skipping 22 matching lines...) Expand all
165 172
166 # Custom tags like @requires may have url like descriptions, so ignore 173 # Custom tags like @requires may have url like descriptions, so ignore
167 # the tag, similar to how we handle @see. 174 # the tag, similar to how we handle @see.
168 custom_tags = set(['@%s' % f for f in FLAGS.custom_jsdoc_tags]) 175 custom_tags = set(['@%s' % f for f in FLAGS.custom_jsdoc_tags])
169 if (len(parts.difference(self.LONG_LINE_IGNORE | custom_tags)) 176 if (len(parts.difference(self.LONG_LINE_IGNORE | custom_tags))
170 > max_parts): 177 > max_parts):
171 self._HandleError( 178 self._HandleError(
172 errors.LINE_TOO_LONG, 179 errors.LINE_TOO_LONG,
173 'Line too long (%d characters).' % len(line), last_token) 180 'Line too long (%d characters).' % len(line), last_token)
174 181
175 def _CheckJsDocType(self, token): 182 def _CheckJsDocType(self, token, js_type):
176 """Checks the given type for style errors. 183 """Checks the given type for style errors.
177 184
178 Args: 185 Args:
179 token: The DOC_FLAG token for the flag whose type to check. 186 token: The DOC_FLAG token for the flag whose type to check.
187 js_type: The flag's typeannotation.TypeAnnotation instance.
180 """ 188 """
181 flag = token.attached_object 189 if not js_type: return
182 flag_type = flag.type
183 if flag_type and flag_type is not None and not flag_type.isspace():
184 pieces = self.TYPE_SPLIT.split(flag_type)
185 if len(pieces) == 1 and flag_type.count('|') == 1 and (
186 flag_type.endswith('|null') or flag_type.startswith('null|')):
187 self._HandleError(
188 errors.JSDOC_PREFER_QUESTION_TO_PIPE_NULL,
189 'Prefer "?Type" to "Type|null": "%s"' % flag_type, token)
190 190
191 # TODO(user): We should do actual parsing of JsDoc types to report an 191 if js_type.type_group and len(js_type.sub_types) == 2:
192 # error for wrong usage of '?' and '|' e.g. {?number|string|null} etc. 192 identifiers = [t.identifier for t in js_type.sub_types]
193 if 'null' in identifiers:
194 # Don't warn if the identifier is a template type (e.g. {TYPE|null}.
195 if not identifiers[0].isupper() and not identifiers[1].isupper():
196 self._HandleError(
197 errors.JSDOC_PREFER_QUESTION_TO_PIPE_NULL,
198 'Prefer "?Type" to "Type|null": "%s"' % js_type, token)
193 199
194 if error_check.ShouldCheck(Rule.BRACES_AROUND_TYPE) and ( 200 # TODO(user): We should report an error for wrong usage of '?' and '|'
195 flag.type_start_token.type != Type.DOC_START_BRACE or 201 # e.g. {?number|string|null} etc.
196 flag.type_end_token.type != Type.DOC_END_BRACE): 202
197 self._HandleError( 203 for sub_type in js_type.IterTypes():
198 errors.MISSING_BRACES_AROUND_TYPE, 204 self._CheckJsDocType(token, sub_type)
199 'Type must always be surrounded by curly braces.', token)
200 205
201 def _CheckForMissingSpaceBeforeToken(self, token): 206 def _CheckForMissingSpaceBeforeToken(self, token):
202 """Checks for a missing space at the beginning of a token. 207 """Checks for a missing space at the beginning of a token.
203 208
204 Reports a MISSING_SPACE error if the token does not begin with a space or 209 Reports a MISSING_SPACE error if the token does not begin with a space or
205 the previous token doesn't end with a space and the previous token is on the 210 the previous token doesn't end with a space and the previous token is on the
206 same line as the token. 211 same line as the token.
207 212
208 Args: 213 Args:
209 token: The token being checked 214 token: The token being checked
(...skipping 11 matching lines...) Expand all
221 def _CheckOperator(self, token): 226 def _CheckOperator(self, token):
222 """Checks an operator for spacing and line style. 227 """Checks an operator for spacing and line style.
223 228
224 Args: 229 Args:
225 token: The operator token. 230 token: The operator token.
226 """ 231 """
227 last_code = token.metadata.last_code 232 last_code = token.metadata.last_code
228 233
229 if not self._ExpectSpaceBeforeOperator(token): 234 if not self._ExpectSpaceBeforeOperator(token):
230 if (token.previous and token.previous.type == Type.WHITESPACE and 235 if (token.previous and token.previous.type == Type.WHITESPACE and
231 last_code and last_code.type in (Type.NORMAL, Type.IDENTIFIER)): 236 last_code and last_code.type in (Type.NORMAL, Type.IDENTIFIER) and
237 last_code.line_number == token.line_number):
232 self._HandleError( 238 self._HandleError(
233 errors.EXTRA_SPACE, 'Extra space before "%s"' % token.string, 239 errors.EXTRA_SPACE, 'Extra space before "%s"' % token.string,
234 token.previous, position=Position.All(token.previous.string)) 240 token.previous, position=Position.All(token.previous.string))
235 241
236 elif (token.previous and 242 elif (token.previous and
237 not token.previous.IsComment() and 243 not token.previous.IsComment() and
244 not tokenutil.IsDot(token) and
238 token.previous.type in Type.EXPRESSION_ENDER_TYPES): 245 token.previous.type in Type.EXPRESSION_ENDER_TYPES):
239 self._HandleError(errors.MISSING_SPACE, 246 self._HandleError(errors.MISSING_SPACE,
240 'Missing space before "%s"' % token.string, token, 247 'Missing space before "%s"' % token.string, token,
241 position=Position.AtBeginning()) 248 position=Position.AtBeginning())
242 249
243 # Check that binary operators are not used to start lines. 250 # Check wrapping of operators.
244 if ((not last_code or last_code.line_number != token.line_number) and 251 next_code = tokenutil.GetNextCodeToken(token)
252
253 is_dot = tokenutil.IsDot(token)
254 wrapped_before = last_code and last_code.line_number != token.line_number
255 wrapped_after = next_code and next_code.line_number != token.line_number
256
257 if FLAGS.dot_on_next_line and is_dot and wrapped_after:
258 self._HandleError(
259 errors.LINE_ENDS_WITH_DOT,
260 '"." must go on the following line',
261 token)
262 if (not is_dot and wrapped_before and
245 not token.metadata.IsUnaryOperator()): 263 not token.metadata.IsUnaryOperator()):
246 self._HandleError( 264 self._HandleError(
247 errors.LINE_STARTS_WITH_OPERATOR, 265 errors.LINE_STARTS_WITH_OPERATOR,
248 'Binary operator should go on previous line "%s"' % token.string, 266 'Binary operator must go on previous line "%s"' % token.string,
249 token) 267 token)
250 268
269 def _IsLabel(self, token):
270 # A ':' token is considered part of a label if it occurs in a case
271 # statement, a plain label, or an object literal, i.e. is not part of a
272 # ternary.
273
274 return (token.string == ':' and
275 token.metadata.context.type in (Context.LITERAL_ELEMENT,
276 Context.CASE_BLOCK,
277 Context.STATEMENT))
278
251 def _ExpectSpaceBeforeOperator(self, token): 279 def _ExpectSpaceBeforeOperator(self, token):
252 """Returns whether a space should appear before the given operator token. 280 """Returns whether a space should appear before the given operator token.
253 281
254 Args: 282 Args:
255 token: The operator token. 283 token: The operator token.
256 284
257 Returns: 285 Returns:
258 Whether there should be a space before the token. 286 Whether there should be a space before the token.
259 """ 287 """
260 if token.string == ',' or token.metadata.IsUnaryPostOperator(): 288 if token.string == ',' or token.metadata.IsUnaryPostOperator():
261 return False 289 return False
262 290
291 if tokenutil.IsDot(token):
292 return False
293
263 # Colons should appear in labels, object literals, the case of a switch 294 # Colons should appear in labels, object literals, the case of a switch
264 # statement, and ternary operator. Only want a space in the case of the 295 # statement, and ternary operator. Only want a space in the case of the
265 # ternary operator. 296 # ternary operator.
266 if (token.string == ':' and 297 if self._IsLabel(token):
267 token.metadata.context.type in (Context.LITERAL_ELEMENT,
268 Context.CASE_BLOCK,
269 Context.STATEMENT)):
270 return False 298 return False
271 299
272 if token.metadata.IsUnaryOperator() and token.IsFirstInLine(): 300 if token.metadata.IsUnaryOperator() and token.IsFirstInLine():
273 return False 301 return False
274 302
275 return True 303 return True
276 304
277 def CheckToken(self, token, state): 305 def CheckToken(self, token, state):
278 """Checks a token, given the current parser_state, for warnings and errors. 306 """Checks a token, given the current parser_state, for warnings and errors.
279 307
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 space_count = len(token.string) - len(token.string.lstrip()) 339 space_count = len(token.string) - len(token.string.lstrip())
312 if space_count: 340 if space_count:
313 self._HandleError(errors.EXTRA_SPACE, 'Extra space after "("', 341 self._HandleError(errors.EXTRA_SPACE, 'Extra space after "("',
314 token, position=Position(0, space_count)) 342 token, position=Position(0, space_count))
315 343
316 elif (token_type == Type.START_BLOCK and 344 elif (token_type == Type.START_BLOCK and
317 token.metadata.context.type == Context.BLOCK): 345 token.metadata.context.type == Context.BLOCK):
318 self._CheckForMissingSpaceBeforeToken(token) 346 self._CheckForMissingSpaceBeforeToken(token)
319 347
320 elif token_type == Type.END_BLOCK: 348 elif token_type == Type.END_BLOCK:
321 # This check is for object literal end block tokens, but there is no need
322 # to test that condition since a comma at the end of any other kind of
323 # block is undoubtedly a parse error.
324 last_code = token.metadata.last_code 349 last_code = token.metadata.last_code
325 if last_code.IsOperator(','): 350
326 self._HandleError( 351 if FLAGS.check_trailing_comma:
327 errors.COMMA_AT_END_OF_LITERAL, 352 if last_code.IsOperator(','):
328 'Illegal comma at end of object literal', last_code, 353 self._HandleError(
329 position=Position.All(last_code.string)) 354 errors.COMMA_AT_END_OF_LITERAL,
355 'Illegal comma at end of object literal', last_code,
356 position=Position.All(last_code.string))
330 357
331 if state.InFunction() and state.IsFunctionClose(): 358 if state.InFunction() and state.IsFunctionClose():
332 is_immediately_called = (token.next and
333 token.next.type == Type.START_PAREN)
334 if state.InTopLevelFunction(): 359 if state.InTopLevelFunction():
335 # A semicolons should not be included at the end of a function 360 # A semicolons should not be included at the end of a function
336 # declaration. 361 # declaration.
337 if not state.InAssignedFunction(): 362 if not state.InAssignedFunction():
338 if not last_in_line and token.next.type == Type.SEMICOLON: 363 if not last_in_line and token.next.type == Type.SEMICOLON:
339 self._HandleError( 364 self._HandleError(
340 errors.ILLEGAL_SEMICOLON_AFTER_FUNCTION, 365 errors.ILLEGAL_SEMICOLON_AFTER_FUNCTION,
341 'Illegal semicolon after function declaration', 366 'Illegal semicolon after function declaration',
342 token.next, position=Position.All(token.next.string)) 367 token.next, position=Position.All(token.next.string))
343 368
344 # A semicolon should be included at the end of a function expression 369 # A semicolon should be included at the end of a function expression
345 # that is not immediately called. 370 # that is not immediately called or used by a dot operator.
346 if state.InAssignedFunction(): 371 if (state.InAssignedFunction() and token.next
347 if not is_immediately_called and ( 372 and token.next.type != Type.SEMICOLON):
348 last_in_line or token.next.type != Type.SEMICOLON): 373 next_token = tokenutil.GetNextCodeToken(token)
374 is_immediately_used = next_token and (
375 next_token.type == Type.START_PAREN or
376 tokenutil.IsDot(next_token))
377 if not is_immediately_used:
349 self._HandleError( 378 self._HandleError(
350 errors.MISSING_SEMICOLON_AFTER_FUNCTION, 379 errors.MISSING_SEMICOLON_AFTER_FUNCTION,
351 'Missing semicolon after function assigned to a variable', 380 'Missing semicolon after function assigned to a variable',
352 token, position=Position.AtEnd(token.string)) 381 token, position=Position.AtEnd(token.string))
353 382
354 if state.InInterfaceMethod() and last_code.type != Type.START_BLOCK: 383 if state.InInterfaceMethod() and last_code.type != Type.START_BLOCK:
355 self._HandleError(errors.INTERFACE_METHOD_CANNOT_HAVE_CODE, 384 self._HandleError(errors.INTERFACE_METHOD_CANNOT_HAVE_CODE,
356 'Interface methods cannot contain code', last_code) 385 'Interface methods cannot contain code', last_code)
357 386
358 elif (state.IsBlockClose() and 387 elif (state.IsBlockClose() and
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 lambda token: token.type == Type.KEYWORD and token.string == 'for', 424 lambda token: token.type == Type.KEYWORD and token.string == 'for',
396 end_func=lambda token: token.type == Type.SEMICOLON, 425 end_func=lambda token: token.type == Type.SEMICOLON,
397 distance=None, 426 distance=None,
398 reverse=True) 427 reverse=True)
399 428
400 if not for_token: 429 if not for_token:
401 self._HandleError(errors.REDUNDANT_SEMICOLON, 'Redundant semicolon', 430 self._HandleError(errors.REDUNDANT_SEMICOLON, 'Redundant semicolon',
402 token, position=Position.All(token.string)) 431 token, position=Position.All(token.string))
403 432
404 elif token_type == Type.START_PAREN: 433 elif token_type == Type.START_PAREN:
405 if token.previous and token.previous.type == Type.KEYWORD: 434 # Ensure that opening parentheses have a space before any keyword
435 # that is not being invoked like a member function.
436 if (token.previous and token.previous.type == Type.KEYWORD and
437 (not token.previous.metadata or
438 not token.previous.metadata.last_code or
439 not token.previous.metadata.last_code.string or
440 token.previous.metadata.last_code.string[-1:] != '.')):
406 self._HandleError(errors.MISSING_SPACE, 'Missing space before "("', 441 self._HandleError(errors.MISSING_SPACE, 'Missing space before "("',
407 token, position=Position.AtBeginning()) 442 token, position=Position.AtBeginning())
408 elif token.previous and token.previous.type == Type.WHITESPACE: 443 elif token.previous and token.previous.type == Type.WHITESPACE:
409 before_space = token.previous.previous 444 before_space = token.previous.previous
445 # Ensure that there is no extra space before a function invocation,
446 # even if the function being invoked happens to be a keyword.
410 if (before_space and before_space.line_number == token.line_number and 447 if (before_space and before_space.line_number == token.line_number and
411 before_space.type == Type.IDENTIFIER): 448 before_space.type == Type.IDENTIFIER or
449 (before_space.type == Type.KEYWORD and before_space.metadata and
450 before_space.metadata.last_code and
451 before_space.metadata.last_code.string and
452 before_space.metadata.last_code.string[-1:] == '.')):
412 self._HandleError( 453 self._HandleError(
413 errors.EXTRA_SPACE, 'Extra space before "("', 454 errors.EXTRA_SPACE, 'Extra space before "("',
414 token.previous, position=Position.All(token.previous.string)) 455 token.previous, position=Position.All(token.previous.string))
415 456
416 elif token_type == Type.START_BRACKET: 457 elif token_type == Type.START_BRACKET:
417 self._HandleStartBracket(token, last_non_space_token) 458 self._HandleStartBracket(token, last_non_space_token)
418 elif token_type in (Type.END_PAREN, Type.END_BRACKET): 459 elif token_type in (Type.END_PAREN, Type.END_BRACKET):
419 # Ensure there is no space before closing parentheses, except when 460 # Ensure there is no space before closing parentheses, except when
420 # it's in a for statement with an omitted section, or when it's at the 461 # it's in a for statement with an omitted section, or when it's at the
421 # beginning of a line. 462 # beginning of a line.
463
464 last_code = token.metadata.last_code
465 if FLAGS.check_trailing_comma and token_type == Type.END_BRACKET:
466 if last_code.IsOperator(','):
467 self._HandleError(
468 errors.COMMA_AT_END_OF_LITERAL,
469 'Illegal comma at end of array literal', last_code,
470 position=Position.All(last_code.string))
471
422 if (token.previous and token.previous.type == Type.WHITESPACE and 472 if (token.previous and token.previous.type == Type.WHITESPACE and
423 not token.previous.IsFirstInLine() and 473 not token.previous.IsFirstInLine() and
424 not (last_non_space_token and last_non_space_token.line_number == 474 not (last_non_space_token and last_non_space_token.line_number ==
425 token.line_number and 475 token.line_number and
426 last_non_space_token.type == Type.SEMICOLON)): 476 last_non_space_token.type == Type.SEMICOLON)):
427 self._HandleError( 477 self._HandleError(
428 errors.EXTRA_SPACE, 'Extra space before "%s"' % 478 errors.EXTRA_SPACE, 'Extra space before "%s"' %
429 token.string, token.previous, 479 token.string, token.previous,
430 position=Position.All(token.previous.string)) 480 position=Position.All(token.previous.string))
431 481
432 if token.type == Type.END_BRACKET:
433 last_code = token.metadata.last_code
434 if last_code.IsOperator(','):
435 self._HandleError(
436 errors.COMMA_AT_END_OF_LITERAL,
437 'Illegal comma at end of array literal', last_code,
438 position=Position.All(last_code.string))
439
440 elif token_type == Type.WHITESPACE: 482 elif token_type == Type.WHITESPACE:
441 if self.ILLEGAL_TAB.search(token.string): 483 if self.ILLEGAL_TAB.search(token.string):
442 if token.IsFirstInLine(): 484 if token.IsFirstInLine():
443 if token.next: 485 if token.next:
444 self._HandleError( 486 self._HandleError(
445 errors.ILLEGAL_TAB, 487 errors.ILLEGAL_TAB,
446 'Illegal tab in whitespace before "%s"' % token.next.string, 488 'Illegal tab in whitespace before "%s"' % token.next.string,
447 token, position=Position.All(token.string)) 489 token, position=Position.All(token.string))
448 else: 490 else:
449 self._HandleError( 491 self._HandleError(
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 527
486 elif flag.flag_type == 'suppress': 528 elif flag.flag_type == 'suppress':
487 if flag.type is None: 529 if flag.type is None:
488 # A syntactically invalid suppress tag will get tokenized as a normal 530 # A syntactically invalid suppress tag will get tokenized as a normal
489 # flag, indicating an error. 531 # flag, indicating an error.
490 self._HandleError( 532 self._HandleError(
491 errors.INCORRECT_SUPPRESS_SYNTAX, 533 errors.INCORRECT_SUPPRESS_SYNTAX,
492 'Invalid suppress syntax: should be @suppress {errortype}. ' 534 'Invalid suppress syntax: should be @suppress {errortype}. '
493 'Spaces matter.', token) 535 'Spaces matter.', token)
494 else: 536 else:
495 for suppress_type in re.split(r'\||,', flag.type): 537 for suppress_type in flag.jstype.IterIdentifiers():
496 if suppress_type not in state.GetDocFlag().SUPPRESS_TYPES: 538 if suppress_type not in state.GetDocFlag().SUPPRESS_TYPES:
497 self._HandleError( 539 self._HandleError(
498 errors.INVALID_SUPPRESS_TYPE, 540 errors.INVALID_SUPPRESS_TYPE,
499 'Invalid suppression type: %s' % suppress_type, token) 541 'Invalid suppression type: %s' % suppress_type, token)
500 542
501 elif (error_check.ShouldCheck(Rule.WELL_FORMED_AUTHOR) and 543 elif (error_check.ShouldCheck(Rule.WELL_FORMED_AUTHOR) and
502 flag.flag_type == 'author'): 544 flag.flag_type == 'author'):
503 # TODO(user): In non strict mode check the author tag for as much as 545 # TODO(user): In non strict mode check the author tag for as much as
504 # it exists, though the full form checked below isn't required. 546 # it exists, though the full form checked below isn't required.
505 string = token.next.string 547 string = token.next.string
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 if 'name' in token.values: 586 if 'name' in token.values:
545 flag_name = '@' + token.values['name'] 587 flag_name = '@' + token.values['name']
546 588
547 if flag_name not in self.JSDOC_FLAGS_DESCRIPTION_NOT_REQUIRED: 589 if flag_name not in self.JSDOC_FLAGS_DESCRIPTION_NOT_REQUIRED:
548 self._HandleError( 590 self._HandleError(
549 errors.MISSING_JSDOC_TAG_DESCRIPTION, 591 errors.MISSING_JSDOC_TAG_DESCRIPTION,
550 'Missing description in %s tag' % flag_name, token) 592 'Missing description in %s tag' % flag_name, token)
551 else: 593 else:
552 self._CheckForMissingSpaceBeforeToken(flag.description_start_token) 594 self._CheckForMissingSpaceBeforeToken(flag.description_start_token)
553 595
554 if flag.flag_type in state.GetDocFlag().HAS_TYPE: 596 if flag.HasType():
555 if flag.type_start_token is not None: 597 if flag.type_start_token is not None:
556 self._CheckForMissingSpaceBeforeToken( 598 self._CheckForMissingSpaceBeforeToken(
557 token.attached_object.type_start_token) 599 token.attached_object.type_start_token)
558 600
559 if flag.type and not flag.type.isspace(): 601 if flag.jstype and not flag.jstype.IsEmpty():
560 self._CheckJsDocType(token) 602 self._CheckJsDocType(token, flag.jstype)
603
604 if error_check.ShouldCheck(Rule.BRACES_AROUND_TYPE) and (
605 flag.type_start_token.type != Type.DOC_START_BRACE or
606 flag.type_end_token.type != Type.DOC_END_BRACE):
607 self._HandleError(
608 errors.MISSING_BRACES_AROUND_TYPE,
609 'Type must always be surrounded by curly braces.', token)
561 610
562 if token_type in (Type.DOC_FLAG, Type.DOC_INLINE_FLAG): 611 if token_type in (Type.DOC_FLAG, Type.DOC_INLINE_FLAG):
563 if (token.values['name'] not in state.GetDocFlag().LEGAL_DOC and 612 if (token.values['name'] not in state.GetDocFlag().LEGAL_DOC and
564 token.values['name'] not in FLAGS.custom_jsdoc_tags): 613 token.values['name'] not in FLAGS.custom_jsdoc_tags):
565 self._HandleError( 614 self._HandleError(
566 errors.INVALID_JSDOC_TAG, 615 errors.INVALID_JSDOC_TAG,
567 'Invalid JsDoc tag: %s' % token.values['name'], token) 616 'Invalid JsDoc tag: %s' % token.values['name'], token)
568 617
569 if (error_check.ShouldCheck(Rule.NO_BRACES_AROUND_INHERIT_DOC) and 618 if (error_check.ShouldCheck(Rule.NO_BRACES_AROUND_INHERIT_DOC) and
570 token.values['name'] == 'inheritDoc' and 619 token.values['name'] == 'inheritDoc' and
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
630 not self.InExplicitlyTypedLanguage()): 679 not self.InExplicitlyTypedLanguage()):
631 # It is convention to hide public fields in some ECMA 680 # It is convention to hide public fields in some ECMA
632 # implementations from documentation using the @private tag. 681 # implementations from documentation using the @private tag.
633 self._HandleError( 682 self._HandleError(
634 errors.EXTRA_PRIVATE, 683 errors.EXTRA_PRIVATE,
635 'Member "%s" must not have @private JsDoc' % 684 'Member "%s" must not have @private JsDoc' %
636 identifier, token) 685 identifier, token)
637 686
638 # These flags are only legal on localizable message definitions; 687 # These flags are only legal on localizable message definitions;
639 # such variables always begin with the prefix MSG_. 688 # such variables always begin with the prefix MSG_.
640 for f in ('desc', 'hidden', 'meaning'): 689 if not identifier.startswith('MSG_') and '.MSG_' not in identifier:
641 if (jsdoc.HasFlag(f) 690 for f in ('desc', 'hidden', 'meaning'):
642 and not identifier.startswith('MSG_') 691 if jsdoc.HasFlag(f):
643 and identifier.find('.MSG_') == -1): 692 self._HandleError(
644 self._HandleError( 693 errors.INVALID_USE_OF_DESC_TAG,
645 errors.INVALID_USE_OF_DESC_TAG, 694 'Member "%s" does not start with MSG_ and thus '
646 'Member "%s" should not have @%s JsDoc' % (identifier, f), 695 'should not have @%s JsDoc' % (identifier, f),
647 token) 696 token)
648 697
649 # Check for illegaly assigning live objects as prototype property values. 698 # Check for illegaly assigning live objects as prototype property values.
650 index = identifier.find('.prototype.') 699 index = identifier.find('.prototype.')
651 # Ignore anything with additional .s after the prototype. 700 # Ignore anything with additional .s after the prototype.
652 if index != -1 and identifier.find('.', index + 11) == -1: 701 if index != -1 and identifier.find('.', index + 11) == -1:
653 equal_operator = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES) 702 equal_operator = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES)
654 next_code = tokenutil.SearchExcept(equal_operator, Type.NON_CODE_TYPES) 703 next_code = tokenutil.SearchExcept(equal_operator, Type.NON_CODE_TYPES)
655 if next_code and ( 704 if next_code and (
656 next_code.type in (Type.START_BRACKET, Type.START_BLOCK) or 705 next_code.type in (Type.START_BRACKET, Type.START_BLOCK) or
657 next_code.IsOperator('new')): 706 next_code.IsOperator('new')):
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
807 """Gets a list of regexps for lines which can be longer than the limit. 856 """Gets a list of regexps for lines which can be longer than the limit.
808 857
809 Returns: 858 Returns:
810 A list of regexps, used as matches (rather than searches). 859 A list of regexps, used as matches (rather than searches).
811 """ 860 """
812 return [] 861 return []
813 862
814 def InExplicitlyTypedLanguage(self): 863 def InExplicitlyTypedLanguage(self):
815 """Returns whether this ecma implementation is explicitly typed.""" 864 """Returns whether this ecma implementation is explicitly typed."""
816 return False 865 return False
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698