Version 2.17.0-166.0.dev

Merge commit '589baa47920822dea07cc19a54e2a9e088affbf8' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
index 827a088..36aff2e 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_definition.dart
@@ -11,9 +11,15 @@
 import 'package:analysis_server/src/lsp/mapping.dart';
 import 'package:analysis_server/src/plugin/result_merger.dart';
 import 'package:analysis_server/src/protocol_server.dart' show NavigationTarget;
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
 import 'package:analyzer_plugin/src/utilities/navigation/navigation.dart';
+import 'package:analyzer_plugin/utilities/analyzer_converter.dart';
 import 'package:analyzer_plugin/utilities/navigation/navigation_dart.dart';
 import 'package:collection/collection.dart';
 
@@ -47,14 +53,16 @@
 
   Future<AnalysisNavigationParams> getServerResult(
       bool supportsLocationLink, String path, int offset) async {
-    final collector =
-        NavigationCollectorImpl(collectCodeLocations: supportsLocationLink);
+    final collector = NavigationCollectorImpl();
 
     final result = await server.getResolvedUnit(path);
     final unit = result?.unit;
     if (unit != null) {
       computeDartNavigation(
           server.resourceProvider, collector, unit, offset, 0);
+      if (supportsLocationLink) {
+        _updateTargetsWithCodeLocations(collector);
+      }
       collector.createRegions();
     }
 
@@ -171,6 +179,50 @@
     return otherResults.isNotEmpty ? otherResults : results;
   }
 
+  /// Get the location of the code (excluding leading doc comments) for this element.
+  protocol.Location? _getCodeLocation(Element element) {
+    var codeElement = element;
+    // For synthetic getters created for fields, we need to access the associated
+    // variable to get the codeOffset/codeLength.
+    if (codeElement.isSynthetic && codeElement is PropertyAccessorElementImpl) {
+      final variable = codeElement.variable;
+      if (variable is ElementImpl) {
+        codeElement = variable as ElementImpl;
+      }
+    }
+
+    // Read the main codeOffset from the element. This may include doc comments
+    // but will give the correct end position.
+    int? codeOffset, codeLength;
+    if (codeElement is ElementImpl) {
+      codeOffset = codeElement.codeOffset;
+      codeLength = codeElement.codeLength;
+    }
+
+    if (codeOffset == null || codeLength == null) {
+      return null;
+    }
+
+    // Read the declaration so we can get the offset after the doc comments.
+    // TODO(dantup): Skip this for parts (getParsedLibrary will throw), but find
+    // a better solution.
+    final declaration = _parsedDeclaration(codeElement);
+    var node = declaration?.node;
+    if (node is VariableDeclaration) {
+      node = node.parent;
+    }
+    if (node is AnnotatedNode) {
+      var offsetAfterDocs = node.firstTokenAfterCommentAndMetadata.offset;
+
+      // Reduce the length by the difference between the end of docs and the start.
+      codeLength -= offsetAfterDocs - codeOffset;
+      codeOffset = offsetAfterDocs;
+    }
+
+    return AnalyzerConverter()
+        .locationFromElement(element, offset: codeOffset, length: codeLength);
+  }
+
   Location? _toLocation(
       AnalysisNavigationParams mergedResults, NavigationTarget target) {
     final targetFilePath = mergedResults.files[target.fileIndex];
@@ -191,4 +243,34 @@
             region, sourceLineInfo, targetFilePath, target, targetLineInfo)
         : null;
   }
+
+  void _updateTargetsWithCodeLocations(NavigationCollectorImpl collector) {
+    for (var targetToUpdate in collector.targetsToUpdate) {
+      var codeLocation = _getCodeLocation(targetToUpdate.element);
+      if (codeLocation != null) {
+        targetToUpdate.target
+          ..codeOffset = codeLocation.offset
+          ..codeLength = codeLocation.length;
+      }
+    }
+  }
+
+  static ElementDeclarationResult? _parsedDeclaration(Element element) {
+    var session = element.session;
+    if (session == null) {
+      return null;
+    }
+
+    var libraryPath = element.library?.source.fullName;
+    if (libraryPath == null) {
+      return null;
+    }
+
+    var parsedLibrary = session.getParsedLibrary(libraryPath);
+    if (parsedLibrary is! ParsedLibraryResult) {
+      return null;
+    }
+
+    return parsedLibrary.getElementDeclaration(element);
+  }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index d0f199e..0f8b8ce 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -711,6 +711,8 @@
   status: needsEvaluation
 CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT:
   status: needsEvaluation
+CompileTimeErrorCode.NON_FINAL_FIELD_IN_ENUM:
+  status: needsEvaluation
 CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR:
   status: needsEvaluation
 CompileTimeErrorCode.NON_GENERATIVE_IMPLICIT_CONSTRUCTOR:
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 8f78367..d5e5c71 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -241,6 +241,9 @@
     if (node is CompilationUnit) {
       return member;
     }
+    if (node is EnumDeclaration) {
+      return member;
+    }
     member = node;
   }
   return null;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 163572e..b33e29a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -435,8 +435,13 @@
       return validateCreateFunction(searchEngine, libraryElement, name);
     }
     // method of class
+    ClassElement? classElement;
     if (parent is ClassDeclaration) {
-      var classElement = parent.declaredElement!;
+      classElement = parent.declaredElement!;
+    } else if (parent is EnumDeclaration) {
+      classElement = parent.declaredElement!;
+    }
+    if (classElement != null) {
       return validateCreateMethod(searchEngine,
           AnalysisSessionHelper(resolveResult.session), classElement, name);
     }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index 4d55c6c..8065f1f 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -13,6 +13,7 @@
 import 'package:analysis_server/src/services/refactoring/visible_ranges_computer.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/utilities/strings.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -149,12 +150,15 @@
     // check if there is a member with "newName" in the same ClassElement
     for (var newNameMember in getChildren(elementClass, name)) {
       result.addError(
-          format(
-              "Class '{0}' already declares {1} with name '{2}'.",
-              elementClass.displayName,
-              getElementKindName(newNameMember),
-              name),
-          newLocation_fromElement(newNameMember));
+        format(
+          "{0} '{1}' already declares {2} with name '{3}'.",
+          capitalize(elementClass.kind.displayName),
+          elementClass.displayName,
+          getElementKindName(newNameMember),
+          name,
+        ),
+        newLocation_fromElement(newNameMember),
+      );
     }
   }
 
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index 6d19ce9..440b1b4 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -67,38 +67,7 @@
     await createProject();
   }
 
