From 9574f08d4902b18e9db2deb01b2b0e74526fa401 Mon Sep 17 00:00:00 2001
From: Youssef1313 <youssefvictor00@gmail.com>
Date: Fri, 17 Jan 2025 14:21:14 +0100
Subject: [PATCH] Simplify reflection

---
 .../Discovery/AssemblyEnumerator.cs           |  2 +-
 .../Discovery/TestMethodValidator.cs          |  2 +-
 .../Discovery/TypeValidator.cs                |  2 +-
 .../Execution/TestClassInfo.cs                | 10 +--
 .../Execution/TestMethodInfo.cs               |  8 +-
 .../Execution/TestMethodRunner.cs             |  4 +-
 .../MSTest.TestAdapter/Execution/TypeCache.cs | 14 ++--
 .../Helpers/AttributeComparer.cs              | 14 ----
 .../Helpers/ReflectHelper.cs                  | 82 ++++---------------
 .../Discovery/TestMethodValidatorTests.cs     |  4 +-
 .../Discovery/TypeValidatorTests.cs           |  4 +-
 .../Execution/TypeCacheTests.cs               | 30 +++----
 .../Helpers/ReflectHelperTests.cs             | 10 +--
 13 files changed, 59 insertions(+), 127 deletions(-)
 delete mode 100644 src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs

diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
index 74654b6bca..69c5d1e277 100644
--- a/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
+++ b/src/Adapter/MSTest.TestAdapter/Discovery/AssemblyEnumerator.cs
@@ -359,7 +359,7 @@ private static bool TryUnfoldITestDataSources(UnitTestElement test, TestMethodIn
         // We don't have a special method to filter attributes that are not derived from Attribute, so we take all
         // attributes and filter them. We don't have to care if there is one, because this method is only entered when
         // there is at least one (we determine this in TypeEnumerator.GetTestFromMethod.
-        IEnumerable<ITestDataSource> testDataSources = ReflectHelper.Instance.GetDerivedAttributes<Attribute>(testMethodInfo.MethodInfo, inherit: false).OfType<ITestDataSource>();
+        IEnumerable<ITestDataSource> testDataSources = ReflectHelper.Instance.GetAttributes<Attribute>(testMethodInfo.MethodInfo, inherit: false).OfType<ITestDataSource>();
 
         // We need to use a temporary list to avoid adding tests to the main list if we fail to expand any data source.
         List<UnitTestElement> tempListOfTests = new();
diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs
index 2669c119ad..043a3e7d60 100644
--- a/src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs
+++ b/src/Adapter/MSTest.TestAdapter/Discovery/TestMethodValidator.cs
@@ -53,7 +53,7 @@ internal virtual bool IsValidTestMethod(MethodInfo testMethodInfo, Type type, IC
         // but the difference is quite small, and we don't expect a huge amount of non-test methods in the assembly.
         //
         // Also skip all methods coming from object, because they cannot be tests.
-        if (testMethodInfo.DeclaringType == typeof(object) || !_reflectHelper.IsDerivedAttributeDefined<TestMethodAttribute>(testMethodInfo, inherit: false))
+        if (testMethodInfo.DeclaringType == typeof(object) || !_reflectHelper.IsAttributeDefined<TestMethodAttribute>(testMethodInfo, inherit: false))
         {
             return false;
         }
diff --git a/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs b/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs
index 9e8e1c98d6..b82623ca7c 100644
--- a/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs
+++ b/src/Adapter/MSTest.TestAdapter/Discovery/TypeValidator.cs
@@ -52,7 +52,7 @@ internal virtual bool IsValidTestClass(Type type, List<string> warnings)
         // gives us a better performance.
         // It would be possible to use non-caching reflection here if we knew that we are only doing discovery that won't be followed by run,
         // but the difference is quite small, and we don't expect a huge amount of non-test classes in the assembly.
-        if (!type.IsClass || !_reflectHelper.IsDerivedAttributeDefined<TestClassAttribute>(type, inherit: false))
+        if (!type.IsClass || !_reflectHelper.IsAttributeDefined<TestClassAttribute>(type, inherit: false))
         {
             return false;
         }
diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs b/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs
index 2139e2340b..4d5261ecd3 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/TestClassInfo.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
 using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions;
@@ -411,7 +411,7 @@ internal UnitTestResult GetResultOrRunClassInitialize(ITestContext testContext,
 
             DebugEx.Assert(!IsClassInitializeExecuted, "If class initialize was executed, we should have been in the previous if were we have a result available.");
 
-            bool isSTATestClass = AttributeComparer.IsDerived<STATestClassAttribute>(ClassAttribute);
+            bool isSTATestClass = ClassAttribute is STATestClassAttribute;
             bool isWindowsOS = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
             if (isSTATestClass
                 && isWindowsOS
@@ -631,7 +631,7 @@ internal void ExecuteClassCleanup(TestContext testContext)
                 if (classCleanupMethod is not null)
                 {
                     if (ClassAttribute.IgnoreMessage is null &&
-                        !ReflectHelper.Instance.IsNonDerivedAttributeDefined<IgnoreAttribute>(classCleanupMethod.DeclaringType!, false))
+                        !ReflectHelper.Instance.IsAttributeDefined<IgnoreAttribute>(classCleanupMethod.DeclaringType!, false))
                     {
                         ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, remainingCleanupCount: BaseClassCleanupMethods.Count, testContext);
                     }
@@ -643,7 +643,7 @@ internal void ExecuteClassCleanup(TestContext testContext)
                     {
                         classCleanupMethod = BaseClassCleanupMethods[i];
                         if (ClassAttribute.IgnoreMessage is null &&
-                            !ReflectHelper.Instance.IsNonDerivedAttributeDefined<IgnoreAttribute>(classCleanupMethod.DeclaringType!, false))
+                            !ReflectHelper.Instance.IsAttributeDefined<IgnoreAttribute>(classCleanupMethod.DeclaringType!, false))
                         {
                             ClassCleanupException = InvokeCleanupMethod(classCleanupMethod, remainingCleanupCount: BaseClassCleanupMethods.Count - 1 - i, testContext);
                             if (ClassCleanupException is not null)
@@ -711,7 +711,7 @@ internal void RunClassCleanup(ITestContext testContext, ClassCleanupManager clas
             return;
         }
 
-        bool isSTATestClass = AttributeComparer.IsDerived<STATestClassAttribute>(ClassAttribute);
+        bool isSTATestClass = ClassAttribute is STATestClassAttribute;
         bool isWindowsOS = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
         if (isSTATestClass
             && isWindowsOS
diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs b/src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs
index 4085813c23..6551b6c106 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/TestMethodInfo.cs
@@ -95,11 +95,11 @@ internal TestMethodInfo(
 
     internal RetryBaseAttribute? RetryAttribute { get; }
 
-    public Attribute[]? GetAllAttributes(bool inherit) => ReflectHelper.Instance.GetDerivedAttributes<Attribute>(TestMethod, inherit).ToArray();
+    public Attribute[]? GetAllAttributes(bool inherit) => ReflectHelper.Instance.GetAttributes<Attribute>(TestMethod, inherit).ToArray();
 
     public TAttributeType[] GetAttributes<TAttributeType>(bool inherit)
         where TAttributeType : Attribute
-        => ReflectHelper.Instance.GetDerivedAttributes<TAttributeType>(TestMethod, inherit).ToArray();
+        => ReflectHelper.Instance.GetAttributes<TAttributeType>(TestMethod, inherit).ToArray();
 
     /// <summary>
     /// Execute test method. Capture failures, handle async and return result.
@@ -231,7 +231,7 @@ public virtual TestResult Invoke(object?[]? arguments)
 
         try
         {
-            expectedExceptions = ReflectHelper.Instance.GetDerivedAttributes<ExpectedExceptionBaseAttribute>(TestMethod, inherit: true);
+            expectedExceptions = ReflectHelper.Instance.GetAttributes<ExpectedExceptionBaseAttribute>(TestMethod, inherit: true);
         }
         catch (Exception ex)
         {
@@ -267,7 +267,7 @@ public virtual TestResult Invoke(object?[]? arguments)
     /// </returns>
     private RetryBaseAttribute? GetRetryAttribute()
     {
-        IEnumerable<RetryBaseAttribute> attributes = ReflectHelper.Instance.GetDerivedAttributes<RetryBaseAttribute>(TestMethod, inherit: true);
+        IEnumerable<RetryBaseAttribute> attributes = ReflectHelper.Instance.GetAttributes<RetryBaseAttribute>(TestMethod, inherit: true);
         using IEnumerator<RetryBaseAttribute> enumerator = attributes.GetEnumerator();
         if (!enumerator.MoveNext())
         {
diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs b/src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs
index 249301cd2d..1c4ddb68f3 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/TestMethodRunner.cs
@@ -64,8 +64,8 @@ public TestMethodRunner(TestMethodInfo testMethodInfo, TestMethod testMethod, IT
     /// <returns>The test results.</returns>
     internal List<TestResult> Execute(string initializationLogs, string initializationErrorLogs, string initializationTrace, string initializationTestContextMessages)
     {
-        bool isSTATestClass = AttributeComparer.IsDerived<STATestClassAttribute>(_testMethodInfo.Parent.ClassAttribute);
-        bool isSTATestMethod = AttributeComparer.IsDerived<STATestMethodAttribute>(_testMethodInfo.TestMethodOptions.Executor);
+        bool isSTATestClass = _testMethodInfo.Parent.ClassAttribute is STATestClassAttribute;
+        bool isSTATestMethod = _testMethodInfo.TestMethodOptions.Executor is STATestMethodAttribute;
         bool isSTARequested = isSTATestClass || isSTATestMethod;
         bool isWindowsOS = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
         if (isSTARequested && isWindowsOS && Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
diff --git a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs b/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs
index 2b13c8384d..8323241a16 100644
--- a/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs
+++ b/src/Adapter/MSTest.TestAdapter/Execution/TypeCache.cs
@@ -397,7 +397,7 @@ private TestAssemblyInfo GetAssemblyInfo(Type type)
             try
             {
                 // Only examine classes which are TestClass or derives from TestClass attribute
-                if (!_reflectionHelper.IsDerivedAttributeDefined<TestClassAttribute>(t, inherit: false))
+                if (!_reflectionHelper.IsAttributeDefined<TestClassAttribute>(t, inherit: false))
                 {
                     continue;
                 }
@@ -448,7 +448,7 @@ private bool IsAssemblyOrClassInitializeMethod<TInitializeAttribute>(MethodInfo
         // {
         //    return false;
         // }
-        if (!_reflectionHelper.IsNonDerivedAttributeDefined<TInitializeAttribute>(methodInfo, false))
+        if (!_reflectionHelper.IsAttributeDefined<TInitializeAttribute>(methodInfo, false))
         {
             return false;
         }
@@ -476,7 +476,7 @@ private bool IsAssemblyOrClassCleanupMethod<TCleanupAttribute>(MethodInfo method
         // {
         //    return false;
         // }
-        if (!_reflectionHelper.IsNonDerivedAttributeDefined<TCleanupAttribute>(methodInfo, false))
+        if (!_reflectionHelper.IsAttributeDefined<TCleanupAttribute>(methodInfo, false))
         {
             return false;
         }
@@ -607,8 +607,8 @@ private void UpdateInfoIfTestInitializeOrCleanupMethod(
         bool isBase,
         Dictionary<string, string?> instanceMethods)
     {
-        bool hasTestInitialize = _reflectionHelper.IsNonDerivedAttributeDefined<TestInitializeAttribute>(methodInfo, inherit: false);
-        bool hasTestCleanup = _reflectionHelper.IsNonDerivedAttributeDefined<TestCleanupAttribute>(methodInfo, inherit: false);
+        bool hasTestInitialize = _reflectionHelper.IsAttributeDefined<TestInitializeAttribute>(methodInfo, inherit: false);
+        bool hasTestCleanup = _reflectionHelper.IsAttributeDefined<TestCleanupAttribute>(methodInfo, inherit: false);
 
         if (!hasTestCleanup && !hasTestInitialize)
         {
@@ -833,12 +833,12 @@ private void SetCustomProperties(TestMethodInfo testMethodInfo, ITestContext tes
         DebugEx.Assert(testMethodInfo != null, "testMethodInfo is Null");
         DebugEx.Assert(testMethodInfo.TestMethod != null, "testMethodInfo.TestMethod is Null");
 
-        IEnumerable<TestPropertyAttribute> attributes = _reflectionHelper.GetDerivedAttributes<TestPropertyAttribute>(testMethodInfo.TestMethod, inherit: true);
+        IEnumerable<TestPropertyAttribute> attributes = _reflectionHelper.GetAttributes<TestPropertyAttribute>(testMethodInfo.TestMethod, inherit: true);
         DebugEx.Assert(attributes != null, "attributes is null");
 
         if (testMethodInfo.TestMethod.DeclaringType is { } testClass)
         {
-            attributes = attributes.Concat(_reflectionHelper.GetDerivedAttributes<TestPropertyAttribute>(testClass, inherit: true));
+            attributes = attributes.Concat(_reflectionHelper.GetAttributes<TestPropertyAttribute>(testClass, inherit: true));
         }
 
         foreach (TestPropertyAttribute attribute in attributes)
diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs b/src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs
deleted file mode 100644
index c82f46d996..0000000000
--- a/src/Adapter/MSTest.TestAdapter/Helpers/AttributeComparer.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
-
-internal static class AttributeComparer
-{
-    public static bool IsNonDerived<TAttribute>(Attribute attribute) =>
-        // We are explicitly checking the given type *exactly*. We don't want to consider inheritance.
-        // So, this should NOT be refactored to 'attribute is TAttribute'.
-        attribute.GetType() == typeof(TAttribute);
-
-    public static bool IsDerived<TAttribute>(Attribute attribute) => attribute is TAttribute;
-}
diff --git a/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs b/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs
index 7dcd86d56d..9800bd70ce 100644
--- a/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs
+++ b/src/Adapter/MSTest.TestAdapter/Helpers/ReflectHelper.cs
@@ -28,35 +28,6 @@ internal class ReflectHelper : MarshalByRefObject
 
     public static ReflectHelper Instance => InstanceValue.Value;
 
-    /// <summary>
-    /// Checks to see if a member or type is decorated with the given attribute. The type is checked exactly. If attribute is derived (inherits from) a class, e.g. [MyTestClass] from [TestClass] it won't match if you look for [TestClass]. The inherit parameter does not impact this checking.
-    /// </summary>
-    /// <remarks>
-    /// Note that because derived attribute types are not considered, <typeparamref name="TAttribute"/> should be sealed.
-    /// </remarks>
-    /// <typeparam name="TAttribute">Attribute to search for by fully qualified name.</typeparam>
-    /// <param name="memberInfo">Member/Type to test.</param>
-    /// <param name="inherit">Inspect inheritance chain of the member or class. E.g. if parent class has this attribute defined.</param>
-    /// <returns>True if the attribute of the specified type is defined on this member or a class.</returns>
-    public virtual bool IsNonDerivedAttributeDefined<TAttribute>(MemberInfo memberInfo, bool inherit)
-        where TAttribute : Attribute
-    {
-        Guard.NotNull(memberInfo);
-
-        // Get attributes defined on the member from the cache.
-        Attribute[] attributes = GetCustomAttributesCached(memberInfo, inherit);
-
-        foreach (Attribute attribute in attributes)
-        {
-            if (AttributeComparer.IsNonDerived<TAttribute>(attribute))
-            {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
     /// <summary>
     /// Checks to see if a member or type is decorated with the given attribute, or an attribute that derives from it. e.g. [MyTestClass] from [TestClass] will match if you look for [TestClass]. The inherit parameter does not impact this checking.
     /// </summary>
@@ -64,7 +35,7 @@ public virtual bool IsNonDerivedAttributeDefined<TAttribute>(MemberInfo memberIn
     /// <param name="memberInfo">Member to inspect for attributes.</param>
     /// <param name="inherit">Inspect inheritance chain of the member or class. E.g. if parent class has this attribute defined.</param>
     /// <returns>True if the attribute of the specified type is defined on this member or a class.</returns>
-    public virtual /* for testing */ bool IsDerivedAttributeDefined<TAttribute>(MemberInfo memberInfo, bool inherit)
+    public virtual /* for testing */ bool IsAttributeDefined<TAttribute>(MemberInfo memberInfo, bool inherit)
         where TAttribute : Attribute
     {
         Guard.NotNull(memberInfo);
@@ -77,7 +48,7 @@ public virtual bool IsNonDerivedAttributeDefined<TAttribute>(MemberInfo memberIn
         {
             DebugEx.Assert(attribute != null, $"{nameof(ReflectHelper)}.{nameof(GetCustomAttributesCached)}: internal error: wrong value in the attributes dictionary.");
 
-            if (AttributeComparer.IsDerived<TAttribute>(attribute))
+            if (attribute is TAttribute)
             {
                 return true;
             }
@@ -98,31 +69,6 @@ public virtual bool IsNonDerivedAttributeDefined<TAttribute>(MemberInfo memberIn
 #endif
     public override object InitializeLifetimeService() => null!;
 
-    /// <summary>
-    /// Gets first attribute that matches the type (but is not derived from it). Use this together with attribute that is both sealed and does not allow multiple.
-    /// In such case there cannot be more attributes, and this will avoid the cost of
-    /// checking for more than one attribute.
-    /// </summary>
-    /// <typeparam name="TAttribute">Type of the attribute to find.</typeparam>
-    /// <param name="attributeProvider">The type, assembly or method.</param>
-    /// <param name="inherit">If we should inspect parents of this type.</param>
-    /// <returns>The attribute that is found or null.</returns>
-    public TAttribute? GetFirstNonDerivedAttributeOrDefault<TAttribute>(ICustomAttributeProvider attributeProvider, bool inherit)
-    where TAttribute : Attribute
-    {
-        Attribute[] cachedAttributes = GetCustomAttributesCached(attributeProvider, inherit);
-
-        foreach (Attribute cachedAttribute in cachedAttributes)
-        {
-            if (AttributeComparer.IsNonDerived<TAttribute>(cachedAttribute))
-            {
-                return (TAttribute)cachedAttribute;
-            }
-        }
-
-        return null;
-    }
-
     /// <summary>
     /// Gets first attribute that matches the type or is derived from it.
     /// Use this together with attribute that does not allow multiple. In such case there cannot be more attributes, and this will avoid the cost of
@@ -140,9 +86,9 @@ public virtual bool IsNonDerivedAttributeDefined<TAttribute>(MemberInfo memberIn
 
         foreach (Attribute cachedAttribute in cachedAttributes)
         {
-            if (AttributeComparer.IsDerived<TAttribute>(cachedAttribute))
+            if (cachedAttribute is TAttribute cachedAttributeAsTAttribute)
             {
-                return (TAttribute)cachedAttribute;
+                return cachedAttributeAsTAttribute;
             }
         }
 
@@ -179,9 +125,9 @@ internal virtual bool IsMethodDeclaredInSameAssemblyAsType(MethodInfo method, Ty
     /// <returns>Categories defined.</returns>
     internal virtual /* for tests, we are mocking this */ string[] GetTestCategories(MemberInfo categoryAttributeProvider, Type owningType)
     {
-        IEnumerable<TestCategoryBaseAttribute> methodCategories = GetDerivedAttributes<TestCategoryBaseAttribute>(categoryAttributeProvider, inherit: true);
-        IEnumerable<TestCategoryBaseAttribute> typeCategories = GetDerivedAttributes<TestCategoryBaseAttribute>(owningType, inherit: true);
-        IEnumerable<TestCategoryBaseAttribute> assemblyCategories = GetDerivedAttributes<TestCategoryBaseAttribute>(owningType.Assembly, inherit: true);
+        IEnumerable<TestCategoryBaseAttribute> methodCategories = GetAttributes<TestCategoryBaseAttribute>(categoryAttributeProvider, inherit: true);
+        IEnumerable<TestCategoryBaseAttribute> typeCategories = GetAttributes<TestCategoryBaseAttribute>(owningType, inherit: true);
+        IEnumerable<TestCategoryBaseAttribute> assemblyCategories = GetAttributes<TestCategoryBaseAttribute>(owningType.Assembly, inherit: true);
 
         return methodCategories.Concat(typeCategories).Concat(assemblyCategories).SelectMany(c => c.TestCategories).ToArray();
     }
@@ -240,8 +186,8 @@ internal static TestIdGenerationStrategy GetTestIdGenerationStrategy(Assembly as
     /// <param name="owningType">The type that owns <paramref name="testMethod"/>.</param>
     /// <returns>True if test method should not run in parallel.</returns>
     internal bool IsDoNotParallelizeSet(MemberInfo testMethod, Type owningType)
-        => IsDerivedAttributeDefined<DoNotParallelizeAttribute>(testMethod, inherit: true)
-        || IsDerivedAttributeDefined<DoNotParallelizeAttribute>(owningType, inherit: true);
+        => IsAttributeDefined<DoNotParallelizeAttribute>(testMethod, inherit: true)
+        || IsAttributeDefined<DoNotParallelizeAttribute>(owningType, inherit: true);
 
     /// <summary>
     /// Get the parallelization behavior for a test assembly.
@@ -327,11 +273,11 @@ internal static bool IsDoNotParallelizeSet(Assembly assembly)
     /// <returns>List of traits.</returns>
     internal virtual IEnumerable<Trait> GetTestPropertiesAsTraits(MemberInfo testPropertyProvider)
     {
-        IEnumerable<TestPropertyAttribute> testPropertyAttributes = GetDerivedAttributes<TestPropertyAttribute>(testPropertyProvider, inherit: true);
+        IEnumerable<TestPropertyAttribute> testPropertyAttributes = GetAttributes<TestPropertyAttribute>(testPropertyProvider, inherit: true);
 
         if (testPropertyProvider.DeclaringType is { } testClass)
         {
-            testPropertyAttributes = testPropertyAttributes.Concat(GetDerivedAttributes<TestPropertyAttribute>(testClass, inherit: true));
+            testPropertyAttributes = testPropertyAttributes.Concat(GetAttributes<TestPropertyAttribute>(testClass, inherit: true));
         }
 
         foreach (TestPropertyAttribute testProperty in testPropertyAttributes)
@@ -348,7 +294,7 @@ internal virtual IEnumerable<Trait> GetTestPropertiesAsTraits(MemberInfo testPro
     /// <param name="attributeProvider">The member to inspect.</param>
     /// <param name="inherit">Look at inheritance chain.</param>
     /// <returns>An instance of the attribute.</returns>
-    internal virtual /* for tests, for moq */ IEnumerable<TAttributeType> GetDerivedAttributes<TAttributeType>(ICustomAttributeProvider attributeProvider, bool inherit)
+    internal virtual /* for tests, for moq */ IEnumerable<TAttributeType> GetAttributes<TAttributeType>(ICustomAttributeProvider attributeProvider, bool inherit)
         where TAttributeType : Attribute
     {
         Attribute[] attributes = GetCustomAttributesCached(attributeProvider, inherit);
@@ -358,9 +304,9 @@ internal virtual IEnumerable<Trait> GetTestPropertiesAsTraits(MemberInfo testPro
         {
             DebugEx.Assert(attribute != null, "ReflectHelper.DefinesAttributeDerivedFrom: internal error: wrong value in the attributes dictionary.");
 
-            if (AttributeComparer.IsDerived<TAttributeType>(attribute))
+            if (attribute is TAttributeType attributeAsAttributeType)
             {
-                yield return (TAttributeType)attribute;
+                yield return attributeAsAttributeType;
             }
         }
     }
diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs
index ef2d8b35b7..c12268190f 100644
--- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs
+++ b/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TestMethodValidatorTests.cs
@@ -34,7 +34,7 @@ public TestMethodValidatorTests()
     public void IsValidTestMethodShouldReturnFalseForMethodsWithoutATestMethodAttributeOrItsDerivedAttributes()
     {
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<UTF.TestMethodAttribute>(It.IsAny<MemberInfo>(), false)).Returns(false);
+            rh => rh.IsAttributeDefined<UTF.TestMethodAttribute>(It.IsAny<MemberInfo>(), false)).Returns(false);
         Verify(!_testMethodValidator.IsValidTestMethod(_mockMethodInfo.Object, _type, _warnings));
     }
 
@@ -183,7 +183,7 @@ public void WhenDiscoveryOfInternalsIsEnabledIsValidTestMethodShouldReturnFalseF
     #endregion
 
     private void SetupTestMethod() => _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<UTF.TestMethodAttribute>(It.IsAny<MemberInfo>(), false)).Returns(true);
+            rh => rh.IsAttributeDefined<UTF.TestMethodAttribute>(It.IsAny<MemberInfo>(), false)).Returns(true);
 }
 
 #region Dummy types
diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs
index 68687c1bd7..d1ce91ead0 100644
--- a/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs
+++ b/test/UnitTests/MSTestAdapter.UnitTests/Discovery/TypeValidatorTests.cs
@@ -49,7 +49,7 @@ public void IsValidTestClassShouldReturnTrueForClassesMarkedByAnAttributeDerived
     {
         _mockReflectHelper.Setup(rh => rh.IsNonDerivedAttributeDefined<UTF.TestClassAttribute>(It.IsAny<TypeInfo>(), false)).Returns(false);
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<UTF.TestClassAttribute>(It.IsAny<TypeInfo>(), false)).Returns(true);
+            rh => rh.IsAttributeDefined<UTF.TestClassAttribute>(It.IsAny<TypeInfo>(), false)).Returns(true);
         Verify(_typeValidator.IsValidTestClass(typeof(TypeValidatorTests), _warnings));
     }
 
@@ -393,7 +393,7 @@ private static Type[] GetAllTestTypes()
 
     #region private methods
 
-    private void SetupTestClass() => _mockReflectHelper.Setup(rh => rh.IsDerivedAttributeDefined<UTF.TestClassAttribute>(It.IsAny<TypeInfo>(), false)).Returns(true);
+    private void SetupTestClass() => _mockReflectHelper.Setup(rh => rh.IsAttributeDefined<UTF.TestClassAttribute>(It.IsAny<TypeInfo>(), false)).Returns(true);
 
     #endregion
 }
diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs
index 2398bd2457..65fc5893da 100644
--- a/test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs
+++ b/test/UnitTests/MSTestAdapter.UnitTests/Execution/TypeCacheTests.cs
@@ -233,7 +233,7 @@ public void GetTestMethodInfoShouldCacheAssemblyInitializeAttribute()
         var testMethod = new TestMethod("TestInit", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyInitializeAttribute>(type.GetMethod("AssemblyInit"), false)).Returns(true);
@@ -253,7 +253,7 @@ public void GetTestMethodInfoShouldCacheAssemblyCleanupAttribute()
         var testMethod = new TestMethod("TestCleanup", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyCleanupAttribute>(type.GetMethod("AssemblyCleanup"), false)).Returns(true);
@@ -273,7 +273,7 @@ public void GetTestMethodInfoShouldCacheAssemblyInitAndCleanupAttribute()
         var testMethod = new TestMethod("TestInitOrCleanup", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyInitializeAttribute>(type.GetMethod("AssemblyInit"), false)).Returns(true);
@@ -296,7 +296,7 @@ public void GetTestMethodInfoShouldThrowIfAssemblyInitHasIncorrectSignature()
         var testMethod = new TestMethod("M", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyInitializeAttribute>(type.GetMethod("AssemblyInit"), false)).Returns(true);
@@ -326,7 +326,7 @@ public void GetTestMethodInfoShouldThrowIfAssemblyCleanupHasIncorrectSignature()
         var testMethod = new TestMethod("M", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyCleanupAttribute>(type.GetMethod("AssemblyCleanup"), false)).Returns(true);
@@ -357,7 +357,7 @@ public void GetTestMethodInfoShouldCacheAssemblyInfoInstanceAndReuseTheCache()
         var testMethod = new TestMethod(methodInfo.Name, type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _typeCache.GetTestMethodInfo(
                 testMethod,
@@ -369,7 +369,7 @@ public void GetTestMethodInfoShouldCacheAssemblyInfoInstanceAndReuseTheCache()
                 new TestContextImplementation(testMethod, new ThreadSafeStringWriter(null, "test"), new Dictionary<string, object>()),
                 false);
 
-        _mockReflectHelper.Verify(rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false), Times.Once);
+        _mockReflectHelper.Verify(rh => rh.IsAttributeDefined<TestClassAttribute>(type, false), Times.Once);
         Verify(_typeCache.AssemblyInfoCache.Count == 1);
     }
 
@@ -425,7 +425,7 @@ public void GetTestMethodInfoShouldCacheBaseClassInitializeAttributes()
         var testMethod = new TestMethod("TestMethod", type.FullName, "A", false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
            rh => rh.IsNonDerivedAttributeDefined<ClassInitializeAttribute>(baseType.GetMethod("AssemblyInit"), false)).Returns(true);
@@ -474,7 +474,7 @@ public void GetTestMethodInfoShouldCacheBaseClassCleanupAttributes()
         var testMethod = new TestMethod("TestMethod", type.FullName, "A", false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
         _mockReflectHelper.Setup(
           rh => rh.IsNonDerivedAttributeDefined<ClassCleanupAttribute>(baseType.GetMethod("AssemblyCleanup"), false)).Returns(true);
         _mockReflectHelper.Setup(
@@ -523,7 +523,7 @@ public void GetTestMethodInfoShouldCacheBaseClassInitAndCleanupAttributes()
         MethodInfo baseCleanupMethod = baseType.GetMethod("ClassCleanup");
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
           rh => rh.IsNonDerivedAttributeDefined<ClassInitializeAttribute>(baseInitializeMethod, false)).Returns(true);
@@ -623,7 +623,7 @@ public void GetTestMethodInfoShouldThrowIfClassInitHasIncorrectSignature()
         var testMethod = new TestMethod("M", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<ClassInitializeAttribute>(type.GetMethod("AssemblyInit"), false)).Returns(true);
@@ -653,7 +653,7 @@ public void GetTestMethodInfoShouldThrowIfClassCleanupHasIncorrectSignature()
         var testMethod = new TestMethod("M", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<ClassCleanupAttribute>(type.GetMethod("AssemblyCleanup"), false)).Returns(true);
@@ -723,7 +723,7 @@ public void GetTestMethodInfoShouldThrowIfTestInitOrCleanupHasIncorrectSignature
         var testMethod = new TestMethod("M", type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<TestInitializeAttribute>(type.GetMethod("TestInit"), false)).Returns(true);
@@ -1277,7 +1277,7 @@ public void AssemblyInfoListWithExecutableCleanupMethodsShouldReturnEmptyListWhe
         var testMethod = new TestMethod(methodInfo.Name, type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyCleanupAttribute>(type.GetMethod("AssemblyCleanup"), false)).Returns(false);
@@ -1299,7 +1299,7 @@ public void AssemblyInfoListWithExecutableCleanupMethodsShouldReturnAssemblyInfo
         var testMethod = new TestMethod(methodInfo.Name, type.FullName, "A", isAsync: false);
 
         _mockReflectHelper.Setup(
-            rh => rh.IsDerivedAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
+            rh => rh.IsAttributeDefined<TestClassAttribute>(type, false)).Returns(true);
 
         _mockReflectHelper.Setup(
             rh => rh.IsNonDerivedAttributeDefined<AssemblyCleanupAttribute>(type.GetMethod("AssemblyCleanup"), false)).Returns(true);
diff --git a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs b/test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs
index 54a001d1e8..5ea8ae6689 100644
--- a/test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs
+++ b/test/UnitTests/MSTestAdapter.UnitTests/Helpers/ReflectHelperTests.cs
@@ -201,7 +201,7 @@ public void HasAttributeDerivedFromShouldReturnTrueIfSpecifiedAttributeIsDefined
             Setup(ro => ro.GetCustomAttributes(mockMemberInfo.Object, true)).
             Returns(attributes);
 
-        Verify(rh.IsDerivedAttributeDefined<TestMethodAttribute>(mockMemberInfo.Object, true));
+        Verify(rh.IsAttributeDefined<TestMethodAttribute>(mockMemberInfo.Object, true));
     }
 
     public void HasAttributeDerivedFromShouldReturnFalseIfSpecifiedAttributeIsNotDefinedOnAMember()
@@ -231,10 +231,10 @@ public void HasAttributeDerivedFromShouldReturnFromCache()
             Setup(ro => ro.GetCustomAttributes(memberInfo, true)).
             Returns(attributes);
 
-        Verify(rh.IsDerivedAttributeDefined<TestMethodAttribute>(memberInfo, true));
+        Verify(rh.IsAttributeDefined<TestMethodAttribute>(memberInfo, true));
 
         // Validate that reflection APIs are not called again.
-        Verify(rh.IsDerivedAttributeDefined<TestMethodAttribute>(memberInfo, true));
+        Verify(rh.IsAttributeDefined<TestMethodAttribute>(memberInfo, true));
         _testablePlatformServiceProvider.MockReflectionOperations.Verify(ro => ro.GetCustomAttributes(memberInfo, true), Times.Once);
 
         // Also validate that reflection APIs for an individual type is not called since the cache gives us what we need already.
@@ -275,8 +275,8 @@ public void GettingAttributesShouldNotReturnInheritedAttributesWhenAskingForNonI
             Setup(ro => ro.GetCustomAttributes(It.IsAny<Type>(), /* inherit */ false)).
             Returns([new TestClassAttribute()]);
 
-        TestClassAttribute[] inheritedAttributes = rh.GetDerivedAttributes<TestClassAttribute>(typeof(object), inherit: true).ToArray();
-        TestClassAttribute[] nonInheritedAttributes = rh.GetDerivedAttributes<TestClassAttribute>(typeof(object), inherit: false).ToArray();
+        TestClassAttribute[] inheritedAttributes = rh.GetAttributes<TestClassAttribute>(typeof(object), inherit: true).ToArray();
+        TestClassAttribute[] nonInheritedAttributes = rh.GetAttributes<TestClassAttribute>(typeof(object), inherit: false).ToArray();
 
         Verify(inheritedAttributes.Length == 2);
         Verify(nonInheritedAttributes.Length == 1);