[element model] migrate `specify_nonobvious_property_types`

Bug: https://github.com/dart-lang/linter/issues/5099
Change-Id: I5bb2753f96527f80a000c08f923ac78c1c03e89d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391680
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Auto-Submit: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index b00d61f..c0f55d5 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -569,7 +569,13 @@
   @override
   List<GetterElement> get getters => accessors
       .where((accessor) => accessor.isGetter)
-      .map((fragment) => (fragment as GetterFragment).element as GetterElement)
+      .map((fragment) => switch (fragment) {
+            GetterFragment(:var element) => element as GetterElement,
+            GetterMember() => fragment,
+            _ => throw StateError(
+                'unexpected fragment type: ${fragment.runtimeType}',
+              )
+          })
       .toList();
 
   @override
@@ -718,7 +724,13 @@
   @override
   List<SetterElement> get setters => accessors
       .where((accessor) => accessor.isSetter)
-      .map((fragment) => (fragment as SetterFragment).element as SetterElement)
+      .map((fragment) => switch (fragment) {
+            SetterFragment(:var element) => element as SetterElement,
+            SetterMember() => fragment,
+            _ => throw StateError(
+                'unexpected fragment type: ${fragment.runtimeType}',
+              )
+          })
       .toList();
 
   @override
diff --git a/pkg/linter/analyzer_use_new_elements.txt b/pkg/linter/analyzer_use_new_elements.txt
index 52c7419..33302ee 100644
--- a/pkg/linter/analyzer_use_new_elements.txt
+++ b/pkg/linter/analyzer_use_new_elements.txt
@@ -158,6 +158,7 @@
 lib/src/rules/sort_constructors_first.dart
 lib/src/rules/sort_unnamed_constructors_first.dart
 lib/src/rules/specify_nonobvious_local_variable_types.dart
+lib/src/rules/specify_nonobvious_property_types.dart
 lib/src/rules/super_goes_last.dart
 lib/src/rules/test_types_in_equals.dart
 lib/src/rules/throw_in_finally.dart
@@ -196,6 +197,7 @@
 lib/src/rules/use_is_even_rather_than_modulo.dart
 lib/src/rules/use_named_constants.dart
 lib/src/rules/use_raw_strings.dart
+lib/src/rules/use_rethrow_when_possible.dart
 lib/src/rules/use_string_in_part_of_directives.dart
 lib/src/rules/use_test_throws_matchers.dart
 lib/src/rules/use_to_and_as_if_applicable.dart
diff --git a/pkg/linter/lib/src/extensions.dart b/pkg/linter/lib/src/extensions.dart
index 469fd03..5cabce7 100644
--- a/pkg/linter/lib/src/extensions.dart
+++ b/pkg/linter/lib/src/extensions.dart
@@ -28,6 +28,16 @@
   Map<DartObject, Set<FieldElement2>> get enumConstants => {..._enumConstants};
 }
 
+extension on SetterElement {
+  /// Return name in a format suitable for string comparison.
+  String? get canonicalName {
+    var name = name3;
+    if (name == null) return null;
+    // TODO(pq): remove when `name3` consistently does not include a trailing `=`.
+    return name.endsWith('=') ? name.substring(0, name.length - 1) : name;
+  }
+}
+
 extension AstNodeExtension on AstNode {
   Iterable<AstNode> get childNodes => childEntities.whereType<AstNode>();
 
@@ -609,6 +619,12 @@
     searchSupertypes(this, {}, interfaceTypes);
     return interfaceTypes;
   }
+
+  GetterElement? getGetter2(String name) =>
+      getters.firstWhereOrNull((s) => s.name3 == name);
+
+  SetterElement? getSetter2(String name) =>
+      setters.firstWhereOrNull((s) => s.canonicalName == name);
 }
 
 extension LibraryElementExtension2 on LibraryElement2? {
diff --git a/pkg/linter/lib/src/rules/specify_nonobvious_property_types.dart b/pkg/linter/lib/src/rules/specify_nonobvious_property_types.dart
index 432619b..9302975 100644
--- a/pkg/linter/lib/src/rules/specify_nonobvious_property_types.dart
+++ b/pkg/linter/lib/src/rules/specify_nonobvious_property_types.dart
@@ -4,9 +4,10 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/element2.dart';
 
 import '../analyzer.dart';
+import '../extensions.dart';
 import '../util/obvious_types.dart';
 
 const _desc = r'Specify non-obvious type annotations for local variables.';
@@ -63,20 +64,23 @@
         bool ignoreThisVariable = false;
         AstNode? owningDeclaration = node;
         while (owningDeclaration != null) {
-          InterfaceElement? owningElement = switch (owningDeclaration) {
-            ClassDeclaration(:var declaredElement) => declaredElement,
-            MixinDeclaration(:var declaredElement) => declaredElement,
-            EnumDeclaration(:var declaredElement) => declaredElement,
-            ExtensionTypeDeclaration(:var declaredElement) => declaredElement,
+          InterfaceElement2? owningElement = switch (owningDeclaration) {
+            ClassDeclaration(:var declaredFragment?) =>
+              declaredFragment.element,
+            MixinDeclaration(:var declaredFragment?) =>
+              declaredFragment.element,
+            EnumDeclaration(:var declaredFragment?) => declaredFragment.element,
+            ExtensionTypeDeclaration(:var declaredFragment?) =>
+              declaredFragment.element,
             _ => null,
           };
           if (owningElement != null) {
             var variableName = child.name.lexeme;
             for (var superInterface in owningElement.allSupertypes) {
-              if (superInterface.getGetter(variableName) != null) {
+              if (superInterface.getGetter2(variableName) != null) {
                 ignoreThisVariable = true;
               }
-              if (superInterface.getSetter(variableName) != null) {
+              if (superInterface.getSetter2(variableName) != null) {
                 ignoreThisVariable = true;
               }
             }