mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +00:00
Implement reporting WarningCode.SDK_VERSION_SINCE
It is not enabled by default yet, because there are existing violations. Bug: https://github.com/dart-lang/sdk/issues/34978 Change-Id: I60147d4c240d63d2f631513c8dfbd4917c35d47c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/287660 Reviewed-by: Samuel Rawlins <srawlins@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
919eb05b27
commit
10ee5fdf94
|
@ -2805,6 +2805,8 @@ WarningCode.SDK_VERSION_NEVER:
|
|||
notes: Deprecated
|
||||
WarningCode.SDK_VERSION_SET_LITERAL:
|
||||
status: hasFix
|
||||
WarningCode.SDK_VERSION_SINCE:
|
||||
status: needsEvaluation
|
||||
WarningCode.SDK_VERSION_UI_AS_CODE:
|
||||
status: hasFix
|
||||
WarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT:
|
||||
|
|
|
@ -165,6 +165,15 @@ extension IdentifierExtension on Identifier {
|
|||
return _readElement(this);
|
||||
}
|
||||
|
||||
SimpleIdentifier get simpleName {
|
||||
final self = this;
|
||||
if (self is SimpleIdentifier) {
|
||||
return self;
|
||||
} else {
|
||||
return (self as PrefixedIdentifier).identifier;
|
||||
}
|
||||
}
|
||||
|
||||
Element? get writeElement {
|
||||
return _writeElement(this);
|
||||
}
|
||||
|
|
|
@ -6736,6 +6736,16 @@ class WarningCode extends AnalyzerErrorCode {
|
|||
hasPublishedDocs: true,
|
||||
);
|
||||
|
||||
/// Parameters:
|
||||
/// 0: the version specified in the `@Since()` annotation
|
||||
/// 1: the SDK version constraints
|
||||
static const WarningCode SDK_VERSION_SINCE = WarningCode(
|
||||
'SDK_VERSION_SINCE',
|
||||
"This API is available since SDK {0}, but constraints '{1}' don't "
|
||||
"guarantee it.",
|
||||
correctionMessage: "Try updating the SDK constraints.",
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
static const WarningCode SDK_VERSION_UI_AS_CODE = WarningCode(
|
||||
'SDK_VERSION_UI_AS_CODE',
|
||||
|
|
|
@ -993,6 +993,7 @@ const List<ErrorCode> errorCodeValues = [
|
|||
WarningCode.SDK_VERSION_IS_EXPRESSION_IN_CONST_CONTEXT,
|
||||
WarningCode.SDK_VERSION_NEVER,
|
||||
WarningCode.SDK_VERSION_SET_LITERAL,
|
||||
WarningCode.SDK_VERSION_SINCE,
|
||||
WarningCode.SDK_VERSION_UI_AS_CODE,
|
||||
WarningCode.SDK_VERSION_UI_AS_CODE_IN_CONST_CONTEXT,
|
||||
WarningCode.SUBTYPE_OF_SEALED_CLASS,
|
||||
|
|
|
@ -16,6 +16,9 @@ import 'package:pub_semver/pub_semver.dart';
|
|||
/// A visitor that finds code that assumes a later version of the SDK than the
|
||||
/// minimum version required by the SDK constraints in `pubspec.yaml`.
|
||||
class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
||||
/// TODO(scheglov) Fix pre-existing violations and remove.
|
||||
static bool shouldCheckSinceSdkVersion = false;
|
||||
|
||||
/// The error reporter to be used to report errors.
|
||||
final ErrorReporter _errorReporter;
|
||||
|
||||
|
@ -123,6 +126,20 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
bool get checkUiAsCode =>
|
||||
_checkUiAsCode ??= !before_2_2_2.intersect(_versionConstraint).isEmpty;
|
||||
|
||||
@override
|
||||
void visitArgumentList(ArgumentList node) {
|
||||
// Check (optional) positional arguments.
|
||||
// Named arguments are checked in [NamedExpression].
|
||||
for (final argument in node.arguments) {
|
||||
if (argument is! NamedExpression) {
|
||||
final parameter = argument.staticParameterElement;
|
||||
_checkSinceSdkVersion(parameter, node, errorNode: argument);
|
||||
}
|
||||
}
|
||||
|
||||
super.visitArgumentList(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitAsExpression(AsExpression node) {
|
||||
if (checkConstantUpdate2018 && node.inConstantContext) {
|
||||
|
@ -132,6 +149,13 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
super.visitAsExpression(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitAssignmentExpression(AssignmentExpression node) {
|
||||
_checkSinceSdkVersion(node.readElement, node);
|
||||
_checkSinceSdkVersion(node.writeElement, node);
|
||||
super.visitAssignmentExpression(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitBinaryExpression(BinaryExpression node) {
|
||||
if (checkTripleShift) {
|
||||
|
@ -171,6 +195,12 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
super.visitBinaryExpression(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitConstructorName(ConstructorName node) {
|
||||
_checkSinceSdkVersion(node.staticElement, node);
|
||||
super.visitConstructorName(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitExtensionDeclaration(ExtensionDeclaration node) {
|
||||
if (checkExtensionMethods) {
|
||||
|
@ -199,6 +229,12 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
_inUiAsCode = wasInUiAsCode;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
||||
_checkSinceSdkVersion(node.staticElement, node);
|
||||
super.visitFunctionExpressionInvocation(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitHideCombinator(HideCombinator node) {
|
||||
// Don't flag references to either `Future` or `Stream` within a combinator.
|
||||
|
@ -232,6 +268,30 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
super.visitMethodDeclaration(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitMethodInvocation(MethodInvocation node) {
|
||||
_checkSinceSdkVersion(node.methodName.staticElement, node);
|
||||
super.visitMethodInvocation(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitNamedType(NamedType node) {
|
||||
_checkSinceSdkVersion(node.name.staticElement, node);
|
||||
super.visitNamedType(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitPrefixedIdentifier(PrefixedIdentifier node) {
|
||||
_checkSinceSdkVersion(node.staticElement, node);
|
||||
super.visitPrefixedIdentifier(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitPropertyAccess(PropertyAccess node) {
|
||||
_checkSinceSdkVersion(node.propertyName.staticElement, node);
|
||||
super.visitPropertyAccess(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitSetOrMapLiteral(SetOrMapLiteral node) {
|
||||
if (node.isSet && checkSetLiterals && !_inSetLiteral) {
|
||||
|
@ -254,6 +314,7 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
if (node.inDeclarationContext()) {
|
||||
return;
|
||||
}
|
||||
_checkSinceSdkVersion(node.staticElement, node);
|
||||
var element = node.staticElement;
|
||||
if (checkFutureAndStream &&
|
||||
element is InterfaceElement &&
|
||||
|
@ -287,6 +348,54 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
_inUiAsCode = wasInUiAsCode;
|
||||
}
|
||||
|
||||
void _checkSinceSdkVersion(
|
||||
Element? element,
|
||||
AstNode target, {
|
||||
AstNode? errorNode,
|
||||
}) {
|
||||
if (!shouldCheckSinceSdkVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (element != null) {
|
||||
final sinceSdkVersion = element.sinceSdkVersion;
|
||||
if (sinceSdkVersion != null) {
|
||||
if (!_versionConstraint.requiresAtLeast(sinceSdkVersion)) {
|
||||
if (errorNode == null) {
|
||||
if (target is AssignmentExpression) {
|
||||
target = target.leftHandSide;
|
||||
}
|
||||
if (target is ConstructorName) {
|
||||
errorNode = target.name ?? target.type.name.simpleName;
|
||||
} else if (target is FunctionExpressionInvocation) {
|
||||
errorNode = target.argumentList;
|
||||
} else if (target is MethodInvocation) {
|
||||
errorNode = target.methodName;
|
||||
} else if (target is NamedType) {
|
||||
errorNode = target.name.simpleName;
|
||||
} else if (target is PrefixedIdentifier) {
|
||||
errorNode = target.identifier;
|
||||
} else if (target is PropertyAccess) {
|
||||
errorNode = target.propertyName;
|
||||
} else if (target is SimpleIdentifier) {
|
||||
errorNode = target;
|
||||
} else {
|
||||
throw UnimplementedError('(${target.runtimeType}) $target');
|
||||
}
|
||||
}
|
||||
_errorReporter.reportErrorForNode(
|
||||
WarningCode.SDK_VERSION_SINCE,
|
||||
errorNode,
|
||||
[
|
||||
sinceSdkVersion.toString(),
|
||||
_versionConstraint.toString(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Given that the [node] is only valid when the ui-as-code feature is
|
||||
/// enabled, check that the code will not be executed with a version of the
|
||||
/// SDK that does not support the feature.
|
||||
|
@ -309,3 +418,22 @@ class SdkConstraintVerifier extends RecursiveAstVisitor<void> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension on VersionConstraint {
|
||||
bool requiresAtLeast(Version version) {
|
||||
final self = this;
|
||||
if (self is Version) {
|
||||
return self == version;
|
||||
}
|
||||
if (self is VersionRange) {
|
||||
final min = self.min;
|
||||
if (min == null) {
|
||||
return false;
|
||||
} else {
|
||||
return min >= version;
|
||||
}
|
||||
}
|
||||
// We don't know, but will not complain.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22889,6 +22889,13 @@ WarningCode:
|
|||
```dart
|
||||
var s = new Set<int>();
|
||||
```
|
||||
SDK_VERSION_SINCE:
|
||||
problemMessage: "This API is available since SDK {0}, but constraints '{1}' don't guarantee it."
|
||||
correctionMessage: Try updating the SDK constraints.
|
||||
comment: |-
|
||||
Parameters:
|
||||
0: the version specified in the `@Since()` annotation
|
||||
1: the SDK version constraints
|
||||
SDK_VERSION_UI_AS_CODE:
|
||||
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."
|
||||
correctionMessage: Try updating the SDK constraints.
|
||||
|
|
|
@ -20,4 +20,17 @@ class SdkConstraintVerifierTest extends PubPackageResolutionTest {
|
|||
|
||||
await assertErrorsInCode(source, expectedErrors ?? []);
|
||||
}
|
||||
|
||||
/// Verify that the [expectedErrors] are produced if the [source] is analyzed
|
||||
/// in a context that uses given SDK [constraints].
|
||||
Future<void> verifyVersion2(String constraints, String source,
|
||||
{List<ExpectedError>? expectedErrors}) async {
|
||||
writeTestPackagePubspecYamlFile(
|
||||
PubspecYamlFileConfig(
|
||||
sdkVersion: constraints,
|
||||
),
|
||||
);
|
||||
|
||||
await assertErrorsInCode(source, expectedErrors ?? []);
|
||||
}
|
||||
}
|
||||
|
|
947
pkg/analyzer/test/src/diagnostics/sdk_version_since_test.dart
Normal file
947
pkg/analyzer/test/src/diagnostics/sdk_version_since_test.dart
Normal file
|
@ -0,0 +1,947 @@
|
|||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:analyzer/src/hint/sdk_constraint_verifier.dart';
|
||||
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import 'sdk_constraint_verifier_support.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(SdkVersionSinceTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class SdkVersionSinceTest extends SdkConstraintVerifierTest {
|
||||
@override
|
||||
List<MockSdkLibrary> additionalMockSdkLibraries = [];
|
||||
|
||||
@override
|
||||
void setUp() {
|
||||
SdkConstraintVerifier.shouldCheckSinceSdkVersion = true;
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> tearDown() async {
|
||||
SdkConstraintVerifier.shouldCheckSinceSdkVersion = false;
|
||||
await super.tearDown();
|
||||
}
|
||||
|
||||
test_class_constructor_formalParameter_optionalNamed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
void A({@Since('2.15') int? foo});
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
A(foo: 0);
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_constructor_formalParameter_optionalPositional() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
void A([@Since('2.15') int? foo]);
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
A(42);
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 2),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_constructor_named_instanceCreation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A<T> {
|
||||
@Since('2.15')
|
||||
A.named();
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
A<int>.named();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 5),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_constructor_named_tearOff() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A<T> {
|
||||
@Since('2.15')
|
||||
A.named();
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
A<int>.named;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 5),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_constructor_unnamed_instanceCreation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A<T> {
|
||||
@Since('2.15')
|
||||
A();
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
A<int>();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 33, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_field_read() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
int foo = 0;
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
(a).foo;
|
||||
a.foo;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
error(WarningCode.SDK_VERSION_SINCE, 49, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_field_readWrite() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
int foo = 0;
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
(a).foo += 0;
|
||||
a.foo += 0;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
error(WarningCode.SDK_VERSION_SINCE, 54, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_field_write() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
int foo = 0;
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
(a).foo = 0;
|
||||
a.foo = 0;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
error(WarningCode.SDK_VERSION_SINCE, 53, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_getter() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
int get foo => 0;
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
(a).foo;
|
||||
a.foo;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
error(WarningCode.SDK_VERSION_SINCE, 49, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_getterSetter_readWrite_both() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
int get foo => 0;
|
||||
@Since('2.15')
|
||||
set foo(int _) {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
a.foo += 0;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_getterSetter_readWrite_getter() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
int get foo => 0;
|
||||
set foo(int _) {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
a.foo += 0;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_getterSetter_readWrite_setter() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
int get foo => 0;
|
||||
@Since('2.15')
|
||||
set foo(int _) {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
a.foo += 0;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_instanceCreation_prefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A<T> {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo' as foo;
|
||||
|
||||
void f() {
|
||||
foo.A<int>();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 44, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_instanceCreation_unprefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A<T> {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
A<int>();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 33, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_method_call_functionExpressionInvocation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
void call() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
a();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 37, 2),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_method_formalParameter_optionalNamed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
void foo(
|
||||
int a, {
|
||||
@Since('2.15')
|
||||
int? bar,
|
||||
}) {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
foo(0, bar: 1);
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_method_formalParameter_optionalPositional() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
void foo(
|
||||
int a, [
|
||||
@Since('2.15')
|
||||
int? bar,
|
||||
]) {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
foo(0, 42);
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 2),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_method_methodInvocation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
a.foo();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_method_methodTearOff_prefixedIdentifier() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
a.foo;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 3),
|
||||
]);
|
||||
|
||||
final node = findNode.prefixed('.foo');
|
||||
assertResolvedNodeText(node, r'''
|
||||
PrefixedIdentifier
|
||||
prefix: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: self::@function::f::@parameter::a
|
||||
staticType: A
|
||||
period: .
|
||||
identifier: SimpleIdentifier
|
||||
token: foo
|
||||
staticElement: dart:foo::@class::A::@method::foo
|
||||
staticType: void Function()
|
||||
staticElement: dart:foo::@class::A::@method::foo
|
||||
staticType: void Function()
|
||||
''');
|
||||
}
|
||||
|
||||
test_class_method_methodTearOff_propertyAccess() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
(a).foo;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
]);
|
||||
|
||||
final node = findNode.propertyAccess('.foo');
|
||||
assertResolvedNodeText(node, r'''
|
||||
PropertyAccess
|
||||
target: ParenthesizedExpression
|
||||
leftParenthesis: (
|
||||
expression: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: self::@function::f::@parameter::a
|
||||
staticType: A
|
||||
rightParenthesis: )
|
||||
staticType: A
|
||||
operator: .
|
||||
propertyName: SimpleIdentifier
|
||||
token: foo
|
||||
staticElement: dart:foo::@class::A::@method::foo
|
||||
staticType: void Function()
|
||||
staticType: void Function()
|
||||
''');
|
||||
}
|
||||
|
||||
test_class_setter() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
class A {
|
||||
@Since('2.15')
|
||||
set foo(int _) {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {
|
||||
(a).foo = 0;
|
||||
a.foo = 0;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 40, 3),
|
||||
error(WarningCode.SDK_VERSION_SINCE, 53, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_typeAnnotation_prefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A<T> {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo' as foo;
|
||||
|
||||
void f(foo.A<int> a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_class_typeAnnotation_unprefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A<T> {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A<int> a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_constraints_exact_equal() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('2.15.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: []);
|
||||
}
|
||||
|
||||
test_constraints_exact_greater() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('2.16.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_constraints_exact_less() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_constraints_greater_equal() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>2.15.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: []);
|
||||
}
|
||||
|
||||
test_constraints_greaterOrEq_equal() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.15.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: []);
|
||||
}
|
||||
|
||||
test_constraints_greaterOrEq_greater() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.16.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: []);
|
||||
}
|
||||
|
||||
test_constraints_greaterOrEq_less() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
class A {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(A a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_enum_constant() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
enum E {
|
||||
v1,
|
||||
@Since('2.15')
|
||||
v2
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
E.v2;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 2),
|
||||
]);
|
||||
}
|
||||
|
||||
test_enum_typeAnnotation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
enum E {
|
||||
v
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(E a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_extension_getter() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
extension E on int {
|
||||
@Since('2.15')
|
||||
int get foo => 0;
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
0.foo;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_extension_itself_extensionOverride_methodInvocation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
extension E on int {
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
E(0).foo();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 33, 1),
|
||||
error(WarningCode.SDK_VERSION_SINCE, 38, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_extension_itself_methodInvocation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
extension E on int {
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
0.foo();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_extension_method_methodInvocation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
extension E on int {
|
||||
@Since('2.15')
|
||||
void foo() {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
0.foo();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_extension_setter() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
extension E on int {
|
||||
@Since('2.15')
|
||||
set foo(int _) {}
|
||||
}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
0.foo = 1;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 35, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_functionTypeAlias() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
typedef void X(int _);
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(X a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_genericTypeAlias() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
typedef X = List<int>;
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(X a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_mixin_typeAnnotation() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
mixin M<T> {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f(M<int> a) {}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 27, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_topLevelFunction_prefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
void bar() {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo' as foo;
|
||||
|
||||
void f() {
|
||||
foo.bar();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 44, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_topLevelFunction_unprefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
void foo() {}
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
foo();
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 33, 3),
|
||||
]);
|
||||
}
|
||||
|
||||
test_topLevelVariable_prefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
const v = 0;
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo' as foo;
|
||||
|
||||
void f() {
|
||||
foo.v;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 44, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_topLevelVariable_unprefixed() async {
|
||||
_addDartFooLibrary(r'''
|
||||
import 'dart:_internal';
|
||||
|
||||
@Since('2.15')
|
||||
const v = 0;
|
||||
''');
|
||||
|
||||
await verifyVersion2('>=2.14.0', '''
|
||||
import 'dart:foo';
|
||||
|
||||
void f() {
|
||||
v;
|
||||
}
|
||||
''', expectedErrors: [
|
||||
error(WarningCode.SDK_VERSION_SINCE, 33, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
void _addDartFooLibrary(String content) {
|
||||
additionalMockSdkLibraries.add(
|
||||
MockSdkLibrary('foo', [
|
||||
MockSdkLibraryUnit('foo/foo.dart', content),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -723,6 +723,7 @@ import 'sdk_version_is_expression_in_const_context_test.dart'
|
|||
as sdk_version_is_expression_in_const_context;
|
||||
import 'sdk_version_never_test.dart' as sdk_version_never;
|
||||
import 'sdk_version_set_literal_test.dart' as sdk_version_set_literal;
|
||||
import 'sdk_version_since_test.dart' as sdk_version_since;
|
||||
import 'sdk_version_ui_as_code_in_const_context_test.dart'
|
||||
as sdk_version_ui_as_code_in_const_context;
|
||||
import 'sdk_version_ui_as_code_test.dart' as sdk_version_ui_as_code;
|
||||
|
@ -1345,6 +1346,7 @@ main() {
|
|||
sdk_version_is_expression_in_const_context.main();
|
||||
sdk_version_never.main();
|
||||
sdk_version_set_literal.main();
|
||||
sdk_version_since.main();
|
||||
sdk_version_ui_as_code.main();
|
||||
sdk_version_ui_as_code_in_const_context.main();
|
||||
sealed_class_subtype_outside_of_library.main();
|
||||
|
|
Loading…
Reference in a new issue