From 72a40e6f6a62cd48b4bc7b7d1c78772e72b2e4b7 Mon Sep 17 00:00:00 2001 From: Stef Heyenrath Date: Tue, 13 Dec 2022 18:51:06 +0100 Subject: [PATCH] Add support to generate code for interface without a namespace (#46) --- .../Interfaces/IAddressUid.cs | 9 ++++ .../ProxyInterfaceConsumerForAkka/Program.cs | 3 ++ .../ProxyInterfaceConsumerForAkka.csproj | 13 +++--- .../PartialInterfacesGenerator.cs | 6 +-- .../FileGenerators/ProxyClassesGenerator.cs | 7 +-- .../Utils/NamespaceHelper.cs | 15 +++++++ .../Destination/INoNamespace.g.cs | 27 ++++++++++++ .../Destination/NoNamespaceProxy.g.cs | 36 ++++++++++++++++ .../ProxyInterfaceSourceGeneratorTest.cs | 43 +++++++++++++++++++ .../AkkaExamples/ILocalActorRefProvider.cs | 6 +++ .../Source/Human.cs | 2 - .../Source/INoNamespace.cs | 4 ++ .../Source/NoNamespace.cs | 6 +++ 13 files changed, 163 insertions(+), 14 deletions(-) create mode 100644 src-examples/ProxyInterfaceConsumerForAkka/Interfaces/IAddressUid.cs create mode 100644 src/ProxyInterfaceSourceGenerator/Utils/NamespaceHelper.cs create mode 100644 tests/ProxyInterfaceSourceGeneratorTests/Destination/INoNamespace.g.cs create mode 100644 tests/ProxyInterfaceSourceGeneratorTests/Destination/NoNamespaceProxy.g.cs create mode 100644 tests/ProxyInterfaceSourceGeneratorTests/Source/AkkaExamples/ILocalActorRefProvider.cs create mode 100644 tests/ProxyInterfaceSourceGeneratorTests/Source/INoNamespace.cs create mode 100644 tests/ProxyInterfaceSourceGeneratorTests/Source/NoNamespace.cs diff --git a/src-examples/ProxyInterfaceConsumerForAkka/Interfaces/IAddressUid.cs b/src-examples/ProxyInterfaceConsumerForAkka/Interfaces/IAddressUid.cs new file mode 100644 index 0000000..3b9edd4 --- /dev/null +++ b/src-examples/ProxyInterfaceConsumerForAkka/Interfaces/IAddressUid.cs @@ -0,0 +1,9 @@ +using Akka.Remote; + +// namespace ProxyInterfaceConsumerForAkka.Interfaces; <-- no namespace + +[ProxyInterfaceGenerator.Proxy(typeof(AddressUid))] +// ReSharper disable once CheckNamespace +public partial interface IAddressUid +{ +} \ No newline at end of file diff --git a/src-examples/ProxyInterfaceConsumerForAkka/Program.cs b/src-examples/ProxyInterfaceConsumerForAkka/Program.cs index 8fd3715..7171963 100644 --- a/src-examples/ProxyInterfaceConsumerForAkka/Program.cs +++ b/src-examples/ProxyInterfaceConsumerForAkka/Program.cs @@ -7,6 +7,9 @@ public class Program { public static void Main() { + Akka.Remote.AddressUid auid = null; + IAddressUid addressUidProxy = new AddressUidProxy(auid); + LocalActorRefProvider p = null; ILocalActorRefProvider proxy = new LocalActorRefProviderProxy(p); } diff --git a/src-examples/ProxyInterfaceConsumerForAkka/ProxyInterfaceConsumerForAkka.csproj b/src-examples/ProxyInterfaceConsumerForAkka/ProxyInterfaceConsumerForAkka.csproj index 2b2d8fa..c79aed1 100644 --- a/src-examples/ProxyInterfaceConsumerForAkka/ProxyInterfaceConsumerForAkka.csproj +++ b/src-examples/ProxyInterfaceConsumerForAkka/ProxyInterfaceConsumerForAkka.csproj @@ -15,15 +15,16 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + - --> + \ No newline at end of file diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs index 7c4ec99..d42454c 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/PartialInterfacesGenerator.cs @@ -59,6 +59,7 @@ internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator { var extendsProxyClasses = GetExtendsProxyData(proxyData, classSymbol); var @new = extendsProxyClasses.Any() ? "new " : string.Empty; + var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(ns); return $@"//---------------------------------------------------------------------------------------- // @@ -72,8 +73,7 @@ internal class PartialInterfacesGenerator : BaseGenerator, IFilesGenerator {(SupportsNullable ? "#nullable enable" : string.Empty)} using System; -namespace {ns} -{{ +{namespaceStart} public partial interface {interfaceName} {{ {@new}{classSymbol.Symbol} _Instance {{ get; }} @@ -84,7 +84,7 @@ namespace {ns} {GenerateEvents(classSymbol, proxyData.ProxyBaseClasses)} }} -}} +{namespaceEnd} {(SupportsNullable ? "#nullable disable" : string.Empty)}"; } diff --git a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs index 06cf07a..0d515c4 100644 --- a/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs +++ b/src/ProxyInterfaceSourceGenerator/FileGenerators/ProxyClassesGenerator.cs @@ -84,6 +84,8 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator configurationForMapster = GenerateMapperConfigurationForMapster(); } + var (namespaceStart, namespaceEnd) = NamespaceBuilder.Build(pd.Namespace); + return $@"//---------------------------------------------------------------------------------------- // // This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator. @@ -96,8 +98,7 @@ internal partial class ProxyClassesGenerator : BaseGenerator, IFilesGenerator {(SupportsNullable ? "#nullable enable" : string.Empty)} using System; -namespace {pd.Namespace} -{{ +{namespaceStart} public {@abstract}partial class {className} : {extends}{interfaceName} {{ public {@new}{targetClassSymbol.Symbol} _Instance {{ get; }} @@ -117,7 +118,7 @@ namespace {pd.Namespace} {configurationForMapster} }} }} -}} +{namespaceEnd} {(SupportsNullable ? "#nullable disable" : string.Empty)}"; } diff --git a/src/ProxyInterfaceSourceGenerator/Utils/NamespaceHelper.cs b/src/ProxyInterfaceSourceGenerator/Utils/NamespaceHelper.cs new file mode 100644 index 0000000..3f48f5d --- /dev/null +++ b/src/ProxyInterfaceSourceGenerator/Utils/NamespaceHelper.cs @@ -0,0 +1,15 @@ +namespace ProxyInterfaceSourceGenerator.Utils; + +internal static class NamespaceBuilder +{ + public static (string Start, string End) Build(string ns) + { + var namespaceDefined = !string.IsNullOrEmpty(ns); + + return + ( + namespaceDefined ? $"namespace {ns}\r\n{{" : string.Empty, + namespaceDefined ? "}" : string.Empty + ); + } +} \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Destination/INoNamespace.g.cs b/tests/ProxyInterfaceSourceGeneratorTests/Destination/INoNamespace.g.cs new file mode 100644 index 0000000..f05c71a --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Destination/INoNamespace.g.cs @@ -0,0 +1,27 @@ +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + + + public partial interface INoNamespace + { + ProxyInterfaceSourceGeneratorTests.Source.NoNamespace _Instance { get; } + + bool Test { get; set; } + + + + + + + } + +#nullable disable \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Destination/NoNamespaceProxy.g.cs b/tests/ProxyInterfaceSourceGeneratorTests/Destination/NoNamespaceProxy.g.cs new file mode 100644 index 0000000..fcbf9a9 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Destination/NoNamespaceProxy.g.cs @@ -0,0 +1,36 @@ +//---------------------------------------------------------------------------------------- +// +// This code was generated by https://github.com/StefH/ProxyInterfaceSourceGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//---------------------------------------------------------------------------------------- + +#nullable enable +using System; + + + public partial class NoNamespaceProxy : INoNamespace + { + public ProxyInterfaceSourceGeneratorTests.Source.NoNamespace _Instance { get; } + + + public bool Test { get => _Instance.Test; set => _Instance.Test = value; } + + + + + + + + public NoNamespaceProxy(ProxyInterfaceSourceGeneratorTests.Source.NoNamespace instance) + { + _Instance = instance; + + + + } + } + +#nullable disable \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs index d9a2766..2680e17 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/ProxyInterfaceSourceGeneratorTest.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using CSharp.SourceGenerators.Extensions; using CSharp.SourceGenerators.Extensions.Models; using FluentAssertions; @@ -49,6 +50,48 @@ namespace ProxyInterfaceSourceGeneratorTests result.Files.Should().HaveCount(1); } + [Fact] + public void GenerateFiles_When_NoNamespace_Should_GenerateCorrectFiles() + { + // Arrange + var fileNames = new[] + { + "INoNamespace.g.cs", + "NoNamespaceProxy.g.cs" + }; + + var path = "./Source/INoNamespace.cs"; + var sourceFile = new SourceFile + { + Path = path, + Text = File.ReadAllText(path), + AttributeToAddToInterface = new ExtraAttribute + { + Name = "ProxyInterfaceGenerator.Proxy", + ArgumentList = "typeof(ProxyInterfaceSourceGeneratorTests.Source.NoNamespace)" + } + }; + + // Act + var result = _sut.Execute(new[] + { + sourceFile + }); + + // Assert + result.Valid.Should().BeTrue(); + result.Files.Should().HaveCount(fileNames.Length + 1); + + foreach (var fileName in fileNames.Select((fileName, index) => new { fileName, index })) + { + var builder = result.Files[fileName.index + 1]; // +1 means skip the attribute + builder.Path.Should().EndWith(fileName.fileName); + + if (Write) File.WriteAllText($"../../../Destination/{fileName.fileName}", builder.Text); + builder.Text.Should().Be(File.ReadAllText($"../../../Destination/{fileName.fileName}")); + } + } + [Fact] public void GenerateFiles_ForSingleClass_Should_GenerateCorrectFiles() { diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/AkkaExamples/ILocalActorRefProvider.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/AkkaExamples/ILocalActorRefProvider.cs new file mode 100644 index 0000000..bd959e2 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/AkkaExamples/ILocalActorRefProvider.cs @@ -0,0 +1,6 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source.AkkaActor +{ + public partial interface ILocalActorRefProvider + { + } +} \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs index 7f36057..eef45d3 100644 --- a/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/Human.cs @@ -1,5 +1,3 @@ -using Xunit.Sdk; - namespace ProxyInterfaceSourceGeneratorTests.Source { public class Human diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/INoNamespace.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/INoNamespace.cs new file mode 100644 index 0000000..2f2d42c --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/INoNamespace.cs @@ -0,0 +1,4 @@ +// ReSharper disable once CheckNamespace +public partial interface INoNamespace +{ +} \ No newline at end of file diff --git a/tests/ProxyInterfaceSourceGeneratorTests/Source/NoNamespace.cs b/tests/ProxyInterfaceSourceGeneratorTests/Source/NoNamespace.cs new file mode 100644 index 0000000..31cd3c6 --- /dev/null +++ b/tests/ProxyInterfaceSourceGeneratorTests/Source/NoNamespace.cs @@ -0,0 +1,6 @@ +namespace ProxyInterfaceSourceGeneratorTests.Source; + +public class NoNamespace +{ + public bool Test { get; set; } +} \ No newline at end of file