blob: 6150a2c1ab330d594c9b3211aceec6d11070c753 [file] [log] [blame]
// 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;
}
}