Add hasPragmaAnalyzerNonNullable to AstBuilder and CompilationUnitImpl.
Start integration testing for non-nullable types.
Just interface type, and just parsing for now. Obviously we cannot
start working on resolver until the CL with `nullability` is landed.
R=brianwilkerson@google.com, paulberry@google.com
Change-Id: I8fe70c29b25fad56739a549b09a235a83f9960e7
Reviewed-on: https://dart-review.googlesource.com/c/88434
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Dan Rubel <danrubel@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 23a69ac..749f864 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -2342,6 +2342,12 @@
Map<int, AstNode> localDeclarations;
/**
+ * Is `true` if the non-nullable feature is enabled, and this library
+ * unit is annotated with `@pragma('analyzer:non-nullable')`.
+ */
+ bool hasPragmaAnalyzerNonNullable = false;
+
+ /**
* Initialize a newly created compilation unit to have the given directives
* and declarations. The [scriptTag] can be `null` if there is no script tag
* in the compilation unit. The list of [directives] can be `null` if there
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 6aea1f1..94a0fbe 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -99,7 +99,9 @@
/// `true` if non-nullable behavior is enabled
bool enableNonNullable = false;
- bool showNullableTypeErrors = true;
+ /// Is `true` if [enableNonNullable] is enabled, and the library directive
+ /// is annotated with `@pragma('analyzer:non-nullable')`.
+ bool hasPragmaAnalyzerNonNullable = false;
AstBuilder(ErrorReporter errorReporter, this.fileUri, this.isFullAst,
[Uri uri])
@@ -967,7 +969,7 @@
@override
void handleType(Token beginToken, Token questionMark) {
debugEvent("Type");
- if (showNullableTypeErrors) {
+ if (!enableNonNullable) {
reportErrorIfNullableType(questionMark);
}
@@ -1128,7 +1130,7 @@
void endFunctionType(Token functionToken, Token questionMark) {
assert(optional('Function', functionToken));
debugEvent("FunctionType");
- if (showNullableTypeErrors) {
+ if (!enableNonNullable) {
reportErrorIfNullableType(questionMark);
}
@@ -2101,10 +2103,8 @@
if (arguments.length == 1) {
Expression tag = arguments[0];
if (tag is StringLiteral) {
- // TODO(danrubel): handle other flags such as
- // 'analyzer:non-nullable' without the trailing star.
- if (tag.stringValue == 'analyzer:non-nullable*') {
- showNullableTypeErrors = false;
+ if (tag.stringValue == 'analyzer:non-nullable') {
+ hasPragmaAnalyzerNonNullable = true;
break;
}
}
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
index 751b788..389c230 100644
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ b/pkg/analyzer/lib/src/generated/parser_fasta.dart
@@ -169,6 +169,8 @@
currentToken = fastaParser.parseUnit(currentToken);
CompilationUnitImpl compilationUnit = astBuilder.pop();
compilationUnit.localDeclarations = astBuilder.localDeclarations;
+ compilationUnit.hasPragmaAnalyzerNonNullable =
+ astBuilder.hasPragmaAnalyzerNonNullable;
return compilationUnit;
}
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 827110a..3f8732d 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -16,8 +16,8 @@
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/string_source.dart';
import 'package:analyzer/src/test_utilities/ast_type_matchers.dart';
-import 'package:front_end/src/fasta/parser/parser.dart' as fasta;
import 'package:front_end/src/fasta/parser/forwarding_listener.dart' as fasta;
+import 'package:front_end/src/fasta/parser/parser.dart' as fasta;
import 'package:front_end/src/fasta/scanner.dart'
show ScannerResult, scanString;
import 'package:front_end/src/fasta/scanner/error_token.dart' show ErrorToken;
@@ -1434,7 +1434,7 @@
class NNBDParserTest_Fasta extends FastaParserTestCase {
parseNNBDCompilationUnit(String code, {List<ExpectedError> errors}) {
createParser('''
-@pragma('analyzer:non-nullable*') library nnbd.parser.test;
+@pragma('analyzer:non-nullable') library nnbd.parser.test;
$code
''');
_parserProxy.astBuilder.enableNonNullable = true;
@@ -1520,31 +1520,31 @@
void test_pragma_missing() {
createParser("library foo;");
_parserProxy.astBuilder.enableNonNullable = true;
- _parserProxy.parseCompilationUnit2();
- expect(_parserProxy.astBuilder.showNullableTypeErrors, true);
+ CompilationUnitImpl unit = _parserProxy.parseCompilationUnit2();
+ expect(unit.hasPragmaAnalyzerNonNullable, false);
}
void test_pragma_non_nullable() {
- createParser("@pragma('analyzer:non-nullable*') library foo;");
+ createParser("@pragma('analyzer:non-nullable') library foo;");
_parserProxy.astBuilder.enableNonNullable = true;
- _parserProxy.parseCompilationUnit2();
- expect(_parserProxy.astBuilder.showNullableTypeErrors, false);
+ CompilationUnitImpl unit = _parserProxy.parseCompilationUnit2();
+ expect(unit.hasPragmaAnalyzerNonNullable, true);
}
void test_pragma_non_nullable_not_enabled() {
- createParser("@pragma('analyzer:non-nullable*') library foo;");
- _parserProxy.parseCompilationUnit2();
- expect(_parserProxy.astBuilder.showNullableTypeErrors, true);
+ createParser("@pragma('analyzer:non-nullable') library foo;");
+ CompilationUnitImpl unit = _parserProxy.parseCompilationUnit2();
+ expect(unit.hasPragmaAnalyzerNonNullable, false);
}
void test_pragma_other() {
createParser("@pragma('analyzer:foo') library foo;");
_parserProxy.astBuilder.enableNonNullable = true;
- _parserProxy.parseCompilationUnit2();
- expect(_parserProxy.astBuilder.showNullableTypeErrors, true);
+ CompilationUnitImpl unit = _parserProxy.parseCompilationUnit2();
+ expect(unit.hasPragmaAnalyzerNonNullable, false);
}
- void test_without_pragma() {
+ void test_enableNonNullable_false() {
parseCompilationUnit('main() { x is String? ? (x + y) : z; }',
errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 20, 1)]);
}
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
new file mode 100644
index 0000000..1d4d442
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(NonNullableTest);
+ });
+}
+
+@reflectiveTest
+class NonNullableTest extends DriverResolutionTest {
+ @override
+ AnalysisOptionsImpl get analysisOptions =>
+ AnalysisOptionsImpl()..enabledExperiments = [EnableString.non_nullable];
+
+ test_interfaceType() async {
+ addTestFile(r'''
+int v = 0;
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ var typeName = findNode.typeName('int v');
+ expect(typeName.name.name, 'int');
+ expect(typeName.question, isNull);
+ }
+
+ test_interfaceType_nullable() async {
+ addTestFile(r'''
+int? v = 0;
+''');
+ await resolveTestFile();
+ assertNoTestErrors();
+
+ var typeName = findNode.typeName('int? v');
+ expect(typeName.name.name, 'int');
+ expect(typeName.question, isNotNull);
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index c52454e..4848102 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -19,6 +19,7 @@
as instance_member_inference_mixin_test;
import 'method_invocation_test.dart' as method_invocation_test;
import 'mixin_test.dart' as mixin_test;
+import 'non_nullable_test.dart' as non_nullable_test;
import 'optional_const_test.dart' as optional_const_test;
import 'property_access_test.dart' as property_access_test;
import 'top_type_inference_test.dart' as top_type_inference_test;
@@ -38,6 +39,7 @@
instance_member_inference_mixin_test.main();
method_invocation_test.main();
mixin_test.main();
+ non_nullable_test.main();
optional_const_test.main();
property_access_test.main();
top_type_inference_test.main();