Skip to content

Commit

Permalink
Populate custom attributes on type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
danielmarbach committed Jun 30, 2019
1 parent a548b85 commit 4da56b1
Showing 1 changed file with 15 additions and 9 deletions.
24 changes: 15 additions & 9 deletions src/PublicApiGenerator/ApiGenerator.cs
Expand Up @@ -226,7 +226,7 @@ static CodeTypeDeclaration CreateTypeDeclaration(TypeDefinition publicType, stri
if (declaration.IsInterface && publicType.BaseType != null)
throw new NotImplementedException("Base types for interfaces needs testing");

PopulateGenericParameters(publicType, declaration.TypeParameters);
PopulateGenericParameters(publicType, declaration.TypeParameters, excludeAttributes);

if (publicType.BaseType != null && ShouldOutputBaseType(publicType))
{
Expand Down Expand Up @@ -280,7 +280,7 @@ static CodeTypeDeclaration CreateDelegateDeclaration(TypeDefinition publicType,

// CodeDOM. No support. Return type attributes.
PopulateCustomAttributes(invokeMethod.MethodReturnType, declaration.CustomAttributes, type => ModifyCodeTypeReference(type, "return:"), excludeAttributes);
PopulateGenericParameters(publicType, declaration.TypeParameters);
PopulateGenericParameters(publicType, declaration.TypeParameters, excludeAttributes);
PopulateMethodParameters(invokeMethod, declaration.Parameters, excludeAttributes);

// Of course, CodeDOM doesn't support generic type parameters for delegates. Of course.
Expand All @@ -299,26 +299,32 @@ static bool ShouldOutputBaseType(TypeDefinition publicType)
return publicType.BaseType.FullName != "System.Object" && publicType.BaseType.FullName != "System.ValueType";
}

static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters)
static void PopulateGenericParameters(IGenericParameterProvider publicType, CodeTypeParameterCollection parameters, HashSet<string> excludeAttributes)
{
foreach (var parameter in publicType.GenericParameters)
{
if (parameter.HasCustomAttributes)
throw new NotImplementedException("Attributes on type parameters is not supported. And weird");

// A little hacky. Means we get "in" and "out" prefixed on any constraints, but it's either that
// or add it as a custom attribute, which looks even weirder
// or add it as a custom attribute
var name = parameter.Name;
if (parameter.IsCovariant)
name = "out " + name;
if (parameter.IsContravariant)
name = "in " + name;

var attributeCollection = new CodeAttributeDeclarationCollection();
if (parameter.HasCustomAttributes)
{
PopulateCustomAttributes(parameter, attributeCollection, excludeAttributes);
}

var typeParameter = new CodeTypeParameter(name)
{
HasConstructorConstraint =
parameter.HasDefaultConstructorConstraint && !parameter.HasNotNullableValueTypeConstraint
};

typeParameter.CustomAttributes.AddRange(attributeCollection.OfType<CodeAttributeDeclaration>().ToArray());

if (parameter.HasNotNullableValueTypeConstraint)
typeParameter.Constraints.Add(" struct"); // Extra space is a hack!
if (parameter.HasReferenceTypeConstraint)
Expand Down Expand Up @@ -428,7 +434,7 @@ static string ConvertAttributeToCode(Func<CodeTypeReference, CodeTypeReference>
static bool ShouldIncludeAttribute(CustomAttribute attribute, HashSet<string> excludeAttributes)
{
var attributeTypeDefinition = attribute.AttributeType.Resolve();
return attributeTypeDefinition != null && !excludeAttributes.Contains(attribute.AttributeType.FullName) && attributeTypeDefinition.IsPublic;
return attributeTypeDefinition != null && !excludeAttributes.Contains(attribute.AttributeType.FullName) && (attributeTypeDefinition.IsPublic || attributeTypeDefinition.FullName == "System.Runtime.CompilerServices.NullableAttribute");
}

static CodeExpression CreateInitialiserExpression(CustomAttributeArgument attributeArgument)
Expand Down Expand Up @@ -558,7 +564,7 @@ static void AddMethodToTypeDeclaration(CodeTypeDeclaration typeDeclaration, Meth
ReturnType = returnType,
};
PopulateCustomAttributes(member.MethodReturnType, method.ReturnTypeCustomAttributes, excludeAttributes);
PopulateGenericParameters(member, method.TypeParameters);
PopulateGenericParameters(member, method.TypeParameters, excludeAttributes);
PopulateMethodParameters(member, method.Parameters, excludeAttributes, IsExtensionMethod(member));

typeDeclaration.Members.Add(method);
Expand Down

0 comments on commit 4da56b1

Please sign in to comment.