Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1462)

Unified Diff: third_party/closure_linter/closure_linter/closurizednamespacesinfo.py

Issue 411243002: closure_linter: 2.3.4 => 2.3.14 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove checker Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/closure_linter/closure_linter/closurizednamespacesinfo.py
diff --git a/third_party/closure_linter/closure_linter/closurizednamespacesinfo.py b/third_party/closure_linter/closure_linter/closurizednamespacesinfo.py
index f2902dc31c7029f5f476c442f494fb28c93c6071..03bcf1caf34c67babd2dffb8bc52d816410bc8f1 100755
--- a/third_party/closure_linter/closure_linter/closurizednamespacesinfo.py
+++ b/third_party/closure_linter/closure_linter/closurizednamespacesinfo.py
@@ -24,17 +24,20 @@ processed to determine if they constitute the creation or usage of a dependency.
+import re
+
from closure_linter import javascripttokens
from closure_linter import tokenutil
-# pylint: disable-msg=C6409
+# pylint: disable=g-bad-name
TokenType = javascripttokens.JavaScriptTokenType
DEFAULT_EXTRA_NAMESPACES = [
- 'goog.testing.asserts',
- 'goog.testing.jsunit',
+ 'goog.testing.asserts',
+ 'goog.testing.jsunit',
]
+
class ClosurizedNamespacesInfo(object):
"""Dependency information for closurized JavaScript files.
@@ -79,11 +82,13 @@ class ClosurizedNamespacesInfo(object):
# two lists would only have to contain namespaces.
# A list of tuples where the first element is the namespace of an identifier
- # created in the file and the second is the identifier itself.
+ # created in the file, the second is the identifier itself and the third is
+ # the line number where it's created.
self._created_namespaces = []
# A list of tuples where the first element is the namespace of an identifier
- # used in the file and the second is the identifier itself.
+ # used in the file, the second is the identifier itself and the third is the
+ # line number where it's used.
self._used_namespaces = []
# A list of seemingly-unnecessary namespaces that are goog.required() and
@@ -111,7 +116,7 @@ class ClosurizedNamespacesInfo(object):
A list of strings where each string is a 'namespace' corresponding to an
existing goog.provide statement in the file being checked.
"""
- return list(self._provided_namespaces)
+ return set(self._provided_namespaces)
def GetRequiredNamespaces(self):
"""Returns the namespaces which are already required by this file.
@@ -120,7 +125,7 @@ class ClosurizedNamespacesInfo(object):
A list of strings where each string is a 'namespace' corresponding to an
existing goog.require statement in the file being checked.
"""
- return list(self._required_namespaces)
+ return set(self._required_namespaces)
def IsExtraProvide(self, token):
"""Returns whether the given goog.provide token is unnecessary.
@@ -132,10 +137,7 @@ class ClosurizedNamespacesInfo(object):
True if the given token corresponds to an unnecessary goog.provide
statement, otherwise False.
"""
- if self._scopified_file:
- return False
-
- namespace = tokenutil.Search(token, TokenType.STRING_TEXT).string
+ namespace = tokenutil.GetStringAfterToken(token)
base_namespace = namespace.split('.', 1)[0]
if base_namespace not in self._closurized_namespaces:
@@ -145,7 +147,7 @@ class ClosurizedNamespacesInfo(object):
return True
# TODO(user): There's probably a faster way to compute this.
- for created_namespace, created_identifier in self._created_namespaces:
+ for created_namespace, created_identifier, _ in self._created_namespaces:
if namespace == created_namespace or namespace == created_identifier:
return False
@@ -161,10 +163,7 @@ class ClosurizedNamespacesInfo(object):
True if the given token corresponds to an unnecessary goog.require
statement, otherwise False.
"""
- if self._scopified_file:
- return False
-
- namespace = tokenutil.Search(token, TokenType.STRING_TEXT).string
+ namespace = tokenutil.GetStringAfterToken(token)
base_namespace = namespace.split('.', 1)[0]
if base_namespace not in self._closurized_namespaces:
@@ -186,34 +185,33 @@ class ClosurizedNamespacesInfo(object):
return True
# TODO(user): There's probably a faster way to compute this.
- for used_namespace, used_identifier in self._used_namespaces:
+ for used_namespace, used_identifier, _ in self._used_namespaces:
if namespace == used_namespace or namespace == used_identifier:
return False
return True
def GetMissingProvides(self):
- """Returns the set of missing provided namespaces for the current file.
+ """Returns the dict of missing provided namespaces for the current file.
Returns:
- Returns a set of strings where each string is a namespace that should be
- provided by this file, but is not.
+ Returns a dictionary of key as string and value as integer where each
+ string(key) is a namespace that should be provided by this file, but is
+ not and integer(value) is first line number where it's defined.
"""
- if self._scopified_file:
- return set()
-
- missing_provides = set()
- for namespace, identifier in self._created_namespaces:
+ missing_provides = dict()
+ for namespace, identifier, line_number in self._created_namespaces:
if (not self._IsPrivateIdentifier(identifier) and
namespace not in self._provided_namespaces and
identifier not in self._provided_namespaces and
- namespace not in self._required_namespaces):
- missing_provides.add(namespace)
+ namespace not in self._required_namespaces and
+ namespace not in missing_provides):
+ missing_provides[namespace] = line_number
return missing_provides
def GetMissingRequires(self):
- """Returns the set of missing required namespaces for the current file.
+ """Returns the dict of missing required namespaces for the current file.
For each non-private identifier used in the file, find either a
goog.require, goog.provide or a created identifier that satisfies it.
@@ -227,29 +225,28 @@ class ClosurizedNamespacesInfo(object):
can't always detect the creation of the namespace.
Returns:
- Returns a set of strings where each string is a namespace that should be
- required by this file, but is not.
+ Returns a dictionary of key as string and value integer where each
+ string(key) is a namespace that should be required by this file, but is
+ not and integer(value) is first line number where it's used.
"""
- if self._scopified_file:
- return set()
-
external_dependencies = set(self._required_namespaces)
# Assume goog namespace is always available.
external_dependencies.add('goog')
created_identifiers = set()
- for namespace, identifier in self._created_namespaces:
+ for namespace, identifier, line_number in self._created_namespaces:
created_identifiers.add(identifier)
- missing_requires = set()
- for namespace, identifier in self._used_namespaces:
+ missing_requires = dict()
+ for namespace, identifier, line_number in self._used_namespaces:
if (not self._IsPrivateIdentifier(identifier) and
namespace not in external_dependencies and
namespace not in self._provided_namespaces and
identifier not in external_dependencies and
- identifier not in created_identifiers):
- missing_requires.add(namespace)
+ identifier not in created_identifiers and
+ namespace not in missing_requires):
+ missing_requires[namespace] = line_number
return missing_requires
@@ -295,7 +292,7 @@ class ClosurizedNamespacesInfo(object):
if token.type == TokenType.IDENTIFIER:
# TODO(user): Consider saving the whole identifier in metadata.
- whole_identifier_string = self._GetWholeIdentifierString(token)
+ whole_identifier_string = tokenutil.GetIdentifierForToken(token)
if whole_identifier_string is None:
# We only want to process the identifier one time. If the whole string
# identifier is None, that means this token was part of a multi-token
@@ -306,7 +303,7 @@ class ClosurizedNamespacesInfo(object):
# just ignore it (e.g. dynamic loading in test runners).
if token.string == 'goog.require' and not state_tracker.InFunction():
self._require_tokens.append(token)
- namespace = tokenutil.Search(token, TokenType.STRING_TEXT).string
+ namespace = tokenutil.GetStringAfterToken(token)
if namespace in self._required_namespaces:
self._duplicate_require_tokens.append(token)
else:
@@ -317,11 +314,11 @@ class ClosurizedNamespacesInfo(object):
jsdoc = state_tracker.GetDocComment()
if jsdoc and ('extraRequire' in jsdoc.suppressions):
self._suppressed_requires.append(namespace)
- self._AddUsedNamespace(state_tracker, namespace)
+ self._AddUsedNamespace(state_tracker, namespace, token.line_number)
elif token.string == 'goog.provide':
self._provide_tokens.append(token)
- namespace = tokenutil.Search(token, TokenType.STRING_TEXT).string
+ namespace = tokenutil.GetStringAfterToken(token)
if namespace in self._provided_namespaces:
self._duplicate_provide_tokens.append(token)
else:
@@ -331,27 +328,63 @@ class ClosurizedNamespacesInfo(object):
# gets treated as a regular goog.provide (i.e. still gets sorted).
jsdoc = state_tracker.GetDocComment()
if jsdoc and ('extraProvide' in jsdoc.suppressions):
- self._AddCreatedNamespace(state_tracker, namespace)
+ self._AddCreatedNamespace(state_tracker, namespace, token.line_number)
elif token.string == 'goog.scope':
self._scopified_file = True
+ elif token.string == 'goog.setTestOnly':
+
+ # Since the message is optional, we don't want to scan to later lines.
+ for t in tokenutil.GetAllTokensInSameLine(token):
+ if t.type == TokenType.STRING_TEXT:
+ message = t.string
+
+ if re.match(r'^\w+(\.\w+)+$', message):
+ # This looks like a namespace. If it's a Closurized namespace,
+ # consider it created.
+ base_namespace = message.split('.', 1)[0]
+ if base_namespace in self._closurized_namespaces:
+ self._AddCreatedNamespace(state_tracker, message,
+ token.line_number)
+
+ break
else:
jsdoc = state_tracker.GetDocComment()
+ if token.metadata and token.metadata.aliased_symbol:
+ whole_identifier_string = token.metadata.aliased_symbol
if jsdoc and jsdoc.HasFlag('typedef'):
self._AddCreatedNamespace(state_tracker, whole_identifier_string,
- self.GetClosurizedNamespace(
+ token.line_number,
+ namespace=self.GetClosurizedNamespace(
whole_identifier_string))
else:
- self._AddUsedNamespace(state_tracker, whole_identifier_string)
+ if not (token.metadata and token.metadata.is_alias_definition):
+ self._AddUsedNamespace(state_tracker, whole_identifier_string,
+ token.line_number)
elif token.type == TokenType.SIMPLE_LVALUE:
identifier = token.values['identifier']
- namespace = self.GetClosurizedNamespace(identifier)
- if state_tracker.InFunction():
- self._AddUsedNamespace(state_tracker, identifier)
- elif namespace and namespace != 'goog':
- self._AddCreatedNamespace(state_tracker, identifier, namespace)
+ start_token = tokenutil.GetIdentifierStart(token)
+ if start_token and start_token != token:
+ # Multi-line identifier being assigned. Get the whole identifier.
+ identifier = tokenutil.GetIdentifierForToken(start_token)
+ else:
+ start_token = token
+ # If an alias is defined on the start_token, use it instead.
+ if (start_token and
+ start_token.metadata and
+ start_token.metadata.aliased_symbol and
+ not start_token.metadata.is_alias_definition):
+ identifier = start_token.metadata.aliased_symbol
+
+ if identifier:
+ namespace = self.GetClosurizedNamespace(identifier)
+ if state_tracker.InFunction():
+ self._AddUsedNamespace(state_tracker, identifier, token.line_number)
+ elif namespace and namespace != 'goog':
+ self._AddCreatedNamespace(state_tracker, identifier,
+ token.line_number, namespace=namespace)
elif token.type == TokenType.DOC_FLAG:
flag_type = token.attached_object.flag_type
@@ -360,53 +393,11 @@ class ClosurizedNamespacesInfo(object):
# Interfaces should be goog.require'd.
doc_start = tokenutil.Search(token, TokenType.DOC_START_BRACE)
interface = tokenutil.Search(doc_start, TokenType.COMMENT)
- self._AddUsedNamespace(state_tracker, interface.string)
-
-
- def _GetWholeIdentifierString(self, token):
- """Returns the whole identifier string for the given token.
-
- Checks the tokens after the current one to see if the token is one in a
- sequence of tokens which are actually just one identifier (i.e. a line was
- wrapped in the middle of an identifier).
+ self._AddUsedNamespace(state_tracker, interface.string,
+ token.line_number)
- Args:
- token: The token to check.
-
- Returns:
- The whole identifier string or None if this token is not the first token
- in a multi-token identifier.
- """
- result = ''
-
- # Search backward to determine if this token is the first token of the
- # identifier. If it is not the first token, return None to signal that this
- # token should be ignored.
- prev_token = token.previous
- while prev_token:
- if (prev_token.IsType(TokenType.IDENTIFIER) or
- prev_token.IsType(TokenType.NORMAL) and prev_token.string == '.'):
- return None
- elif (not prev_token.IsType(TokenType.WHITESPACE) and
- not prev_token.IsAnyType(TokenType.COMMENT_TYPES)):
- break
- prev_token = prev_token.previous
-
- # Search forward to find other parts of this identifier separated by white
- # space.
- next_token = token
- while next_token:
- if (next_token.IsType(TokenType.IDENTIFIER) or
- next_token.IsType(TokenType.NORMAL) and next_token.string == '.'):
- result += next_token.string
- elif (not next_token.IsType(TokenType.WHITESPACE) and
- not next_token.IsAnyType(TokenType.COMMENT_TYPES)):
- break
- next_token = next_token.next
-
- return result
-
- def _AddCreatedNamespace(self, state_tracker, identifier, namespace=None):
+ def _AddCreatedNamespace(self, state_tracker, identifier, line_number,
+ namespace=None):
"""Adds the namespace of an identifier to the list of created namespaces.
If the identifier is annotated with a 'missingProvide' suppression, it is
@@ -415,6 +406,7 @@ class ClosurizedNamespacesInfo(object):
Args:
state_tracker: The JavaScriptStateTracker instance.
identifier: The identifier to add.
+ line_number: Line number where namespace is created.
namespace: The namespace of the identifier or None if the identifier is
also the namespace.
"""
@@ -425,9 +417,9 @@ class ClosurizedNamespacesInfo(object):
if jsdoc and 'missingProvide' in jsdoc.suppressions:
return
- self._created_namespaces.append([namespace, identifier])
+ self._created_namespaces.append([namespace, identifier, line_number])
- def _AddUsedNamespace(self, state_tracker, identifier):
+ def _AddUsedNamespace(self, state_tracker, identifier, line_number):
"""Adds the namespace of an identifier to the list of used namespaces.
If the identifier is annotated with a 'missingRequire' suppression, it is
@@ -436,14 +428,16 @@ class ClosurizedNamespacesInfo(object):
Args:
state_tracker: The JavaScriptStateTracker instance.
identifier: An identifier which has been used.
+ line_number: Line number where namespace is used.
"""
jsdoc = state_tracker.GetDocComment()
if jsdoc and 'missingRequire' in jsdoc.suppressions:
return
namespace = self.GetClosurizedNamespace(identifier)
- if namespace:
- self._used_namespaces.append([namespace, identifier])
+ # b/5362203 If its a variable in scope then its not a required namespace.
+ if namespace and not state_tracker.IsVariableInScope(namespace):
+ self._used_namespaces.append([namespace, identifier, line_number])
def GetClosurizedNamespace(self, identifier):
"""Given an identifier, returns the namespace that identifier is from.

Powered by Google App Engine
This is Rietveld 408576698