* Check implementation assemblies instead of reference assemblies. * Try to print the source code location for failing API (this required processing the implementation assemblies, because the reference assemblies don't have debug information where the source code location is stored). * Don't report API that has [EditorBrowsable (None)] attributes, presumably we decided to keep these for compatibility, while highly discouraging their continued use. Also stop doing this for the next time we can do a breaking change, maybe we can remove these APIs then. * Don't report API that has [UnsupportedOSPlatform ("...#.#") attributes (with a version number), presumably this is API that is still valid for some OS versions. * Enable the test for all APIs (no ignores anymore). It's green! Fixes https://github.com/xamarin/xamarin-macios/issues/13621.
This commit is contained in:
Родитель
4bda73fc82
Коммит
df491ed4b3
|
@ -19,7 +19,7 @@ namespace Cecil.Tests {
|
|||
static Dictionary<string, AssemblyDefinition> cache = new Dictionary<string, AssemblyDefinition> ();
|
||||
|
||||
// make sure we load assemblies only once into memory
|
||||
public static AssemblyDefinition? GetAssembly (string assembly, ReaderParameters? parameters = null)
|
||||
public static AssemblyDefinition? GetAssembly (string assembly, ReaderParameters? parameters = null, bool readSymbols = false)
|
||||
{
|
||||
if (!File.Exists (assembly))
|
||||
return null;
|
||||
|
@ -29,6 +29,7 @@ namespace Cecil.Tests {
|
|||
resolver.AddSearchDirectory (GetBCLDirectory (assembly));
|
||||
parameters = new ReaderParameters () {
|
||||
AssemblyResolver = resolver,
|
||||
ReadSymbols = readSymbols,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -179,6 +180,8 @@ namespace Cecil.Tests {
|
|||
|
||||
public static IEnumerable NetPlatformAssemblies => Configuration.GetRefLibraries ();
|
||||
|
||||
public static IEnumerable NetPlatformImplementationAssemblies => Configuration.GetBaseLibraryImplementations ();
|
||||
|
||||
public static IEnumerable TaskAssemblies {
|
||||
get {
|
||||
yield return CreateTestFixtureDataFromPath (Path.Combine (Configuration.SdkRootXI, "lib", "msbuild", "iOS", "Xamarin.iOS.Tasks.dll"));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
@ -13,40 +14,60 @@ namespace Cecil.Tests {
|
|||
[TestFixture]
|
||||
public class ObsoleteTest {
|
||||
|
||||
[TestCaseSource (typeof (Helper), "NetPlatformAssemblies")] // call this method with every .net6 library
|
||||
[TestCaseSource (typeof (Helper), nameof (Helper.NetPlatformImplementationAssemblies))] // call this method with every .net6 library
|
||||
public void GetAllObsoletedThings (string assemblyPath)
|
||||
{
|
||||
var assembly = Helper.GetAssembly (assemblyPath);
|
||||
if (assembly is null) {
|
||||
Assert.Ignore ("{assemblyPath} could not be found (might be disabled in build)");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine (assemblyPath);
|
||||
var assembly = Helper.GetAssembly (assemblyPath, readSymbols: true)!;
|
||||
Assert.That (assembly, Is.Not.Null, "Must find the assembly");
|
||||
|
||||
// Make a list of Obsolete things
|
||||
HashSet<string> found = new HashSet<string> ();
|
||||
var found = new HashSet<string> ();
|
||||
|
||||
foreach (var prop in Helper.FilterProperties (assembly, a => HasObsoleteAttribute (a))) {
|
||||
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 => HasObsoleteAttribute (a))) {
|
||||
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 => HasObsoleteAttribute (a))) {
|
||||
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");
|
||||
}
|
||||
|
||||
Assert.That (found, Is.Empty, string.Join (Environment.NewLine, found));
|
||||
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);
|
||||
|
@ -55,15 +76,62 @@ namespace Cecil.Tests {
|
|||
|
||||
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];
|
||||
|
||||
// Skipping all namespaces until issue https://github.com/xamarin/xamarin-macios/issues/13621 is fixed
|
||||
switch (ns) {
|
||||
default:
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -760,6 +760,13 @@ namespace Xamarin.Tests
|
|||
return variable.Split (new char [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetBaseLibraryImplementations ()
|
||||
{
|
||||
foreach (var platform in GetIncludedPlatforms (true))
|
||||
foreach (var lib in GetBaseLibraryImplementations (platform))
|
||||
yield return lib;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> GetBaseLibraryImplementations (ApplePlatform platform)
|
||||
{
|
||||
var runtimeIdentifiers = GetRuntimeIdentifiers (platform);
|
||||
|
|
Загрузка…
Ссылка в новой задаче