-  Future<void> test_class_declaration() async {
-    addTestFile('''
-class A<E> {}
-class I1<K, V> {}
-class I2<E> {}
-class M1 {}
-class M2<E> {}
-class B<T> extends A<T> with M1, M2<int> implements I1<int, String>, I2 {}
-''');
-    var hover = await prepareHover('B<T>');
-    expect(hover.containingClassDescription, null);
-    expect(
-        hover.elementDescription,
-        'class B<T> extends A<T> with M1, M2<int> '
-        'implements I1<int, String>, I2<dynamic>');
-    expect(hover.staticType, isNull);
-    expect(hover.propagatedType, isNull);
-  }
-
-  Future<void> test_class_declaration_abstract() async {
-    addTestFile('''
-class A {}
-abstract class B extends A {}
-''');
-    var hover = await prepareHover('B extends');
-    expect(hover.containingClassDescription, null);
-    expect(hover.elementDescription, 'abstract class B extends A');
-    expect(hover.staticType, isNull);
-    expect(hover.propagatedType, isNull);
-  }
-
-  Future<void> test_constructor_named() async {
+  Future<void> test_class_constructor_named() async {
     addTestFile('''
 library my.library;
 class A {
@@ -129,7 +98,7 @@
     }
   }
 
-  Future<void> test_constructor_noKeyword_const() async {
+  Future<void> test_class_constructor_noKeyword_const() async {
     addTestFile('''
 library my.library;
 class A {
@@ -156,7 +125,7 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_constructor_noKeyword_new() async {
+  Future<void> test_class_constructor_noKeyword_new() async {
     addTestFile('''
 library my.library;
 class A {}
@@ -181,7 +150,7 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_constructor_synthetic() async {
+  Future<void> test_class_constructor_synthetic() async {
     addTestFile('''
 library my.library;
 class A {
@@ -207,7 +176,7 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_constructor_synthetic_withTypeArgument() async {
+  Future<void> test_class_constructor_synthetic_withTypeArgument() async {
     addTestFile('''
 library my.library;
 class A<T> {}
@@ -249,7 +218,7 @@
     }
   }
 
-  Future<void> test_constructorReference_named() async {
+  Future<void> test_class_constructorReference_named() async {
     addTestFile('''
 class A<T> {
   /// doc aaa
@@ -276,7 +245,7 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_constructorReference_unnamed_declared() async {
+  Future<void> test_class_constructorReference_unnamed_declared() async {
     addTestFile('''
 class A<T> {
   /// doc aaa
@@ -303,7 +272,7 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_constructorReference_unnamed_declared_new() async {
+  Future<void> test_class_constructorReference_unnamed_declared_new() async {
     addTestFile('''
 class A<T> {
   /// doc aaa
@@ -330,7 +299,7 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_constructorReference_unnamed_synthetic() async {
+  Future<void> test_class_constructorReference_unnamed_synthetic() async {
     addTestFile('''
 class A<T> {}
 
@@ -353,6 +322,269 @@
     expect(hover.parameter, isNull);
   }
 
+  Future<void> test_class_declaration() async {
+    addTestFile('''
+class A<E> {}
+class I1<K, V> {}
+class I2<E> {}
+class M1 {}
+class M2<E> {}
+class B<T> extends A<T> with M1, M2<int> implements I1<int, String>, I2 {}
+''');
+    var hover = await prepareHover('B<T>');
+    expect(hover.containingClassDescription, null);
+    expect(
+        hover.elementDescription,
+        'class B<T> extends A<T> with M1, M2<int> '
+        'implements I1<int, String>, I2<dynamic>');
+    expect(hover.staticType, isNull);
+    expect(hover.propagatedType, isNull);
+  }
+
+  Future<void> test_class_declaration_abstract() async {
+    addTestFile('''
+class A {}
+abstract class B extends A {}
+''');
+    var hover = await prepareHover('B extends');
+    expect(hover.containingClassDescription, null);
+    expect(hover.elementDescription, 'abstract class B extends A');
+    expect(hover.staticType, isNull);
+    expect(hover.propagatedType, isNull);
+  }
+
+  Future<void> test_class_getter_synthetic() async {
+    addTestFile('''
+library my.library;
+class A {
+  /// doc aaa
+  /// doc bbb
+  String fff;
+}
+void f(A a) {
+  print(a.fff);
+}
+''');
+    var hover = await prepareHover('fff);');
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'A');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'String fff');
+    expect(hover.elementKind, 'field');
+    // types
+    expect(hover.staticType, 'String');
+    expect(hover.propagatedType, isNull);
+  }
+
+  Future<void> test_class_method_declaration() async {
+    addTestFile('''
+library my.library;
+class A {
+  /// doc aaa
+  /// doc bbb
+  List<String> mmm(int a, String b) {
+  }
+}
+''');
+    var hover = await prepareHover('mmm(int a');
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'A');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'List<String> mmm(int a, String b)');
+    expect(hover.elementKind, 'method');
+    // types
+    expect(hover.staticType, isNull);
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
+  }
+
+  Future<void> test_class_method_reference() async {
+    addTestFile('''
+library my.library;
+class A {
+  List<String> mmm(int a, String b) {
+  }
+}
+void f(A a) {
+  a.mmm(42, 'foo');
+}
+''');
+    var hover = await prepareHover('mm(42, ');
+    // range
+    expect(hover.offset, findOffset('mmm(42, '));
+    expect(hover.length, 'mmm'.length);
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.elementDescription, 'List<String> mmm(int a, String b)');
+    expect(hover.elementKind, 'method');
+    expect(hover.isDeprecated, isFalse);
+    // types
+    expect(hover.staticType, 'List<String> Function(int, String)');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
+  }
+
+  Future<void> test_class_method_reference_deprecated() async {
+    addTestFile('''
+class A {
+  @deprecated
+  static void test() {}
+}
+void f() {
+  A.test();
+}
+''');
+    var hover = await prepareHover('test();');
+    // element
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.elementDescription, 'void test()');
+    expect(hover.elementKind, 'method');
+    expect(hover.isDeprecated, isTrue);
+  }
+
+  Future<void> test_class_method_reference_genericMethod() async {
+    addTestFile('''
+library my.library;
+
+abstract class Stream<T> {
+  Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer);
+}
+abstract class StreamTransformer<T, S> {}
+
+f(Stream<int> s) {
+  s.transform(null);
+}
+''');
+    var hover = await prepareHover('nsform(n');
+    // range
+    expect(hover.offset, findOffset('transform(n'));
+    expect(hover.length, 'transform'.length);
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.elementDescription,
+        'Stream<S> transform<S>(StreamTransformer<int, S> streamTransformer)');
+    expect(hover.elementKind, 'method');
+    expect(hover.isDeprecated, isFalse);
+    // types
+    expect(hover.staticType,
+        'Stream<dynamic> Function(StreamTransformer<int, dynamic>)');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
+  }
+
+  Future<void> test_class_setter_hasDocumentation() async {
+    addTestFile('''
+class A {
+  /// getting
+  int get foo => 42;
+  /// setting
+  set foo(int x) {}
+}
+void f(A a) {
+  a.foo = 123;
+}
+''');
+    var hover = await prepareHover('foo = ');
+    expect(hover.containingClassDescription, 'A');
+    expect(hover.dartdoc, '''setting''');
+    expect(hover.elementDescription, 'void set foo(int x)');
+    expect(hover.elementKind, 'setter');
+  }
+
+  Future<void> test_class_setter_noDocumentation() async {
+    addTestFile('''
+class A {
+  /// getting
+  int get foo => 42;
+  set foo(int x) {}
+}
+void f(A a) {
+  a.foo = 123;
+}
+''');
+    var hover = await prepareHover('foo = ');
+    expect(hover.containingClassDescription, 'A');
+    expect(hover.dartdoc, '''getting''');
+    expect(hover.elementDescription, 'void set foo(int x)');
+    expect(hover.elementKind, 'setter');
+  }
+
+  Future<void> test_class_setter_super_hasDocumentation() async {
+    addTestFile('''
+class A {
+  /// pgetting
+  int get foo => 42;
+  /// psetting
+  set foo(int x) {}
+}
+class B extends A {
+  /// getting
+  int get foo => 42;
+  set foo(int x) {}
+}
+void f(B b) {
+  b.foo = 123;
+}
+''');
+    var hover = await prepareHover('foo = ');
+    expect(hover.containingClassDescription, 'B');
+    expect(hover.dartdoc, '''psetting\n\nCopied from `A`.''');
+    expect(hover.elementDescription, 'void set foo(int x)');
+    expect(hover.elementKind, 'setter');
+  }
+
+  Future<void> test_class_setter_super_noDocumentation() async {
+    addTestFile('''
+class A {
+  /// pgetting
+  int get foo => 42;
+  set foo(int x) {}
+}
+class B extends A {
+  int get foo => 42;
+  set foo(int x) {}
+}
+void f(B b) {
+  b.foo = 123;
+}
+''');
+    var hover = await prepareHover('foo = ');
+    expect(hover.containingClassDescription, 'B');
+    expect(hover.dartdoc, '''pgetting\n\nCopied from `A`.''');
+    expect(hover.elementDescription, 'void set foo(int x)');
+    expect(hover.elementKind, 'setter');
+  }
+
+  @failingTest
+  Future<void> test_class_setter_super_noSetter() async {
+    addTestFile('''
+class A {
+  /// pgetting
+  int get foo => 42;
+}
+class B extends A {
+  set foo(int x) {}
+}
+void f(B b) {
+  b.foo = 123;
+}
+''');
+    var hover = await prepareHover('foo = ');
+    expect(hover.containingClassDescription, 'B');
+    expect(hover.dartdoc, '''pgetting''');
+    expect(hover.elementDescription, 'void set foo(int x)');
+    expect(hover.elementKind, 'setter');
+  }
+
   Future<void> test_dartdoc_block() async {
     addTestFile('''
 /**
@@ -453,6 +685,131 @@
     expect(hover.propagatedType, isNull);
   }
 
+  Future<void> test_enum_getter() async {
+    addTestFile('''
+library my.library;
+enum E {
+  v;
+  /// doc aaa
+  /// doc bbb
+  int get foo => 0;
+}
+void f(E e) {
+  print(e.foo);
+}
+''');
+    var hover = await prepareHover('foo);');
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'E');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'int get foo');
+    expect(hover.elementKind, 'getter');
+  }
+
+  Future<void> test_enum_getter_synthetic() async {
+    addTestFile('''
+library my.library;
+enum E {
+  v;
+  /// doc aaa
+  /// doc bbb
+  final String fff;
+}
+void f(E e) {
+  print(e.fff);
+}
+''');
+    var hover = await prepareHover('fff);');
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'E');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'String fff');
+    expect(hover.elementKind, 'field');
+    // types
+    expect(hover.staticType, 'String');
+    expect(hover.propagatedType, isNull);
+  }
+
+  Future<void> test_enum_method_declaration() async {
+    addTestFile('''
+library my.library;
+enum E {
+  v;
+  /// doc aaa
+  /// doc bbb
+  List<String> mmm(int a, String b) {
+  }
+}
+''');
+    var hover = await prepareHover('mmm(int a');
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'E');
+    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+    expect(hover.elementDescription, 'List<String> mmm(int a, String b)');
+    expect(hover.elementKind, 'method');
+    // types
+    expect(hover.staticType, isNull);
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
+  }
+
+  Future<void> test_enum_method_reference() async {
+    addTestFile('''
+library my.library;
+enum E {
+  v;
+  List<String> mmm(int a, String b) {
+  }
+}
+void f(E e) {
+  e.mmm(42, 'foo');
+}
+''');
+    var hover = await prepareHover('mm(42, ');
+    // range
+    expect(hover.offset, findOffset('mmm(42, '));
+    expect(hover.length, 'mmm'.length);
+    // element
+    expect(hover.containingLibraryName, 'bin/test.dart');
+    expect(hover.containingLibraryPath, testFile);
+    expect(hover.containingClassDescription, 'E');
+    expect(hover.elementDescription, 'List<String> mmm(int a, String b)');
+    expect(hover.elementKind, 'method');
+    expect(hover.isDeprecated, isFalse);
+    // types
+    expect(hover.staticType, 'List<String> Function(int, String)');
+    expect(hover.propagatedType, isNull);
+    // no parameter
+    expect(hover.parameter, isNull);
+  }
+
+  Future<void> test_enum_setter_hasDocumentation() async {
+    addTestFile('''
+enum E {
+  v;
+  /// getting
+  int get foo => 42;
+  /// setting
+  set foo(int x) {}
+}
+void f(E e) {
+  e.foo = 123;
+}
+''');
+    var hover = await prepareHover('foo = ');
+    expect(hover.containingClassDescription, 'E');
+    expect(hover.dartdoc, '''setting''');
+    expect(hover.elementDescription, 'void set foo(int x)');
+    expect(hover.elementKind, 'setter');
+  }
+
   Future<void> test_extensionDeclaration() async {
     addTestFile('''
 class A {}
@@ -586,31 +943,6 @@
     expect(hover.parameter, isNull);
   }
 
-  Future<void> test_getter_synthetic() async {
-    addTestFile('''
-library my.library;
-class A {
-  /// doc aaa
-  /// doc bbb
-  String fff;
-}
-void f(A a) {
-  print(a.fff);
-}
-''');
-    var hover = await prepareHover('fff);');
-    // element
-    expect(hover.containingLibraryName, 'bin/test.dart');
-    expect(hover.containingLibraryPath, testFile);
-    expect(hover.containingClassDescription, 'A');
-    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-    expect(hover.elementDescription, 'String fff');
-    expect(hover.elementKind, 'field');
-    // types
-    expect(hover.staticType, 'String');
-    expect(hover.propagatedType, isNull);
-  }
-
   Future<void> test_integerLiteral() async {
     addTestFile('''
 void f() {
@@ -726,109 +1058,6 @@
     expect(hover.propagatedType, null);
   }
 
-  Future<void> test_method_declaration() async {
-    addTestFile('''
-library my.library;
-class A {
-  /// doc aaa
-  /// doc bbb
-  List<String> mmm(int a, String b) {
-  }
-}
-''');
-    var hover = await prepareHover('mmm(int a');
-    // element
-    expect(hover.containingLibraryName, 'bin/test.dart');
-    expect(hover.containingLibraryPath, testFile);
-    expect(hover.containingClassDescription, 'A');
-    expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
-    expect(hover.elementDescription, 'List<String> mmm(int a, String b)');
-    expect(hover.elementKind, 'method');
-    // types
-    expect(hover.staticType, isNull);
-    expect(hover.propagatedType, isNull);
-    // no parameter
-    expect(hover.parameter, isNull);
-  }
-
-  Future<void> test_method_reference() async {
-    addTestFile('''
-library my.library;
-class A {
-  List<String> mmm(int a, String b) {
-  }
-}
-void f(A a) {
-  a.mmm(42, 'foo');
-}
-''');
-    var hover = await prepareHover('mm(42, ');
-    // range
-    expect(hover.offset, findOffset('mmm(42, '));
-    expect(hover.length, 'mmm'.length);
-    // element
-    expect(hover.containingLibraryName, 'bin/test.dart');
-    expect(hover.containingLibraryPath, testFile);
-    expect(hover.elementDescription, 'List<String> mmm(int a, String b)');
-    expect(hover.elementKind, 'method');
-    expect(hover.isDeprecated, isFalse);
-    // types
-    expect(hover.staticType, 'List<String> Function(int, String)');
-    expect(hover.propagatedType, isNull);
-    // no parameter
-    expect(hover.parameter, isNull);
-  }
-
-  Future<void> test_method_reference_deprecated() async {
-    addTestFile('''
-class A {
-  @deprecated
-  static void test() {}
-}
-void f() {
-  A.test();
-}
-''');
-    var hover = await prepareHover('test();');
-    // element
-    expect(hover.containingLibraryPath, testFile);
-    expect(hover.elementDescription, 'void test()');
-    expect(hover.elementKind, 'method');
-    expect(hover.isDeprecated, isTrue);
-  }
-
-  Future<void> test_method_reference_genericMethod() async {
-    addTestFile('''
-library my.library;
-
-abstract class Stream<T> {
-  Stream<S> transform<S>(StreamTransformer<T, S> streamTransformer);
-}
-abstract class StreamTransformer<T, S> {}
-
-f(Stream<int> s) {
-  s.transform(null);
-}
-''');
-    var hover = await prepareHover('nsform(n');
-    // range
-    expect(hover.offset, findOffset('transform(n'));
-    expect(hover.length, 'transform'.length);
-    // element
-    expect(hover.containingLibraryName, 'bin/test.dart');
-    expect(hover.containingLibraryPath, testFile);
-    expect(hover.elementDescription,
-        'Stream<S> transform<S>(StreamTransformer<int, S> streamTransformer)');
-    expect(hover.elementKind, 'method');
-    expect(hover.isDeprecated, isFalse);
-    // types
-    expect(hover.staticType,
-        'Stream<dynamic> Function(StreamTransformer<int, dynamic>)');
-    expect(hover.propagatedType, isNull);
-    // no parameter
-    expect(hover.parameter, isNull);
-  }
-
   Future<void> test_mixin_declaration() async {
     addTestFile('''
 mixin A on B, C implements D, E {}
@@ -1002,110 +1231,6 @@
     expect(hover.staticType, 'int');
   }
 
-  Future<void> test_setter_hasDocumentation() async {
-    addTestFile('''
-class A {
-  /// getting
-  int get foo => 42;
-  /// setting
-  set foo(int x) {}
-}
-void f(A a) {
-  a.foo = 123;
-}
-''');
-    var hover = await prepareHover('foo = ');
-    expect(hover.containingClassDescription, 'A');
-    expect(hover.dartdoc, '''setting''');
-    expect(hover.elementDescription, 'void set foo(int x)');
-    expect(hover.elementKind, 'setter');
-  }
-
-  Future<void> test_setter_noDocumentation() async {
-    addTestFile('''
-class A {
-  /// getting
-  int get foo => 42;
-  set foo(int x) {}
-}
-void f(A a) {
-  a.foo = 123;
-}
-''');
-    var hover = await prepareHover('foo = ');
-    expect(hover.containingClassDescription, 'A');
-    expect(hover.dartdoc, '''getting''');
-    expect(hover.elementDescription, 'void set foo(int x)');
-    expect(hover.elementKind, 'setter');
-  }
-
-  Future<void> test_setter_super_hasDocumentation() async {
-    addTestFile('''
-class A {
-  /// pgetting
-  int get foo => 42;
-  /// psetting
-  set foo(int x) {}
-}
-class B extends A {
-  /// getting
-  int get foo => 42;
-  set foo(int x) {}
-}
-void f(B b) {
-  b.foo = 123;
-}
-''');
-    var hover = await prepareHover('foo = ');
-    expect(hover.containingClassDescription, 'B');
-    expect(hover.dartdoc, '''psetting\n\nCopied from `A`.''');
-    expect(hover.elementDescription, 'void set foo(int x)');
-    expect(hover.elementKind, 'setter');
-  }
-
-  Future<void> test_setter_super_noDocumentation() async {
-    addTestFile('''
-class A {
-  /// pgetting
-  int get foo => 42;
-  set foo(int x) {}
-}
-class B extends A {
-  int get foo => 42;
-  set foo(int x) {}
-}
-void f(B b) {
-  b.foo = 123;
-}
-''');
-    var hover = await prepareHover('foo = ');
-    expect(hover.containingClassDescription, 'B');
-    expect(hover.dartdoc, '''pgetting\n\nCopied from `A`.''');
-    expect(hover.elementDescription, 'void set foo(int x)');
-    expect(hover.elementKind, 'setter');
-  }
-
-  @failingTest
-  Future<void> test_setter_super_noSetter() async {
-    addTestFile('''
-class A {
-  /// pgetting
-  int get foo => 42;
-}
-class B extends A {
-  set foo(int x) {}
-}
-void f(B b) {
-  b.foo = 123;
-}
-''');
-    var hover = await prepareHover('foo = ');
-    expect(hover.containingClassDescription, 'B');
-    expect(hover.dartdoc, '''pgetting''');
-    expect(hover.elementDescription, 'void set foo(int x)');
-    expect(hover.elementKind, 'setter');
-  }
-
   Future<void> test_simpleIdentifier_typedef_functionType() async {
     addTestFile('''
 typedef A = void Function(int);
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index 2ed436f..c0d0616 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -371,6 +371,44 @@
     ]);
   }
 
+  Future<void> test_class_fromField_toMixinGetter() async {
+    addTestFile('''
+abstract class A {
+  var test = 1;
+}
+class Mixin {
+  get test => 2;
+}
+class B extends A with Mixin {}
+''');
+    var items = await _getTypeHierarchy('test = 1;');
+    var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+    var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+    var memberA = itemA.memberElement!;
+    var memberB = itemB.memberElement!;
+    expect(memberA.location!.offset, findOffset('test = 1;'));
+    expect(memberB.location!.offset, findOffset('test => 2;'));
+  }
+
+  Future<void> test_class_fromField_toMixinSetter() async {
+    addTestFile('''
+abstract class A {
+  var test = 1;
+}
+class Mixin {
+  set test(m) {}
+}
+class B extends A with Mixin {}
+''');
+    var items = await _getTypeHierarchy('test = 1;');
+    var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+    var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+    var memberA = itemA.memberElement!;
+    var memberB = itemB.memberElement!;
+    expect(memberA.location!.offset, findOffset('test = 1;'));
+    expect(memberB.location!.offset, findOffset('test(m) {}'));
+  }
+
   Future<void> test_class_implementsTypes() async {
     addTestFile('''
 class MA {}
@@ -432,6 +470,484 @@
     ]);
   }
 
+  Future<void> test_class_member_fromField_toField() async {
+    addTestFile('''
+class A {
+  var test = 1;
+}
+class B extends A {
+  var test = 2;
+}
+''');
+
+    void checkItems(List<TypeHierarchyItem> items) {
+      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+      var memberA = itemA.memberElement!;
+      var memberB = itemB.memberElement!;
+      expect(memberA.location!.offset, findOffset('test = 1;'));
+      expect(memberB.location!.offset, findOffset('test = 2;'));
+    }
+
+    checkItems(await _getTypeHierarchy('test = 1;'));
+    checkItems(await _getTypeHierarchy('test = 2;'));
+  }
+
+  Future<void> test_class_member_fromField_toGetter() async {
+    addTestFile('''
+class A {
+  get test => 1;
+}
+class B extends A {
+  var test = 2;
+}
+''');
+
+    void checkItems(List<TypeHierarchyItem> items) {
+      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+      var memberA = itemA.memberElement!;
+      var memberB = itemB.memberElement!;
+      expect(memberA.location!.offset, findOffset('test => 1'));
+      expect(memberB.location!.offset, findOffset('test = 2;'));
+    }
+
+    checkItems(await _getTypeHierarchy('test => 1;'));
+    checkItems(await _getTypeHierarchy('test = 2;'));
+  }
+
+  Future<void> test_class_member_fromField_toSetter() async {
+    addTestFile('''
+class A {
+  set test(a) {}
+}
+class B extends A {
+  var test = 2;
+}
+''');
+
+    void checkItems(List<TypeHierarchyItem> items) {
+      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+      var memberA = itemA.memberElement!;
+      var memberB = itemB.memberElement!;
+      expect(memberA.location!.offset, findOffset('test(a) {}'));
+      expect(memberB.location!.offset, findOffset('test = 2;'));
+    }
+
+    checkItems(await _getTypeHierarchy('test(a) {}'));
+    checkItems(await _getTypeHierarchy('test = 2;'));
+  }
+
+  Future<void> test_class_member_fromFinalField_toGetter() async {
+    addTestFile('''
+class A {
+  get test => 1;
+}
+class B extends A {
+  final test = 2;
+}
+''');
+
+    void checkItems(List<TypeHierarchyItem> items) {
+      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+      var memberA = itemA.memberElement!;
+      var memberB = itemB.memberElement!;
+      expect(memberA.location!.offset, findOffset('test => 1'));
+      expect(memberB.location!.offset, findOffset('test = 2;'));
+    }
+
+    checkItems(await _getTypeHierarchy('test => 1;'));
+    checkItems(await _getTypeHierarchy('test = 2;'));
+  }
+
+  Future<void> test_class_member_fromFinalField_toSetter() async {
+    addTestFile('''
+class A {
+  set test(x) {}
+}
+class B extends A {
+  final test = 2;
+}
+''');
+    var items = await _getTypeHierarchy('test = 2;');
+    var itemA = items.firstWhere((e) => e.classElement.name == 'A');
+    var itemB = items.firstWhere((e) => e.classElement.name == 'B');
+    expect(itemA.memberElement, isNull);
+    expect(itemB.memberElement!.location!.offset, findOffset('test = 2;'));
+  }
+
+  Future<void> test_class_member_getter() async {
+    addTestFile('''
+class A {
+  get test => null; // in A
+}
+class B extends A {
+  get test => null; // in B
+}
+class C extends B {
+}
+class D extends C {
+  get test => null; // in D
+}
+''');
+    var items = await _getTypeHierarchy('test => null; // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemD = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemD.classElement.name, 'D');
+    expect(itemA.memberElement!.location!.offset,
+        findOffset('test => null; // in A'));
+    expect(itemB.memberElement!.location!.offset,
+        findOffset('test => null; // in B'));
+    expect(itemC.memberElement, isNull);
+    expect(itemD.memberElement!.location!.offset,
+        findOffset('test => null; // in D'));
+  }
+
+  Future<void> test_class_member_method() async {
+    addTestFile('''
+class A {
+  test() {} // in A
+}
+class B extends A {
+  test() {} // in B
+}
+class C extends B {
+}
+class D extends C {
+  test() {} // in D
+}
+''');
+    var items = await _getTypeHierarchy('test() {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemD = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemD.classElement.name, 'D');
+    expect(
+        itemA.memberElement!.location!.offset, findOffset('test() {} // in A'));
+    expect(
+        itemB.memberElement!.location!.offset, findOffset('test() {} // in B'));
+    expect(itemC.memberElement, isNull);
+    expect(
+        itemD.memberElement!.location!.offset, findOffset('test() {} // in D'));
+  }
+
+  Future<void> test_class_member_method_private_differentLib() async {
+    newFile(join(testFolder, 'lib.dart'), content: r'''
+import 'test.dart';
+class A {
+  void _m() {}
+}
+class C extends B {
+  void _m() {}
+}
+''');
+    addTestFile('''
+import 'lib.dart';
+class B extends A {
+  _m() {} // in B
+}
+class D extends C {
+  _m() {} // in D
+}
+''');
+    var items = await _getTypeHierarchy('_m() {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemD = items[itemC.subclasses[0]];
+    expect(itemB.classElement.name, 'B');
+    expect(itemA.classElement.name, 'A');
+    expect(itemC.classElement.name, 'C');
+    expect(itemD.classElement.name, 'D');
+    expect(itemA.memberElement, isNull);
+    expect(itemC.memberElement, isNull);
+    expect(itemB.memberElement, isNotNull);
+    expect(itemD.memberElement, isNotNull);
+  }
+
+  Future<void> test_class_member_method_private_sameLib() async {
+    addTestFile('''
+class A {
+  _m() {} // in A
+}
+class B extends A {
+  _m() {} // in B
+}
+class C extends B {
+  _m() {} // in C
+}
+''');
+    var items = await _getTypeHierarchy('_m() {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(
+        itemA.memberElement!.location!.offset, findOffset('_m() {} // in A'));
+    expect(
+        itemB.memberElement!.location!.offset, findOffset('_m() {} // in B'));
+    expect(
+        itemC.memberElement!.location!.offset, findOffset('_m() {} // in C'));
+  }
+
+  Future<void> test_class_member_ofMixin2_method() async {
+    addTestFile('''
+class M1 {
+  void test() {} // in M1
+}
+class M2 {
+  void test() {} // in M2
+}
+class D1 extends Object with M1 {}
+class D2 extends Object with M1, M2 {}
+class D3 extends Object with M2, M1 {}
+class D4 extends Object with M2, M1 {
+  void test() {} // in D4
+}
+''');
+    var items = await _getTypeHierarchy('test() {} // in M1');
+    var itemM1 = items.firstWhere((e) => e.classElement.name == 'M1');
+    var item1 = items.firstWhere((e) => e.classElement.name == 'D1');
+    var item2 = items.firstWhere((e) => e.classElement.name == 'D2');
+    var item3 = items.firstWhere((e) => e.classElement.name == 'D3');
+    var item4 = items.firstWhere((e) => e.classElement.name == 'D4');
+    expect(itemM1, isNotNull);
+    expect(item1, isNotNull);
+    expect(item2, isNotNull);
+    expect(item3, isNotNull);
+    expect(item4, isNotNull);
+    // D1 does not override
+    {
+      var member1 = item1.memberElement;
+      expect(member1, isNull);
+    }
+    // D2 mixes-in M2 last, which overrides
+    {
+      var member2 = item2.memberElement!;
+      expect(member2.location!.offset, findOffset('test() {} // in M2'));
+    }
+    // D3 mixes-in M1 last and does not override itself
+    {
+      var member3 = item3.memberElement;
+      expect(member3, isNull);
+    }
+    // D4 mixes-in M1 last, but it also overrides
+    {
+      var member4 = item4.memberElement!;
+      expect(member4.location!.offset, findOffset('test() {} // in D4'));
+    }
+  }
+
+  Future<void> test_class_member_ofMixin_getter() async {
+    addTestFile('''
+abstract class Base {
+  get test; // in Base
+}
+class Mixin {
+  get test => null; // in Mixin
+}
+class Derived1 extends Base with Mixin {}
+class Derived2 extends Base {
+  get test => null; // in Derived2
+}
+''');
+    var items = await _getTypeHierarchy('test; // in Base');
+    var itemBase = items.firstWhere((e) => e.classElement.name == 'Base');
+    var item1 = items.firstWhere((e) => e.classElement.name == 'Derived1');
+    var item2 = items.firstWhere((e) => e.classElement.name == 'Derived2');
+    var memberBase = itemBase.memberElement!;
+    var member1 = item1.memberElement!;
+    var member2 = item2.memberElement!;
+    expect(memberBase.location!.offset, findOffset('test; // in Base'));
+    expect(member1.location!.offset, findOffset('test => null; // in Mixin'));
+    expect(
+        member2.location!.offset, findOffset('test => null; // in Derived2'));
+  }
+
+  Future<void> test_class_member_ofMixin_method() async {
+    addTestFile('''
+abstract class Base {
+  void test(); // in Base
+}
+class Mixin {
+  void test() {} // in Mixin
+}
+class Derived1 extends Base with Mixin {}
+class Derived2 extends Base {
+  void test() {} // in Derived2
+}
+''');
+    var items = await _getTypeHierarchy('test(); // in Base');
+    var itemBase = items.firstWhere((e) => e.classElement.name == 'Base');
+    var item1 = items.firstWhere((e) => e.classElement.name == 'Derived1');
+    var item2 = items.firstWhere((e) => e.classElement.name == 'Derived2');
+    var memberBase = itemBase.memberElement!;
+    var member1 = item1.memberElement!;
+    var member2 = item2.memberElement!;
+    expect(memberBase.location!.offset, findOffset('test(); // in Base'));
+    expect(member1.location!.offset, findOffset('test() {} // in Mixin'));
+    expect(member2.location!.offset, findOffset('test() {} // in Derived2'));
+  }
+
+  Future<void> test_class_member_ofMixin_setter() async {
+    addTestFile('''
+abstract class Base {
+  set test(x); // in Base
+}
+class Mixin {
+  set test(x) {} // in Mixin
+}
+class Derived1 extends Base with Mixin {}
+class Derived2 extends Base {
+  set test(x) {} // in Derived2
+}
+''');
+    var items = await _getTypeHierarchy('test(x); // in Base');
+    var itemBase = items.firstWhere((e) => e.classElement.name == 'Base');
+    var item1 = items.firstWhere((e) => e.classElement.name == 'Derived1');
+    var item2 = items.firstWhere((e) => e.classElement.name == 'Derived2');
+    var memberBase = itemBase.memberElement!;
+    var member1 = item1.memberElement!;
+    var member2 = item2.memberElement!;
+    expect(memberBase.location!.offset, findOffset('test(x); // in Base'));
+    expect(member1.location!.offset, findOffset('test(x) {} // in Mixin'));
+    expect(member2.location!.offset, findOffset('test(x) {} // in Derived2'));
+  }
+
+  Future<void> test_class_member_ofSuperclassConstraint_getter() async {
+    addTestFile('''
+class A {
+  get test => 0; // in A
+}
+
+mixin M on A {
+  get test => 0; // in M
+}
+''');
+    var items = await _getTypeHierarchy('test => 0; // in A');
+
+    var inA = items.firstWhere((e) => e.classElement.name == 'A');
+    var inM = items.firstWhere((e) => e.classElement.name == 'M');
+
+    _assertMember(inA, 'test => 0; // in A');
+    _assertMember(inM, 'test => 0; // in M');
+  }
+
+  Future<void> test_class_member_ofSuperclassConstraint_method() async {
+    addTestFile('''
+class A {
+  void test() {} // in A
+}
+
+mixin M on A {
+  void test() {} // in M
+}
+''');
+    var items = await _getTypeHierarchy('test() {} // in A');
+
+    var inA = items.firstWhere((e) => e.classElement.name == 'A');
+    var inM = items.firstWhere((e) => e.classElement.name == 'M');
+
+    _assertMember(inA, 'test() {} // in A');
+    _assertMember(inM, 'test() {} // in M');
+  }
+
+  Future<void> test_class_member_ofSuperclassConstraint_setter() async {
+    addTestFile('''
+class A {
+  set test(x) {} // in A
+}
+
+mixin M on A {
+  set test(x) {} // in M
+}
+''');
+    var items = await _getTypeHierarchy('test(x) {} // in A');
+
+    var inA = items.firstWhere((e) => e.classElement.name == 'A');
+    var inM = items.firstWhere((e) => e.classElement.name == 'M');
+
+    _assertMember(inA, 'test(x) {} // in A');
+    _assertMember(inM, 'test(x) {} // in M');
+  }
+
+  Future<void> test_class_member_operator() async {
+    addTestFile('''
+class A {
+  operator ==(x) => null; // in A
+}
+class B extends A {
+  operator ==(x) => null; // in B
+}
+class C extends B {
+}
+class D extends C {
+  operator ==(x) => null; // in D
+}
+''');
+    var items = await _getTypeHierarchy('==(x) => null; // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemD = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemD.classElement.name, 'D');
+    expect(itemA.memberElement!.location!.offset,
+        findOffset('==(x) => null; // in A'));
+    expect(itemB.memberElement!.location!.offset,
+        findOffset('==(x) => null; // in B'));
+    expect(itemC.memberElement, isNull);
+    expect(itemD.memberElement!.location!.offset,
+        findOffset('==(x) => null; // in D'));
+  }
+
+  Future<void> test_class_member_setter() async {
+    addTestFile('''
+class A {
+  set test(x) {} // in A
+}
+class B extends A {
+  set test(x) {} // in B
+}
+class C extends B {
+}
+class D extends C {
+  set test(x) {} // in D
+}
+''');
+    var items = await _getTypeHierarchy('test(x) {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemD = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemD.classElement.name, 'D');
+    expect(itemA.memberElement!.location!.offset,
+        findOffset('test(x) {} // in A'));
+    expect(itemB.memberElement!.location!.offset,
+        findOffset('test(x) {} // in B'));
+    expect(itemC.memberElement, isNull);
+    expect(itemD.memberElement!.location!.offset,
+        findOffset('test(x) {} // in D'));
+  }
+
   Future<void> test_class_order() async {
     addTestFile('''
 class A {}
@@ -542,6 +1058,76 @@
     ]);
   }
 
+  Future<void> test_class_superOnly() async {
+    addTestFile('''
+class A {}
+class B {}
+class C extends A implements B {}
+class D extends C {}
+''');
+    var items = await _getTypeHierarchy('C extends', superOnly: true);
+    expect(_toJson(items), [
+      {
+        'classElement': {
+          'kind': 'CLASS',
+          'name': 'C',
+          'location': anything,
+          'flags': 0
+        },
+        'superclass': 1,
+        'interfaces': [3],
+        'mixins': [],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'CLASS',
+          'name': 'A',
+          'location': anything,
+          'flags': 0
+        },
+        'superclass': 2,
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'CLASS',
+          'name': 'Object',
+          'location': anything,
+          'flags': 0
+        },
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'CLASS',
+          'name': 'B',
+          'location': anything,
+          'flags': 0
+        },
+        'superclass': 2,
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      }
+    ]);
+  }
+
+  Future<void> test_class_superOnly_fileDoesNotExist() async {
+    var request = SearchGetTypeHierarchyParams(
+            convertPath('/does/not/exist.dart'), 0,
+            superOnly: true)
+        .toRequest(requestId);
+    var response = await serverChannel.sendRequest(request);
+    var items =
+        SearchGetTypeHierarchyResult.fromResponse(response).hierarchyItems;
+    expect(items, isNull);
+  }
+
   Future<void> test_class_withTypes() async {
     addTestFile('''
 class MA {}
@@ -603,549 +1189,57 @@
     ]);
   }
 
-  Future<void> test_fromField_toMixinGetter() async {
+  Future<void> test_enum_displayName() async {
     addTestFile('''
-abstract class A {
-  var test = 1;
-}
-class Mixin {
-  get test => 2;
-}
-class B extends A with Mixin {}
-''');
-    var items = await _getTypeHierarchy('test = 1;');
-    var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-    var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-    var memberA = itemA.memberElement!;
-    var memberB = itemB.memberElement!;
-    expect(memberA.location!.offset, findOffset('test = 1;'));
-    expect(memberB.location!.offset, findOffset('test => 2;'));
-  }
+mixin M<T> {}
 
-  Future<void> test_fromField_toMixinSetter() async {
-    addTestFile('''
-abstract class A {
-  var test = 1;
-}
-class Mixin {
-  set test(m) {}
-}
-class B extends A with Mixin {}
-''');
-    var items = await _getTypeHierarchy('test = 1;');
-    var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-    var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-    var memberA = itemA.memberElement!;
-    var memberB = itemB.memberElement!;
-    expect(memberA.location!.offset, findOffset('test = 1;'));
-    expect(memberB.location!.offset, findOffset('test(m) {}'));
-  }
-
-  Future<void> test_member_fromField_toField() async {
-    addTestFile('''
-class A {
-  var test = 1;
-}
-class B extends A {
-  var test = 2;
+enum E with M<int> {
+  v;
 }
 ''');
+    var items = await _getTypeHierarchy('E with');
 
-    void checkItems(List<TypeHierarchyItem> items) {
-      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-      var memberA = itemA.memberElement!;
-      var memberB = itemB.memberElement!;
-      expect(memberA.location!.offset, findOffset('test = 1;'));
-      expect(memberB.location!.offset, findOffset('test = 2;'));
-    }
-
-    checkItems(await _getTypeHierarchy('test = 1;'));
-    checkItems(await _getTypeHierarchy('test = 2;'));
-  }
-
-  Future<void> test_member_fromField_toGetter() async {
-    addTestFile('''
-class A {
-  get test => 1;
-}
-class B extends A {
-  var test = 2;
-}
-''');
-
-    void checkItems(List<TypeHierarchyItem> items) {
-      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-      var memberA = itemA.memberElement!;
-      var memberB = itemB.memberElement!;
-      expect(memberA.location!.offset, findOffset('test => 1'));
-      expect(memberB.location!.offset, findOffset('test = 2;'));
-    }
-
-    checkItems(await _getTypeHierarchy('test => 1;'));
-    checkItems(await _getTypeHierarchy('test = 2;'));
-  }
-
-  Future<void> test_member_fromField_toSetter() async {
-    addTestFile('''
-class A {
-  set test(a) {}
-}
-class B extends A {
-  var test = 2;
-}
-''');
-
-    void checkItems(List<TypeHierarchyItem> items) {
-      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-      var memberA = itemA.memberElement!;
-      var memberB = itemB.memberElement!;
-      expect(memberA.location!.offset, findOffset('test(a) {}'));
-      expect(memberB.location!.offset, findOffset('test = 2;'));
-    }
-
-    checkItems(await _getTypeHierarchy('test(a) {}'));
-    checkItems(await _getTypeHierarchy('test = 2;'));
-  }
-
-  Future<void> test_member_fromFinalField_toGetter() async {
-    addTestFile('''
-class A {
-  get test => 1;
-}
-class B extends A {
-  final test = 2;
-}
-''');
-
-    void checkItems(List<TypeHierarchyItem> items) {
-      var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-      var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-      var memberA = itemA.memberElement!;
-      var memberB = itemB.memberElement!;
-      expect(memberA.location!.offset, findOffset('test => 1'));
-      expect(memberB.location!.offset, findOffset('test = 2;'));
-    }
-
-    checkItems(await _getTypeHierarchy('test => 1;'));
-    checkItems(await _getTypeHierarchy('test = 2;'));
-  }
-
-  Future<void> test_member_fromFinalField_toSetter() async {
-    addTestFile('''
-class A {
-  set test(x) {}
-}
-class B extends A {
-  final test = 2;
-}
-''');
-    var items = await _getTypeHierarchy('test = 2;');
-    var itemA = items.firstWhere((e) => e.classElement.name == 'A');
-    var itemB = items.firstWhere((e) => e.classElement.name == 'B');
-    expect(itemA.memberElement, isNull);
-    expect(itemB.memberElement!.location!.offset, findOffset('test = 2;'));
-  }
-
-  Future<void> test_member_getter() async {
-    addTestFile('''
-class A {
-  get test => null; // in A
-}
-class B extends A {
-  get test => null; // in B
-}
-class C extends B {
-}
-class D extends C {
-  get test => null; // in D
-}
-''');
-    var items = await _getTypeHierarchy('test => null; // in B');
     var itemB = items[0];
+    expect(itemB.classElement.name, 'E');
+
     var itemA = items[itemB.superclass!];
-    var itemC = items[itemB.subclasses[0]];
-    var itemD = items[itemC.subclasses[0]];
-    expect(itemA.classElement.name, 'A');
-    expect(itemB.classElement.name, 'B');
-    expect(itemC.classElement.name, 'C');
-    expect(itemD.classElement.name, 'D');
-    expect(itemA.memberElement!.location!.offset,
-        findOffset('test => null; // in A'));
-    expect(itemB.memberElement!.location!.offset,
-        findOffset('test => null; // in B'));
-    expect(itemC.memberElement, isNull);
-    expect(itemD.memberElement!.location!.offset,
-        findOffset('test => null; // in D'));
+    expect(itemA.classElement.name, 'Enum');
+    expect(itemA.displayName, isNull);
+
+    expect(itemB.mixins, hasLength(1));
+    var itemM = items[itemB.mixins[0]];
+    expect(itemM.classElement.name, 'M');
+    expect(itemM.displayName, 'M<int>');
   }
 
-  Future<void> test_member_method() async {
-    addTestFile('''
-class A {
-  test() {} // in A
-}
-class B extends A {
-  test() {} // in B
-}
-class C extends B {
-}
-class D extends C {
-  test() {} // in D
-}
-''');
-    var items = await _getTypeHierarchy('test() {} // in B');
-    var itemB = items[0];
-    var itemA = items[itemB.superclass!];
-    var itemC = items[itemB.subclasses[0]];
-    var itemD = items[itemC.subclasses[0]];
-    expect(itemA.classElement.name, 'A');
-    expect(itemB.classElement.name, 'B');
-    expect(itemC.classElement.name, 'C');
-    expect(itemD.classElement.name, 'D');
-    expect(
-        itemA.memberElement!.location!.offset, findOffset('test() {} // in A'));
-    expect(
-        itemB.memberElement!.location!.offset, findOffset('test() {} // in B'));
-    expect(itemC.memberElement, isNull);
-    expect(
-        itemD.memberElement!.location!.offset, findOffset('test() {} // in D'));
-  }
-
-  Future<void> test_member_method_private_differentLib() async {
-    newFile(join(testFolder, 'lib.dart'), content: r'''
-import 'test.dart';
-class A {
-  void _m() {}
-}
-class C extends B {
-  void _m() {}
-}
-''');
-    addTestFile('''
-import 'lib.dart';
-class B extends A {
-  _m() {} // in B
-}
-class D extends C {
-  _m() {} // in D
-}
-''');
-    var items = await _getTypeHierarchy('_m() {} // in B');
-    var itemB = items[0];
-    var itemA = items[itemB.superclass!];
-    var itemC = items[itemB.subclasses[0]];
-    var itemD = items[itemC.subclasses[0]];
-    expect(itemB.classElement.name, 'B');
-    expect(itemA.classElement.name, 'A');
-    expect(itemC.classElement.name, 'C');
-    expect(itemD.classElement.name, 'D');
-    expect(itemA.memberElement, isNull);
-    expect(itemC.memberElement, isNull);
-    expect(itemB.memberElement, isNotNull);
-    expect(itemD.memberElement, isNotNull);
-  }
-
-  Future<void> test_member_method_private_sameLib() async {
-    addTestFile('''
-class A {
-  _m() {} // in A
-}
-class B extends A {
-  _m() {} // in B
-}
-class C extends B {
-  _m() {} // in C
-}
-''');
-    var items = await _getTypeHierarchy('_m() {} // in B');
-    var itemB = items[0];
-    var itemA = items[itemB.superclass!];
-    var itemC = items[itemB.subclasses[0]];
-    expect(itemA.classElement.name, 'A');
-    expect(itemB.classElement.name, 'B');
-    expect(itemC.classElement.name, 'C');
-    expect(
-        itemA.memberElement!.location!.offset, findOffset('_m() {} // in A'));
-    expect(
-        itemB.memberElement!.location!.offset, findOffset('_m() {} // in B'));
-    expect(
-        itemC.memberElement!.location!.offset, findOffset('_m() {} // in C'));
-  }
-
-  Future<void> test_member_ofMixin2_method() async {
-    addTestFile('''
-class M1 {
-  void test() {} // in M1
-}
-class M2 {
-  void test() {} // in M2
-}
-class D1 extends Object with M1 {}
-class D2 extends Object with M1, M2 {}
-class D3 extends Object with M2, M1 {}
-class D4 extends Object with M2, M1 {
-  void test() {} // in D4
-}
-''');
-    var items = await _getTypeHierarchy('test() {} // in M1');
-    var itemM1 = items.firstWhere((e) => e.classElement.name == 'M1');
-    var item1 = items.firstWhere((e) => e.classElement.name == 'D1');
-    var item2 = items.firstWhere((e) => e.classElement.name == 'D2');
-    var item3 = items.firstWhere((e) => e.classElement.name == 'D3');
-    var item4 = items.firstWhere((e) => e.classElement.name == 'D4');
-    expect(itemM1, isNotNull);
-    expect(item1, isNotNull);
-    expect(item2, isNotNull);
-    expect(item3, isNotNull);
-    expect(item4, isNotNull);
-    // D1 does not override
-    {
-      var member1 = item1.memberElement;
-      expect(member1, isNull);
-    }
-    // D2 mixes-in M2 last, which overrides
-    {
-      var member2 = item2.memberElement!;
-      expect(member2.location!.offset, findOffset('test() {} // in M2'));
-    }
-    // D3 mixes-in M1 last and does not override itself
-    {
-      var member3 = item3.memberElement;
-      expect(member3, isNull);
-    }
-    // D4 mixes-in M1 last, but it also overrides
-    {
-      var member4 = item4.memberElement!;
-      expect(member4.location!.offset, findOffset('test() {} // in D4'));
-    }
-  }
-
-  Future<void> test_member_ofMixin_getter() async {
-    addTestFile('''
-abstract class Base {
-  get test; // in Base
-}
-class Mixin {
-  get test => null; // in Mixin
-}
-class Derived1 extends Base with Mixin {}
-class Derived2 extends Base {
-  get test => null; // in Derived2
-}
-''');
-    var items = await _getTypeHierarchy('test; // in Base');
-    var itemBase = items.firstWhere((e) => e.classElement.name == 'Base');
-    var item1 = items.firstWhere((e) => e.classElement.name == 'Derived1');
-    var item2 = items.firstWhere((e) => e.classElement.name == 'Derived2');
-    var memberBase = itemBase.memberElement!;
-    var member1 = item1.memberElement!;
-    var member2 = item2.memberElement!;
-    expect(memberBase.location!.offset, findOffset('test; // in Base'));
-    expect(member1.location!.offset, findOffset('test => null; // in Mixin'));
-    expect(
-        member2.location!.offset, findOffset('test => null; // in Derived2'));
-  }
-
-  Future<void> test_member_ofMixin_method() async {
-    addTestFile('''
-abstract class Base {
-  void test(); // in Base
-}
-class Mixin {
-  void test() {} // in Mixin
-}
-class Derived1 extends Base with Mixin {}
-class Derived2 extends Base {
-  void test() {} // in Derived2
-}
-''');
-    var items = await _getTypeHierarchy('test(); // in Base');
-    var itemBase = items.firstWhere((e) => e.classElement.name == 'Base');
-    var item1 = items.firstWhere((e) => e.classElement.name == 'Derived1');
-    var item2 = items.firstWhere((e) => e.classElement.name == 'Derived2');
-    var memberBase = itemBase.memberElement!;
-    var member1 = item1.memberElement!;
-    var member2 = item2.memberElement!;
-    expect(memberBase.location!.offset, findOffset('test(); // in Base'));
-    expect(member1.location!.offset, findOffset('test() {} // in Mixin'));
-    expect(member2.location!.offset, findOffset('test() {} // in Derived2'));
-  }
-
-  Future<void> test_member_ofMixin_setter() async {
-    addTestFile('''
-abstract class Base {
-  set test(x); // in Base
-}
-class Mixin {
-  set test(x) {} // in Mixin
-}
-class Derived1 extends Base with Mixin {}
-class Derived2 extends Base {
-  set test(x) {} // in Derived2
-}
-''');
-    var items = await _getTypeHierarchy('test(x); // in Base');
-    var itemBase = items.firstWhere((e) => e.classElement.name == 'Base');
-    var item1 = items.firstWhere((e) => e.classElement.name == 'Derived1');
-    var item2 = items.firstWhere((e) => e.classElement.name == 'Derived2');
-    var memberBase = itemBase.memberElement!;
-    var member1 = item1.memberElement!;
-    var member2 = item2.memberElement!;
-    expect(memberBase.location!.offset, findOffset('test(x); // in Base'));
-    expect(member1.location!.offset, findOffset('test(x) {} // in Mixin'));
-    expect(member2.location!.offset, findOffset('test(x) {} // in Derived2'));
-  }
-
-  Future<void> test_member_ofSuperclassConstraint_getter() async {
-    addTestFile('''
-class A {
-  get test => 0; // in A
-}
-
-mixin M on A {
-  get test => 0; // in M
-}
-''');
-    var items = await _getTypeHierarchy('test => 0; // in A');
-
-    var inA = items.firstWhere((e) => e.classElement.name == 'A');
-    var inM = items.firstWhere((e) => e.classElement.name == 'M');
-
-    _assertMember(inA, 'test => 0; // in A');
-    _assertMember(inM, 'test => 0; // in M');
-  }
-
-  Future<void> test_member_ofSuperclassConstraint_method() async {
-    addTestFile('''
-class A {
-  void test() {} // in A
-}
-
-mixin M on A {
-  void test() {} // in M
-}
-''');
-    var items = await _getTypeHierarchy('test() {} // in A');
-
-    var inA = items.firstWhere((e) => e.classElement.name == 'A');
-    var inM = items.firstWhere((e) => e.classElement.name == 'M');
-
-    _assertMember(inA, 'test() {} // in A');
-    _assertMember(inM, 'test() {} // in M');
-  }
-
-  Future<void> test_member_ofSuperclassConstraint_setter() async {
-    addTestFile('''
-class A {
-  set test(x) {} // in A
-}
-
-mixin M on A {
-  set test(x) {} // in M
-}
-''');
-    var items = await _getTypeHierarchy('test(x) {} // in A');
-
-    var inA = items.firstWhere((e) => e.classElement.name == 'A');
-    var inM = items.firstWhere((e) => e.classElement.name == 'M');
-
-    _assertMember(inA, 'test(x) {} // in A');
-    _assertMember(inM, 'test(x) {} // in M');
-  }
-
-  Future<void> test_member_operator() async {
-    addTestFile('''
-class A {
-  operator ==(x) => null; // in A
-}
-class B extends A {
-  operator ==(x) => null; // in B
-}
-class C extends B {
-}
-class D extends C {
-  operator ==(x) => null; // in D
-}
-''');
-    var items = await _getTypeHierarchy('==(x) => null; // in B');
-    var itemB = items[0];
-    var itemA = items[itemB.superclass!];
-    var itemC = items[itemB.subclasses[0]];
-    var itemD = items[itemC.subclasses[0]];
-    expect(itemA.classElement.name, 'A');
-    expect(itemB.classElement.name, 'B');
-    expect(itemC.classElement.name, 'C');
-    expect(itemD.classElement.name, 'D');
-    expect(itemA.memberElement!.location!.offset,
-        findOffset('==(x) => null; // in A'));
-    expect(itemB.memberElement!.location!.offset,
-        findOffset('==(x) => null; // in B'));
-    expect(itemC.memberElement, isNull);
-    expect(itemD.memberElement!.location!.offset,
-        findOffset('==(x) => null; // in D'));
-  }
-
-  Future<void> test_member_setter() async {
-    addTestFile('''
-class A {
-  set test(x) {} // in A
-}
-class B extends A {
-  set test(x) {} // in B
-}
-class C extends B {
-}
-class D extends C {
-  set test(x) {} // in D
-}
-''');
-    var items = await _getTypeHierarchy('test(x) {} // in B');
-    var itemB = items[0];
-    var itemA = items[itemB.superclass!];
-    var itemC = items[itemB.subclasses[0]];
-    var itemD = items[itemC.subclasses[0]];
-    expect(itemA.classElement.name, 'A');
-    expect(itemB.classElement.name, 'B');
-    expect(itemC.classElement.name, 'C');
-    expect(itemD.classElement.name, 'D');
-    expect(itemA.memberElement!.location!.offset,
-        findOffset('test(x) {} // in A'));
-    expect(itemB.memberElement!.location!.offset,
-        findOffset('test(x) {} // in B'));
-    expect(itemC.memberElement, isNull);
-    expect(itemD.memberElement!.location!.offset,
-        findOffset('test(x) {} // in D'));
-  }
-
-  Future<void> test_superOnly() async {
+  Future<void> test_enum_implements() async {
     addTestFile('''
 class A {}
 class B {}
-class C extends A implements B {}
-class D extends C {}
+enum E implements A, B {
+  v;
+}
 ''');
-    var items = await _getTypeHierarchy('C extends', superOnly: true);
+    var items = await _getTypeHierarchy('E implements');
     expect(_toJson(items), [
       {
         'classElement': {
-          'kind': 'CLASS',
-          'name': 'C',
+          'kind': 'ENUM',
+          'name': 'E',
           'location': anything,
           'flags': 0
         },
         'superclass': 1,
-        'interfaces': [3],
+        'interfaces': [3, 4],
         'mixins': [],
         'subclasses': []
       },
       {
         'classElement': {
           'kind': 'CLASS',
-          'name': 'A',
+          'name': 'Enum',
           'location': anything,
-          'flags': 0
+          'flags': 1
         },
         'superclass': 2,
         'interfaces': [],
@@ -1166,6 +1260,18 @@
       {
         'classElement': {
           'kind': 'CLASS',
+          'name': 'A',
+          'location': anything,
+          'flags': 0
+        },
+        'superclass': 2,
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'CLASS',
           'name': 'B',
           'location': anything,
           'flags': 0
@@ -1178,15 +1284,179 @@
     ]);
   }
 
-  Future<void> test_superOnly_fileDoesNotExist() async {
-    var request = SearchGetTypeHierarchyParams(
-            convertPath('/does/not/exist.dart'), 0,
-            superOnly: true)
-        .toRequest(requestId);
-    var response = await serverChannel.sendRequest(request);
-    var items =
-        SearchGetTypeHierarchyResult.fromResponse(response).hierarchyItems;
-    expect(items, isNull);
+  Future<void> test_enum_member_getter() async {
+    addTestFile('''
+class A {
+  int get test => 0; // in A
+}
+class B extends A {
+  int get test => 0; // in B
+}
+class C extends B {
+}
+enum E implements C {
+  v;
+  int get test => 0; // in D
+}
+''');
+    var items = await _getTypeHierarchy('test => 0; // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemE = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemE.classElement.name, 'E');
+    expect(
+      itemA.memberElement!.location!.offset,
+      findOffset('test => 0; // in A'),
+    );
+    expect(
+      itemB.memberElement!.location!.offset,
+      findOffset('test => 0; // in B'),
+    );
+    expect(itemC.memberElement, isNull);
+    expect(
+      itemE.memberElement!.location!.offset,
+      findOffset('test => 0; // in D'),
+    );
+  }
+
+  Future<void> test_enum_member_method() async {
+    addTestFile('''
+class A {
+  void test() {} // in A
+}
+class B extends A {
+  void test() {} // in B
+}
+class C extends B {
+}
+enum E implements C {
+  v;
+  void test() {} // in E
+}
+''');
+    var items = await _getTypeHierarchy('test() {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemE = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemE.classElement.name, 'E');
+    expect(
+      itemA.memberElement!.location!.offset,
+      findOffset('test() {} // in A'),
+    );
+    expect(
+      itemB.memberElement!.location!.offset,
+      findOffset('test() {} // in B'),
+    );
+    expect(itemC.memberElement, isNull);
+    expect(
+      itemE.memberElement!.location!.offset,
+      findOffset('test() {} // in E'),
+    );
+  }
+
+  Future<void> test_enum_member_setter() async {
+    addTestFile('''
+class A {
+  set test(int x) {} // in A
+}
+class B extends A {
+  set test(int x) {} // in B
+}
+class C extends B {
+}
+enum E implements C {
+  v;
+  set test(int x) {} // in E
+}
+''');
+    var items = await _getTypeHierarchy('test(int x) {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass!];
+    var itemC = items[itemB.subclasses[0]];
+    var itemE = items[itemC.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemE.classElement.name, 'E');
+    expect(
+      itemA.memberElement!.location!.offset,
+      findOffset('test(int x) {} // in A'),
+    );
+    expect(
+      itemB.memberElement!.location!.offset,
+      findOffset('test(int x) {} // in B'),
+    );
+    expect(itemC.memberElement, isNull);
+    expect(
+      itemE.memberElement!.location!.offset,
+      findOffset('test(int x) {} // in E'),
+    );
+  }
+
+  Future<void> test_enum_with() async {
+    addTestFile('''
+mixin M {}
+enum E with M {
+  v;
+}
+''');
+    var items = await _getTypeHierarchy('E with');
+    expect(_toJson(items), [
+      {
+        'classElement': {
+          'kind': 'ENUM',
+          'name': 'E',
+          'location': anything,
+          'flags': 0
+        },
+        'superclass': 1,
+        'interfaces': [],
+        'mixins': [3],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'CLASS',
+          'name': 'Enum',
+          'location': anything,
+          'flags': 1
+        },
+        'superclass': 2,
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'CLASS',
+          'name': 'Object',
+          'location': anything,
+          'flags': 0
+        },
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      },
+      {
+        'classElement': {
+          'kind': 'MIXIN',
+          'name': 'M',
+          'location': anything,
+          'flags': 1
+        },
+        'interfaces': [],
+        'mixins': [],
+        'subclasses': []
+      }
+    ]);
   }
 
   void _assertMember(TypeHierarchyItem item, String search) {
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index 98584b89..865fbcb 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -11,15 +11,129 @@
 
 void main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(ExtractMethodEnumTest);
     defineReflectiveTests(ExtractMethodTest);
   });
 }
 
 @reflectiveTest
-class ExtractMethodTest extends RefactoringTest {
-  @override
-  late ExtractMethodRefactoringImpl refactoring;
+class ExtractMethodEnumTest extends _ExtractMethodTest {
+  Future<void> test_bad_conflict_method_alreadyDeclaresMethod() async {
+    await indexTestUnit('''
+enum E {
+  v;
+  void res() {}
+  void foo() {
+// start
+    print(0);
+// end
+  }
+}
+''');
+    _createRefactoringForStartEndComments();
+    return _assertConditionsError(
+        "Enum 'E' already declares method with name 'res'.");
+  }
 
+  Future<void> test_bad_conflict_method_shadowsSuperDeclaration() async {
+    await indexTestUnit('''
+mixin M {
+  void res() {}
+}
+
+enum E with M {
+  v;
+  void foo() {
+    res();
+// start
+    print(0);
+// end
+  }
+}
+''');
+    _createRefactoringForStartEndComments();
+    return _assertConditionsError("Created method will shadow method 'M.res'.");
+  }
+
+  Future<void> test_bad_conflict_topLevel_willHideInheritedMemberUsage() async {
+    await indexTestUnit('''
+mixin M {
+  void res() {}
+}
+
+enum E with M {
+  v;
+  void foo() {
+    res();
+  }
+}
+
+void f() {
+// start
+  print(0);
+// end
+}
+''');
+    _createRefactoringForStartEndComments();
+    return _assertConditionsError(
+        "Created function will shadow method 'M.res'.");
+  }
+
+  Future<void> test_singleExpression_method() async {
+    await indexTestUnit('''
+enum E {
+  v;
+  void foo() {
+    int a = 1 + 2;
+  }
+}
+''');
+    _createRefactoringForString('1 + 2');
+    // apply refactoring
+    return _assertSuccessfulRefactoring('''
+enum E {
+  v;
+  void foo() {
+    int a = res();
+  }
+
+  int res() => 1 + 2;
+}
+''');
+  }
+
+  Future<void> test_statements_method() async {
+    await indexTestUnit('''
+enum E {
+  v;
+  void foo() {
+// start
+    print(0);
+// end
+  }
+}
+''');
+    _createRefactoringForStartEndComments();
+    // apply refactoring
+    return _assertSuccessfulRefactoring('''
+enum E {
+  v;
+  void foo() {
+// start
+    res();
+// end
+  }
+
+  void res() {
+    print(0);
+  }
+}
+''');
+  }
+}
+
+@reflectiveTest
+class ExtractMethodTest extends _ExtractMethodTest {
   Future<void> test_bad_assignmentLeftHandSide() async {
     await indexTestUnit('''
 void f() {
@@ -2877,6 +2991,11 @@
 Completer<int> newCompleter() => null;
 ''');
   }
+}
+
+class _ExtractMethodTest extends RefactoringTest {
+  @override
+  late ExtractMethodRefactoringImpl refactoring;
 
   Future _assertConditionsError(String message) async {
     var status = await refactoring.checkAllConditions();
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 35d678c..e775831 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -12,17 +12,86 @@
 
 void main() {
   defineReflectiveSuite(() {
+    defineReflectiveTests(InlineMethodEnumTest);
     defineReflectiveTests(InlineMethodTest);
   });
 }
 
 @reflectiveTest
-class InlineMethodTest extends RefactoringTest {
-  @override
-  late InlineMethodRefactoringImpl refactoring;
-  bool? deleteSource;
-  bool? inlineAll;
+class InlineMethodEnumTest extends _InlineMethodTest {
+  Future<void> test_getter_classMember_instance() async {
+    await indexTestUnit(r'''
+enum E {
+  v;
+  final int f = 0;
+  int get result => f + 1;
+}
+void f(E e) {
+  print(e.result);
+}
+''');
+    _createRefactoring('result =>');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+enum E {
+  v;
+  final int f = 0;
+}
+void f(E e) {
+  print(e.f + 1);
+}
+''');
+  }
 
+  Future<void> test_getter_classMember_static() async {
+    await indexTestUnit(r'''
+enum E {
+  v;
+  static int get result => 1 + 2;
+}
+void f() {
+  print(E.result);
+}
+''');
+    _createRefactoring('result =>');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+enum E {
+  v;
+}
+void f() {
+  print(1 + 2);
+}
+''');
+  }
+
+  Future<void> test_method_singleStatement() async {
+    await indexTestUnit(r'''
+enum E {
+  v;
+  void test() {
+    print(0);
+  }
+  void foo() {
+    test();
+  }
+}
+''');
+    _createRefactoring('test() {');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+enum E {
+  v;
+  void foo() {
+    print(0);
+  }
+}
+''');
+  }
+}
+
+@reflectiveTest
+class InlineMethodTest extends _InlineMethodTest {
   Future<void> test_access_FunctionElement() async {
     await indexTestUnit(r'''
 test(a, b) {
@@ -1749,6 +1818,13 @@
 var a = 42;
 ''');
   }
+}
+
+class _InlineMethodTest extends RefactoringTest {
+  @override
+  late InlineMethodRefactoringImpl refactoring;
+  bool? deleteSource;
+  bool? inlineAll;
 
   Future _assertConditionsError(String message) async {
     var status = await refactoring.checkAllConditions();
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 6d0c321..524da05 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -1102,7 +1102,7 @@
     var status = await refactoring.checkFinalConditions();
     assertRefactoringStatus(status, RefactoringProblemSeverity.ERROR,
         expectedMessage:
-            "Class 'E' already declares method with name 'newName'.",
+            "Enum 'E' already declares method with name 'newName'.",
         expectedContextSearch: 'newName() {} // existing');
   }
 
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 61ddf10..1e78252 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -349,6 +349,7 @@
   CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE,
   CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY,
   CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT,
+  CompileTimeErrorCode.NON_FINAL_FIELD_IN_ENUM,
   CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
   CompileTimeErrorCode.NON_GENERATIVE_IMPLICIT_CONSTRUCTOR,
   CompileTimeErrorCode.NON_SYNC_FACTORY,
diff --git a/pkg/analyzer/lib/src/dart/element/greatest_lower_bound.dart b/pkg/analyzer/lib/src/dart/element/greatest_lower_bound.dart
index fdabfea..7e5b176 100644
--- a/pkg/analyzer/lib/src/dart/element/greatest_lower_bound.dart
+++ b/pkg/analyzer/lib/src/dart/element/greatest_lower_bound.dart
@@ -274,7 +274,7 @@
     // The bounds of type parameters must be equal.
     // Otherwise the result is `Never`.
     var freshTypeFormalTypes =
-        FunctionTypeImpl.relateTypeFormals(f, g, (t, s, _, __) => t == s);
+        FunctionTypeImpl.relateTypeFormals(f, g, (t, s) => t == s);
     if (freshTypeFormalTypes == null) {
       return NeverTypeImpl.instance;
     }
diff --git a/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart b/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart
index 94dd226..55f46ff 100644
--- a/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart
+++ b/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart
@@ -724,7 +724,7 @@
     // The bounds of type parameters must be equal.
     // Otherwise the result is `Function`.
     var freshTypeFormalTypes =
-        FunctionTypeImpl.relateTypeFormals(f, g, (t, s, _, __) => t == s);
+        FunctionTypeImpl.relateTypeFormals(f, g, (t, s) => t == s);
     if (freshTypeFormalTypes == null) {
       return _interfaceTypeFunctionNone;
     }
diff --git a/pkg/analyzer/lib/src/dart/element/subtype.dart b/pkg/analyzer/lib/src/dart/element/subtype.dart
index 4c8850c..50ec06d 100644
--- a/pkg/analyzer/lib/src/dart/element/subtype.dart
+++ b/pkg/analyzer/lib/src/dart/element/subtype.dart
@@ -351,8 +351,7 @@
     }
 
     // The bounds of type parameters must be equal.
-    var freshTypeFormalTypes =
-        FunctionTypeImpl.relateTypeFormals(f, g, (t, s, _, __) {
+    var freshTypeFormalTypes = FunctionTypeImpl.relateTypeFormals(f, g, (t, s) {
       return isSubtypeOf(t, s) && isSubtypeOf(s, t);
     });
     if (freshTypeFormalTypes == null) {
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 94ec607..92ac1d9 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -180,8 +180,8 @@
       // To test this, we instantiate both types with the same (unique) type
       // variables, and see if the result is equal.
       if (typeFormals.isNotEmpty) {
-        var freshVariables = FunctionTypeImpl.relateTypeFormals(
-            this, other, (t, s, _, __) => t == s);
+        var freshVariables =
+            FunctionTypeImpl.relateTypeFormals(this, other, (t, s) => t == s);
         if (freshVariables == null) {
           return false;
         }
@@ -295,9 +295,7 @@
   static List<TypeParameterType>? relateTypeFormals(
       FunctionType f1,
       FunctionType f2,
-      bool Function(DartType bound2, DartType bound1,
-              TypeParameterElement formal2, TypeParameterElement formal1)
-          relation) {
+      bool Function(DartType bound2, DartType bound1) relation) {
     List<TypeParameterElement> params1 = f1.typeFormals;
     List<TypeParameterElement> params2 = f2.typeFormals;
     return relateTypeFormals2(params1, params2, relation);
@@ -306,9 +304,7 @@
   static List<TypeParameterType>? relateTypeFormals2(
       List<TypeParameterElement> params1,
       List<TypeParameterElement> params2,
-      bool Function(DartType bound2, DartType bound1,
-              TypeParameterElement formal2, TypeParameterElement formal1)
-          relation) {
+      bool Function(DartType bound2, DartType bound1) relation) {
     int count = params1.length;
     if (params2.length != count) {
       return null;
@@ -340,7 +336,7 @@
           .substituteType(bound1);
       bound2 = Substitution.fromPairs(variables2, variablesFresh)
           .substituteType(bound2);
-      if (!relation(bound2, bound1, p2, p1)) {
+      if (!relation(bound2, bound1)) {
         return null;
       }
 
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index ad9d61e..10bbfb6 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -10702,6 +10702,16 @@
   );
 
   /**
+   * No parameters.
+   */
+  static const CompileTimeErrorCode NON_FINAL_FIELD_IN_ENUM =
+      CompileTimeErrorCode(
+    'NON_FINAL_FIELD_IN_ENUM',
+    "Enum can only declare final fields.",
+    correctionMessage: "Try making the field final.",
+  );
+
+  /**
    * Parameters:
    * 0: the non-generative constructor
    */
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 5d28080..c923c69 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -677,6 +677,7 @@
       _checkForNotInitializedNonNullableStaticField(node);
       _checkForWrongTypeParameterVarianceInField(node);
       _checkForLateFinalFieldWithConstConstructor(node);
+      _checkForNonFinalFieldInEnum(node);
       super.visitFieldDeclaration(node);
     } finally {
       _isInStaticVariableDeclaration = false;
@@ -3706,6 +3707,23 @@
         CompileTimeErrorCode.NON_CONST_MAP_AS_EXPRESSION_STATEMENT, literal);
   }
 
+  void _checkForNonFinalFieldInEnum(FieldDeclaration node) {
+    if (node.isStatic) return;
+
+    var variableList = node.fields;
+    if (variableList.isFinal) return;
+
+    var enclosingClass = _enclosingClass;
+    if (enclosingClass == null || !enclosingClass.isEnum) {
+      return;
+    }
+
+    errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.NON_FINAL_FIELD_IN_ENUM,
+      variableList.variables.first.name,
+    );
+  }
+
   /// Verify that the given method [declaration] of operator `[]=`, has `void`
   /// return type.
   ///
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 0269177..477c268 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -9073,6 +9073,10 @@
       13.2 Expression Statements: It is a compile-time error if a non-constant
       map literal that has no explicit type arguments appears in a place where a
       statement is expected.
+  NON_FINAL_FIELD_IN_ENUM:
+    problemMessage: Enum can only declare final fields.
+    correctionMessage: Try making the field final.
+    comment: No parameters.
   NON_GENERATIVE_CONSTRUCTOR:
     problemMessage: "The generative constructor '{0}' is expected, but a factory was found."
     correctionMessage: Try calling a different constructor of the superclass, or making the called constructor not be a factory constructor.
diff --git a/pkg/analyzer/test/src/diagnostics/non_final_field_in_enum_test.dart b/pkg/analyzer/test/src/diagnostics/non_final_field_in_enum_test.dart
new file mode 100644
index 0000000..e35f6d35
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/non_final_field_in_enum_test.dart
@@ -0,0 +1,37 @@
+// 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/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(NonFinalFieldInEnumTest);
+  });
+}
+
+@reflectiveTest
+class NonFinalFieldInEnumTest extends PubPackageResolutionTest {
+  test_instance_notFinal() async {
+    await assertErrorsInCode(r'''
+enum E {
+  v;
+  int foo = 0;
+}
+''', [
+      error(CompileTimeErrorCode.NON_FINAL_FIELD_IN_ENUM, 20, 3),
+    ]);
+  }
+
+  test_static_notFinal() async {
+    await assertNoErrorsInCode(r'''
+enum E {
+  v;
+  static int foo = 0;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/override_on_non_overriding_field_test.dart b/pkg/analyzer/test/src/diagnostics/override_on_non_overriding_field_test.dart
index 6e67586..5b5ba51 100644
--- a/pkg/analyzer/test/src/diagnostics/override_on_non_overriding_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/override_on_non_overriding_field_test.dart
@@ -71,10 +71,10 @@
 enum E {
   v;
   @override
-  int? foo;
+  final int foo = 0;
 }
 ''', [
-      error(HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD, 33, 3),
+      error(HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD, 38, 3),
     ]);
   }
 
@@ -83,19 +83,15 @@
 class A {
   int get a => 0;
   void set b(int _) {}
-  int c = 0;
 }
 
 enum E implements A {
   v;
   @override
-  final int a = 1;
+  int get a => 0;
 
   @override
-  int b = 0;
-
-  @override
-  int c = 0;
+  void set b(int _) {}
 }
 ''');
   }
@@ -110,10 +106,10 @@
 enum E with M {
   v;
   @override
-  final int a = 1;
+  int get a => 0;
 
   @override
-  int b = 0;
+  void set b(int _) {}
 }
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 689de3e..8bfc4e8 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -529,6 +529,7 @@
 import 'non_constant_map_value_test.dart' as non_constant_map_value;
 import 'non_constant_set_element_test.dart' as non_constant_set_element;
 import 'non_constant_type_argument_test.dart' as non_constant_type_argument;
+import 'non_final_field_in_enum_test.dart' as non_final_field_in_enum;
 import 'non_generative_constructor_test.dart' as non_generative_constructor;
 import 'non_generative_implicit_constructor_test.dart'
     as non_generative_implicit_constructor;
@@ -1139,6 +1140,7 @@
     non_constant_map_value_from_deferred_library.main();
     non_constant_set_element.main();
     non_constant_type_argument.main();
+    non_final_field_in_enum.main();
     non_generative_constructor.main();
     non_generative_implicit_constructor.main();
     non_native_function_type_argument_to_pointer.main();
diff --git a/pkg/analyzer/test/src/diagnostics/values_declaration_in_enum_test.dart b/pkg/analyzer/test/src/diagnostics/values_declaration_in_enum_test.dart
index b66fed4..3deb2aa 100644
--- a/pkg/analyzer/test/src/diagnostics/values_declaration_in_enum_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/values_declaration_in_enum_test.dart
@@ -29,10 +29,10 @@
     await assertErrorsInCode(r'''
 enum E {
   v;
-  int values = 0;
+  final int values = 0;
 }
 ''', [
-      error(CompileTimeErrorCode.VALUES_DECLARATION_IN_ENUM, 20, 6),
+      error(CompileTimeErrorCode.VALUES_DECLARATION_IN_ENUM, 26, 6),
     ]);
   }
 
diff --git a/pkg/analyzer_plugin/lib/src/utilities/navigation/navigation.dart b/pkg/analyzer_plugin/lib/src/utilities/navigation/navigation.dart
index 23709a3..da91052 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/navigation/navigation.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/navigation/navigation.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/element/element.dart' as analyzer;
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart' show SourceRange;
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -33,10 +34,8 @@
 
 /// A concrete implementation of [NavigationCollector].
 class NavigationCollectorImpl implements NavigationCollector {
-  /// Whether the collector is collecting target code locations. Computers can
-  /// skip computing these if this is false.
-  @override
-  final bool collectCodeLocations;
+  /// Each target which was created from an element is added here.
+  final List<TargetToUpdate> targetsToUpdate = [];
 
   /// A list of navigation regions.
   final List<NavigationRegion> regions = <NavigationRegion>[];
@@ -54,25 +53,24 @@
 
   final Map<String, int> fileMap = <String, int>{};
 
-  NavigationCollectorImpl({this.collectCodeLocations = false});
+  NavigationCollectorImpl();
 
   @override
   void addRange(
       SourceRange range, ElementKind targetKind, Location targetLocation,
-      {Location? targetCodeLocation}) {
+      {analyzer.Element? targetElement}) {
     addRegion(range.offset, range.length, targetKind, targetLocation,
-        targetCodeLocation: targetCodeLocation);
+        targetElement: targetElement);
   }
 
   @override
   void addRegion(
       int offset, int length, ElementKind targetKind, Location targetLocation,
-      {Location? targetCodeLocation}) {
+      {analyzer.Element? targetElement}) {
     var range = SourceRange(offset, length);
     // add new target
     var targets = regionMap.putIfAbsent(range, () => <int>[]);
-    var targetIndex =
-        _addTarget(targetKind, targetLocation, targetCodeLocation);
+    var targetIndex = _addTarget(targetKind, targetLocation, targetElement);
     targets.add(targetIndex);
   }
 
@@ -96,7 +94,8 @@
     return index;
   }
 
-  int _addTarget(ElementKind kind, Location location, Location? codeLocation) {
+  int _addTarget(
+      ElementKind kind, Location location, analyzer.Element? element) {
     var pair = Pair<ElementKind, Location>(kind, location);
     var index = targetMap[pair];
     if (index == null) {
@@ -104,12 +103,23 @@
       var fileIndex = _addFile(file);
       index = targets.length;
       var target = NavigationTarget(kind, fileIndex, location.offset,
-          location.length, location.startLine, location.startColumn,
-          codeOffset: collectCodeLocations ? codeLocation?.offset : null,
-          codeLength: collectCodeLocations ? codeLocation?.length : null);
+          location.length, location.startLine, location.startColumn);
       targets.add(target);
       targetMap[pair] = index;
+      if (element != null) {
+        targetsToUpdate.add(TargetToUpdate(element, target));
+      }
     }
     return index;
   }
 }
+
+/// The element and the navigation target created for it.
+///
+/// If code location feature is enabled, we update [target] using [element].
+class TargetToUpdate {
+  final analyzer.Element element;
+  final NavigationTarget target;
+
+  TargetToUpdate(this.element, this.target);
+}
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation.dart
index 9e02f7a4f..1267087 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/element/element.dart' as analyzer;
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/protocol/protocol.dart';
@@ -26,21 +27,22 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class NavigationCollector {
-  /// Whether the collector is collecting target code locations. Computers can
-  /// skip computing these if this is false.
-  bool get collectCodeLocations;
-
   /// Record a new navigation region corresponding to the given [range] that
   /// should navigate to the given [targetNameLocation].
   void addRange(
       SourceRange range, ElementKind targetKind, Location targetLocation,
-      {Location targetCodeLocation});
+      {analyzer.Element? targetElement});
 
   /// Record a new navigation region with the given [offset] and [length] that
   /// should navigate to the given [targetNameLocation].
+  ///
+  /// In the most cases the [targetNameLocation] is already based on the
+  /// [targetElement], but in a few cases this method is invoked without an
+  /// element. The element is provided to associate it with the target, and
+  /// later update the target.
   void addRegion(int offset, int length, ElementKind targetKind,
       Location targetNameLocation,
-      {Location? targetCodeLocation});
+      {analyzer.Element? targetElement});
 }
 
 /// An object used to produce navigation regions.
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index 2bd48bc..803d099 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -2,7 +2,6 @@
 // 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/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
@@ -92,12 +91,7 @@
       return;
     }
 
-    var codeLocation = collector.collectCodeLocations
-        ? _getCodeLocation(element, location, converter)
-        : null;
-
-    collector.addRegion(offset, length, kind, location,
-        targetCodeLocation: codeLocation);
+    collector.addRegion(offset, length, kind, location, targetElement: element);
   }
 
   void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element? element) {
@@ -121,51 +115,6 @@
     _addRegion(offset, length, element);
   }
 
-  /// Get the location of the code (excluding leading doc comments) for this element.
-  protocol.Location? _getCodeLocation(Element element,
-      protocol.Location location, AnalyzerConverter converter) {
-    var codeElement = element;
-    // For synthetic getters created for fields, we need to access the associated
-    // variable to get the codeOffset/codeLength.
-    if (codeElement.isSynthetic && codeElement is PropertyAccessorElementImpl) {
-      final variable = codeElement.variable;
-      if (variable is ElementImpl) {
-        codeElement = variable as ElementImpl;
-      }
-    }
-
-    // Read the main codeOffset from the element. This may include doc comments
-    // but will give the correct end position.
-    int? codeOffset, codeLength;
-    if (codeElement is ElementImpl) {
-      codeOffset = codeElement.codeOffset;
-      codeLength = codeElement.codeLength;
-    }
-
-    if (codeOffset == null || codeLength == null) {
-      return null;
-    }
-
-    // Read the declaration so we can get the offset after the doc comments.
-    // TODO(dantup): Skip this for parts (getParsedLibrary will throw), but find
-    // a better solution.
-    final declaration = _parsedDeclaration(codeElement);
-    var node = declaration?.node;
-    if (node is VariableDeclaration) {
-      node = node.parent;
-    }
-    if (node is AnnotatedNode) {
-      var offsetAfterDocs = node.firstTokenAfterCommentAndMetadata.offset;
-
-      // Reduce the length by the difference between the end of docs and the start.
-      codeLength -= (offsetAfterDocs - codeOffset);
-      codeOffset = offsetAfterDocs;
-    }
-
-    return converter.locationFromElement(element,
-        offset: codeOffset, length: codeLength);
-  }
-
   /// Checks if offset/length intersect with the range the user requested
   /// navigation regions for.
   ///
@@ -185,25 +134,6 @@
     }
     return true;
   }
-
-  static ElementDeclarationResult? _parsedDeclaration(Element element) {
-    var session = element.session;
-    if (session == null) {
-      return null;
-    }
-
-    var libraryPath = element.library?.source.fullName;
-    if (libraryPath == null) {
-      return null;
-    }
-
-    var parsedLibrary = session.getParsedLibrary(libraryPath);
-    if (parsedLibrary is! ParsedLibraryResult) {
-      return null;
-    }
-
-    return parsedLibrary.getElementDeclaration(element);
-  }
 }
 
 class _DartNavigationComputerVisitor extends RecursiveAstVisitor<void> {
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index cd2c23c..db4f022 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -827,7 +827,8 @@
       // Expand architectures.
       var architectures = data["arch"] as String;
       if (architectures == "all") {
-        architectures = "ia32,x64,x64c,simarm,simarm64,simarm64c";
+        architectures =
+            "ia32,x64,x64c,simarm,simarm64,simarm64c,simriscv32,simriscv64";
       }
 
       for (var architectureName in architectures.split(",")) {
diff --git a/runtime/vm/base_isolate.h b/runtime/vm/base_isolate.h
index a8c09ee..0bfd061 100644
--- a/runtime/vm/base_isolate.h
+++ b/runtime/vm/base_isolate.h
@@ -21,12 +21,6 @@
 class BaseIsolate {
  public:
 #if defined(DEBUG)
-  void AssertCurrentThreadIsMutator() const;
-#else
-  void AssertCurrentThreadIsMutator() const {}
-#endif  // DEBUG
-
-#if defined(DEBUG)
   static void AssertCurrent(BaseIsolate* isolate);
 #endif
 
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 73f681f..bb5eda5 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -334,7 +334,13 @@
 #define START_NO_CALLBACK_SCOPE(thread) thread->IncrementNoCallbackScopeDepth()
 
 // End a no Dart API call backs Scope.
-#define END_NO_CALLBACK_SCOPE(thread) thread->DecrementNoCallbackScopeDepth()
+#define END_NO_CALLBACK_SCOPE(thread)                                          \
+  do {                                                                         \
+    thread->DecrementNoCallbackScopeDepth();                                   \
+    if (thread->no_callback_scope_depth() == 0) {                              \
+      thread->heap()->CheckExternalGC(thread);                                 \
+    }                                                                          \
+  } while (false)
 
 #define CHECK_CALLBACK_STATE(thread)                                           \
   if (thread->no_callback_scope_depth() != 0) {                                \
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 5691670..73c4f52 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -2808,6 +2808,34 @@
   TestByteDataDirectAccess();
 }
 
+static void NopCallback(void* isolate_callback_data, void* peer) {}
+
+TEST_CASE(DartAPI_ExternalAllocationDuringNoCallbackScope) {
+  Dart_Handle bytes = Dart_NewTypedData(Dart_TypedData_kUint8, 100);
+  EXPECT_VALID(bytes);
+
+  intptr_t gc_count_before = Thread::Current()->heap()->Collections(Heap::kNew);
+
+  Dart_TypedData_Type type;
+  void* data;
+  intptr_t len;
+  Dart_Handle result = Dart_TypedDataAcquireData(bytes, &type, &data, &len);
+  EXPECT_VALID(result);
+
+  Dart_WeakPersistentHandle weak =
+      Dart_NewWeakPersistentHandle(bytes, NULL, 100 * MB, NopCallback);
+  EXPECT_VALID(reinterpret_cast<Dart_Handle>(weak));
+
+  EXPECT_EQ(gc_count_before,
+            Thread::Current()->heap()->Collections(Heap::kNew));
+
+  result = Dart_TypedDataReleaseData(bytes);
+  EXPECT_VALID(result);
+
+  EXPECT_LT(gc_count_before,
+            Thread::Current()->heap()->Collections(Heap::kNew));
+}
+
 static void ExternalTypedDataAccessTests(Dart_Handle obj,
                                          Dart_TypedData_Type expected_type,
                                          uint8_t data[],
@@ -2917,8 +2945,6 @@
   EXPECT(value);
 }
 
-static void NopCallback(void* isolate_callback_data, void* peer) {}
-
 static void UnreachedCallback(void* isolate_callback_data, void* peer) {
   UNREACHABLE();
 }
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 286206f..feed760 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -149,30 +149,18 @@
 }
 
 void Heap::AllocatedExternal(intptr_t size, Space space) {
-  ASSERT(Thread::Current()->no_safepoint_scope_depth() == 0);
   if (space == kNew) {
-    Isolate::Current()->AssertCurrentThreadIsMutator();
     new_space_.AllocatedExternal(size);
-    if (new_space_.ExternalInWords() <= (4 * new_space_.CapacityInWords())) {
-      return;
-    }
-    // Attempt to free some external allocation by a scavenge. (If the total
-    // remains above the limit, next external alloc will trigger another.)
-    CollectGarbage(GCType::kScavenge, GCReason::kExternal);
-    // Promotion may have pushed old space over its limit. Fall through for old
-    // space GC check.
   } else {
     ASSERT(space == kOld);
     old_space_.AllocatedExternal(size);
   }
 
-  if (old_space_.ReachedHardThreshold()) {
-    if (last_gc_was_old_space_) {
-      CollectNewSpaceGarbage(Thread::Current(), GCReason::kFull);
-    }
-    CollectGarbage(GCType::kMarkSweep, GCReason::kExternal);
+  Thread* thread = Thread::Current();
+  if (thread->no_callback_scope_depth() == 0) {
+    CheckExternalGC(thread);
   } else {
-    CheckStartConcurrentMarking(Thread::Current(), GCReason::kExternal);
+    // Check delayed until Dart_TypedDataRelease.
   }
 }
 
@@ -190,6 +178,27 @@
   old_space_.AllocatedExternal(size);
 }
 
+void Heap::CheckExternalGC(Thread* thread) {
+  ASSERT(thread->no_safepoint_scope_depth() == 0);
+  ASSERT(thread->no_callback_scope_depth() == 0);
+  if (new_space_.ExternalInWords() >= (4 * new_space_.CapacityInWords())) {
+    // Attempt to free some external allocation by a scavenge. (If the total
+    // remains above the limit, next external alloc will trigger another.)
+    CollectGarbage(GCType::kScavenge, GCReason::kExternal);
+    // Promotion may have pushed old space over its limit. Fall through for old
+    // space GC check.
+  }
+
+  if (old_space_.ReachedHardThreshold()) {
+    if (last_gc_was_old_space_) {
+      CollectNewSpaceGarbage(thread, GCReason::kFull);
+    }
+    CollectGarbage(GCType::kMarkSweep, GCReason::kExternal);
+  } else {
+    CheckStartConcurrentMarking(thread, GCReason::kExternal);
+  }
+}
+
 bool Heap::Contains(uword addr) const {
   return new_space_.Contains(addr) || old_space_.Contains(addr);
 }
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 121e075..59eae20 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -83,6 +83,7 @@
   void FreedExternal(intptr_t size, Space space);
   // Move external size from new to old space. Does not by itself trigger GC.
   void PromotedExternal(intptr_t size);
+  void CheckExternalGC(Thread* thread);
 
   // Heap contains the specified address.
   bool Contains(uword addr) const;
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 46145f4..c6e70aa 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1656,11 +1656,6 @@
 void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
   ASSERT(isolate == Isolate::Current());
 }
-
-void BaseIsolate::AssertCurrentThreadIsMutator() const {
-  ASSERT(Isolate::Current() == this);
-  ASSERT(Thread::Current()->IsMutatorThread());
-}
 #endif  // defined(DEBUG)
 
 #if defined(DEBUG)
diff --git a/tools/VERSION b/tools/VERSION
index 0a5488c..6f1c666 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 165
+PRERELEASE 166
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/gn.py b/tools/gn.py
index b895393..2b43717 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -345,7 +345,7 @@
 
 def ProcessOptions(args):
     if args.arch == 'all':
-        args.arch = 'ia32,x64,simarm,simarm64,x64c,simarm64c'
+        args.arch = 'ia32,x64,simarm,simarm64,x64c,simarm64c,simriscv32,simriscv64'
     if args.mode == 'all':
         args.mode = 'debug,release,product'
     if args.os == 'all':