Fully qualify Type names where possible

This commit is contained in:
Koen Bekkenutte
2021-11-26 00:00:47 +08:00
parent ac90b5b1a1
commit 7790f146e4
11 changed files with 114 additions and 26 deletions
@@ -45,5 +45,31 @@ namespace EntityFrameworkCore.Projectables.Generator
return base.VisitNullableType(node); return base.VisitNullableType(node);
} }
public override SyntaxNode? VisitIdentifierName(IdentifierNameSyntax node)
{
var typeInfo = _semanticModel.GetTypeInfo(node);
if (typeInfo.Type is not null)
{
return SyntaxFactory.ParseTypeName(
typeInfo.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
).WithTriviaFrom(node);
}
return base.VisitIdentifierName(node);
}
public override SyntaxNode? VisitQualifiedName(QualifiedNameSyntax node)
{
var typeInfo = _semanticModel.GetTypeInfo(node);
if (typeInfo.Type is not null)
{
return SyntaxFactory.ParseTypeName(
typeInfo.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
).WithTriviaFrom(node);
}
return base.VisitQualifiedName(node);
}
} }
} }
@@ -130,6 +130,15 @@ namespace EntityFrameworkCore.Projectables.Generator
} }
else if (symbolInfo.Symbol.Kind is SymbolKind.Property or SymbolKind.Method or SymbolKind.Field && SymbolEqualityComparer.Default.Equals(symbolInfo.Symbol.ContainingType, _targetTypeSymbol)) else if (symbolInfo.Symbol.Kind is SymbolKind.Property or SymbolKind.Method or SymbolKind.Field && SymbolEqualityComparer.Default.Equals(symbolInfo.Symbol.ContainingType, _targetTypeSymbol))
{ {
if (node.Parent is MemberAccessExpressionSyntax parentMemberAccessNode)
{
var targetSymbolInfo = _semanticModel.GetSymbolInfo(parentMemberAccessNode.Expression);
if (targetSymbolInfo.Symbol is { Kind: SymbolKind.Parameter })
{
return base.VisitIdentifierName(node);
}
}
return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.IdentifierName("@this"), SyntaxFactory.IdentifierName("@this"),
node node
@@ -0,0 +1,10 @@
SELECT [t0].[Id], [t0].[EntityId], [t0].[ParentId]
FROM [Entity] AS [e]
LEFT JOIN (
SELECT [t].[Id], [t].[EntityId], [t].[ParentId]
FROM (
SELECT [e0].[Id], [e0].[EntityId], [e0].[ParentId], ROW_NUMBER() OVER(PARTITION BY [e0].[EntityId] ORDER BY [e0].[Id]) AS [row]
FROM [Entity] AS [e0]
) AS [t]
WHERE [t].[row] <= 1
) AS [t0] ON [e].[Id] = [t0].[EntityId]
@@ -1,37 +1,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using EntityFrameworkCore.Projectables.FunctionalTests.Helpers; using EntityFrameworkCore.Projectables.FunctionalTests.Helpers;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using ScenarioTests;
using VerifyXunit; using VerifyXunit;
using Xunit; using Xunit;
namespace EntityFrameworkCore.Projectables.FunctionalTests namespace EntityFrameworkCore.Projectables.FunctionalTests
{ {
[UsesVerify] [UsesVerify]
public class StatelessPropertyTests public class TypeNameQualificationTests
{ {
public record Entity public record Entity
{ {
public int Id { get; set; } public int Id { get; set; }
public int? ParentId { get; set; }
public ICollection<Entity> Children { get; } = new List<Entity>();
[Projectable] [Projectable]
public int Computed => 0; public Entity? FirstChild =>
} Children.OrderBy(x => x.Id).FirstOrDefault();
[Fact]
public Task FilterOnProjectableProperty()
{
using var dbContext = new SampleDbContext<Entity>();
var query = dbContext.Set<Entity>().AsQueryable()
.Where(x => x.Computed == 1);
return Verifier.Verify(query.ToQueryString());
} }
[Fact] [Fact]
@@ -40,7 +32,7 @@ namespace EntityFrameworkCore.Projectables.FunctionalTests
using var dbContext = new SampleDbContext<Entity>(); using var dbContext = new SampleDbContext<Entity>();
var query = dbContext.Set<Entity>() var query = dbContext.Set<Entity>()
.Select(x => x.Computed); .Select(x => x.FirstChild);
return Verifier.Verify(query.ToQueryString()); return Verifier.Verify(query.ToQueryString());
} }
@@ -0,0 +1,18 @@
using System;
using System.Linq;
using System.Collections.Generic;
using EntityFrameworkCore.Projectables;
using Foo;
namespace EntityFrameworkCore.Projectables.Generated
#nullable disable
{
public static class Foo_EntityExtensions_Entity_Something
{
public static System.Linq.Expressions.Expression<System.Func<global::Foo.EntityExtensions.Entity, global::Foo.EntityExtensions.Entity>> Expression()
{
return (global::Foo.EntityExtensions.Entity entity) =>
entity;
}
}
}
@@ -9,9 +9,9 @@ namespace EntityFrameworkCore.Projectables.Generated
{ {
public static class Foo_EntityExtensions_GetFirstRelatedIgnoreNulls public static class Foo_EntityExtensions_GetFirstRelatedIgnoreNulls
{ {
public static System.Linq.Expressions.Expression<System.Func<Entity, Entity>> Expression() public static System.Linq.Expressions.Expression<System.Func<global::Foo.EntityExtensions.Entity, global::Foo.EntityExtensions.Entity>> Expression()
{ {
return (Entity entity) => return (global::Foo.EntityExtensions.Entity entity) =>
entity.RelatedEntities[0]; entity.RelatedEntities[0];
} }
} }
@@ -9,9 +9,9 @@ namespace EntityFrameworkCore.Projectables.Generated
{ {
public static class Foo_EntityExtensions_GetFirstRelatedIgnoreNulls public static class Foo_EntityExtensions_GetFirstRelatedIgnoreNulls
{ {
public static System.Linq.Expressions.Expression<System.Func<Entity, Entity>> Expression() public static System.Linq.Expressions.Expression<System.Func<global::Foo.EntityExtensions.Entity, global::Foo.EntityExtensions.Entity>> Expression()
{ {
return (Entity entity) => return (global::Foo.EntityExtensions.Entity entity) =>
entity != null ? (entity.RelatedEntities != null ? (entity.RelatedEntities[0]) : null) : null; entity != null ? (entity.RelatedEntities != null ? (entity.RelatedEntities[0]) : null) : null;
} }
} }
@@ -9,9 +9,9 @@ namespace EntityFrameworkCore.Projectables.Generated
{ {
public static class Foo_EntityExtensions_GetFirstName public static class Foo_EntityExtensions_GetFirstName
{ {
public static System.Linq.Expressions.Expression<System.Func<Entity, string>> Expression() public static System.Linq.Expressions.Expression<System.Func<global::Foo.EntityExtensions.Entity, string>> Expression()
{ {
return (Entity entity) => return (global::Foo.EntityExtensions.Entity entity) =>
entity.FullName != null ? (entity.FullName.Substring(entity.FullName != null ? (entity.FullName.IndexOf(' ') ) : null?? 0)) : null; entity.FullName != null ? (entity.FullName.Substring(entity.FullName != null ? (entity.FullName.IndexOf(' ') ) : null?? 0)) : null;
} }
} }
@@ -8,9 +8,9 @@ namespace EntityFrameworkCore.Projectables.Generated
{ {
public static class Foo_C_Foo public static class Foo_C_Foo
{ {
public static System.Linq.Expressions.Expression<System.Func<D, int>> Expression() public static System.Linq.Expressions.Expression<System.Func<global::Foo.D, int>> Expression()
{ {
return (D d) => return (global::Foo.D d) =>
1; 1;
} }
} }
@@ -8,7 +8,7 @@ namespace EntityFrameworkCore.Projectables.Generated
{ {
public static class Foo_C_Foo public static class Foo_C_Foo
{ {
public static System.Linq.Expressions.Expression<System.Func<global::Foo.C, D>> Expression() public static System.Linq.Expressions.Expression<System.Func<global::Foo.C, global::Foo.D>> Expression()
{ {
return (global::Foo.C @this) => return (global::Foo.C @this) =>
@this.Dees.First(); @this.Dees.First();
@@ -867,6 +867,39 @@ namespace Foo {
return Verifier.Verify(result.GeneratedTrees[0].ToString()); return Verifier.Verify(result.GeneratedTrees[0].ToString());
} }
[Fact]
public Task DeclarationTypeNamesAreGettingFullyQualified()
{
var compilation = CreateCompilation(@"
using System;
using System.Linq;
using System.Collections.Generic;
using EntityFrameworkCore.Projectables;
namespace Foo {
public static class EntityExtensions
{
public record Entity
{
public int Id { get; set; }
public string? FullName { get; set; }
[Projectable]
public static Entity Something(Entity entity)
=> entity;
}
}
}
");
var result = RunGenerator(compilation);
Assert.Empty(result.Diagnostics);
Assert.Single(result.GeneratedTrees);
return Verifier.Verify(result.GeneratedTrees[0].ToString());
}
#region Helpers #region Helpers
Compilation CreateCompilation(string source, bool expectedToCompile = true) Compilation CreateCompilation(string source, bool expectedToCompile = true)