private static void GenerateSourceFile(GeneratorExecutionContext context, string interfaceFullTypeName) { INamedTypeSymbol?interfaceSymbol = context.Compilation.GetTypeByMetadataName(interfaceFullTypeName); if (interfaceSymbol == null) { return; } if (!TryGetTypeNamesFromInterface(interfaceFullTypeName, out string interfaceNamespace, out string controlTypeName)) { return; } if (interfaceFullTypeName == "Microcharts.IChart") { // For now, hack the IChart case GenerateChartSourceFile(context); return; } string baseTypeName = GetBaseInterface(interfaceSymbol).Name; string controlBaseTypeName = baseTypeName == "IStandardControl" ? "StandardControl" : baseTypeName.Substring(1); StringBuilder sourceCode = new StringBuilder(); sourceCode.Append($@"// This file was generated using Microsoft.StandardUI.Media; using Microsoft.StandardUI.Wpf.Media; using Microsoft.StandardUI.Wpf; namespace {interfaceNamespace}.Wpf {{ public class {controlTypeName} : {controlBaseTypeName}, {interfaceFullTypeName} {{ public {controlTypeName}() {{ InitImplementation(new {interfaceNamespace}.{controlTypeName}Implementation<{interfaceFullTypeName}>(this)); }}"); ImportedControlGenerator.GenerateProperties(interfaceSymbol, controlTypeName, sourceCode); sourceCode.Append($@" }} }}"); // Create the file context.AddSource(controlTypeName, sourceCode.ToString()); }
/// <summary> /// Appends the source code to implement the properties on <paramref name="interfaceSymbol"/> to <paramref name="sourceCode"/>. /// </summary> /// <example> /// public Brush? Fill /// { /// get => (Brush?)GetValue(FillProperty); /// set => SetValue(FillProperty, value); /// } /// /// IBrush IRadialGauge.Fill /// { /// get => Fill; /// set => Fill = (Brush?)value; /// } /// </example> /// <param name="interfaceSymbol">The interface whose properties should be implemented.</param> /// <param name="controlTypeName">The name of the control class that is implementing the interface.</param> /// <param name="sourceCode">The StringBuilder to which the source code should be written.</param> private static void GenerateProperties(INamedTypeSymbol interfaceSymbol, string controlTypeName, StringBuilder sourceCode) { foreach (IPropertySymbol propertySymbol in interfaceSymbol.GetMembers().Where(member => member.Kind == SymbolKind.Property)) { string propertyName = propertySymbol.Name; string explicitInterfacePropertyType = propertySymbol.Type.Name; string publicPropertyType = ImportedControlGenerator.IsStandardUIInterface(propertySymbol.Type) ? explicitInterfacePropertyType.Substring(1) : explicitInterfacePropertyType; // The dependency property sourceCode.Append($@" public static readonly System.Windows.DependencyProperty {propertyName}Property = PropertyUtils.Register(nameof({propertyName}), typeof({publicPropertyType}), typeof({controlTypeName}), null); "); // The public property implementation sourceCode.Append($@" public {publicPropertyType}? {propertyName} {{ get => ({publicPropertyType}?)GetValue({propertyName}Property);"); if (propertySymbol.SetMethod != null) { sourceCode.Append($@" set => SetValue({propertyName}Property, value);"); } sourceCode.Append($@" }} "); // The explicit property implementation sourceCode.Append($@" {explicitInterfacePropertyType} {propertySymbol.ContainingType.Name}.{propertyName} {{ get => {propertyName};"); if (propertySymbol.SetMethod != null) { sourceCode.Append($@" set => { propertyName} = ({publicPropertyType}?)value;"); } sourceCode.Append($@" }}"); } }
public void Execute(GeneratorExecutionContext context) { SyntaxReceiver rx = (SyntaxReceiver)context.SyntaxContextReceiver !; HashSet <string> generatedInterfaces = new HashSet <string>(); foreach (string interfaceFullTypeName in rx.InterfacesToGenerate) { INamedTypeSymbol?interfaceSymbol = context.Compilation.GetTypeByMetadataName(interfaceFullTypeName); if (interfaceSymbol == null) { continue; } if (generatedInterfaces.Contains(interfaceFullTypeName)) { continue; } ImportedControlGenerator.GenerateSourceFile(context, interfaceFullTypeName); generatedInterfaces.Add(interfaceFullTypeName); // Generate any ancestor types INamedTypeSymbol?ancestorType = GetBaseInterface(interfaceSymbol); while (ancestorType != null) { var symbolDisplayFormat = new SymbolDisplayFormat( typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces); string ancestorFullTypeName = ancestorType.ToDisplayString(symbolDisplayFormat); if (ancestorFullTypeName == "Microsoft.StandardUI.Controls.IStandardControl" || generatedInterfaces.Contains(ancestorFullTypeName)) { break; } ImportedControlGenerator.GenerateSourceFile(context, ancestorFullTypeName); generatedInterfaces.Add(ancestorFullTypeName); ancestorType = GetBaseInterface(ancestorType); } } }