xamarin-macios/tests/cecil-tests/ObsoleteTest.cs

136 строки
3.9 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using NUnit.Framework;
using Mono.Cecil;
#nullable enable
namespace Cecil.Tests {
[TestFixture]
public class ObsoleteTest {
[TestCaseSource (typeof (Helper), nameof (Helper.NetPlatformImplementationAssemblies))] // call this method with every .net6 library
public void GetAllObsoletedThings (string assemblyPath)
{
var assembly = Helper.GetAssembly (assemblyPath, readSymbols: true);
// Make a list of Obsolete things
var found = new HashSet<string> ();
foreach (var prop in Helper.FilterProperties (assembly, a => FilterMember (a))) {
if (Skip (prop))
continue;
Console.WriteLine ($"{GetLocation (prop.GetMethod ?? prop.SetMethod)} {prop.FullName}");
found.Add (prop.FullName);
}
foreach (var meth in Helper.FilterMethods (assembly, a => FilterMember (a))) {
if (Skip (meth))
continue;
Console.WriteLine ($"{GetLocation (meth)} {meth.FullName}");
found.Add (meth.FullName);
}
foreach (var type in Helper.FilterTypes (assembly, a => FilterMember (a))) {
if (Skip (type))
continue;
Console.WriteLine ($"{GetLocation (type.Methods.FirstOrDefault ())} {type.FullName}");
found.Add (type.FullName);
}
// TODO: Events?
Assert.That (found, Is.Empty, "Obsolete API");
}
bool FilterMember (ICustomAttributeProvider provider)
{
// If an API isn't obsolete, it's not under scrutiny from this test.
if (!HasObsoleteAttribute (provider))
return false;
// If the API has an UnsupportedOSPlatform attribute with a version, it means the API is available
// on earlier OS versions, which means we can't remove it.
if (HasVersionedUnsupportedOSPlatformAttribute (provider))
return false;
#if !XAMCORE_5_0
// If we've hidden an API from the IDE, assume we've decided to keep the API for binary compatibility
// At least until the next time we can do breaking changes.
if (HasEditorBrowseableNeverAttribute (provider))
return false;
#endif
// I'm bad!
return true;
}
bool HasObsoleteAttribute (ICustomAttributeProvider provider) => HasObsoleteAttribute (provider.CustomAttributes);
bool HasObsoleteAttribute (IEnumerable<CustomAttribute> attributes) => attributes.Any (a => IsObsoleteAttribute (a));
bool IsObsoleteAttribute (CustomAttribute attribute) => attribute.AttributeType.Name == "Obsolete" || (attribute.AttributeType.Name == "ObsoleteAttribute");
bool HasVersionedUnsupportedOSPlatformAttribute (ICustomAttributeProvider provider)
{
if (provider?.HasCustomAttributes != true)
return false;
foreach (var attr in provider.CustomAttributes) {
if (attr.AttributeType.Name != "UnsupportedOSPlatformAttribute")
continue;
var platform = (string) attr.ConstructorArguments [0].Value;
// is this a platform string with a version?
foreach (var ch in platform) {
if (ch >= '0' && ch <= '9')
return true;
}
}
// no UnsupportedOSPlatform attribute with a version here
return false;
}
bool HasEditorBrowseableNeverAttribute (ICustomAttributeProvider provider)
{
if (provider?.HasCustomAttributes != true)
return false;
foreach (var attr in provider.CustomAttributes) {
if (attr.AttributeType.Name != "EditorBrowsableAttribute")
continue;
var state = (EditorBrowsableState) attr.ConstructorArguments [0].Value;
if (state == EditorBrowsableState.Never)
return true;
}
return false;
}
bool Skip (MemberReference member)
{
var ns = member.FullName.Split ('.') [0];
switch (ns) {
default:
return false;
}
}
static string GetLocation (MethodDefinition method)
{
if (method is null)
return "<no location> ";
if (method.DebugInformation.HasSequencePoints) {
var seq = method.DebugInformation.SequencePoints [0];
return seq.Document.Url + ":" + seq.StartLine + " ";
}
return string.Empty;
}
}
}