Skip to content

Commit

Permalink
feat: Support custom attributes in generic parameters.
Browse files Browse the repository at this point in the history
For nullability support.

Mono.Cecil introduced a breaking change in jbevain/cecil#594 because of dotnet/roslyn#29997
  • Loading branch information
amanda-tarafa authored and jskeet committed Aug 4, 2021
1 parent 50a3e27 commit 3fed752
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 4 deletions.
10 changes: 10 additions & 0 deletions tools/Google.Cloud.Tools.VersionCompat.Tests/ClassMethodTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ namespace GenericConstraintChanged2.B { public class C { public void A<T, U>() w
namespace GenericConstraintChanged3.A { public class C { public void A<T, U>() where T : IList<T> where U : IList<T> { } } }
namespace GenericConstraintChanged3.B { public class C { public void A<T, U>() where T : IList<U> where U : IList<T> { } } }

// TODO: Shouldn't this be enable?
#nullable disable
namespace GenericConstraintChanged4.A { public class C { public void A<T>() where T : IList<T> { } } }
namespace GenericConstraintChanged4.B { public class C { public void A<T>() where T : IList<T>? { } } }

#nullable restore

namespace MethodModiferChanged1.A { public abstract class C { public virtual int A() => 0; } }
namespace MethodModiferChanged1.B { public abstract class C { public int A() => 0; } }

Expand Down Expand Up @@ -137,6 +144,9 @@ public class ClassMethodTest : TestBase
((Level.Major, Cause.MethodGenericConstraintChanged), (Level.Minor, Cause.MethodGenericConstraintChanged));
[Fact] public void GenericConstraintChanged3() => Test()
((Level.Major, Cause.MethodGenericConstraintChanged), (Level.Minor, Cause.MethodGenericConstraintChanged));
[Fact]
public void GenericConstraintChanged4() => Test()
((Level.Major, Cause.MethodGenericConstraintChanged), (Level.Minor, Cause.MethodGenericConstraintChanged));
[Fact] public void MethodModiferChanged1() => TestMajor(Cause.MethodModifierChanged);
[Fact] public void MethodModiferChanged2() => TestMajor(Cause.MethodModifierChanged);
[Fact] public void MethodModiferChanged3() => TestMajor(Cause.MethodModifierChanged);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Mono.Cecil;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;

namespace Google.Cloud.Tools.VersionCompat.CecilUtils
{
/// <summary>
/// GenericParameterConstraint comparer that compares GenericParameterConstraint
/// on their ConstraintType using the SameTypeComparar and on the types of the
/// CustomAttributes.
/// See https://github.com/dotnet/roslyn/issues/29997
/// </summary>
internal class SameGenericParameterConstraintComparer : IEqualityComparer<GenericParameterConstraint>
{
public static SameGenericParameterConstraintComparer Instance { get; } = new SameGenericParameterConstraintComparer();

private SameGenericParameterConstraintComparer() { }

public bool Equals(GenericParameterConstraint x, GenericParameterConstraint y)
{
if (x is null && y is null)
{
return true;
}
if (x is null || y is null)
{
return false;
}

return SameTypeComparer.Instance.Equals(x.ConstraintType, y.ConstraintType)
&& x.CustomAttributes.Select(attr => attr.AttributeType).ToImmutableHashSet(SameTypeComparer.Instance)
.SetEquals(y.CustomAttributes.Select(attr => attr.AttributeType).ToImmutableHashSet(SameTypeComparer.Instance));
}

public int GetHashCode(GenericParameterConstraint obj)
{
if (obj is null)
{
return 0;
}
var hashCode = SameTypeComparer.Instance.GetHashCode(obj?.ConstraintType);
foreach (var typ in obj.CustomAttributes.Select(attr => attr.AttributeType).ToImmutableHashSet(SameTypeComparer.Instance).OrderBy(typ => typ.FullName))
{
hashCode ^= SameTypeComparer.Instance.GetHashCode(typ);
}

return hashCode;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ public IEnumerable<Diff> ImplementedInterfaces()
(Cause.MethodGenericConstraintChanged, Cause.MethodGenericVarianceChanged);
foreach (var (o, n) in oGenericParameters.Zip(nGenericParameters))
{
// TODO: Check `unmanaged` constaint.
// TODO: Check `unmanaged` constraint.
if ((!o.HasReferenceTypeConstraint && n.HasReferenceTypeConstraint) ||
(!o.HasNotNullableValueTypeConstraint && n.HasNotNullableValueTypeConstraint) ||
(!o.HasDefaultConstructorConstraint && n.HasDefaultConstructorConstraint) ||
!n.Constraints.ToImmutableHashSet(SameTypeComparer.Instance).IsSubsetOf(o.Constraints))
!n.Constraints.ToImmutableHashSet(SameGenericParameterConstraintComparer.Instance).IsSubsetOf(o.Constraints))
{
yield return Diff.Major(causeConstraint, $"{prefix} changed constraint on generic parameter '{n}'");
}
if ((!n.HasReferenceTypeConstraint && o.HasReferenceTypeConstraint) ||
(!n.HasNotNullableValueTypeConstraint && o.HasNotNullableValueTypeConstraint) ||
(!n.HasDefaultConstructorConstraint && o.HasDefaultConstructorConstraint) ||
!o.Constraints.ToImmutableHashSet(SameTypeComparer.Instance).IsSubsetOf(n.Constraints))
!o.Constraints.ToImmutableHashSet(SameGenericParameterConstraintComparer.Instance).IsSubsetOf(n.Constraints))
{
yield return Diff.Minor(causeConstraint, $"{prefix} changed constraint on generic parameter '{n}'");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.4" />
<PackageReference Include="SharpCompress" Version="0.28.3" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.1" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
</ItemGroup>

</Project>

0 comments on commit 3fed752

Please sign in to comment.