Skip to content

Commit

Permalink
Merge pull request #27 from codecentric/logging
Browse files Browse the repository at this point in the history
- Add abillity to set custom namespace name
  • Loading branch information
ChristianSauer authored Jan 30, 2024
2 parents f220195 + e0378db commit bb6eec4
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<Version>2.0.0</Version>
<Version>2.1.0</Version>
<PackageReadmeFile>README.md</PackageReadmeFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>1701;1702;NU5128</NoWarn>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,44 @@ namespace AutomaticInterface;
[Generator]
public class AutomaticInterfaceGenerator : IIncrementalGenerator
{
private const string DefaultAttributeName = "GenerateAutomaticInterface";
public const string DefaultAttributeName = "GenerateAutomaticInterface";

public void Initialize(IncrementalGeneratorInitializationContext context)
{
var classes = context
.SyntaxProvider.CreateSyntaxProvider(CouldBeClassAsync, Transform)
.SyntaxProvider.CreateSyntaxProvider(CouldBeClassWithInterfaceAttribute, Transform)
.Where(type => type is not null)
.Collect();

context.RegisterSourceOutput(classes, GenerateCode);
}

private void GenerateCode(
private static bool CouldBeClassWithInterfaceAttribute(
SyntaxNode syntaxNode,
CancellationToken _
)
{
if (syntaxNode is not AttributeSyntax attribute)
{
return false;
}

var name = ExtractName(attribute.Name);

return name is DefaultAttributeName;
}

private static string? ExtractName(NameSyntax? name)
{
return name switch
{
SimpleNameSyntax ins => ins.Identifier.Text,
QualifiedNameSyntax qns => qns.Right.Identifier.Text,
_ => null
};
}

private static void GenerateCode(
SourceProductionContext context,
ImmutableArray<ITypeSymbol?> enumerations
)
Expand All @@ -44,7 +69,8 @@ private void GenerateCode(

var code = Builder.BuildInterfaceFor(type);

context.AddSource(typeNamespace, code);
var hintName = $"{typeNamespace}.I{type.Name}";
context.AddSource(hintName, code);
}
}

Expand All @@ -66,29 +92,4 @@ CancellationToken cancellationToken
) as ITypeSymbol;
return type;
}

private static bool CouldBeClassAsync(
SyntaxNode syntaxNode,
CancellationToken cancellationToken
)
{
if (syntaxNode is not AttributeSyntax attribute)
{
return false;
}

var name = ExtractName(attribute.Name);

return name is DefaultAttributeName;
}

private static string? ExtractName(NameSyntax? name)
{
return name switch
{
SimpleNameSyntax ins => ins.Identifier.Text,
QualifiedNameSyntax qns => qns.Right.Identifier.Text,
_ => null
};
}
}
22 changes: 21 additions & 1 deletion AutomaticInterface/AutomaticInterface/Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ is not ClassDeclarationSyntax classSyntax
return string.Empty;
}

var namespaceName = typeSymbol.ContainingNamespace.ToDisplayString();
var namespaceName = GetNameSpace(typeSymbol);

var interfaceName = $"I{classSyntax.GetClassName()}";

Expand All @@ -39,6 +39,26 @@ is not ClassDeclarationSyntax classSyntax
return generatedCode;
}

private static string GetNameSpace(ISymbol typeSymbol)
{
var generationAttribute = typeSymbol
.GetAttributes()
.FirstOrDefault(x =>
x.AttributeClass != null
&& x.AttributeClass.Name.Contains(AutomaticInterfaceGenerator.DefaultAttributeName)
);

if (generationAttribute == null)
{
return typeSymbol.ContainingNamespace.ToDisplayString();
}
var customNs = generationAttribute.ConstructorArguments.FirstOrDefault().Value?.ToString();

return string.IsNullOrWhiteSpace(customNs)
? typeSymbol.ContainingNamespace.ToDisplayString()
: customNs!;
}

private static void AddMethodsToInterface(
ITypeSymbol classSymbol,
InterfaceBuilder codeGenerator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
namespace AutomaticInterfaceAttribute
{
[AttributeUsage(AttributeTargets.Class)]
public class GenerateAutomaticInterfaceAttribute : Attribute { }
public class GenerateAutomaticInterfaceAttribute : Attribute
{
public GenerateAutomaticInterfaceAttribute(string namespaceName = "") { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using AutomaticInterfaceAttribute;
using CustomNamespace;

namespace AutomaticInterfaceExample
{
/// <summary>
/// Class Documentation will be copied
/// </summary>
[GenerateAutomaticInterface("CustomNamespace")]
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Major Code Smell",
"S1144:Unused private types or members should be removed",
Justification = "Demo class"
)]
public class DemoClass2 : IDemoClass2
{
public void Test() { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@
using System.CodeDom.Compiler;
using AutomaticInterfaceAttribute;

/// <summary>
/// Result of the generator
/// </summary>
namespace AutomaticInterfaceExample
{
/// <summary>
/// Bla bla
/// Result of the generator
/// </summary>
[GeneratedCode("AutomaticInterface", "")]
public partial interface InterfaceExample // would be IDemoClass normally, changed to avoid naming problems
Expand Down
2 changes: 1 addition & 1 deletion AutomaticInterface/TestNuget/TestNuget.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutomaticInterface" Version="1.1.1">
<PackageReference Include="AutomaticInterface" Version="2.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
74 changes: 73 additions & 1 deletion AutomaticInterface/Tests/GeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1766,7 +1766,79 @@ public partial interface IDemoClass
}
}
#nullable restore


""";
GenerateCode(code).Should().Be(expected);
}

[Fact]
public void CustomNameSpace()
{
const string code = """

using AutomaticInterfaceAttribute;
using System;

namespace AutomaticInterfaceExample
{
[AttributeUsage(AttributeTargets.Class)]
public class GenerateAutomaticInterfaceAttribute : Attribute
{
public GenerateAutomaticInterfaceAttribute(string namespaceName = "") { }
}

/// <summary>
/// Bla bla
/// </summary>
[GenerateAutomaticInterface("CustomNameSpace")]
class DemoClass
{

public async Task<Stream?> GetFinalDocumentsByIDFails(
string agreementID,
string docType,
bool amt = false ,
bool? attachSupportingDocuments = true,
CancellationToken cancellationToken = default)
{
await Task.Delay(100);
return default(Stream?);

}
}
}

""";

const string expected = """
//--------------------------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//--------------------------------------------------------------------------------------------------

#nullable enable
using System.CodeDom.Compiler;
using AutomaticInterfaceAttribute;
using System;

namespace CustomNameSpace
{
/// <summary>
/// Bla bla
/// </summary>
[GeneratedCode("AutomaticInterface", "")]
public partial interface IDemoClass
{
/// <inheritdoc />
Task<Stream?> GetFinalDocumentsByIDFails(string agreementID, string docType, bool amt = False, bool? attachSupportingDocuments = True, CancellationToken cancellationToken = null);

}
}
#nullable restore

""";
GenerateCode(code).Should().Be(expected);
}
Expand Down

0 comments on commit bb6eec4

Please sign in to comment.