| // Copyright (c) 2017, 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:analysis_server/protocol/protocol_generated.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/visitor.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| |
| /** |
| * An object used to compute the list of elements referenced within a given |
| * region of a compilation unit that are imported into the compilation unit's |
| * library. |
| */ |
| class ImportedElementsComputer { |
| /** |
| * The compilation unit in which the elements are referenced. |
| */ |
| final CompilationUnit unit; |
| |
| /** |
| * The offset of the region containing the references to be returned. |
| */ |
| final int offset; |
| |
| /** |
| * The length of the region containing the references to be returned. |
| */ |
| final int length; |
| |
| /** |
| * Initialize a newly created computer to compute the list of imported |
| * elements referenced in the given [unit] within the region with the given |
| * [offset] and [length]. |
| */ |
| ImportedElementsComputer(this.unit, this.offset, this.length); |
| |
| /** |
| * Compute and return the list of imported elements. |
| */ |
| List<ImportedElements> compute() { |
| _Visitor visitor = |
| new _Visitor(unit.declaredElement.library, offset, offset + length); |
| unit.accept(visitor); |
| return visitor.importedElements.values.toList(); |
| } |
| } |
| |
| /** |
| * The visitor used by an [ImportedElementsComputer] to record the names of all |
| * imported elements. |
| */ |
| class _Visitor extends UnifyingAstVisitor<Object> { |
| /** |
| * The element representing the library containing the code being visited. |
| */ |
| final LibraryElement containingLibrary; |
| |
| /** |
| * The offset of the start of the region of text being copied. |
| */ |
| final int startOffset; |
| |
| /** |
| * The offset of the end of the region of text being copied. |
| */ |
| final int endOffset; |
| |
| /** |
| * A table mapping library path and prefix keys to the imported elements from |
| * that library. |
| */ |
| Map<String, ImportedElements> importedElements = <String, ImportedElements>{}; |
| |
| /** |
| * Initialize a newly created visitor to visit nodes within a specified |
| * region. |
| */ |
| _Visitor(this.containingLibrary, this.startOffset, this.endOffset); |
| |
| @override |
| Object visitNode(AstNode node) { |
| if (node.offset <= endOffset && node.end >= startOffset) { |
| node.visitChildren(this); |
| } |
| return null; |
| } |
| |
| @override |
| Object visitSimpleIdentifier(SimpleIdentifier node) { |
| if (!node.inDeclarationContext() && |
| node.offset <= endOffset && |
| node.end >= startOffset && |
| !_isConstructorDeclarationReturnType(node)) { |
| Element nodeElement = node.staticElement; |
| if (nodeElement != null && |
| nodeElement.enclosingElement is CompilationUnitElement) { |
| LibraryElement nodeLibrary = nodeElement.library; |
| String path = nodeLibrary.definingCompilationUnit.source.fullName; |
| String prefix = ''; |
| AstNode parent = node.parent; |
| if (parent is PrefixedIdentifier && parent.identifier == node) { |
| SimpleIdentifier prefixIdentifier = parent.prefix; |
| if (prefixIdentifier.offset <= endOffset && |
| prefixIdentifier.end >= startOffset) { |
| Element prefixElement = prefixIdentifier.staticElement; |
| if (prefixElement is PrefixElement) { |
| prefix = prefixElement.name; |
| } |
| } |
| } |
| String key = '$prefix;$path'; |
| ImportedElements elements = importedElements.putIfAbsent( |
| key, () => new ImportedElements(path, prefix, <String>[])); |
| List<String> elementNames = elements.elements; |
| String elementName = nodeElement.name; |
| if (!elementNames.contains(elementName)) { |
| elementNames.add(elementName); |
| } |
| } |
| } |
| return null; |
| } |
| |
| static bool _isConstructorDeclarationReturnType(SimpleIdentifier node) { |
| AstNode parent = node.parent; |
| return parent is ConstructorDeclaration && parent.returnType == node; |
| } |
| } |