Fix for '?.' and '?..' in binary AST.

Change-Id: I35ecb6ed10e52e47ca5690deacda0688bcb5a6f2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213407
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index f0583b2..bc6446c 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -80,7 +80,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 177;
+  static const int DATA_VERSION = 178;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index a75433d..61f2728 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -805,14 +805,20 @@
     var typeArguments = _readOptionalNode() as TypeArgumentList?;
     var arguments = readNode() as ArgumentList;
 
+    Token? operator;
+    if (AstBinaryFlags.hasQuestion(flags)) {
+      operator = AstBinaryFlags.hasPeriod(flags)
+          ? Tokens.questionPeriod()
+          : Tokens.questionPeriodPeriod();
+    } else if (AstBinaryFlags.hasPeriod(flags)) {
+      operator = Tokens.period();
+    } else if (AstBinaryFlags.hasPeriod2(flags)) {
+      operator = Tokens.periodPeriod();
+    }
+
     var node = astFactory.methodInvocation(
       target,
-      Tokens.choose(
-        AstBinaryFlags.hasPeriod(flags),
-        Tokens.period(),
-        AstBinaryFlags.hasPeriod2(flags),
-        Tokens.periodPeriod(),
-      ),
+      operator,
       methodName,
       typeArguments,
       arguments,
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 6287bc4..11fcb12 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -485,12 +485,18 @@
   void visitMethodInvocation(MethodInvocation node) {
     _writeByte(Tag.MethodInvocation);
 
+    var operatorType = node.operator?.type;
     _writeByte(
       AstBinaryFlags.encode(
-        hasPeriod: node.operator?.type == TokenType.PERIOD,
-        hasPeriod2: node.operator?.type == TokenType.PERIOD_PERIOD,
+        hasPeriod: operatorType == TokenType.PERIOD ||
+            operatorType == TokenType.QUESTION_PERIOD,
+        hasPeriod2: operatorType == TokenType.PERIOD_PERIOD ||
+            operatorType == TokenType.QUESTION_PERIOD_PERIOD,
+        hasQuestion: operatorType == TokenType.QUESTION_PERIOD ||
+            operatorType == TokenType.QUESTION_PERIOD_PERIOD,
       ),
     );
+
     _writeOptionalNode(node.target);
     _writeNode(node.methodName);
     _storeInvocationExpression(node);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 41c6205..685f2f4 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -11008,6 +11008,91 @@
 ''');
   }
 
+  test_const_topLevel_methodInvocation_questionPeriod() async {
+    var library = await checkLibrary(r'''
+const int? a = 0;
+const b = a?.toString();
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    topLevelVariables
+      static const a @11
+        type: int?
+        constantInitializer
+          IntegerLiteral
+            literal: 0 @15
+            staticType: int
+      static const b @24
+        type: String?
+        constantInitializer
+          MethodInvocation
+            argumentList: ArgumentList
+              leftParenthesis: ( @39
+              rightParenthesis: ) @40
+            methodName: SimpleIdentifier
+              staticElement: dart:core::@class::int::@method::toString
+              staticType: String Function()
+              token: toString @31
+            operator: ?. @29
+            staticInvokeType: String Function()
+            staticType: String?
+            target: SimpleIdentifier
+              staticElement: self::@getter::a
+              staticType: int?
+              token: a @28
+    accessors
+      synthetic static get a @-1
+        returnType: int?
+      synthetic static get b @-1
+        returnType: String?
+''');
+  }
+
+  test_const_topLevel_methodInvocation_questionPeriodPeriod() async {
+    var library = await checkLibrary(r'''
+const int? a = 0;
+const b = a?..toString();
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    topLevelVariables
+      static const a @11
+        type: int?
+        constantInitializer
+          IntegerLiteral
+            literal: 0 @15
+            staticType: int
+      static const b @24
+        type: int?
+        constantInitializer
+          CascadeExpression
+            cascadeSections
+              MethodInvocation
+                argumentList: ArgumentList
+                  leftParenthesis: ( @40
+                  rightParenthesis: ) @41
+                methodName: SimpleIdentifier
+                  staticElement: dart:core::@class::int::@method::toString
+                  staticType: String Function()
+                  token: toString @32
+                operator: ?.. @29
+                staticInvokeType: String Function()
+                staticType: String
+            staticType: int?
+            target: SimpleIdentifier
+              staticElement: self::@getter::a
+              staticType: int?
+              token: a @28
+    accessors
+      synthetic static get a @-1
+        returnType: int?
+      synthetic static get b @-1
+        returnType: int?
+''');
+  }
+
   test_const_topLevel_nullSafe_nullAware_propertyAccess() async {
     var library = await checkLibrary(r'''
 const String? a = '';