-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Omnisharp VS Code Issue 1814 Fix #1007
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor changes from me, will let @DustinCampbell review too.
package-lock.json
Outdated
@@ -0,0 +1,3 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should probably drop this file. 😄
@@ -96,27 +97,43 @@ public SignatureHelpService(OmniSharpWorkspace workspace) | |||
var invocation = node as InvocationExpressionSyntax; | |||
if (invocation != null && invocation.ArgumentList.Span.Contains(position)) | |||
{ | |||
var i = await document.GetSemanticModelAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably give i
a slightly better name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this semanticaModel
and replace the call to await document.GetSemanticModelAsync()
below with the variable as well. There's no need to call it twice.
@@ -153,6 +153,7 @@ public class MyClass | |||
} | |||
} | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra whitespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work fixing the bug! There's just some code clean up left to do.
@@ -1,13 +1,21 @@ | |||
using Microsoft.CodeAnalysis; | |||
using Microsoft.CodeAnalysis.CSharp.Syntax; | |||
using System.Collections.Generic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: System namespaces should be sorted on top.
@@ -96,27 +97,43 @@ public SignatureHelpService(OmniSharpWorkspace workspace) | |||
var invocation = node as InvocationExpressionSyntax; | |||
if (invocation != null && invocation.ArgumentList.Span.Contains(position)) | |||
{ | |||
var i = await document.GetSemanticModelAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this semanticaModel
and replace the call to await document.GetSemanticModelAsync()
below with the variable as well. There's no need to call it twice.
return new InvocationContext() | ||
{ | ||
SemanticModel = await document.GetSemanticModelAsync(), | ||
Position = position, | ||
Receiver = invocation.Expression, | ||
ArgumentList = invocation.ArgumentList | ||
ArgumentTypes = invocation.ArgumentList.Arguments.Select(argument => i.GetTypeInfo(argument.Expression)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the expression here getting complex enough to extract into a local?
var objectCreation = node as ObjectCreationExpressionSyntax; | ||
if (objectCreation != null && objectCreation.ArgumentList.Span.Contains(position)) | ||
{ | ||
var i = await document.GetSemanticModelAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
semanticModel
rather than i
return new InvocationContext() | ||
{ | ||
SemanticModel = await document.GetSemanticModelAsync(), | ||
Position = position, | ||
Receiver = invocation.Expression, | ||
ArgumentList = invocation.ArgumentList | ||
ArgumentTypes = invocation.ArgumentList.Arguments.Select(argument => i.GetTypeInfo(argument.Expression)), | ||
Separators = invocation.ArgumentList.Arguments.GetSeparators() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment as above
Position = position, | ||
Receiver = objectCreation, | ||
ArgumentList = objectCreation.ArgumentList | ||
ArgumentTypes = objectCreation.ArgumentList.Arguments.Select(argument => i.GetTypeInfo(argument.Expression)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akshita31 we can extract this logic into an extension method or a private function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd consider adding two constructor overloads to InvocationContext which will deal with this initialization. If we want to keep InvocationContext a POCO [Plain Old C# Object] then we can put this logic into a factory method instead. I don't have a strong preference.
ArgumentTypes = attributeSyntax.ArgumentList.Arguments.Select(argument => i.GetTypeInfo(argument.Expression)), | ||
Separators = attributeSyntax.ArgumentList.Arguments.GetSeparators() | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comments as above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you avoid copying and pasting the same code multiple times?
Position = position, | ||
Receiver = objectCreation, | ||
ArgumentList = objectCreation.ArgumentList | ||
ArgumentTypes = objectCreation.ArgumentList.Arguments.Select(argument => i.GetTypeInfo(argument.Expression)), | ||
Separators = objectCreation.ArgumentList.Arguments.GetSeparators() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here
Assert.Single(signature.Parameters); | ||
Assert.Equal("value", signature.Parameters.ElementAt(0).Name); | ||
Assert.Equal("int value", signature.Parameters.ElementAt(0).Label); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary blank line
|
||
namespace OmniSharp.Roslyn.CSharp.Services.Signatures | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lots of extra whitespace here.
@@ -115,7 +115,7 @@ public SignatureHelpFacts(ITestOutputHelper output) | |||
public static void Main(){ | |||
Foo($$); | |||
} | |||
pubic static Foo(bool b, int n = 1234) | |||
public static Foo(bool b, int n = 1234) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have we verified that this code was not intentionally invalid previously?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, didn't verify that. Should I revert it back to the previous state ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't think so. This doesn't look intentional to me based on the test name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should look at the test and decide whether the typo was intentional :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess, based on what's being tested, is that it was unintentional.
int value; | ||
public MyTestAttribute(int value) | ||
{ | ||
this.value =value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a space between =
and value
void TestMethod(int value){ | ||
this.value = value; | ||
} | ||
public class MyTestAttribute : Attribute { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newline here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C# code typically puts opening {
on a new line. Consider using VS to format the document as this will get your style in-line with C#.
@@ -153,6 +153,42 @@ private int Foo(int one, int two, int three) | |||
} | |||
|
|||
[Fact] | |||
public async Task AttributeConstructorSignatureHelp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rchande the tests for signatures in Constructor/Method invocations cover a bunch of scenarios. Is this single test sufficient to cover attribute signatures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akshita31 the test name here seems misaligned with the names of other tests in this file. Since we're replicating a test behavior in a new syntax node, can you align the test names between this and constructor/method signatures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused by the "1st position" comment, but looks like there is plenty of other coverage.
var types = invocation.ArgumentList.Arguments | ||
.Select(argument => invocation.SemanticModel.GetTypeInfo(argument.Expression)); | ||
var types = invocation.ArgumentTypes; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary empty lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @akshita31! The change looks good overall. Like others, I have some style feedback to keep the code in-line with the rest of the repo. I'd also like to be sure that you and @rchande are comfortable with the level of test coverage here. Thanks for the contribution!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good--minor nits.
|
||
namespace OmniSharp.Roslyn.CSharp.Services.Signatures | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blank lines
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blank lines
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blank line
@@ -96,27 +97,43 @@ public SignatureHelpService(OmniSharpWorkspace workspace) | |||
var invocation = node as InvocationExpressionSyntax; | |||
if (invocation != null && invocation.ArgumentList.Span.Contains(position)) | |||
{ | |||
var i = await document.GetSemanticModelAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused?
return new InvocationContext() | ||
{ | ||
SemanticModel = await document.GetSemanticModelAsync(), | ||
SemanticModel = i, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see--can you make this consistent with above, either with "i" or just calling GetSemanticModel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also "i" is probably not the best name :)
@@ -153,6 +153,7 @@ public class MyClass | |||
} | |||
} | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blank line
@@ -115,7 +115,7 @@ public SignatureHelpFacts(ITestOutputHelper output) | |||
public static void Main(){ | |||
Foo($$); | |||
} | |||
pubic static Foo(bool b, int n = 1234) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol
package-lock.json
Outdated
@@ -0,0 +1,3 @@ | |||
{ | |||
"lockfileVersion": 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intenentional?
const string source = | ||
@"using System; | ||
|
||
namespace New_folder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you align the quoted string to the left margin? Makes it easier to tell what the test contents are
@@ -153,6 +153,42 @@ private int Foo(int one, int two, int three) | |||
} | |||
|
|||
[Fact] | |||
public async Task AttributeConstructorSignatureHelp() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about the second parameter, or if there aren't any?
@akshita31 : Your last commit didn't compile (you didn't replace references to |
@@ -192,7 +192,7 @@ public MyTestAttribute(int value) | |||
Assert.Equal("int value", signature.Parameters.ElementAt(0).Label); | |||
} | |||
[Fact] | |||
public async Task SignatureHelpforAttCtorMultipleArg() | |||
public async Task SignatureHelpforAttCtorMultipleParam() | |||
{ | |||
const string source = | |||
@"using System; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this pass? It doesn't look like there's a "$$" anywhere in the markup?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, I see it. Anyway, it seems like the test is called "MultipleParam", but you're only testing in the first parameter position.
double value2; | ||
public MyTestAttribute() | ||
{ | ||
this.value1 = 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can delete all the "value1" and "value2" related stuff since this test doesn't use them.
@@ -153,7 +153,7 @@ private int Foo(int one, int two, int three) | |||
} | |||
|
|||
[Fact] | |||
public async Task SignatureHelpforAttCtorSingleArg() | |||
public async Task SignatureHelpforAttCtorSingleParam() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer that we not abbreviate "attribute".
} | ||
node = node.Parent; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't remove this line (the rule is to leave a blank line between a close brace and a statement).
public IEnumerable<SyntaxToken> Separators { get; set; } | ||
public IEnumerable<SyntaxToken> Separators { get; set; } | ||
|
||
public InvocationContext(SemanticModel SemModel,int Pos,SyntaxNode Rec, ArgumentListSyntax ArgList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lowerCase parameter names.
space after comma
what does "rec" mean?
@@ -11,7 +12,24 @@ internal class InvocationContext | |||
public int Position { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not your fault, but do these properties actually need to be mutable? Can we have them be get-only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes , it works with get-only.
} | ||
public class MyTestAttribute : Attribute | ||
{ | ||
int value1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Up to you, but you can remove the fields and their assignment, if you want to make the test code even simpler.
…essary details in tests
public SemanticModel SemanticModel { get; } | ||
public int Position { get; } | ||
public SyntaxNode Receiver { get; } | ||
public IEnumerable<TypeInfo> ArgumentTypes { get; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra space
public class MyTestAttribute : Attribute | ||
{ | ||
int value1; | ||
double value2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can remove these.
public class MyTestAttribute : Attribute | ||
{ | ||
int value1; | ||
double value2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can still be removed?
This is looking much better! Just a couple more tiny nits from me and that |
return new InvocationContext(semanticModel, position, objectCreation,objectCreation.ArgumentList); | ||
} | ||
var attributeSyntax = node as AttributeSyntax; | ||
if (attributeSyntax != null && attributeSyntax.ArgumentList.Span.Contains(position)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make this a little cleaner by using a pattern match expression:
if (node is AttributeSyntax attributeSyntax && attributeSyntax ... )
@@ -74,7 +72,6 @@ public SignatureHelpService(OmniSharpWorkspace workspace) | |||
} | |||
} | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave this blank line here (the brace is followed by a statement).
@@ -90,24 +91,25 @@ public SignatureHelpService(OmniSharpWorkspace workspace) | |||
// Walk up until we find a node that we're interested in. | |||
while (node != null) | |||
{ | |||
var invocation = node as InvocationExpressionSyntax; | |||
if (invocation != null && invocation.ArgumentList.Span.Contains(position)) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, should have been more specific. Blank line between close brace and statement :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple more nits and I'm OK with this change.
Assert.Equal("value", signature.Parameters.ElementAt(0).Name); | ||
Assert.Equal("int value", signature.Parameters.ElementAt(0).Label); | ||
} | ||
[Fact] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line before method. Should be between close brace and [Fact]
Assert.Equal("value2", signature.Parameters.ElementAt(1).Name); | ||
Assert.Equal("double value2", signature.Parameters.ElementAt(1).Label); | ||
} | ||
[Fact] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line before method. Should be between close brace and [Fact]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks!
ArgumentTypes = argList.Arguments.Select(argument => semModel.GetTypeInfo(argument.Expression)); | ||
Separators = argList.Arguments.GetSeparators(); | ||
} | ||
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, AttributeArgumentListSyntax argList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blank line after before this constructor please!
@TheRealPiotrP : Have your requested changes been addressed? |
dotnet/vscode-csharp#1814
The issue was arising because there was no code to handle the AttributeSyntax type node(which is the case for the Attribute Constructors). But there was a difference between the type of arguments being used by the InvocationExpressionSyntax class and the AttributeSyntax class.Hence instead of keeping the entire Arguments object, we pulled out the relevant properties at the initial stage itself, and a change was made to the InvocationContext class accordingly. A test case has also been added to verify the behavior.
Please review @rchande @TheRealPiotrP @DustinCampbell .