Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 73 additions & 13 deletions src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,24 @@
sorted.UserData[key] = original.UserData[key];
}

var emptyParamList = new List<CodeParameterDeclarationExpression>();

var sortedMembers = original.Members.OfType<CodeTypeMember>()
.OrderBy(m => m.Attributes.HasFlag(MemberAttributes.Static))
.ThenBy(m => m.GetType().Name, StringComparer.Ordinal)
.ThenBy(m => m is CodeMemberMethod ? CSharpOperatorKeyword.Get(m.Name) : m.Name, StringComparer.Ordinal)
.ThenBy(m => m is CodeMemberMethod method
? method.TypeParameters.Count
: 0)
.ThenBy(m => m is CodeMemberMethod method
? method.Parameters.Count
: 0)
? method.TypeParameters.Count
: 0)
.ThenBy(m => m is CodeMemberMethod method
? method.Parameters.OfType<CodeParameterDeclarationExpression>().ToList()
: emptyParamList,
new ParamListComparer());
? method.Parameters.Count
: 0)
.ThenBy(m => m is CodeMemberMethod method && method.Parameters.Count > 0
? method.Parameters.OfType<CodeParameterDeclarationExpression>().ToList()
: [],
ParamListComparer.Instance)
.ThenBy(m => m is CodeMemberMethod method && method.TypeParameters.Count > 0
? method.TypeParameters.OfType<CodeTypeParameter>().ToList()
: [],
TypeParamListComparer.Instance);

foreach (var member in sortedMembers)
{
Expand All @@ -66,6 +68,8 @@

private class ParamListComparer : IComparer<List<CodeParameterDeclarationExpression>>
{
public static readonly ParamListComparer Instance = new();

public int Compare(List<CodeParameterDeclarationExpression> x, List<CodeParameterDeclarationExpression> y)
{
var paramIndex = 0;
Expand All @@ -92,14 +96,21 @@

private int Compare(CodeTypeReference x, CodeTypeReference y)
{
var baseType = string.CompareOrdinal(x.BaseType, y.BaseType);
string GetBaseType(CodeTypeReference r)
{
return r.BaseType == "System.Nullable`1" && r.TypeArguments.Count == 1
? r.TypeArguments[0].BaseType + "?"
: r.BaseType;
}

var baseType = string.CompareOrdinal(GetBaseType(x), GetBaseType(y));
if (baseType != 0)
{
return baseType;
}

var typeArgsX = x.TypeArguments.OfType<CodeTypeReference>().ToList();
var typeArgsY = y.TypeArguments.OfType<CodeTypeReference>().ToList();
var typeArgsX = x.BaseType == "System.Nullable`1" && x.TypeArguments.Count == 1 ? [] : x.TypeArguments.OfType<CodeTypeReference>().ToList();
var typeArgsY = y.BaseType == "System.Nullable`1" && y.TypeArguments.Count == 1 ? [] : y.TypeArguments.OfType<CodeTypeReference>().ToList();

var typeArgIndex = 0;
for (; typeArgIndex < typeArgsX.Count; ++typeArgIndex)
Expand All @@ -119,4 +130,53 @@
return typeArgIndex < typeArgsY.Count ? -1 : 0;
}
}

private class TypeParamListComparer : IComparer<List<CodeTypeParameter>>
{
public static readonly TypeParamListComparer Instance = new();

public int Compare(List<CodeTypeParameter> x, List<CodeTypeParameter> y)
{
var paramIndex = 0;
for (; paramIndex < x.Count; ++paramIndex)
{
var paramX = x[paramIndex];
var paramY = y[paramIndex];

var name = string.CompareOrdinal(paramX.Name, paramY.Name);
if (name != 0)
{
return name;

Check warning on line 149 in src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs#L148-L149

Added lines #L148 - L149 were not covered by tests
}

var constraints = Compare(paramX.Constraints, paramY.Constraints);
if (constraints != 0)
{
return constraints;
}
}

Check warning on line 157 in src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs#L157

Added line #L157 was not covered by tests

return paramIndex < y.Count ? -1 : 0;
}

private int Compare(CodeTypeReferenceCollection x, CodeTypeReferenceCollection y)
{
var count = x.Count.CompareTo(y.Count);
if (count != 0)
{
return count;

Check warning on line 167 in src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs#L166-L167

Added lines #L166 - L167 were not covered by tests
}

for (int i = 0; i < x.Count; ++i)
{
var baseType = x[i].BaseType.CompareTo(y[i].BaseType);
if (baseType != 0)
{
return baseType;
}
}

Check warning on line 177 in src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs#L177

Added line #L177 was not covered by tests

return 0;

Check warning on line 179 in src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/PublicApiGenerator/CodeTypeDeclarationExtensions.cs#L179

Added line #L179 was not covered by tests
}
}
}
37 changes: 37 additions & 0 deletions src/PublicApiGeneratorTests/ConstraintsOrdering.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using PublicApiGeneratorTests.Examples;

namespace PublicApiGeneratorTests
{
public class ConstraintsOrdering : ApiGeneratorTestsBase
{
[Fact]
public void Should_Order_Class_First()
{
AssertPublicApi(typeof(ClassWithNullableSignatureOfDifferentConstraint),
"""
namespace PublicApiGeneratorTests.Examples
{
public static class ClassWithNullableSignatureOfDifferentConstraint
{
public static T ShouldNotBeNull<T>([System.Diagnostics.CodeAnalysis.NotNull] this T? actual, string? customMessage = null)
where T : class { }
public static T ShouldNotBeNull<T>([System.Diagnostics.CodeAnalysis.NotNull] this T? actual, string? customMessage = null)
where T : struct { }
}
}
""");
}
}

namespace Examples
{
public static class ClassWithNullableSignatureOfDifferentConstraint
{
public static T ShouldNotBeNull<T>([System.Diagnostics.CodeAnalysis.NotNull] this T? actual, string? customMessage = null)
where T : struct => throw null;

public static T ShouldNotBeNull<T>([System.Diagnostics.CodeAnalysis.NotNull] this T? actual, string? customMessage = null)
where T : class => throw null;
}
}
}