From 27110228435bcdd1f4e81166c9c09bcd1a7988b2 Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Tue, 3 Mar 2020 11:32:46 +0000 Subject: [PATCH] [ScopeProvider][optimization] don't visit formatting information nodes --- libcst/metadata/scope_provider.py | 104 ++---------------------------- 1 file changed, 6 insertions(+), 98 deletions(-) diff --git a/libcst/metadata/scope_provider.py b/libcst/metadata/scope_provider.py index 6a8581f8..128c7fcc 100644 --- a/libcst/metadata/scope_provider.py +++ b/libcst/metadata/scope_provider.py @@ -556,7 +556,6 @@ class ComprehensionScope(LocalScope): class ScopeVisitor(cst.CSTVisitor): - # TODO: Don't provide scope for formatting nodes (semicolon, which space, etc.) # since it's probably not useful. That can makes this visitor cleaner. def __init__(self, provider: "ScopeProvider") -> None: self.provider: ScopeProvider = provider @@ -604,17 +603,6 @@ class ScopeVisitor(cst.CSTVisitor): ) self.scope.record_assignment(name_value, node) - - # visit remaining attributes - if isinstance(node, cst.Import): - remaining_attrs = [node.semicolon, node.whitespace_after_import] - else: - remaining_attrs = [node.semicolon, node.whitespace_after_import] - - for attr in remaining_attrs: - if isinstance(attr, cst.CSTNode): - attr.visit(self) - return False def visit_Import(self, node: cst.Import) -> Optional[bool]: @@ -645,19 +633,6 @@ class ScopeVisitor(cst.CSTVisitor): node.params.visit(self) node.body.visit(self) - # visit remaining attributes - for attr in [ - node.asynchronous, - node.leading_lines, - node.lines_after_decorators, - node.whitespace_after_def, - node.whitespace_after_name, - node.whitespace_before_params, - node.whitespace_before_colon, - ]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) - for decorator in node.decorators: decorator.visit(self) returns = node.returns @@ -670,16 +645,6 @@ class ScopeVisitor(cst.CSTVisitor): with self._new_scope(FunctionScope, node): node.params.visit(self) node.body.visit(self) - - # visit remaining attributes - for attr in [ - node.colon, - node.lpar, - node.rpar, - node.whitespace_after_lambda, - ]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) return False def visit_Param(self, node: cst.Param) -> Optional[bool]: @@ -690,30 +655,13 @@ class ScopeVisitor(cst.CSTVisitor): if field: field.visit(self) - # visit remaining attributes - for attr in [ - node.equal, - node.comma, - node.star, - node.whitespace_after_star, - node.whitespace_after_param, - ]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) return False def visit_Arg(self, node: cst.Arg) -> bool: # The keyword of Arg is neither an Assignment nor an Access and we explicitly don't visit it. - for attr in [ - node.value, - node.equal, - node.comma, - node.star, - node.whitespace_after_star, - node.whitespace_after_arg, - ]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) + value = node.value + if value: + value.visit(self) return False def visit_ClassDef(self, node: cst.ClassDef) -> Optional[bool]: @@ -728,39 +676,16 @@ class ScopeVisitor(cst.CSTVisitor): with self._new_scope(ClassScope, node, get_full_name_for_node(node.name)): for statement in node.body.body: statement.visit(self) - - # visit remaining attributes - for attr in [ - node.lpar, - node.rpar, - node.leading_lines, - node.lines_after_decorators, - node.whitespace_after_class, - node.whitespace_after_name, - node.whitespace_before_colon, - ]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) return False def visit_Global(self, node: cst.Global) -> Optional[bool]: for name_item in node.names: self.scope.record_global_overwrite(name_item.name.value) - - # visit remaining attributes - for attr in [node.whitespace_after_global, node.semicolon]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) return False def visit_Nonlocal(self, node: cst.Nonlocal) -> Optional[bool]: for name_item in node.names: self.scope.record_nonlocal_overwrite(name_item.name.value) - - # visit remaining attributes - for attr in [node.whitespace_after_nonlocal, node.semicolon]: - if isinstance(attr, cst.CSTNode): - attr.visit(self) return False def visit_ListComp(self, node: cst.ListComp) -> Optional[bool]: @@ -827,26 +752,6 @@ class ScopeVisitor(cst.CSTVisitor): node.value.visit(self) else: node.elt.visit(self) - - if isinstance(node, cst.ListComp): - remaining_attrs = [node.lbracket, node.rbracket, node.lpar, node.rpar] - elif isinstance(node, cst.SetComp): - remaining_attrs = [node.lbrace, node.rbrace, node.lpar, node.rpar] - elif isinstance(node, cst.DictComp): - remaining_attrs = [ - node.lbrace, - node.rbrace, - node.lpar, - node.rpar, - node.whitespace_before_colon, - node.whitespace_after_colon, - ] - else: # cst.GeneratorExp - remaining_attrs = [node.lpar, node.rpar] - - for attr in remaining_attrs: - if isinstance(attr, cst.CSTNode): - attr.visit(self) return False def infer_accesses(self) -> None: @@ -868,6 +773,9 @@ class ScopeProvider(BatchableMetadataProvider[Optional[Scope]]): more advanced static analysis. E.g. given a :class:`~libcst.FunctionDef` node, we can check the type of its Scope to figure out whether it is a class method (:class:`ClassScope`) or a regular function (:class:`GlobalScope`). + + Scope metadata is available for most node types other than formatting information nodes + (whitespace, parentheses, etc.). """ METADATA_DEPENDENCIES = (ExpressionContextProvider,)