-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Polyfill the incremental generator ForAttributeWithMetadataName from roslyn (for EventSourceGeneration). #71662
Changes from 7 commits
498b5e6
6cade39
f8b212b
2ed84a2
b2847be
e09862d
4ce9f76
c2a0af8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,119 +4,96 @@ | |
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
using System.Threading; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; | ||
|
||
namespace Generators | ||
{ | ||
public partial class EventSourceGenerator | ||
{ | ||
private static bool IsSyntaxTargetForGeneration(SyntaxNode node, CancellationToken cancellationToken) => | ||
node is ClassDeclarationSyntax { AttributeLists.Count: > 0 }; | ||
|
||
private static EventSourceClass? GetSemanticTargetForGeneration(GeneratorSyntaxContext context, CancellationToken cancellationToken) | ||
private static EventSourceClass? GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken) | ||
{ | ||
const string EventSourceAutoGenerateAttribute = "System.Diagnostics.Tracing.EventSourceAutoGenerateAttribute"; | ||
const string EventSourceAttribute = "System.Diagnostics.Tracing.EventSourceAttribute"; | ||
|
||
var classDef = (ClassDeclarationSyntax)context.Node; | ||
SemanticModel sm = context.SemanticModel; | ||
var classDef = (ClassDeclarationSyntax)context.TargetNode; | ||
NamespaceDeclarationSyntax? ns = classDef.Parent as NamespaceDeclarationSyntax; | ||
if (ns is null) | ||
{ | ||
if (classDef.Parent is not CompilationUnitSyntax) | ||
{ | ||
// since this generator doesn't know how to generate a nested type... | ||
return null; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. moved this check up. there was no point doing it in a loop since it would always be the same result. and if it always caused us to continue, we'd never set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: this logic is wrong in that it can't handle: A better check would likely be to do |
||
|
||
EventSourceClass? eventSourceClass = null; | ||
string? nspace = null; | ||
|
||
bool autoGenerate = false; | ||
foreach (AttributeListSyntax cal in classDef.AttributeLists) | ||
foreach (AttributeData attribute in context.TargetSymbol.GetAttributes()) | ||
{ | ||
foreach (AttributeSyntax ca in cal.Attributes) | ||
if (attribute.AttributeClass?.Name != "EventSourceAttribute" || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in general, try to do the basic name check first. it's much faster and allocation-light versus ToDisplayString |
||
attribute.AttributeClass.ToDisplayString() != EventSourceAttribute) | ||
{ | ||
if (sm.GetSymbolInfo(ca, cancellationToken).Symbol is not IMethodSymbol caSymbol) | ||
{ | ||
// badly formed attribute definition, or not the right attribute | ||
continue; | ||
} | ||
continue; | ||
} | ||
|
||
string attributeFullName = caSymbol.ContainingType.ToDisplayString(); | ||
nspace ??= ConstructNamespace(ns); | ||
|
||
if (attributeFullName.Equals(EventSourceAutoGenerateAttribute, StringComparison.Ordinal)) | ||
{ | ||
autoGenerate = true; | ||
continue; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we required having EventSourceAutoGenerateAttribute before. otherwise, autogenerate would not be true, and we'd bail out below. |
||
} | ||
string className = classDef.Identifier.ValueText; | ||
string name = className; | ||
string guid = ""; | ||
|
||
if (!attributeFullName.Equals(EventSourceAttribute, StringComparison.Ordinal)) | ||
{ | ||
continue; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the code below would only execute if we had EventSourceAttribute, so that's what we maintain below. |
||
ImmutableArray<KeyValuePair<string, TypedConstant>> args = attribute.NamedArguments; | ||
foreach (KeyValuePair<string, TypedConstant> arg in args) | ||
{ | ||
string argName = arg.Key; | ||
string value = arg.Value.Value?.ToString(); | ||
|
||
string nspace = string.Empty; | ||
NamespaceDeclarationSyntax? ns = classDef.Parent as NamespaceDeclarationSyntax; | ||
if (ns is null) | ||
{ | ||
if (classDef.Parent is not CompilationUnitSyntax) | ||
{ | ||
// since this generator doesn't know how to generate a nested type... | ||
continue; | ||
} | ||
} | ||
else | ||
switch (argName) | ||
{ | ||
nspace = ns.Name.ToString(); | ||
while (true) | ||
{ | ||
ns = ns.Parent as NamespaceDeclarationSyntax; | ||
if (ns == null) | ||
{ | ||
break; | ||
} | ||
|
||
nspace = $"{ns.Name}.{nspace}"; | ||
} | ||
case "Guid": | ||
guid = value; | ||
break; | ||
case "Name": | ||
name = value; | ||
break; | ||
} | ||
} | ||
|
||
string className = classDef.Identifier.ToString(); | ||
string name = className; | ||
string guid = ""; | ||
if (!Guid.TryParse(guid, out Guid result)) | ||
{ | ||
result = GenerateGuidFromName(name.ToUpperInvariant()); | ||
} | ||
|
||
SeparatedSyntaxList<AttributeArgumentSyntax>? args = ca.ArgumentList?.Arguments; | ||
if (args is not null) | ||
{ | ||
foreach (AttributeArgumentSyntax arg in args) | ||
{ | ||
string argName = arg.NameEquals!.Name.Identifier.ToString(); | ||
string value = sm.GetConstantValue(arg.Expression, cancellationToken).ToString(); | ||
|
||
switch (argName) | ||
{ | ||
case "Guid": | ||
guid = value; | ||
break; | ||
case "Name": | ||
name = value; | ||
break; | ||
} | ||
} | ||
} | ||
eventSourceClass = new EventSourceClass(nspace, className, name, result); | ||
continue; | ||
} | ||
|
||
if (!Guid.TryParse(guid, out Guid result)) | ||
{ | ||
result = GenerateGuidFromName(name.ToUpperInvariant()); | ||
} | ||
return eventSourceClass; | ||
} | ||
|
||
eventSourceClass = new EventSourceClass(nspace, className, name, result); | ||
continue; | ||
} | ||
} | ||
private static string? ConstructNamespace(NamespaceDeclarationSyntax? ns) | ||
{ | ||
if (ns is null) | ||
return string.Empty; | ||
|
||
if (!autoGenerate) | ||
string nspace = ns.Name.ToString(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note. this is not correct. if you have |
||
while (true) | ||
{ | ||
return null; | ||
ns = ns.Parent as NamespaceDeclarationSyntax; | ||
if (ns == null) | ||
{ | ||
break; | ||
} | ||
|
||
nspace = $"{ns.Name}.{nspace}"; | ||
} | ||
|
||
return eventSourceClass; | ||
return nspace; | ||
} | ||
|
||
// From System.Private.CoreLib | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -358,13 +358,13 @@ private static IncrementalStubGenerationContext CalculateStubInformation( | |
// Since the char type in an array will not be part of the P/Invoke signature, we can | ||
// use the regular blittable marshaller in all cases. | ||
new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true), | ||
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, Scenario.ElementIn, Scenario.ElementRef, Scenario.ElementOut)); | ||
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut)); | ||
// We don't need to include the later generator factories for collection elements | ||
// as the later generator factories only apply to parameters. | ||
generatorFactory = new AttributedMarshallingModelGeneratorFactory( | ||
generatorFactory, | ||
elementFactory, | ||
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, Scenario.ManagedToUnmanagedIn, Scenario.ManagedToUnmanagedRef, Scenario.ManagedToUnmanagedOut)); | ||
new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still not clear on why these changes are necessary in this PR. Is this PR renaming Scenario to MarshalMode or something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These were bad merges as i was undoing the changes. The files are now untouched. Note: this will be squashed when PR is merged, so there won't be random cruft like this in your repo history. However, i don't like squashing as the PR is in progress as that can make it harder to see what's going on. If you want though i can pre-squash. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Nope. |
||
|
||
generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); | ||
} | ||
|
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 don't need to check for EventSourceAutoGenerateAttribute. we wouldn't have gotten here unless we had that attribute on the class we're examining.