public void Execute(GeneratorExecutionContext context) { // If this isn't working, run 'dotnet build-server shutdown' first. if (Environment .GetEnvironmentVariable($"Debug{nameof(GodotOnReadySourceGenerator)}") == "true") { Debugger.Launch(); } var receiver = context.SyntaxReceiver as OnReadyReceiver ?? throw new Exception(); INamedTypeSymbol GetSymbolByName(string fullName) => context.Compilation.GetTypeByMetadataName(fullName) ?? throw new Exception($"Can't find {fullName}"); var onReadyGetSymbol = GetSymbolByName("GodotOnReady.Attributes.OnReadyGetAttribute"); var onReadyFindSymbol = GetSymbolByName("GodotOnReady.Attributes.OnReadyFindAttribute"); var onReadySymbol = GetSymbolByName("GodotOnReady.Attributes.OnReadyAttribute"); var generateDataSelectorEnumSymbol = GetSymbolByName("GodotOnReady.Attributes.GenerateDataSelectorEnumAttribute"); var injectAncestorValueAttributeSymbol = GetSymbolByName("GodotOnReady.Attributes.InjectAncestorValueAttribute"); var resourceSymbol = GetSymbolByName("Godot.Resource"); var nodeSymbol = GetSymbolByName("Godot.Node"); List <PartialClassAddition> additions = new(); var classSymbols = receiver.AllClasses .Select(classDecl => { INamedTypeSymbol?classSymbol = context.Compilation .GetSemanticModel(classDecl.SyntaxTree) .GetDeclaredSymbol(classDecl); if (classSymbol is null) { context.ReportDiagnostic( Diagnostic.Create( new DiagnosticDescriptor( "GORSG0001", "Inspection", $"Unable to find declared symbol for {classDecl}. Skipping.", "GORSG.Parsing", DiagnosticSeverity.Warning, true ), classDecl.GetLocation() ) ); } return(classSymbol); }) .Distinct(SymbolEqualityComparer.Default) .OfType <INamedTypeSymbol>(); foreach (var classSymbol in classSymbols) { foreach (var attribute in classSymbol.GetAttributes() .Where(a => Equal(a.AttributeClass, generateDataSelectorEnumSymbol))) { var fields = classSymbol.GetMembers() .OfType <IFieldSymbol>() .Where(f => f.IsReadOnly && f.IsStatic) .ToArray(); additions.Add(new DataSelectorEnumAddition( fields, new AttributeSite(classSymbol, attribute))); } foreach (var member in MemberSymbol.CreateAll(classSymbol).ToArray()) { foreach (var attribute in member.Symbol.GetAttributes()) { var site = new MemberAttributeSite( member, new AttributeSite(classSymbol, attribute)); if (Equal(attribute.AttributeClass, injectAncestorValueAttributeSymbol)) { additions.Add(new InjectAncestorValueAddition(site)); } else if (Equal(attribute.AttributeClass, onReadyFindSymbol)) { additions.Add(new OnReadyFindNodeAddition(site)); } else if (Equal(attribute.AttributeClass, onReadyGetSymbol)) { if (member.Type.IsOfBaseType(nodeSymbol)) { additions.Add(new OnReadyGetNodeAddition(site)); } else if (site.AttributeSite.Attribute.NamedArguments .Any(a => a.Key == "Property" && a.Value.Value is string { Length: > 0 }))
public InjectAncestorValueAddition(MemberAttributeSite memberSite) : base(memberSite.AttributeSite.Class) { Member = memberSite.Member; _nodeType = (INamedTypeSymbol)Member.Type; _nodeName = _nodeType.Name; var args = memberSite.AttributeSite.Attribute.ConstructorArguments; if (args.Length > 0) { if (args[0].Value is INamedTypeSymbol s) { _nodeType = s; _nodeName = _nodeType.Name; } } if (args.Length > 1) { if (args[1].Value is string s) { _nodeName = s; } } // We don't want the node, we want a property or field of the node with a specific type. if (!Member.Type.Equals(_nodeType, SymbolEqualityComparer.Default)) { var matches = MemberSymbol.CreateAll(_nodeType) .Where(s => // Ignore backing fields. !s.Symbol.IsImplicitlyDeclared && s.Type.IsOfBaseType(Member.Type)) .ToArray(); if (matches.Length == 0) { string issue = $"No field or property of type \"{Member.Type.ToFullDisplayString()}\" " + $"found in injection source \"{_nodeType.ToFullDisplayString()}\". " + "Expected exactly one"; Diagnostics.Add( Diagnostic.Create( new DiagnosticDescriptor( "GORSG0004", "Inspection", issue, "GORSG.Parsing", DiagnosticSeverity.Error, true ), Member.Symbol.Locations.FirstOrDefault() ) ); } else if (matches.Length > 1) { string issue = $"Multiple members of type \"{Member.Type.ToFullDisplayString()}\" " + $"found in injection source {_nodeType.ToFullDisplayString()}, " + "but expected exactly one. Found: " + string.Join(", ", matches.Select(m => m.Name)); Diagnostics.Add( Diagnostic.Create( new DiagnosticDescriptor( "GORSG0005", "Inspection", issue, "GORSG.Parsing", DiagnosticSeverity.Error, true ), Member.Symbol.Locations.FirstOrDefault() ) ); } else { _sourceMember = matches[0]; } } }