Write and read comment references.

R=brianwilkerson@google.com

Change-Id: If7d0e97ec98cc7ee2a5ac1c664cb296762911a69
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/100930
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 8458072..1b02655 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -4845,6 +4845,12 @@
   }
 
   @override
+  List<LinkedNodeBuilder> get comment_references {
+    assert(kind == idl.LinkedNodeKind.comment);
+    return _variantField_2 ??= <LinkedNodeBuilder>[];
+  }
+
+  @override
   List<LinkedNodeBuilder> get compilationUnit_declarations {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     return _variantField_2 ??= <LinkedNodeBuilder>[];
@@ -4991,6 +4997,11 @@
     _variantField_2 = value;
   }
 
+  set comment_references(List<LinkedNodeBuilder> value) {
+    assert(kind == idl.LinkedNodeKind.comment);
+    _variantField_2 = value;
+  }
+
   set compilationUnit_declarations(List<LinkedNodeBuilder> value) {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     _variantField_2 = value;
@@ -5306,6 +5317,12 @@
   }
 
   @override
+  LinkedNodeBuilder get commentReference_identifier {
+    assert(kind == idl.LinkedNodeKind.commentReference);
+    return _variantField_6;
+  }
+
+  @override
   LinkedNodeBuilder get compilationUnit_scriptTag {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     return _variantField_6;
@@ -5764,6 +5781,11 @@
     _variantField_6 = value;
   }
 
+  set commentReference_identifier(LinkedNodeBuilder value) {
+    assert(kind == idl.LinkedNodeKind.commentReference);
+    _variantField_6 = value;
+  }
+
   set compilationUnit_scriptTag(LinkedNodeBuilder value) {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     _variantField_6 = value;
@@ -6185,6 +6207,12 @@
   }
 
   @override
+  int get commentReference_newKeyword {
+    assert(kind == idl.LinkedNodeKind.commentReference);
+    return _variantField_15 ??= 0;
+  }
+
+  @override
   int get compilationUnit_beginToken {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     return _variantField_15 ??= 0;
@@ -6741,6 +6769,12 @@
     _variantField_15 = value;
   }
 
