Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 28, 2025

Adds a new code analyzer MSTEST0059 that detects usage of RuntimeInformation.IsOSPlatform with early return or Assert.Inconclusive in test methods and suggests using the [OSCondition] attribute instead.

Fixes #7011

Changes Made

  • Analyzer: Created UseOSConditionAttributeInsteadOfRuntimeCheckAnalyzer that detects:

    • if (RuntimeInformation.IsOSPlatform(...)) { return; } patterns (suggests ConditionMode.Exclude)
    • if (!RuntimeInformation.IsOSPlatform(...)) { return; } patterns (suggests ConditionMode.Include)
    • Assert.Inconclusive calls within the if blocks
    • Supports Windows, Linux, OSX, and FreeBSD platforms
  • Code Fixer: Created UseOSConditionAttributeInsteadOfRuntimeCheckFixer that:

    • Adds [OSCondition] attribute with the appropriate ConditionMode and OperatingSystems value
    • Removes the if statement from the method body
  • Infrastructure:

    • Added diagnostic ID MSTEST0059 in DiagnosticIds.cs
    • Added type name for RuntimeInformation in WellKnownTypeNames.cs
    • Added resource strings and localization entries
  • Tests: Comprehensive unit tests covering:

    • Negated and non-negated runtime checks
    • Different platforms (Windows, Linux, OSX)
    • Single statement vs block returns
    • Assert.Inconclusive patterns
    • Edge cases (else branches, non-test methods, other statements)
    • Code fix behavior with trivias (leading/trailing/inline comments)
Original prompt

This section details on the original issue you should resolve

<issue_title>Add analyzer for OSCondition</issue_title>
<issue_description>## Summary

With #6994 merged an analyzer can help widespread the use of the new attribute.

</issue_description>

<agent_instructions>Add a new code analyzer that will detect in test methods the usage of early return or assert.inconclusive for calls to RuntimeInformation.IsOSPlatform and suggest instead to use [OSCondition] attribute. We should also handle !RuntimeInformation.... and also provide a codefix for this new analyzer.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Add analyzer for OSCondition usage in test methods Add analyzer for OSCondition (MSTEST0059) Nov 28, 2025
Copilot AI requested a review from Evangelink November 28, 2025 10:28
Copilot finished work on behalf of Evangelink November 28, 2025 10:28
Copy link
Contributor Author

Copilot AI commented Nov 28, 2025

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 8xbvsblobprodcus382.vsblob.vsassets.io
    • Triggering command: /home/REDACTED/work/testfx/testfx/.dotnet/dotnet /home/REDACTED/work/testfx/testfx/.dotnet/dotnet msbuild /m /nologo /clp:Summary /v:minimal /nr:true /warnaserror /p:TreatWarningsAsErrors=true /p:ContinuousIntegrationBuild=false /home/REDACTED/work/testfx/testfx/artifacts/toolset/restore.proj /t:__WriteToolsetLocation /clp:ErrorsOnly;NoSummary /p:__ToolsetLocationOutputFile=/home/REDACTED/work/testfx/testfx/artifacts/toolset/11.0.0-beta.25575.1.txt (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from Evangelink November 28, 2025 13:25
Copilot finished work on behalf of Evangelink November 28, 2025 13:25
Copilot finished work on behalf of Evangelink November 28, 2025 13:31
Copy link
Member

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

@copilot let's add some test cases with trivias to see how the code fix reacts. For example

// Skip on windows
if (RuntimeInformation.IsOSPLatform(OSPlatform.Windows)

or with trivias after the if block

@Evangelink Evangelink marked this pull request as ready for review November 28, 2025 15:00
Copy link
Contributor Author

Copilot AI commented Nov 28, 2025

@copilot let's add some test cases with trivias to see how the code fix reacts. For example

Added test cases with trivias in cbd04fa:

  • WhenRuntimeCheckWithLeadingComment_Diagnostic: Comment before the if statement
  • WhenRuntimeCheckWithTrailingComment_Diagnostic: Comment after the if block
  • WhenRuntimeCheckWithCommentInsideBlock_Diagnostic: Comment inside the if block

Copilot AI requested a review from Evangelink November 28, 2025 15:03
Copilot finished work on behalf of Evangelink November 28, 2025 15:03
@Evangelink Evangelink enabled auto-merge (squash) November 28, 2025 15:05
return;
}

IMethodSymbol? isOSPlatformMethod = runtimeInformationSymbol.GetMembers("IsOSPlatform")
Copy link
Member

Choose a reason for hiding this comment

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

Do we also want to handle OperatingSystem.Is<OS> methods?

Comment on lines +84 to +86
blockContext.RegisterOperationAction(
operationContext => AnalyzeIfStatement(operationContext, isOSPlatformMethod, assertSymbol),
OperationKind.Conditional);
Copy link
Member

Choose a reason for hiding this comment

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

This will analyze conditions that appear anywhere in the method body. But if I have a test method like the following:

[TestMethod]
public void MyTestMethod()
{
    // arrange

    // some assertions

    // if windows, return

    // some other assertions that are non-Windows only.
}

This shouldn't get flagged.


// Check if it's an invocation of RuntimeInformation.IsOSPlatform
if (actualCondition is not IInvocationOperation invocation ||
!SymbolEqualityComparer.Default.Equals(invocation.TargetMethod.OriginalDefinition, isOSPlatformMethod))
Copy link
Member

Choose a reason for hiding this comment

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

Is accessing OriginalDefinition really needed here?

Comment on lines +186 to +194
foreach (IOperation operation in blockOperation.Operations)
{
if (IsReturnOrAssertInconclusive(operation, assertSymbol))
{
return true;
}
}

return false;
Copy link
Member

Choose a reason for hiding this comment

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

Is this correct? Shouldn't we only look at the first operation?

}

// Find the if statement to remove
IfStatementSyntax? ifStatement = diagnosticNode.FirstAncestorOrSelf<IfStatementSyntax>();
Copy link
Member

Choose a reason for hiding this comment

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

The diagnostic node here is what? Shouldn't it be the IfStatementSyntax in question already? Why do we need FirstAncestorOrSelf?

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.

Add analyzer for OSCondition

3 participants