Skip to content

fix(mutating): avoid CS0136 from recursive/var pattern designations#3602

Open
slang25 wants to merge 4 commits into
stryker-mutator:masterfrom
slang25:slang25/fix-pattern-designation-cs0136
Open

fix(mutating): avoid CS0136 from recursive/var pattern designations#3602
slang25 wants to merge 4 commits into
stryker-mutator:masterfrom
slang25:slang25/fix-pattern-designation-cs0136

Conversation

@slang25

@slang25 slang25 commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Mutating an expression that introduces a variable via a recursive or var pattern designation (e.g. s is { Length: > 0 } region) at expression level produced a ternary that duplicated the declaration across branches, triggering CS0136.
  • Teach ContainsDeclarations to detect SingleVariableDesignation when its parent is a RecursivePatternSyntax/VarPatternSyntax. The scoping leaves other designations (out var, tuple deconstruction, list patterns) at their previous expression-level behavior.
  • In MutationStore.Inject, when the source expression contains a declaration, skip ternary placement and forward the pending mutations to the enclosing block so they can be controlled by an if-statement.

Fixes #3597. Split out from #3594.

Test plan

  • New RoslynHelperTests cover recursive/var/declaration patterns
  • Existing Mutators and Mutants test suites still pass
  • Manual verification: mutation on a project using s is { Length: > 0 } region no longer produces CS0136 mutants

Mutating an expression that introduces a variable via a recursive or var
pattern designation (e.g. `s is { Length: > 0 } region`) at expression
level produces a ternary that duplicates the declaration across branches,
triggering CS0136.

- Teach ContainsDeclarations to detect SingleVariableDesignation when
  its parent is a RecursivePatternSyntax/VarPatternSyntax, leaving other
  designations (out var, tuple deconstruction, list patterns) untouched.
- In MutationStore.Inject, when the source expression contains a
  declaration, skip ternary placement and forward the pending mutations
  to the enclosing block so they can be controlled by an if-statement.

Fixes stryker-mutator#3597
Copilot AI review requested due to automatic review settings May 19, 2026 13:36

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

Note

Copilot was unable to run its full agentic suite in this review.

Prevents C# compiler error CS0136 when mutating expressions that introduce variables via pattern designations by improving declaration detection and avoiding expression-level ternary placement for such cases.

Changes:

  • Extend ContainsDeclarations to detect SingleVariableDesignation for recursive/var patterns.
  • Skip expression-level injection in MutationStore.Inject when the source expression contains declarations (to avoid duplicated declarations in ternary branches).
  • Add unit tests covering pattern designation declaration detection.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/Stryker.Core/Stryker.Core/Mutants/MutationStore.cs Avoids ternary-based expression injection when declarations are present to prevent CS0136.
src/Stryker.Core/Stryker.Core/Helpers/RoslynHelper.cs Enhances declaration detection for recursive/var pattern designations.
src/Stryker.Core/Stryker.Core.UnitTest/Helpers/RoslynHelperTests.cs Adds tests validating ContainsDeclarations behavior for patterns and non-declaration expressions.

Comment thread src/Stryker.Core/Stryker.Core/Mutants/MutationStore.cs
Comment thread src/Stryker.Core/Stryker.Core/Helpers/RoslynHelper.cs Outdated
Comment thread src/Stryker.Core/Stryker.Core.UnitTest/Helpers/RoslynHelperTests.cs
slang25 and others added 2 commits May 20, 2026 11:58
- Extract IsRecursiveOrVarPatternDesignation helper from ContainsDeclarations.
- Clarify MutationStore.Inject comment: pending store is left intact so Leave() forwards mutations to an enclosing level.
- Add negative test cases for recursive/var patterns without a SingleVariableDesignation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 4, 2026 21:41

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

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment on lines +12 to +16
[TestMethod]
[DataRow("s is { Length: > 0 } region")]
[DataRow("s is var captured")]
[DataRow("s is int n")]
public void ContainsDeclarationsShouldDetectPatternDesignations(string expression)
Comment on lines +28 to +36
[TestMethod]
[DataRow("s.Length > 0")]
[DataRow("s is [_, _]")]
[DataRow("(a, b)")]
// Recursive / var patterns without a SingleVariableDesignation introduce
// no variable, so they must not trigger ContainsDeclarations.
[DataRow("s is { Length: > 0 }")]
[DataRow("s is var _")]
public void ContainsDeclarationsShouldReturnFalseWithoutDeclarations(string expression)
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.

Recursive/var pattern designations cause CS0136 in expression-level mutations

2 participants