+  set commentReference_newKeyword(int value) {
+    assert(kind == idl.LinkedNodeKind.commentReference);
+    assert(value == null || value >= 0);
+    _variantField_15 = value;
+  }
+
   set compilationUnit_beginToken(int value) {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     assert(value == null || value >= 0);
@@ -10424,6 +10458,15 @@
         _variantField_6 = cascadeExpression_target,
         _variantField_25 = expression_type;
 
+  LinkedNodeBuilder.comment({
+    List<LinkedNodeBuilder> comment_references,
+    List<int> comment_tokens,
+    idl.LinkedNodeCommentType comment_type,
+  })  : _kind = idl.LinkedNodeKind.comment,
+        _variantField_2 = comment_references,
+        _variantField_28 = comment_tokens,
+        _variantField_29 = comment_type;
+
   LinkedNodeBuilder.compilationUnit({
     List<LinkedNodeBuilder> compilationUnit_declarations,
     LinkedNodeBuilder compilationUnit_scriptTag,
@@ -11103,6 +11146,13 @@
         _variantField_19 = catchClause_rightParenthesis,
         _variantField_9 = catchClause_stackTraceParameter;
 
+  LinkedNodeBuilder.commentReference({
+    LinkedNodeBuilder commentReference_identifier,
+    int commentReference_newKeyword,
+  })  : _kind = idl.LinkedNodeKind.commentReference,
+        _variantField_6 = commentReference_identifier,
+        _variantField_15 = commentReference_newKeyword;
+
   LinkedNodeBuilder.conditionalExpression({
     LinkedNodeBuilder conditionalExpression_condition,
     int conditionalExpression_colon,
@@ -11699,13 +11749,6 @@
         _variantField_15 = thisExpression_thisKeyword,
         _variantField_25 = expression_type;
 
-  LinkedNodeBuilder.comment({
-    List<int> comment_tokens,
-    idl.LinkedNodeCommentType comment_type,
-  })  : _kind = idl.LinkedNodeKind.comment,
-        _variantField_28 = comment_tokens,
-        _variantField_29 = comment_type;
-
   /// Flush [informative] data recursively.
   void flushInformative() {
     _variantField_24?.flushInformative();
@@ -12175,6 +12218,15 @@
   }
 
   @override
+  List<idl.LinkedNode> get comment_references {
+    assert(kind == idl.LinkedNodeKind.comment);
+    _variantField_2 ??=
+        const fb.ListReader<idl.LinkedNode>(const _LinkedNodeReader())
+            .vTableGet(_bc, _bcOffset, 2, const <idl.LinkedNode>[]);
+    return _variantField_2;
+  }
+
+  @override
   List<idl.LinkedNode> get compilationUnit_declarations {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     _variantField_2 ??=
@@ -12547,6 +12599,14 @@
   }
 
   @override
+  idl.LinkedNode get commentReference_identifier {
+    assert(kind == idl.LinkedNodeKind.commentReference);
+    _variantField_6 ??=
+        const _LinkedNodeReader().vTableGet(_bc, _bcOffset, 6, null);
+    return _variantField_6;
+  }
+
+  @override
   idl.LinkedNode get compilationUnit_scriptTag {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     _variantField_6 ??=
@@ -13191,6 +13251,14 @@
   }
 
   @override
+  int get commentReference_newKeyword {
+    assert(kind == idl.LinkedNodeKind.commentReference);
+    _variantField_15 ??=
+        const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 15, 0);
+    return _variantField_15;
+  }
+
+  @override
   int get compilationUnit_beginToken {
     assert(kind == idl.LinkedNodeKind.compilationUnit);
     _variantField_15 ??=
@@ -16158,6 +16226,14 @@
       if (expression_type != null)
         _result["expression_type"] = expression_type.toJson();
     }
+    if (kind == idl.LinkedNodeKind.comment) {
+      if (comment_references.isNotEmpty)
+        _result["comment_references"] =
+            comment_references.map((_value) => _value.toJson()).toList();
+      if (comment_tokens.isNotEmpty) _result["comment_tokens"] = comment_tokens;
+      if (comment_type != idl.LinkedNodeCommentType.block)
+        _result["comment_type"] = comment_type.toString().split('.')[1];
+    }
     if (kind == idl.LinkedNodeKind.compilationUnit) {
       if (compilationUnit_declarations.isNotEmpty)
         _result["compilationUnit_declarations"] = compilationUnit_declarations
@@ -16945,6 +17021,13 @@
         _result["catchClause_stackTraceParameter"] =
             catchClause_stackTraceParameter.toJson();
     }
+    if (kind == idl.LinkedNodeKind.commentReference) {
+      if (commentReference_identifier != null)
+        _result["commentReference_identifier"] =
+            commentReference_identifier.toJson();
+      if (commentReference_newKeyword != 0)
+        _result["commentReference_newKeyword"] = commentReference_newKeyword;
+    }
     if (kind == idl.LinkedNodeKind.conditionalExpression) {
       if (conditionalExpression_condition != null)
         _result["conditionalExpression_condition"] =
@@ -17558,11 +17641,6 @@
       if (expression_type != null)
         _result["expression_type"] = expression_type.toJson();
     }
-    if (kind == idl.LinkedNodeKind.comment) {
-      if (comment_tokens.isNotEmpty) _result["comment_tokens"] = comment_tokens;
-      if (comment_type != idl.LinkedNodeCommentType.block)
-        _result["comment_type"] = comment_type.toString().split('.')[1];
-    }
     return _result;
   }
 
@@ -17817,6 +17895,15 @@
         "kind": kind,
       };
     }
+    if (kind == idl.LinkedNodeKind.comment) {
+      return {
+        "comment_references": comment_references,
+        "comment_tokens": comment_tokens,
+        "comment_type": comment_type,
+        "isSynthetic": isSynthetic,
+        "kind": kind,
+      };
+    }
     if (kind == idl.LinkedNodeKind.compilationUnit) {
       return {
         "compilationUnit_declarations": compilationUnit_declarations,
@@ -18382,6 +18469,14 @@
         "kind": kind,
       };
     }
+    if (kind == idl.LinkedNodeKind.commentReference) {
+      return {
+        "commentReference_identifier": commentReference_identifier,
+        "commentReference_newKeyword": commentReference_newKeyword,
+        "isSynthetic": isSynthetic,
+        "kind": kind,
+      };
+    }
     if (kind == idl.LinkedNodeKind.conditionalExpression) {
       return {
         "conditionalExpression_condition": conditionalExpression_condition,
@@ -18968,14 +19063,6 @@
         "kind": kind,
       };
     }
-    if (kind == idl.LinkedNodeKind.comment) {
-      return {
-        "comment_tokens": comment_tokens,
-        "comment_type": comment_type,
-        "isSynthetic": isSynthetic,
-        "kind": kind,
-      };
-    }
     throw StateError("Unexpected $kind");
   }
 
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index ad1b299..0a30d49 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -223,6 +223,8 @@
 
   comment,
 
