analyzer: Validate doc directive argument formats

Work towards https://github.com/dart-lang/sdk/issues/52705

Change-Id: Ieea17365397eaf9936ea9eaede2d472bd91abbc6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/327300
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Samuel Rawlins <srawlins@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index 4ae98a3..aae3eea 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -3452,22 +3452,29 @@
     The fix is to remove `Function` from where it's referenced.
 WarningCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE:
   status: hasFix
+WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT:
+  status: noFix
 WarningCode.DOC_DIRECTIVE_HAS_EXTRA_ARGUMENTS:
   status: needsFix
   notes: |-
-    The fix is to remove the extra arguments..
+    The fix is to remove the extra arguments.
 WarningCode.DOC_DIRECTIVE_HAS_UNEXPECTED_NAMED_ARGUMENT:
   status: needsFix
   notes: |-
     The fix is to remove the unexpected named argument.
 WarningCode.DOC_DIRECTIVE_MISSING_CLOSING_BRACE:
-  status: needsEvaluation
+  status: needsFix
+  notes: Add the closing brace at the end of the line.
 WarningCode.DOC_DIRECTIVE_MISSING_CLOSING_TAG:
-  status: needsEvaluation
+  status: needsFix
+  notes: Add the appropriate closing tag, perhaps on the line just following.
 WarningCode.DOC_DIRECTIVE_MISSING_ONE_ARGUMENT:
   status: noFix
 WarningCode.DOC_DIRECTIVE_MISSING_OPENING_TAG:
-  status: needsEvaluation
+  status: needsFix
+  notes: |-
+    I can think of two: Offer to insert the appropriate starting tag (maybe
+    on the preceding line), and offer to change the end-tag to the start-tag.
 WarningCode.DOC_DIRECTIVE_MISSING_THREE_ARGUMENTS:
   status: noFix
 WarningCode.DOC_DIRECTIVE_MISSING_TWO_ARGUMENTS:
diff --git a/pkg/analyzer/lib/dart/ast/doc_comment.dart b/pkg/analyzer/lib/dart/ast/doc_comment.dart
index 8e6a09f..a662796 100644
--- a/pkg/analyzer/lib/dart/ast/doc_comment.dart
+++ b/pkg/analyzer/lib/dart/ast/doc_comment.dart
@@ -68,6 +68,39 @@
   });
 }
 
+/// A parameter in a doc directive, with it's expected format, if it has one.
+@experimental
+final class DocDirectiveParameter {
+  final String name;
+  final DocDirectiveParameterFormat expectedFormat;
+
+  const DocDirectiveParameter(this.name, this.expectedFormat);
+}
+
+/// The expected format of a doc directive parameter, which indicates some
+/// minimal validation that can produce diagnostics.
+@experimental
+enum DocDirectiveParameterFormat {
+  /// A format indicating that arguments are not validated.
+  any('any'),
+
+  /// A format indicating that an argument must be parsable as an integer.
+  integer('an integer'),
+
+  /// A format indicating that an argument must be parsable as a URI.
+  uri('a URI'),
+
+  /// A format indicating that an argument must be parsable as a URI, and be in
+  /// the format of a YouTube video URL.
+  youtubeUrl("a YouTube URL, starting with '$youtubeUrlPrefix'");
+
+  static const youtubeUrlPrefix = 'https://www.youtube.com/watch?v=';
+
+  final String displayString;
+
+  const DocDirectiveParameterFormat(this.displayString);
+}
+
 /// A positional argument in a doc directive. See [DocDirective] for their
 /// syntax.
 @experimental
@@ -126,8 +159,14 @@
   /// https://github.com/dart-lang/dartdoc/wiki/Doc-comment-directives#animations.
   animation(
     'animation',
-    positionalParameters: ['width', 'height', 'url'],
-    namedParameters: ['id'],
+    positionalParameters: [
+      DocDirectiveParameter('width', DocDirectiveParameterFormat.integer),
+      DocDirectiveParameter('height', DocDirectiveParameterFormat.integer),
+      DocDirectiveParameter('url', DocDirectiveParameterFormat.uri),
+    ],
+    namedParameters: [
+      DocDirectiveParameter('id', DocDirectiveParameterFormat.any),
+    ],
   ),
 
   /// A [DocDirective] declaring the associated library is the "canonical"
@@ -147,7 +186,9 @@
     // directive name is a rare departure from that style. Migrate users to use
     // 'canonical-for'.
     'canonicalFor',
-    positionalParameters: ['element'],
+    positionalParameters: [
+      DocDirectiveParameter('element', DocDirectiveParameterFormat.any),
+    ],
   ),
 
   /// A [DocDirective] declaring a categorization into a named category.
