diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs index 0b097fbe8a..883b634e78 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs +++ b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs @@ -83,7 +83,7 @@ internal ICollection EnumerateAssembly(string assemblyFileName, Assembly assembly = PlatformServiceProvider.Instance.FileOperations.LoadAssembly(assemblyFileName, isReflectionOnly: false); - IReadOnlyList types = GetTypes(assembly, assemblyFileName, warningMessages); + Type[] types = GetTypes(assembly, assemblyFileName, warningMessages); bool discoverInternals = ReflectHelper.GetDiscoverInternalsAttribute(assembly) != null; TestIdGenerationStrategy testIdGenerationStrategy = ReflectHelper.GetTestIdGenerationStrategy(assembly); diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs index 386891f596..916c7da27a 100644 --- a/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs +++ b/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs @@ -106,7 +106,7 @@ internal static bool HasCorrectTestContextSignature(Type type) { DebugEx.Assert(type != null, "HasCorrectTestContextSignature type is null"); - IEnumerable propertyInfoEnumerable = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredProperties(type); + PropertyInfo[] propertyInfoEnumerable = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredProperties(type); var propertyInfo = new List(); foreach (PropertyInfo pinfo in propertyInfoEnumerable) diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs b/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs index 5b07edca36..6ab6227133 100644 --- a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs +++ b/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs @@ -259,7 +259,7 @@ private static bool TryGetUnescapedManagedTypeName(TestMethod testMethod, [NotNu /// The . private TestClassInfo CreateClassInfo(Type classType, TestMethod testMethod) { - IEnumerable constructors = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredConstructors(classType); + ConstructorInfo[] constructors = PlatformServiceProvider.Instance.ReflectionOperations.GetDeclaredConstructors(classType); (ConstructorInfo CtorInfo, bool IsParameterless)? selectedConstructor = null; foreach (ConstructorInfo ctor in constructors) @@ -399,7 +399,7 @@ private TestAssemblyInfo GetAssemblyInfo(Type type) assemblyInfo = new TestAssemblyInfo(assembly); - IReadOnlyList types = AssemblyEnumerator.GetTypes(assembly, assembly.FullName!, null); + Type[] types = AssemblyEnumerator.GetTypes(assembly, assembly.FullName!, null); foreach (Type t in types) { diff --git a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs index c69b9bbdc4..19877998ab 100644 --- a/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs +++ b/src/Adapter/MSTest.TestAdapter/SourceGeneration/SourceGeneratedReflectionOperations.cs @@ -50,16 +50,16 @@ public object[] GetCustomAttributes(Assembly assembly, Type /* the attribute typ return attributes.ToArray(); } - public IEnumerable GetDeclaredConstructors(Type classType) + public ConstructorInfo[] GetDeclaredConstructors(Type classType) => ReflectionDataProvider.TypeConstructors[classType]; public MethodInfo? GetDeclaredMethod(Type dynamicDataDeclaringType, string dynamicDataSourceName) => GetDeclaredMethods(dynamicDataDeclaringType).FirstOrDefault(m => m.Name == dynamicDataSourceName); - public IEnumerable GetDeclaredMethods(Type classType) + public MethodInfo[] GetDeclaredMethods(Type classType) => ReflectionDataProvider.TypeMethods[classType]; - public IEnumerable GetDeclaredProperties(Type type) + public PropertyInfo[] GetDeclaredProperties(Type type) => ReflectionDataProvider.TypeProperties[type]; public PropertyInfo? GetDeclaredProperty(Type type, string propertyName) @@ -68,7 +68,7 @@ public IEnumerable GetDeclaredProperties(Type type) public Type[] GetDefinedTypes(Assembly assembly) => ReflectionDataProvider.Types; - public IEnumerable GetRuntimeMethods(Type type) + public MethodInfo[] GetRuntimeMethods(Type type) => ReflectionDataProvider.TypeMethods[type]; public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters) => throw new NotImplementedException(); diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations2.cs b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations2.cs index 4e651384d6..7de179b9f6 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations2.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations2.cs @@ -7,19 +7,19 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Int internal interface IReflectionOperations2 : IReflectionOperations { - IEnumerable GetDeclaredConstructors(Type classType); + ConstructorInfo[] GetDeclaredConstructors(Type classType); MethodInfo? GetDeclaredMethod(Type dynamicDataDeclaringType, string dynamicDataSourceName); - IEnumerable GetDeclaredMethods(Type classType); + MethodInfo[] GetDeclaredMethods(Type classType); - IEnumerable GetDeclaredProperties(Type type); + PropertyInfo[] GetDeclaredProperties(Type type); PropertyInfo? GetDeclaredProperty(Type type, string propertyName); Type[] GetDefinedTypes(Assembly assembly); - IEnumerable GetRuntimeMethods(Type type); + MethodInfo[] GetRuntimeMethods(Type type); MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters); diff --git a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs index 9fd567d020..653a5d7499 100644 --- a/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs +++ b/src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations2.cs @@ -9,6 +9,9 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices; internal sealed class ReflectionOperations2 : ReflectionOperations, IReflectionOperations2 { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + private const BindingFlags Everything = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; + public ReflectionOperations2() { #if NET8_0_OR_GREATER @@ -23,26 +26,26 @@ public ReflectionOperations2() #pragma warning disable IL2026 // Members attributed with RequiresUnreferencedCode may break when trimming #pragma warning disable IL2067 // 'target parameter' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to 'target method'. #pragma warning disable IL2057 // Unrecognized value passed to the typeName parameter of 'System.Type.GetType(String)' - public IEnumerable GetDeclaredConstructors(Type classType) - => classType.GetTypeInfo().DeclaredConstructors; + public ConstructorInfo[] GetDeclaredConstructors(Type classType) + => classType.GetConstructors(DeclaredOnlyLookup); public MethodInfo? GetDeclaredMethod(Type type, string methodName) - => type.GetTypeInfo().GetDeclaredMethod(methodName); + => type.GetMethod(methodName, DeclaredOnlyLookup); - public IEnumerable GetDeclaredMethods(Type classType) - => classType.GetTypeInfo().DeclaredMethods; + public MethodInfo[] GetDeclaredMethods(Type classType) + => classType.GetMethods(DeclaredOnlyLookup); - public IEnumerable GetDeclaredProperties(Type type) - => type.GetTypeInfo().DeclaredProperties; + public PropertyInfo[] GetDeclaredProperties(Type type) + => type.GetProperties(DeclaredOnlyLookup); public PropertyInfo? GetDeclaredProperty(Type type, string propertyName) - => type.GetTypeInfo().GetDeclaredProperty(propertyName); + => type.GetProperty(propertyName, DeclaredOnlyLookup); public Type[] GetDefinedTypes(Assembly assembly) - => assembly.DefinedTypes.ToArray(); + => assembly.GetTypes(); - public IEnumerable GetRuntimeMethods(Type type) - => type.GetRuntimeMethods(); + public MethodInfo[] GetRuntimeMethods(Type type) + => type.GetMethods(Everything); public MethodInfo? GetRuntimeMethod(Type declaringType, string methodName, Type[] parameters) => declaringType.GetRuntimeMethod(methodName, parameters); diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs index c34c2d834f..77d616faae 100644 --- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs +++ b/test/UnitTests/MSTestAdapter.UnitTests/Discovery/AssemblyEnumeratorTests.cs @@ -101,7 +101,7 @@ public void GetTypesShouldReturnSetOfDefinedTypes() TypeInfo[] expectedTypes = [typeof(DummyTestClass).GetTypeInfo(), typeof(DummyTestClass).GetTypeInfo()]; // Setup mocks - mockAssembly.Setup(a => a.DefinedTypes).Returns(expectedTypes); + mockAssembly.Setup(a => a.GetTypes()).Returns(expectedTypes); IReadOnlyList types = AssemblyEnumerator.GetTypes(mockAssembly.Object, string.Empty, _warnings); Verify(expectedTypes.SequenceEqual(types)); @@ -123,7 +123,7 @@ public void GetTypesShouldReturnReflectionTypeLoadExceptionTypesOnException() var reflectedTypes = new Type[] { typeof(DummyTestClass) }; // Setup mocks - mockAssembly.Setup(a => a.DefinedTypes).Throws(new ReflectionTypeLoadException(reflectedTypes, null)); + mockAssembly.Setup(a => a.GetTypes()).Throws(new ReflectionTypeLoadException(reflectedTypes, null)); IReadOnlyList types = AssemblyEnumerator.GetTypes(mockAssembly.Object, string.Empty, _warnings); @@ -137,8 +137,8 @@ public void GetTypesShouldLogWarningsWhenReflectionFailsWithLoaderExceptions() var exceptions = new Exception[] { new("DummyLoaderException") }; // Setup mocks - mockAssembly.Setup(a => a.DefinedTypes).Throws(new ReflectionTypeLoadException(null, exceptions)); - mockAssembly.Setup(a => a.DefinedTypes).Throws(new ReflectionTypeLoadException(null, exceptions)); + mockAssembly.Setup(a => a.GetTypes()).Throws(new ReflectionTypeLoadException(null, exceptions)); + mockAssembly.Setup(a => a.GetTypes()).Throws(new ReflectionTypeLoadException(null, exceptions)); IReadOnlyList types = AssemblyEnumerator.GetTypes(mockAssembly.Object, "DummyAssembly", _warnings); @@ -237,7 +237,7 @@ public void EnumerateAssemblyShouldReturnEmptyListWhenNoTestElementsInAType() // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); @@ -256,7 +256,7 @@ public void EnumerateAssemblyShouldReturnTestElementsForAType() // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); @@ -278,7 +278,7 @@ public void EnumerateAssemblyShouldReturnMoreThanOneTestElementForAType() // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); @@ -300,7 +300,7 @@ public void EnumerateAssemblyShouldReturnMoreThanOneTestElementForMoreThanOneTyp // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass), typeof(DummyTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(DummyTestClass).GetTypeInfo(), typeof(DummyTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); @@ -323,7 +323,7 @@ public void EnumerateAssemblyShouldNotLogWarningsIfNonePresent() // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(InternalTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(InternalTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); @@ -345,7 +345,7 @@ public void EnumerateAssemblyShouldLogWarningsIfPresent() // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(InternalTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(InternalTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object); @@ -365,7 +365,7 @@ public void EnumerateAssemblyShouldHandleExceptionsWhileEnumeratingAType() // Setup mocks mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(InternalTestClass)]); - mockAssembly.Setup(a => a.DefinedTypes) + mockAssembly.Setup(a => a.GetTypes()) .Returns([typeof(InternalTestClass).GetTypeInfo()]); _testablePlatformServiceProvider.MockFileOperations.Setup(fo => fo.LoadAssembly("DummyAssembly", false)) .Returns(mockAssembly.Object);