+  commentReference,
+
   compilationUnit,
 
   conditionalExpression,
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 171389f..d37f619 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -1167,12 +1167,21 @@
   ])
   int get combinator_keyword;
 
+  @VariantId(2, variant: LinkedNodeKind.comment)
+  List<LinkedNode> get comment_references;
+
   @VariantId(28, variant: LinkedNodeKind.comment)
   List<int> get comment_tokens;
 
   @VariantId(29, variant: LinkedNodeKind.comment)
   LinkedNodeCommentType get comment_type;
 
+  @VariantId(6, variant: LinkedNodeKind.commentReference)
+  LinkedNode get commentReference_identifier;
+
+  @VariantId(15, variant: LinkedNodeKind.commentReference)
+  int get commentReference_newKeyword;
+
   @VariantId(15, variant: LinkedNodeKind.compilationUnit)
   int get compilationUnit_beginToken;
 
@@ -2455,6 +2464,7 @@
   classDeclaration,
   classTypeAlias,
   comment,
+  commentReference,
   compilationUnit,
   conditionalExpression,
   configuration,
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index b362bdf..e7b2b94 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -266,7 +266,7 @@
       case LinkedNodeCommentType.documentation:
         return astFactory.documentationComment(
           tokens,
-          // TODO(scheglov) references
+          _readNodeList(data.comment_references),
         );
       case LinkedNodeCommentType.endOfLine:
         return astFactory.endOfLineComment(
@@ -277,6 +277,13 @@
     }
   }
 
