Skip to content

Use generated descriptors for MTP discovery - #10777

Open
Amaury Levé (Evangelink) wants to merge 1 commit into
mainfrom
dev/amauryleve/implement-generated-descriptor-path
Open

Use generated descriptors for MTP discovery#10777
Amaury Levé (Evangelink) wants to merge 1 commit into
mainfrom
dev/amauryleve/implement-generated-descriptor-path

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Summary

Add a bounded MTP-only generated descriptor discovery path for plain synchronous [TestMethod] and [DataRow] methods.

Generated methods that declare complete support bypass the legacy runtime method enumeration and validation pass. Mixed classes fall back per method, while VSTest continues using the existing discovery path.

Old and new flow

Before:
generated registry -> MethodInfo registration -> runtime method scan/validation
-> UnitTestElement -> existing lifecycle/execution -> MTP TestNode

After (supported subset):
generated descriptor -> UnitTestElement
-> existing lifecycle/execution -> MTP TestNode

Fallback:
unsupported generated method -> existing runtime method scan/validation

This deliberately retains UnitTestElement, filtering, lifecycle, execution, and result conversion. It is the first production vertical slice, not a second lifecycle engine.

Supported subset

The fast path is limited to complete generated descriptors for public, instance, non-abstract, non-async, void methods with the exact built-in TestMethodAttribute and optional DataRowAttributes.

The legacy path remains authoritative for:

  • async/Task/ValueTask methods;
  • custom TestMethodAttribute implementations;
  • DynamicData/custom ITestDataSource;
  • incomplete or unsupported metadata;
  • ambiguous overloads and mixed classes;
  • VSTest.

The selection is observable internally through generated-descriptor metadata and focused path-selection tests.

Impact

Projects/layers changed:

  • MSTest.SourceGeneration models and emitters expose descriptor capability.
  • PlatformServices registration/provider surfaces descriptor methods.
  • MTP discovery consumes supported descriptors and falls back per method.
  • Existing lifecycle, TestContext, execution, retry, timeout, cleanup, filtering, and result pipelines are unchanged.

Controlled discovery benchmark, 10,000 iterations with two tests per iteration and five samples:

  • allocations: 114,451,416 B -> 89,573,624 B (-21.7%);
  • median elapsed: 508.162 ms -> 415.724 ms (-18.2%), but one sample regressed, so no strong wall-clock claim is made.

Release assembly size cost:

  • MSTest.SourceGeneration: +8,192 B (+4.94%);
  • MSTestAdapter.PlatformServices net8.0: +11,264 B (+2.13%).

Validation

  • MSTest.SourceGeneration.UnitTests: 127/127 passed.
  • MSTestAdapter.PlatformServices.UnitTests net8.0: 1,081/1,081 passed.
  • Managed ReflectionFree acceptance: 2/2 passed (net8.0 and net10.0).
  • NativeAOT acceptance: 2/2 passed.
  • Release pack: succeeded with 0 warnings and 0 errors.
  • Three independent reviews covered correctness, architecture/compatibility, and performance.

Future phases

This PR does not bypass UnitTestElement, TypeCache during execution, the lifecycle engine, or MTP result conversion. Follow-up work can introduce a generated execution abstraction and broader descriptor eligibility while preserving this per-method fallback boundary.

Bypass legacy method enumeration and validation for the bounded generated synchronous TestMethod and DataRow subset while retaining per-method fallback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: fd0b7d0f-8590-4c8b-ae58-635c652c60ef
Copilot AI balanced review requested due to automatic review settings August 26, 2026 15:54
// ToString() outputs method name and its signature. This is necessary for overloaded methods to be recognized as distinct tests.
foundDuplicateTests = foundDuplicateTests || !foundTests.Add(method.ToString() ?? method.Name);
UnitTestElement testMethod = GetTestFromMethod(method, classDisablesParallelization, warnings);
if (descriptorMethodSet?.Contains(method) == true)

Copilot AI commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

One or more custom setup steps configured for this repository failed during this Copilot code review run:

Build the repository

