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:
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+33
-77
@@ -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 {
|
||||
|
||||
+11
-15
@@ -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 {
|
||||
|
||||
+4
-8
@@ -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 {
|
||||
|
||||
+4
-8
@@ -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 {
|
||||
|
||||
+4
-8
@@ -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)],
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+20
-52
@@ -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 {
|
||||
|
||||
+5
-20
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user