Skip to content

Commit 10ee5fd

Browse files
scheglovCommit Queue
authored and
Commit Queue
committed
Implement reporting WarningCode.SDK_VERSION_SINCE
It is not enabled by default yet, because there are existing violations. Bug: #34978 Change-Id: I60147d4c240d63d2f631513c8dfbd4917c35d47c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287660 Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 919eb05 commit 10ee5fd

File tree

9 files changed

+1119
-0
lines changed

9 files changed

+1119
-0
lines changed

pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2805,6 +2805,8 @@ WarningCode.SDK_VERSION_NEVER:
28052805
notes: Deprecated
28062806
WarningCode.SDK_VERSION_SET_LITERAL:
28072807
status: hasFix
2808+
WarningCode.SDK_VERSION_SINCE:
2809+
status: needsEvaluation
28082810
WarningCode.SDK_VERSION_UI_AS_CODE:
28092811
status: hasFix
28102812
WarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT:

pkg/analyzer/lib/src/dart/ast/extensions.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,15 @@ extension IdentifierExtension on Identifier {
165165
return _readElement(this);
166166
}
167167

168+
SimpleIdentifier get simpleName {
169+
final self = this;
170+
if (self is SimpleIdentifier) {
171+
return self;
172+
} else {
173+
return (self as PrefixedIdentifier).identifier;
174+
}
175+
}
176+
168177
Element? get writeElement {
169178
return _writeElement(this);
170179
}

pkg/analyzer/lib/src/error/codes.g.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6736,6 +6736,16 @@ class WarningCode extends AnalyzerErrorCode {
67366736
hasPublishedDocs: true,
67376737
);
67386738

6739+
/// Parameters:
6740+
/// 0: the version specified in the `@Since()` annotation
6741+
/// 1: the SDK version constraints
6742+
static const WarningCode SDK_VERSION_SINCE = WarningCode(
6743+
'SDK_VERSION_SINCE',
6744+
"This API is available since SDK {0}, but constraints '{1}' don't "
6745+
"guarantee it.",
6746+
correctionMessage: "Try updating the SDK constraints.",
6747+
);
6748+
67396749
/// No parameters.
67406750
static const WarningCode SDK_VERSION_UI_AS_CODE = WarningCode(
67416751
'SDK_VERSION_UI_AS_CODE',

pkg/analyzer/lib/src/error/error_code_values.g.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,7 @@ const List<ErrorCode> errorCodeValues = [
993993
WarningCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT,
994994
WarningCode.SDK_VERSION_NEVER,
995995
WarningCode.SDK_VERSION_SET_LITERAL,
996+
WarningCode.SDK_VERSION_SINCE,
996997
WarningCode.SDK_VERSION_UI_AS_CODE,
997998
WarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT,
998999
WarningCode.SUBTYPE_OF_SEALED_CLASS,

pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import 'package:pub_semver/pub_semver.dart';
1616
/// A visitor that finds code that assumes a later version of the SDK than the
1717
/// minimum version required by the SDK constraints in `pubspec.yaml`.
1818
class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
19+
/// TODO(scheglov) Fix pre-existing violations and remove.
20+
static bool shouldCheckSinceSdkVersion = false;
21+
1922
/// The error reporter to be used to report errors.
2023
final ErrorReporter _errorReporter;
2124

@@ -123,6 +126,20 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
123126
bool get checkUiAsCode =>
124127
_checkUiAsCode ??= !before_2_2_2.intersect(_versionConstraint).isEmpty;
125128

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+
126143
@override
127144
void visitAsExpression(AsExpression node) {
128145
if (checkConstantUpdate2018 && node.inConstantContext) {
@@ -132,6 +149,13 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
132149
super.visitAsExpression(node);
133150
}
134151

152+
@override
153+
void visitAssignmentExpression(AssignmentExpression node) {
154+
_checkSinceSdkVersion(node.readElement, node);
155+
_checkSinceSdkVersion(node.writeElement, node);
156+
super.visitAssignmentExpression(node);
157+
}
158+
135159
@override
136160
void visitBinaryExpression(BinaryExpression node) {
137161
if (checkTripleShift) {
@@ -171,6 +195,12 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
171195
super.visitBinaryExpression(node);
172196
}
173197

198+
@override
199+
void visitConstructorName(ConstructorName node) {
200+
_checkSinceSdkVersion(node.staticElement, node);
201+
super.visitConstructorName(node);
202+
}
203+
174204
@override
175205
void visitExtensionDeclaration(ExtensionDeclaration node) {
176206
if (checkExtensionMethods) {
@@ -199,6 +229,12 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
199229
_inUiAsCode = wasInUiAsCode;
200230
}
201231

232+
@override
233+
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
234+
_checkSinceSdkVersion(node.staticElement, node);
235+
super.visitFunctionExpressionInvocation(node);
236+
}
237+
202238
@override
203239
void visitHideCombinator(HideCombinator node) {
204240
// Don't flag references to either `Future` or `Stream` within a combinator.
@@ -232,6 +268,30 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
232268
super.visitMethodDeclaration(node);
233269
}
234270

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+
235295
@override
236296
void visitSetOrMapLiteral(SetOrMapLiteral node) {
237297
if (node.isSet && checkSetLiterals && !_inSetLiteral) {
@@ -254,6 +314,7 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
254314
if (node.inDeclarationContext()) {
255315
return;
256316
}
317+
_checkSinceSdkVersion(node.staticElement, node);
257318
var element = node.staticElement;
258319
if (checkFutureAndStream &&
259320
element is InterfaceElement &&
@@ -287,6 +348,54 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
287348
_inUiAsCode = wasInUiAsCode;
288349
}
289350

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+
290399
/// Given that the [node] is only valid when the ui-as-code feature is
291400
/// enabled, check that the code will not be executed with a version of the
292401
/// SDK that does not support the feature.
@@ -309,3 +418,22 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
309418
}
310419
}
311420
}
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+
}

pkg/analyzer/messages.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22889,6 +22889,13 @@ WarningCode:
2288922889
```dart
2289022890
var s = new Set<int>();
2289122891
```
22892+
SDK_VERSION_SINCE:
22893+
problemMessage: "This API is available since SDK {0}, but constraints '{1}' don't guarantee it."
22894+
correctionMessage: Try updating the SDK constraints.
22895+
comment: |-
22896+
Parameters:
22897+
0: the version specified in the `@Since()` annotation
22898+
1: the SDK version constraints
2289222899
SDK_VERSION_UI_AS_CODE:
2289322900
problemMessage: "The for, if, and spread elements weren't supported until version 2.3.0, but this code is required to be able to run on earlier versions."
2289422901
correctionMessage: Try updating the SDK constraints.

pkg/analyzer/test/src/diagnostics/sdk_constraint_verifier_support.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,17 @@ class SdkConstraintVerifierTest extends PubPackageResolutionTest {
2020

2121
await assertErrorsInCode(source, expectedErrors ?? []);
2222
}
23+
24+
/// Verify that the [expectedErrors] are produced if the [source] is analyzed
25+
/// in a context that uses given SDK [constraints].
26+
Future<void> verifyVersion2(String constraints, String source,
27+
{List<ExpectedError>? expectedErrors}) async {
28+
writeTestPackagePubspecYamlFile(
29+
PubspecYamlFileConfig(
30+
sdkVersion: constraints,
31+
),
32+
);
33+
34+
await assertErrorsInCode(source, expectedErrors ?? []);
35+
}
2336
}

0 commit comments

Comments
 (0)