Version 2.17.0-104.0.dev

Merge commit '85cdbe31ca89771308c2230a0cc7fbb0991c0b7f' into 'dev'
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index 21183bd..01ddaa6 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -71,9 +71,10 @@
 
     var reader = _libraryReaders[uriStr];
     if (reader == null) {
+      var libraryUriList = rootReference.children.map((e) => e.name).toList();
       throw ArgumentError(
         'Missing library: $uriStr\n'
-        'Available libraries: ${_libraryReaders.keys.toList()}',
+        'Available libraries: $libraryUriList',
       );
     }
 
diff --git a/pkg/analyzer/test/src/fasta/ast_builder_test.dart b/pkg/analyzer/test/src/fasta/ast_builder_test.dart
index 5edc30a..311e173 100644
--- a/pkg/analyzer/test/src/fasta/ast_builder_test.dart
+++ b/pkg/analyzer/test/src/fasta/ast_builder_test.dart
@@ -130,6 +130,36 @@
       ..argumentList.isSynthetic;
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/48380')
+  void test_enum_constant_name_typeArguments_dot_semicolon() {
+    var parseResult = parseStringWithErrors(r'''
+enum E {
+  v<int>.;
+}
+''');
+    parseResult.assertErrors([
+      error(ParserErrorCode.ENUM_CONSTANT_WITH_TYPE_ARGUMENTS_WITHOUT_ARGUMENTS,
+          12, 5),
+      error(ParserErrorCode.MISSING_IDENTIFIER, 18, 1),
+    ]);
+
+    var E = parseResult.findNode.enumDeclaration('enum E');
+    var v = parseResult.findNode.enumConstantDeclaration('v<int>');
+    check(v).name.name.isEqualTo('v');
+
+    var arguments = check(v).arguments.isNotNull;
+    arguments.typeArguments.isNotNull;
+
+    var constructorSelector = arguments.constructorSelector.isNotNull;
+    var syntheticName = constructorSelector.value.name;
+    constructorSelector.name.isSynthetic;
+
+    arguments.argumentList
+      ..isSynthetic
+      ..leftParenthesis.isLinkedToPrevious(syntheticName.token)
+      ..rightParenthesis.isLinkedToNext(E.semicolon!);
+  }
+
   void test_enum_constant_withTypeArgumentsWithoutArguments() {
     var parseResult = parseStringWithErrors(r'''
 enum E<T> {
diff --git a/pkg/analyzer/test/util/token_check.dart b/pkg/analyzer/test/util/token_check.dart
index ac26ede..67671d0 100644
--- a/pkg/analyzer/test/util/token_check.dart
+++ b/pkg/analyzer/test/util/token_check.dart
@@ -33,12 +33,38 @@
     fail('Not synthetic');
   }
 
+  CheckTarget<Token?> get next {
+    return nest(
+      value.next,
+      (selected) => 'has next ${valueStr(selected)}',
+    );
+  }
+
+  CheckTarget<Token?> get previous {
+    return nest(
+      value.previous,
+      (selected) => 'has previous ${valueStr(selected)}',
+    );
+  }
+
   CheckTarget<TokenType> get type {
     return nest(
       value.type,
       (selected) => 'has type ${valueStr(selected)}',
     );
   }
+
+  void isLinkedToNext(Token next) {
+    this.next.isEqualTo(next);
+    nest(next, (value) => 'next ${valueStr(value)}').previous.isEqualTo(value);
+  }
+
+  void isLinkedToPrevious(Token previous) {
+    nest(previous, (value) => 'given previous ${valueStr(value)}')
+        .next
+        .isEqualTo(value);
+    this.previous.isEqualTo(previous);
+  }
 }
 
 extension TokenQuestionExtension on CheckTarget<Token?> {
diff --git a/tools/VERSION b/tools/VERSION
index a1cb1b8..5c8d4b8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 103
+PRERELEASE 104
 PRERELEASE_PATCH 0
\ No newline at end of file