mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 03:27:43 +00:00
Disallow uninitialized non-nullable variables
Declaring a non-nullable variable without initializing it is a static error. If a constant is declared instead (either run-time or compile-time) the error handling logic is the same as before. BUG= R=jmesserly@google.com Review URL: https://codereview.chromium.org/2219653005 .
This commit is contained in:
parent
b2c771263f
commit
f5f4bb4ebd
|
@ -2743,6 +2743,7 @@ abstract class ErrorCode {
|
|||
StaticTypeWarningCode.NON_BOOL_EXPRESSION,
|
||||
StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION,
|
||||
StaticTypeWarningCode.NON_BOOL_OPERAND,
|
||||
StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED,
|
||||
StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
|
||||
StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
|
||||
StaticTypeWarningCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
|
||||
|
@ -4280,6 +4281,14 @@ class StaticTypeWarningCode extends ErrorCode {
|
|||
const StaticTypeWarningCode('NON_BOOL_OPERAND',
|
||||
"The operands of the '{0}' operator must be assignable to 'bool'");
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const StaticTypeWarningCode NON_NULLABLE_FIELD_NOT_INITIALIZED =
|
||||
const StaticTypeWarningCode(
|
||||
'NON_NULLABLE_FIELD_NOT_INITIALIZED',
|
||||
"Variable '{0}' of non-nullable type '{1}' must be initialized");
|
||||
|
||||
/**
|
||||
* 15.8 Parameterized Types: It is a static type warning if <i>A<sub>i</sub>,
|
||||
* 1 <= i <= n</i> does not denote a type in the enclosing lexical scope.
|
||||
|
|
|
@ -628,6 +628,20 @@ class CodeChecker extends RecursiveAstVisitor {
|
|||
node.visitChildren(this);
|
||||
}
|
||||
|
||||
@override
|
||||
Object visitVariableDeclaration(VariableDeclaration node) {
|
||||
if (!node.isConst &&
|
||||
!node.isFinal &&
|
||||
node.initializer == null &&
|
||||
rules.isNonNullableType(node?.element?.type)) {
|
||||
_recordMessage(
|
||||
node,
|
||||
StaticTypeWarningCode.NON_NULLABLE_FIELD_NOT_INITIALIZED,
|
||||
[node.name, node?.element?.type]);
|
||||
}
|
||||
return super.visitVariableDeclaration(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitWhileStatement(WhileStatement node) {
|
||||
checkBoolean(node.condition);
|
||||
|
|
|
@ -48,12 +48,6 @@ main() {
|
|||
checkFile('int x = null;');
|
||||
}
|
||||
|
||||
void test_uninitialized_nonnullable() {
|
||||
// If `int`s are non-nullable, then this code should throw an error.
|
||||
addFile('int x;');
|
||||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
}
|
||||
|
||||
void test_initialize_nonnullable_with_null() {
|
||||
addFile('int x = /*error:INVALID_ASSIGNMENT*/null;');
|
||||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
|
@ -76,6 +70,50 @@ main() {
|
|||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
}
|
||||
|
||||
void test_uninitialized_nonnullable_local_variable() {
|
||||
// Ideally, we will do flow analysis and throw an error only if a variable
|
||||
// is used before it has been initialized.
|
||||
addFile('main() { int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x; }');
|
||||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
}
|
||||
|
||||
void test_uninitialized_nonnullable_top_level_variable_declaration() {
|
||||
// If `int`s are non-nullable, then this code should throw an error.
|
||||
addFile('int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x;');
|
||||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
}
|
||||
|
||||
void test_uninitialized_nonnullable_field_declaration() {
|
||||
addFile('''
|
||||
void foo() {}
|
||||
|
||||
class A {
|
||||
// Ideally, we should allow x to be init in the constructor, but that requires
|
||||
// too much complication in the checker, so for now we throw a static error at
|
||||
// the declaration site.
|
||||
int /*error:NON_NULLABLE_FIELD_NOT_INITIALIZED*/x;
|
||||
|
||||
A();
|
||||
}
|
||||
''');
|
||||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
}
|
||||
|
||||
void test_prefer_final_to_non_nullable_error() {
|
||||
addFile('main() { final int /*error:FINAL_NOT_INITIALIZED*/x; }');
|
||||
addFile('final int /*error:FINAL_NOT_INITIALIZED*/x;');
|
||||
addFile('''
|
||||
void foo() {}
|
||||
|
||||
class A {
|
||||
final int x;
|
||||
|
||||
/*warning:FINAL_NOT_INITIALIZED_CONSTRUCTOR_1*/A();
|
||||
}
|
||||
''');
|
||||
check(nonnullableTypes: <String>['dart:core,int']);
|
||||
}
|
||||
|
||||
// Default example from NNBD document.
|
||||
final String defaultNnbdExample = '''
|
||||
class Point {
|
||||
|
|
Loading…
Reference in a new issue