-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Don't add parenthesis when committing type with accessible nested type using dot #80846
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
Conversation
| if (typeMembers.Any(t => t.DeclaredAccessibility == Accessibility.Public)) | ||
| return true; | ||
|
|
||
| return typeMembers.Any(t => t.DeclaredAccessibility == Accessibility.Internal) && |
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.
Maybe we could make it even less aggressive (and simpler) in auto-completing () by only checking for types declared public, thoughts?
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.
We have an IsAccessibleTo helper. Can you use that?
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.
@CyrusNajmabadi Done. Could you pls take another look?
| else if (context.IsObjectCreationTypeContext) | ||
| { | ||
| // If this is a type symbol/alias symbol, also consider appending parenthesis when later, it is committed by using special characters, | ||
| // and the type is used as constructor |
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 this comment stale now? I can't quite tell. But it does allude to what I'm a bit confused about -- should we be explicitly adding the parenthesis only when there isn't a commit character, or the user typed a paren? I guess this original behavior is making me scratch my head in the first place...
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 think this comment still applies, especially when combined with the new comment a couple of lines below. I don't remember the original design, but this behavior doesn't feel counter intuitive to me. Since this is after new, the type name can only be used as a constructor (except the nested type scenario, which is what this PR's about), if you commit with . or ;, you'd need to move cursor back and type the ( otherwise, and when you commit TAB, you can keep on typing ( without moving cursor
| { | ||
| foreach (var typeMember in typeSymbol.GetTypeMembers()) | ||
| { | ||
| if (typeMember.DeclaredAccessibility <= Accessibility.Protected) |
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.
note: this is not really accurate. for example, you can have protected/private nested types that are then referencable from within the inner type. i think you want if (typeMember.IsAccessibleWithin( and then pass the .ContainingType for where the operation was invokved from. Which i think is on hte syntax context. So basically, get rid of the first two 'if' checks, and update the bottom one.
these are good to test as well.
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.
yea, this is intended to be a heuristic to cover common cases. Because we might be handed a speculative member model here (see this), I think we can't reliably do something like below, otherwise it might throw
var containingType = syntaxContext.SemanticModel.GetDeclaredSymbol(syntaxContext.ContainingTypeDeclaration!, cancellationToken);
if (typeMember.IsAccessibleWithin(containingType))
...you can have protected/private nested types that are then referencable from within the inner type
I think this is fine. The change is only relevant when you are typing the outer type name, and I think people typically don't access the nested ones via the outer one when they are within the inner or derived type. For example
class Outer
{
class Inner1
{
void M()
{
// you could use `Inner` instead of `Outer.Inner` 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.
I think this is fine. The change is only relevant when you are typing the outer type name, and I think people typically don't access the nested ones via the outer one when they are within the inner or derived type. For example
That's a reasonable point. Though i think you'll still just be in an easier scenario simplifying, and using hte above approach. it's a case where, IMO, it's simpler and more correct.
From offline convo, you should be fine to call GetDeclaredSymbol even for speculative scenarios.
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.
Talked offline, the comment about speculative member model above stands so merging as is.
added more comments in the code to explain this.
src/Features/Core/Portable/Completion/Providers/SymbolCompletionItem.cs
Outdated
Show resolved
Hide resolved
CyrusNajmabadi
left a comment
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.
Preemptively signing off if you make the suggested change. if you can't, please let me know why. thanks.
|
Specifically, the suggested change about checking accessibility properly. not the minor suggestion to use an expression-bodied member. |
fix #78515, #51629