Skip to content

Fixing 'else' keyword completion#25703

Merged
jcouv merged 15 commits intodotnet:masterfrom
Neme12:elseRecommender
Apr 17, 2018
Merged

Fixing 'else' keyword completion#25703
jcouv merged 15 commits intodotnet:masterfrom
Neme12:elseRecommender

Conversation

@Neme12
Copy link
Copy Markdown
Contributor

@Neme12 Neme12 commented Mar 25, 2018

fixes #25336

I tried rewriting the tests using theory at the end to make them less overwhelming and significantly reduce the repetition, but I'm not sure if it's the right thing to do considering that this sort of approach isn't used in any other tests.
@CyrusNajmabadi I think I remember you saying that tests should contain the literal code so that it's easy to understand each one separately and we should generally avoid using any sort of helpers. Do you think what I did here is acceptable?

@Neme12 Neme12 requested a review from a team as a code owner March 25, 2018 02:08
@jcouv jcouv added Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee. labels Mar 25, 2018
Console.WriteLine();
}
$@"if (true)
{statement}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i personally dislike this. I cannot see what's happening. My tests are now non-local.

The only sort of 'theory' approach i've ever been ok with is targetted, simple application of theories, where the theory is on hte test method itself. if i have to look up more than 2-3 lines, or i have to go look at another class/method etc. then i've completely lost the plot on what the test is testing. Previously i could see this exactly. Now i can't. this is a net negative for me here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ok I can revert it back... it just seemed to me like this way it's much easier to read, review and spot bugs in the tests, whereas with a lot of duplication it's really easy to miss something

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 25, 2018

Choose a reason for hiding this comment

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

and also more importantly, when writing more tests people will usually avoid writing all the cases and just do some of them (or more likely just one) to not bother with writing so much duplication, which can sometimes miss bugs due to missing test cases

Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi Mar 25, 2018

Choose a reason for hiding this comment

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

IMO, tests for this sort of thing should be written based on the expected interesting cases based on the code change. So, your change adds an arbitrary walk upwards looking for if-statements. And it also checks that if-statement for the last token of the true-statement within it.

It seems like we could test this out with some very judicious tests that would demonstrate that both of those pieces of logic are working properly. For example, we sholud not see 'else' here:

if (true) 
     Console.WriteLine()
$$

Because the last token of hte true-statement would be the missing-token ; and htat's not what we're on. Similarly, we should see if after Console.WriteLine();. And we should see if htis if it deeply nested. Testing one level deep, two levels deep, and something larger should be sufficient.

You also removed some existing branches in the original code. We shoudl ensure appropriate behavior remains for those.

This does not seem like a lot of tests needed. It tests positive and negative cases. And feels appropriate given the code change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I'll add tests for that too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

it just seemed to me like this way it's much easier to read, review and spot bugs in the tests

It's harder for me, because i ca'nt just look at a test and know what it means. I have to go analyze other parts of the test file to know. We try to avoid that. I've accepted some Theories in hte past where the theory travels with the test method. and the theory itself is very tiny. i.e. i've seen theories that try to do major replacements in the code, and def make it less clear.

I'm on the fence here about this one. But, give my previous post, i don't think it adds substantial value given just writing the 6ish test cases manually.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes. this form seems ok to me. i can live with inline data at individual test sites.

Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

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

I like the code change. i don't like the test change. that said, i'm sympathetic about the amount of duplication you feel you're incur here.


[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestAfterIfBlock()
class Statements : DataAttribute
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

private

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

I tried rewriting the tests using theory at the end to make them less overwhelming

To me this i a non-problem. I don't think of test quantity as being "overwhelming". It's just a lot of tests. There are still the same number of tests when you use theories, you just have used a generation technique to produce the tests, which i think decreases clarity.

At the end of hte day you generally have 100% test coverage until you break something and either a single test breaks, or a set of tests break. You go and look at those tests, figure it out and rinse/repeat. The number of total tests isn't really relevant here.

@Neme12
Copy link
Copy Markdown
Contributor Author

Neme12 commented Mar 25, 2018

@CyrusNajmabadi What if I put InlineData on each test instead but still kept it as a theory? How would you feel about that?

if (token.IsKind(SyntaxKind.CloseBraceToken) && ifStatement.Statement is BlockSyntax && token == ((BlockSyntax)ifStatement.Statement).CloseBraceToken)
{
return true;
if (ifStatement.Statement.GetLastToken(includeSkipped: true, includeZeroWidth: true) == token)
Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 25, 2018

Choose a reason for hiding this comment

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

I actually have no idea why includeSkipped: true is needed here. There's no test that covers this, everything passes either way.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IncludeSkipped is likely appropriate, though harder to test for. It basically means, "if the parser ran into stuff it totally didn't understand, but it attached it to that staement, then treat hte last token of that skipped run of tokens as the last token of the statement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It seems really unlikely that there would be a skipped semicolon at the end. That usually parsers as a separate empty statement.

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 25, 2018

Choose a reason for hiding this comment

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

In the original implementation, else is not offered in code like this (because the last token including skipped is not a semicolon or a close brace):

if (true)
    Console.WriteLine();,

But with this PR, it is offered. Which is the expected behavior here? To offer or not offer? I will add a test either way. If it's to not offer, includeSkipped should actually be removed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Which is the expected behavior here?

The expected behavior is whatever is easiest to provide :)

You could literally have this work, and that would be ok. Or it could not work, and that would be ok.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

whatever is easiest to provide

The difference is just in setting includeSkipped to either true or false. Then I guess easiest to provide would be to not specify the argument?

Copy link
Copy Markdown
Contributor Author

@Neme12 Neme12 Mar 27, 2018

Choose a reason for hiding this comment

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

Given that there is no completion for anything after such skipped tokens and the fact that if you type else at that point it doesn't actually end up being an else clause (it becomes a skipped token too), I'm removing this.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi What if I put InlineData on each test instead but still kept it as a theory? How would you feel about that?

I would probably be ok with that. though i like the InlineData to be small to be clear as to what's going on. In your case, it's likely ok. But it's not a blanket rule that that's ok for all tests.

if (token.IsKind(SyntaxKind.CloseBraceToken) && ifStatement.Statement is BlockSyntax && token == ((BlockSyntax)ifStatement.Statement).CloseBraceToken)
{
return true;
if (ifStatement.Statement.GetLastToken(includeZeroWidth: true) == token)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

warrants a comment. but not a big deal.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed in 0c495ca

Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

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

Thanks!

@jcouv jcouv added this to the 15.8 milestone Mar 27, 2018
@Neme12
Copy link
Copy Markdown
Contributor Author

Neme12 commented Mar 28, 2018

retest windows_debug_vs-integration_prtest please

@Neme12
Copy link
Copy Markdown
Contributor Author

Neme12 commented Mar 30, 2018

retest windows_debug_vs-integration_prtest please

@Neme12
Copy link
Copy Markdown
Contributor Author

Neme12 commented Apr 6, 2018

retest windows_debug_spanish_unit32_prtest please

Copy link
Copy Markdown
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks

@jcouv
Copy link
Copy Markdown
Member

jcouv commented Apr 17, 2018

@dotnet/roslyn-ide Can this community PR get a final review?

Copy link
Copy Markdown
Contributor

@dpoeschl dpoeschl left a comment

Choose a reason for hiding this comment

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

Nice! Thanks!

@jcouv jcouv merged commit 5aedc27 into dotnet:master Apr 17, 2018
@Neme12 Neme12 deleted the elseRecommender branch April 17, 2018 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing completion for 'else' after nested if with else

4 participants