Skip to content

Allow independent methods to have the same parameter name#45501

Merged
sharwell merged 2 commits intodotnet:release/dev16.7from
sharwell:param-name
Jun 30, 2020
Merged

Allow independent methods to have the same parameter name#45501
sharwell merged 2 commits intodotnet:release/dev16.7from
sharwell:param-name

Conversation

@sharwell
Copy link
Contributor

Fixes #45492

@sharwell sharwell requested a review from a team as a code owner June 27, 2020 22:31
@miqm
Copy link

miqm commented Jun 28, 2020

@sharwell What in case of local methods? In C#8 we can hide existing parameter, but in netcore2.1 suggested name can breake up build.

Here's a testCase:

    public class Context { }
    public class C
    {
        void Goo(Context context) { 
        
            void InnerGoo(Context c$$)
        }        
    }

@sharwell
Copy link
Contributor Author

@miqm I believe that's an existing bug, so I wasn't trying to fix it. Is there a specific case that worked in 16.6 but isn't working anymore?

@miqm
Copy link

miqm commented Jun 28, 2020

@sharwell - I think I didn't make myself clear enough. The full test cases, that IMHO should work, are as follows:

{
var markup = @"
public class DbContext { }
public class C
{
    void Goo(DbContext context) {
        void InnerGoo(DbContext $$) { }
    }
}
";
await VerifyItemExistsAsync(markup, "dbContext", glyph: (int) Glyph.Parameter);
await VerifyItemExistsAsync(markup, "db", glyph: (int) Glyph.Parameter);
await VerifyItemExistsAsync(markup, "context1", glyph: (int)Glyph.Parameter);
}
{
var markup = @"
public class DbContext { }
public class C
{
    void Goo() {
        DbContext context;
        void InnerGoo(DbContext $$) { }
    }
}
";
await VerifyItemExistsAsync(markup, "dbContext", glyph: (int) Glyph.Parameter);
await VerifyItemExistsAsync(markup, "db", glyph: (int) Glyph.Parameter);
await VerifyItemExistsAsync(markup, "context1", glyph: (int)Glyph.Parameter);
}
{
var markup = @"
public class DbContext { }
public class C
{
    DbContext dbContext;
    void Goo(DbContext context) {
        void InnerGoo(DbContext $$) { }
    }
}
";
await VerifyItemExistsAsync(markup, "dbContext", glyph: (int) Glyph.Parameter);
await VerifyItemExistsAsync(markup, "db", glyph: (int) Glyph.Parameter);
await VerifyItemExistsAsync(markup, "context1", glyph: (int)Glyph.Parameter);
}

I verified those test cases on 16.7-preview2 and they all work. I'm not sure if they will work with your code. Stopping search on ParameterList syntax will take into account only items on current parameter list (inner method's list) and will not take into account the outer method block.

Copy link

@miqm miqm left a comment

Choose a reason for hiding this comment

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

Instead adding additional case I'd revert to what it was before but use a new method with old IsExecutableBlock method content.

public SyntaxNode GetParameterList(SyntaxNode node)
=> node.GetParameterList();

public bool IsParameterList(SyntaxNode node)
Copy link

Choose a reason for hiding this comment

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

        public bool IsParameterScope(SyntaxNode node)
            => node.IsKind(SyntaxKind.Block, SyntaxKind.SwitchSection);

SyntaxToken? GetNameOfParameter(SyntaxNode node);
SyntaxNode GetDefaultOfParameter(SyntaxNode node);
SyntaxNode GetParameterList(SyntaxNode node);
bool IsParameterList(SyntaxNode node);
Copy link

Choose a reason for hiding this comment

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

bool IsParameterScope(SyntaxNode node);

Return node.GetParameterList()
End Function

Public Function IsParameterList(node As SyntaxNode) As Boolean Implements ISyntaxFacts.IsParameterList
Copy link

Choose a reason for hiding this comment

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

        Public Function IsParameterScope(node As SyntaxNode) As Boolean Implements ISyntaxFacts.IsParameterScope
            Return node.IsKind(SyntaxKind.Block, SyntaxKind.SwitchSection)
        End Function

{
var container = containerOpt ?? location.AncestorsAndSelf().FirstOrDefault(
a => SyntaxFacts.IsExecutableBlock(a) || SyntaxFacts.IsMethodBody(a));
a => SyntaxFacts.IsExecutableBlock(a) || SyntaxFacts.IsParameterList(a) || SyntaxFacts.IsMethodBody(a));
Copy link

Choose a reason for hiding this comment

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

                a => SyntaxFacts.IsParameterScope(a) || SyntaxFacts.IsMethodBody(a));

Copy link
Contributor

Choose a reason for hiding this comment

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

IsParameterScope isn't something SyntaxFacts should know about. SyntaxFacts is just a way to structurally ask what type of node something is, in a way that is agnostic to VB/C#. i.e. if both VB/C# have an InvocationExpressionSyntax, then SyntaxFacts can be used with IsInvocationExpression to ask that question in a uniform way, without worrying about lang.

It's specifically for syntactic similarity questions, not for semantic questions (like scopes). Thanks!

Copy link

@miqm miqm Jun 28, 2020

Choose a reason for hiding this comment

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

@CyrusNajmabadi Ok, understood. Although I still think this particular change will lead to check only current ParameterList and will not take into account i.e. method body for local method parameters. Perhaps it could be added some sort of container filter which can be used by Declaration Name provider to take into account only MethodBody (if there is one)?

@miqm
Copy link

miqm commented Jun 29, 2020

@miqm I believe that's an existing bug, so I wasn't trying to fix it. Is there a specific case that worked in 16.6 but isn't working anymore?

@sharwell This is screenshot from 16.6.2:
image

As you can see, context1 name is suggested here correctly - context is used in the method parameters list. In this solution I think "context" will be suggested, as the lookup for container will stop on first Parameters list - in this case - on the parameters list for the local method.

@sharwell sharwell changed the base branch from master to release/dev16.7 June 29, 2020 23:46
@jinujoseph jinujoseph added this to the 16.7.P4 milestone Jun 29, 2020
@sharwell
Copy link
Contributor Author

sharwell commented Jun 30, 2020

@miqm I added all your tests locally and they worked without other changes. See my new commit!

Copy link

@miqm miqm left a comment

Choose a reason for hiding this comment

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

Oh, apparently inner method's parameterList is not ParameterList in SyntaxFacts understanding. Happy to approve :)

@sharwell sharwell merged commit ca3c46b into dotnet:release/dev16.7 Jun 30, 2020
@sharwell sharwell deleted the param-name branch June 30, 2020 05:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parameter name is suggested with number suffix while it should be plain

4 participants