+  CommentReference _read_commentReference(LinkedNode data) {
+    return astFactory.commentReference(
+      _getToken(data.commentReference_newKeyword),
+      _readNode(data.commentReference_identifier),
+    );
+  }
+
   CompilationUnit _read_compilationUnit(LinkedNode data) {
     return astFactory.compilationUnit2(
         beginToken: _getToken(data.compilationUnit_beginToken),
@@ -1335,6 +1342,8 @@
         return _read_classTypeAlias(data);
       case LinkedNodeKind.comment:
         return _read_comment(data);
+      case LinkedNodeKind.commentReference:
+        return _read_commentReference(data);
       case LinkedNodeKind.compilationUnit:
         return _read_compilationUnit(data);
       case LinkedNodeKind.conditionalExpression:
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index 06ca89b..028ffd8 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -13,19 +13,21 @@
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/lazy_ast.dart';
 import 'package:analyzer/src/summary2/linking_bundle_context.dart';
-import 'package:analyzer/src/summary2/tokens_context.dart';
+import 'package:analyzer/src/summary2/tokens_writer.dart';
 
 /// Serializer of fully resolved ASTs into flat buffers.
 class AstBinaryWriter extends ThrowingAstVisitor<LinkedNodeBuilder> {
   final LinkingBundleContext _linkingContext;
-  final TokensContext _tokensContext;
+  final _tokensWriter = TokensWriter();
 
   /// This field is set temporary while visiting [FieldDeclaration] or
   /// [TopLevelVariableDeclaration] to store data shared among all variables
   /// in these declarations.
   LinkedNodeVariablesDeclarationBuilder _variablesDeclaration;
 
-  AstBinaryWriter(this._linkingContext, this._tokensContext);
+  AstBinaryWriter(this._linkingContext);
+
+  UnlinkedTokensBuilder get tokensBuilder => _tokensWriter.tokensBuilder;
 
   @override
   LinkedNodeBuilder visitAdjacentStrings(AdjacentStrings node) {
@@ -232,6 +234,21 @@
     return LinkedNodeBuilder.comment(
       comment_tokens: _getTokens(node.tokens),
       comment_type: type,
+      comment_references: _writeNodeList(node.references),
+    );
+  }
+
+  @override
+  LinkedNodeBuilder visitCommentReference(CommentReference node) {
+    var identifier = node.identifier;
+    _tokensWriter.writeTokens(
+      node.newKeyword ?? identifier.beginToken,
+      identifier.endToken,
+    );
+
+    return LinkedNodeBuilder.commentReference(
+      commentReference_identifier: identifier.accept(this),
+      commentReference_newKeyword: _getToken(node.newKeyword),
     );
   }
 
@@ -1345,6 +1362,7 @@
   }
 
   LinkedNodeBuilder writeNode(AstNode node) {
+    _tokensWriter.writeTokens(node.beginToken, node.endToken);
     return node.accept(this);
   }
 
@@ -1364,7 +1382,7 @@
   }
 
   int _getToken(Token token) {
-    return _tokensContext.indexOfToken(token);
+    return _tokensWriter.indexOfToken(token);
   }
 
   List<int> _getTokens(List<Token> tokenList) {
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 82fe2ca..60a3c9d 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -23,7 +23,6 @@
 import 'package:analyzer/src/summary2/linking_bundle_context.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:analyzer/src/summary2/simply_bounded.dart';
-import 'package:analyzer/src/summary2/tokens_writer.dart';
 import 'package:analyzer/src/summary2/top_level_inference.dart';
 import 'package:analyzer/src/summary2/type_alias.dart';
 import 'package:analyzer/src/summary2/types_builder.dart';
@@ -200,19 +199,14 @@
 
       for (var unitContext in builder.context.units) {
         var unit = unitContext.unit;
-        var tokensResult = TokensWriter().writeTokens(
-          unit.beginToken,
-          unit.endToken,
-        );
-        var tokensContext = tokensResult.toContext();
 
-        var writer = new AstBinaryWriter(linkingBundleContext, tokensContext);
+        var writer = AstBinaryWriter(linkingBundleContext);
         var unitLinkedNode = writer.writeNode(unit);
         builder.node.units.add(
           LinkedNodeUnitBuilder(
             isSynthetic: unitContext.isSynthetic,
             uriStr: unitContext.uriStr,
-            tokens: tokensResult.tokens,
+            tokens: writer.tokensBuilder,
             node: unitLinkedNode,
           ),
         );
diff --git a/pkg/analyzer/lib/src/summary2/tokens_context.dart b/pkg/analyzer/lib/src/summary2/tokens_context.dart
index deaa244..72235c9 100644
--- a/pkg/analyzer/lib/src/summary2/tokens_context.dart
+++ b/pkg/analyzer/lib/src/summary2/tokens_context.dart
@@ -4,15 +4,9 @@
 
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
-import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary2/tokens_writer.dart';
 
-/// The context for reading or writing tokens.
-///
-/// Tokens cannot be compared, so tokens for [indexOfToken] must be previously
-/// received from [tokenOfIndex], or the context must be created from a
-/// [TokensResult] (the result of writing previously parsed tokens).
+/// The context for reading tokens.
 class TokensContext {
   final UnlinkedTokens _tokens;
   final List<Token> _indexToToken;
@@ -22,36 +16,6 @@
       : _indexToToken = List<Token>(_tokens.type.length),
         _tokenToIndex = Map.identity();
 
-  TokensContext.fromResult(
-      this._tokens, this._indexToToken, this._tokenToIndex);
-
-  /// TODO(scheglov) Not used yet, maybe remove.
-  int addSyntheticToken(
-      UnlinkedTokenKind kind, UnlinkedTokenType type, String lexeme) {
-    var index = _tokens.kind.length;
-    UnlinkedTokensBuilder tokens = _tokens;
-    tokens.kind.add(kind);
-    tokens.lexeme.add(lexeme);
-    tokens.offset.add(0);
-    tokens.length.add(0);
-    tokens.type.add(type);
-    tokens.next.add(0);
-    tokens.endGroup.add(0);
-    tokens.precedingComment.add(0);
-    tokens.isSynthetic.add(true);
-    return index;
-  }
-
-  int indexOfToken(Token token) {
-    if (token == null) return 0;
-
-    var index = _tokenToIndex[token];
-    if (index == null) {
-      throw StateError('Unexpected token: $token');
-    }
-    return index;
-  }
-
   String lexeme(int index) {
     return _tokens.lexeme[index];
   }
diff --git a/pkg/analyzer/lib/src/summary2/tokens_writer.dart b/pkg/analyzer/lib/src/summary2/tokens_writer.dart
index 32af28c..3f4b549 100644
--- a/pkg/analyzer/lib/src/summary2/tokens_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/tokens_writer.dart
@@ -6,25 +6,10 @@
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
-import 'package:analyzer/src/summary2/tokens_context.dart';
 import 'package:meta/meta.dart';
 
-/// The result of writing a sequence of tokens.
-class TokensResult {
-  final UnlinkedTokensBuilder tokens;
-  final List<Token> _indexToToken;
-  final Map<Token, int> _tokenToIndex;
-
-  TokensResult(this.tokens, this._indexToToken, this._tokenToIndex);
-
-  TokensContext toContext() {
-    return TokensContext.fromResult(tokens, _indexToToken, _tokenToIndex);
-  }
-}
-
 class TokensWriter {
   final UnlinkedTokensBuilder _tokens = UnlinkedTokensBuilder();
-  final List<Token> _indexToToken = [];
   final Map<Token, int> _tokenToIndex = Map.identity();
 
   TokensWriter() {
@@ -40,8 +25,20 @@
     );
   }
 
+  UnlinkedTokensBuilder get tokensBuilder => _tokens;
+
+  int indexOfToken(Token token) {
+    if (token == null) return 0;
+
+    var index = _tokenToIndex[token];
+    if (index == null) {
+      throw StateError('Unexpected token: $token');
+    }
+    return index;
+  }
+
   /// Write all the tokens from the [first] to the [last] inclusively.
-  TokensResult writeTokens(Token first, Token last) {
+  void writeTokens(Token first, Token last) {
     if (first is CommentToken) {
       first = (first as CommentToken).parent;
     }
@@ -67,8 +64,6 @@
 
       if (token == last) break;
     }
-
-    return TokensResult(_tokens, _indexToToken, _tokenToIndex);
   }
 
   int _addToken(
@@ -91,8 +86,7 @@
     _tokens.precedingComment.add(precedingComment);
     _tokens.type.add(type);
 
-    var index = _indexToToken.length;
-    _indexToToken.add(token);
+    var index = _tokenToIndex.length;
     _tokenToIndex[token] = index;
     return index;
   }
diff --git a/pkg/analyzer/test/src/dart/resolution/comment_test.dart b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
index dc7def9..c93fc8d 100644
--- a/pkg/analyzer/test/src/dart/resolution/comment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/comment_test.dart
@@ -13,13 +13,9 @@
   });
 }
 
-@reflectiveTest
-class CommentDriverResolutionTest extends DriverResolutionTest
-    with ClassAliasResolutionMixin {}
-
 mixin ClassAliasResolutionMixin implements ResolutionTest {
   test_error_unqualifiedReferenceToNonLocalStaticMember() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 class A {
   static void foo() {}
 }
@@ -27,8 +23,6 @@
 /// [foo]
 class B extends A {}
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('foo]'),
@@ -36,41 +30,26 @@
     );
   }
 
