@@ -16,6 +16,9 @@ import 'package:pub_semver/pub_semver.dart';
16
16
/// A visitor that finds code that assumes a later version of the SDK than the
17
17
/// minimum version required by the SDK constraints in `pubspec.yaml` .
18
18
class SdkConstraintVerifier extends RecursiveAstVisitor <void > {
19
+ /// TODO(scheglov) Fix pre-existing violations and remove.
20
+ static bool shouldCheckSinceSdkVersion = false ;
21
+
19
22
/// The error reporter to be used to report errors.
20
23
final ErrorReporter _errorReporter;
21
24
@@ -123,6 +126,20 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
123
126
bool get checkUiAsCode =>
124
127
_checkUiAsCode ?? = ! before_2_2_2.intersect (_versionConstraint).isEmpty;
125
128
129
+ @override
130
+ void visitArgumentList (ArgumentList node) {
131
+ // Check (optional) positional arguments.
132
+ // Named arguments are checked in [NamedExpression].
133
+ for (final argument in node.arguments) {
134
+ if (argument is ! NamedExpression ) {
135
+ final parameter = argument.staticParameterElement;
136
+ _checkSinceSdkVersion (parameter, node, errorNode: argument);
137
+ }
138
+ }
139
+
140
+ super .visitArgumentList (node);
141
+ }
142
+
126
143
@override
127
144
void visitAsExpression (AsExpression node) {
128
145
if (checkConstantUpdate2018 && node.inConstantContext) {
@@ -132,6 +149,13 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
132
149
super .visitAsExpression (node);
133
150
}
134
151
152
+ @override
153
+ void visitAssignmentExpression (AssignmentExpression node) {
154
+ _checkSinceSdkVersion (node.readElement, node);
155
+ _checkSinceSdkVersion (node.writeElement, node);
156
+ super .visitAssignmentExpression (node);
157
+ }
158
+
135
159
@override
136
160
void visitBinaryExpression (BinaryExpression node) {
137
161
if (checkTripleShift) {
@@ -171,6 +195,12 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
171
195
super .visitBinaryExpression (node);
172
196
}
173
197
198
+ @override
199
+ void visitConstructorName (ConstructorName node) {
200
+ _checkSinceSdkVersion (node.staticElement, node);
201
+ super .visitConstructorName (node);
202
+ }
203
+
174
204
@override
175
205
void visitExtensionDeclaration (ExtensionDeclaration node) {
176
206
if (checkExtensionMethods) {
@@ -199,6 +229,12 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
199
229
_inUiAsCode = wasInUiAsCode;
200
230
}
201
231
232
+ @override
233
+ void visitFunctionExpressionInvocation (FunctionExpressionInvocation node) {
234
+ _checkSinceSdkVersion (node.staticElement, node);
235
+ super .visitFunctionExpressionInvocation (node);
236
+ }
237
+
202
238
@override
203
239
void visitHideCombinator (HideCombinator node) {
204
240
// Don't flag references to either `Future` or `Stream` within a combinator.
@@ -232,6 +268,30 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
232
268
super .visitMethodDeclaration (node);
233
269
}
234
270
271
+ @override
272
+ void visitMethodInvocation (MethodInvocation node) {
273
+ _checkSinceSdkVersion (node.methodName.staticElement, node);
274
+ super .visitMethodInvocation (node);
275
+ }
276
+
277
+ @override
278
+ void visitNamedType (NamedType node) {
279
+ _checkSinceSdkVersion (node.name.staticElement, node);
280
+ super .visitNamedType (node);
281
+ }
282
+
283
+ @override
284
+ void visitPrefixedIdentifier (PrefixedIdentifier node) {
285
+ _checkSinceSdkVersion (node.staticElement, node);
286
+ super .visitPrefixedIdentifier (node);
287
+ }
288
+
289
+ @override
290
+ void visitPropertyAccess (PropertyAccess node) {
291
+ _checkSinceSdkVersion (node.propertyName.staticElement, node);
292
+ super .visitPropertyAccess (node);
293
+ }
294
+
235
295
@override
236
296
void visitSetOrMapLiteral (SetOrMapLiteral node) {
237
297
if (node.isSet && checkSetLiterals && ! _inSetLiteral) {
@@ -254,6 +314,7 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
254
314
if (node.inDeclarationContext ()) {
255
315
return ;
256
316
}
317
+ _checkSinceSdkVersion (node.staticElement, node);
257
318
var element = node.staticElement;
258
319
if (checkFutureAndStream &&
259
320
element is InterfaceElement &&
@@ -287,6 +348,54 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
287
348
_inUiAsCode = wasInUiAsCode;
288
349
}
289
350
351
+ void _checkSinceSdkVersion (
352
+ Element ? element,
353
+ AstNode target, {
354
+ AstNode ? errorNode,
355
+ }) {
356
+ if (! shouldCheckSinceSdkVersion) {
357
+ return ;
358
+ }
359
+
360
+ if (element != null ) {
361
+ final sinceSdkVersion = element.sinceSdkVersion;
362
+ if (sinceSdkVersion != null ) {
363
+ if (! _versionConstraint.requiresAtLeast (sinceSdkVersion)) {
364
+ if (errorNode == null ) {
365
+ if (target is AssignmentExpression ) {
366
+ target = target.leftHandSide;
367
+ }
368
+ if (target is ConstructorName ) {
369
+ errorNode = target.name ?? target.type.name.simpleName;
370
+ } else if (target is FunctionExpressionInvocation ) {
371
+ errorNode = target.argumentList;
372
+ } else if (target is MethodInvocation ) {
373
+ errorNode = target.methodName;
374
+ } else if (target is NamedType ) {
375
+ errorNode = target.name.simpleName;
376
+ } else if (target is PrefixedIdentifier ) {
377
+ errorNode = target.identifier;
378
+ } else if (target is PropertyAccess ) {
379
+ errorNode = target.propertyName;
380
+ } else if (target is SimpleIdentifier ) {
381
+ errorNode = target;
382
+ } else {
383
+ throw UnimplementedError ('(${target .runtimeType }) $target ' );
384
+ }
385
+ }
386
+ _errorReporter.reportErrorForNode (
387
+ WarningCode .SDK_VERSION_SINCE ,
388
+ errorNode,
389
+ [
390
+ sinceSdkVersion.toString (),
391
+ _versionConstraint.toString (),
392
+ ],
393
+ );
394
+ }
395
+ }
396
+ }
397
+ }
398
+
290
399
/// Given that the [node] is only valid when the ui-as-code feature is
291
400
/// enabled, check that the code will not be executed with a version of the
292
401
/// SDK that does not support the feature.
@@ -309,3 +418,22 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
309
418
}
310
419
}
311
420
}
421
+
422
+ extension on VersionConstraint {
423
+ bool requiresAtLeast (Version version) {
424
+ final self = this ;
425
+ if (self is Version ) {
426
+ return self == version;
427
+ }
428
+ if (self is VersionRange ) {
429
+ final min = self.min;
430
+ if (min == null ) {
431
+ return false ;
432
+ } else {
433
+ return min >= version;
434
+ }
435
+ }
436
+ // We don't know, but will not complain.
437
+ return true ;
438
+ }
439
+ }
0 commit comments