Setup steps run before each review. If the review above is missing context, or no review was posted at all, the failing step above may be the cause. See the workflow run for failure details, fix your setup steps configuration, and re-request a review.

Note

You can configure setup steps for Copilot code review separately from Copilot cloud agent with a copilot-code-review.yml file. Read the docs for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an MTP-only fast discovery path using generated descriptors while preserving legacy fallback and VSTest behavior.

Changes:

  • Extends source-generation metadata with descriptor eligibility and completeness.
  • Uses descriptors during MTP discovery with per-method fallback.
  • Adds unit, acceptance, and NativeAOT coverage.
Show a summary per file
File Description
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/TestableImplementations/TestablePlatformServiceProvider.cs Supports generated reflection providers in tests.
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/TestableImplementations/MockableReflectionOperations.cs Forwards descriptor lookups.
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/SourceGeneration/SourceGeneratedReflectionOperationsTests.cs Tests descriptor retrieval and completeness.
test/UnitTests/MSTestAdapter.PlatformServices.UnitTests/Discovery/TypeEnumeratorTests.cs Tests fast-path selection and fallback.
test/UnitTests/MSTest.SourceGeneration.UnitTests/MSTestReflectionMetadataGeneratorTests.cs Verifies generated descriptor metadata.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/SourceGenerationNonAotTests.cs Checks non-AOT generated output.
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/NativeAotTests.cs Checks NativeAOT eligibility metadata.
src/Analyzers/MSTest.SourceGeneration/Models/TestClassModel.cs Adds descriptor capability fields.
src/Analyzers/MSTest.SourceGeneration/Generators/TestClassModelBuilder.cs Determines descriptor eligibility.
src/Analyzers/MSTest.SourceGeneration/Generators/RuntimeRegistrationEmitter.cs Emits descriptor registration.
src/Analyzers/MSTest.SourceGeneration/Generators/MetadataRegistryEmitter.cs Emits descriptor metadata properties.
src/Adapter/MSTestAdapter.PlatformServices/SourceGeneration/SourceGeneratedReflectionOperations.cs Exposes registered descriptors.
src/Adapter/MSTestAdapter.PlatformServices/SourceGeneration/SourceGeneratedReflectionDataProvider.cs Stores descriptor data.
src/Adapter/MSTestAdapter.PlatformServices/SourceGeneration/ReflectionMetadataHook.cs Registers descriptor metadata.
src/Adapter/MSTestAdapter.PlatformServices/SourceGeneration/CompositeSourceGeneratedReflectionDataProvider.cs Merges descriptor providers.
src/Adapter/MSTestAdapter.PlatformServices/Services/ReflectionOperations.cs Provides reflection-mode fallback.
src/Adapter/MSTestAdapter.PlatformServices/PublicAPI/PublicAPI.Unshipped.txt Tracks the new public overload.
src/Adapter/MSTestAdapter.PlatformServices/ObjectModel/UnitTestElement.cs Marks descriptor-originated tests.
src/Adapter/MSTestAdapter.PlatformServices/Interfaces/IReflectionOperations.cs Defines descriptor lookup.
src/Adapter/MSTestAdapter.PlatformServices/Discovery/TypeEnumerator.cs Consumes descriptors during discovery.
src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumeratorWrapper.cs Enables descriptors for MTP.
src/Adapter/MSTestAdapter.PlatformServices/Discovery/AssemblyEnumerator.cs Propagates descriptor selection.

Review details

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 22/22 changed files
  • Comments generated: 3
  • Review effort level: Balanced