-  test_new() async {
-    addTestFile(r'''
+  test_identifier_beforeClass() async {
+    await assertNoErrorsInCode(r'''
+/// [foo]
 class A {
-  A();
-  A.named();
+  foo() {}
 }
-
-/// [new A] or [new A.named]
-main() {}
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
-      findNode.simple('A]'),
-      findElement.unnamedConstructor('A'),
-    );
-    assertElement(
-      findNode.simple('A.named]'),
-      findElement.class_('A'),
-    );
-    assertElement(
-      findNode.simple('named]'),
-      findElement.constructor('named', of: 'A'),
+      findNode.simple('foo]'),
+      findElement.method('foo'),
     );
   }
 
   test_identifier_beforeConstructor() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 class A {
   /// [p]
   A(int p);
 }''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('p]'),
@@ -79,7 +58,7 @@
   }
 
   test_identifier_beforeEnum() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 /// This is the [Samurai] kind.
 enum Samurai {
   /// Use [int].
@@ -87,8 +66,6 @@
   /// Like [WITH_SWORD], but only without one.
   WITHOUT_SWORD
 }''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('Samurai]'),
@@ -105,12 +82,10 @@
   }
 
   test_identifier_beforeFunction_blockBody() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 /// [p]
 foo(int p) {}
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('p]'),
@@ -118,27 +93,11 @@
     );
   }
 
