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();