12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#!/usr/bin/env python 22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Copyright 2007 The Closure Linter Authors. All Rights Reserved. 42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Licensed under the Apache License, Version 2.0 (the "License"); 62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# you may not use this file except in compliance with the License. 72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# You may obtain a copy of the License at 82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# http://www.apache.org/licenses/LICENSE-2.0 102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Unless required by applicable law or agreed to in writing, software 122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# distributed under the License is distributed on an "AS-IS" BASIS, 132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# See the License for the specific language governing permissions and 152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# limitations under the License. 162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis"""Light weight EcmaScript state tracker that reads tokens and tracks state.""" 182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis__author__ = ('robbyw@google.com (Robert Walker)', 202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'ajp@google.com (Andy Perelson)') 212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 222da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport re 232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 242da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import javascripttokenizer 252da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import javascripttokens 262da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom closure_linter import tokenutil 272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Shorthand 292da489cd246702bee5938545b18a6f710ed214bcJamie GennisType = javascripttokens.JavaScriptTokenType 302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 322da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass DocFlag(object): 332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Generic doc flag object. 342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Attribute: 362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_type: param, return, define, type, etc. 372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_token: The flag token. 382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type_start_token: The first token specifying the flag type, 392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis including braces. 402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type_end_token: The last token specifying the flag type, 412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis including braces. 422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type: The type spec. 432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name_token: The token specifying the flag name. 442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name: The flag name 452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis description_start_token: The first token in the description. 462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis description_end_token: The end token in the description. 472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis description: The description. 482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Please keep these lists alphabetized. 512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The list of standard jsdoc tags is from 532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis STANDARD_DOC = frozenset([ 542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'author', 552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'bug', 562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'const', 572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'constructor', 582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'define', 592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'deprecated', 602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'enum', 612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'export', 622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'extends', 632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'externs', 642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'fileoverview', 652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'implements', 662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'implicitCast', 672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'interface', 682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'lends', 692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'license', 702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'noalias', 712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'nocompile', 722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'nosideeffects', 732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'override', 742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'owner', 752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'param', 762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'preserve', 772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'private', 782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'return', 792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'see', 802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'supported', 812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'template', 822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'this', 832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'type', 842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'typedef', 852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ]) 862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ANNOTATION = frozenset(['preserveTry', 'suppress']) 882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis LEGAL_DOC = STANDARD_DOC | ANNOTATION 902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Includes all Closure Compiler @suppress types. 922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Not all of these annotations are interpreted by Closure Linter. 932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # 942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Specific cases: 952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # - accessControls is supported by the compiler at the expression 962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # and method level to suppress warnings about private/protected 972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # access (method level applies to all references in the method). 982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The linter mimics the compiler behavior. 992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis SUPPRESS_TYPES = frozenset([ 1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'accessControls', 1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'ambiguousFunctionDecl', 1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'checkRegExp', 1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'checkTypes', 1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'checkVars', 1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'const', 1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'constantProperty', 1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'deprecated', 1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'duplicate', 1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'es5Strict', 1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'externsValidation', 1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'extraProvide', 1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'extraRequire', 1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'fileoverviewTags', 1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'globalThis', 1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'internetExplorerChecks', 1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'invalidCasts', 1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'missingProperties', 1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'missingProvide', 1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'missingRequire', 1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'nonStandardJsDocs', 1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'strictModuleDepCheck', 1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'tweakValidation', 1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'typeInvalidation', 1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'undefinedNames', 1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'undefinedVars', 1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'underscore', 1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'unknownDefines', 1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'uselessCode', 1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'visibility', 1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'with']) 1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis HAS_DESCRIPTION = frozenset([ 1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'define', 'deprecated', 'desc', 'fileoverview', 'license', 'param', 1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'preserve', 'return', 'supported']) 1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis HAS_TYPE = frozenset([ 1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'define', 'enum', 'extends', 'implements', 'param', 'return', 'type', 1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 'suppress']) 1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis TYPE_ONLY = frozenset(['enum', 'extends', 'implements', 'suppress', 'type']) 1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis HAS_NAME = frozenset(['param']) 1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EMPTY_COMMENT_LINE = re.compile(r'^\s*\*?\s*$') 1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EMPTY_STRING = re.compile(r'^\s*$') 1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, flag_token): 1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Creates the DocFlag object and attaches it to the given start token. 1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_token: The starting token of the flag. 1522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.flag_token = flag_token 1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.flag_type = flag_token.string.strip().lstrip('@') 1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Extract type, if applicable. 1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type = None 1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_start_token = None 1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_end_token = None 1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.flag_type in self.HAS_TYPE: 1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis brace = tokenutil.SearchUntil(flag_token, [Type.DOC_START_BRACE], 1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Type.FLAG_ENDING_TYPES) 1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if brace: 1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis end_token, contents = _GetMatchingEndBraceAndContents(brace) 1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type = contents 1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_start_token = brace 1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_end_token = end_token 1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif (self.flag_type in self.TYPE_ONLY and 1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_token.next.type not in Type.FLAG_ENDING_TYPES): 1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_start_token = flag_token.next 1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_end_token, self.type = _GetEndTokenAndContents( 1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type_start_token) 1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.type is not None: 1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.type = self.type.strip() 1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Extract name, if applicable. 1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name_token = None 1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name = None 1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.flag_type in self.HAS_NAME: 1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Handle bad case, name could be immediately after flag token. 1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name_token = _GetNextIdentifierToken(flag_token) 1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Handle good case, if found token is after type start, look for 1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # identifier after type end, since types contain identifiers. 1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (self.type and self.name_token and 1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis tokenutil.Compare(self.name_token, self.type_start_token) > 0): 1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name_token = _GetNextIdentifierToken(self.type_end_token) 1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.name_token: 1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name = self.name_token.string 1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Extract description, if applicable. 1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.description_start_token = None 1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.description_end_token = None 1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.description = None 1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.flag_type in self.HAS_DESCRIPTION: 1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis search_start_token = flag_token 1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.name_token and self.type_end_token: 1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if tokenutil.Compare(self.type_end_token, self.name_token) > 0: 2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis search_start_token = self.type_end_token 2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis search_start_token = self.name_token 2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif self.name_token: 2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis search_start_token = self.name_token 2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif self.type: 2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis search_start_token = self.type_end_token 2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis interesting_token = tokenutil.Search(search_start_token, 2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Type.FLAG_DESCRIPTION_TYPES | Type.FLAG_ENDING_TYPES) 2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if interesting_token.type in Type.FLAG_DESCRIPTION_TYPES: 2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.description_start_token = interesting_token 2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.description_end_token, self.description = ( 2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis _GetEndTokenAndContents(interesting_token)) 2142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2162da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass DocComment(object): 2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """JavaScript doc comment object. 2182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Attributes: 2202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis ordered_params: Ordered list of parameters documented. 2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_token: The token that starts the doc comment. 2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis end_token: The token that ends the doc comment. 2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis suppressions: Map of suppression type to the token that added it. 2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, start_token): 2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Create the doc comment object. 2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_token: The first token in the doc comment. 2302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__params = {} 2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.ordered_params = [] 2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__flags = {} 2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.start_token = start_token 2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.end_token = None 2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.suppressions = {} 2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.invalidated = False 2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Invalidate(self): 2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Indicate that the JSDoc is well-formed but we had problems parsing it. 2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis This is a short-circuiting mechanism so that we don't emit false 2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis positives about well-formed doc comments just because we don't support 2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis hot new syntaxes. 2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.invalidated = True 2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsInvalidated(self): 2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Test whether Invalidate() has been called.""" 2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.invalidated 2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def AddParam(self, name, param_type): 2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Add a new documented parameter. 2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name: The name of the parameter to document. 2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis param_type: The parameter's declared JavaScript type. 2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.ordered_params.append(name) 2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__params[name] = param_type 2612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def AddSuppression(self, token): 2632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Add a new error suppression flag. 2642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The suppression flag token. 2672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis #TODO(user): Error if no braces 2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis brace = tokenutil.SearchUntil(token, [Type.DOC_START_BRACE], 2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis [Type.DOC_FLAG]) 2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if brace: 2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis end_token, contents = _GetMatchingEndBraceAndContents(brace) 2732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for suppression in contents.split('|'): 2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.suppressions[suppression] = token 2752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def SuppressionOnly(self): 2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns whether this comment contains only suppression flags.""" 2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for flag_type in self.__flags.keys(): 2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag_type != 'suppress': 2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 2812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 2822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def AddFlag(self, flag): 2842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Add a new document flag. 2852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 2872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag: DocFlag object. 2882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.__flags[flag.flag_type] = flag 2902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InheritsDocumentation(self): 2922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Test if the jsdoc implies documentation inheritance. 2932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if documentation may be pulled off the superclass. 2962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 2972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.HasFlag('inheritDoc') or self.HasFlag('override') 2982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def HasFlag(self, flag_type): 3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Test if the given flag has been set. 3012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 3032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_type: The type of the flag to check. 3042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 3062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the flag is set. 3072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 3082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return flag_type in self.__flags 3092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetFlag(self, flag_type): 3112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Gets the last flag of the given type. 3122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 3142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag_type: The type of the flag to get. 3152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 3172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The last instance of the given flag type in this doc comment. 3182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 3192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.__flags[flag_type] 3202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def CompareParameters(self, params): 3222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Computes the edit distance and list from the function params to the docs. 3232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Uses the Levenshtein edit distance algorithm, with code modified from 3252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance#Python 3262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 3282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis params: The parameter list for the function declaration. 3292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 3312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The edit distance, the edit list. 3322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 3332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis source_len, target_len = len(self.ordered_params), len(params) 3342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_lists = [[]] 3352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis distance = [[]] 3362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for i in range(target_len+1): 3372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_lists[0].append(['I'] * i) 3382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis distance[0].append(i) 3392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for j in range(1, source_len+1): 3412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_lists.append([['D'] * j]) 3422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis distance.append([j]) 3432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for i in range(source_len): 3452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis for j in range(target_len): 3462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis cost = 1 3472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.ordered_params[i] == params[j]: 3482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis cost = 0 3492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis deletion = distance[i][j+1] + 1 3512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis insertion = distance[i+1][j] + 1 3522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis substitution = distance[i][j] + cost 3532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list = None 3552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis best = None 3562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if deletion <= insertion and deletion <= substitution: 3572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Deletion is best. 3582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis best = deletion 3592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list = list(edit_lists[i][j+1]) 3602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list.append('D') 3612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif insertion <= substitution: 3632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Insertion is best. 3642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis best = insertion 3652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list = list(edit_lists[i+1][j]) 3662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list.append('I') 3672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_lists[i+1].append(edit_list) 3682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Substitution is best. 3712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis best = substitution 3722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list = list(edit_lists[i][j]) 3732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if cost: 3742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list.append('S') 3752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 3762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_list.append('=') 3772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis edit_lists[i+1].append(edit_list) 3792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis distance[i+1].append(best) 3802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return distance[source_len][target_len], edit_lists[source_len][target_len] 3822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __repr__(self): 3842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns a string representation of this object. 3852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 3872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis A string representation of this object. 3882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 3892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return '<DocComment: %s, %s>' % (str(self.__params), str(self.__flags)) 3902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 3932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Helper methods used by DocFlag and DocComment to parse out flag information. 3942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# 3952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 3972da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _GetMatchingEndBraceAndContents(start_brace): 3982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns the matching end brace and contents between the two braces. 3992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis If any FLAG_ENDING_TYPE token is encountered before a matching end brace, then 4012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis that token is used as the matching ending token. Contents will have all 4022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis comment prefixes stripped out of them, and all comment prefixes in between the 4032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start and end tokens will be split out into separate DOC_PREFIX tokens. 4042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 4062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_brace: The DOC_START_BRACE token immediately before desired contents. 4072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 4092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The matching ending token (DOC_END_BRACE or FLAG_ENDING_TYPE) and a string 4102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis of the contents between the matching tokens, minus any comment prefixes. 4112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 4122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis open_count = 1 4132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis close_count = 0 4142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents = [] 4152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # We don't consider the start brace part of the type string. 4172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = start_brace.next 4182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while open_count != close_count: 4192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.type == Type.DOC_START_BRACE: 4202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis open_count += 1 4212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif token.type == Type.DOC_END_BRACE: 4222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis close_count += 1 4232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.type != Type.DOC_PREFIX: 4252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents.append(token.string) 4262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if token.type in Type.FLAG_ENDING_TYPES: 4282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis break 4292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = token.next 4302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis #Don't include the end token (end brace, end doc comment, etc.) in type. 4322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = token.previous 4332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents = contents[:-1] 4342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return token, ''.join(contents) 4362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _GetNextIdentifierToken(start_token): 4392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Searches for and returns the first identifier at the beginning of a token. 4402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Searches each token after the start to see if it starts with an identifier. 4422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis If found, will split the token into at most 3 piecies: leading whitespace, 4432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis identifier, rest of token, returning the identifier token. If no identifier is 4442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis found returns None and changes no tokens. Search is abandoned when a 4452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis FLAG_ENDING_TYPE token is found. 4462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 4482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_token: The token to start searching after. 4492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 4512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The identifier token is found, None otherwise. 4522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 4532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = start_token.next 4542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while token and not token.type in Type.FLAG_ENDING_TYPES: 4562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis match = javascripttokenizer.JavaScriptTokenizer.IDENTIFIER.match( 4572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.string) 4582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (match is not None and token.type == Type.COMMENT and 4592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis len(token.string) == len(match.group(0))): 4602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return token 4612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token = token.next 4632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return None 4652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4672da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _GetEndTokenAndContents(start_token): 4682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns last content token and all contents before FLAG_ENDING_TYPE token. 4692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Comment prefixes are split into DOC_PREFIX tokens and stripped from the 4712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis returned contents. 4722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 4742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis start_token: The token immediately before the first content token. 4752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 4762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 4772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The last content token and a string of all contents including start and 4782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis end tokens, with comment prefixes stripped. 4792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 4802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis iterator = start_token 4812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_line = iterator.line_number 4822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_token = None 4832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents = '' 4842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc_depth = 0 4852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while not iterator.type in Type.FLAG_ENDING_TYPES or doc_depth > 0: 4862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (iterator.IsFirstInLine() and 4872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis DocFlag.EMPTY_COMMENT_LINE.match(iterator.line)): 4882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # If we have a blank comment line, consider that an implicit 4892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # ending of the description. This handles a case like: 4902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # 4912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # * @return {boolean} True 4922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # * 4932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # * Note: This is a sentence. 4942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # 4952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # The note is not part of the @return description, but there was 4962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # no definitive ending token. Rather there was a line containing 4972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # only a doc comment prefix or whitespace. 4982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis break 4992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # b/2983692 5012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # don't prematurely match against a @flag if inside a doc flag 5022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # need to think about what is the correct behavior for unterminated 5032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # inline doc flags 5042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (iterator.type == Type.DOC_START_BRACE and 5052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis iterator.next.type == Type.DOC_INLINE_FLAG): 5062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc_depth += 1 5072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif (iterator.type == Type.DOC_END_BRACE and 5082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc_depth > 0): 5092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc_depth -= 1 5102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if iterator.type in Type.FLAG_DESCRIPTION_TYPES: 5122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents += iterator.string 5132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_token = iterator 5142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis iterator = iterator.next 5162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if iterator.line_number != last_line: 5172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents += '\n' 5182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_line = iterator.line_number 5192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis end_token = last_token 5212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if DocFlag.EMPTY_STRING.match(contents): 5222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents = None 5232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 5242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Strip trailing newline. 5252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis contents = contents[:-1] 5262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return end_token, contents 5282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5302da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass Function(object): 5312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Data about a JavaScript function. 5322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Attributes: 5342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis block_depth: Block depth the function began at. 5352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc: The DocComment associated with the function. 5362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis has_return: If the function has a return value. 5372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis has_this: If the function references the 'this' object. 5382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_assigned: If the function is part of an assignment. 5392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_constructor: If the function is a constructor. 5402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name: The name of the function, whether given in the function keyword or 5412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis as the lvalue the function is assigned to. 5422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 5432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, block_depth, is_assigned, doc, name): 5452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.block_depth = block_depth 5462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.is_assigned = is_assigned 5472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.is_constructor = doc and doc.HasFlag('constructor') 5482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.is_interface = doc and doc.HasFlag('interface') 5492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.has_return = False 5502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.has_throw = False 5512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.has_this = False 5522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.name = name 5532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.doc = doc 5542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5562da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass StateTracker(object): 5572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """EcmaScript state tracker. 5582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Tracks block depth, function names, etc. within an EcmaScript token stream. 5602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 5612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis OBJECT_LITERAL = 'o' 5632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis CODE = 'c' 5642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def __init__(self, doc_flag=DocFlag): 5662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Initializes a JavaScript token stream state tracker. 5672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 5692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc_flag: An optional custom DocFlag used for validating 5702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis documentation flags. 5712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 5722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_flag = doc_flag 5732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self.Reset() 5742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def Reset(self): 5762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Resets the state tracker to prepare for processing a new page.""" 5772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._block_depth = 0 5782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._is_block_close = False 5792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._paren_depth = 0 5802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions = [] 5812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions_by_name = {} 5822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_comment = None 5832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment = None 5842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._cumulative_params = None 5852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._block_types = [] 5862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_non_space_token = None 5872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_line = None 5882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._first_token = None 5892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._documented_identifiers = set() 5902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InFunction(self): 5922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within a function. 5932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 5952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within a function. 5962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 5972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return bool(self._functions) 5982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 5992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InConstructor(self): 6002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within a constructor. 6012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within a constructor. 6042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.InFunction() and self._functions[-1].is_constructor 6062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InInterfaceMethod(self): 6082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within an interface method. 6092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within an interface method. 6122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.InFunction(): 6142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._functions[-1].is_interface: 6152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 6162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 6172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name = self._functions[-1].name 6182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis prototype_index = name.find('.prototype.') 6192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if prototype_index != -1: 6202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis class_function_name = name[0:prototype_index] 6212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (class_function_name in self._functions_by_name and 6222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions_by_name[class_function_name].is_interface): 6232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return True 6242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 6262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InTopLevelFunction(self): 6282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within a top level function. 6292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within a top level function. 6322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return len(self._functions) == 1 and self.InTopLevel() 6342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InAssignedFunction(self): 6362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within a function variable. 6372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if if the current token is within a function variable 6402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.InFunction() and self._functions[-1].is_assigned 6422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsFunctionOpen(self): 6442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is a function block open. 6452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is a function block open. 6482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (self._functions and 6502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions[-1].block_depth == self._block_depth - 1) 6512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsFunctionClose(self): 6532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is a function block close. 6542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is a function block close. 6572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (self._functions and 6592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions[-1].block_depth == self._block_depth) 6602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InBlock(self): 6622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within a block. 6632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within a block. 6662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return bool(self._block_depth) 6682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsBlockClose(self): 6702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is a block close. 6712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is a block close. 6742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._is_block_close 6762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InObjectLiteral(self): 6782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within an object literal. 6792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within an object literal. 6822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._block_depth and self._block_types[-1] == self.OBJECT_LITERAL 6842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InObjectLiteralDescendant(self): 6862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token has an object literal ancestor. 6872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token has an object literal ancestor. 6902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self.OBJECT_LITERAL in self._block_types 6922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InParentheses(self): 6942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns true if the current token is within parentheses. 6952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 6962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 6972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True if the current token is within parentheses. 6982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 6992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return bool(self._paren_depth) 7002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InTopLevel(self): 7022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Whether we are at the top level in the class. 7032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis This function call is language specific. In some languages like 7052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis JavaScript, a function is top level if it is not inside any parenthesis. 7062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis In languages such as ActionScript, a function is top level if it is directly 7072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis within a class. 7082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis raise TypeError('Abstract method InTopLevel not implemented') 7102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetBlockType(self, token): 7122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Determine the block type given a START_BLOCK token. 7132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Code blocks come after parameters, keywords like else, and closing parens. 7152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 7172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The current token. Can be assumed to be type START_BLOCK. 7182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Code block type for current token. 7202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis raise TypeError('Abstract method GetBlockType not implemented') 7222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetParams(self): 7242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns the accumulated input params as an array. 7252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis In some EcmasSript languages, input params are specified like 7272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (param:Type, param2:Type2, ...) 7282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis in other they are specified just as 7292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (param, param2) 7302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis We handle both formats for specifying parameters here and leave 7312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis it to the compilers for each language to detect compile errors. 7322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis This allows more code to be reused between lint checkers for various 7332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis EcmaScript languages. 7342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The accumulated input params as an array. 7372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis params = [] 7392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._cumulative_params: 7402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis params = re.compile(r'\s+').sub('', self._cumulative_params).split(',') 7412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Strip out the type from parameters of the form name:Type. 7422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis params = map(lambda param: param.split(':')[0], params) 7432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return params 7452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetLastComment(self): 7472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the last plain comment that could be used as documentation. 7482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The last plain comment that could be used as documentation. 7512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._last_comment 7532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetDocComment(self): 7552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the most recent applicable documentation comment. 7562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The last applicable documentation comment. 7592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._doc_comment 7612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def HasDocComment(self, identifier): 7632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns whether the identifier has been documented yet. 7642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 7662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis identifier: The identifier. 7672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Whether the identifier has been documented yet. 7702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return identifier in self._documented_identifiers 7722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def InDocComment(self): 7742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns whether the current token is in a doc comment. 7752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Whether the current token is in a doc comment. 7782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._doc_comment and self._doc_comment.end_token is None 7802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetDocFlag(self): 7822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Returns the current documentation flags. 7832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 7852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The current documentation flags. 7862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 7872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._doc_flag 7882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def IsTypeToken(self, t): 7902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.InDocComment() and t.type not in (Type.START_DOC_COMMENT, 7912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Type.DOC_FLAG, Type.DOC_INLINE_FLAG, Type.DOC_PREFIX): 7922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis f = tokenutil.SearchUntil(t, [Type.DOC_FLAG], [Type.START_DOC_COMMENT], 7932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis None, True) 7942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if f and f.attached_object.type_start_token is not None: 7952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return (tokenutil.Compare(t, f.attached_object.type_start_token) > 0 and 7962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis tokenutil.Compare(t, f.attached_object.type_end_token) < 0) 7972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return False 7982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 7992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetFunction(self): 8002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the function the current code block is a part of. 8012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 8032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The current Function object. 8042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 8052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self._functions: 8062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._functions[-1] 8072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetBlockDepth(self): 8092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the block depth. 8102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Returns: 8122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis The current block depth. 8132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 8142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._block_depth 8152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetLastNonSpaceToken(self): 8172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the last non whitespace token.""" 8182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._last_non_space_token 8192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetLastLine(self): 8212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the last line.""" 8222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._last_line 8232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def GetFirstToken(self): 8252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Return the very first token in the file.""" 8262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis return self._first_token 8272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def HandleToken(self, token, last_non_space_token): 8292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Handles the given token and updates state. 8302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 8322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token to handle. 8332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_non_space_token: 8342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 8352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._is_block_close = False 8362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not self._first_token: 8382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._first_token = token 8392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Track block depth. 8412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type = token.type 8422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if type == Type.START_BLOCK: 8432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._block_depth += 1 8442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Subclasses need to handle block start very differently because 8462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # whether a block is a CODE or OBJECT_LITERAL block varies significantly 8472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # by language. 8482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._block_types.append(self.GetBlockType(token)) 8492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Track block depth. 8512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.END_BLOCK: 8522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._is_block_close = not self.InObjectLiteral() 8532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._block_depth -= 1 8542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._block_types.pop() 8552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Track parentheses depth. 8572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.START_PAREN: 8582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._paren_depth += 1 8592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Track parentheses depth. 8612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.END_PAREN: 8622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._paren_depth -= 1 8632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.COMMENT: 8652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_comment = token.string 8662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.START_DOC_COMMENT: 8682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_comment = None 8692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment = DocComment(token) 8702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.END_DOC_COMMENT: 8722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment.end_token = token 8732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type in (Type.DOC_FLAG, Type.DOC_INLINE_FLAG): 8752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis flag = self._doc_flag(token) 8762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token.attached_object = flag 8772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment.AddFlag(flag) 8782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if flag.flag_type == 'param' and flag.name: 8802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment.AddParam(flag.name, flag.type) 8812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif flag.flag_type == 'suppress': 8822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment.AddSuppression(token) 8832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.FUNCTION_DECLARATION: 8852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES, None, 8862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis True) 8872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc = None 8882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Only functions outside of parens are eligible for documentation. 8892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not self._paren_depth: 8902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis doc = self._doc_comment 8912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 8922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name = '' 8932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_assigned = last_code and (last_code.IsOperator('=') or 8942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis last_code.IsOperator('||') or last_code.IsOperator('&&') or 8952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis (last_code.IsOperator(':') and not self.InObjectLiteral())) 8962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if is_assigned: 8972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # TODO(robbyw): This breaks for x[2] = ... 8982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Must use loop to find full function name in the case of line-wrapped 8992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # declarations (bug 1220601) like: 9002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # my.function.foo. 9012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # bar = function() ... 9022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis identifier = tokenutil.Search(last_code, Type.SIMPLE_LVALUE, None, True) 9032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while identifier and identifier.type in ( 9042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Type.IDENTIFIER, Type.SIMPLE_LVALUE): 9052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name = identifier.string + name 9062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Traverse behind us, skipping whitespace and comments. 9072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while True: 9082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis identifier = identifier.previous 9092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not identifier or not identifier.type in Type.NON_CODE_TYPES: 9102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis break 9112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis else: 9132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_token = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES) 9142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis while next_token and next_token.IsType(Type.FUNCTION_NAME): 9152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis name += next_token.string 9162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_token = tokenutil.Search(next_token, Type.FUNCTION_NAME, 2) 9172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function = Function(self._block_depth, is_assigned, doc, name) 9192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions.append(function) 9202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions_by_name[name] = function 9212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.START_PARAMETERS: 9232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._cumulative_params = '' 9242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.PARAMETERS: 9262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._cumulative_params += token.string 9272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.KEYWORD and token.string == 'return': 9292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_token = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES) 9302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not next_token.IsType(Type.SEMICOLON): 9312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function = self.GetFunction() 9322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if function: 9332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function.has_return = True 9342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.KEYWORD and token.string == 'throw': 9362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function = self.GetFunction() 9372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if function: 9382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function.has_throw = True 9392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.SIMPLE_LVALUE: 9412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis identifier = token.values['identifier'] 9422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis jsdoc = self.GetDocComment() 9432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if jsdoc: 9442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._documented_identifiers.add(identifier) 9452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._HandleIdentifier(identifier, True) 9472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.IDENTIFIER: 9492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._HandleIdentifier(token.string, False) 9502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # Detect documented non-assignments. 9522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis next_token = tokenutil.SearchExcept(token, Type.NON_CODE_TYPES) 9532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if next_token.IsType(Type.SEMICOLON): 9542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if (self._last_non_space_token and 9552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_non_space_token.IsType(Type.END_DOC_COMMENT)): 9562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._documented_identifiers.add(token.string) 9572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def _HandleIdentifier(self, identifier, is_assignment): 9592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Process the given identifier. 9602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Currently checks if it references 'this' and annotates the function 9622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis accordingly. 9632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 9652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis identifier: The identifer to process. 9662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis is_assignment: Whether the identifer is being written to. 9672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 9682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if identifier == 'this' or identifier.startswith('this.'): 9692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function = self.GetFunction() 9702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if function: 9712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis function.has_this = True 9722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis def HandleAfterToken(self, token): 9752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """Handle updating state after a token has been checked. 9762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis This function should be used for destructive state changes such as 9782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis deleting a tracked object. 9792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Args: 9812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis token: The token to handle. 9822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis """ 9832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type = token.type 9842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if type == Type.SEMICOLON or type == Type.END_PAREN or ( 9852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis type == Type.END_BRACKET and 9862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_non_space_token.type not in ( 9872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis Type.SINGLE_QUOTE_STRING_END, Type.DOUBLE_QUOTE_STRING_END)): 9882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # We end on any numeric array index, but keep going for string based 9892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # array indices so that we pick up manually exported identifiers. 9902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment = None 9912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_comment = None 9922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.END_BLOCK: 9942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment = None 9952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_comment = None 9962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 9972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if self.InFunction() and self.IsFunctionClose(): 9982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis # TODO(robbyw): Detect the function's name for better errors. 9992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._functions.pop() 10002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 10012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis elif type == Type.END_PARAMETERS and self._doc_comment: 10022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._doc_comment = None 10032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_comment = None 10042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 10052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis if not token.IsAnyType(Type.WHITESPACE, Type.BLANK_LINE): 10062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_non_space_token = token 10072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis 10082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis self._last_line = token.line 1009