-  test_identifier_parameter_functionTyped() async {
-    addTestFile(r'''
-/// [bar]
-foo(int bar()) {}
-''');
-    await resolveTestFile();
-    assertNoTestErrors();
-
-    assertElement(
-      findNode.simple('bar]'),
-      findElement.parameter('bar'),
-    );
-  }
-
   test_identifier_beforeFunction_expressionBody() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 /// [p]
 foo(int p) => null;
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('p]'),
@@ -147,12 +106,10 @@
   }
 
   test_identifier_beforeFunctionTypeAlias() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 /// [p]
 typedef Foo(int p);
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('p]'),
@@ -161,12 +118,10 @@
   }
 
   test_identifier_beforeGenericTypeAlias() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 /// Can resolve [T], [S], and [p].
 typedef Foo<T> = Function<S>(int p);
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
       findNode.simple('T]'),
@@ -180,18 +135,16 @@
   }
 
   test_identifier_beforeGetter() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 /// [int]
 get g => null;
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(findNode.simple('int]'), intElement);
   }
 
   test_identifier_beforeMethod() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 abstract class A {
   /// [p1]
   ma(int p1);
@@ -206,8 +159,6 @@
   md(int p5, {int p6});
 }
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(findNode.simple('p1]'), findElement.parameter('p1'));
     assertElement(findNode.simple('p2]'), findElement.parameter('p2'));
@@ -216,24 +167,20 @@
     assertElement(findNode.simple('p5]'), findElement.parameter('p5'));
   }
 
