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