Index: third_party/closure_linter/closure_linter/aliaspass.py |
diff --git a/third_party/closure_linter/closure_linter/aliaspass.py b/third_party/closure_linter/closure_linter/aliaspass.py |
deleted file mode 100644 |
index bb37bfa07b2d9087ecff365dceb91a6dadfac3c2..0000000000000000000000000000000000000000 |
--- a/third_party/closure_linter/closure_linter/aliaspass.py |
+++ /dev/null |
@@ -1,248 +0,0 @@ |
-#!/usr/bin/env python |
-# |
-# Copyright 2012 The Closure Linter Authors. All Rights Reserved. |
-# Licensed under the Apache License, Version 2.0 (the "License"); |
-# you may not use this file except in compliance with the License. |
-# You may obtain a copy of the License at |
-# |
-# http://www.apache.org/licenses/LICENSE-2.0 |
-# |
-# Unless required by applicable law or agreed to in writing, software |
-# distributed under the License is distributed on an "AS-IS" BASIS, |
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-# See the License for the specific language governing permissions and |
-# limitations under the License. |
- |
-"""Pass that scans for goog.scope aliases and lint/usage errors.""" |
- |
-# Allow non-Google copyright |
-# pylint: disable=g-bad-file-header |
- |
-__author__ = ('nnaze@google.com (Nathan Naze)') |
- |
-from closure_linter import ecmametadatapass |
-from closure_linter import errors |
-from closure_linter import javascripttokens |
-from closure_linter import scopeutil |
-from closure_linter import tokenutil |
-from closure_linter.common import error |
- |
- |
-# TODO(nnaze): Create a Pass interface and move this class, EcmaMetaDataPass, |
-# and related classes onto it. |
- |
- |
-def _GetAliasForIdentifier(identifier, alias_map): |
- """Returns the aliased_symbol name for an identifier. |
- |
- Example usage: |
- >>> alias_map = {'MyClass': 'goog.foo.MyClass'} |
- >>> _GetAliasForIdentifier('MyClass.prototype.action', alias_map) |
- 'goog.foo.MyClass.prototype.action' |
- |
- >>> _GetAliasForIdentifier('MyClass.prototype.action', {}) |
- None |
- |
- Args: |
- identifier: The identifier. |
- alias_map: A dictionary mapping a symbol to an alias. |
- |
- Returns: |
- The aliased symbol name or None if not found. |
- """ |
- ns = identifier.split('.', 1)[0] |
- aliased_symbol = alias_map.get(ns) |
- if aliased_symbol: |
- return aliased_symbol + identifier[len(ns):] |
- |
- |
-def _SetTypeAlias(js_type, alias_map): |
- """Updates the alias for identifiers in a type. |
- |
- Args: |
- js_type: A typeannotation.TypeAnnotation instance. |
- alias_map: A dictionary mapping a symbol to an alias. |
- """ |
- aliased_symbol = _GetAliasForIdentifier(js_type.identifier, alias_map) |
- if aliased_symbol: |
- js_type.alias = aliased_symbol |
- for sub_type in js_type.IterTypes(): |
- _SetTypeAlias(sub_type, alias_map) |
- |
- |
-class AliasPass(object): |
- """Pass to identify goog.scope() usages. |
- |
- Identifies goog.scope() usages and finds lint/usage errors. Notes any |
- aliases of symbols in Closurized namespaces (that is, reassignments |
- such as "var MyClass = goog.foo.MyClass;") and annotates identifiers |
- when they're using an alias (so they may be expanded to the full symbol |
- later -- that "MyClass.prototype.action" refers to |
- "goog.foo.MyClass.prototype.action" when expanded.). |
- """ |
- |
- def __init__(self, closurized_namespaces=None, error_handler=None): |
- """Creates a new pass. |
- |
- Args: |
- closurized_namespaces: A set of Closurized namespaces (e.g. 'goog'). |
- error_handler: An error handler to report lint errors to. |
- """ |
- |
- self._error_handler = error_handler |
- |
- # If we have namespaces, freeze the set. |
- if closurized_namespaces: |
- closurized_namespaces = frozenset(closurized_namespaces) |
- |
- self._closurized_namespaces = closurized_namespaces |
- |
- def Process(self, start_token): |
- """Runs the pass on a token stream. |
- |
- Args: |
- start_token: The first token in the stream. |
- """ |
- |
- if start_token is None: |
- return |
- |
- # TODO(nnaze): Add more goog.scope usage checks. |
- self._CheckGoogScopeCalls(start_token) |
- |
- # If we have closurized namespaces, identify aliased identifiers. |
- if self._closurized_namespaces: |
- context = start_token.metadata.context |
- root_context = context.GetRoot() |
- self._ProcessRootContext(root_context) |
- |
- def _CheckGoogScopeCalls(self, start_token): |
- """Check goog.scope calls for lint/usage errors.""" |
- |
- def IsScopeToken(token): |
- return (token.type is javascripttokens.JavaScriptTokenType.IDENTIFIER and |
- token.string == 'goog.scope') |
- |
- # Find all the goog.scope tokens in the file |
- scope_tokens = [t for t in start_token if IsScopeToken(t)] |
- |
- for token in scope_tokens: |
- scope_context = token.metadata.context |
- |
- if not (scope_context.type == ecmametadatapass.EcmaContext.STATEMENT and |
- scope_context.parent.type == ecmametadatapass.EcmaContext.ROOT): |
- self._MaybeReportError( |
- error.Error(errors.INVALID_USE_OF_GOOG_SCOPE, |
- 'goog.scope call not in global scope', token)) |
- |
- # There should be only one goog.scope reference. Register errors for |
- # every instance after the first. |
- for token in scope_tokens[1:]: |
- self._MaybeReportError( |
- error.Error(errors.EXTRA_GOOG_SCOPE_USAGE, |
- 'More than one goog.scope call in file.', token)) |
- |
- def _MaybeReportError(self, err): |
- """Report an error to the handler (if registered).""" |
- if self._error_handler: |
- self._error_handler.HandleError(err) |
- |
- @classmethod |
- def _YieldAllContexts(cls, context): |
- """Yields all contexts that are contained by the given context.""" |
- yield context |
- for child_context in context.children: |
- for descendent_child in cls._YieldAllContexts(child_context): |
- yield descendent_child |
- |
- @staticmethod |
- def _IsTokenInParentBlock(token, parent_block): |
- """Determines whether the given token is contained by the given block. |
- |
- Args: |
- token: A token |
- parent_block: An EcmaContext. |
- |
- Returns: |
- Whether the token is in a context that is or is a child of the given |
- parent_block context. |
- """ |
- context = token.metadata.context |
- |
- while context: |
- if context is parent_block: |
- return True |
- context = context.parent |
- |
- return False |
- |
- def _ProcessRootContext(self, root_context): |
- """Processes all goog.scope blocks under the root context.""" |
- |
- assert root_context.type is ecmametadatapass.EcmaContext.ROOT |
- |
- # Process aliases in statements in the root scope for goog.module-style |
- # aliases. |
- global_alias_map = {} |
- for context in root_context.children: |
- if context.type == ecmametadatapass.EcmaContext.STATEMENT: |
- for statement_child in context.children: |
- if statement_child.type == ecmametadatapass.EcmaContext.VAR: |
- match = scopeutil.MatchModuleAlias(statement_child) |
- if match: |
- # goog.require aliases cannot use further aliases, the symbol is |
- # the second part of match, directly. |
- symbol = match[1] |
- if scopeutil.IsInClosurizedNamespace(symbol, |
- self._closurized_namespaces): |
- global_alias_map[match[0]] = symbol |
- |
- # Process each block to find aliases. |
- for context in root_context.children: |
- self._ProcessBlock(context, global_alias_map) |
- |
- def _ProcessBlock(self, context, global_alias_map): |
- """Scans a goog.scope block to find aliases and mark alias tokens.""" |
- alias_map = global_alias_map.copy() |
- |
- # Iterate over every token in the context. Each token points to one |
- # context, but multiple tokens may point to the same context. We only want |
- # to check each context once, so keep track of those we've seen. |
- seen_contexts = set() |
- token = context.start_token |
- while token and self._IsTokenInParentBlock(token, context): |
- token_context = token.metadata.context if token.metadata else None |
- |
- # Check to see if this token is an alias. |
- if token_context and token_context not in seen_contexts: |
- seen_contexts.add(token_context) |
- |
- # If this is a alias statement in the goog.scope block. |
- if (token_context.type == ecmametadatapass.EcmaContext.VAR and |
- scopeutil.IsGoogScopeBlock(token_context.parent.parent)): |
- match = scopeutil.MatchAlias(token_context) |
- |
- # If this is an alias, remember it in the map. |
- if match: |
- alias, symbol = match |
- symbol = _GetAliasForIdentifier(symbol, alias_map) or symbol |
- if scopeutil.IsInClosurizedNamespace(symbol, |
- self._closurized_namespaces): |
- alias_map[alias] = symbol |
- |
- # If this token is an identifier that matches an alias, |
- # mark the token as an alias to the original symbol. |
- if (token.type is javascripttokens.JavaScriptTokenType.SIMPLE_LVALUE or |
- token.type is javascripttokens.JavaScriptTokenType.IDENTIFIER): |
- identifier = tokenutil.GetIdentifierForToken(token) |
- if identifier: |
- aliased_symbol = _GetAliasForIdentifier(identifier, alias_map) |
- if aliased_symbol: |
- token.metadata.aliased_symbol = aliased_symbol |
- |
- elif token.type == javascripttokens.JavaScriptTokenType.DOC_FLAG: |
- flag = token.attached_object |
- if flag and flag.HasType() and flag.jstype: |
- _SetTypeAlias(flag.jstype, alias_map) |
- |
- token = token.next # Get next token |