-  test_identifier_beforeClass() async {
-    addTestFile(r'''
-/// [foo]
-class A {
-  foo() {}
-}
+  test_identifier_parameter_functionTyped() async {
+    await assertNoErrorsInCode(r'''
+/// [bar]
+foo(int bar()) {}
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     assertElement(
-      findNode.simple('foo]'),
-      findElement.method('foo'),
+      findNode.simple('bar]'),
+      findElement.parameter('bar'),
     );
   }
 
   test_identifier_setter() async {
-    addTestFile(r'''
+    await assertNoErrorsInCode(r'''
 class A {
   /// [x] in A
   mA() {}
@@ -245,11 +192,38 @@
   mB() {}
 }
 ''');
-    await resolveTestFile();
-    assertNoTestErrors();
 
     var x = findElement.setter('x', of: 'A');
     assertElement(findNode.simple('x] in A'), x);
     assertElement(findNode.simple('x] in B'), x);
   }
+
+  test_new() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  A();
+  A.named();
 }
+
+/// [new A] or [new A.named]
+main() {}
+''');
+
+    assertElement(
+      findNode.simple('A]'),
+      findElement.unnamedConstructor('A'),
+    );
+    assertElement(
+      findNode.simple('A.named]'),
+      findElement.class_('A'),
+    );
+    assertElement(
+      findNode.simple('named]'),
+      findElement.constructor('named', of: 'A'),
+    );
+  }
+}
+
+@reflectiveTest
+class CommentDriverResolutionTest extends DriverResolutionTest
+    with ClassAliasResolutionMixin {}
diff --git a/pkg/analyzer/test/src/summary2/ast_binary_writer_integration_test.dart b/pkg/analyzer/test/src/summary2/ast_binary_writer_integration_test.dart
index 990a122..1fc7fae 100644
--- a/pkg/analyzer/test/src/summary2/ast_binary_writer_integration_test.dart
+++ b/pkg/analyzer/test/src/summary2/ast_binary_writer_integration_test.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/src/summary2/linked_unit_context.dart';
 import 'package:analyzer/src/summary2/linking_bundle_context.dart';
 import 'package:analyzer/src/summary2/reference.dart';
-import 'package:analyzer/src/summary2/tokens_writer.dart';
 import 'package:front_end/src/testing/package_root.dart' as package_root;
 import 'package:test/test.dart';
 
@@ -60,22 +59,16 @@
     lineInfo = parseResult.lineInfo;
     var originalUnit = parseResult.unit;
 
-    TokensResult tokensResult = TokensWriter().writeTokens(
-      originalUnit.beginToken,
-      originalUnit.endToken,
-    );
-    var tokensContext = tokensResult.toContext();
-
     var rootReference = Reference.root();
     var dynamicRef = rootReference.getChild('dart:core').getChild('dynamic');
 
     var linkingBundleContext = LinkingBundleContext(dynamicRef);
-    var writer = new AstBinaryWriter(linkingBundleContext, tokensContext);
+    var writer = AstBinaryWriter(linkingBundleContext);
     var unitLinkedNode = writer.writeNode(originalUnit);
 
     linkedNodeUnit = LinkedNodeUnitBuilder(
       node: unitLinkedNode,
-      tokens: tokensResult.tokens,
+      tokens: writer.tokensBuilder,
     );
   }
 
diff --git a/pkg/analyzer/test/src/summary2/ast_binary_writer_test.dart b/pkg/analyzer/test/src/summary2/ast_binary_writer_test.dart
index 918101f..b195dca 100644
--- a/pkg/analyzer/test/src/summary2/ast_binary_writer_test.dart
+++ b/pkg/analyzer/test/src/summary2/ast_binary_writer_test.dart
@@ -12,7 +12,6 @@
 import 'package:analyzer/src/summary2/linked_unit_context.dart';
 import 'package:analyzer/src/summary2/linking_bundle_context.dart';
 import 'package:analyzer/src/summary2/reference.dart';
-import 'package:analyzer/src/summary2/tokens_writer.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -126,17 +125,11 @@
     var originalUnit = parseResult.unit;
     var originalCode = originalUnit.toSource();
 
-    var tokensResult = TokensWriter().writeTokens(
-      originalUnit.beginToken,
-      originalUnit.endToken,
-    );
-    var tokensContext = tokensResult.toContext();
-
     var rootReference = Reference.root();
     var dynamicRef = rootReference.getChild('dart:core').getChild('dynamic');
 
     var linkingBundleContext = LinkingBundleContext(dynamicRef);
-    var writer = new AstBinaryWriter(linkingBundleContext, tokensContext);
+    var writer = AstBinaryWriter(linkingBundleContext);
     var builder = writer.writeNode(originalUnit);
 
     var bundleContext = LinkedBundleContext(
@@ -154,7 +147,7 @@
       false,
       LinkedNodeUnitBuilder(
         node: builder,
-        tokens: tokensResult.tokens,
+        tokens: writer.tokensBuilder,
       ),
     );