Add nullability suffix to callback parameters - Fixes #2477 (#2478)

* Add nullability suffix to callback parameters - Fixes #2477

* Add end2end rendering test
diff --git a/lib/src/render/parameter_renderer.dart b/lib/src/render/parameter_renderer.dart
index fffbd46..dd1a2f7 100644
--- a/lib/src/render/parameter_renderer.dart
+++ b/lib/src/render/parameter_renderer.dart
@@ -185,6 +185,7 @@
         buf.write(renderLinkedParams(paramModelType.element.parameters,
             showMetadata: showMetadata, showNames: showNames));
         buf.write(')');
+        buf.write(paramModelType.nullabilitySuffix);
       }
       if (!paramModelType.isTypedef && paramModelType.type is FunctionType) {
         buf.write('(');
@@ -193,6 +194,7 @@
             showMetadata: showMetadata,
             showNames: showNames));
         buf.write(')');
+        buf.write(paramModelType.nullabilitySuffix);
       }
     } else if (param.modelType != null) {
       var linkedTypeName = paramModelType.linkedName;
diff --git a/test/end2end/model_special_cases_test.dart b/test/end2end/model_special_cases_test.dart
index ac0015a..e6f2114 100644
--- a/test/end2end/model_special_cases_test.dart
+++ b/test/end2end/model_special_cases_test.dart
@@ -89,6 +89,7 @@
         optOutOfNullSafety,
         nullableElements;
     Class b;
+    Class c;
 
     setUpAll(() async {
       lateFinalWithoutInitializer = (await _testPackageGraphExperiments)
@@ -105,6 +106,8 @@
           .firstWhere((lib) => lib.name == 'nullable_elements');
       b = nullSafetyClassMemberDeclarations.allClasses
           .firstWhere((c) => c.name == 'B');
+      c = nullSafetyClassMemberDeclarations.allClasses
+          .firstWhere((c) => c.name == 'C');
     });
 
     test('isNullSafety is set correctly for libraries', () {
@@ -154,6 +157,24 @@
               '</ol>'));
     });
 
+    test('anonymous callback parameters are correctly marked as nullable', () {
+      var m3 = c.instanceMethods.firstWhere((m) => m.name == 'm3');
+      var listen = m3.allParameters.firstWhere((p) => p.name == 'listen');
+      var onDone = m3.allParameters.firstWhere((p) => p.name == 'onDone');
+      expect(listen.isRequiredPositional, isTrue);
+      expect(onDone.isNamed, isTrue);
+
+      expect(
+          m3.linkedParamsLines,
+          equals(
+              '<ol class="parameter-list"><li><span class="parameter" id="m3-param-listen"><span class="type-annotation">void</span> <span class="parameter-name">listen</span>(<ol class="parameter-list"><li><span class="parameter" id="param-t"><span class="type-annotation">int</span> <span class="parameter-name">t</span></span></li>\n'
+              '</ol>\n'
+              ')?, </span></li>\n'
+              '<li><span class="parameter" id="m3-param-onDone">{<span class="type-annotation">void</span> <span class="parameter-name">onDone</span>(<ol class="parameter-list"></ol>\n'
+              ')?}</span></li>\n'
+              '</ol>'));
+    });
+
     test('Late final class member test', () {
       var c = lateFinalWithoutInitializer.allClasses
           .firstWhere((c) => c.name == 'C');
diff --git a/testing/test_package_experiments/lib/nnbd_class_member_declarations.dart b/testing/test_package_experiments/lib/nnbd_class_member_declarations.dart
index 4687944..7d13186 100644
--- a/testing/test_package_experiments/lib/nnbd_class_member_declarations.dart
+++ b/testing/test_package_experiments/lib/nnbd_class_member_declarations.dart
@@ -26,4 +26,6 @@
   List<int?> get testFieldNullableParameter => [];
 
   List<Map<String, num?>>? method1() => null;
+
+  void m3(void listen(int t)?, {void onDone()?});
 }