mirror of
https://github.com/dart-lang/sdk
synced 2024-10-06 15:50:01 +00:00
[analyzer] Add the ability to locate an Element from an ElementLocation
Change-Id: If2f3bfcdaa330dc1bcb9c1078500e982660ae8c7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264300 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
8995807b2b
commit
3e587da7f0
|
@ -481,6 +481,10 @@ abstract class DirectiveUriWithUnit extends DirectiveUriWithSource {
|
|||
///
|
||||
/// Clients may not extend, implement or mix-in this class.
|
||||
abstract class Element implements AnalysisTarget {
|
||||
/// A list of this element's children.
|
||||
/// There is no guarantee of the order in which the children will be included.
|
||||
List<Element> get children;
|
||||
|
||||
/// Return the analysis context in which this element is defined.
|
||||
AnalysisContext get context;
|
||||
|
||||
|
|
|
@ -100,6 +100,16 @@ abstract class AbstractClassElementImpl extends _ExistingElementImpl
|
|||
return library.session.classHierarchy.implementedInterfaces(this);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
...accessors,
|
||||
...fields,
|
||||
...constructors,
|
||||
...methods,
|
||||
...typeParameters,
|
||||
];
|
||||
|
||||
@override
|
||||
String get displayName => name;
|
||||
|
||||
|
@ -384,16 +394,6 @@ abstract class AbstractClassElementImpl extends _ExistingElementImpl
|
|||
}));
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(accessors, visitor);
|
||||
safelyVisitChildren(fields, visitor);
|
||||
safelyVisitChildren(constructors, visitor);
|
||||
safelyVisitChildren(methods, visitor);
|
||||
safelyVisitChildren(typeParameters, visitor);
|
||||
}
|
||||
|
||||
/// Return an iterable containing all of the implementations of a getter with
|
||||
/// the given [getterName] that are defined in this class any any superclass
|
||||
/// of this class (but not in interfaces).
|
||||
|
@ -1126,6 +1126,19 @@ class CompilationUnitElementImpl extends UriReferencedElementImpl
|
|||
_accessors = accessors;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
...accessors,
|
||||
...classes,
|
||||
...enums2,
|
||||
...extensions,
|
||||
...functions,
|
||||
...mixins2,
|
||||
...typeAliases,
|
||||
...topLevelVariables,
|
||||
];
|
||||
|
||||
@override
|
||||
List<ClassElement> get classes {
|
||||
return _classes;
|
||||
|
@ -1299,19 +1312,6 @@ class CompilationUnitElementImpl extends UriReferencedElementImpl
|
|||
|
||||
this.linkedData = linkedData;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(accessors, visitor);
|
||||
safelyVisitChildren(classes, visitor);
|
||||
safelyVisitChildren(enums2, visitor);
|
||||
safelyVisitChildren(extensions, visitor);
|
||||
safelyVisitChildren(functions, visitor);
|
||||
safelyVisitChildren(mixins2, visitor);
|
||||
safelyVisitChildren(typeAliases, visitor);
|
||||
safelyVisitChildren(topLevelVariables, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// A [FieldElement] for a 'const' or 'final' field that has an initializer.
|
||||
|
@ -2204,6 +2204,9 @@ abstract class ElementImpl implements Element {
|
|||
reference?.element = this;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => const [];
|
||||
|
||||
/// The length of the element's code, or `null` if the element is synthetic.
|
||||
int? get codeLength => _codeLength;
|
||||
|
||||
|
@ -2675,13 +2678,6 @@ abstract class ElementImpl implements Element {
|
|||
_metadataFlags = 0;
|
||||
}
|
||||
|
||||
/// Use the given [visitor] to visit all of the [children] in the given array.
|
||||
void safelyVisitChildren(List<Element> children, ElementVisitor visitor) {
|
||||
for (Element child in children) {
|
||||
child.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the code range for this element.
|
||||
void setCodeRange(int offset, int length) {
|
||||
_codeOffset = offset;
|
||||
|
@ -2723,9 +2719,13 @@ abstract class ElementImpl implements Element {
|
|||
return getDisplayString(withNullability: true);
|
||||
}
|
||||
|
||||
/// Use the given [visitor] to visit all of the children of this element.
|
||||
/// There is no guarantee of the order in which the children will be visited.
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
// There are no children to visit
|
||||
for (Element child in children) {
|
||||
child.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return flags that denote presence of a few specific annotations.
|
||||
|
@ -3025,6 +3025,13 @@ abstract class ExecutableElementImpl extends _ExistingElementImpl
|
|||
/// [offset].
|
||||
ExecutableElementImpl(String super.name, super.offset, {super.reference});
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
...typeParameters,
|
||||
...parameters,
|
||||
];
|
||||
|
||||
@override
|
||||
Element get enclosingElement => super.enclosingElement!;
|
||||
|
||||
|
@ -3198,13 +3205,6 @@ abstract class ExecutableElementImpl extends _ExistingElementImpl
|
|||
|
||||
this.linkedData = linkedData;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(typeParameters, visitor);
|
||||
safelyVisitChildren(parameters, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete implementation of an [ExtensionElement].
|
||||
|
@ -3243,6 +3243,15 @@ class ExtensionElementImpl extends _ExistingElementImpl
|
|||
_accessors = accessors;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
...accessors,
|
||||
...fields,
|
||||
...methods,
|
||||
...typeParameters,
|
||||
];
|
||||
|
||||
@override
|
||||
String get displayName => name ?? '';
|
||||
|
||||
|
@ -3386,15 +3395,6 @@ class ExtensionElementImpl extends _ExistingElementImpl
|
|||
|
||||
this.linkedData = linkedData;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(accessors, visitor);
|
||||
safelyVisitChildren(fields, visitor);
|
||||
safelyVisitChildren(methods, visitor);
|
||||
safelyVisitChildren(typeParameters, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete implementation of a [FieldElement].
|
||||
|
@ -3581,6 +3581,13 @@ class GenericFunctionTypeElementImpl extends _ExistingElementImpl
|
|||
GenericFunctionTypeElementImpl.forOffset(int nameOffset)
|
||||
: super("", nameOffset);
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
...typeParameters,
|
||||
...parameters,
|
||||
];
|
||||
|
||||
@override
|
||||
String get identifier => '-';
|
||||
|
||||
|
@ -3657,13 +3664,6 @@ class GenericFunctionTypeElementImpl extends _ExistingElementImpl
|
|||
void appendTo(ElementDisplayStringBuilder builder) {
|
||||
builder.writeGenericFunctionTypeElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(typeParameters, visitor);
|
||||
safelyVisitChildren(parameters, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// This mixins is added to elements that can have cache completion data.
|
||||
|
@ -3895,6 +3895,13 @@ class LibraryElementImpl extends LibraryOrAugmentationElementImpl
|
|||
return super.augmentationImports;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
...parts2,
|
||||
..._partUnits,
|
||||
];
|
||||
|
||||
@override
|
||||
CompilationUnitElementImpl get enclosingUnit {
|
||||
return _definingCompilationUnit;
|
||||
|
@ -4233,15 +4240,6 @@ class LibraryElementImpl extends LibraryOrAugmentationElementImpl
|
|||
return NullabilityEliminator.perform(typeProvider, type);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(parts2, visitor);
|
||||
for (final partUnit in _partUnits) {
|
||||
partUnit.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
List<LibraryAugmentationElementImpl> _computeAugmentations() {
|
||||
final result = <LibraryAugmentationElementImpl>[];
|
||||
|
||||
|
@ -4444,6 +4442,14 @@ abstract class LibraryOrAugmentationElementImpl extends ElementImpl
|
|||
_augmentationImports = imports;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => [
|
||||
...super.children,
|
||||
definingCompilationUnit,
|
||||
...libraryExports,
|
||||
...libraryImports,
|
||||
];
|
||||
|
||||
@override
|
||||
CompilationUnitElementImpl get definingCompilationUnit =>
|
||||
_definingCompilationUnit;
|
||||
|
@ -4517,14 +4523,6 @@ abstract class LibraryOrAugmentationElementImpl extends ElementImpl
|
|||
return _definingCompilationUnit.source;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
_definingCompilationUnit.accept(visitor);
|
||||
safelyVisitChildren(libraryExports, visitor);
|
||||
safelyVisitChildren(libraryImports, visitor);
|
||||
}
|
||||
|
||||
void _readLinkedData();
|
||||
|
||||
static List<PrefixElement> buildPrefixesFromImports(
|
||||
|
@ -4890,6 +4888,9 @@ class MultiplyDefinedElementImpl implements MultiplyDefinedElement {
|
|||
MultiplyDefinedElementImpl(
|
||||
this.context, this.session, this.name, this.conflictingElements);
|
||||
|
||||
@override
|
||||
List<Element> get children => const [];
|
||||
|
||||
@override
|
||||
Element? get declaration => null;
|
||||
|
||||
|
@ -5077,9 +5078,13 @@ class MultiplyDefinedElementImpl implements MultiplyDefinedElement {
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
/// Use the given [visitor] to visit all of the children of this element.
|
||||
/// There is no guarantee of the order in which the children will be visited.
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
// There are no children to visit
|
||||
for (Element child in children) {
|
||||
child.accept(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5186,6 +5191,9 @@ class ParameterElementImpl extends VariableElementImpl
|
|||
return element;
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => parameters;
|
||||
|
||||
@override
|
||||
ParameterElement get declaration => this;
|
||||
|
||||
|
@ -5261,12 +5269,6 @@ class ParameterElementImpl extends VariableElementImpl
|
|||
void appendTo(ElementDisplayStringBuilder builder) {
|
||||
builder.writeFormalParameter(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(parameters, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// The parameter of an implicit setter.
|
||||
|
|
|
@ -155,6 +155,9 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
|
|||
this.typeParameters,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Element> get children => parameters;
|
||||
|
||||
@override
|
||||
ExecutableElement get declaration => super.declaration as ExecutableElement;
|
||||
|
||||
|
@ -226,12 +229,6 @@ abstract class ExecutableMember extends Member implements ExecutableElement {
|
|||
builder.writeExecutableElement(this, displayName);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(parameters, visitor);
|
||||
}
|
||||
|
||||
static ExecutableElement from2(
|
||||
ExecutableElement element,
|
||||
MapSubstitution substitution,
|
||||
|
@ -493,6 +490,9 @@ abstract class Member implements Element {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<Element> get children => const [];
|
||||
|
||||
@override
|
||||
AnalysisContext get context => _declaration.context;
|
||||
|
||||
|
@ -648,14 +648,6 @@ abstract class Member implements Element {
|
|||
bool isAccessibleIn2(LibraryElement library) =>
|
||||
_declaration.isAccessibleIn2(library);
|
||||
|
||||
/// Use the given [visitor] to visit all of the [children].
|
||||
void safelyVisitChildren(List<Element> children, ElementVisitor visitor) {
|
||||
// TODO(brianwilkerson) Make this private
|
||||
for (Element child in children) {
|
||||
child.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
E? thisOrAncestorMatching<E extends Element>(
|
||||
bool Function(Element) predicate,
|
||||
|
@ -672,9 +664,13 @@ abstract class Member implements Element {
|
|||
return getDisplayString(withNullability: false);
|
||||
}
|
||||
|
||||
/// Use the given [visitor] to visit all of the children of this element.
|
||||
/// There is no guarantee of the order in which the children will be visited.
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
// There are no children to visit
|
||||
for (Element child in children) {
|
||||
child.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
/// If this member is a legacy view, erase nullability from the [type].
|
||||
|
@ -876,6 +872,9 @@ class ParameterMember extends VariableMember
|
|||
this.typeParameters,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Element> get children => parameters;
|
||||
|
||||
@override
|
||||
ParameterElement get declaration => super.declaration as ParameterElement;
|
||||
|
||||
|
@ -932,12 +931,6 @@ class ParameterMember extends VariableMember
|
|||
builder.writeFormalParameter(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
super.visitChildren(visitor);
|
||||
safelyVisitChildren(parameters, visitor);
|
||||
}
|
||||
|
||||
static ParameterElement from(
|
||||
ParameterElement element, MapSubstitution substitution) {
|
||||
TypeProviderImpl? typeProvider;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2022, 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/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/library_element.dart';
|
||||
|
||||
extension AnalysisSessionExtension on AnalysisSession {
|
||||
/// Locates the [Element] that [location] represents.
|
||||
///
|
||||
/// Local elements such as variables inside functions cannot be found using
|
||||
/// this method.
|
||||
///
|
||||
/// Returns `null` if the element cannot be found.
|
||||
Future<Element?> locateElement(ElementLocation location) async {
|
||||
final components = location.components;
|
||||
if (location.components.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The first component is the library which we'll use to start the search.
|
||||
final libraryUri = components.first;
|
||||
final result = await getLibraryByUri(libraryUri);
|
||||
return result is LibraryElementResult
|
||||
? result.element.locateElement(location)
|
||||
: null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2022, 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/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
|
||||
extension LibraryElementExtension on LibraryElement {
|
||||
/// Locates an [Element] in this library by its [ElementLocation].
|
||||
///
|
||||
/// It is assumed that the first component of [location] matches this library.
|
||||
///
|
||||
/// Local elements such as variables inside functions cannot be found using
|
||||
/// this method.
|
||||
Element? locateElement(ElementLocation location) =>
|
||||
_locateElement(location, 0);
|
||||
}
|
||||
|
||||
extension _ElementExtension on Element {
|
||||
/// Locates an [Element] by its [ElementLocation] assuming this element
|
||||
/// is a match up to [thisIndex].
|
||||
Element? _locateElement(ElementLocation location, int thisIndex) {
|
||||
final components = location.components;
|
||||
RangeError.checkValidIndex(thisIndex, components);
|
||||
|
||||
final nextIndex = thisIndex + 1;
|
||||
if (nextIndex == components.length) {
|
||||
// This element matches the last component so return it.
|
||||
return this;
|
||||
}
|
||||
|
||||
// Search for a matching child.
|
||||
final identifier = components[nextIndex];
|
||||
for (final child in children) {
|
||||
if ((child as ElementImpl).identifier == identifier) {
|
||||
return child._locateElement(location, nextIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) 2022, 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/analysis/results.dart';
|
||||
import 'package:analyzer/dart/analysis/session.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/dart/analysis/results.dart';
|
||||
import 'package:analyzer/src/test_utilities/test_code_format.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/analysis_session.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../dart/resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(LocateElementTest);
|
||||
});
|
||||
}
|
||||
|
||||
/// Tests `locateElement()` on [AnalysisSession].
|
||||
///
|
||||
/// This extension method largely delegates to `LibraryElement.locateElement`
|
||||
/// which is tested more comprehensively in
|
||||
/// 'test/src/utilities/extensions/library_element_test.dart'.
|
||||
@reflectiveTest
|
||||
class LocateElementTest extends PubPackageResolutionTest {
|
||||
late _MockAnalysisSession session;
|
||||
|
||||
File get testFile2 => getFile('$testPackageLibPath/test2.dart');
|
||||
|
||||
/// Create a library and (unless [addToSession] is `false`) add it to [session].
|
||||
Future<LibraryElement> createLibrary(
|
||||
String path,
|
||||
String content, {
|
||||
bool addToSession = true,
|
||||
}) async {
|
||||
final code = TestCode.parse(content);
|
||||
newFile(path, code.code);
|
||||
final library = (await resolveFile(path)).libraryElement;
|
||||
if (addToSession) {
|
||||
session.addLibrary(library);
|
||||
}
|
||||
return library;
|
||||
}
|
||||
|
||||
/// Find class [name] in [library].
|
||||
ClassElement findClass(LibraryElement library, String name) {
|
||||
return library.definingCompilationUnit.getClass(name)!;
|
||||
}
|
||||
|
||||
/// Locate the element referenced by [location] in [session].
|
||||
Future<Element?> getElement(ElementLocation? location) =>
|
||||
session.locateElement(location!);
|
||||
|
||||
@override
|
||||
void setUp() {
|
||||
super.setUp();
|
||||
session = _MockAnalysisSession();
|
||||
}
|
||||
|
||||
void test_elementInLibrary() async {
|
||||
final libraryOne = await createLibrary(testFile.path, 'class C {}');
|
||||
final libraryTwo = await createLibrary(testFile2.path, 'class C {}');
|
||||
final classOne = findClass(libraryOne, 'C');
|
||||
final classTwo = findClass(libraryTwo, 'C');
|
||||
|
||||
expect(await getElement(classOne.location!), classOne);
|
||||
expect(await getElement(classTwo.location!), classTwo);
|
||||
}
|
||||
|
||||
void test_invalid() async {
|
||||
final library =
|
||||
await createLibrary(testFile.path, 'class C {}', addToSession: false);
|
||||
final class_ = findClass(library, 'C');
|
||||
|
||||
expect(await getElement(class_.location!), isNull);
|
||||
}
|
||||
|
||||
void test_library() async {
|
||||
final libraryOne = await createLibrary(testFile.path, 'class C {}');
|
||||
final libraryTwo = await createLibrary(testFile2.path, 'class C {}');
|
||||
|
||||
expect(await getElement(libraryOne.location!), libraryOne);
|
||||
expect(await getElement(libraryTwo.location!), libraryTwo);
|
||||
}
|
||||
}
|
||||
|
||||
class _MockAnalysisSession implements AnalysisSession {
|
||||
final _libraries = <String, LibraryElement>{};
|
||||
|
||||
void addLibrary(LibraryElement library) =>
|
||||
_libraries[library.identifier] = library;
|
||||
|
||||
@override
|
||||
Future<SomeLibraryElementResult> getLibraryByUri(String uri) async {
|
||||
final library = _libraries[uri];
|
||||
return library != null
|
||||
? LibraryElementResultImpl(library)
|
||||
: CannotResolveUriResult();
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright (c) 2022, 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/src/dart/ast/element_locator.dart';
|
||||
import 'package:analyzer/src/test_utilities/test_code_format.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/ast.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/library_element.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../dart/resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(LocateElementTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class LocateElementTest extends PubPackageResolutionTest {
|
||||
Future<void> assertLocation(String content) async {
|
||||
final code = TestCode.parse(content);
|
||||
await resolveTestCode(code.code);
|
||||
|
||||
// Get the element we'll be searching for from the marker in code.
|
||||
final node = result.unit.nodeCovering(offset: code.position.offset);
|
||||
final expectedElement = ElementLocator.locate(node)!;
|
||||
|
||||
// Verify locating the element using its location finds the same element.
|
||||
final actualElement =
|
||||
result.libraryElement.locateElement(expectedElement.location!);
|
||||
expect(actualElement, expectedElement);
|
||||
}
|
||||
|
||||
void test_class() async {
|
||||
await assertLocation('''
|
||||
class C^ {}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_class_const() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
static const ^c = '';
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_class_constructor() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
C.named() {}
|
||||
^C() {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_class_constructor_named() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
C.named() {}
|
||||
}
|
||||
|
||||
class C2 {
|
||||
C.nam^ed() {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_class_field() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
int f = 0;
|
||||
}
|
||||
class C2 {
|
||||
int f^ = 0;
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_class_getter() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
String get s => '';
|
||||
}
|
||||
class C2 {
|
||||
String get s^ => '';
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_class_setter() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
set s(String a) {}
|
||||
}
|
||||
class C2 {
|
||||
set ^s(String a) {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_const() async {
|
||||
await assertLocation('''
|
||||
const ^c = '';
|
||||
''');
|
||||
}
|
||||
|
||||
void test_enum() async {
|
||||
await assertLocation('''
|
||||
enum ^E {}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_enum_const2() async {
|
||||
await assertLocation('''
|
||||
enum E {
|
||||
o^ne(1);
|
||||
final int n;
|
||||
const E(this.n);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_enum_constructor() async {
|
||||
await assertLocation('''
|
||||
enum E {
|
||||
final int n;
|
||||
const ^E(this.n);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_extension() async {
|
||||
await assertLocation('''
|
||||
extension on int {}
|
||||
exten^sion on String {}
|
||||
extension on int {}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_extension_named() async {
|
||||
await assertLocation('''
|
||||
extension StringEx^tension on String {}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_getter() async {
|
||||
await assertLocation('''
|
||||
String get ^g => '';
|
||||
''');
|
||||
}
|
||||
|
||||
void test_method() async {
|
||||
await assertLocation('''
|
||||
class C {
|
||||
void m() {}
|
||||
}
|
||||
class C2 {
|
||||
void ^m() {}
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_mixin() async {
|
||||
await assertLocation('''
|
||||
mixin ^M {}
|
||||
''');
|
||||
}
|
||||
|
||||
void test_setter() async {
|
||||
await assertLocation('''
|
||||
Set f^(String v) => '';
|
||||
''');
|
||||
}
|
||||
|
||||
void test_topLevelVariable() async {
|
||||
await assertLocation('''
|
||||
int ^a = 1;
|
||||
''');
|
||||
}
|
||||
|
||||
void test_typedef() async {
|
||||
await assertLocation('''
|
||||
typedef ^S = String;
|
||||
''');
|
||||
}
|
||||
}
|
|
@ -4,16 +4,20 @@
|
|||
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'analysis_session_test.dart' as analysis_session;
|
||||
import 'ast_test.dart' as ast;
|
||||
import 'collection_test.dart' as collection;
|
||||
import 'library_element_test.dart' as library_element;
|
||||
import 'object_test.dart' as object;
|
||||
import 'stream_test.dart' as stream;
|
||||
import 'string_test.dart' as string;
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
analysis_session.main();
|
||||
ast.main();
|
||||
collection.main();
|
||||
library_element.main();
|
||||
object.main();
|
||||
stream.main();
|
||||
string.main();
|
||||
|
|
Loading…
Reference in a new issue