Skip to content

Commit

Permalink
Fix simple factory for generic type markers
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Aug 7, 2024
1 parent a7ec131 commit 6aebe3b
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 6 deletions.
15 changes: 11 additions & 4 deletions src/Pure.DI.Core/Core/ApiInvocationProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,12 @@ private void VisitSimpleFactory(
{
var argTypeSyntax = argsTypes[i];
var argType = semantic.GetTypeSymbol<ITypeSymbol>(semanticModel, argTypeSyntax);
namespaces.Add(argType.ContainingNamespace.ToString());
var argNamespace = argType.ContainingNamespace;
if (argNamespace is not null)
{
namespaces.Add(argNamespace.ToString());
}

var attributes = paramAttributes[i];
resolvers.Add(new MdResolver
{
Expand All @@ -424,17 +429,19 @@ private void VisitSimpleFactory(
SyntaxFactory.IdentifierName(ctxName),
SyntaxFactory.IdentifierName(nameof(IContext.Inject))))
.AddArgumentListArguments(valueArg);

block.Add(SyntaxFactory.ExpressionStatement(injection));
}

if (lambdaExpression.Block is {} lambdaBlock)
var fullyQualifiedNameRewriter = new FullyQualifiedNameRewriter(semanticModel);
var fullyQualifiedTypesLambdaExpression = (ParenthesizedLambdaExpressionSyntax)fullyQualifiedNameRewriter.VisitParenthesizedLambdaExpression(lambdaExpression)!;
if (fullyQualifiedTypesLambdaExpression.Block is {} lambdaBlock)
{
block.AddRange(lambdaBlock.Statements);
}
else
{
if (lambdaExpression.ExpressionBody is { } body)
if (fullyQualifiedTypesLambdaExpression.ExpressionBody is { } body)
{
block.Add(SyntaxFactory.ReturnStatement(body));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/FactoryTypeRewriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public MdFactory Build(RewriterContext<MdFactory> context)
var semanticModel = _context.Setup.SemanticModel;
foreach (var arg in node.Arguments)
{
var typeName = arg.ToString();
var typeName = arg.ToString();
var isFound = false;
foreach (var type in semanticModel.Compilation.GetTypesByMetadataName(typeName))
{
Expand Down
48 changes: 48 additions & 0 deletions src/Pure.DI.Core/Core/FullyQualifiedNameRewriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
namespace Pure.DI.Core;

using Microsoft.CodeAnalysis.CSharp.Syntax;

internal class FullyQualifiedNameRewriter(SemanticModel semanticModel): CSharpSyntaxRewriter
{
public static readonly SymbolDisplayFormat FullTypeNameFormat =
new(
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
miscellaneousOptions:
SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
SymbolDisplayMiscellaneousOptions.UseSpecialTypes);

public override SyntaxNode? VisitQualifiedName(QualifiedNameSyntax node)
{
if (semanticModel.GetSymbolInfo(node).Symbol is not ITypeSymbol type)
{
return base.VisitQualifiedName(node);
}

var typeName = type.ToDisplayString(NullableFlowState.None, FullTypeNameFormat);
return SyntaxFactory.ParseTypeName(typeName);
}

public override SyntaxNode? VisitGenericName(GenericNameSyntax node)
{
if (semanticModel.GetSymbolInfo(node).Symbol is not ITypeSymbol type)
{
return base.VisitGenericName(node);
}

var typeName = type.ToDisplayString(NullableFlowState.None, FullTypeNameFormat);
return SyntaxFactory.ParseTypeName(typeName);
}

public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
{
if (semanticModel.GetSymbolInfo(node).Symbol is not ITypeSymbol type)
{
return base.VisitIdentifierName(node);
}

var typeName = type.ToDisplayString(NullableFlowState.None, FullTypeNameFormat);
return SyntaxFactory.ParseTypeName(typeName);
}
}
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/SetupsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ InvocationExpressionSyntax Inject(ITypeSymbol injectedType, string injectedName,
curPosition++;

var valueDeclaration = SyntaxFactory.DeclarationExpression(
SyntaxFactory.ParseTypeName(injectedType.ToString()).WithTrailingTrivia(SyntaxFactory.Space),
SyntaxFactory.ParseTypeName(injectedType.ToDisplayString(NullableFlowState.None, FullyQualifiedNameRewriter.FullTypeNameFormat)).WithTrailingTrivia(SyntaxFactory.Space),
SyntaxFactory.SingleVariableDesignation(SyntaxFactory.Identifier(injectedName)));

var valueArg =
Expand Down
76 changes: 76 additions & 0 deletions tests/Pure.DI.IntegrationTests/SimpleFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,82 @@ public static void Main()
result.StdOut.ShouldBe(["Sample.Dependency"], result);
}

[Theory]
[InlineData("global::System.Collections.Generic.")]
[InlineData("System.Collections.Generic.")]
[InlineData("")]
public async Task ShouldSupportSimpleFactoryWhenArrOfT(string typePrefix)
{
// Given

// When
var result = await """
using System;
using System.Collections.Generic;
using Pure.DI;

namespace Sample
{
interface IDependency {}

class Dependency: IDependency {}

interface IService
{
IDependency? Dep { get; }

IService Initialize(IDependency dep);
}

class Service: IService
{
public IDependency? Dep { get; private set; }

public IService Initialize(IDependency dep)
{
Dep = dep;
return this;
}

public override string ToString()
{
return Dep?.ToString() ?? "";
}
}

static class Setup
{
private static void SetupComposition()
{
DI.Setup("Composition")
.Bind<global::System.Collections.Generic.ICollection<TT>>()
.Bind<global::System.Collections.Generic.IList<TT>>()
.Bind<global::System.Collections.Generic.List<TT>>()
.To((TT[] arr) => new global::System.Collections.Generic.List<TT>(arr))
.Bind().To<Dependency>()
.Bind().To<Service>()
.Bind<string>().To((IService service, #TypePrefixIList<IDependency> dependency) => service.Initialize(dependency[0]).ToString() ?? "")
.Root<string>("DepName");
}
}

public class Program
{
public static void Main()
{
var composition = new Composition();
var depName = composition.DepName;
Console.WriteLine(depName);
}
}
}
""".Replace("#TypePrefix", typePrefix).RunAsync();

// Then
result.Success.ShouldBeTrue(result);
result.StdOut.ShouldBe(["Sample.Dependency"], result);
}

[Fact]
public async Task ShouldSupportSimpleFactoryWhenSimpleLambdaWitgGenericParams()
{
Expand Down

0 comments on commit 6aebe3b

Please sign in to comment.