15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#!/usr/bin/env python
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Copyright 2012 The Closure Linter Authors. All Rights Reserved.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the "License");
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# you may not use this file except in compliance with the License.
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# You may obtain a copy of the License at
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#      http://www.apache.org/licenses/LICENSE-2.0
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Unless required by applicable law or agreed to in writing, software
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# distributed under the License is distributed on an "AS-IS" BASIS,
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# See the License for the specific language governing permissions and
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# limitations under the License.
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""Pass that scans for goog.scope aliases and lint/usage errors."""
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Allow non-Google copyright
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# pylint: disable=g-bad-file-header
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)__author__ = ('nnaze@google.com (Nathan Naze)')
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import itertools
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from closure_linter import ecmametadatapass
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from closure_linter import errors
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from closure_linter import javascripttokens
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from closure_linter import scopeutil
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from closure_linter import tokenutil
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from closure_linter.common import error
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# TODO(nnaze): Create a Pass interface and move this class, EcmaMetaDataPass,
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# and related classes onto it.
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def _GetAliasForIdentifier(identifier, alias_map):
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Returns the aliased_symbol name for an identifier.
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Example usage:
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    >>> alias_map = {'MyClass': 'goog.foo.MyClass'}
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    >>> _GetAliasForIdentifier('MyClass.prototype.action', alias_map)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    'goog.foo.MyClass.prototype.action'
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    >>> _GetAliasForIdentifier('MyClass.prototype.action', {})
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    None
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Args:
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    identifier: The identifier.
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    alias_map: A dictionary mapping a symbol to an alias.
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Returns:
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    The aliased symbol name or None if not found.
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ns = identifier.split('.', 1)[0]
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  aliased_symbol = alias_map.get(ns)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if aliased_symbol:
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return aliased_symbol + identifier[len(ns):]
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class AliasPass(object):
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """Pass to identify goog.scope() usages.
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Identifies goog.scope() usages and finds lint/usage errors.  Notes any
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  aliases of symbols in Closurized namespaces (that is, reassignments
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  such as "var MyClass = goog.foo.MyClass;") and annotates identifiers
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  when they're using an alias (so they may be expanded to the full symbol
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  later -- that "MyClass.prototype.action" refers to
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  "goog.foo.MyClass.prototype.action" when expanded.).
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  """
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def __init__(self, closurized_namespaces=None, error_handler=None):
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Creates a new pass.
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Args:
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      closurized_namespaces: A set of Closurized namespaces (e.g. 'goog').
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      error_handler: An error handler to report lint errors to.
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._error_handler = error_handler
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # If we have namespaces, freeze the set.
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if closurized_namespaces:
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      closurized_namespaces = frozenset(closurized_namespaces)
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._closurized_namespaces = closurized_namespaces
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def Process(self, start_token):
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Runs the pass on a token stream.
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Args:
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      start_token: The first token in the stream.
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if start_token is None:
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # TODO(nnaze): Add more goog.scope usage checks.
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._CheckGoogScopeCalls(start_token)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # If we have closurized namespaces, identify aliased identifiers.
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if self._closurized_namespaces:
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      context = start_token.metadata.context
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      root_context = context.GetRoot()
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      self._ProcessRootContext(root_context)
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _CheckGoogScopeCalls(self, start_token):
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Check goog.scope calls for lint/usage errors."""
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    def IsScopeToken(token):
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return (token.type is javascripttokens.JavaScriptTokenType.IDENTIFIER and
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              token.string == 'goog.scope')
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Find all the goog.scope tokens in the file
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    scope_tokens = [t for t in start_token if IsScopeToken(t)]
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for token in scope_tokens:
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      scope_context = token.metadata.context
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if not (scope_context.type == ecmametadatapass.EcmaContext.STATEMENT and
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              scope_context.parent.type == ecmametadatapass.EcmaContext.ROOT):
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._MaybeReportError(
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            error.Error(errors.INVALID_USE_OF_GOOG_SCOPE,
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                        'goog.scope call not in global scope', token))
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # There should be only one goog.scope reference.  Register errors for
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # every instance after the first.
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for token in scope_tokens[1:]:
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      self._MaybeReportError(
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          error.Error(errors.EXTRA_GOOG_SCOPE_USAGE,
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                      'More than one goog.scope call in file.', token))
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _MaybeReportError(self, err):
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Report an error to the handler (if registered)."""
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if self._error_handler:
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      self._error_handler.HandleError(err)
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  @classmethod
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _YieldAllContexts(cls, context):
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Yields all contexts that are contained by the given context."""
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    yield context
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for child_context in context.children:
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for descendent_child in cls._YieldAllContexts(child_context):
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        yield descendent_child
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  @staticmethod
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _IsTokenInParentBlock(token, parent_block):
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Determines whether the given token is contained by the given block.
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Args:
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      token: A token
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      parent_block: An EcmaContext.
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Returns:
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      Whether the token is in a context that is or is a child of the given
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      parent_block context.
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    context = token.metadata.context
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while context:
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if context is parent_block:
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return True
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      context = context.parent
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return False
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _ProcessRootContext(self, root_context):
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Processes all goog.scope blocks under the root context."""
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert root_context.type is ecmametadatapass.EcmaContext.ROOT
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Identify all goog.scope blocks.
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    goog_scope_blocks = itertools.ifilter(
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        scopeutil.IsGoogScopeBlock,
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        self._YieldAllContexts(root_context))
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Process each block to find aliases.
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for scope_block in goog_scope_blocks:
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      self._ProcessGoogScopeBlock(scope_block)
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def _ProcessGoogScopeBlock(self, scope_block):
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    """Scans a goog.scope block to find aliases and mark alias tokens."""
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    alias_map = dict()
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Iterate over every token in the scope_block. Each token points to one
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # context, but multiple tokens may point to the same context. We only want
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # to check each context once, so keep track of those we've seen.
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    seen_contexts = set()
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    token = scope_block.start_token
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    while token and self._IsTokenInParentBlock(token, scope_block):
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      token_context = token.metadata.context
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      # Check to see if this token is an alias.
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if token_context not in seen_contexts:
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        seen_contexts.add(token_context)
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        # If this is a alias statement in the goog.scope block.
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (token_context.type == ecmametadatapass.EcmaContext.VAR and
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            token_context.parent.parent is scope_block):
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          match = scopeutil.MatchAlias(token_context)
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          # If this is an alias, remember it in the map.
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          if match:
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            alias, symbol = match
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            symbol = _GetAliasForIdentifier(symbol, alias_map) or symbol
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if scopeutil.IsInClosurizedNamespace(symbol,
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                 self._closurized_namespaces):
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              alias_map[alias] = symbol
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      # If this token is an identifier that matches an alias,
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      # mark the token as an alias to the original symbol.
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (token.type is javascripttokens.JavaScriptTokenType.SIMPLE_LVALUE or
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          token.type is javascripttokens.JavaScriptTokenType.IDENTIFIER):
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        identifier = tokenutil.GetIdentifierForToken(token)
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if identifier:
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          aliased_symbol = _GetAliasForIdentifier(identifier, alias_map)
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          if aliased_symbol:
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            token.metadata.aliased_symbol = aliased_symbol
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      token = token.next  # Get next token
223