@@ -191,8 +232,13 @@
   /// https://github.com/dart-lang/dartdoc/wiki/Doc-comment-directives#examples.
   example(
     'example',
-    positionalParameters: ['path'],
-    namedParameters: ['region', 'lang'],
+    positionalParameters: [
+      DocDirectiveParameter('path', DocDirectiveParameterFormat.any)
+    ],
+    namedParameters: [
+      DocDirectiveParameter('region', DocDirectiveParameterFormat.any),
+      DocDirectiveParameter('lang', DocDirectiveParameterFormat.any),
+    ],
   ),
 
   /// A [DocDirective] declaring a block of HTML content which is to be inserted
@@ -207,7 +253,12 @@
   /// This directive has one required argument: the name. For example:
   ///
   /// `{@macro some-macro}`
-  macro('macro', positionalParameters: ['name']),
+  macro(
+    'macro',
+    positionalParameters: [
+      DocDirectiveParameter('name', DocDirectiveParameterFormat.any),
+    ],
+  ),
 
   /// A [DocDirective] declaring a categorization into a named sub-category.
   ///
@@ -234,7 +285,13 @@
   /// See documentation at
   /// https://github.com/dart-lang/dartdoc/wiki/Doc-comment-directives#templates-and-macros.
   // TODO(srawlins): Migrate users to use 'end-template'.
-  template.block('template', 'endtemplate', positionalParameters: ['name']),
+  template.block(
+    'template',
+    'endtemplate',
+    positionalParameters: [
+      DocDirectiveParameter('name', DocDirectiveParameterFormat.any),
+    ],
+  ),
 
   /// A [DocDirective] declaring an embedded YouTube video.
   ///
@@ -245,7 +302,14 @@
   ///
   /// See documentation at
   /// https://github.com/dart-lang/dartdoc/wiki/Doc-comment-directives#youtube-videos.
-  youtube('youtube', positionalParameters: ['width', 'height', 'url']);
+  youtube(
+    'youtube',
+    positionalParameters: [
+      DocDirectiveParameter('width', DocDirectiveParameterFormat.integer),
+      DocDirectiveParameter('height', DocDirectiveParameterFormat.integer),
+      DocDirectiveParameter('url', DocDirectiveParameterFormat.youtubeUrl),
+    ],
+  );
 
   /// Whether this starts a block directive, which must be closed by a specific
   /// closing directive.
@@ -262,11 +326,11 @@
   /// in the case of a block directive's closing tag, and `null` otherwise.
   final String? opposingName;
 
-  /// The positional parameter names, which are each required.
-  final List<String> positionalParameters;
+  /// The positional parameters, which are each required.
+  final List<DocDirectiveParameter> positionalParameters;
 
-  /// The named parameter names, which are each optional.
-  final List<String> namedParameters;
+  /// The named parameters, which are each optional.
+  final List<DocDirectiveParameter> namedParameters;
 
   /// Whether "rest" parameters are allowed.
   ///
@@ -276,8 +340,8 @@
 
   const DocDirectiveType(
     this.name, {
-    this.positionalParameters = const <String>[],
-    this.namedParameters = const <String>[],
+    this.positionalParameters = const <DocDirectiveParameter>[],
+    this.namedParameters = const <DocDirectiveParameter>[],
     this.restParametersAllowed = false,
   })  : isBlock = false,
         opposingName = null;
@@ -285,9 +349,9 @@
   const DocDirectiveType.block(
     this.name,
     this.opposingName, {
-    this.positionalParameters = const <String>[],
+    this.positionalParameters = const <DocDirectiveParameter>[],
   })  : isBlock = true,
-        namedParameters = const <String>[],
+        namedParameters = const <DocDirectiveParameter>[],
         restParametersAllowed = false;
 
   const DocDirectiveType.end(
@@ -295,8 +359,8 @@
     required String openingTag,
   })  : opposingName = openingTag,
         isBlock = false,
-        positionalParameters = const <String>[],
-        namedParameters = const <String>[],
+        positionalParameters = const <DocDirectiveParameter>[],
+        namedParameters = const <DocDirectiveParameter>[],
         restParametersAllowed = false;
 }
 
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 19a02da..9dd326f 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -6056,6 +6056,15 @@
   );
 
   ///  Parameters:
