- first implementation generating factory source code

pull/62/head
Simon G. 4 days ago
parent aea48017a7
commit 88e242ed20
Signed by: SimonG
GPG Key ID: 0B82B964BA536523
  1. 124
      LightweightIocContainer.FactoryGenerator/FactoryGenerator.cs

@ -19,6 +19,8 @@ public class FactoryGenerator : IIncrementalGenerator
private const string GENERATED_FILE_HEADER = "//---GENERATED by FactoryGenerator! DO NOT EDIT!---";
private const string INDENT = " ";
private const string CLEAR_MULTITON_INSTANCE_METHOD_NAME = "ClearMultitonInstance";
public void Initialize(IncrementalGeneratorInitializationContext context)
{
string? classNamespace = typeof(FactoryGenerator).Namespace;
@ -27,6 +29,7 @@ public class FactoryGenerator : IIncrementalGenerator
IncrementalValuesProvider<ITypeSymbol?> syntaxProvider = context.SyntaxProvider.CreateSyntaxProvider(IsCallToGenerateFactory, GetTypeArgument);
context.RegisterSourceOutput(syntaxProvider.Collect(), GenerateTypeDependentClasses);
context.RegisterSourceOutput(syntaxProvider, GenerateFactory);
}
private string GenerateFactoryExtensionsClass(string? classNamespace, string className)
@ -149,9 +152,130 @@ public class FactoryGenerator : IIncrementalGenerator
return stringBuilder.ToString();
}
private string GenerateFactorySourceCode(ITypeSymbol typeSymbol)
{
string typeName = typeSymbol.Name;
string? typeNamespace = typeSymbol.ContainingNamespace.IsGlobalNamespace ? null : typeSymbol.ContainingNamespace.ToString();
StringBuilder stringBuilder = new();
stringBuilder.AppendLine(GENERATED_FILE_HEADER);
stringBuilder.AppendLine();
stringBuilder.AppendLine("using LightweightIocContainer;");
stringBuilder.AppendLine();
if (typeNamespace is not null)
{
stringBuilder.AppendLine($"namespace {typeNamespace};");
stringBuilder.AppendLine();
}
stringBuilder.AppendLine($"public class Generated{typeName}(IocContainer container) : {typeName}");
stringBuilder.AppendLine("{");
foreach (ISymbol? member in typeSymbol.GetMembers())
{
if (member is not IMethodSymbol method)
continue;
stringBuilder.AppendLine();
if (!method.ReturnsVoid) //create method
{
stringBuilder.Append($"{INDENT}public {method.ReturnType.Name} {method.Name}");
if (method.IsGenericMethod)
stringBuilder.Append($"<{string.Join(", ", method.TypeParameters.Select(p => p.Name))}>");
stringBuilder.Append($"({string.Join(", ", method.Parameters.Select(GetParameterText))})");
if (method.IsGenericMethod)
{
foreach (ITypeParameterSymbol typeParameter in method.TypeParameters)
{
List<string> parameterConstraints = GetParameterConstraints(typeParameter);
if (parameterConstraints.Count == 0)
continue;
stringBuilder.Append($" where {typeParameter.Name} : {string.Join(", ", parameterConstraints)}");
}
}
stringBuilder.AppendLine();
stringBuilder.AppendLine($"{INDENT}{{");
foreach (IParameterSymbol parameter in method.Parameters)
{
stringBuilder.AppendLine($"{INDENT}{INDENT}object? {parameter.Name}Value = {parameter.Name}");
stringBuilder.AppendLine($"{INDENT}{INDENT}if ({parameter.Name}Value is null)");
stringBuilder.AppendLine($"{INDENT}{INDENT}{INDENT}{parameter.Name}Value = new NullParameter(typeof({parameter.Type.Name}));");
stringBuilder.AppendLine();
}
if (method.IsAsync)
stringBuilder.Append($"{INDENT}{INDENT}return await container.ResolveAsync<>("); //TODO: Get return type from Task<>
else
stringBuilder.Append($"{INDENT}{INDENT}return container.Resolve<{method.ReturnType.Name}>(");
stringBuilder.Append(string.Join(", ", method.Parameters.Select(p => $"{p.Name}Value")));
stringBuilder.AppendLine(");");
stringBuilder.AppendLine($"{INDENT}}}");
}
else if (method.Name == CLEAR_MULTITON_INSTANCE_METHOD_NAME)
{
//TODO
}
}
typeSymbol.GetMembers();
stringBuilder.AppendLine("}");
return stringBuilder.ToString();
}
private IEnumerable<string> GetNamespacesOfTypes(ImmutableArray<ITypeSymbol?> types) =>
types.OfType<ITypeSymbol>()
.Select(s => s.ContainingNamespace.IsGlobalNamespace ? null : s.ContainingNamespace.ToString())
.OfType<string>()
.Distinct();
private string GetParameterText(IParameterSymbol parameter)
{
StringBuilder stringBuilder = new();
stringBuilder.Append(parameter.Type.Name);
if (parameter.NullableAnnotation == NullableAnnotation.Annotated)
stringBuilder.Append("?");
stringBuilder.Append($" {parameter.Name}");
return stringBuilder.ToString();
}
private List<string> GetParameterConstraints(ITypeParameterSymbol typeParameterSymbol)
{
List<string> constraints = [];
foreach (ITypeSymbol constraintType in typeParameterSymbol.ConstraintTypes)
constraints.Add(constraintType.Name);
if (typeParameterSymbol.HasReferenceTypeConstraint)
constraints.Add("class");
if (typeParameterSymbol.HasValueTypeConstraint)
constraints.Add("struct");
if (typeParameterSymbol.HasConstructorConstraint)
constraints.Add("new()");
if (typeParameterSymbol.HasUnmanagedTypeConstraint)
constraints.Add("unmanaged");
if (typeParameterSymbol.HasNotNullConstraint)
constraints.Add("notnull");
return constraints;
}
}
Loading…
Cancel
Save