Skip to content

Commit

Permalink
Simplify PretendName Output
Browse files Browse the repository at this point in the history
  • Loading branch information
justindbaur committed Dec 24, 2023
1 parent de8c87d commit ef9112f
Show file tree
Hide file tree
Showing 18 changed files with 427 additions and 551 deletions.
31 changes: 8 additions & 23 deletions src/Pretender.SourceGenerator/Emitter/CreateEmitter.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Operations;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
using Microsoft.CodeAnalysis.Operations;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Pretender.SourceGenerator.Writing;
using Pretender.SourceGenerator.Parser;

namespace Pretender.SourceGenerator.Emitter
{
internal class CreateEmitter
{
private readonly IInvocationOperation _originalOperation;
private readonly KnownTypeSymbols _knownTypeSymbols;
private readonly ImmutableArray<ITypeSymbol>? _typeArguments;
private readonly ImmutableArray<InterceptsLocationInfo> _locations;
private readonly int _index;

public CreateEmitter(IInvocationOperation originalOperation, ImmutableArray<ITypeSymbol>? typeArguments, ImmutableArray<InterceptsLocationInfo> locations, int index)
public CreateEmitter(IInvocationOperation originalOperation, KnownTypeSymbols knownTypeSymbols, ImmutableArray<ITypeSymbol>? typeArguments, ImmutableArray<InterceptsLocationInfo> locations, int index)
{
_originalOperation = originalOperation;
_knownTypeSymbols = knownTypeSymbols;
_typeArguments = typeArguments;
_locations = locations;
_index = index;
}

public INamedTypeSymbol PretendType => (INamedTypeSymbol)_originalOperation.TargetMethod.ReturnType;

public IInvocationOperation Operation => _originalOperation;

public void Emit(IndentedTextWriter writer, CancellationToken cancellationToken)
Expand Down Expand Up @@ -63,7 +66,7 @@ public void Emit(IndentedTextWriter writer, CancellationToken cancellationToken)

using (writer.WriteBlock())
{
writer.Write($"return new {returnType.ToPretendName()}(pretend");
writer.Write($"return new {_knownTypeSymbols.GetPretendName(PretendType)}(pretend");

if (_typeArguments.HasValue)
{
Expand All @@ -81,23 +84,5 @@ public void Emit(IndentedTextWriter writer, CancellationToken cancellationToken)
}
}
}

private ImmutableArray<AttributeListSyntax> CreateInterceptsAttributes()
{
var builder = ImmutableArray.CreateBuilder<AttributeListSyntax>(_locations.Length);

foreach (var location in _locations)
{
var attribute = Create(location.ToAttributeSyntax());
builder.Add(attribute);
}

return builder.MoveToImmutable();

static AttributeListSyntax Create(AttributeSyntax attribute)
{
return AttributeList(SingletonSeparatedList(attribute));
}
}
}
}
16 changes: 10 additions & 6 deletions src/Pretender.SourceGenerator/Emitter/PretendEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ namespace Pretender.SourceGenerator.Emitter
{
internal class PretendEmitter
{
private readonly ITypeSymbol _pretendType;
private readonly INamedTypeSymbol _pretendType;
private readonly KnownTypeSymbols _knownTypeSymbols;
private readonly IReadOnlyDictionary<IMethodSymbol, MethodStrategy> _methodStrategies;
private readonly bool _fillExisting;

public PretendEmitter(ITypeSymbol pretendType, IReadOnlyDictionary<IMethodSymbol, MethodStrategy> methodStrategies, bool fillExisting)
public PretendEmitter(INamedTypeSymbol pretendType, KnownTypeSymbols knownTypeSymbols, bool fillExisting)
{
_methodStrategies = knownTypeSymbols.GetTypesStrategies(pretendType);
_pretendType = pretendType;
_methodStrategies = methodStrategies;
_knownTypeSymbols = knownTypeSymbols;
_fillExisting = fillExisting;
}

public INamedTypeSymbol PretendType => _pretendType;

public void Emit(IndentedTextWriter writer, CancellationToken token)
{
token.ThrowIfCancellationRequested();
Expand All @@ -28,15 +32,15 @@ public void Emit(IndentedTextWriter writer, CancellationToken token)
}
else
{
writer.WriteLine($"file class {_pretendType.ToPretendName()} : {_pretendType.ToFullDisplayString()}");
writer.WriteLine($"file class {_knownTypeSymbols.GetPretendName(PretendType)} : {_pretendType.ToFullDisplayString()}");
}
using (writer.WriteBlock())
{
// static fields
foreach (var strategyEntry in _methodStrategies)
{
var strategy = strategyEntry.Value;
writer.Write($"public static readonly MethodInfo {strategy.UniqueName}_MethodInfo = typeof({_pretendType.ToPretendName()})");
writer.Write($"public static readonly MethodInfo {strategy.UniqueName}_MethodInfo = typeof({_knownTypeSymbols.GetPretendName(PretendType)})");
strategyEntry.Value.EmitMethodGetter(writer, token);
writer.WriteLine(skipIfPresent: true);
}
Expand All @@ -47,7 +51,7 @@ public void Emit(IndentedTextWriter writer, CancellationToken token)
writer.WriteLine();

// main constructor
writer.WriteLine($"public {_pretendType.ToPretendName()}(Pretend<{_pretendType.ToFullDisplayString()}> pretend)");
writer.WriteLine($"public {_knownTypeSymbols.GetPretendName(PretendType)}(Pretend<{_pretendType.ToFullDisplayString()}> pretend)");
using (writer.WriteBlock())
{
writer.WriteLine("_pretend = pretend;");
Expand Down
6 changes: 3 additions & 3 deletions src/Pretender.SourceGenerator/Emitter/SetupActionEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ internal class SetupActionEmitter
private readonly ImmutableArray<SetupArgumentEmitter> _setupArgumentEmitters;
private readonly KnownTypeSymbols _knownTypeSymbols;

public SetupActionEmitter(ITypeSymbol pretendType, IMethodSymbol setupMethod, ImmutableArray<SetupArgumentEmitter> setupArgumentEmitters, KnownTypeSymbols knownTypeSymbols)
public SetupActionEmitter(INamedTypeSymbol pretendType, IMethodSymbol setupMethod, ImmutableArray<SetupArgumentEmitter> setupArgumentEmitters, KnownTypeSymbols knownTypeSymbols)
{
PretendType = pretendType;
SetupMethod = setupMethod;
_setupArgumentEmitters = setupArgumentEmitters;
_knownTypeSymbols = knownTypeSymbols;
}

public ITypeSymbol PretendType { get; }
public INamedTypeSymbol PretendType { get; }
public IMethodSymbol SetupMethod { get; }

public void Emit(IndentedTextWriter writer, CancellationToken cancellationToken)
Expand Down Expand Up @@ -68,7 +68,7 @@ public void Emit(IndentedTextWriter writer, CancellationToken cancellationToken)
var methodStrategy = _knownTypeSymbols.GetSingleMethodStrategy(SetupMethod);

// TODO: default value
writer.WriteLine($"return new ReturningCompiledSetup<{PretendType.ToFullDisplayString()}, {returnType.ToUnknownTypeString()}>(pretend, {PretendType.ToPretendName()}.{methodStrategy.UniqueName}_MethodInfo, {matcherName}, expr.Target, defaultValue: default);");
writer.WriteLine($"return new ReturningCompiledSetup<{PretendType.ToFullDisplayString()}, {returnType.ToUnknownTypeString()}>(pretend, {_knownTypeSymbols.GetPretendName(PretendType)}.{methodStrategy.UniqueName}_MethodInfo, {matcherName}, expr.Target, defaultValue: default);");
}
else
{
Expand Down
1 change: 1 addition & 0 deletions src/Pretender.SourceGenerator/Parser/CreateParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public CreateParser(CreateInvocation createInvocation, ImmutableArray<Intercepts
// and we should provide the constructor to use to the emitter maybe
var emitter = new CreateEmitter(
_createInvocation.Operation,
_knownTypeSymbols,
_createInvocation.TypeArguments,
_locations,
_index);
Expand Down
30 changes: 29 additions & 1 deletion src/Pretender.SourceGenerator/Parser/KnownTypeSymbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ namespace Pretender.SourceGenerator.Parser
internal sealed class KnownTypeSymbols
{
private readonly ConcurrentDictionary<INamedTypeSymbol, Dictionary<IMethodSymbol, MethodStrategy>> _cachedTypeMethodNames = new(SymbolEqualityComparer.Default);
private readonly ConcurrentDictionary<INamedTypeSymbol, string> _cachedPretendNames = new(SymbolEqualityComparer.Default);
private readonly ConcurrentDictionary<string, int> _pretendNameTracker = new();

public Compilation Compilation { get; }

Expand All @@ -24,7 +26,7 @@ internal sealed class KnownTypeSymbols
// Known abstractions with fakes
public INamedTypeSymbol? MicrosoftExtensionsLoggingILogger { get; }
public INamedTypeSymbol? MicrosoftExtensionsLoggingTestingFakeLogger { get; }
public INamedTypeSymbol? MicrosoftExtensionsLoggingAbstractionsNullLogger { get; }
public INamedTypeSymbol? MicrosoftExtensionsLoggingAbstractionsNullLogger { get; }

public INamedTypeSymbol? MicrosoftExtensionsLoggingILoggerOfT { get; }

Expand Down Expand Up @@ -109,5 +111,31 @@ public static bool IsPretend(INamedTypeSymbol type)
ContainingAssembly.Name: "Pretender",
};
}

public string GetPretendName(INamedTypeSymbol type)
{
if (_cachedPretendNames.TryGetValue(type, out var name))
{
return name;
}

var prettyName = type.Name;

if (_pretendNameTracker.TryGetValue(prettyName, out var nextNum))
{
// This type has been tracked before
var nextName = $"Pretend{type.Name}{nextNum}";
_pretendNameTracker[prettyName] = ++nextNum;
return nextName;
}

// Never tracked before

// Start with 1
_pretendNameTracker[prettyName] = 1;
var firstName = $"Pretend{prettyName}";
_cachedPretendNames[type] = firstName;
return firstName;
}
}
}
2 changes: 1 addition & 1 deletion src/Pretender.SourceGenerator/Parser/PretendParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public PretendParser(PretendInvocation pretendInvocation, KnownTypeSymbols known

cancellationToken.ThrowIfCancellationRequested();

return (new PretendEmitter(PretendInvocation.PretendType, methodStrategies, PretendInvocation.FillExisting), null);
return (new PretendEmitter(PretendInvocation.PretendType, _knownTypeSymbols, PretendInvocation.FillExisting), null);
}
}
}
4 changes: 2 additions & 2 deletions src/Pretender.SourceGenerator/Parser/SetupActionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ namespace Pretender.SourceGenerator.Parser
internal class SetupActionParser
{
private readonly IOperation _setupActionArgument;
private readonly ITypeSymbol _pretendType;
private readonly INamedTypeSymbol _pretendType;
private readonly bool _forcePropertySetter;
private readonly KnownTypeSymbols _knownTypeSymbols;

// TODO: Should I have a higher IOperation kind here? Like InvocationOperation?
public SetupActionParser(IOperation setupActionArgument, ITypeSymbol pretendType, bool forcePropertySetter, KnownTypeSymbols knownTypeSymbols)
public SetupActionParser(IOperation setupActionArgument, INamedTypeSymbol pretendType, bool forcePropertySetter, KnownTypeSymbols knownTypeSymbols)
{
_setupActionArgument = setupActionArgument;
_pretendType = pretendType;
Expand Down
3 changes: 2 additions & 1 deletion src/Pretender.SourceGenerator/Parser/SetupParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public SetupParser(SetupInvocation setupInvocation, KnownTypeSymbols knownTypeSy

// Setup calls are expected to be called from Pretend<T> so the type argument gives us the type we are pretending
// TODO: Assert the containing type maybe?
var pretendType = operation.TargetMethod.ContainingType.TypeArguments[0];
// This should be a safe cast
var pretendType = (INamedTypeSymbol)operation.TargetMethod.ContainingType.TypeArguments[0];

var useSetMethod = operation.TargetMethod.Name == "SetupSet";

Expand Down
3 changes: 2 additions & 1 deletion src/Pretender.SourceGenerator/Parser/VerifyParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public VerifyParser(VerifyInvocation verifyInvocation, KnownTypeSymbols knownTyp
cancellationToken.ThrowIfCancellationRequested();

// Verify calls are expected to be called from Pretend<T> so the type argument gives us the type we are pretending
var pretendType = operation.TargetMethod.ContainingType.TypeArguments[0];
// This should be a safe cast
var pretendType = (INamedTypeSymbol)operation.TargetMethod.ContainingType.TypeArguments[0];

// TODO: This doesn't exist yet
var useSetMethod = operation.TargetMethod.Name == "VerifySet";
Expand Down
Loading

0 comments on commit ef9112f

Please sign in to comment.