@@ -1,2 +1,3 @@
#nullable enable
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.SourceGeneration.ReflectionMetadataHook.Register(System.Reflection.Assembly! assembly, System.Type![]! types, System.Collections.Generic.IReadOnlyDictionary<System.Type!, System.Reflection.MethodInfo![]!>! testMethods, System.Collections.Generic.IReadOnlyDictionary<System.Type!, System.Attribute![]!>! typeAttributes, object![]! assemblyAttributes, System.Collections.Generic.IReadOnlyDictionary<System.Reflection.MethodInfo!, System.Attribute![]!>! methodAttributes, System.Collections.Generic.IReadOnlyDictionary<System.Reflection.MethodInfo!, System.Func<object?, object?[]?, object?>!>! methodInvokers, System.Collections.Generic.IReadOnlyDictionary<System.Type!, Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.SourceGeneration.ConstructorInvokerInfo[]!>! constructorInvokers, System.Collections.Generic.IReadOnlyDictionary<System.Reflection.PropertyInfo!, System.Action<object?, object?>!>! propertySetters) -> void
static Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.SourceGeneration.ReflectionMetadataHook.Register(System.Reflection.Assembly! assembly, System.Type![]! types, System.Collections.Generic.IReadOnlyDictionary<System.Type!, System.Reflection.MethodInfo![]!>! testMethods, System.Collections.Generic.IReadOnlyDictionary<System.Type!, System.Attribute![]!>! typeAttributes, object![]! assemblyAttributes, System.Collections.Generic.IReadOnlyDictionary<System.Reflection.MethodInfo!, System.Attribute![]!>! methodAttributes, System.Collections.Generic.IReadOnlyDictionary<System.Reflection.MethodInfo!, System.Func<object?, object?[]?, object?>!>! methodInvokers, System.Collections.Generic.IReadOnlyDictionary<System.Type!, Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.SourceGeneration.ConstructorInvokerInfo[]!>! constructorInvokers, System.Collections.Generic.IReadOnlyDictionary<System.Reflection.PropertyInfo!, System.Action<object?, object?>!>! propertySetters, System.Collections.Generic.IReadOnlyDictionary<System.Type!, System.Reflection.MethodInfo![]!>! descriptorTestMethods, System.Type![]! descriptorCompleteTypes) -> void
Comment on lines +160 to +162
bool areGeneratedDescriptorsComplete = supportsGeneratedDescriptors
&& !hasUnsupportedTestMethod
&& finalizedMethods.Where(static method => method.IsTestMethod).All(static method => method.IsDescriptorSupported);
Comment on lines +212 to +214
using (sb.Block("if (testClass.AreGeneratedDescriptorsComplete)"))
{
sb.AppendLine("descriptorCompleteTypes.Add(type);");

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary — PR #10777

This PR introduces source-generated test descriptors for native MTP discovery, allowing the discovery path to skip the legacy runtime-method scan when generated metadata is complete. The design is well-layered: the source generator emits per-method/per-class support flags, the ReflectionMetadataHook.Register overload carries the new dictionaries, and the TypeEnumerator consumes them with a clean fallback path.

Verdict Table

# Dimension Verdict
1 Algorithmic Correctness ⚠️ Merge semantics for DescriptorCompleteTypes are last-writer-wins — may silently produce wrong result when multiple providers register the same type
2 Threading & Concurrency ✅ N/A — no new shared mutable state introduced
3 Security & IPC ✅ N/A
4 Public API & Binary Compat ✅ New Register overload added (additive), old overload delegates. PublicAPI.Unshipped.txt updated.
5 Performance & Allocations ✅ Good — List pre-sized, HashSet used for skip-set
6 Cross-TFM Compatibility ✅ N/A — no TFM-specific APIs used
7 Resource & IDisposable ✅ N/A
8 Defensive Coding ✅ Null checks on new parameters, graceful fallback when descriptors unavailable
9 Localization ✅ N/A
10 Test Isolation ✅ Tests set up their own providers
11 Assertion Quality ✅ Uses AwesomeAssertions per project policy
12 Flakiness Patterns ✅ N/A
13 Test Completeness ✅ Good coverage of complete, incomplete, and non-MTP paths
14 Data-Driven Test Coverage ✅ N/A
15 Code Structure ⚠️ Minor — redundant ternary in AssemblyEnumerator
16–22 Remaining dimensions ✅ N/A or clean

Key Findings

  1. MAJOR — CompositeSourceGeneratedReflectionDataProvider merge semantics: MergeInto for DescriptorCompleteTypes uses last-writer-wins. When two providers disagree on completeness for the same type, correctness depends on registration order. The safe semantic is logical AND. Same concern applies to DescriptorTestMethods (arrays should be concatenated, not overwritten).

  2. Minor — Redundant ternary: The call in AssemblyEnumerator.DiscoverTestsInType could use the two-arg overload directly.

  3. Minor — Name-based duplicate detection vs. signature-based: TestClassModelBuilder disqualifies overloaded methods by name, while the runtime uses ToString() (includes signature). This is conservative but worth documenting.

Overall this is a solid, well-tested addition. The merge-semantics issue (finding #1) is the only one that could cause a real bug in multi-assembly/multi-provider scenarios.

@@ -203,6 +205,8 @@ private static SourceGeneratedReflectionDataProvider BuildMergedSnapshot(IReadOn
MergeInto(typeConstructorsInvoker, provider.TypeConstructorsInvoker);
MergeInto(typeMethodInvokers, provider.TypeMethodInvokers);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge semantics for DescriptorCompleteTypes may silently regress completeness (Algorithmic Correctness).

MergeInto uses last-writer-wins (target[key] = value). If two source-generated providers register the same type — one with true (complete) and one with false (incomplete) — the final result depends on iteration order. The unit test TryGetTestMethodDescriptors_RetainsPerMethodFallbackWhenRegistrationIsIncomplete passes only because the false provider is added second.

The correct merge semantic for completeness is logical AND: a type is only complete if all providers declare it complete. Similarly, the MethodInfo[] for DescriptorTestMethods should be merged (union), not overwritten.

Consider replacing MergeInto here with a specialized merge:

if (target.TryGetValue(kvp.Key, out bool existing))
    target[kvp.Key] = existing && kvp.Value;
else
    target[kvp.Key] = kvp.Value;

int synchronousMethodIndex = registry.IndexOf("Name = \"TestMethod1\"", StringComparison.Ordinal);
int synchronousNextMethodIndex = registry.IndexOf("Name = \"TestMethod2\"", synchronousMethodIndex, StringComparison.Ordinal);
Assert.IsGreaterThan(-1, synchronousMethodIndex);
Assert.IsGreaterThan(synchronousMethodIndex, synchronousNextMethodIndex);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertion arguments appear inverted (Algorithmic Correctness).

Assert.IsGreaterThan<T>(T lowerBound, T value) asserts that value > lowerBound. Here the call is:

Assert.IsGreaterThan(synchronousMethodIndex, synchronousNextMethodIndex);

This asserts synchronousNextMethodIndex > synchronousMethodIndex, i.e. TestMethod2 appears after TestMethod1. But looking at the existing pattern on line 171, Assert.IsGreaterThan(asyncMethodIndex, nextMethodIndex) asserts that nextMethodIndex > asyncMethodIndex — which is the same ordering intent ("next method appears later"). So this is correct.

However, just double-check: is the intent to verify that TestMethod1 appears before TestMethod2? If so, this is correct. If the intent is the reverse, the arguments need to be swapped. Consider adding a clarifying comment for future readers.

AreAttributesComplete: methodAttributes.IsComplete,
DynamicDataSources: DynamicDataSourceBuilder.BuildDynamicDataSources(inheritedAttributes, method, consumingAssembly));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HasOnlyDescriptorSupportedAttributes is restrictive — only [TestMethod] and [DataRow] are supported (Design observation).

This is a deliberate, conservative starting point for the descriptor path. However, as a note for reviewers: tests decorated with [Timeout], [Priority], [Owner], or other well-known attributes will fall back to legacy discovery even though those attributes don't change discovery semantics. Worth calling out in a tracking issue or inline comment for future expansion.

typeFullName = type.FullName;
TypeEnumerator testTypeEnumerator = GetTypeEnumerator(type, assemblyFileName, discoverInternals);
List<UnitTestElement>? unitTestCases = testTypeEnumerator.Enumerate(warningMessages);
List<UnitTestElement>? unitTestCases = useGeneratedDescriptors

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ternary branch is redundant — just pass the value directly (Code Structure).

List<UnitTestElement>? unitTestCases = useGeneratedDescriptors
    ? testTypeEnumerator.Enumerate(warningMessages, useGeneratedDescriptors: true)
    : testTypeEnumerator.Enumerate(warningMessages);

Since the two-arg overload simply delegates to the same EnumerateCore, this can be simplified to a single call:

List<UnitTestElement>? unitTestCases = testTypeEnumerator.Enumerate(warningMessages, useGeneratedDescriptors);

The overload Enumerate(List<string> warnings, bool useGeneratedDescriptors) already exists and handles both paths.

&& classAttributes.Attributes[0].FullyQualifiedAttributeType == TestClassAttributeName;

var duplicateTestMethodNames = new HashSet<string>(
methods

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicateTestMethodNames detection uses method.Name but duplicate-test detection at runtime uses method.ToString() (Algorithmic Correctness).

In TypeEnumerator.GetTests, duplicates are detected via method.ToString() (which includes the signature, catching overloads). Here, methods with the same name are disqualified from descriptor support, even if they have different signatures (legitimate overloads).

This means overloaded test methods (e.g. TestAdd(int) and TestAdd(string)) will always fall back to legacy discovery even though they're not truly "duplicate" tests. This seems intentionally conservative, but consider documenting this as a known limitation or using signature-based grouping for a tighter match.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Expert test review — PR #10777

GradeTestMutationNotesHow to improve
B (80–89) new SourceGeneratedReflectionOperationsTests.
TryGetTestMethodDescriptors_
RetainsPerMethodFallbackWhenRegistrationIsIncomplete
1/2 killed Both merged providers register the same MethodInfo, so distinct-provider merge mistakes aren't caught. Use a second real method for the incomplete provider so the test fails if the wrong provider's descriptor set wins.
B (80–89) new TypeEnumeratorTests.
EnumerateShouldIgnoreGeneratedDescriptorsOutsideNativeMtp
2/3 killed Verifies the legacy path is used but not that discovered test count matches the non-descriptor baseline exactly. Assert the exact expected test count (e.g. 1) instead of only NotBeEmpty().
A (90–100) new TypeEnumeratorTests.
EnumerateShouldUseCompleteGeneratedDescriptorsWithoutLegacyMethodValidation
4/4 killed Confirms descriptor-only enumeration skips legacy validator and sets the flag correctly.
A (90–100) new TypeEnumeratorTests.
EnumerateShouldFallBackPerMethodWhenGeneratedDescriptorsAreIncomplete
4/4 killed Exercises the merge of descriptor and legacy-validated methods, including dedup against the descriptor set.
A (90–100) new TypeEnumeratorTests.
EnumerateShouldSelectPlainAndDataRowDescriptorsWhenComplete
3/3 killed Confirms both plain and DataRow-attributed methods are selected as complete descriptors.
A (90–100) new SourceGeneratedReflectionOperationsTests.
TryGetTestMethodDescriptors_
ReturnsRegisteredMethodsAndCompleteness
2/2 killed Directly verifies method identity and the completeness flag for a single provider.
A (90–100) mod MSTestReflectionMetadataGeneratorTests.
Generator_
EmitsRegistry_
WithDiscoveredTestClass
3/3 killed New assertions confirm descriptor support/completeness flags are emitted true for the simple case.
A (90–100) new MSTestReflectionMetadataGeneratorTests.
Generator_
DeclaresDescriptorSupportOnlyForBoundedSynchronousSubset
6/6 killed Covers DataRow-supported, attribute-fallback, async-fallback, and private-fallback branches with ordered substring checks.
A (90–100) mod NativeAotTests.
NativeAotTests_
WillRunWithExitCodeZero
2/2 killed New assertions confirm the synchronous method is marked descriptor-supported end-to-end in a real build/run.
A (90–100) mod SourceGenerationNonAotTests.
SourceGenerationNonAot_
BuildsAndRunsTests_
WithExitCodeZero
5/5 killed Validates the full descriptor pipeline (flags plus generated registration wiring) against a real compiled/run assembly.

General observation (not test-specific): three copilot-pull-request-reviewer production-code threads already flag real correctness gaps in the feature under test (partial-class completeness blind spot in TestClassModelBuilder, unresolved-member completeness in RuntimeRegistrationEmitter, and a CodeQL boolean-simplification note in TypeEnumerator). None of the reviewed tests currently exercise those specific scenarios (a partial [TestClass] split across generators, or a descriptor method that fails ResolveMethod), so consider adding regression tests once those production issues are addressed.

This advisory comment was generated automatically. Grades are heuristic and informational — they do not block merging. Suggestions on the Files changed tab can be applied with one click. Re-run with /review-tests.

🤖 Automated content by GitHub Copilot. Generated by the Test Reviewer on PR (on open / sync) workflow. · auto · 144.4 AIC · ⌖ 1.22 AIC · ⊞ 16.9K · [◷]( · )

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated content by GitHub Copilot. Generated by the Test Reviewer on PR (on open / sync) workflow. · auto · 144.4 AIC · ⌖ 1.22 AIC · ⊞ 16.9K ·

operations.TryGetTestMethodDescriptors(typeof(Sample), out MethodInfo[]? methods, out bool isComplete)
.Should().BeTrue();
methods.Should().ContainSingle().Which.Should().BeSameAs(method);
isComplete.Should().BeFalse();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧪 Test review · Grade B (80–89) — Both providers register the same MethodInfo, so the test never proves the composite actually merges distinct per-provider descriptor sets.

Use a second real method on Sample for the incomplete provider (or assert on a differing method reference) so the test would fail if merging picked the wrong provider entry.

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Build Failure Analysis

Summary — The Linux Release build failed because dotnet format/analyzer style errors (IDE0306/IDE0028, promoted to build errors) fire on a new line added by this PR.

Root cause: Collection initialization can be simplified

TypeEnumerator.GetTests was modified to build descriptorMethodSet via new HashSet<MethodInfo>(descriptorMethods). The repo's style analyzers require the collection-expression form ([.. descriptorMethods]) instead of the constructor-with-argument form, so IDE0306/IDE0028 are raised and — since this repo builds with analyzers as errors — the build fails.

Affected files / errors

Proposed fix

-            : new HashSet<MethodInfo>(descriptorMethods);
+            : [.. descriptorMethods];

Build overview
  • MSBuild: 18.11.0-1.26420.103+1d599674e
  • Projects: 51, Errors: 7, Warnings: 1
  • Failed projects: Build.proj, NonWindowsTests.slnf, MSTestAdapter.PlatformServices.csproj, MSTest.TestAdapter.csproj
All MSBuild errors (7)
Code Project File:Line Message
IDE0306 MSTestAdapter.PlatformServices TypeEnumerator.cs:99 Collection initialization can be simplified
IDE0028 MSTestAdapter.PlatformServices TypeEnumerator.cs:99 Collection initialization can be simplified
(duplicated across multiple targets, same root cause)

🤖 Generated by the Build Failure Analysis workflow using (a href="(dev.azure.com/redacted) · commit 025fb6e

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · auto · 82.8 AIC · ⌖ 1.54 AIC · ⊞ 13.3K · [◷]( · )

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Automated content by GitHub Copilot. Generated by the Build Failure Analysis workflow. · auto · 82.8 AIC · ⌖ 1.54 AIC · ⊞ 13.3K ·

var tests = new List<UnitTestElement>(descriptorMethods.Length);
HashSet<MethodInfo>? descriptorMethodSet = descriptorMethods.Length == 0
? null
: new HashSet<MethodInfo>(descriptorMethods);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 IDE0306/IDE0028 — Collection initialization can be simplified; use a collection expression instead of the HashSet<T> constructor with an argument, matching the analyzer rule enforced as an error in this build.

Suggested change
: new HashSet<MethodInfo>(descriptorMethods);
: [.. descriptorMethods];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants