Skip to content
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

Updated statement generation to handle accessibility #1334

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 75 additions & 94 deletions src/DependencyInjection.Analyzers/StatementGeneration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ string lifetime
)
{
var serviceTypeExpression = AssemblyProviders.StatementGeneration.GetTypeOfExpression(compilation, serviceType);
var isAccessible = compilation.IsSymbolAccessibleWithin(implementationType, compilation.Assembly);
var isImplementationAccessible = compilation.IsSymbolAccessibleWithin(implementationType, compilation.Assembly);

if (isAccessible)
if (isImplementationAccessible)
{
var implementationTypeExpression = SimpleLambdaExpression(Parameter(Identifier("a")))
.WithExpressionBody(
Expand All @@ -33,7 +33,14 @@ string lifetime
)
);

return GenerateServiceType(serviceType, serviceTypeExpression, implementationType, implementationTypeExpression, lifetime);
return GenerateServiceType(
compilation,
serviceType,
serviceTypeExpression,
implementationType,
implementationTypeExpression,
lifetime
);
}
else
{
Expand All @@ -52,7 +59,14 @@ string lifetime
IdentifierName(Helpers.GetGenericDisplayName(serviceType))
)
);
return GenerateServiceType(serviceType, serviceTypeExpression, implementationType, implementationTypeExpression, lifetime);
return GenerateServiceType(
compilation,
serviceType,
serviceTypeExpression,
implementationType,
implementationTypeExpression,
lifetime
);
}
}

Expand All @@ -65,106 +79,73 @@ string lifetime
{
var serviceTypeExpression = AssemblyProviders.StatementGeneration.GetTypeOfExpression(compilation, serviceType);
var implementationTypeExpression = AssemblyProviders.StatementGeneration.GetTypeOfExpression(compilation, implementationType);
return GenerateServiceType(serviceType, serviceTypeExpression, implementationType, implementationTypeExpression, lifetime);
return GenerateServiceType(
compilation,
serviceType,
serviceTypeExpression,
implementationType,
implementationTypeExpression,
lifetime
);
}

public static InvocationExpressionSyntax GenerateServiceType(
Compilation compilation,
INamedTypeSymbol serviceType,
ExpressionSyntax serviceTypeExpression,
INamedTypeSymbol implementationType,
ExpressionSyntax implementationTypeExpression,
string lifetime
)
{
switch ( serviceTypeExpression, implementationTypeExpression )
{
case (TypeOfExpressionSyntax serviceTypeOfExpression, TypeOfExpressionSyntax implementationTypeOfExpression)
when !serviceType.IsUnboundGenericType && !implementationType.IsUnboundGenericType:
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ServiceDescriptor"),
GenericName(lifetime)
.WithTypeArgumentList(
TypeArgumentList(
SeparatedList<TypeSyntax>(
[
serviceTypeOfExpression.Type,
implementationTypeOfExpression.Type,
]
)
)
)
)
);
case (TypeOfExpressionSyntax { Type: not GenericNameSyntax { IsUnboundGenericName: true } } serviceTypeOfExpression, { })
when !serviceType.IsUnboundGenericType:
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ServiceDescriptor"),
GenericName(lifetime)
.WithTypeArgumentList(TypeArgumentList(SeparatedList<TypeSyntax>([serviceTypeOfExpression.Type])))
)
)
.WithArgumentList(
ArgumentList(
SeparatedList(
[
Argument(implementationTypeExpression),
]
)
)
);
default:
return InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ServiceDescriptor"),
IdentifierName(lifetime)
)
)
.WithArgumentList(
ArgumentList(
SeparatedList(
[
Argument(serviceTypeExpression),
Argument(implementationTypeExpression!),
]
)
)
);
}
var isServiceTypeAccessible = compilation.IsSymbolAccessibleWithin(serviceType, compilation.Assembly);
var isImplementationTypeAccessible = compilation.IsSymbolAccessibleWithin(implementationType, compilation.Assembly);
return ( isServiceTypeAccessible, serviceTypeExpression, isImplementationTypeAccessible, implementationTypeExpression )
switch
{
(true, TypeOfExpressionSyntax serviceTypeOfExpression, true, TypeOfExpressionSyntax implementationTypeOfExpression)
when serviceType is { IsUnboundGenericType: false } && implementationType is { IsUnboundGenericType: false } => InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ServiceDescriptor"),
GenericName(lifetime)
.WithTypeArgumentList(
TypeArgumentList(
SeparatedList(
[
serviceTypeOfExpression.Type,
implementationTypeOfExpression.Type,
]
)
)
)
)
),
(true, TypeOfExpressionSyntax { Type: not GenericNameSyntax { IsUnboundGenericName: true } } serviceTypeOfExpression, _, { })
when serviceType is { IsUnboundGenericType: false } => InvocationExpression(
MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ServiceDescriptor"),
GenericName(lifetime)
.WithTypeArgumentList(TypeArgumentList(SeparatedList([serviceTypeOfExpression.Type])))
)
)
.WithArgumentList(
ArgumentList(
SeparatedList(
[
Argument(implementationTypeExpression),
]
)
)
),
_ => InvocationExpression(
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, IdentifierName("ServiceDescriptor"), IdentifierName(lifetime))
)
.WithArgumentList(ArgumentList(SeparatedList([Argument(serviceTypeExpression), Argument(implementationTypeExpression!)]))),
};
}

public static bool IsOpenGenericType(this INamedTypeSymbol type)
{
return type.IsGenericType && ( type.IsUnboundGenericType || type.TypeArguments.All(z => z.TypeKind == TypeKind.TypeParameter) );
}

private static MemberAccessExpressionSyntax DescribeLifetime(string lifetime) => MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
IdentifierName("ServiceDescriptor"),
IdentifierName(lifetime)
);

private static InvocationExpressionSyntax GenerateServiceType_(
ExpressionSyntax serviceTypeExpression,
ExpressionSyntax implementationTypeExpression,
string lifetime
)
{
return InvocationExpression(DescribeLifetime(lifetime))
.WithArgumentList(
ArgumentList(
SeparatedList(
new[]
{
Argument(serviceTypeExpression),
Argument(implementationTypeExpression),
}
)
)
);
}
public static bool IsOpenGenericType(this INamedTypeSymbol type) =>
type.IsGenericType && ( type.IsUnboundGenericType || type.TypeArguments.All(z => z.TypeKind == TypeKind.TypeParameter) );
}
Loading