+  ///  0: the name of the doc directive argument
+  ///  1: the expected format
+  static const WarningCode DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT = WarningCode(
+    'DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT',
+    "The '{0}' argument must be formatted as {1}.",
+    correctionMessage: "Try formatting '{0}' as {1}.",
+  );
+
+  ///  Parameters:
   ///  0: the name of the doc directive
   ///  1: the actual number of arguments
   ///  2: the expected number of arguments
diff --git a/pkg/analyzer/lib/src/error/doc_comment_verifier.dart b/pkg/analyzer/lib/src/error/doc_comment_verifier.dart
index 32faa15..5fcc176 100644
--- a/pkg/analyzer/lib/src/error/doc_comment_verifier.dart
+++ b/pkg/analyzer/lib/src/error/doc_comment_verifier.dart
@@ -2,6 +2,8 @@
 // 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 'dart:math' as math;
+
 import 'package:analyzer/dart/ast/doc_comment.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/error/codes.g.dart';
@@ -13,10 +15,6 @@
   DocCommentVerifier(this._errorReporter);
 
   void docDirective(DocDirective docDirective) {
-    // TODO(srawlins): Validate format of each parameter. For example, an
-    // animation directive's width must be an int, a youtube directive's URL
-    // must be a valid YouTube URL, etc.
-
     switch (docDirective) {
       case SimpleDocDirective():
         docDirectiveTag(docDirective.tag);
@@ -29,6 +27,30 @@
   }
 
   void docDirectiveTag(DocDirectiveTag tag) {
+    validateArgumentCount(tag);
+    validateArgumentFormat(tag);
+  }
+
+  /// Verifies doc imports, written as `@docImport`.
+  void docImport(DocImport docImport) {
+    var deferredKeyword = docImport.import.deferredKeyword;
+    if (deferredKeyword != null) {
+      _errorReporter.reportErrorForToken(
+        WarningCode.DOC_IMPORT_CANNOT_BE_DEFERRED,
+        deferredKeyword,
+      );
+    }
+    var configurations = docImport.import.configurations;
+    if (configurations.isNotEmpty) {
+      _errorReporter.reportErrorForOffset(
+        WarningCode.DOC_IMPORT_CANNOT_HAVE_CONFIGURATIONS,
+        configurations.first.offset,
+        configurations.last.end - configurations.first.offset,
+      );
+    }
+  }
+
+  void validateArgumentCount(DocDirectiveTag tag) {
     var positionalArgumentCount = tag.positionalArguments.length;
     var required = tag.type.positionalParameters;
     var requiredCount = tag.type.positionalParameters.length;
@@ -40,12 +62,12 @@
           WarningCode.DOC_DIRECTIVE_MISSING_ONE_ARGUMENT,
           tag.offset,
           tag.end - tag.offset,
-          [tag.type.name, required.last],
+          [tag.type.name, required.last.name],
         );
       } else if (gap == 2) {
         var missingArguments = [
-          required[required.length - 2],
-          required.last,
+          required[required.length - 2].name,
+          required.last.name,
         ];
         _errorReporter.reportErrorForOffset(
           WarningCode.DOC_DIRECTIVE_MISSING_TWO_ARGUMENTS,
@@ -55,9 +77,9 @@
         );
       } else if (gap == 3) {
         var missingArguments = [
-          required[required.length - 3],
-          required[required.length - 2],
-          required.last,
+          required[required.length - 3].name,
+          required[required.length - 2].name,
+          required.last.name,
         ];
         _errorReporter.reportErrorForOffset(
           WarningCode.DOC_DIRECTIVE_MISSING_THREE_ARGUMENTS,
@@ -86,7 +108,7 @@
     }
 
     for (var namedArgument in tag.namedArguments) {
-      if (!tag.type.namedParameters.contains(namedArgument.name)) {
+      if (!tag.type.namedParameters.containsNamed(namedArgument.name)) {
         _errorReporter.reportErrorForOffset(
           WarningCode.DOC_DIRECTIVE_HAS_UNEXPECTED_NAMED_ARGUMENT,
           namedArgument.offset,
@@ -97,22 +119,45 @@
     }
   }
 
-  /// Verifies doc imports, written as `@docImport`.
-  void docImport(DocImport docImport) {
-    var deferredKeyword = docImport.import.deferredKeyword;
-    if (deferredKeyword != null) {
-      _errorReporter.reportErrorForToken(
-        WarningCode.DOC_IMPORT_CANNOT_BE_DEFERRED,
-        deferredKeyword,
-      );
-    }
-    var configurations = docImport.import.configurations;
-    if (configurations.isNotEmpty) {
-      _errorReporter.reportErrorForOffset(
-        WarningCode.DOC_IMPORT_CANNOT_HAVE_CONFIGURATIONS,
-        configurations.first.offset,
-        configurations.last.end - configurations.first.offset,
-      );
+  void validateArgumentFormat(DocDirectiveTag tag) {
+    var required = tag.type.positionalParameters;
+    var positionalArgumentCount =
+        math.min(tag.positionalArguments.length, required.length);
+    for (var i = 0; i < positionalArgumentCount; i++) {
+      var parameter = required[i];
+      var argument = tag.positionalArguments[i];
+
+      void reportWrongFormat() {
+        _errorReporter.reportErrorForOffset(
+          WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT,
+          argument.offset,
+          argument.end - argument.offset,
+          [parameter.name, parameter.expectedFormat.displayString],
+        );
+      }
+
+      switch (parameter.expectedFormat) {
+        case DocDirectiveParameterFormat.any:
+          continue;
+        case DocDirectiveParameterFormat.integer:
+          if (int.tryParse(argument.value) == null) {
+            reportWrongFormat();
+          }
+        case DocDirectiveParameterFormat.uri:
+          if (Uri.tryParse(argument.value) == null) {
+            reportWrongFormat();
+          }
+        case DocDirectiveParameterFormat.youtubeUrl:
+          if (Uri.tryParse(argument.value) == null ||
+              !argument.value
+                  .startsWith(DocDirectiveParameterFormat.youtubeUrlPrefix)) {
+            reportWrongFormat();
+          }
+      }
     }
   }
 }
+
+extension on List<DocDirectiveParameter> {
+  bool containsNamed(String name) => any((p) => p.name == name);
+}
diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart
index 84ffdc5..eee0503 100644
--- a/pkg/analyzer/lib/src/error/error_code_values.g.dart
+++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart
@@ -950,6 +950,7 @@
   WarningCode.DEPRECATED_IMPLEMENTS_FUNCTION,
   WarningCode.DEPRECATED_MIXIN_FUNCTION,
   WarningCode.DEPRECATED_NEW_IN_COMMENT_REFERENCE,
+  WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT,
   WarningCode.DOC_DIRECTIVE_HAS_EXTRA_ARGUMENTS,
   WarningCode.DOC_DIRECTIVE_HAS_UNEXPECTED_NAMED_ARGUMENT,
   WarningCode.DOC_DIRECTIVE_MISSING_CLOSING_BRACE,
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 350a8b0f..8dd209c 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -22161,6 +22161,14 @@
       Parameters:
       0: the name of the doc directive
       1: the name of the missing argument
+  DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT:
+    problemMessage: "The '{0}' argument must be formatted as {1}."
+    correctionMessage: "Try formatting '{0}' as {1}."
+    hasPublishedDocs: false
+    comment: |-
+      Parameters:
+      0: the name of the doc directive argument
+      1: the expected format
   DOC_DIRECTIVE_MISSING_OPENING_TAG:
     problemMessage: "Doc directive is missing an opening tag."
     correctionMessage: "Try opening the directive with the appropriate opening tag, '{0}'."
diff --git a/pkg/analyzer/test/src/diagnostics/doc_directive_argument_wrong_format_test.dart b/pkg/analyzer/test/src/diagnostics/doc_directive_argument_wrong_format_test.dart
new file mode 100644
index 0000000..809e638
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/doc_directive_argument_wrong_format_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2023, 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/error/codes.g.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(DocDirectiveArgumentWrongFormatTest);
+  });
+}
+
+@reflectiveTest
+class DocDirectiveArgumentWrongFormatTest extends PubPackageResolutionTest {
+  test_animation_heightWrongFormat() async {
+    await assertErrorsInCode('''
+/// {@animation 600 nan http://google.com}
+class C {}
+''', [
+      error(WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT, 20, 3),
+    ]);
+  }
+
+  test_animation_urlWrongFormat() async {
+    await assertNoErrorsInCode('''
+/// {@animation 600 400 other}
+class C {}
+''');
+  }
+
+  test_animation_widthWrongFormat() async {
+    await assertErrorsInCode('''
+/// {@animation nan 400 http://google.com}
+class C {}
+''', [
+      error(WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT, 16, 3),
+    ]);
+  }
+
+  test_youtube_heightWrongFormat() async {
+    await assertErrorsInCode('''
+/// {@youtube 600 nan https://www.youtube.com/watch?v=123}
+class C {}
+''', [
+      error(WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT, 18, 3),
+    ]);
+  }
+
+  test_youtube_urlWrongFormat() async {
+    await assertErrorsInCode('''
+/// {@youtube 600 400 http://google.com}
+class C {}
+''', [
+      error(WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT, 22, 17),
+    ]);
+  }
+
+  test_youtube_widthWrongFormat() async {
+    await assertErrorsInCode('''
+/// {@youtube nan 400 https://www.youtube.com/watch?v=123}
+class C {}
+''', [
+      error(WarningCode.DOC_DIRECTIVE_ARGUMENT_WRONG_FORMAT, 14, 3),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/doc_directive_has_extra_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/doc_directive_has_extra_arguments_test.dart
index ea9b703..2cfac36 100644
--- a/pkg/analyzer/test/src/diagnostics/doc_directive_has_extra_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/doc_directive_has_extra_arguments_test.dart
@@ -49,25 +49,25 @@
 
   test_youtube_hasExtraArgument() async {
     await assertErrorsInCode('''
-/// {@youtube 600 400 http://google.com foo}
+/// {@youtube 600 400 https://www.youtube.com/watch?v=123 foo}
 class C {}
 ''', [
-      error(WarningCode.DOC_DIRECTIVE_HAS_EXTRA_ARGUMENTS, 40, 3),
+      error(WarningCode.DOC_DIRECTIVE_HAS_EXTRA_ARGUMENTS, 58, 3),
     ]);
   }
 
   test_youtube_hasExtraArgument_trailingWhitespace() async {
     await assertErrorsInCode('''
-/// {@youtube 600 400 http://google.com foo }
+/// {@youtube 600 400 https://www.youtube.com/watch?v=123 foo }
 class C {}
 ''', [
-      error(WarningCode.DOC_DIRECTIVE_HAS_EXTRA_ARGUMENTS, 40, 3),
+      error(WarningCode.DOC_DIRECTIVE_HAS_EXTRA_ARGUMENTS, 58, 3),
     ]);
   }
 
   test_youtube_noExtraArguments() async {
     await assertNoErrorsInCode('''
-/// {@youtube 600 400 http://google.com}
+/// {@youtube 600 400 https://www.youtube.com/watch?v=123}
 class C {}
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/doc_directive_missing_one_argument_test.dart b/pkg/analyzer/test/src/diagnostics/doc_directive_missing_one_argument_test.dart
index 195e162..bbc8bea 100644
--- a/pkg/analyzer/test/src/diagnostics/doc_directive_missing_one_argument_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/doc_directive_missing_one_argument_test.dart
@@ -56,7 +56,7 @@
 
   test_youtube_hasThreeArguments() async {
     await assertNoErrorsInCode('''
-/// {@youtube 600 400 http://google.com}
+/// {@youtube 600 400 https://www.youtube.com/watch?v=123}
 class C {}
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/doc_directive_missing_three_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/doc_directive_missing_three_arguments_test.dart
index 1619ede..496631d 100644
--- a/pkg/analyzer/test/src/diagnostics/doc_directive_missing_three_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/doc_directive_missing_three_arguments_test.dart
@@ -33,7 +33,7 @@
 
   test_youtube_hasWidth() async {
     await assertNoErrorsInCode('''
-/// {@youtube 600 400 http://google.com}
+/// {@youtube 600 400 https://www.youtube.com/watch?v=123}
 class C {}
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/doc_directive_missing_two_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/doc_directive_missing_two_arguments_test.dart
index 029efef..6bcc8a8 100644
--- a/pkg/analyzer/test/src/diagnostics/doc_directive_missing_two_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/doc_directive_missing_two_arguments_test.dart
@@ -40,7 +40,7 @@
 
   test_youtube_hasThreeArguments() async {
     await assertNoErrorsInCode('''
-/// {@youtube 600 400 http://google.com}
+/// {@youtube 600 400 https://www.youtube.com/watch?v=123}
 class C {}
 ''');
   }
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 56ca51a..15a8145 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -167,6 +167,8 @@
 import 'deprecated_member_use_test.dart' as deprecated_member_use;
 import 'deprecated_mixin_function_test.dart' as deprecated_mixin_function;
 import 'division_optimization_test.dart' as division_optimization;
+import 'doc_directive_argument_wrong_format_test.dart'
+    as doc_directive_argument_wrong_format;
 import 'doc_directive_has_extra_arguments_test.dart'
     as doc_directive_has_extra_arguments;
 import 'doc_directive_has_unexpected_named_argument_test.dart'
@@ -1026,6 +1028,7 @@
     deprecated_member_use.main();
     deprecated_mixin_function.main();
     division_optimization.main();
+    doc_directive_argument_wrong_format.main();
     doc_directive_has_extra_arguments.main();
     doc_directive_has_unexpected_named_argument.main();
     doc_directive_missing_one_argument.main();