CQ. Migrate more tests from assertErrorsInCode().

Move another batch of analyzer tests away from offset-based
assertErrorsInCode() expectations. Put expected diagnostics and context
messages directly in the source snippets instead, including multi-file
cases that need context markers in supporting files.

This keeps each diagnostic expectation next to the code that produces
it, making the tests easier to read and less fragile when surrounding
code changes. It also removes now-unused diagnostic imports and helper
parameters that were only needed for explicit ExpectedDiagnostic lists.

Update the diagnostic expectation utilities so stripping generated
marker lines preserves the retained source lines correctly.

Change-Id: Ibe3890b9ff5e2b2e102e13e5ecc243bdf80c5f4b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509682
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Konstantin Shcheglov
2026-06-08 13:47:41 -07:00
parent 9b8d908379
commit 3a85655f91
24 changed files with 1405 additions and 1369 deletions
@@ -5,7 +5,6 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -2682,18 +2681,20 @@ class A {
''');
}
@failingTest
test_null_callOperator() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
null + 5;
// ^
// [diag.invalidUseOfNullValue] An expression whose value is always 'null' can't be dereferenced.
null == 5;
//^^^^^^^
// [diag.unnecessaryNullComparisonNeverNullFalse] The operand can't be 'null', so the condition is always 'false'.
null[0];
// ^
// [diag.invalidUseOfNullValue] An expression whose value is always 'null' can't be dereferenced.
}
''',
[error(diag.undefinedMethod, 0, 0), error(diag.undefinedMethod, 0, 0)],
);
''');
}
test_optionalNew_rewrite() async {
+246 -256
View File
@@ -11,7 +11,6 @@ import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -328,17 +327,19 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
// variable if they are ordered right to left, when the variable
// appears co- and contra-variantly, and that an error is issued
// for the non-matching bound.
String code = r'''
var result = await resolveTestCodeWithDiagnostics(r'''
typedef To Func1<From, To>(From x);
T f<T extends Func1<S, S>, S>(S x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'T'.
void test() { var x = f(3)(null); }
''';
var result = await assertErrorsInCode(code, [
error(diag.returnOfInvalidTypeFromFunction, 82, 4),
error(diag.unusedLocalVariable, 110, 1),
error(diag.couldNotInfer, 114, 1),
error(diag.argumentTypeNotAssignable, 119, 4),
]);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'x' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'Object? Function(Never)' for 'T' which doesn't work:\n Type parameter 'T' is declared to extend 'S Function(S)' producing 'int Function(int)'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Null' can't be assigned to the parameter type 'Never'.
''');
List<Statement> statements = AstFinder.getStatementsInTopLevelFunction(
result.unit,
@@ -961,39 +962,36 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_downwards1() async {
// Test that downwards inference interacts correctly with FutureOr
// parameters.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
Future<int> test() => mk(new Future<int>.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 60, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards2() async {
// Test that downwards inference interacts correctly with FutureOr
// parameters when the downwards context is FutureOr
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
FutureOr<int> test() => mk(new Future<int>.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 60, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_downwards3() async {
// Test that downwards inference correctly propagates into
// arguments.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
Future<int> test() => mk(new Future.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 60, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments[0].argumentExpression.staticType
@@ -1004,13 +1002,12 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_downwards4() async {
// Test that downwards inference interacts correctly with FutureOr
// parameters when the downwards context is FutureOr
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
FutureOr<int> test() => mk(new Future.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 60, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments[0].argumentExpression.staticType
@@ -1021,13 +1018,12 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_downwards5() async {
// Test that downwards inference correctly pins the type when it
// comes from a FutureOr
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
FutureOr<num> test() => mk(new Future.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 60, 4)],
);
''');
_isFutureOf([_isNum])(invoke.staticType as InterfaceType);
_isFutureOf([_isNum])(
invoke.argumentList.arguments[0].argumentExpression.staticType
@@ -1038,13 +1034,12 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_downwards6() async {
// Test that downwards inference doesn't decompose FutureOr
// when instantiating type variables.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
FutureOr<int> test() => mk(new Future.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 42, 4)],
);
''');
_isFutureOrOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments[0].argumentExpression.staticType
@@ -1055,13 +1050,12 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_downwards7() async {
// Test that downwards inference incorporates bounds correctly
// when instantiating type variables.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T extends Future<int>>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
FutureOr<int> test() => mk(new Future.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 64, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments[0].argumentExpression.staticType
@@ -1074,13 +1068,12 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
// when instantiating type variables.
// TODO(leafp): I think this should pass once the inference changes
// that jmesserly is adding are landed.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T extends Future<Object>>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
FutureOr<int> test() => mk(new Future.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 65, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
_isFutureOfInt(
invoke.argumentList.arguments[0].argumentExpression.staticType
@@ -1091,13 +1084,12 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_downwards9() async {
// Test that downwards inference decomposes correctly with
// other composite types
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
List<T> mk<T>(T x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'List<T>'.
FutureOr<List<int>> test() => mk(3);
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 48, 4)],
);
''');
_isListOf(_isInt)(invoke.staticType as InterfaceType);
_isInt(invoke.argumentList.arguments[0].argumentExpression.typeOrThrow);
}
@@ -1112,50 +1104,42 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_methods2() async {
// Test that FutureOr does not have the constituent type methods
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<int> x) => x.abs();
''',
expectedDiagnostics: [error(diag.undefinedMethod, 61, 3)],
);
// ^^^
// [diag.undefinedMethod] The method 'abs' isn't defined for the type 'FutureOr'.
''');
_isInvalidType(invoke.typeOrThrow);
}
test_futureOr_methods3() async {
// Test that FutureOr does not have the Future type methods
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<int> x) => x.then((x) => x);
''',
expectedDiagnostics: [error(diag.undefinedMethod, 61, 4)],
);
// ^^^^
// [diag.undefinedMethod] The method 'then' isn't defined for the type 'FutureOr'.
''');
_isInvalidType(invoke.typeOrThrow);
}
test_futureOr_methods4() async {
// Test that FutureOr<dynamic> does not have all methods
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
dynamic test(FutureOr<dynamic> x) => x.abs();
''',
expectedDiagnostics: [
error(diag.uncheckedMethodInvocationOfNullableValue, 65, 3),
],
);
// ^^^
// [diag.uncheckedMethodInvocationOfNullableValue] The method 'abs' can't be unconditionally invoked because the receiver can be 'null'.
''');
_isInvalidType(invoke.typeOrThrow);
}
test_futureOr_no_return() async {
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then((int x) {});
''',
expectedDiagnostics: [
error(diag.notInitializedNonNullableVariable, 79, 1),
],
);
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].argumentExpression.typeOrThrow,
);
@@ -1163,16 +1147,13 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
}
test_futureOr_no_return_value() async {
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then((int x) {return;});
''',
expectedDiagnostics: [
error(diag.notInitializedNonNullableVariable, 79, 1),
],
);
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].argumentExpression.typeOrThrow,
);
@@ -1180,16 +1161,13 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
}
test_futureOr_return_null() async {
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then((int x) {return null;});
''',
expectedDiagnostics: [
error(diag.notInitializedNonNullableVariable, 79, 1),
],
);
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].argumentExpression.typeOrThrow,
);
@@ -1199,40 +1177,35 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
test_futureOr_upwards1() async {
// Test that upwards inference correctly prefers to instantiate type
// variables with the "smaller" solution when both are possible.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
Future<T> mk<T>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'Future<T>'.
dynamic test() => mk(new Future<int>.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 60, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOr_upwards2() async {
// Test that upwards inference fails when the solution doesn't
// match the bound.
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
T mk<T extends Future<Object>>(FutureOr<T> x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'mk' because it has a return type of 'T'.
dynamic test() => mk(new Future<int>.value(42));
''',
expectedDiagnostics: [error(diag.returnOfInvalidTypeFromFunction, 75, 4)],
);
''');
_isFutureOfInt(invoke.staticType as InterfaceType);
}
test_futureOrNull_no_return() async {
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then<Null>((int x) {});
''',
expectedDiagnostics: [
error(diag.notInitializedNonNullableVariable, 79, 1),
],
);
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].argumentExpression.typeOrThrow,
);
@@ -1240,16 +1213,13 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
}
test_futureOrNull_no_return_value() async {
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then<Null>((int x) {return;});
''',
expectedDiagnostics: [
error(diag.notInitializedNonNullableVariable, 79, 1),
],
);
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].argumentExpression.typeOrThrow,
);
@@ -1257,16 +1227,13 @@ class StrongModeLocalInferenceTest extends PubPackageResolutionTest {
}
test_futureOrNull_return_null() async {
MethodInvocation invoke = await _testFutureOr(
r'''
MethodInvocation invoke = await _testFutureOr(r'''
FutureOr<T> mk<T>(Future<T> x) => x;
Future<int> f;
// ^
// [diag.notInitializedNonNullableVariable] The non-nullable variable 'f' must be initialized.
test() => f.then<Null>((int x) { return null;});
''',
expectedDiagnostics: [
error(diag.notInitializedNonNullableVariable, 79, 1),
],
);
''');
_isFunction2Of(_isInt, _isNull)(
invoke.argumentList.arguments[0].argumentExpression.typeOrThrow,
);
@@ -1355,20 +1322,21 @@ void test() {
}
test_inference_error_arguments() async {
var code = r'''
var result = await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T>(F<T, T> f) => (x) => f(f(x));
test() {
var h = g((int x) => 42.0);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'double' for 'T' which doesn't work:\n Parameter 'f' declared as 'T Function(T)'\n but argument is 'double Function(int)'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'double Function(int)' can't be assigned to the parameter type 'F<double, double>'.
}
''';
var result = await assertErrorsInCode(code, [
error(diag.unusedLocalVariable, 84, 1),
error(diag.couldNotInfer, 88, 1),
error(diag.argumentTypeNotAssignable, 90, 15),
]);
''');
_expectInferenceError(result, r'''
Couldn't infer type parameter 'T'.
@@ -1382,21 +1350,23 @@ Consider passing explicit type argument(s) to the generic.
}
test_inference_error_arguments2() async {
var code = r'''
var result = await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T>(F<T, T> a, F<T, T> b) => (x) => a(b(x));
test() {
var h = g((int x) => 42.0, (double x) => 42);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'num' for 'T' which doesn't work:\n Parameter 'a' declared as 'T Function(T)'\n but argument is 'double Function(int)'.\n Parameter 'b' declared as 'T Function(T)'\n but argument is 'int Function(double)'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'double Function(int)' can't be assigned to the parameter type 'F<num, num>'.
// ^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'int Function(double)' can't be assigned to the parameter type 'F<num, num>'.
}
''';
var result = await assertErrorsInCode(code, [
error(diag.unusedLocalVariable, 95, 1),
error(diag.couldNotInfer, 99, 1),
error(diag.argumentTypeNotAssignable, 101, 15),
error(diag.argumentTypeNotAssignable, 118, 16),
]);
''');
_expectInferenceError(result, r'''
Couldn't infer type parameter 'T'.
@@ -1490,20 +1460,21 @@ test(Iterable values) {
}
test_inference_error_returnContext() async {
var code = r'''
var result = await resolveTestCodeWithDiagnostics(r'''
typedef R F<T, R>(T t);
F<T, T> g<T>(T t) => (x) => t;
test() {
F<num, int> h = g(42);
// ^
// [diag.unusedLocalVariable] The value of the local variable 'h' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'num' for 'T' which doesn't work:\n Return type declared as 'T Function(T)'\n used where 'int Function(num)' is required.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^
// [diag.invalidAssignment] A value of type 'F<num, num>' can't be assigned to a variable of type 'F<num, int>'.
}
''';
var result = await assertErrorsInCode(code, [
error(diag.unusedLocalVariable, 80, 1),
error(diag.couldNotInfer, 84, 1),
error(diag.invalidAssignment, 84, 5),
]);
''');
_expectInferenceError(result, r'''
Couldn't infer type parameter 'T'.
@@ -3552,14 +3523,14 @@ class B<T2, U2> {
_isListOf(_isString)(exp.staticType as InterfaceType);
}
/// Verifies the result has [diag.couldNotInfer] with
/// Verifies the result has a `could_not_infer` diagnostic with
/// the expected [errorMessage].
void _expectInferenceError(
TestResolvedUnitResult result,
String errorMessage,
) {
var errors = result.diagnostics
.where((e) => e.diagnosticCode == diag.couldNotInfer)
.where((e) => e.diagnosticCode.lowerCaseUniqueName == 'could_not_infer')
.map((e) => e.message)
.toList();
expect(errors.length, 1);
@@ -3602,20 +3573,16 @@ class B<T2, U2> {
/// Helper method for testing `FutureOr<T>`.
///
/// Validates that [code] produces [expectedDiagnostics]. It should define a
/// function "test", whose body is an expression that invokes a method.
/// Returns that invocation.
Future<MethodInvocation> _testFutureOr(
String code, {
List<ExpectedDiagnostic> expectedDiagnostics = const [],
}) async {
/// Validates that [code] defines a function "test", whose body is an
/// expression that invokes a method. Returns that invocation.
Future<MethodInvocation> _testFutureOr(String code) async {
var fullCode =
"""
import "dart:async";
$code
""";
var result = await assertErrorsInCode(fullCode, expectedDiagnostics);
var result = await resolveTestCodeWithDiagnostics(fullCode);
FunctionDeclaration test = AstFinder.getTopLevelFunction(
result.unit,
@@ -5088,24 +5055,18 @@ class D extends C {}
test_instantiateToBounds_class_error_instantiation_malbounded() async {
// Test that instance creations are strictly checked for malbounded default
// types
var result = await assertErrorsInCode(
r'''
var result = await resolveTestCodeWithDiagnostics(r'''
class C<T0 extends List<T1>, T1 extends List<T0>> {}
void test() {
var c = new C();
// ^
// [diag.unusedLocalVariable] The value of the local variable 'c' isn't used.
// ^
// [context 1] The raw type was instantiated as 'C<List<Object?>, List<List<Object?>>>', and is not regular-bounded.
// [diag.couldNotInfer] Couldn't infer type parameter 'T0'.\n\nTried to infer 'List<Object?>' for 'T0' which doesn't work:\n Type parameter 'T0' is declared to extend 'List<T1>' producing 'List<List<List<Object?>>>'.\n\nConsider passing explicit type argument(s) to the generic.
// [diag.typeArgumentNotMatchingBounds][context 1] 'List<Object?>' doesn't conform to the bound 'List<List<List<Object?>>>' of the type parameter 'T0'.
}
''',
[
error(diag.unusedLocalVariable, 73, 1),
error(diag.couldNotInfer, 81, 1),
error(
diag.typeArgumentNotMatchingBounds,
81,
1,
contextMessages: [message(testFile, 81, 1)],
),
],
);
''');
_assertLocalVarType(result, 'c', 'C<List<Object?>, List<List<Object?>>>');
}
@@ -5238,20 +5199,19 @@ void main() {
test_instantiateToBounds_generic_function_error_malbounded() async {
// Test that generic methods are strictly checked for malbounded default
// types
var result = await assertErrorsInCode(
r'''
var result = await resolveTestCodeWithDiagnostics(r'''
T0 f<T0 extends List<T1>, T1 extends List<T0>>() {}
// ^
// [diag.bodyMightCompleteNormally] The body might complete normally, causing 'null' to be returned, but the return type, 'T0', is a potentially non-nullable type.
void g() {
var c = f();
// ^
// [diag.unusedLocalVariable] The value of the local variable 'c' isn't used.
// ^
// [diag.couldNotInfer] Couldn't infer type parameter 'T0'.\n\nTried to infer 'List<Object?>' for 'T0' which doesn't work:\n Type parameter 'T0' is declared to extend 'List<T1>' producing 'List<List<List<Object?>>>'.\n\nConsider passing explicit type argument(s) to the generic.
return;
}
''',
[
error(diag.bodyMightCompleteNormally, 3, 1),
error(diag.unusedLocalVariable, 69, 1),
error(diag.couldNotInfer, 73, 1),
],
);
''');
_assertLocalVarType(result, 'c', 'List<Object?>');
}
@@ -5419,19 +5379,30 @@ class C<E> {
}
test_objectMethodOnFunctions_Anonymous() async {
await _objectMethodOnFunctions_helper2(
r'''
await _objectMethodOnFunctions_helper2(r'''
void main() {
var f = (x) => 3;
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// Cascades, no errors
f..toString();
@@ -5443,81 +5414,99 @@ void main() {
(f)..toString;
(f)..hashCode;
}
''',
[
error(diag.unusedLocalVariable, 69, 2),
error(diag.unusedLocalVariable, 94, 2),
error(diag.unusedLocalVariable, 117, 2),
error(diag.unusedLocalVariable, 183, 2),
error(diag.unusedLocalVariable, 210, 2),
error(diag.unusedLocalVariable, 235, 2),
],
);
''');
}
test_objectMethodOnFunctions_Function() async {
await _objectMethodOnFunctions_helper2(
r'''
await _objectMethodOnFunctions_helper2(r'''
void main() {
Function f;
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Cascades, no errors
f..toString();
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..toString;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..hashCode;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expression cascades, no errors
(f)..toString();
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..toString;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..hashCode;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
}
''',
[
error(diag.unusedLocalVariable, 63, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 68, 1),
error(diag.unusedLocalVariable, 88, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 93, 1),
error(diag.unusedLocalVariable, 111, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 116, 1),
error(diag.unusedLocalVariable, 177, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 183, 1),
error(diag.unusedLocalVariable, 204, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 210, 1),
error(diag.unusedLocalVariable, 229, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 235, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 276, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 293, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 308, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 361, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 380, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 397, 1),
],
);
''');
}
test_objectMethodOnFunctions_Static() async {
await _objectMethodOnFunctions_helper2(
r'''
await _objectMethodOnFunctions_helper2(r'''
int f(int x) => null;
// ^^^^
// [diag.returnOfInvalidTypeFromFunction] A value of type 'Null' can't be returned from the function 'f' because it has a return type of 'int'.
void main() {
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// Cascades, no errors
f..toString();
@@ -5529,68 +5518,72 @@ void main() {
(f)..toString;
(f)..hashCode;
}
''',
[
error(diag.returnOfInvalidTypeFromFunction, 16, 4),
error(diag.unusedLocalVariable, 71, 2),
error(diag.unusedLocalVariable, 96, 2),
error(diag.unusedLocalVariable, 119, 2),
error(diag.unusedLocalVariable, 185, 2),
error(diag.unusedLocalVariable, 212, 2),
error(diag.unusedLocalVariable, 237, 2),
],
);
''');
}
test_objectMethodOnFunctions_Typedef() async {
await _objectMethodOnFunctions_helper2(
r'''
await _objectMethodOnFunctions_helper2(r'''
typedef bool Predicate<T>(T object);
void main() {
Predicate<int> f;
// No errors, correct type
var t0 = f.toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't0' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t1 = f.toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't1' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t2 = f.hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't2' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expressions, no errors, correct type
var t3 = (f).toString();
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't3' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t4 = (f).toString;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't4' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
var t5 = (f).hashCode;
// ^^
// [diag.unusedLocalVariable] The value of the local variable 't5' isn't used.
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Cascades, no errors
f..toString();
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..toString;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
f..hashCode;
//^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
// Expression cascades, no errors
(f)..toString();
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..toString;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
(f)..hashCode;
// ^
// [diag.notAssignedPotentiallyNonNullableLocalVariable] The non-nullable local variable 'f' must be assigned before it can be used.
}
''',
[
error(diag.unusedLocalVariable, 107, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 112, 1),
error(diag.unusedLocalVariable, 132, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 137, 1),
error(diag.unusedLocalVariable, 155, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 160, 1),
error(diag.unusedLocalVariable, 221, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 227, 1),
error(diag.unusedLocalVariable, 248, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 254, 1),
error(diag.unusedLocalVariable, 273, 2),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 279, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 320, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 337, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 352, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 405, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 424, 1),
error(diag.notAssignedPotentiallyNonNullableLocalVariable, 441, 1),
],
);
''');
}
test_returnOfInvalidType_object_void() async {
@@ -5706,11 +5699,8 @@ main() {
assertType(element.type, expectedType);
}
Future<void> _objectMethodOnFunctions_helper2(
String code,
List<ExpectedDiagnostic> expectedDiagnostics,
) async {
var result = await assertErrorsInCode(code, expectedDiagnostics);
Future<void> _objectMethodOnFunctions_helper2(String code) async {
var result = await resolveTestCodeWithDiagnostics(code);
_assertLocalVarType(result, 't0', "String");
_assertLocalVarType(result, 't1', "String Function()");
_assertLocalVarType(result, 't2', "int");
@@ -4,8 +4,6 @@
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer_testing/analysis_rule/analysis_rule.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -7688,19 +7686,18 @@ void main() {
''');
}
@FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/55467')
test_listLiteral_expression_nonConstant() async {
await assertErrorsInCode(
'''
// TODO(scheglov): https://github.com/dart-lang/sdk/issues/55467
await resolveTestCodeWithDiagnostics('''
var b = 7;
var x = const A([b]);
// ^
// [diag.invalidConstant] Invalid constant value.
class A {
const A(List<int> p);
}
''',
[error(diag.nonConstantListElement, 28, 1)],
);
''');
}
test_redirectingConstructor_typeParameter() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'context_collection_resolution.dart';
@@ -80,8 +79,7 @@ InstanceCreationExpression
}
test_inference_inout_parameter() async {
var result = await assertErrorsInCode(
'''
var result = await resolveTestCodeWithDiagnostics(r'''
class Invariant<inout T> {}
class Exactly<inout T> {}
@@ -90,14 +88,14 @@ Exactly<T> inferInvInv<T>(Invariant<T> x, Invariant<T> y) => new Exactly<T>();
main() {
inferInvInv(Invariant<String>(), Invariant<int>());
//^^^^^^^^^^^
// [diag.couldNotInfer] Couldn't infer type parameter 'T'.\n\nTried to infer 'Object' for 'T' which doesn't work:\n Parameter 'x' declared as 'Invariant<T>'\n but argument is 'Invariant<String>'.\n Parameter 'y' declared as 'Invariant<T>'\n but argument is 'Invariant<int>'.\n\nConsider passing explicit type argument(s) to the generic.
// ^^^^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Invariant<String>' can't be assigned to the parameter type 'Invariant<Object>'.
// ^^^^^^^^^^^^^^^^
// [diag.argumentTypeNotAssignable] The argument type 'Invariant<int>' can't be assigned to the parameter type 'Invariant<Object>'.
}
''',
[
error(diag.couldNotInfer, 147, 11),
error(diag.argumentTypeNotAssignable, 159, 19),
error(diag.argumentTypeNotAssignable, 180, 16),
],
);
''');
var node = result.findNode.methodInvocation('inferInvInv(');
nodeTextConfiguration.skipArgumentList = true;
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -175,34 +174,31 @@ void f() {
}
test_method_conflict_conflict_notSpecific_sameName() async {
var one = newFile('$testPackageLibPath/one.dart', '''
var one = getFile('$testPackageLibPath/one.dart');
var two = getFile('$testPackageLibPath/two.dart');
await resolveFilesWithDiagnostics({
one: '''
extension E on int { void foo() {} }
''');
var two = newFile('$testPackageLibPath/two.dart', '''
// ^
// [context 1] E is defined in /home/test/lib/one.dart
''',
two: '''
extension E on int { void foo() {} }
''');
await assertErrorsInCode(
'''
// ^
// [context 2] E is defined in /home/test/lib/two.dart
''',
testFile: '''
// ignore_for_file: unused_import
import 'one.dart';
import 'two.dart';
void f() {
0.foo();
// ^^^
// [diag.ambiguousExtensionMemberAccessTwo][context 1][context 2] A member named 'foo' is defined in 'extension E on int (where E is defined in /home/test/lib/one.dart)' and 'extension E on int (where E is defined in /home/test/lib/two.dart)', and neither is more specific.
}
''',
[
error(
diag.ambiguousExtensionMemberAccessTwo,
87,
3,
messageContains: [
"'extension E on int (where E is defined in ${one.path})' and "
"'extension E on int (where E is defined in ${two.path})',",
],
contextMessages: [message(one, 10, 1), message(two, 10, 1)],
),
],
);
});
}
test_method_conflict_conflict_notSpecific_sameName_invalidType() async {
@@ -334,34 +330,36 @@ void f() {
}
test_method_triple_conflict_sameName() async {
var one = newFile('$testPackageLibPath/one.dart', '''
var one = getFile('$testPackageLibPath/one.dart');
var two = getFile('$testPackageLibPath/two.dart');
var three = getFile('$testPackageLibPath/three.dart');
await resolveFilesWithDiagnostics({
one: '''
extension E on int { void foo() {} }
''');
var two = newFile('$testPackageLibPath/two.dart', '''
// ^
// [context 1] E is defined in /home/test/lib/one.dart
''',
two: '''
extension E on int { void foo() {} }
''');
newFile('$testPackageLibPath/three.dart', '''
// ^
// [context 2] E is defined in /home/test/lib/two.dart
''',
three: '''
extension E1 on int { void foo() {} }
''');
await assertErrorsInCode(
'''
''',
testFile: '''
// ignore_for_file: unused_import
import 'one.dart';
import 'two.dart';
import 'three.dart';
void f() {
0.foo();
// ^^^
// [diag.ambiguousExtensionMemberAccessThreeOrMore][context 1][context 2] A member named 'foo' is defined in extension 'E', extension 'E', and extension 'E1', and none are more specific.
}
''',
[
error(
diag.ambiguousExtensionMemberAccessThreeOrMore,
108,
3,
contextMessages: [message(one, 10, 1), message(two, 10, 1)],
),
],
);
});
}
test_noMoreSpecificExtension() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -283,19 +282,18 @@ class A {
''');
}
@FailingTest(reason: 'Not yet implemented')
@SkippedTest() // TODO(scheglov): Not yet implemented.
test_topLevelVariable_asExpression() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
import 'package:meta/meta.dart';
final f = v as Object;
// ^
// [diag.assignmentOfDoNotStore] 'v' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable.
@doNotStore
String get v => '';
''',
[error(diag.assignmentOfDoNotStore, 44, 1)],
);
''');
}
test_topLevelVariable_assignment_field() async {
@@ -369,19 +367,18 @@ class A {
''');
}
@FailingTest(reason: 'Not yet implemented')
@SkippedTest() // TODO(scheglov): Not yet implemented.
test_topLevelVariable_cascadeExpression_target() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
import 'package:meta/meta.dart';
final f = v..runtimeType;
// ^
// [diag.assignmentOfDoNotStore] 'v' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable.
@doNotStore
String get v => '';
''',
[error(diag.assignmentOfDoNotStore, 44, 1)],
);
''');
}
test_topLevelVariable_conditionalExpression() async {
@@ -401,21 +398,20 @@ String get v => '';
''');
}
@FailingTest(reason: 'Not yet implemented')
@SkippedTest() // TODO(scheglov): Not yet implemented.
test_topLevelVariable_dotShorthandPropertyAccess() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
import 'package:meta/meta.dart';
final A f = .v;
// ^
// [diag.assignmentOfDoNotStore] 'v' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable.
class A {
@doNotStore
static A get v => A();
}
''',
[error(diag.assignmentOfDoNotStore, 47, 1)],
);
''');
}
test_topLevelVariable_forElement() async {
@@ -531,19 +527,18 @@ String get v => '';
''');
}
@FailingTest(reason: 'Not yet implemented')
@SkippedTest() // TODO(scheglov): Not yet implemented.
test_topLevelVariable_nullAssert() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
import 'package:meta/meta.dart';
final f = v!;
// ^
// [diag.assignmentOfDoNotStore] 'v' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable.
@doNotStore
String? get v => '';
''',
[error(diag.assignmentOfDoNotStore, 44, 1)],
);
''');
}
test_topLevelVariable_nullAwareElement() async {
@@ -612,22 +607,21 @@ List<String> get v => [];
''');
}
@FailingTest(reason: 'Not yet implemented')
@SkippedTest() // TODO(scheglov): Not yet implemented.
test_topLevelVariable_switchExpression_caseBody() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
import 'package:meta/meta.dart';
final f = switch (1 == 2) {
true => v,
// ^
// [diag.assignmentOfDoNotStore] 'v' is marked 'doNotStore' and shouldn't be assigned to a field or top-level variable.
false => '',
};
@doNotStore
String? get v => '';
''',
[error(diag.assignmentOfDoNotStore, 72, 1)],
);
''');
}
test_topLevelVariable_switchExpression_condition() async {
@@ -2,8 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer_testing/analysis_rule/analysis_rule.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -40,71 +38,43 @@ base class Bar implements Foo {}
}
test_class_outside_sealed() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
base class A {}
''');
var a = getFile('$testPackageLibPath/a.dart');
await assertErrorsInCode(
r'''
await resolveFilesWithDiagnostics({
a: r'''
base class A {}
// ^
// [context 1] The type 'B' is a subtype of 'A', and 'A' is defined here.
''',
testFile: r'''
import 'a.dart';
sealed class B extends A {}
base class C implements B {}
// ^
// [diag.baseClassImplementedOutsideOfLibrary][context 1] The class 'A' can't be implemented outside of its library because it's a base class.
''',
[
this.error(
diag.baseClassImplementedOutsideOfLibrary,
69,
1,
text:
"The class 'A' can't be implemented outside of its library because it's a base class.",
contextMessages: [
contextMessage(
a,
11,
1,
textContains: [
"The type 'B' is a subtype of 'A', and 'A' is defined here.",
],
),
],
),
],
);
});
}
test_class_outside_sealed_noBase() async {
// Instead of emitting [SUBTYPE_OF_BASE_IS_NOT_BASE_FINAL_OR_SEALED], we
// tell the user that they can't implement an indirect base supertype.
var a = newFile('$testPackageLibPath/a.dart', r'''
base class A {}
''');
var a = getFile('$testPackageLibPath/a.dart');
await assertErrorsInCode(
r'''
await resolveFilesWithDiagnostics({
a: r'''
base class A {}
// ^
// [context 1] The type 'B' is a subtype of 'A', and 'A' is defined here.
''',
testFile: r'''
import 'a.dart';
sealed class B extends A {}
class C implements B {}
// ^
// [diag.baseClassImplementedOutsideOfLibrary][context 1] The class 'A' can't be implemented outside of its library because it's a base class.
''',
[
this.error(
diag.baseClassImplementedOutsideOfLibrary,
64,
1,
text:
"The class 'A' can't be implemented outside of its library because it's a base class.",
contextMessages: [
contextMessage(
a,
11,
1,
textContains: [
"The type 'B' is a subtype of 'A', and 'A' is defined here.",
],
),
],
),
],
);
});
}
test_class_outside_viaExtends() async {
@@ -159,37 +129,23 @@ base class C = Object with M implements B;
}
test_classTypeAlias_outside() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
base class A {}
''');
var a = getFile('$testPackageLibPath/a.dart');
await assertErrorsInCode(
r'''
await resolveFilesWithDiagnostics({
a: r'''
base class A {}
// ^
// [context 1] The type 'B' is a subtype of 'A', and 'A' is defined here.
''',
testFile: r'''
import 'a.dart';
sealed class B extends A {}
mixin M {}
base class C = Object with M implements B;
// ^
// [diag.baseClassImplementedOutsideOfLibrary][context 1] The class 'A' can't be implemented outside of its library because it's a base class.
''',
[
this.error(
diag.baseClassImplementedOutsideOfLibrary,
96,
1,
text:
"The class 'A' can't be implemented outside of its library because it's a base class.",
contextMessages: [
contextMessage(
a,
11,
1,
textContains: [
"The type 'B' is a subtype of 'A', and 'A' is defined here.",
],
),
],
),
],
);
});
}
test_enum_inside() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -39,26 +38,23 @@ base class Bar implements Foo {}
}
test_class_outside_viaExtends() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
base mixin A {}
''');
var a = getFile('$testPackageLibPath/a.dart');
await assertErrorsInCode(
r'''
await resolveFilesWithDiagnostics({
a: r'''
base mixin A {}
// ^
// [context 1] The type 'B' is a subtype of 'A', and 'A' is defined here.
''',
testFile: r'''
import 'a.dart';
sealed class B extends Object with A {}
class C implements B {}
// ^
// [diag.baseMixinImplementedOutsideOfLibrary][context 1] The mixin 'A' can't be implemented outside of its library because it's a base mixin.
''',
[
error(
diag.baseMixinImplementedOutsideOfLibrary,
77,
1,
contextMessages: [message(a, 11, 1)],
),
],
);
});
}
test_class_outside_viaTypedef_inside() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -52,27 +51,39 @@ enum E {
}
test_enum_method_nonNullable_blockBody_switchStatement_notNullable_notExhaustive() async {
await assertErrorsInCode(
r'''
if (_arePatternsEnabled) {
await resolveTestCodeWithDiagnostics(r'''
enum E {
a, b;
int get value {
switch (this) {
// ^^^^^^
// [diag.nonExhaustiveSwitchStatement] The type 'E' isn't exhaustively matched by the switch cases since it doesn't match the pattern 'E.b'.
case a:
return 0;
}
}
}
''',
[
if (!_arePatternsEnabled) ...[
error(diag.bodyMightCompleteNormally, 28, 5),
error(diag.missingEnumConstantInSwitch, 40, 13),
] else
error(diag.nonExhaustiveSwitchStatement, 40, 6),
],
);
''');
} else {
await resolveTestCodeWithDiagnostics(r'''
enum E {
a, b;
int get value {
// ^^^^^
// [diag.bodyMightCompleteNormally] The body might complete normally, causing 'null' to be returned, but the return type, 'int', is a potentially non-nullable type.
switch (this) {
// ^^^^^^^^^^^^^
// [diag.missingEnumConstantInSwitch] Missing case clause for 'b'.
case a:
return 0;
}
}
}
''');
}
}
test_factoryConstructor_named_blockBody() async {
@@ -188,30 +199,40 @@ int f(Foo foo) {
}
test_function_nonNullable_blockBody_switchStatement_notNullable_notExhaustive() async {
await assertErrorsInCode(
r'''
if (_arePatternsEnabled) {
await resolveTestCodeWithDiagnostics(r'''
enum Foo { a, b }
int f(Foo foo) {
switch (foo) {
//^^^^^^
// [diag.nonExhaustiveSwitchStatement] The type 'Foo' isn't exhaustively matched by the switch cases since it doesn't match the pattern 'Foo.b'.
case Foo.a:
return 0;
}
}
''',
[
if (!_arePatternsEnabled) ...[
error(diag.bodyMightCompleteNormally, 23, 1),
error(diag.missingEnumConstantInSwitch, 38, 12),
] else
error(diag.nonExhaustiveSwitchStatement, 38, 6),
],
);
''');
} else {
await resolveTestCodeWithDiagnostics(r'''
enum Foo { a, b }
int f(Foo foo) {
// ^
// [diag.bodyMightCompleteNormally] The body might complete normally, causing 'null' to be returned, but the return type, 'int', is a potentially non-nullable type.
switch (foo) {
//^^^^^^^^^^^^
// [diag.missingEnumConstantInSwitch] Missing case clause for 'b'.
case Foo.a:
return 0;
}
}
''');
}
}
test_function_nonNullable_blockBody_switchStatement_notNullable_notExhaustive_enhanced() async {
await assertErrorsInCode(
r'''
if (_arePatternsEnabled) {
await resolveTestCodeWithDiagnostics(r'''
enum E {
a, b;
@@ -220,19 +241,33 @@ enum E {
int f(E e) {
switch (e) {
//^^^^^^
// [diag.nonExhaustiveSwitchStatement] The type 'E' isn't exhaustively matched by the switch cases since it doesn't match the pattern 'E.b'.
case E.a:
return 0;
}
}
''',
[
if (!_arePatternsEnabled) ...[
error(diag.bodyMightCompleteNormally, 47, 1),
error(diag.missingEnumConstantInSwitch, 58, 10),
] else
error(diag.nonExhaustiveSwitchStatement, 58, 6),
],
);
''');
} else {
await resolveTestCodeWithDiagnostics(r'''
enum E {
a, b;
static const c = 0;
}
int f(E e) {
// ^
// [diag.bodyMightCompleteNormally] The body might complete normally, causing 'null' to be returned, but the return type, 'int', is a potentially non-nullable type.
switch (e) {
//^^^^^^^^^^
// [diag.missingEnumConstantInSwitch] Missing case clause for 'b'.
case E.a:
return 0;
}
}
''');
}
}
test_function_nonNullable_blockBody_switchStatement_nullable_exhaustive_default() async {
@@ -270,27 +305,39 @@ int f(Foo? foo) {
}
test_function_nonNullable_blockBody_switchStatement_nullable_notExhaustive_null() async {
await assertErrorsInCode(
r'''
if (_arePatternsEnabled) {
await resolveTestCodeWithDiagnostics(r'''
enum Foo { a, b }
int f(Foo? foo) {
switch (foo) {
//^^^^^^
// [diag.nonExhaustiveSwitchStatement] The type 'Foo?' isn't exhaustively matched by the switch cases since it doesn't match the pattern 'null'.
case Foo.a:
return 0;
case Foo.b:
return 1;
}
}
''',
[
if (!_arePatternsEnabled) ...[
error(diag.bodyMightCompleteNormally, 23, 1),
error(diag.missingEnumConstantInSwitch, 39, 12),
] else
error(diag.nonExhaustiveSwitchStatement, 39, 6),
],
);
''');
} else {
await resolveTestCodeWithDiagnostics(r'''
enum Foo { a, b }
int f(Foo? foo) {
// ^
// [diag.bodyMightCompleteNormally] The body might complete normally, causing 'null' to be returned, but the return type, 'int', is a potentially non-nullable type.
switch (foo) {
//^^^^^^^^^^^^
// [diag.missingEnumConstantInSwitch] Missing case clause for 'null'.
case Foo.a:
return 0;
case Foo.b:
return 1;
}
}
''');
}
}
test_function_nullable_blockBody() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -29,20 +28,18 @@ class C {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_inClass_instanceMethod_staticMethodInAugmentation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
class A {
void foo() {}
}
augment class A {
static void foo() {}
// ^^^
// [diag.conflictingStaticAndInstance] Class 'A' can't define static member 'foo' and have instance member 'A.foo' with the same name.
}
''',
[error(diag.conflictingStaticAndInstance, 61, 3)],
);
''');
}
test_inClass_staticGetter_instanceGetter() async {
@@ -100,20 +97,18 @@ class C {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_inClass_staticMethod_instanceMethodInAugmentation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
class A {
static void foo() {}
// ^^^
// [diag.conflictingStaticAndInstance] Class 'A' can't define static member 'foo' and have instance member 'A.foo' with the same name.
}
augment class A {
void foo() {}
}
''',
[error(diag.conflictingStaticAndInstance, 24, 3)],
);
''');
}
test_inClass_staticMethod_instanceSetter() async {
@@ -290,20 +285,18 @@ class B extends Object with M {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_inMixin_instanceMethod_staticMethodInAugmentation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
mixin A {
void foo() {}
}
augment mixin A {
static void foo() {}
// ^^^
// [diag.conflictingStaticAndInstance] Class 'A' can't define static member 'foo' and have instance member 'A.foo' with the same name.
}
''',
[error(diag.conflictingStaticAndInstance, 61, 3)],
);
''');
}
test_inMixin_instanceMethod_staticSetter() async {
@@ -358,20 +351,18 @@ class B extends Object with A {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_inMixin_staticMethod_instanceMethodInAugmentation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
mixin A {
static void foo() {}
// ^^^
// [diag.conflictingStaticAndInstance] Class 'A' can't define static member 'foo' and have instance member 'A.foo' with the same name.
}
augment mixin A {
void foo() {}
}
''',
[error(diag.conflictingStaticAndInstance, 24, 3)],
);
''');
}
test_inSuper_implicitObject_staticMethod_instanceGetter() async {
@@ -2,8 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer_testing/analysis_rule/analysis_rule.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -34,35 +32,27 @@ const C b = C(false || a.x);
}
test_constructorFieldInitializer_fromSeparateLibrary() async {
var lib = newFile('$testPackageLibPath/lib.dart', r'''
var lib = getFile('$testPackageLibPath/lib.dart');
await resolveFilesWithDiagnostics({
lib: r'''
class A<T> {
final int f;
const A() : f = T.foo;
// ^^^^^
// [context 1] The error is in the field initializer of 'A', and occurs here.
// [diag.invalidConstant] Invalid constant value.
// ^^^
// [diag.undefinedGetter] The getter 'foo' isn't defined for the type 'Type'.
}
''');
await assertErrorsInCode(
r'''
''',
testFile: r'''
import 'lib.dart';
const a = const A();
// ^^^^^^^^^
// [diag.constEvalPropertyAccess][context 1] The property 'foo' can't be accessed on the type 'Type' in a constant expression.
''',
[
error(
diag.constEvalPropertyAccess,
29,
9,
contextMessages: [
contextMessage(
lib,
46,
5,
textContains: [
"The error is in the field initializer of 'A', and occurs here.",
],
),
],
),
],
);
});
}
test_length_dynamic_notNull() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -945,29 +944,22 @@ class B implements A {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_method_returnType_interface_fromAugmentation() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
class A {
int foo() => 0;
// ^^^
// [context 1] The member being overridden.
}
class B {
String foo() => '';
// ^^^
// [diag.invalidOverride][context 1] 'B.foo' ('String Function()') isn't a valid override of 'A.foo' ('int Function()').
}
augment class B implements A {}
''',
[
error(
diag.invalidOverride,
50,
3,
contextMessages: [message(testFile, 16, 3)],
),
],
);
''');
}
test_method_returnType_interface_grandparent() async {
@@ -1017,29 +1009,22 @@ class B extends A {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_method_returnType_superclass_fromAugmentation() async {
await assertErrorsInCode(
'''
await resolveTestCodeWithDiagnostics('''
class A {
int foo() => 0;
// ^^^
// [context 1] The member being overridden.
}
class B {
String foo() => '';
// ^^^
// [diag.invalidOverride][context 1] 'B.foo' ('String Function()') isn't a valid override of 'A.foo' ('int Function()').
}
augment class B extends A {}
''',
[
error(
diag.invalidOverride,
50,
3,
contextMessages: [message(testFile, 16, 3)],
),
],
);
''');
}
test_method_returnType_superclass_grandparent() async {
@@ -1143,29 +1128,22 @@ mixin M on A {
''');
}
@SkippedTest() // TODO(scheglov): implement augmentation
test_mixin_method_returnType_on_fromAugmentation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
class A {
int foo() => 0;
// ^^^
// [context 1] The member being overridden.
}
mixin M {
String foo() => '';
// ^^^
// [diag.invalidOverride][context 1] 'M.foo' ('String Function()') isn't a valid override of 'A.foo' ('int Function()').
}
augment mixin M on A {}
''',
[
error(
diag.invalidOverride,
50,
3,
contextMessages: [message(testFile, 16, 3)],
),
],
);
''');
}
test_mixin_setter_type_on() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -18,20 +17,17 @@ main() {
@reflectiveTest
class NonConstantListElementFromDeferredLibraryTest
extends PubPackageResolutionTest {
@failingTest
test_const_ifElement_thenTrue_deferredElse() async {
// reports wrong error code (which is not crucial to fix)
newFile('$testPackageLibPath/lib1.dart', r'''
const int c = 1;
''');
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
import 'lib1.dart' deferred as a;
const cond = true;
var v = const [ if (cond) 'a' else a.c ];
''',
[error(diag.nonConstantListElementFromDeferredLibrary, 0, 0)],
);
// ^^^
// [diag.nonConstantListElement] The values in a const list literal must be constants.
''');
}
test_const_ifElement_thenTrue_deferredThen() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -18,19 +17,16 @@ main() {
@reflectiveTest
class NonConstantMapKeyFromDeferredLibraryTest
extends PubPackageResolutionTest {
@failingTest
test_const_ifElement_thenTrue_deferredElse() async {
// reports wrong error code
newFile('$testPackageLibPath/lib1.dart', r'''
const int c = 1;''');
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
import 'lib1.dart' deferred as a;
const cond = true;
var v = const { if (cond) 0: 1 else a.c : 0};
''',
[error(diag.nonConstantMapKeyFromDeferredLibrary, 0, 0)],
);
// ^^^
// [diag.nonConstantMapKey] The keys in a const map literal must be constant.
''');
}
test_const_ifElement_thenTrue_deferredThen() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -18,19 +17,16 @@ main() {
@reflectiveTest
class NonConstantMapValueFromDeferredLibraryTest
extends PubPackageResolutionTest {
@failingTest
test_const_ifElement_thenTrue_elseDeferred() async {
// reports wrong error code
newFile('$testPackageLibPath/lib1.dart', r'''
const int c = 1;''');
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
import 'lib1.dart' deferred as a;
const cond = true;
var v = const { if (cond) 'a': 'b' else 'c' : a.c};
''',
[error(diag.nonConstantMapValueFromDeferredLibrary, 99, 3)],
);
// ^^^
// [diag.nonConstantMapValue] The values in a const map literal must be constant.
''');
}
test_const_ifElement_thenTrue_thenDeferred() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -105,26 +104,24 @@ class foo {}
}
test_part_topLevelFunction_inLibrary() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
var a = getFile('$testPackageLibPath/a.dart');
await resolveFilesWithDiagnostics({
a: r'''
part 'test.dart';
void foo() {}
''');
await assertErrorsInCode(
r'''
// ^^^
// [context 1] The first definition of this name.
''',
testFile: r'''
part of 'a.dart';
import 'dart:math' as foo;
// ^^^^^^^^^^^
// [diag.unusedImport] Unused import: 'dart:math'.
// ^^^
// [diag.prefixCollidesWithTopLevelMember][context 1] The name 'foo' is already used as an import prefix and can't be used to name a top-level element.
''',
[
error(diag.unusedImport, 25, 11),
error(
diag.prefixCollidesWithTopLevelMember,
40,
3,
contextMessages: [message(a, 23, 3)],
),
],
);
});
}
test_part_topLevelFunction_inPart() async {
@@ -146,30 +143,28 @@ void foo() {}
}
test_part_topLevelFunction_inPart2() async {
newFile('$testPackageLibPath/a.dart', r'''
var a = getFile('$testPackageLibPath/a.dart');
var b = getFile('$testPackageLibPath/b.dart');
await resolveFilesWithDiagnostics({
a: r'''
part 'test.dart';
part 'b.dart';
''');
var b = newFile('$testPackageLibPath/b.dart', r'''
''',
b: r'''
part of 'a.dart';
void foo() {}
''');
await assertErrorsInCode(
r'''
// ^^^
// [context 1] The first definition of this name.
''',
testFile: r'''
part of 'a.dart';
import 'dart:math' as foo;
// ^^^^^^^^^^^
// [diag.unusedImport] Unused import: 'dart:math'.
// ^^^
// [diag.prefixCollidesWithTopLevelMember][context 1] The name 'foo' is already used as an import prefix and can't be used to name a top-level element.
''',
[
error(diag.unusedImport, 25, 11),
error(
diag.prefixCollidesWithTopLevelMember,
40,
3,
contextMessages: [message(b, 23, 3)],
),
],
);
});
}
}
@@ -2,8 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer_testing/analysis_rule/analysis_rule.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -160,36 +158,21 @@ class D extends C {}
}
test_class_sealed_extends_outside() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
var a = getFile('$testPackageLibPath/a.dart');
await resolveFilesWithDiagnostics({
a: r'''
base class A {}
''');
await assertErrorsInCode(
r'''
// ^
// [context 1] The type 'B' is a subtype of 'A', and 'A' is defined here.
''',
testFile: r'''
import 'a.dart';
sealed class B extends A {}
class C extends B {}
// ^
// [diag.subtypeOfBaseIsNotBaseFinalOrSealed][context 1] The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.
''',
[
this.error(
diag.subtypeOfBaseIsNotBaseFinalOrSealed,
51,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
contextMessage(
a,
11,
1,
textContains: [
"The type 'B' is a subtype of 'A', and 'A' is defined here.",
],
),
],
),
],
);
});
}
test_class_sealed_extends_unordered() async {
@@ -275,36 +258,21 @@ class C extends B {}
}
test_mixinClass_sealed_outside() async {
var a = newFile('$testPackageLibPath/a.dart', r'''
var a = getFile('$testPackageLibPath/a.dart');
await resolveFilesWithDiagnostics({
a: r'''
base mixin class A {}
''');
await assertErrorsInCode(
r'''
// ^
// [context 1] The type 'B' is a subtype of 'A', and 'A' is defined here.
''',
testFile: r'''
import 'a.dart';
sealed class B with A {}
class C extends B {}
// ^
// [diag.subtypeOfBaseIsNotBaseFinalOrSealed][context 1] The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.
''',
[
this.error(
diag.subtypeOfBaseIsNotBaseFinalOrSealed,
48,
1,
text:
"The type 'C' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'base'.",
contextMessages: [
contextMessage(
a,
17,
1,
textContains: [
"The type 'B' is a subtype of 'A', and 'A' is defined here.",
],
),
],
),
],
);
});
}
test_mixinClass_with() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -29,27 +28,13 @@ class B extends A {}
@SkippedTest() // TODO(scheglov): implement augmentation
test_class_extends_inAugmentation() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
augment class B extend A {}
''');
await assertErrorsInCode(
r'''
part 'a.dart';
await resolveTestCodeWithDiagnostics(r'''
final class A {}
class B {}
''',
[
error(
diag.subtypeOfFinalIsNotBaseFinalOrSealed,
38,
1,
text:
"The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.",
),
],
);
// ^
// [diag.subtypeOfFinalIsNotBaseFinalOrSealed] The type 'B' must be 'base', 'final' or 'sealed' because the supertype 'A' is 'final'.
augment class B extends A {}
''');
}
test_class_extends_outside() async {
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -46,8 +45,8 @@ void f(int a) {
}
test_completes() async {
await assertErrorsInCode(
'''
if (_patternsEnabled) {
await resolveTestCodeWithDiagnostics(r'''
void f(int a) {
switch (a) {
case 0:
@@ -55,9 +54,20 @@ void f(int a) {
default:
return;
}
}''',
[if (!_patternsEnabled) error(diag.switchCaseCompletesNormally, 35, 4)],
);
}''');
} else {
await resolveTestCodeWithDiagnostics(r'''
void f(int a) {
switch (a) {
case 0:
// ^^^^
// [diag.switchCaseCompletesNormally] The 'case' shouldn't complete normally.
print(0);
default:
return;
}
}''');
}
}
test_continue_loop() async {
@@ -119,8 +129,8 @@ Never neverCompletes() {
}
test_multiple_cases_sharing_a_body() async {
await assertErrorsInCode(
'''
if (_patternsEnabled) {
await resolveTestCodeWithDiagnostics(r'''
void f(int a) {
switch (a) {
case 0:
@@ -129,9 +139,21 @@ void f(int a) {
default:
return;
}
}''',
[if (!_patternsEnabled) error(diag.switchCaseCompletesNormally, 35, 4)],
);
}''');
} else {
await resolveTestCodeWithDiagnostics(r'''
void f(int a) {
switch (a) {
case 0:
// ^^^^
// [diag.switchCaseCompletesNormally] The 'case' shouldn't complete normally.
case 1:
print(0);
default:
return;
}
}''');
}
}
test_return() async {
+35 -139
View File
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -73,76 +72,56 @@ TODO: Implement2
}
test_todo_multiLineCommentWrapped() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
/* TODO(a): Implement something
// [diag.todo][column 6][length 64] TODO(a): Implement something that is too long for one line
* that is too long for one line
* This line is not part of the todo
*/
/* TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
* that is too long for one line
* This line is not part of the todo
*/
/* TODO(a): Implement something
// [diag.todo][column 6][length 64] TODO(a): Implement something that is too long for one line
* that is too long for one line
*
* This line is not part of the todo
*/
/* TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
* that is too long for one line
*
* This line is not part of the todo
*/
*/
}
''',
[
error(
diag.todo,
14,
64,
text: 'TODO(a): Implement something that is too long for one line',
),
error(
diag.todo,
129,
61,
text: 'TODO: Implement something that is too long for one line',
),
error(
diag.todo,
241,
64,
text: 'TODO(a): Implement something that is too long for one line',
),
error(
diag.todo,
362,
61,
text: 'TODO: Implement something that is too long for one line',
),
],
);
''');
}
test_todo_multiLineCommentWrapped_windows_line_endings() async {
await assertErrorsInCode(
await resolveTestCodeWithDiagnostics(
r'''
main() {
/* TODO(a): Implement something
// [diag.todo][column 6][length 65] TODO(a): Implement something that is too long for one line
* that is too long for one line
* This line is not part of the todo
*/
/* TODO: Implement something
// [diag.todo][column 6][length 62] TODO: Implement something that is too long for one line
* that is too long for one line
* This line is not part of the todo
*/
/* TODO(a): Implement something
// [diag.todo][column 6][length 65] TODO(a): Implement something that is too long for one line
* that is too long for one line
*
* This line is not part of the todo
*/
/* TODO: Implement something
// [diag.todo][column 6][length 62] TODO: Implement something that is too long for one line
* that is too long for one line
*
* This line is not part of the todo
@@ -151,32 +130,6 @@ main() {
'''
.split("\n")
.join("\r\n"),
[
error(
diag.todo,
15,
65,
text: 'TODO(a): Implement something that is too long for one line',
),
error(
diag.todo,
134,
62,
text: 'TODO: Implement something that is too long for one line',
),
error(
diag.todo,
250,
65,
text: 'TODO(a): Implement something that is too long for one line',
),
error(
diag.todo,
376,
62,
text: 'TODO: Implement something that is too long for one line',
),
],
);
}
@@ -193,32 +146,25 @@ main() {
test_todo_singleLineCommentDoubleCommented() async {
// Continuations are ignored for code that looks like commented comments
// although the original TODOs are still picked up.
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
// // TODO: Implement something
// [diag.todo][column 12][length 67] TODO: Implement something that is too long for one line
// // that is too long for one line
// main() {
// // TODO: Implement something
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.todo] TODO: Implement something
// // this is not a todo
// main() {
// // TODO: Implement something
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.todo] TODO: Implement something
// main() {
}
''',
[
error(
diag.todo,
20,
67,
text: 'TODO: Implement something that is too long for one line',
),
error(diag.todo, 117, 25, text: 'TODO: Implement something'),
error(diag.todo, 202, 25, text: 'TODO: Implement something'),
],
);
''');
}
test_todo_singleLineCommentFollowedByDartdoc() async {
@@ -232,111 +178,61 @@ void f() {}
}
test_todo_singleLineCommentLessIndentedContinuation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
// TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
// that is too long for one line
// this is not part of the todo
}
''',
[
error(
diag.todo,
14,
61,
text: 'TODO: Implement something that is too long for one line',
),
],
);
''');
}
test_todo_singleLineCommentMoreIndentedContinuation() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
// TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
// that is too long for one line
// this is not part of the todo
}
''',
[
error(
diag.todo,
14,
61,
text: 'TODO: Implement something that is too long for one line',
),
],
);
''');
}
test_todo_singleLineCommentNested() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
// TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
// that is too long for one line
// TODO: This is a separate todo that is accidentally indented
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// [diag.todo] TODO: This is a separate todo that is accidentally indented
}
''',
[
error(
diag.todo,
14,
61,
text: 'TODO: Implement something that is too long for one line',
),
error(
diag.todo,
82,
59,
text: 'TODO: This is a separate todo that is accidentally indented',
),
],
);
''');
}
test_todo_singleLineCommentWrapped() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
main() {
// TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
// that is too long for one line
// this is not part of the todo
// TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
// that is too long for one line
// this is not part of the todo
// TODO: Implement something
// [diag.todo][column 6][length 61] TODO: Implement something that is too long for one line
// that is too long for one line
//
// this is not part of the todo
}
''',
[
error(
diag.todo,
14,
61,
text: 'TODO: Implement something that is too long for one line',
),
error(
diag.todo,
116,
61,
text: 'TODO: Implement something that is too long for one line',
),
error(
diag.todo,
220,
61,
text: 'TODO: Implement something that is too long for one line',
),
],
);
''');
}
test_undone() async {
@@ -8,7 +8,6 @@ import 'package:analyzer/analysis_rule/rule_visitor_registry.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/diagnostic/diagnostic.dart' as diag;
import 'package:analyzer/src/test_utilities/lint_registration_mixin.dart';
import 'package:analyzer_testing/utilities/utilities.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -80,16 +79,13 @@ class UnignorableIgnoreTest extends PubPackageResolutionTest
);
var avoidIntRule = _AvoidIntRule();
registerLintRule(avoidIntRule);
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
// ignore: avoid_int
// ^^^^^^^^^
// [diag.unignorableIgnore] The diagnostic 'avoid_int' can't be ignored.
int a = 0;
''',
[
error(diag.unignorableIgnore, 11, 9),
error(avoidIntRule.diagnosticCode, 21, 3),
],
);
// [diag.avoidInt][column 1][length 3] Avoid int.
''');
}
}
@@ -98,7 +94,7 @@ class _AvoidIntRule extends AnalysisRule {
'avoid_int',
'Avoid int.',
correctionMessage: 'Try avoiding int.',
uniqueName: 'LintCode.avoid_int',
uniqueName: 'avoid_int',
);
_AvoidIntRule() : super(name: 'avoid_int', description: '');
@@ -2,7 +2,6 @@
// 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/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@@ -35,20 +34,15 @@ f() async* {
''');
}
@FailingTest(
reason:
'We are currently trying to parse the yield statement as a '
'binary expression.',
)
test_sync() async {
await assertErrorsInCode(
r'''
await resolveTestCodeWithDiagnostics(r'''
f() {
yield 0;
//^^^^^
// [diag.expectedToken] Expected to find ';'.
// [diag.undefinedIdentifier] Undefined name 'yield'.
}
''',
[error(diag.yieldInNonGenerator, 0, 0)],
);
''');
}
test_syncStar() async {
File diff suppressed because it is too large Load Diff
@@ -11,20 +11,19 @@ import 'package:analyzer_testing/utilities/extensions/diagnostic_code.dart';
/// Returns [content] with generated diagnostic expectation marker lines removed.
String removeDiagnosticExpectations(String content) {
var lines = _Line.parse(content);
var allLines = _Line.parse(content);
var codeLines = allLines
.where((line) => !_LineMarker.isMarker(line))
.toList();
var buffer = StringBuffer();
var isFirstLine = true;
for (var line in lines) {
if (_LineMarker.isMarker(line)) {
continue;
}
if (isFirstLine) {
isFirstLine = false;
} else {
buffer.writeln();
}
for (var i = 0; i < codeLines.length; i++) {
var line = codeLines[i];
buffer.write(line.text);
// Write terminators as separators between retained lines; a terminator
// before a removed marker line should not become a trailing terminator.
if (i < codeLines.length - 1) {
buffer.write(line.lineTerminator);
}
}
return buffer.toString();
}
@@ -293,32 +292,35 @@ final class _ExpectedDiagnosticsUpdater {
String _writeContent() {
var buffer = StringBuffer();
var isFirstLine = true;
for (var line in lines) {
if (isFirstLine) {
isFirstLine = false;
} else {
buffer.writeln();
}
buffer.write(line.text);
var markers = markersByLine[line.number];
if (markers != null) {
var markerLineTerminator = line.lineTerminator;
// Use a separator when adding markers after an unterminated final line.
if (markerLineTerminator.isEmpty) {
markerLineTerminator = '\n';
}
markers.sort(_GeneratedMarker.compare);
({int column, int length})? currentCaret;
for (var marker in markers) {
if (marker.caretLength case var caretLength?) {
var markerCaret = (column: marker.column, length: caretLength);
if (markerCaret != currentCaret) {
buffer.writeln();
buffer.write(markerLineTerminator);
buffer.write(_caretLine(marker.column, caretLength));
currentCaret = markerCaret;
}
}
buffer.writeln();
buffer.write(markerLineTerminator);
buffer.write(marker.expectationText);
}
}
buffer.write(line.lineTerminator);
}
return buffer.toString();
}
@@ -456,7 +458,14 @@ final class _Line {
/// The line text without the trailing newline characters.
final String text;
_Line({required this.number, required this.text});
/// The line terminator, if present.
final String lineTerminator;
_Line({
required this.number,
required this.text,
required this.lineTerminator,
});
/// Splits [content] into lines while preserving each line's offset.
///
@@ -470,24 +479,34 @@ final class _Line {
for (var index = 0; index < content.length; index++) {
var codeUnit = content.codeUnitAt(index);
if (codeUnit == 0x0D || codeUnit == 0x0A) {
result.add(
_Line(
number: lineNumber++,
text: content.substring(lineStart, index),
),
);
var lineText = content.substring(lineStart, index);
// Consume the `\n` in a `\r\n` line break.
var lineTerminator = content.substring(index, index + 1);
if (codeUnit == 0x0D &&
index + 1 < content.length &&
content.codeUnitAt(index + 1) == 0x0A) {
lineTerminator = content.substring(index, index + 2);
index++;
}
result.add(
_Line(
number: lineNumber++,
text: lineText,
lineTerminator: lineTerminator,
),
);
lineStart = index + 1;
}
}
result.add(_Line(number: lineNumber, text: content.substring(lineStart)));
result.add(
_Line(
number: lineNumber,
text: content.substring(lineStart),
lineTerminator: '',
),
);
return result;
}
}