diff --git a/lib/src/render/parameter_renderer.dart b/lib/src/render/parameter_renderer.dart index 9ad69a77f0..9a21adc132 100644 --- a/lib/src/render/parameter_renderer.dart +++ b/lib/src/render/parameter_renderer.dart @@ -164,6 +164,22 @@ abstract class ParameterRenderer { : modelType.returnType.linkedName; buffer.write(typeName(returnTypeName)); buffer.write(' ${parameterName(param.name)}'); + + // Writes out the generic type parameters for a function type. + // TODO(kallentu): Pull this type parameter generation into a helper for + // other renderers that also do this same work. + if (modelType is FunctionTypeElementType) { + if (modelType.typeFormals.isNotEmpty) { + if (!modelType.typeFormals.every((t) => t.name == 'dynamic')) { + buffer + ..write('<') + ..writeAll(modelType.typeFormals.map((t) => t.name), + ', ') + ..write('>'); + } + } + } + if (!modelType.isTypedef && modelType is DefinedElementType) { buffer.write('('); buffer.write(renderLinkedParams( diff --git a/test/parameter_test.dart b/test/parameter_test.dart index 79a01fe507..359c8b6a27 100644 --- a/test/parameter_test.dart +++ b/test/parameter_test.dart @@ -22,70 +22,102 @@ class ParameterTest extends DartdocTestBase { @override String get sdkConstraint => '>=2.17.0 <3.0.0'; - void test_requiredPositionalFieldFormalParameter() async { + void test_formalParameter_generic_method() async { var library = await bootPackageWithLibrary(''' -class A { - int? f; - A.requiredPositional(this.f); +class C { + C() {} + int one(int Function(T)? f) { + return 1; + } } '''); - var requiredPositional = library.constructor('A.requiredPositional'); + var one = library.method('C', 'one'); + expect(one.linkedParams, matchesCompressed(r''' + + + int + + f + < + T + >\( + + T + + \)\? + + ''')); + } - expect(requiredPositional.linkedParams, matchesCompressed(r''' - + void test_formalParameter_generic_topLevelFunction() async { + var library = await bootPackageWithLibrary(''' +int one(int Function(T)? f) { + return 1; +} +'''); + var one = library.publicFunctions.firstWhere((c) => c.name == 'one'); + expect(one.linkedParams, matchesCompressed(r''' + - int\? + int f + < + T + >\( + + T + + \)\? ''')); } - void test_optionalPositionalFieldFormalParameter() async { + void test_formalParameter_named() async { var library = await bootPackageWithLibrary(''' class A { int? f; - A.optionalPositional([this.f]); + A.named({this.f}); } '''); - var optionalPositional = library.constructor('A.optionalPositional'); + var named = library.constructor('A.named'); - expect(optionalPositional.linkedParams, matchesCompressed(r''' - - \[ + expect(named.linkedParams, matchesCompressed(r''' + + \{ int\? f - \] + \} ''')); } - void test_optionalPositionalFieldFormalParameterWithDefaultValue() async { + void test_formalParameter_named_defaultValue() async { var library = await bootPackageWithLibrary(''' class A { int? f; - A.defaultValue([this.f = 0]); + A.namedWithDefault({this.f = 0}); } '''); - var defaultValue = library.constructor('A.defaultValue'); + var namedWithDefault = library.constructor('A.namedWithDefault'); - expect(defaultValue.linkedParams, matchesCompressed(r''' - - \[ + expect(namedWithDefault.linkedParams, matchesCompressed(r''' + + \{ int\? f = 0 - \] + \} ''')); } - void test_requiredNamedFieldFormalParameter() async { + void test_formalParameter_named_required() async { var library = await bootPackageWithLibrary(''' class A { int? f; @@ -107,144 +139,137 @@ class A { ''')); } - void test_namedFieldFormalParameter() async { + void test_formalParameter_positional_optional() async { var library = await bootPackageWithLibrary(''' class A { int? f; - A.named({this.f}); + A.optionalPositional([this.f]); } '''); - var named = library.constructor('A.named'); + var optionalPositional = library.constructor('A.optionalPositional'); - expect(named.linkedParams, matchesCompressed(r''' - - \{ + expect(optionalPositional.linkedParams, matchesCompressed(r''' + + \[ int\? f - \} + \] ''')); } - void test_namedFieldFormalParameterWithDefaultValue() async { + void test_formalParameter_positional_optional_defaultValue() async { var library = await bootPackageWithLibrary(''' class A { int? f; - A.namedWithDefault({this.f = 0}); + A.defaultValue([this.f = 0]); } '''); - var namedWithDefault = library.constructor('A.namedWithDefault'); + var defaultValue = library.constructor('A.defaultValue'); - expect(namedWithDefault.linkedParams, matchesCompressed(r''' - - \{ + expect(defaultValue.linkedParams, matchesCompressed(r''' + + \[ int\? f = 0 - \} + \] ''')); } - void test_requiredPositionalSuperParameter() async { + void test_formalParameter_positional_required() async { var library = await bootPackageWithLibrary(''' -class C { - C.requiredPositional(int a); -} -class D extends C { - D.requiredPositional(super.a) : super.requiredPositional(); +class A { + int? f; + A.requiredPositional(this.f); } '''); - var requiredPositional = library.constructor('D.requiredPositional'); + var requiredPositional = library.constructor('A.requiredPositional'); expect(requiredPositional.linkedParams, matchesCompressed(r''' - + - int + int\? - a + f ''')); } - void test_optionalPositionalSuperParameter() async { + void test_superConstructorParameter_fieldFormal() async { var library = await bootPackageWithLibrary(''' class C { - C.optionalPositional([int? a]); + int f; + C.fieldFormal(this.f); } class D extends C { - D.optionalPositional([super.a]) : super.optionalPositional(); + D.fieldFormal(super.f) : super.fieldFormal(); } '''); - var optionalPositional = library.constructor('D.optionalPositional'); + var fieldFormal = library.constructor('D.fieldFormal'); - expect(optionalPositional.linkedParams, matchesCompressed(r''' - - \[ + expect(fieldFormal.linkedParams, matchesCompressed(r''' + - int\? + int - a - \] + f ''')); } - void test_optionalPositionalSuperParameterWithDefault() async { + void test_superConstructorParameter_isSubtype() async { var library = await bootPackageWithLibrary(''' class C { - C.defaultValue([int a = 0]); + C.positionalNum(num g); } class D extends C { - D.defaultValue([super.a = 0]) : super.defaultValue(); + D.positionalNum(int super.g) : super.positionalNum(); } '''); - var defaultValue = library.constructor('D.defaultValue'); + var positionalNum = library.constructor('D.positionalNum'); - expect(defaultValue.linkedParams, matchesCompressed(r''' - - \[ + expect(positionalNum.linkedParams, matchesCompressed(r''' + int - a - = - 0 - \] + g ''')); } - void test_requiredNamedSuperParameters() async { + void test_superConstructorParameter_superParameter() async { var library = await bootPackageWithLibrary(''' class C { - C.requiredNamed({required int a}); + C.requiredPositional(int a); } class D extends C { - D.requiredNamed({required super.a}) : super.requiredNamed(); + D.requiredPositional(super.a) : super.requiredPositional(); +} +class E extends D { + E.superIsSuper(super.a) : super.requiredPositional(); } '''); - var requiredNamed = library.constructor('D.requiredNamed'); + var superIsSuper = library.constructor('E.superIsSuper'); - expect(requiredNamed.linkedParams, matchesCompressed(r''' - - \{ - required + expect(superIsSuper.linkedParams, matchesCompressed(r''' + int a - \} ''')); } - void test_namedSuperParameter() async { + void test_superParameter_named() async { var library = await bootPackageWithLibrary(''' class C { C.named({int? a}); @@ -267,7 +292,7 @@ class D extends C { ''')); } - void test_namedSuperParameterWithDefault() async { + void test_superParameter_named_default() async { var library = await bootPackageWithLibrary(''' class C { C.namedWithDefault({int a = 0}); @@ -292,69 +317,95 @@ class D extends C { ''')); } - void test_superConstructorParameterIsFieldFormal() async { + void test_superParameter_named_required() async { var library = await bootPackageWithLibrary(''' class C { - int f; - C.fieldFormal(this.f); + C.requiredNamed({required int a}); } class D extends C { - D.fieldFormal(super.f) : super.fieldFormal(); + D.requiredNamed({required super.a}) : super.requiredNamed(); } '''); - var fieldFormal = library.constructor('D.fieldFormal'); + var requiredNamed = library.constructor('D.requiredNamed'); - expect(fieldFormal.linkedParams, matchesCompressed(r''' - + expect(requiredNamed.linkedParams, matchesCompressed(r''' + + \{ + required int - f + a + \} ''')); } - void test_superConstructorParameterIsSuperParameter() async { + void test_superParameter_positional_optional() async { var library = await bootPackageWithLibrary(''' class C { - C.requiredPositional(int a); + C.optionalPositional([int? a]); } class D extends C { - D.requiredPositional(super.a) : super.requiredPositional(); + D.optionalPositional([super.a]) : super.optionalPositional(); } -class E extends D { - E.superIsSuper(super.a) : super.requiredPositional(); +'''); + var optionalPositional = library.constructor('D.optionalPositional'); + + expect(optionalPositional.linkedParams, matchesCompressed(r''' + + \[ + + int\? + + a + \] + + ''')); + } + + void test_superParameter_positional_optional_default() async { + var library = await bootPackageWithLibrary(''' +class C { + C.defaultValue([int a = 0]); +} +class D extends C { + D.defaultValue([super.a = 0]) : super.defaultValue(); } '''); - var superIsSuper = library.constructor('E.superIsSuper'); + var defaultValue = library.constructor('D.defaultValue'); - expect(superIsSuper.linkedParams, matchesCompressed(r''' - + expect(defaultValue.linkedParams, matchesCompressed(r''' + + \[ int a + = + 0 + \] ''')); } - void test_parameterIsSubtypeOfSuperConstructorParameter() async { + void test_superParameter_positional_required() async { var library = await bootPackageWithLibrary(''' class C { - C.positionalNum(num g); + C.requiredPositional(int a); } class D extends C { - D.positionalNum(int super.g) : super.positionalNum(); + D.requiredPositional(super.a) : super.requiredPositional(); } '''); - var positionalNum = library.constructor('D.positionalNum'); + var requiredPositional = library.constructor('D.requiredPositional'); - expect(positionalNum.linkedParams, matchesCompressed(r''' - + expect(requiredPositional.linkedParams, matchesCompressed(r''' + int - g + a ''')); } @@ -368,4 +419,9 @@ extension on Library { .constructors .firstWhere((c) => c.name == name); } + + Method method(String className, String methodName) => classes + .firstWhere((clas) => clas.name == className) + .declaredMethods + .firstWhere((method) => method.name == methodName); }