Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 4, 2025

Summary: Fix "Introduce parameter for" on member initializer left-hand side

This PR fixes the issue where the "Introduce parameter for" refactoring was incorrectly being offered on the left-hand side (member name) of member initializers.

Problem

When the user placed the cursor on the identifier in the name position of a member initializer (e.g., a in new { a = ... } or X in new Foo { X = ... }), the "Introduce parameter" refactoring was offered. This doesn't make sense because the identifier represents the member name, not a value that could be parameterized.

Solution

Added validation in IsValidExpression to detect and exclude these cases:

  1. For regular object initializers (new Foo { X = ... }): The existing IsMemberInitializerNamedAssignmentIdentifier method already handles this case.

  2. For anonymous object initializers (new { a = ... }): Added a new abstract method IsAnonymousObjectMemberDeclaratorNameIdentifier with language-specific implementations:

    • C#: Checks if expression is an IdentifierNameSyntaxNameEqualsSyntaxAnonymousObjectMemberDeclaratorSyntax
    • VB: Checks if expression is an IdentifierNameSyntaxNamedFieldInitializerSyntaxAnonymousObjectCreationExpressionSyntax

Changes Made

  • AbstractIntroduceParameterCodeRefactoringProvider.cs: Added abstract method and updated IsValidExpression to check both cases
  • CSharpIntroduceParameterCodeRefactoringProvider.cs: Implemented C#-specific check for anonymous object member names
  • VisualBasicIntroduceParameterCodeRefactoringProvider.vb: Implemented VB-specific check for anonymous object member names
  • IntroduceParameterTests.cs: Added 4 new tests with WorkItem attributes to verify the refactoring is not offered on member initializer names

Testing

  • ✅ All new tests pass with proper WorkItem attribution
  • ✅ Tests use 'Goo' naming convention per code review feedback
  • ✅ Code builds successfully for both C# and VB
  • ✅ Security check completed (no issues found)

Checklist:

  • Understand the issue and investigate the codebase
  • Add abstract method IsAnonymousObjectMemberDeclaratorNameIdentifier
  • Implement the method in C# provider
  • Implement the method in VB provider
  • Update IsValidExpression to use both checks
  • Add tests for anonymous object member initializers
  • Add tests for regular object initializers
  • Build and verify the changes compile successfully
  • Run new tests to verify refactoring is not offered
  • Address code review feedback (use 'Goo', add WorkItem attributes)
  • Run security checks
Original prompt

This section details on the original issue you should resolve

<issue_title>"Introduce parameter for" produces invalid code for nested anonymous type</issue_title>
<issue_description>Version Used: VS 18.0.0 Insiders [11201.2]

Steps to Reproduce:
At the marked location, open the lightbulb menu and select "Introduce parameter for 'a'" > "into extracted method to invoke at callsites".

class C
{
    object M() => new
    {
        $$a = new { },
    };
}

Expected Behavior:
Valid, compilable code is produced.

Actual Behavior:
Uncompilable code is generated:

class C
{
    private global::System.Object GetA() // <- Name is not simplified
    {
        return a; // CS0103: The name 'a' does not exist in the current context
    }

    object M(var a) => new
//           ~~~ CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code
    {
        a = new { },
    };
}
Image

<agent_instructions>@copilot 'introduce parameter for' should not be offered on the left-hand-side of a member-initializer. That includes a member initializer in an anonymous type (like new { X = ... }) or a normal type (like new Foo { X = ... })</agent_instructions>

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


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Add check to prevent "Introduce parameter" refactoring from being offered on the left-hand side of member initializers in both anonymous objects (new { a = ... }) and regular object initializers (new Foo { X = ... }).

- Added abstract method IsAnonymousObjectMemberDeclaratorNameIdentifier to check for anonymous object member names
- Implemented the method in both C# and VB providers
- Added tests to verify refactoring is not offered on member initializer names
- Existing IsMemberInitializerNamedAssignmentIdentifier handles regular object initializers

Co-authored-by: CyrusNajmabadi <[email protected]>
Simplified IsAnonymousObjectMemberDeclaratorNameIdentifier method in VB provider using early returns instead of nested if statements for better readability.

Co-authored-by: CyrusNajmabadi <[email protected]>
Copilot AI changed the title [WIP] Fix invalid code generation for nested anonymous type Don't offer "Introduce parameter" on member initializer names Nov 4, 2025
Copilot AI requested a review from CyrusNajmabadi November 4, 2025 01:03
Copilot finished work on behalf of CyrusNajmabadi November 4, 2025 01:03
class Foo { public int X { get; set; } }
class C
{
Foo M() => new Foo
Copy link
Member

Choose a reason for hiding this comment

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

@copilot use 'Goo' instead of 'Foo' in all tests.
use [Fact, WorkItem("...")] for all the tests you added.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 0cc1448. Renamed 'Foo' to 'Goo' in all tests and added WorkItem attributes with the issue URL.

CyrusNajmabadi and others added 5 commits November 3, 2025 17:52
…icIntroduceParameterCodeRefactoringProvider.vb
…ibutes

- Renamed all instances of 'Foo' to 'Goo' in test classes
- Added WorkItem attribute with issue URL to all new tests
- Added using statement for Roslyn.Test.Utilities

Co-authored-by: CyrusNajmabadi <[email protected]>
Copilot AI requested a review from CyrusNajmabadi November 4, 2025 02:00
Copilot finished work on behalf of CyrusNajmabadi November 4, 2025 02:00
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review November 4, 2025 02:00
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner November 4, 2025 02:00
@CyrusNajmabadi CyrusNajmabadi merged commit d7df934 into main Nov 4, 2025
26 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Nov 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Introduce parameter for" produces invalid code for nested anonymous type

3 participants