-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Make event backing fields accessible to third-party analyzers #40572
Conversation
…perty backing fields
…h the same name as the event of interest
…d prior to being added to the type members collection
… a ref to the event, so taking a ref/pointer to the whole struct should apply to field-like events as well as fields.
if ((member as FieldSymbol)?.AssociatedSymbol is EventSymbol) | ||
{ | ||
continue; | ||
} |
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.
Do you have suggestions for alternatives? This is added to avoid the assertion on line 72:
Debug.Assert(result.IsMultiViable || result.IsClear || result.Error != null); |
var symbol = member switch | ||
{ | ||
FieldSymbol { AssociatedSymbol: PropertySymbol p } => p, | ||
_ => member | ||
}; | ||
|
||
var symbol = field.AssociatedSymbol is PropertySymbol || field.AssociatedSymbol is EventSymbol ? field.AssociatedSymbol : field; |
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 do you think of making this field.AssociatedSymbol ?? field
?
{ | ||
continue; | ||
} | ||
|
||
var fieldType = field.TypeWithAnnotations; |
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.
To be perfectly equivalent to the original code, this would be:
var fieldType = (field.AssociatedField as EventSymbol)?.TypeWithAnnotations ?? field.TypeWithAnnotations;
But it seems unlikely that they would differ.
case SymbolKind.Field: | ||
if (((FieldSymbol)this).AssociatedSymbol is EventSymbol) | ||
return false; | ||
break; |
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 correct?
private static MetadataReference CompileToPEReference(string source) | ||
{ | ||
using var peStream = new MemoryStream(); | ||
|
||
Assert.True(CreateCompilation(source).Emit(peStream).Success); | ||
|
||
peStream.Position = 0; | ||
|
||
return MetadataReference.CreateFromStream(peStream); | ||
} | ||
|
||
private static IAssemblySymbol GetAssemblySymbolForReference(MetadataReference reference) | ||
{ | ||
var compilation = (Compilation)CSharpCompilation.Create( | ||
assemblyName: null, | ||
references: new[] { reference }, | ||
options: new CSharpCompilationOptions( | ||
OutputKind.DynamicallyLinkedLibrary, | ||
metadataImportOptions: MetadataImportOptions.All)); | ||
|
||
return (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(reference); | ||
} |
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.
-
Are there existing helpers I should use/places to add tests if I want to specifically test end to end, source to PublicModel.ISymbol?
-
If not, where should this code go?
} | ||
} | ||
|
||
members.AddRange(fieldMembers); |
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.
members.AddRange(fieldMembers); [](start = 19, length = 32)
Does this also affects fields that back auto-properties?
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.
According to the original Debug.Assert, field.AssociatedSymbol
is either null or its Kind
is SymbolKind.Event
. That means that property backing fields are never in fieldMembers
at this point. I'm not sure why.
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 don't think we would want to change the set of members returned for a NamedTypeSymbol. The model is meant to reflect the language and, form the C# language point of view, there is no backing field member. As you can see we went through a big trouble to hide fields like that and that was intentional. If analyzers or other tools need to get to the backing fields, it would be interesting to understand the real world scenarios. And if we will find them compelling, then perhaps we can add AssociatedSymbol API (or AssociatedField API) to IEventSymbol interface.
Why is it that property backing fields are returned in GetMembers? One real-world scenario cares about backing fields but doesn't care about the difference between properties and events. 💡 Is there any way you'd consider removing property backing fields from GetMembers? That would solve an unrelated problem that is complicating a C# feature. |
@AlekseyTs clearly there is a community ask to expose these members. Even our documentation for |
Then it should be easy to present real world compelling scenarios.
This is a significant design change not merely a bug fix. Why don't you bring this to public API council? |
Here are the two real-world use cases I know of: #36259 (comment) |
Someone will have distill these to clear summary about the use cases, so that multiple people wouldn't have to sift trough discussion threads, and/or try to infer something from code snippets, etc |
Yes, we could consider doing this. Again, having a compelling scenario can help us make a decision. In fact, there is a "TODO" comment in code indicating that we probably had intention to do so, and it is not clear whether we explicitly decided against that, or simply didn't get to implementing the change (https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs#L3098):
|
@jnm2 can we please get a clear summary of the use case here? A motivating example will help us understand if this is the correct way to solve the issue, or if a separate API is needed. Thanks. |
I believe a separate API is needed, so I'll close this. Further, it would unblock design options for dotnet/csharplang#140 if property backing fields were also deliberately excluded from the ITypeSymbol.GetMembers() collection the way event backing fields are. That would necessitate an API to retrieve backing fields for property symbols as well as event symbols for the sake of third-party analyzers. |
Fixes #36259. Other than where I commented, all changes are meant to restore identical outcomes now that the event backing field comes along with the other fields for free. I seemed to remove a lot of workarounds.