Skip to content
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

Offer 'readonly' completion in type contexts #26186

Merged
merged 6 commits into from
May 2, 2018

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Apr 17, 2018

Customer scenario

Type "public" then expect that you are offered a completion for "readonly", so you can type "public readonly struct". Prior to this PR, the completion was not offered.

Bugs this fixes

Fixes #26120

Workarounds, if any

You can always spell out "readonly" without completion help.

Risk & Performance impact

Low. This follows the same pattern used for "public" and other similar keyword recommenders.

Is this a regression from a previous update?

No. "readonly struct" is a new feature in 15.7.

Root cause analysis

This was missed in the IDE test pass.

How was the bug found?

Reported by customer.

@jcouv jcouv added the Area-IDE label Apr 17, 2018
@jcouv jcouv added this to the 15.8 milestone Apr 17, 2018
@jcouv jcouv self-assigned this Apr 17, 2018
@jcouv jcouv requested a review from a team as a code owner April 17, 2018 04:36
private static bool IsValidContextForType(CSharpSyntaxContext context, CancellationToken cancellationToken)
{
return context.IsTypeDeclarationContext(validModifiers: SyntaxKindSet.AllTypeModifiers,
validTypeDeclarations: SyntaxKindSet.ClassStructTypeDeclarations, canBePartial: false, cancellationToken);
Copy link
Member

Choose a reason for hiding this comment

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

can't have a partial readonly struct?

can you have a readonly class? should this just be valid on StructTypeDecls?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Fixed the partial case.

validTypeDeclarations is correct though. It checks the containing type declaration. A readonly struct can be declared inside a class or a struct (there are tests for that).

Copy link
Member

Choose a reason for hiding this comment

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

Gotcha. Thanks!

{
await VerifyAbsenceAsync(
@"new $$");
await VerifyKeywordAsync(SourceCodeKind.Regular, @"new $$");
Copy link
Contributor

Choose a reason for hiding this comment

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

when is it legal to type readonly after new?

Copy link
Contributor

Choose a reason for hiding this comment

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

ah.. i see, i thought this was object creation

Copy link
Contributor

@Neme12 Neme12 Apr 18, 2018

Choose a reason for hiding this comment

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

but this test is still a little odd.. this code would be incorrect outside a class/struct

Copy link
Member Author

Choose a reason for hiding this comment

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

@Neme12 It is not a requirement for completion to strictly only offer was is allowed. It's better to offer a bit too much than bit too little.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jcouv I didn't mean that you have to change the behavior and add a test to make sure it's not offered here. I just think it would be better to test this in a scenario where it makes sense (inside a class). I don't care if it's offered here or not. But I know we do care it's offered inside a class after new.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for clarifying.
What's the scenario where new readonly is useful inside a class?

Copy link
Contributor

Choose a reason for hiding this comment

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

class B
{
    protected struct S { }
}

class C : B
{
    new readonly struct S { }
}

Copy link
Member

Choose a reason for hiding this comment

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

class OuterClass
{
    public struct InnerStruct
    {

    }

    class InnerClass : OuterClass
    {
        public new readonly struct InnerStruct
        {

        }
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

Note: this is super corner case. i personally wouldn't care much if this didn't happen, or came later.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. I expect it will just work. I'll add a test

@Neme12
Copy link
Contributor

Neme12 commented Apr 18, 2018

I think there is the same issue with ref not offered for ref struct. When that gets fixed, we should check that things like "readonly ref struct" work as well.

@Neme12
Copy link
Contributor

Neme12 commented Apr 18, 2018

Also, did you check that the "struct" keyword is offered after readonly?

@Neme12
Copy link
Contributor

Neme12 commented Apr 18, 2018

At the same time, please make sure struct is not offered in these places:

class C
{
    void M()
    {
        ref $$
        ref readonly $$
        ref var x = ref $$
    }
}

@jcouv
Copy link
Member Author

jcouv commented Apr 18, 2018

@Neme12 I'll update the PR to make sure that ref is offered (for typing ref struct and readonly ref struct) and that struct is offered (for ref struct, readonly struct and readonly ref struct).

I don't plan to tighten the completion though (readonly may be offered in some places where it's inappropriate). Not only is that lower priority, from my understanding, but I also suspect that is an existing problem, since I mimicked the behavior for public and private keywords.

public async Task TestAfterReadonlyInMethod()
{
// struct is not useful here, but offered anyways
await VerifyAbsenceAsync(SourceCodeKind.Regular,
Copy link
Contributor

@Neme12 Neme12 Apr 19, 2018

Choose a reason for hiding this comment

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

"offered anyways" VerifyAbsence?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. Thanks

Copy link
Contributor

Choose a reason for hiding this comment

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

but in cases above in TestAfterReadonlyRef, TestAfterRef etc it should be offered right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks

Copy link
Member Author

Choose a reason for hiding this comment

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

It should be fixed now. Thanks!

@jcouv jcouv added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Apr 19, 2018
@jcouv jcouv removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Apr 20, 2018
@jcouv
Copy link
Member Author

jcouv commented Apr 26, 2018

@dotnet/roslyn-ide for review. Thanks

SyntaxKind.UnsafeKeyword
SyntaxKind.UnsafeKeyword,
SyntaxKind.RefKeyword,
SyntaxKind.ReadOnlyKeyword
Copy link
Member

Choose a reason for hiding this comment

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

💡 Include a , at the end of the list, so if we ever have to add items to the end of the list the diff doesn't need to show a change on this line (see e.g. how it would have been better if the line with UnsafeKeyword did not need to change here).

@@ -53,6 +53,7 @@ internal static partial class SyntaxTreeExtensions
case SyntaxKind.VolatileKeyword:
case SyntaxKind.UnsafeKeyword:
case SyntaxKind.AsyncKeyword:
case SyntaxKind.RefKeyword:
Copy link
Member

Choose a reason for hiding this comment

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

💭 Why are InKeyword, OutKeyword, and ThisKeyword not part of this?

Copy link
Member

Choose a reason for hiding this comment

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

those are not considered modifiers in the sense of how this function is working. This is for the modifiers you get on a member or type decl. The method could have its name update accordingly though.

@dpoeschl
Copy link
Contributor

dpoeschl commented Apr 27, 2018

retest windows_debug_unit32_prtest please
Retest reason: jenkins build was gone

@jcouv
Copy link
Member Author

jcouv commented May 2, 2018

@jinujoseph for ask-mode approval for 15.8. Thanks

1 similar comment
@jcouv
Copy link
Member Author

jcouv commented May 2, 2018

@jinujoseph for ask-mode approval for 15.8. Thanks

@jcouv jcouv merged commit 8424006 into dotnet:master May 2, 2018
@jcouv jcouv deleted the readonly-completion branch May 2, 2018 16:19
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.

No IntelliSense suggestion for readonly struct
6 participants