@@ -10,6 +10,13 @@ import 'package:analyzer/dart/element/type.dart';
10
10
import '../extensions.dart' ;
11
11
import '../util/dart_type_utilities.dart' ;
12
12
13
+ const _nameBuildContext = 'BuildContext' ;
14
+ const _nameContainer = 'Container' ;
15
+ const _nameSizedBox = 'SizedBox' ;
16
+ const _nameState = 'State' ;
17
+ const _nameStatefulWidget = 'StatefulWidget' ;
18
+ const _nameWidget = 'Widget' ;
19
+
13
20
var _collectionInterfaces = < InterfaceTypeDefinition > [
14
21
InterfaceTypeDefinition ('List' , 'dart.core' ),
15
22
InterfaceTypeDefinition ('Map' , 'dart.core' ),
@@ -20,6 +27,10 @@ var _collectionInterfaces = <InterfaceTypeDefinition>[
20
27
21
28
_Flutter _flutterInstance = _Flutter ('flutter' , 'package:flutter' );
22
29
30
+ final Uri _uriFramework = Uri .parse (
31
+ 'package:flutter/src/widgets/framework.dart' ,
32
+ );
33
+
23
34
_Flutter get _flutter => _flutterInstance;
24
35
25
36
bool hasWidgetAsAscendant (ClassElement element) =>
@@ -64,13 +75,6 @@ bool isWidgetType(DartType? type) => _flutter.isWidgetType(type);
64
75
///
65
76
/// See pkg/analysis_server/lib/src/utilities/flutter.dart.
66
77
class _Flutter {
67
- static const _nameBuildContext = 'BuildContext' ;
68
- static const _nameContainer = 'Container' ;
69
- static const _nameSizedBox = 'SizedBox' ;
70
- static const _nameState = 'State' ;
71
- static const _nameStatefulWidget = 'StatefulWidget' ;
72
- static const _nameWidget = 'Widget' ;
73
-
74
78
final String packageName;
75
79
final String widgetsUri;
76
80
@@ -122,6 +126,9 @@ class _Flutter {
122
126
bool isExactWidget (ClassElement element) =>
123
127
isExactly (element, _nameWidget, _uriFramework);
124
128
129
+ bool isExactWidget2 (ClassElement2 element) =>
130
+ isExactly2 (element, _nameWidget, _uriFramework);
131
+
125
132
bool isExactWidgetTypeContainer (DartType ? type) =>
126
133
type is InterfaceType &&
127
134
isExactly (type.element, _nameContainer, _uriContainer);
@@ -165,3 +172,39 @@ class _Flutter {
165
172
bool isWidgetType (DartType ? type) =>
166
173
type is InterfaceType && isWidget (type.element3);
167
174
}
175
+
176
+ // TODO(pq): based on similar extension in server. (Move and reuse.)
177
+ extension InterfaceElementExtension2 on InterfaceElement2 ? {
178
+ bool get extendsWidget => _hasWidgetAsAscendant (this , {});
179
+
180
+ bool get isExactlyWidget => _isExactly (_nameWidget, _uriFramework);
181
+
182
+ /// Whether this is the Flutter class `Widget` , or a subtype.
183
+ bool get isWidget {
184
+ var self = this ;
185
+ if (self is ! ClassElement2 ) return false ;
186
+
187
+ if (isExactlyWidget) return true ;
188
+
189
+ return self.allSupertypes
190
+ .any ((type) => type.element3._isExactly (_nameWidget, _uriFramework));
191
+ }
192
+
193
+ /// Whether this is the exact [type] defined in the file with the given [uri] .
194
+ bool _isExactly (String type, Uri uri) {
195
+ var self = this ;
196
+ return self is ClassElement2 &&
197
+ self.name3 == type &&
198
+ self.firstFragment.libraryFragment.source.uri == uri;
199
+ }
200
+
201
+ static bool _hasWidgetAsAscendant (
202
+ InterfaceElement2 ? element, Set <InterfaceElement2 > alreadySeen) {
203
+ if (element == null ) return false ;
204
+ if (element.isExactlyWidget) return true ;
205
+
206
+ if (! alreadySeen.add (element)) return false ;
207
+
208
+ return _hasWidgetAsAscendant (element.supertype? .element3, alreadySeen);
209
+ }
210
+ }
0 commit comments