Insert full method call#49916
Conversation
be84409 to
aecdcd6
Compare
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Outdated
Show resolved
Hide resolved
aecdcd6 to
ebe09f7
Compare
jmarolf
left a comment
There was a problem hiding this comment.
After staring at this for a long time I can't think of a better way to do this with the APIs we have.
...es/Core/Implementation/IntelliSense/SignatureHelp/Controller.Session_SetModelSelectedItem.cs
Outdated
Show resolved
Hide resolved
src/EditorFeatures/Core/Implementation/IntelliSense/SignatureHelp/Controller.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/CSharp/Impl/Snippets/SnippetFunctions/SnippetFunctionArgumentValue.cs
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetCommandHandler.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetCommandHandler.cs
Show resolved
Hide resolved
...io/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionArgumentValue.cs
Outdated
Show resolved
Hide resolved
...io/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionArgumentValue.cs
Outdated
Show resolved
Hide resolved
...io/Core/Def/Implementation/Snippets/SnippetFunctions/AbstractSnippetFunctionArgumentValue.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Test/Snippets/VisualBasicSnippetExpansionClientTests.vb
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Outdated
Show resolved
Hide resolved
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Show resolved
Hide resolved
CyrusNajmabadi
left a comment
There was a problem hiding this comment.
overall, i have no complaints. just some possible suggestions on targetted cleanup that might make things a bit more understandable. def curious if Jason's 'embed parameter info directly in snippet' approach could work.
src/VisualStudio/VisualBasic/Impl/Snippets/SnippetFunctions/SnippetFunctionArgumentValue.vb
Show resolved
Hide resolved
This comment has been minimized.
This comment has been minimized.
jasonmalinowski
left a comment
There was a problem hiding this comment.
Just more questions on how this thing is working...the statement management is still a bit murky to me.
There was a problem hiding this comment.
Why the switch to SemanticModel?
There was a problem hiding this comment.
➡️ AnalyzerRunner was going to need it anyway. Document wasn't providing much. It was mentioned in earlier review comments, and I knew the change was eventually needed, so I implemented it.
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Show resolved
Hide resolved
| /// <param name="methodName">The name of the method as it should appear in code.</param> | ||
| /// <param name="includeMethod"> |
There was a problem hiding this comment.
I guess can the docs say if includeMethod is false, then methodName should be ignored? I guess I'm not sure if "can be document separately" is really helping the clarity here.
| // Create a snippet field for the argument. The name of the field matches the parameter name, and the | ||
| // default value for the field is provided by a call to the internal ArgumentValue snippet function. The | ||
| // parameter to the snippet function is a serialized SymbolKey which can be mapped back to the | ||
| // IParameterSymbol. |
There was a problem hiding this comment.
We don't know the signature to use until Signature Help tells us.
Exactly -- this method isn't running until you know the signature, but by this you can just directly put the values in.
but it increases coupling and would be even more difficult to understand.
I'd say this is far more coupled and more difficult to understand, since there's an implicit handshake between this code and the function implementation.
There was a problem hiding this comment.
Any reason this can't just be Clear()? Yeah, it'll clear the value you're overwriting in the next line, but would mean it's more impervious to any other refactoring where somebody puts some other non-symbol state in that matters.
There was a problem hiding this comment.
➡️ The expansion session is still active at this point. Clear would not accurately reflect the state.
There was a problem hiding this comment.
Which session? It's not starting until the next line, right? If there was a prior session it seems like we aren't caring about it at this point?
It's possible I'm just missing the scenario here -- I would have presumed this method is only called on the snippet picker UI and so at that point any session going away is moot, and there's nothing to preserve because it's not going to be a method expansion snippet being invoked.
There was a problem hiding this comment.
The presence of an active snippet session does not prevent the snippet picker from working, so while it's not common for this case to be hit with an active non-null session it is possible. Even if it's valid to clear the active session while it remains active, it would require substantially more explanation as to why doing so is OK.
In other words, among the available options for clearing state here, none of them is obviously correct and this one is the least confusing.
There was a problem hiding this comment.
We feel confident there's no S_FALSE returns? 😄
There was a problem hiding this comment.
➡️ The documentation for IVsExpansionSession.GetFieldValue does not allow for S_FALSE returns, and the current code worked in practice.
There was a problem hiding this comment.
It feels like this really needs a comment here somewhere to explain the intent of this. It's...not obvious.
There was a problem hiding this comment.
Also making a constant out of "placeholder" ("PlaceholderForEmptyArguments"?) would make this a bit less magic.
There was a problem hiding this comment.
➡️ will document and create a field
src/VisualStudio/Core/Def/Implementation/Snippets/AbstractSnippetExpansionClient.cs
Outdated
Show resolved
Hide resolved
| // It's unclear if/how this state would occur, but if it does we would throw an exception trying to | ||
| // use it. Just return immediately. |
There was a problem hiding this comment.
Want to at least change the comment since "It's unclear if/how this state would occur" isn't the case?
There was a problem hiding this comment.
So I don't really see how _methods is being used here -- I see it being used in IsFullMethodCallSnippet but it seems like can just be a boolean state of whether we're in this mode or not?
There was a problem hiding this comment.
➡️ It probably could be changed, but this is going to have to change anyway as part of nested call support. Leaving it for now since changes in this space have caused undesired "iteration" churn (subtle fallout) that I don't want to go through again knowing the current form works.
There was a problem hiding this comment.
Oh I think I see the bit I might be missing: if you do tab + tab on a method name we'll stick in parenthesis, we stick the methods here to recognize the name later. And this line:
var symbolName = _state._method?.Name ?? _state._methods.FirstOrDefault()?.Name;
Is just doing FirstOrDefault() because all the methods in the group have the same name? Yeah, this is really confusing. 😦
57a9601 to
41a2612
Compare
| // This expansion is not derived from a symbol, so make sure the state isn't tracking any symbol | ||
| // information | ||
| _state.ClearSymbolInformation(); |
There was a problem hiding this comment.
Is this just a paranoia check that we don't imagine this could happen, or can this happen in some way?
|
|
||
| if (expansion.InsertSpecificExpansion(doc, adjustedTextSpan, this, LanguageServiceGuid, pszRelativePath: null, out _state._expansionSession) == VSConstants.S_OK) | ||
| { | ||
| _state._preserveSymbols = false; |
There was a problem hiding this comment.
So it's not clear to me why _preserveSymbols is necessary here -- you're already holding onto the local to assert the symbols aren't changing, why not just instead just reassign the _state? Then you can get rid of _preserveSymbols?
There was a problem hiding this comment.
The API is reentrant (other methods in this class run during a deeply-nested call stack) and eventually end up back here. _preserveSymbols keeps those nested calls from changing state they aren't supposed to touch.
There was a problem hiding this comment.
So as best I can tell from the review is the reentrancy concern here is when you call insert specific the prior session will be dismissed, which if we don't set that wipes out state. But what other call backs are happening that need the state? Is it just the snippet functions which we think can be removed?
There was a problem hiding this comment.
Which session? It's not starting until the next line, right? If there was a prior session it seems like we aren't caring about it at this point?
It's possible I'm just missing the scenario here -- I would have presumed this method is only called on the snippet picker UI and so at that point any session going away is moot, and there's nothing to preserve because it's not going to be a method expansion snippet being invoked.
| /// <summary> | ||
| /// The current symbol presented in an Argument Provider snippet session. This may be null if Signature Help | ||
| /// has not yet provided a symbol to show. | ||
| /// </summary> | ||
| public IMethodSymbol _method; |
There was a problem hiding this comment.
Oh I think I see the bit I might be missing: if you do tab + tab on a method name we'll stick in parenthesis, we stick the methods here to recognize the name later. And this line:
var symbolName = _state._method?.Name ?? _state._methods.FirstOrDefault()?.Name;
Is just doing FirstOrDefault() because all the methods in the group have the same name? Yeah, this is really confusing. 😦
…to insert-full-call
This issue was introduced by dotnet#50552 and caused signature help to misbehave while typing.
jasonmalinowski
left a comment
There was a problem hiding this comment.
Looks good to put in the feature branch; I think next steps are well-tracked.
Implements the case from #12363 where a method takes one or more arguments.
ArgumentProviderheuristics will be added in follow-up.Builds on #49909