Suggest parameter names from matching overloads#52801
Suggest parameter names from matching overloads#52801CyrusNajmabadi merged 13 commits intodotnet:mainfrom
Conversation
| foreach (var sibling in siblingMethods) | ||
| { | ||
| foreach (var siblingParameter in sibling.ParameterList.Parameters) |
There was a problem hiding this comment.
Not really. There are other completion scenarios that are more expensive without problems.
Maybe try running this in a class with a large number of methods all with different names, just to make sure the outer loop isn't too slow in huge types?
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
| var partialSemanticModel = await document.GetPartialSemanticModelAsync(cancellationToken).ConfigureAwait(false); | ||
| if (partialSemanticModel is not null) | ||
| AddNamesFromExistingOverloads(context, partialSemanticModel, result, cancellationToken); |
There was a problem hiding this comment.
Caller already has a semantic model, but it's not a partial semantic model.
var semanticModel = await document.ReuseExistingSpeculativeModelAsync(position, cancellationToken).ConfigureAwait(false);I used partial semantic model per your suggestion @sharwell.
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Show resolved
Hide resolved
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
|
@sharwell @CyrusNajmabadi Anything left here? Thanks! |
davidwengier
left a comment
There was a problem hiding this comment.
This LGTM, but would be good to get a tick from @CyrusNajmabadi or @sharwell for any existing perf concerns.
In particular whilst there might be de-duping code in completion itself, I don't know if this is something we want to rely on. Duplicates in overloads seem like they would be very common, and it would be very simple to filter them out here (add them to the hashset this is already checking).
|
I can look tomorrow |
| if (parameterSyntax is not { Type: { } parameterType, Parent: { Parent: BaseMethodDeclarationSyntax baseMethod } }) | ||
| return; | ||
|
|
||
| var overloads = GetOverloads(baseMethod, namedType); |
There was a problem hiding this comment.
my preference is to swap these parameters so we always go from 'wider to narrow' scope for them.
| if (!overloads.Any()) | ||
| return; | ||
|
|
||
| var methodParameterType = semanticModel.GetTypeInfo(parameterType, cancellationToken).Type; |
There was a problem hiding this comment.
consider doing this first before botherin gto collect overloads.
|
|
||
| var overloads = GetOverloads(baseMethod, namedType); | ||
|
|
||
| if (!overloads.Any()) |
There was a problem hiding this comment.
this will causde double enumeration of an enumerable.
|
I fixed the conflicts. If CI failed, I will get to that in a week after finishing my exams. |
|
@CyrusNajmabadi This should be ready for another look :) |
| } | ||
| "; | ||
| await VerifyItemExistsAsync(markup, "myTok", glyph: (int)Glyph.Parameter); | ||
| await VerifyItemExistsAsync(markup, "cancellationToken", glyph: (int)Glyph.Parameter); |
There was a problem hiding this comment.
can you add an assert about what is selected?
There was a problem hiding this comment.
@CyrusNajmabadi What's the API for doing so? Or does it need an integration test?
There was a problem hiding this comment.
i think you'll need to add a test to CompletionCommandHandlerTests
...Features/CSharpTest/Completion/CompletionProviders/DeclarationNameCompletionProviderTests.cs
Show resolved
Hide resolved
...Features/CSharp/Portable/Completion/CompletionProviders/DeclarationNameCompletionProvider.cs
Outdated
Show resolved
Hide resolved
| { | ||
| return baseMethod switch | ||
| { | ||
| MethodDeclarationSyntax method => namedType.GetMembers(method.Identifier.ValueText).OfType<IMethodSymbol>().ToImmutableArray(), |
There was a problem hiding this comment.
do you want to collect from teh base type as well?
There was a problem hiding this comment.
No strong opinion. I think we can keep it simple for now instead of walking through base types.
CyrusNajmabadi
left a comment
There was a problem hiding this comment.
approving. but if you want to add another test, i would like that.
|
@CyrusNajmabadi Sorry for the delay. I added the test you requested. |
|
|
||
| var parameterSyntax = context.LeftToken.GetAncestor(n => n.IsKind(SyntaxKind.Parameter)) as ParameterSyntax; | ||
| if (parameterSyntax is not { Type: { } parameterType, Parent: { Parent: BaseMethodDeclarationSyntax baseMethod } }) | ||
| return; |
There was a problem hiding this comment.
can you check that the left token is hte last token of the parameter type. i'm actually worried about you offering these names inside the parameter type. Can you add tests that shows this doesn't happen (for example, in the type arg of a generic type).
There was a problem hiding this comment.
@CyrusNajmabadi Likely already handled in GetDeclarationInfoAsync. I'm not sure about the exact test case you're referring to. Something like this?
void M<T>($$) { }There was a problem hiding this comment.
No. more like: void M(List<$$> the left token will be inside a parameter here.
|
overall, i like this. but i do have the concern about this showing up not inside more than just the parameter name. |
| return; | ||
|
|
||
| var parameterSyntax = context.LeftToken.GetAncestor(n => n.IsKind(SyntaxKind.Parameter)) as ParameterSyntax; | ||
| if (parameterSyntax is not { Type: { } parameterType, Parent: { Parent: BaseMethodDeclarationSyntax baseMethod } }) |
There was a problem hiding this comment.
| if (parameterSyntax is not { Type: { } parameterType, Parent: { Parent: BaseMethodDeclarationSyntax baseMethod } }) | |
| if (parameterSyntax is not { Type: { } parameterType, Parent.Parent: BaseMethodDeclarationSyntax baseMethod }) |
There was a problem hiding this comment.
also, we don't want this in the optional initializer value of a parameter either.
There was a problem hiding this comment.
also, we don't want this in the optional initializer value of a parameter either.
I'm not sure what you mean.
// I think this is not handled by declaration name completion at all?
public void M(string s = $$)
{
}There was a problem hiding this comment.
basically, i'm saying that this test doesn't guarantee that (even if some other check does). So it would be good to have a test here for those cases, just to show there's no issue.
There was a problem hiding this comment.
@CyrusNajmabadi Yeah sure adding the test is good for coverage anyway even if already handled. I was trying to make sure I'm properly understanding the scenario you're referring to.
There was a problem hiding this comment.
yup. that's the scenario. the core issue i have with this code is that all it does is check if it's contained within a parameter.
Now, it sounds like there's other code that ensures that we're typing the parameter name. If so, that's great. I just want tests to ensure that works properly. thanks!
…clarationNameCompletionProvider.cs Co-authored-by: CyrusNajmabadi <cyrus.najmabadi@gmail.com>
|
@CyrusNajmabadi Anything left? |
|
Thanks! |
Fixes #52534