Version 2.19.0-330.0.dev

Merge 3e587da7f0f52c4f8b2b2af3c4c32e8056a9de25 into dev
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index d4cc40d..3bef64b 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -481,6 +481,10 @@
 ///
 /// 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;
 
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 6f57ad4..b241e8c 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -101,6 +101,16 @@
   }
 
   @override
+  List<Element> get children => [
+        ...super.children,
+        ...accessors,
+        ...fields,
+        ...constructors,
+        ...methods,
+        ...typeParameters,
+      ];
+
+  @override
   String get displayName => name;
 
   @override
@@ -384,16 +394,6 @@
     }));
   }
 
-  @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).
@@ -1127,6 +1127,19 @@
   }
 
   @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 @@
 
     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 @@
     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 @@
     _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 @@
     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.
@@ -3026,6 +3026,13 @@
   ExecutableElementImpl(String super.name, super.offset, {super.reference});
 
   @override
+  List<Element> get children => [
+        ...super.children,
+        ...typeParameters,
+        ...parameters,
+      ];
+
+  @override
   Element get enclosingElement => super.enclosingElement!;
 
   @Deprecated('Use enclosingElement instead')
@@ -3198,13 +3205,6 @@
 
     this.linkedData = linkedData;
   }
-
-  @override
-  void visitChildren(ElementVisitor visitor) {
-    super.visitChildren(visitor);
-    safelyVisitChildren(typeParameters, visitor);
-    safelyVisitChildren(parameters, visitor);
-  }
 }
 
 /// A concrete implementation of an [ExtensionElement].
@@ -3244,6 +3244,15 @@
   }
 
   @override
+  List<Element> get children => [
+        ...super.children,
+        ...accessors,
+        ...fields,
+        ...methods,
+        ...typeParameters,
+      ];
+
+  @override
   String get displayName => name ?? '';
 
   @override
@@ -3386,15 +3395,6 @@
 
     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].
@@ -3582,6 +3582,13 @@
       : super("", nameOffset);
 
   @override
+  List<Element> get children => [
+        ...super.children,
+        ...typeParameters,
+        ...parameters,
+      ];
+
+  @override
   String get identifier => '-';
 
   @override
@@ -3657,13 +3664,6 @@
   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.
@@ -3896,6 +3896,13 @@
   }
 
   @override
+  List<Element> get children => [
+        ...super.children,
+        ...parts2,
+        ..._partUnits,
+      ];
+
+  @override
   CompilationUnitElementImpl get enclosingUnit {
     return _definingCompilationUnit;
   }
@@ -4233,15 +4240,6 @@
     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>[];
 
@@ -4445,6 +4443,14 @@
   }
 
   @override
+  List<Element> get children => [
+        ...super.children,
+        definingCompilationUnit,
+        ...libraryExports,
+        ...libraryImports,
+      ];
+
+  @override
   CompilationUnitElementImpl get definingCompilationUnit =>
       _definingCompilationUnit;
 
@@ -4517,14 +4523,6 @@
     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(
@@ -4891,6 +4889,9 @@
       this.context, this.session, this.name, this.conflictingElements);
 
   @override
+  List<Element> get children => const [];
+
+  @override
   Element? get declaration => null;
 
   @override
@@ -5077,9 +5078,13 @@
     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);
+    }
   }
 }
 
@@ -5187,6 +5192,9 @@
   }
 
   @override
+  List<Element> get children => parameters;
+
+  @override
   ParameterElement get declaration => this;
 
   @override
@@ -5261,12 +5269,6 @@
   void appendTo(ElementDisplayStringBuilder builder) {
     builder.writeFormalParameter(this);
   }
-
-  @override
-  void visitChildren(ElementVisitor visitor) {
-    super.visitChildren(visitor);
-    safelyVisitChildren(parameters, visitor);
-  }
 }
 
 /// The parameter of an implicit setter.
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 2ba5a6d..957dc0c 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -156,6 +156,9 @@
   );
 
   @override
+  List<Element> get children => parameters;
+
+  @override
   ExecutableElement get declaration => super.declaration as ExecutableElement;
 
   @override
@@ -226,12 +229,6 @@
     builder.writeExecutableElement(this, displayName);
   }
 
-  @override
-  void visitChildren(ElementVisitor visitor) {
-    super.visitChildren(visitor);
-    safelyVisitChildren(parameters, visitor);
-  }
-
   static ExecutableElement from2(
     ExecutableElement element,
     MapSubstitution substitution,
@@ -494,6 +491,9 @@
   }
 
   @override
+  List<Element> get children => const [];
+
+  @override
   AnalysisContext get context => _declaration.context;
 
   @override
@@ -648,14 +648,6 @@
   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 @@
     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].
@@ -877,6 +873,9 @@
   );
 
   @override
+  List<Element> get children => parameters;
+
+  @override
   ParameterElement get declaration => super.declaration as ParameterElement;
 
   @override
@@ -932,12 +931,6 @@
     builder.writeFormalParameter(this);
   }
 
-  @override
-  void visitChildren(ElementVisitor visitor) {
-    super.visitChildren(visitor);
-    safelyVisitChildren(parameters, visitor);
-  }
-
   static ParameterElement from(
       ParameterElement element, MapSubstitution substitution) {
     TypeProviderImpl? typeProvider;
diff --git a/pkg/analyzer/lib/src/utilities/extensions/analysis_session.dart b/pkg/analyzer/lib/src/utilities/extensions/analysis_session.dart
new file mode 100644
index 0000000..c26412b
--- /dev/null
+++ b/pkg/analyzer/lib/src/utilities/extensions/analysis_session.dart
@@ -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;
+  }
+}
diff --git a/pkg/analyzer/lib/src/utilities/extensions/library_element.dart b/pkg/analyzer/lib/src/utilities/extensions/library_element.dart
new file mode 100644
index 0000000..3f25901
--- /dev/null
+++ b/pkg/analyzer/lib/src/utilities/extensions/library_element.dart
@@ -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;
+  }
+}
diff --git a/pkg/analyzer/test/src/utilities/extensions/analysis_session_test.dart b/pkg/analyzer/test/src/utilities/extensions/analysis_session_test.dart
new file mode 100644
index 0000000..de3cd13
--- /dev/null
+++ b/pkg/analyzer/test/src/utilities/extensions/analysis_session_test.dart
@@ -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);
+}
diff --git a/pkg/analyzer/test/src/utilities/extensions/library_element_test.dart b/pkg/analyzer/test/src/utilities/extensions/library_element_test.dart
new file mode 100644
index 0000000..147381d
--- /dev/null
+++ b/pkg/analyzer/test/src/utilities/extensions/library_element_test.dart
@@ -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;
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/utilities/extensions/test_all.dart b/pkg/analyzer/test/src/utilities/extensions/test_all.dart
index b1db4c9..2e04529 100644
--- a/pkg/analyzer/test/src/utilities/extensions/test_all.dart
+++ b/pkg/analyzer/test/src/utilities/extensions/test_all.dart
@@ -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();
diff --git a/tools/VERSION b/tools/VERSION
index e3ffaba..7a33e67 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 19
 PATCH 0
-PRERELEASE 329
+PRERELEASE 330
 PRERELEASE_PATCH 0