| Index: pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
|
| diff --git a/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..811aa925f59ed7771d562ec65a43b3acd6bc9bdb
|
| --- /dev/null
|
| +++ b/pkg/analyzer/lib/src/dart/analysis/referenced_names.dart
|
| @@ -0,0 +1,250 @@
|
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +import 'package:analyzer/dart/ast/ast.dart';
|
| +import 'package:analyzer/dart/ast/visitor.dart';
|
| +
|
| +/**
|
| + * Compute the set of external names referenced in the [unit].
|
| + */
|
| +Set<String> computeReferencedNames(CompilationUnit unit) {
|
| + _ReferencedNamesComputer computer = new _ReferencedNamesComputer();
|
| + unit.accept(computer);
|
| + return computer.names;
|
| +}
|
| +
|
| +/**
|
| + * Chained set of local names, that hide corresponding external names.
|
| + */
|
| +class _LocalNameScope {
|
| + final _LocalNameScope enclosing;
|
| + Set<String> names;
|
| +
|
| + _LocalNameScope(this.enclosing);
|
| +
|
| + factory _LocalNameScope.forBlock(_LocalNameScope enclosing, Block node) {
|
| + _LocalNameScope scope = new _LocalNameScope(enclosing);
|
| + for (Statement statement in node.statements) {
|
| + if (statement is FunctionDeclarationStatement) {
|
| + scope.add(statement.functionDeclaration.name);
|
| + } else if (statement is VariableDeclarationStatement) {
|
| + scope.addVariableNames(statement.variables);
|
| + }
|
| + }
|
| + return scope;
|
| + }
|
| +
|
| + factory _LocalNameScope.forClass(
|
| + _LocalNameScope enclosing, ClassDeclaration node) {
|
| + _LocalNameScope scope = new _LocalNameScope(enclosing);
|
| + scope.addTypeParameters(node.typeParameters);
|
| + for (ClassMember member in node.members) {
|
| + if (member is FieldDeclaration) {
|
| + scope.addVariableNames(member.fields);
|
| + } else if (member is MethodDeclaration) {
|
| + scope.add(member.name);
|
| + }
|
| + }
|
| + return scope;
|
| + }
|
| +
|
| + factory _LocalNameScope.forClassTypeAlias(
|
| + _LocalNameScope enclosing, ClassTypeAlias node) {
|
| + _LocalNameScope scope = new _LocalNameScope(enclosing);
|
| + scope.addTypeParameters(node.typeParameters);
|
| + return scope;
|
| + }
|
| +
|
| + factory _LocalNameScope.forFunction(
|
| + _LocalNameScope enclosing, FunctionDeclaration node) {
|
| + _LocalNameScope scope = new _LocalNameScope(enclosing);
|
| + scope.addTypeParameters(node.functionExpression.typeParameters);
|
| + scope.addFormalParameters(node.functionExpression.parameters);
|
| + return scope;
|
| + }
|
| +
|
| + factory _LocalNameScope.forFunctionTypeAlias(
|
| + _LocalNameScope enclosing, FunctionTypeAlias node) {
|
| + _LocalNameScope scope = new _LocalNameScope(enclosing);
|
| + scope.addTypeParameters(node.typeParameters);
|
| + return scope;
|
| + }
|
| +
|
| + factory _LocalNameScope.forMethod(
|
| + _LocalNameScope enclosing, MethodDeclaration node) {
|
| + _LocalNameScope scope = new _LocalNameScope(enclosing);
|
| + scope.addTypeParameters(node.typeParameters);
|
| + scope.addFormalParameters(node.parameters);
|
| + return scope;
|
| + }
|
| +
|
| + factory _LocalNameScope.forUnit(CompilationUnit node) {
|
| + _LocalNameScope scope = new _LocalNameScope(null);
|
| + for (CompilationUnitMember declaration in node.declarations) {
|
| + if (declaration is NamedCompilationUnitMember) {
|
| + scope.add(declaration.name);
|
| + } else if (declaration is TopLevelVariableDeclaration) {
|
| + scope.addVariableNames(declaration.variables);
|
| + }
|
| + }
|
| + return scope;
|
| + }
|
| +
|
| + void add(SimpleIdentifier identifier) {
|
| + if (identifier != null) {
|
| + names ??= new Set<String>();
|
| + names.add(identifier.name);
|
| + }
|
| + }
|
| +
|
| + void addFormalParameters(FormalParameterList parameterList) {
|
| + if (parameterList != null) {
|
| + parameterList.parameters
|
| + .map((p) => p is NormalFormalParameter ? p.identifier : null)
|
| + .forEach(add);
|
| + }
|
| + }
|
| +
|
| + void addTypeParameters(TypeParameterList typeParameterList) {
|
| + if (typeParameterList != null) {
|
| + typeParameterList.typeParameters.map((p) => p.name).forEach(add);
|
| + }
|
| + }
|
| +
|
| + void addVariableNames(VariableDeclarationList variableList) {
|
| + for (VariableDeclaration variable in variableList.variables) {
|
| + add(variable.name);
|
| + }
|
| + }
|
| +
|
| + bool contains(String name) {
|
| + if (names != null && names.contains(name)) {
|
| + return true;
|
| + }
|
| + if (enclosing != null) {
|
| + return enclosing.contains(name);
|
| + }
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +class _ReferencedNamesComputer extends GeneralizingAstVisitor {
|
| + final Set<String> names = new Set<String>();
|
| + final Set<String> importPrefixNames = new Set<String>();
|
| +
|
| + _LocalNameScope localScope = new _LocalNameScope(null);
|
| +
|
| + @override
|
| + visitBlock(Block node) {
|
| + _LocalNameScope outerScope = localScope;
|
| + try {
|
| + localScope = new _LocalNameScope.forBlock(localScope, node);
|
| + super.visitBlock(node);
|
| + } finally {
|
| + localScope = outerScope;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitClassDeclaration(ClassDeclaration node) {
|
| + _LocalNameScope outerScope = localScope;
|
| + try {
|
| + localScope = new _LocalNameScope.forClass(localScope, node);
|
| + super.visitClassDeclaration(node);
|
| + } finally {
|
| + localScope = outerScope;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitClassTypeAlias(ClassTypeAlias node) {
|
| + _LocalNameScope outerScope = localScope;
|
| + try {
|
| + localScope = new _LocalNameScope.forClassTypeAlias(localScope, node);
|
| + super.visitClassTypeAlias(node);
|
| + } finally {
|
| + localScope = outerScope;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitCompilationUnit(CompilationUnit node) {
|
| + localScope = new _LocalNameScope.forUnit(node);
|
| + super.visitCompilationUnit(node);
|
| + }
|
| +
|
| + @override
|
| + visitConstructorName(ConstructorName node) {
|
| + if (node.parent is! ConstructorDeclaration) {
|
| + super.visitConstructorName(node);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitFunctionDeclaration(FunctionDeclaration node) {
|
| + _LocalNameScope outerScope = localScope;
|
| + try {
|
| + localScope = new _LocalNameScope.forFunction(localScope, node);
|
| + super.visitFunctionDeclaration(node);
|
| + } finally {
|
| + localScope = outerScope;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + _LocalNameScope outerScope = localScope;
|
| + try {
|
| + localScope = new _LocalNameScope.forFunctionTypeAlias(localScope, node);
|
| + super.visitFunctionTypeAlias(node);
|
| + } finally {
|
| + localScope = outerScope;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitImportDirective(ImportDirective node) {
|
| + if (node.prefix != null) {
|
| + importPrefixNames.add(node.prefix.name);
|
| + }
|
| + super.visitImportDirective(node);
|
| + }
|
| +
|
| + @override
|
| + visitMethodDeclaration(MethodDeclaration node) {
|
| + _LocalNameScope outerScope = localScope;
|
| + try {
|
| + localScope = new _LocalNameScope.forMethod(localScope, node);
|
| + super.visitMethodDeclaration(node);
|
| + } finally {
|
| + localScope = outerScope;
|
| + }
|
| + }
|
| +
|
| + @override
|
| + visitSimpleIdentifier(SimpleIdentifier node) {
|
| + // Ignore all declarations.
|
| + if (node.inDeclarationContext()) {
|
| + return;
|
| + }
|
| + // Ignore class names references from constructors.
|
| + AstNode parent = node.parent;
|
| + if (parent is ConstructorDeclaration && parent.returnType == node) {
|
| + return;
|
| + }
|
| + // Prepare name.
|
| + String name = node.name;
|
| + // Ignore unqualified names shadowed by local elements.
|
| + if (!node.isQualified) {
|
| + if (localScope.contains(name)) {
|
| + return;
|
| + }
|
| + if (importPrefixNames.contains(name)) {
|
| + return;
|
| + }
|
| + }
|
| + // Do add the name.
|
| + names.add(name);
|
| + }
|
| +}
|
|
|