1cef7893435aa41160dd1255c43cb8498279738ccChris Craik#!/usr/bin/env python 2cef7893435aa41160dd1255c43cb8498279738ccChris Craik# 3cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Copyright 2012 The Closure Linter Authors. All Rights Reserved. 4cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Licensed under the Apache License, Version 2.0 (the "License"); 5cef7893435aa41160dd1255c43cb8498279738ccChris Craik# you may not use this file except in compliance with the License. 6cef7893435aa41160dd1255c43cb8498279738ccChris Craik# You may obtain a copy of the License at 7cef7893435aa41160dd1255c43cb8498279738ccChris Craik# 8cef7893435aa41160dd1255c43cb8498279738ccChris Craik# http://www.apache.org/licenses/LICENSE-2.0 9cef7893435aa41160dd1255c43cb8498279738ccChris Craik# 10cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Unless required by applicable law or agreed to in writing, software 11cef7893435aa41160dd1255c43cb8498279738ccChris Craik# distributed under the License is distributed on an "AS-IS" BASIS, 12cef7893435aa41160dd1255c43cb8498279738ccChris Craik# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cef7893435aa41160dd1255c43cb8498279738ccChris Craik# See the License for the specific language governing permissions and 14cef7893435aa41160dd1255c43cb8498279738ccChris Craik# limitations under the License. 15cef7893435aa41160dd1255c43cb8498279738ccChris Craik 16cef7893435aa41160dd1255c43cb8498279738ccChris Craik"""Pass that scans for goog.scope aliases and lint/usage errors.""" 17cef7893435aa41160dd1255c43cb8498279738ccChris Craik 18cef7893435aa41160dd1255c43cb8498279738ccChris Craik# Allow non-Google copyright 19cef7893435aa41160dd1255c43cb8498279738ccChris Craik# pylint: disable=g-bad-file-header 20cef7893435aa41160dd1255c43cb8498279738ccChris Craik 21cef7893435aa41160dd1255c43cb8498279738ccChris Craik__author__ = ('nnaze@google.com (Nathan Naze)') 22cef7893435aa41160dd1255c43cb8498279738ccChris Craik 23cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom closure_linter import ecmametadatapass 24cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom closure_linter import errors 25cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom closure_linter import javascripttokens 26cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom closure_linter import scopeutil 27cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom closure_linter import tokenutil 28cef7893435aa41160dd1255c43cb8498279738ccChris Craikfrom closure_linter.common import error 29cef7893435aa41160dd1255c43cb8498279738ccChris Craik 30cef7893435aa41160dd1255c43cb8498279738ccChris Craik 31cef7893435aa41160dd1255c43cb8498279738ccChris Craik# TODO(nnaze): Create a Pass interface and move this class, EcmaMetaDataPass, 32cef7893435aa41160dd1255c43cb8498279738ccChris Craik# and related classes onto it. 33cef7893435aa41160dd1255c43cb8498279738ccChris Craik 34cef7893435aa41160dd1255c43cb8498279738ccChris Craik 35cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef _GetAliasForIdentifier(identifier, alias_map): 36cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Returns the aliased_symbol name for an identifier. 37cef7893435aa41160dd1255c43cb8498279738ccChris Craik 38cef7893435aa41160dd1255c43cb8498279738ccChris Craik Example usage: 39cef7893435aa41160dd1255c43cb8498279738ccChris Craik >>> alias_map = {'MyClass': 'goog.foo.MyClass'} 40cef7893435aa41160dd1255c43cb8498279738ccChris Craik >>> _GetAliasForIdentifier('MyClass.prototype.action', alias_map) 41cef7893435aa41160dd1255c43cb8498279738ccChris Craik 'goog.foo.MyClass.prototype.action' 42cef7893435aa41160dd1255c43cb8498279738ccChris Craik 43cef7893435aa41160dd1255c43cb8498279738ccChris Craik >>> _GetAliasForIdentifier('MyClass.prototype.action', {}) 44cef7893435aa41160dd1255c43cb8498279738ccChris Craik None 45cef7893435aa41160dd1255c43cb8498279738ccChris Craik 46cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 47cef7893435aa41160dd1255c43cb8498279738ccChris Craik identifier: The identifier. 48cef7893435aa41160dd1255c43cb8498279738ccChris Craik alias_map: A dictionary mapping a symbol to an alias. 49cef7893435aa41160dd1255c43cb8498279738ccChris Craik 50cef7893435aa41160dd1255c43cb8498279738ccChris Craik Returns: 51cef7893435aa41160dd1255c43cb8498279738ccChris Craik The aliased symbol name or None if not found. 52cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 53cef7893435aa41160dd1255c43cb8498279738ccChris Craik ns = identifier.split('.', 1)[0] 54cef7893435aa41160dd1255c43cb8498279738ccChris Craik aliased_symbol = alias_map.get(ns) 55cef7893435aa41160dd1255c43cb8498279738ccChris Craik if aliased_symbol: 56cef7893435aa41160dd1255c43cb8498279738ccChris Craik return aliased_symbol + identifier[len(ns):] 57cef7893435aa41160dd1255c43cb8498279738ccChris Craik 58cef7893435aa41160dd1255c43cb8498279738ccChris Craik 59cef7893435aa41160dd1255c43cb8498279738ccChris Craikdef _SetTypeAlias(js_type, alias_map): 60cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Updates the alias for identifiers in a type. 61cef7893435aa41160dd1255c43cb8498279738ccChris Craik 62cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 63cef7893435aa41160dd1255c43cb8498279738ccChris Craik js_type: A typeannotation.TypeAnnotation instance. 64cef7893435aa41160dd1255c43cb8498279738ccChris Craik alias_map: A dictionary mapping a symbol to an alias. 65cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 66cef7893435aa41160dd1255c43cb8498279738ccChris Craik aliased_symbol = _GetAliasForIdentifier(js_type.identifier, alias_map) 67cef7893435aa41160dd1255c43cb8498279738ccChris Craik if aliased_symbol: 68cef7893435aa41160dd1255c43cb8498279738ccChris Craik js_type.alias = aliased_symbol 69cef7893435aa41160dd1255c43cb8498279738ccChris Craik for sub_type in js_type.IterTypes(): 70cef7893435aa41160dd1255c43cb8498279738ccChris Craik _SetTypeAlias(sub_type, alias_map) 71cef7893435aa41160dd1255c43cb8498279738ccChris Craik 72cef7893435aa41160dd1255c43cb8498279738ccChris Craik 73cef7893435aa41160dd1255c43cb8498279738ccChris Craikclass AliasPass(object): 74cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Pass to identify goog.scope() usages. 75cef7893435aa41160dd1255c43cb8498279738ccChris Craik 76cef7893435aa41160dd1255c43cb8498279738ccChris Craik Identifies goog.scope() usages and finds lint/usage errors. Notes any 77cef7893435aa41160dd1255c43cb8498279738ccChris Craik aliases of symbols in Closurized namespaces (that is, reassignments 78cef7893435aa41160dd1255c43cb8498279738ccChris Craik such as "var MyClass = goog.foo.MyClass;") and annotates identifiers 79cef7893435aa41160dd1255c43cb8498279738ccChris Craik when they're using an alias (so they may be expanded to the full symbol 80cef7893435aa41160dd1255c43cb8498279738ccChris Craik later -- that "MyClass.prototype.action" refers to 81cef7893435aa41160dd1255c43cb8498279738ccChris Craik "goog.foo.MyClass.prototype.action" when expanded.). 82cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 83cef7893435aa41160dd1255c43cb8498279738ccChris Craik 84cef7893435aa41160dd1255c43cb8498279738ccChris Craik def __init__(self, closurized_namespaces=None, error_handler=None): 85cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Creates a new pass. 86cef7893435aa41160dd1255c43cb8498279738ccChris Craik 87cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 88cef7893435aa41160dd1255c43cb8498279738ccChris Craik closurized_namespaces: A set of Closurized namespaces (e.g. 'goog'). 89cef7893435aa41160dd1255c43cb8498279738ccChris Craik error_handler: An error handler to report lint errors to. 90cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 91cef7893435aa41160dd1255c43cb8498279738ccChris Craik 92cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._error_handler = error_handler 93cef7893435aa41160dd1255c43cb8498279738ccChris Craik 94cef7893435aa41160dd1255c43cb8498279738ccChris Craik # If we have namespaces, freeze the set. 95cef7893435aa41160dd1255c43cb8498279738ccChris Craik if closurized_namespaces: 96cef7893435aa41160dd1255c43cb8498279738ccChris Craik closurized_namespaces = frozenset(closurized_namespaces) 97cef7893435aa41160dd1255c43cb8498279738ccChris Craik 98cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._closurized_namespaces = closurized_namespaces 99cef7893435aa41160dd1255c43cb8498279738ccChris Craik 100cef7893435aa41160dd1255c43cb8498279738ccChris Craik def Process(self, start_token): 101cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Runs the pass on a token stream. 102cef7893435aa41160dd1255c43cb8498279738ccChris Craik 103cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 104cef7893435aa41160dd1255c43cb8498279738ccChris Craik start_token: The first token in the stream. 105cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 106cef7893435aa41160dd1255c43cb8498279738ccChris Craik 107cef7893435aa41160dd1255c43cb8498279738ccChris Craik if start_token is None: 108cef7893435aa41160dd1255c43cb8498279738ccChris Craik return 109cef7893435aa41160dd1255c43cb8498279738ccChris Craik 110cef7893435aa41160dd1255c43cb8498279738ccChris Craik # TODO(nnaze): Add more goog.scope usage checks. 111cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._CheckGoogScopeCalls(start_token) 112cef7893435aa41160dd1255c43cb8498279738ccChris Craik 113cef7893435aa41160dd1255c43cb8498279738ccChris Craik # If we have closurized namespaces, identify aliased identifiers. 114cef7893435aa41160dd1255c43cb8498279738ccChris Craik if self._closurized_namespaces: 115cef7893435aa41160dd1255c43cb8498279738ccChris Craik context = start_token.metadata.context 116cef7893435aa41160dd1255c43cb8498279738ccChris Craik root_context = context.GetRoot() 117cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._ProcessRootContext(root_context) 118cef7893435aa41160dd1255c43cb8498279738ccChris Craik 119cef7893435aa41160dd1255c43cb8498279738ccChris Craik def _CheckGoogScopeCalls(self, start_token): 120cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Check goog.scope calls for lint/usage errors.""" 121cef7893435aa41160dd1255c43cb8498279738ccChris Craik 122cef7893435aa41160dd1255c43cb8498279738ccChris Craik def IsScopeToken(token): 123cef7893435aa41160dd1255c43cb8498279738ccChris Craik return (token.type is javascripttokens.JavaScriptTokenType.IDENTIFIER and 124cef7893435aa41160dd1255c43cb8498279738ccChris Craik token.string == 'goog.scope') 125cef7893435aa41160dd1255c43cb8498279738ccChris Craik 126cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Find all the goog.scope tokens in the file 127cef7893435aa41160dd1255c43cb8498279738ccChris Craik scope_tokens = [t for t in start_token if IsScopeToken(t)] 128cef7893435aa41160dd1255c43cb8498279738ccChris Craik 129cef7893435aa41160dd1255c43cb8498279738ccChris Craik for token in scope_tokens: 130cef7893435aa41160dd1255c43cb8498279738ccChris Craik scope_context = token.metadata.context 131cef7893435aa41160dd1255c43cb8498279738ccChris Craik 132cef7893435aa41160dd1255c43cb8498279738ccChris Craik if not (scope_context.type == ecmametadatapass.EcmaContext.STATEMENT and 133cef7893435aa41160dd1255c43cb8498279738ccChris Craik scope_context.parent.type == ecmametadatapass.EcmaContext.ROOT): 134cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._MaybeReportError( 135cef7893435aa41160dd1255c43cb8498279738ccChris Craik error.Error(errors.INVALID_USE_OF_GOOG_SCOPE, 136cef7893435aa41160dd1255c43cb8498279738ccChris Craik 'goog.scope call not in global scope', token)) 137cef7893435aa41160dd1255c43cb8498279738ccChris Craik 138cef7893435aa41160dd1255c43cb8498279738ccChris Craik # There should be only one goog.scope reference. Register errors for 139cef7893435aa41160dd1255c43cb8498279738ccChris Craik # every instance after the first. 140cef7893435aa41160dd1255c43cb8498279738ccChris Craik for token in scope_tokens[1:]: 141cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._MaybeReportError( 142cef7893435aa41160dd1255c43cb8498279738ccChris Craik error.Error(errors.EXTRA_GOOG_SCOPE_USAGE, 143cef7893435aa41160dd1255c43cb8498279738ccChris Craik 'More than one goog.scope call in file.', token)) 144cef7893435aa41160dd1255c43cb8498279738ccChris Craik 145cef7893435aa41160dd1255c43cb8498279738ccChris Craik def _MaybeReportError(self, err): 146cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Report an error to the handler (if registered).""" 147cef7893435aa41160dd1255c43cb8498279738ccChris Craik if self._error_handler: 148cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._error_handler.HandleError(err) 149cef7893435aa41160dd1255c43cb8498279738ccChris Craik 150cef7893435aa41160dd1255c43cb8498279738ccChris Craik @classmethod 151cef7893435aa41160dd1255c43cb8498279738ccChris Craik def _YieldAllContexts(cls, context): 152cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Yields all contexts that are contained by the given context.""" 153cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield context 154cef7893435aa41160dd1255c43cb8498279738ccChris Craik for child_context in context.children: 155cef7893435aa41160dd1255c43cb8498279738ccChris Craik for descendent_child in cls._YieldAllContexts(child_context): 156cef7893435aa41160dd1255c43cb8498279738ccChris Craik yield descendent_child 157cef7893435aa41160dd1255c43cb8498279738ccChris Craik 158cef7893435aa41160dd1255c43cb8498279738ccChris Craik @staticmethod 159cef7893435aa41160dd1255c43cb8498279738ccChris Craik def _IsTokenInParentBlock(token, parent_block): 160cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Determines whether the given token is contained by the given block. 161cef7893435aa41160dd1255c43cb8498279738ccChris Craik 162cef7893435aa41160dd1255c43cb8498279738ccChris Craik Args: 163cef7893435aa41160dd1255c43cb8498279738ccChris Craik token: A token 164cef7893435aa41160dd1255c43cb8498279738ccChris Craik parent_block: An EcmaContext. 165cef7893435aa41160dd1255c43cb8498279738ccChris Craik 166cef7893435aa41160dd1255c43cb8498279738ccChris Craik Returns: 167cef7893435aa41160dd1255c43cb8498279738ccChris Craik Whether the token is in a context that is or is a child of the given 168cef7893435aa41160dd1255c43cb8498279738ccChris Craik parent_block context. 169cef7893435aa41160dd1255c43cb8498279738ccChris Craik """ 170cef7893435aa41160dd1255c43cb8498279738ccChris Craik context = token.metadata.context 171cef7893435aa41160dd1255c43cb8498279738ccChris Craik 172cef7893435aa41160dd1255c43cb8498279738ccChris Craik while context: 173cef7893435aa41160dd1255c43cb8498279738ccChris Craik if context is parent_block: 174cef7893435aa41160dd1255c43cb8498279738ccChris Craik return True 175cef7893435aa41160dd1255c43cb8498279738ccChris Craik context = context.parent 176cef7893435aa41160dd1255c43cb8498279738ccChris Craik 177cef7893435aa41160dd1255c43cb8498279738ccChris Craik return False 178cef7893435aa41160dd1255c43cb8498279738ccChris Craik 179cef7893435aa41160dd1255c43cb8498279738ccChris Craik def _ProcessRootContext(self, root_context): 180cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Processes all goog.scope blocks under the root context.""" 181cef7893435aa41160dd1255c43cb8498279738ccChris Craik 182cef7893435aa41160dd1255c43cb8498279738ccChris Craik assert root_context.type is ecmametadatapass.EcmaContext.ROOT 183cef7893435aa41160dd1255c43cb8498279738ccChris Craik 184cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Process aliases in statements in the root scope for goog.module-style 185cef7893435aa41160dd1255c43cb8498279738ccChris Craik # aliases. 186cef7893435aa41160dd1255c43cb8498279738ccChris Craik global_alias_map = {} 187cef7893435aa41160dd1255c43cb8498279738ccChris Craik for context in root_context.children: 188cef7893435aa41160dd1255c43cb8498279738ccChris Craik if context.type == ecmametadatapass.EcmaContext.STATEMENT: 189cef7893435aa41160dd1255c43cb8498279738ccChris Craik for statement_child in context.children: 190cef7893435aa41160dd1255c43cb8498279738ccChris Craik if statement_child.type == ecmametadatapass.EcmaContext.VAR: 191cef7893435aa41160dd1255c43cb8498279738ccChris Craik match = scopeutil.MatchModuleAlias(statement_child) 192cef7893435aa41160dd1255c43cb8498279738ccChris Craik if match: 193cef7893435aa41160dd1255c43cb8498279738ccChris Craik # goog.require aliases cannot use further aliases, the symbol is 194cef7893435aa41160dd1255c43cb8498279738ccChris Craik # the second part of match, directly. 195cef7893435aa41160dd1255c43cb8498279738ccChris Craik symbol = match[1] 196cef7893435aa41160dd1255c43cb8498279738ccChris Craik if scopeutil.IsInClosurizedNamespace(symbol, 197cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._closurized_namespaces): 198cef7893435aa41160dd1255c43cb8498279738ccChris Craik global_alias_map[match[0]] = symbol 199cef7893435aa41160dd1255c43cb8498279738ccChris Craik 200cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Process each block to find aliases. 201cef7893435aa41160dd1255c43cb8498279738ccChris Craik for context in root_context.children: 202cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._ProcessBlock(context, global_alias_map) 203cef7893435aa41160dd1255c43cb8498279738ccChris Craik 204cef7893435aa41160dd1255c43cb8498279738ccChris Craik def _ProcessBlock(self, context, global_alias_map): 205cef7893435aa41160dd1255c43cb8498279738ccChris Craik """Scans a goog.scope block to find aliases and mark alias tokens.""" 206cef7893435aa41160dd1255c43cb8498279738ccChris Craik alias_map = global_alias_map.copy() 207cef7893435aa41160dd1255c43cb8498279738ccChris Craik 208cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Iterate over every token in the context. Each token points to one 209cef7893435aa41160dd1255c43cb8498279738ccChris Craik # context, but multiple tokens may point to the same context. We only want 210cef7893435aa41160dd1255c43cb8498279738ccChris Craik # to check each context once, so keep track of those we've seen. 211cef7893435aa41160dd1255c43cb8498279738ccChris Craik seen_contexts = set() 212cef7893435aa41160dd1255c43cb8498279738ccChris Craik token = context.start_token 213cef7893435aa41160dd1255c43cb8498279738ccChris Craik while token and self._IsTokenInParentBlock(token, context): 214cef7893435aa41160dd1255c43cb8498279738ccChris Craik token_context = token.metadata.context if token.metadata else None 215cef7893435aa41160dd1255c43cb8498279738ccChris Craik 216cef7893435aa41160dd1255c43cb8498279738ccChris Craik # Check to see if this token is an alias. 217cef7893435aa41160dd1255c43cb8498279738ccChris Craik if token_context and token_context not in seen_contexts: 218cef7893435aa41160dd1255c43cb8498279738ccChris Craik seen_contexts.add(token_context) 219cef7893435aa41160dd1255c43cb8498279738ccChris Craik 220cef7893435aa41160dd1255c43cb8498279738ccChris Craik # If this is a alias statement in the goog.scope block. 221cef7893435aa41160dd1255c43cb8498279738ccChris Craik if (token_context.type == ecmametadatapass.EcmaContext.VAR and 222cef7893435aa41160dd1255c43cb8498279738ccChris Craik scopeutil.IsGoogScopeBlock(token_context.parent.parent)): 223cef7893435aa41160dd1255c43cb8498279738ccChris Craik match = scopeutil.MatchAlias(token_context) 224cef7893435aa41160dd1255c43cb8498279738ccChris Craik 225cef7893435aa41160dd1255c43cb8498279738ccChris Craik # If this is an alias, remember it in the map. 226cef7893435aa41160dd1255c43cb8498279738ccChris Craik if match: 227cef7893435aa41160dd1255c43cb8498279738ccChris Craik alias, symbol = match 228cef7893435aa41160dd1255c43cb8498279738ccChris Craik symbol = _GetAliasForIdentifier(symbol, alias_map) or symbol 229cef7893435aa41160dd1255c43cb8498279738ccChris Craik if scopeutil.IsInClosurizedNamespace(symbol, 230cef7893435aa41160dd1255c43cb8498279738ccChris Craik self._closurized_namespaces): 231cef7893435aa41160dd1255c43cb8498279738ccChris Craik alias_map[alias] = symbol 232cef7893435aa41160dd1255c43cb8498279738ccChris Craik 233cef7893435aa41160dd1255c43cb8498279738ccChris Craik # If this token is an identifier that matches an alias, 234cef7893435aa41160dd1255c43cb8498279738ccChris Craik # mark the token as an alias to the original symbol. 235cef7893435aa41160dd1255c43cb8498279738ccChris Craik if (token.type is javascripttokens.JavaScriptTokenType.SIMPLE_LVALUE or 236cef7893435aa41160dd1255c43cb8498279738ccChris Craik token.type is javascripttokens.JavaScriptTokenType.IDENTIFIER): 237cef7893435aa41160dd1255c43cb8498279738ccChris Craik identifier = tokenutil.GetIdentifierForToken(token) 238cef7893435aa41160dd1255c43cb8498279738ccChris Craik if identifier: 239cef7893435aa41160dd1255c43cb8498279738ccChris Craik aliased_symbol = _GetAliasForIdentifier(identifier, alias_map) 240cef7893435aa41160dd1255c43cb8498279738ccChris Craik if aliased_symbol: 241cef7893435aa41160dd1255c43cb8498279738ccChris Craik token.metadata.aliased_symbol = aliased_symbol 242cef7893435aa41160dd1255c43cb8498279738ccChris Craik 243cef7893435aa41160dd1255c43cb8498279738ccChris Craik elif token.type == javascripttokens.JavaScriptTokenType.DOC_FLAG: 244cef7893435aa41160dd1255c43cb8498279738ccChris Craik flag = token.attached_object 245cef7893435aa41160dd1255c43cb8498279738ccChris Craik if flag and flag.HasType() and flag.jstype: 246cef7893435aa41160dd1255c43cb8498279738ccChris Craik _SetTypeAlias(flag.jstype, alias_map) 247cef7893435aa41160dd1255c43cb8498279738ccChris Craik 248cef7893435aa41160dd1255c43cb8498279738ccChris Craik token = token.next # Get next token 249