Skip to content
This repository was archived by the owner on Nov 20, 2024. It is now read-only.

Commit b6714c5

Browse files
authored
analyzer 5.0.0 prep (#3643)
1 parent 201fd3b commit b6714c5

7 files changed

+129
-111
lines changed

lib/src/extensions.dart

+103-103
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,6 @@ import 'package:collection/collection.dart';
1111

1212
import 'util/dart_type_utilities.dart';
1313

14-
extension ElementExtension on Element {
15-
Element get canonicalElement {
16-
var self = this;
17-
if (self is PropertyAccessorElement) {
18-
var variable = self.variable;
19-
if (variable is FieldMember) {
20-
// A field element defined in a parameterized type where the values of
21-
// the type parameters are known.
22-
//
23-
// This concept should be invisible when comparing FieldElements, but a
24-
// bug in the analyzer causes FieldElements to not evaluate as
25-
// equivalent to equivalent FieldMembers. See
26-
// https://github.com/dart-lang/sdk/issues/35343.
27-
return variable.declaration;
28-
} else {
29-
return variable;
30-
}
31-
} else {
32-
return self;
33-
}
34-
}
35-
}
36-
3714
class EnumLikeClassDescription {
3815
final Map<DartObject, Set<FieldElement>> _enumConstants;
3916
EnumLikeClassDescription(this._enumConstants);
@@ -42,6 +19,53 @@ class EnumLikeClassDescription {
4219
Map<DartObject, Set<FieldElement>> get enumConstants => {..._enumConstants};
4320
}
4421

22+
extension AstNodeExtension on AstNode {
23+
Iterable<AstNode> get childNodes => childEntities.whereType<AstNode>();
24+
25+
/// Builds the list resulting from traversing the node in DFS and does not
26+
/// include the node itself.
27+
///
28+
/// It excludes the nodes for which the [excludeCriteria] returns true. If
29+
/// [excludeCriteria] is not provided, all nodes are included.
30+
Iterable<AstNode> traverseNodesInDFS({AstNodePredicate? excludeCriteria}) {
31+
var nodes = <AstNode>{};
32+
var nodesToVisit = List.of(childNodes);
33+
if (excludeCriteria == null) {
34+
while (nodesToVisit.isNotEmpty) {
35+
var node = nodesToVisit.removeAt(0);
36+
nodes.add(node);
37+
nodesToVisit.insertAll(0, node.childNodes);
38+
}
39+
} else {
40+
while (nodesToVisit.isNotEmpty) {
41+
var node = nodesToVisit.removeAt(0);
42+
if (excludeCriteria(node)) continue;
43+
nodes.add(node);
44+
nodesToVisit.insertAll(0, node.childNodes);
45+
}
46+
}
47+
48+
return nodes;
49+
}
50+
}
51+
52+
extension BlockExtension on Block {
53+
/// Returns the last statement of this block, or `null` if this is empty.
54+
///
55+
/// If the last immediate statement of this block is a [Block], recurses into
56+
/// it to find the last statement.
57+
Statement? get lastStatement {
58+
if (statements.isEmpty) {
59+
return null;
60+
}
61+
var lastStatement = statements.last;
62+
if (lastStatement is Block) {
63+
return lastStatement.lastStatement;
64+
}
65+
return lastStatement;
66+
}
67+
}
68+
4569
extension ClassElementExtension on ClassElement {
4670
/// Returns an [EnumLikeClassDescription] for this if the latter is a valid
4771
/// "enum-like" class.
@@ -120,12 +144,17 @@ extension ClassElementExtension on ClassElement {
120144
return false;
121145
}
122146

147+
bool get isEnumLikeClass => asEnumLikeClass != null;
148+
123149
/// Returns whether this class is exactly [otherName] declared in
124150
/// [otherLibrary].
125151
bool isClass(String otherName, String otherLibrary) =>
126152
name == otherName && library.name == otherLibrary;
153+
}
127154

128-
bool get isEnumLikeClass => asEnumLikeClass != null;
155+
extension ClassMemberListExtension on List<ClassMember> {
156+
MethodDeclaration? getMethod(String name) => whereType<MethodDeclaration>()
157+
.firstWhereOrNull((node) => node.name2.lexeme == name);
129158
}
130159

131160
extension ConstructorElementExtension on ConstructorElement {
@@ -141,80 +170,6 @@ extension ConstructorElementExtension on ConstructorElement {
141170
name == constructorName;
142171
}
143172

144-
extension InterfaceElementExtension on InterfaceElement {
145-
/// Returns whether this element is exactly [otherName] declared in
146-
/// [otherLibrary].
147-
bool isClass(String otherName, String otherLibrary) =>
148-
name == otherName && library.name == otherLibrary;
149-
}
150-
151-
extension NullableAstNodeExtension on AstNode? {
152-
Element? get canonicalElement {
153-
var self = this;
154-
if (self is Expression) {
155-
var node = self.unParenthesized;
156-
if (node is Identifier) {
157-
return node.staticElement?.canonicalElement;
158-
} else if (node is PropertyAccess) {
159-
return node.propertyName.staticElement?.canonicalElement;
160-
}
161-
}
162-
return null;
163-
}
164-
}
165-
166-
extension AstNodeExtension on AstNode {
167-
/// Builds the list resulting from traversing the node in DFS and does not
168-
/// include the node itself.
169-
///
170-
/// It excludes the nodes for which the [excludeCriteria] returns true. If
171-
/// [excludeCriteria] is not provided, all nodes are included.
172-
Iterable<AstNode> traverseNodesInDFS({AstNodePredicate? excludeCriteria}) {
173-
var nodes = <AstNode>{};
174-
var nodesToVisit = List.of(childNodes);
175-
if (excludeCriteria == null) {
176-
while (nodesToVisit.isNotEmpty) {
177-
var node = nodesToVisit.removeAt(0);
178-
nodes.add(node);
179-
nodesToVisit.insertAll(0, node.childNodes);
180-
}
181-
} else {
182-
while (nodesToVisit.isNotEmpty) {
183-
var node = nodesToVisit.removeAt(0);
184-
if (excludeCriteria(node)) continue;
185-
nodes.add(node);
186-
nodesToVisit.insertAll(0, node.childNodes);
187-
}
188-
}
189-
190-
return nodes;
191-
}
192-
193-
Iterable<AstNode> get childNodes => childEntities.whereType<AstNode>();
194-
}
195-
196-
extension BlockExtension on Block {
197-
/// Returns the last statement of this block, or `null` if this is empty.
198-
///
199-
/// If the last immediate statement of this block is a [Block], recurses into
200-
/// it to find the last statement.
201-
Statement? get lastStatement {
202-
if (statements.isEmpty) {
203-
return null;
204-
}
205-
var lastStatement = statements.last;
206-
if (lastStatement is Block) {
207-
return lastStatement.lastStatement;
208-
}
209-
return lastStatement;
210-
}
211-
}
212-
213-
extension ClassMemberListExtension on List<ClassMember> {
214-
MethodDeclaration? getMethod(String name) => whereType<MethodDeclaration>()
215-
.firstWhereOrNull((node) => node.name2.lexeme == name);
216-
}
217-
218173
extension DartTypeExtension on DartType? {
219174
bool extendsClass(String? className, String library) {
220175
var self = this;
@@ -269,10 +224,40 @@ extension DartTypeExtension on DartType? {
269224
_extendsClass(type.superclass, seenElements, className, library));
270225
}
271226

227+
extension ElementExtension on Element {
228+
Element get canonicalElement {
229+
var self = this;
230+
if (self is PropertyAccessorElement) {
231+
var variable = self.variable;
232+
if (variable is FieldMember) {
233+
// A field element defined in a parameterized type where the values of
234+
// the type parameters are known.
235+
//
236+
// This concept should be invisible when comparing FieldElements, but a
237+
// bug in the analyzer causes FieldElements to not evaluate as
238+
// equivalent to equivalent FieldMembers. See
239+
// https://github.com/dart-lang/sdk/issues/35343.
240+
return variable.declaration;
241+
} else {
242+
return variable;
243+
}
244+
} else {
245+
return self;
246+
}
247+
}
248+
}
249+
272250
extension ExpressionExtension on Expression? {
273251
bool get isNullLiteral => this?.unParenthesized is NullLiteral;
274252
}
275253

254+
extension InterfaceElementExtension on InterfaceElement {
255+
/// Returns whether this element is exactly [otherName] declared in
256+
/// [otherLibrary].
257+
bool isClass(String otherName, String otherLibrary) =>
258+
name == otherName && library.name == otherLibrary;
259+
}
260+
276261
extension InterfaceTypeExtension on InterfaceType {
277262
/// Returns the collection of all interfaces that this type implements,
278263
/// including itself.
@@ -336,7 +321,7 @@ extension MethodDeclarationExtension on MethodDeclaration {
336321
return null;
337322
}
338323
var parent = declaredElement.enclosingElement3;
339-
if (parent is ClassElement) {
324+
if (parent is InterfaceElement) {
340325
return parent.lookUpGetter(name2.lexeme, declaredElement.library);
341326
}
342327
if (parent is ExtensionElement) {
@@ -351,7 +336,7 @@ extension MethodDeclarationExtension on MethodDeclaration {
351336
return null;
352337
}
353338
var parent = declaredElement.enclosingElement3;
354-
if (parent is ClassElement) {
339+
if (parent is InterfaceElement) {
355340
return parent.lookUpInheritedConcreteGetter(
356341
name2.lexeme, declaredElement.library);
357342
}
@@ -363,7 +348,7 @@ extension MethodDeclarationExtension on MethodDeclaration {
363348
var declaredElement = declaredElement2;
364349
if (declaredElement != null) {
365350
var parent = declaredElement.enclosingElement3;
366-
if (parent is ClassElement) {
351+
if (parent is InterfaceElement) {
367352
return parent.lookUpInheritedConcreteMethod(
368353
name2.lexeme, declaredElement.library);
369354
}
@@ -376,7 +361,7 @@ extension MethodDeclarationExtension on MethodDeclaration {
376361
var declaredElement = declaredElement2;
377362
if (declaredElement != null) {
378363
var parent = declaredElement.enclosingElement3;
379-
if (parent is ClassElement) {
364+
if (parent is InterfaceElement) {
380365
return parent.lookUpInheritedConcreteSetter(
381366
name2.lexeme, declaredElement.library);
382367
}
@@ -389,11 +374,26 @@ extension MethodDeclarationExtension on MethodDeclaration {
389374
var declaredElement = declaredElement2;
390375
if (declaredElement != null) {
391376
var parent = declaredElement.enclosingElement3;
392-
if (parent is ClassElement) {
377+
if (parent is InterfaceElement) {
393378
return parent.lookUpInheritedMethod(
394379
name2.lexeme, declaredElement.library);
395380
}
396381
}
397382
return null;
398383
}
399384
}
385+
386+
extension NullableAstNodeExtension on AstNode? {
387+
Element? get canonicalElement {
388+
var self = this;
389+
if (self is Expression) {
390+
var node = self.unParenthesized;
391+
if (node is Identifier) {
392+
return node.staticElement?.canonicalElement;
393+
} else if (node is PropertyAccess) {
394+
return node.propertyName.staticElement?.canonicalElement;
395+
}
396+
}
397+
return null;
398+
}
399+
}

lib/src/rules/annotate_overrides.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ class _Visitor extends SimpleAstVisitor<void> {
7979
}
8080

8181
Element? getOverriddenMember(Element member) {
82-
var classElement = member.thisOrAncestorOfType<ClassElement>();
82+
var classElement = member.thisOrAncestorOfType<InterfaceElement>();
8383
if (classElement == null) {
8484
return null;
8585
}

lib/src/rules/avoid_renaming_method_parameters.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class _Visitor extends SimpleAstVisitor<void> {
8686
}
8787
var parentElement = parentNode.declaredElement2;
8888
// Note: there are no override semantics with extension methods.
89-
if (parentElement is! ClassElement) {
89+
if (parentElement is! InterfaceElement) {
9090
return;
9191
}
9292

lib/src/rules/public_member_api_docs.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,18 @@ class _Visitor extends SimpleAstVisitor {
161161
return null;
162162
}
163163

164-
var classElement = member.thisOrAncestorOfType<ClassElement>();
165-
if (classElement == null) {
164+
var interfaceElement = member.thisOrAncestorOfType<InterfaceElement>();
165+
if (interfaceElement == null) {
166166
return null;
167167
}
168168
var name = member.name;
169169
if (name == null) {
170170
return null;
171171
}
172172

173-
var libraryUri = classElement.library.source.uri;
173+
var libraryUri = interfaceElement.library.source.uri;
174174
return context.inheritanceManager.getInherited(
175-
classElement.thisType,
175+
interfaceElement.thisType,
176176
Name(libraryUri, name),
177177
);
178178
}

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ environment:
1212
sdk: '>=2.17.0 <3.0.0'
1313

1414
dependencies:
15-
analyzer: ^4.6.0
15+
analyzer: ^4.7.0
1616
args: ^2.1.0
1717
collection: ^1.15.0
1818
http: ^0.13.0

test/rules/constant_identifier_names_test.dart

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ const R = (x: 1);
2929
]);
3030
}
3131

32-
@FailingTest(issue: 'https://github.com/dart-lang/linter/issues/3630')
3332
test_recordTypeDeclarations_ok() async {
3433
await assertNoDiagnostics(r'''
3534
const r = (x: 1);

test/rules/public_member_api_docs_test.dart

+19
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,23 @@ extension E on Object {
4545
lint('public_member_api_docs', 31, 1),
4646
]);
4747
}
48+
49+
test_mixin_method() async {
50+
await assertDiagnostics(r'''
51+
/// A mixin M.
52+
mixin M {
53+
String m() => '';
54+
}''', [
55+
lint('public_member_api_docs', 34, 1),
56+
]);
57+
}
58+
59+
test_mixin_overridingMethod_OK() async {
60+
await assertNoDiagnostics(r'''
61+
/// A mixin M.
62+
mixin M {
63+
@override
64+
String toString() => '';
65+
}''');
66+
}
4867
}

0 commit comments

Comments
 (0)