[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;
}
}