diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
index 5ba3256..9bf0f0c 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -4,34 +4,53 @@ about: Create a bug report to help us improve
title: ''
labels: bug
assignees: ''
-
---
-**Describe the bug**
-A clear and concise description of what the bug is.
+### Describe the bug
+A clear and concise description of what the bug is
+
e.g. Assigned null instead of string to `EnumClass`'s `Namespace` property and it caused exception on compilation
-**Steps to Reproduce**
+### Steps to Reproduce
Provide simple steps to reproduce the behavior
-e.g.
+
+e.g.:
1. Declare enum
-2. Mark it with attribute
-3. Build project
-4. Call `xxx` method
+```csharp
+using EnumClass.Attributes;
+
+namespace Test;
+
+[EnumClass(ClassName = null)]
+public enum SampleEnum
+{
+ First
+}
+```
+2. Build project
+3. Call `xxx` method
+```csharp
+SampleEnum.GetAllMembers();
+```
-**Expected behavior**
+
+### Expected behavior
A clear and concise description of what you expected to happen.
+
e.g. `NullReferenceExcpetion` was thrown during build by generator
-**Actual behaviour**
+### Actual behaviour
What you expect to be done
+
e.g. `null` value was ommited or diagnostic reported
-**Environment**
+### Environment
+
- .NET version (6.0.103, 7.0.15)
- OS (Windows, Linux)
- IDE (Visual Studio, Rider)
-**Logs**
+### Context
+
Provide additional items, such as logs, that would help to solve this issue
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
index cfc1dc1..11d40f0 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -4,24 +4,23 @@ about: Suggest an idea for generator features
title: ''
labels: enhancement
assignees: ''
-
---
-**Is your feature request related to a problem? Please describe**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe problem you'd like to solve or encountered**
-Why do you offering this feature? May be this would be nice to have or have some useful use cases.
+### Problem you'd like to solve or encountered
+Why do you offering this feature?
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen: new generator, additional functions etc...
+May be this would be nice to have or have some useful use cases:
+- Support for libraries
+- More convenient way to use some function
+- etc...
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
+### Solution you'd like
+A clear and concise description of what you want to happen:
+ - new generator
+ - additional functions
+ - etc...
-**Possible use cases**
-Where this feature would be useful? Provide sample use case
+### Possible use cases
+Where this feature would be useful?
-**Possible solution**
-If you have any idea, how this feature could be implemented: extension method, static field etc...
-You may leave it blank
+Provide sample use case
diff --git a/src/EnumClass.Core/EnumClass.Core.csproj b/src/EnumClass.Core/EnumClass.Core.csproj
index 1e36ec6..3971195 100644
--- a/src/EnumClass.Core/EnumClass.Core.csproj
+++ b/src/EnumClass.Core/EnumClass.Core.csproj
@@ -12,7 +12,7 @@
-
-
+
+
diff --git a/src/EnumClass.Core/EnumInfoFactory.cs b/src/EnumClass.Core/EnumInfoFactory.cs
index cbb4bc9..ca08935 100644
--- a/src/EnumClass.Core/EnumInfoFactory.cs
+++ b/src/EnumClass.Core/EnumInfoFactory.cs
@@ -3,6 +3,9 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using EnumClass.Core.Accessibility;
+using EnumClass.Core.Infrastructure;
+using EnumClass.Core.Models;
+using EnumClass.Core.SymbolName;
using EnumClass.Core.UnderlyingType;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -27,25 +30,41 @@ public static EnumInfo CreateFromNamedTypeSymbol(INamedTypeSymbol enumSymbol,
{
var members = enumSymbol.GetMembers();
+ var attributeInfo = ExtractEnumClassAttributeCtorInfo(enumSymbol, enumClassAttribute);
+ var underlyingType = GetUnderlyingType(enumSymbol);
+ var accessibility = GetAccessibility(enumSymbol);
+
+ var resultNamespace = GetResultNamespace(enumSymbol, attributeInfo);
+ var @namespace = new ManuallySpecifiedSymbolName($"global::{resultNamespace}", resultNamespace);
+
+ var generatedClassName = GetClassName(enumSymbol, attributeInfo);
+ var fullyQualifiedClassName = $"global::{resultNamespace}.{generatedClassName}";
+ var className = new ManuallySpecifiedSymbolName(fullyQualifiedClassName, generatedClassName);
+
+ var fullyQualifiedEnumName = SymbolDisplay.ToDisplayString(enumSymbol, SymbolDisplayFormat.FullyQualifiedFormat);
+ var enumName = new ManuallySpecifiedSymbolName(fullyQualifiedEnumName, enumSymbol.Name);
+
var memberInfos = members
- // Skip all non enum fields declarations
.OfType()
+ .Combine(new EnumMemberInfoCreationContext(className, @namespace, enumName))
+ // Skip all non enum fields declarations
// Enum members are all const, according to docs
- .Where(static m => m is {IsConst: true, HasConstantValue:true})
+ .Where(static m => m.Left is {IsConst: true, HasConstantValue:true})
// Try to convert them into EnumMemberInfo
- .Select(symbol => EnumMemberInfoFactory.CreateFromFieldSymbol(symbol, enumMemberInfoAttribute)!)
+ .Select(p => EnumMemberInfoFactory.CreateFromFieldSymbol(p.Left, p.Right, enumMemberInfoAttribute)!)
// And skip failed
.Where(static i => i is not null)
// Finally, create array of members
.ToArray();
- var attributeInfo = ExtractEnumClassAttributeCtorInfo(enumSymbol, enumClassAttribute);
- var fullyQualifiedEnumName = SymbolDisplay.ToDisplayString(enumSymbol, SymbolDisplayFormat.FullyQualifiedFormat);
- var className = GetClassName(enumSymbol, attributeInfo);
- var ns = GetResultNamespace(enumSymbol, attributeInfo);
- var underlyingType = GetUnderlyingType(enumSymbol);
- var accessibility = GetAccessibility(enumSymbol);
- var fullyQualifiedClassName = $"global::{ns}.{className}";
- return new EnumInfo(fullyQualifiedEnumName, className, fullyQualifiedClassName, ns, memberInfos, underlyingType, accessibility);
+
+
+ return new EnumInfo(
+ className,
+ enumName,
+ memberInfos,
+ underlyingType,
+ accessibility,
+ @namespace);
}
private static IAccessibility GetAccessibility(INamedTypeSymbol enumSymbol)
diff --git a/src/EnumClass.Core/EnumMemberInfoCreationContext.cs b/src/EnumClass.Core/EnumMemberInfoCreationContext.cs
new file mode 100644
index 0000000..c0e70bb
--- /dev/null
+++ b/src/EnumClass.Core/EnumMemberInfoCreationContext.cs
@@ -0,0 +1,14 @@
+using EnumClass.Core.SymbolName;
+
+namespace EnumClass.Core;
+
+///
+/// Helpful information for constructing enum member class types
+///
+///
+/// Name for generating enum class
+///
+///
+/// Namespace where enum class will be generated
+///
+internal readonly record struct EnumMemberInfoCreationContext(ISymbolName EnumClassName, ISymbolName Namespace, ISymbolName EnumName);
\ No newline at end of file
diff --git a/src/EnumClass.Core/EnumMemberInfoFactory.cs b/src/EnumClass.Core/EnumMemberInfoFactory.cs
index c7ae8ec..1df8efe 100644
--- a/src/EnumClass.Core/EnumMemberInfoFactory.cs
+++ b/src/EnumClass.Core/EnumMemberInfoFactory.cs
@@ -1,5 +1,8 @@
using System;
using System.Linq;
+using EnumClass.Core.Infrastructure;
+using EnumClass.Core.Models;
+using EnumClass.Core.SymbolName;
using Microsoft.CodeAnalysis;
namespace EnumClass.Core;
@@ -12,12 +15,13 @@ namespace EnumClass.Core;
///
internal static class EnumMemberInfoFactory
{
- ///
+ ///
/// Create enum value info with passed 'raw' values
///
/// Instance of created enum value info
- public static EnumMemberInfo? CreateFromFieldSymbol(IFieldSymbol fieldSymbol,
- INamedTypeSymbol? enumMemberInfoAttribute)
+ internal static EnumMemberInfo? CreateFromFieldSymbol(IFieldSymbol fieldSymbol,
+ EnumMemberInfoCreationContext context,
+ INamedTypeSymbol? enumMemberInfoAttribute)
{
// For enum member this must be true
if (!fieldSymbol.IsConst)
@@ -26,19 +30,20 @@ internal static class EnumMemberInfoFactory
}
// Class name is equivalent to enum member name
- var className = $"{fieldSymbol.Name}EnumValue";
- var fullyQualifiedClassName = $"{fieldSymbol.ContainingNamespace.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}.EnumClass.{className}";
+ var enumClassName = $"{fieldSymbol.Name}EnumValue";
+ var fullyQualifiedEnumClassName = $"{context.EnumClassName.FullyQualified}.{enumClassName}";
+
+ var fullyQualifiedMemberName = $"{context.EnumName.FullyQualified}.{fieldSymbol.Name}";
+ var memberName = fieldSymbol.Name;
- var fullyQualifiedEnumValue = $"{fieldSymbol.ContainingType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}.{fieldSymbol.Name}";
- var enumMemberName = fieldSymbol.Name;
var stringRepresentation = GetToStringFromValue();
var enumMemberNameWithPrefix = $"{fieldSymbol.ContainingType.Name}.{fieldSymbol.Name}";
+
var integralValue = fieldSymbol.ConstantValue?.ToString() ?? throw new ArgumentNullException();
- return new EnumMemberInfo(className,
- fullyQualifiedClassName,
- fullyQualifiedEnumValue,
- enumMemberName,
+ return new EnumMemberInfo(
+ className: new ManuallySpecifiedSymbolName(fullyQualifiedEnumClassName, enumClassName),
+ memberName: new ManuallySpecifiedSymbolName(fullyQualifiedMemberName, memberName),
stringRepresentation,
enumMemberNameWithPrefix,
integralValue);
@@ -46,7 +51,8 @@ internal static class EnumMemberInfoFactory
string GetToStringFromValue()
{
// If no attributes specified, fallback to name of member
- if (fieldSymbol.GetAttributes() is {Length: 0} attributes)
+ var attributes = fieldSymbol.GetAttributes();
+ if (attributes is {Length: 0})
return fieldSymbol.Name;
// Search string info in [EnumMemberInfo]
diff --git a/src/EnumClass.Core/Constants.cs b/src/EnumClass.Core/Infrastructure/Constants.cs
similarity index 94%
rename from src/EnumClass.Core/Constants.cs
rename to src/EnumClass.Core/Infrastructure/Constants.cs
index 3deda09..0e4ab6c 100644
--- a/src/EnumClass.Core/Constants.cs
+++ b/src/EnumClass.Core/Infrastructure/Constants.cs
@@ -1,4 +1,4 @@
-namespace EnumClass.Core;
+namespace EnumClass.Core.Infrastructure;
public static class Constants
{
diff --git a/src/EnumClass.Core/Diagnostics.cs b/src/EnumClass.Core/Infrastructure/Diagnostics.cs
similarity index 95%
rename from src/EnumClass.Core/Diagnostics.cs
rename to src/EnumClass.Core/Infrastructure/Diagnostics.cs
index 97cc3e9..f942c76 100644
--- a/src/EnumClass.Core/Diagnostics.cs
+++ b/src/EnumClass.Core/Infrastructure/Diagnostics.cs
@@ -1,6 +1,6 @@
using Microsoft.CodeAnalysis;
-namespace EnumClass.Core;
+namespace EnumClass.Core.Infrastructure;
public static class Diagnostics
{
diff --git a/src/EnumClass.Core/Infrastructure/ImmutableArrayExtensions.cs b/src/EnumClass.Core/Infrastructure/ImmutableArrayExtensions.cs
new file mode 100644
index 0000000..09f89ef
--- /dev/null
+++ b/src/EnumClass.Core/Infrastructure/ImmutableArrayExtensions.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace EnumClass.Core.Infrastructure;
+
+internal static class ImmutableArrayExtensions
+{
+ // ReSharper disable once LoopCanBeConvertedToQuery
+ public static IEnumerable<(T1 Left, T2 Right)> Combine(this IEnumerable array, T2 value)
+ {
+ foreach (var element in array)
+ {
+ yield return ( element, value );
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/EnumClass.Core/EnumInfo.cs b/src/EnumClass.Core/Models/EnumInfo.cs
similarity index 88%
rename from src/EnumClass.Core/EnumInfo.cs
rename to src/EnumClass.Core/Models/EnumInfo.cs
index bb5ce8c..89dbeb1 100644
--- a/src/EnumClass.Core/EnumInfo.cs
+++ b/src/EnumClass.Core/Models/EnumInfo.cs
@@ -1,36 +1,38 @@
#nullable enable
-using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnumClass.Core.Accessibility;
+using EnumClass.Core.SymbolName;
using EnumClass.Core.UnderlyingType;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-namespace EnumClass.Core;
+namespace EnumClass.Core.Models;
public class EnumInfo
{
+ private readonly ISymbolName _className;
+ private readonly ISymbolName _enumName;
+ private readonly ISymbolName _namespace;
+
///
/// Only class name without namespace
///
- public string ClassName { get; }
-
+ public string ClassName => _className.Plain;
+
///
/// Fully qualified name of generated class
///
- public string FullyQualifiedClassName { get; }
+ public string FullyQualifiedClassName => _className.FullyQualified;
///
/// Fully qualified name of original enum
///
- public string FullyQualifiedEnumName { get; }
-
+ public string FullyQualifiedEnumName => _enumName.FullyQualified;
+
///
- /// Namespace of original enum
+ /// Namespace of generated class
///
- public string Namespace { get; }
+ public string Namespace => _namespace.Plain;
///
/// Members of enum
@@ -48,21 +50,19 @@ public class EnumInfo
///
public IAccessibility Accessibility { get; }
- internal EnumInfo(string fullyQualifiedEnumName,
- string className,
- string fullyQualifiedClassName,
- string ns,
+ internal EnumInfo(ISymbolName className,
+ ISymbolName enumName,
EnumMemberInfo[] members,
IUnderlyingType underlyingType,
- IAccessibility accessibility)
+ IAccessibility accessibility,
+ ISymbolName @namespace)
{
- FullyQualifiedEnumName = fullyQualifiedEnumName;
- Namespace = ns;
+ _className = className;
+ _enumName = enumName;
Members = members;
UnderlyingType = underlyingType;
Accessibility = accessibility;
- FullyQualifiedClassName = fullyQualifiedClassName;
- ClassName = className;
+ _namespace = @namespace;
}
///
diff --git a/src/EnumClass.Core/EnumMemberInfo.cs b/src/EnumClass.Core/Models/EnumMemberInfo.cs
similarity index 80%
rename from src/EnumClass.Core/EnumMemberInfo.cs
rename to src/EnumClass.Core/Models/EnumMemberInfo.cs
index a278543..3263832 100644
--- a/src/EnumClass.Core/EnumMemberInfo.cs
+++ b/src/EnumClass.Core/Models/EnumMemberInfo.cs
@@ -1,39 +1,39 @@
#nullable enable
-using System;
-using System.Linq;
using System.Text;
-using Microsoft.CodeAnalysis;
+using EnumClass.Core.SymbolName;
using Microsoft.CodeAnalysis.CSharp;
-namespace EnumClass.Core;
+namespace EnumClass.Core.Models;
public class EnumMemberInfo
{
+ private readonly ISymbolName _className;
+ private readonly ISymbolName _memberName;
private readonly string _stringRepresentation;
-
+
///
/// Friendly name of class.
/// To use in static fields for classes
///
- public string ClassName { get; }
-
+ public string ClassName => _className.Plain;
+
///
/// Class name of enum class starting with 'global::' prefix
///
- public string FullyQualifiedClassName { get; }
-
+ public string FullyQualifiedClassName => _className.FullyQualified;
+
///
/// Name of enum value we constructing.
/// This is fully qualified, with 'global::' prefix
///
- public string FullyQualifiedEnumValue { get; }
+ public string FullyQualifiedEnumMemberName => _memberName.FullyQualified;
///
/// Name of enum member we constructing.
/// This is without 'global::' prefix and enum name
///
/// Cat
- public string EnumMemberNameOnly { get; }
+ public string MemberName => _memberName.Plain;
///
/// Name of enum member with original enum name prefix.
@@ -48,18 +48,14 @@ public class EnumMemberInfo
///
public string IntegralValue { get; }
- internal EnumMemberInfo(string className,
- string fullyQualifiedClassName,
- string fullyQualifiedEnumValue,
- string enumMemberNameOnly,
+ internal EnumMemberInfo(ISymbolName className,
+ ISymbolName memberName,
string stringRepresentation,
string enumMemberNameWithEnumName,
string integralValue)
{
- ClassName = className;
- FullyQualifiedClassName = fullyQualifiedClassName;
- FullyQualifiedEnumValue = fullyQualifiedEnumValue;
- EnumMemberNameOnly = enumMemberNameOnly;
+ _className = className;
+ _memberName = memberName;
_stringRepresentation = stringRepresentation;
EnumMemberNameWithEnumName = enumMemberNameWithEnumName;
IntegralValue = integralValue;
@@ -76,8 +72,8 @@ public string GetSwitchArgName()
{
return _switchArgName;
}
- var firstLetter = char.ToLowerInvariant(EnumMemberNameOnly[0]);
- var switchArgName = $"{firstLetter}{EnumMemberNameOnly.Substring(1)}Switch";
+ var firstLetter = char.ToLowerInvariant(MemberName[0]);
+ var switchArgName = $"{firstLetter}{MemberName.Substring(1)}Switch";
_switchArgName = switchArgName;
return switchArgName;
}
diff --git a/src/EnumClass.Core/SymbolName/ISymbolName.cs b/src/EnumClass.Core/SymbolName/ISymbolName.cs
new file mode 100644
index 0000000..1349a64
--- /dev/null
+++ b/src/EnumClass.Core/SymbolName/ISymbolName.cs
@@ -0,0 +1,24 @@
+namespace EnumClass.Core.SymbolName;
+
+///
+/// Interface for convenient work with symbol names
+///
+public interface ISymbolName
+{
+ ///
+ /// Fully qualified element name.
+ /// Usually with 'global::' prefix
+ ///
+ ///
+ /// global::EnumClass.Models.PetKind - fully qualified enum name
+ ///
+ public string FullyQualified { get; }
+
+ ///
+ /// Plain name of element.
+ ///
+ ///
+ /// PetKind - only enum name
+ ///
+ public string Plain { get; }
+}
\ No newline at end of file
diff --git a/src/EnumClass.Core/SymbolName/ManuallySpecifiedSymbolName.cs b/src/EnumClass.Core/SymbolName/ManuallySpecifiedSymbolName.cs
new file mode 100644
index 0000000..2c19936
--- /dev/null
+++ b/src/EnumClass.Core/SymbolName/ManuallySpecifiedSymbolName.cs
@@ -0,0 +1,13 @@
+namespace EnumClass.Core.SymbolName;
+
+public class ManuallySpecifiedSymbolName: ISymbolName
+{
+ public ManuallySpecifiedSymbolName(string fullyQualified, string plain)
+ {
+ FullyQualified = fullyQualified;
+ Plain = plain;
+ }
+
+ public string FullyQualified { get; }
+ public string Plain { get; }
+}
\ No newline at end of file
diff --git a/src/EnumClass.Generator/EnumClassIncrementalGenerator.cs b/src/EnumClass.Generator/EnumClassIncrementalGenerator.cs
index b1f8c7c..bb1be79 100644
--- a/src/EnumClass.Generator/EnumClassIncrementalGenerator.cs
+++ b/src/EnumClass.Generator/EnumClassIncrementalGenerator.cs
@@ -2,6 +2,8 @@
using System.Diagnostics.CodeAnalysis;
using System.Text;
using EnumClass.Core;
+using EnumClass.Core.Infrastructure;
+using EnumClass.Core.Models;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -186,14 +188,14 @@ private static void GenerateAllEnumClasses(Compilation
// because usually we have only enum member name in string (my subjective opinion)
foreach (var member in enumInfo.Members)
{
- builder.Append($" case \"{member.EnumMemberNameOnly}\":\n");
- builder.Append($" {enumVariableName} = {member.EnumMemberNameOnly};\n");
+ builder.Append($" case \"{member.MemberName}\":\n");
+ builder.Append($" {enumVariableName} = {member.MemberName};\n");
builder.Append($" return true;\n");
}
foreach (var member in enumInfo.Members)
{
builder.Append($" case \"{member.EnumMemberNameWithEnumName}\":\n");
- builder.Append($" {enumVariableName} = {member.EnumMemberNameOnly};\n");
+ builder.Append($" {enumVariableName} = {member.MemberName};\n");
builder.Append($" return true;\n");
}
@@ -222,7 +224,7 @@ private static void GenerateAllEnumClasses(Compilation
foreach (var member in enumInfo.Members)
{
builder.Append($" case {member.IntegralValue}:\n");
- builder.Append($" {enumVariableName} = {member.EnumMemberNameOnly};\n");
+ builder.Append($" {enumVariableName} = {member.MemberName};\n");
builder.Append($" return true;\n");
}
@@ -305,14 +307,14 @@ private static void GenerateAllEnumClasses(Compilation
{
builder.AppendLine();
// Generate static field for required Enum
- builder.AppendFormat(" public static readonly {0} {1} = new {0}();\n", member.ClassName, member.EnumMemberNameOnly);
+ builder.AppendFormat(" public static readonly {0} {1} = new {0}();\n", member.ClassName, member.MemberName);
// Generate enum class for enum
builder.AppendFormat(" public partial class {0}: {1}\n", member.ClassName, enumInfo.ClassName);
builder.AppendLine(" {");
// Generate constructor
- builder.AppendFormat(" public {0}(): base({1}) {{ }}\n", member.ClassName, member.FullyQualifiedEnumValue);
+ builder.AppendFormat(" public {0}(): base({1}) {{ }}\n", member.ClassName, member.FullyQualifiedEnumMemberName);
// Override default ToString()
builder.AppendLine(" public override string ToString()");
@@ -369,7 +371,7 @@ private static void GenerateAllEnumClasses(Compilation
foreach (var member in enumInfo.Members)
{
- builder.AppendFormat("{0}, ", member.EnumMemberNameOnly);
+ builder.AppendFormat("{0}, ", member.MemberName);
}
builder.AppendLine("};\n");
diff --git a/src/EnumClass.JsonConverter.Generator/JsonConverterIncrementalGenerator.cs b/src/EnumClass.JsonConverter.Generator/JsonConverterIncrementalGenerator.cs
index f58a052..a5ef6a8 100644
--- a/src/EnumClass.JsonConverter.Generator/JsonConverterIncrementalGenerator.cs
+++ b/src/EnumClass.JsonConverter.Generator/JsonConverterIncrementalGenerator.cs
@@ -1,5 +1,6 @@
using System.Text;
using EnumClass.Core;
+using EnumClass.Core.Models;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
@@ -43,6 +44,7 @@ private static void GenerateEnumJsonConverter(EnumInfo enumInfo, SourceProductio
builder.AppendFormat(
" public override {0} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n", enumInfo.FullyQualifiedClassName);
builder.AppendLine(" {");
+
// We are deserializing using integral representation of enum
// For this purpose, Utf8JsonSerializer has TryGet* methods in which second parts are clr name of integral type
// ClrTypeName was added to IUnderlyingType primarily for such cases
diff --git a/src/EnumClass.JsonConverter.Generator/icon.png b/src/EnumClass.JsonConverter.Generator/icon.png
deleted file mode 100644
index 6229951..0000000
Binary files a/src/EnumClass.JsonConverter.Generator/icon.png and /dev/null differ
diff --git a/tests/Generator/EnumClass.Generator.Tests/EnumClass.Generator.Tests.csproj b/tests/Generator/EnumClass.Generator.Tests/EnumClass.Generator.Tests.csproj
index 010ca42..e086629 100644
--- a/tests/Generator/EnumClass.Generator.Tests/EnumClass.Generator.Tests.csproj
+++ b/tests/Generator/EnumClass.Generator.Tests/EnumClass.Generator.Tests.csproj
@@ -29,6 +29,7 @@
+
diff --git a/tests/Generator/EnumClass.Generator.Tests/EnumClassGenerationTests.cs b/tests/Generator/EnumClass.Generator.Tests/EnumClassGeneratorTests.cs
similarity index 74%
rename from tests/Generator/EnumClass.Generator.Tests/EnumClassGenerationTests.cs
rename to tests/Generator/EnumClass.Generator.Tests/EnumClassGeneratorTests.cs
index 3766a82..0a5b64d 100644
--- a/tests/Generator/EnumClass.Generator.Tests/EnumClassGenerationTests.cs
+++ b/tests/Generator/EnumClass.Generator.Tests/EnumClassGeneratorTests.cs
@@ -1,15 +1,14 @@
using System.Reflection;
-using System.Runtime.InteropServices;
using EnumClass.Attributes;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
namespace EnumClass.Generator.Tests;
-public class EnumClassGenerationTests
+public class EnumClassGeneratorTests
{
[Fact]
- public void WithSingleMember__ShouldGenerateCorrectly()
+ public void WithSingleMember__ShouldGenerateWithoutErrors()
{
var source = @"using EnumClass.Attributes;
@@ -28,27 +27,27 @@ public enum SampleEnum: byte
MetadataReference.CreateFromFile(Assembly.GetCallingAssembly().Location),
MetadataReference.CreateFromFile(typeof(string).Assembly.Location),
- // MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Linq.Expressions")).Location),
MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location),
MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("netstandard")).Location),
}, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- var driver = CSharpGeneratorDriver.Create(new EnumClassIncrementalGenerator())
- .RunGenerators(compilation);
+ CSharpGeneratorDriver.Create(new EnumClassIncrementalGenerator())
+ .RunGeneratorsAndUpdateCompilation(compilation, out _, out var diagnostics);
+ Assert.Empty(diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error));
}
[Fact]
- public void WithTwoMembers__ShouldGenerateCorrectly()
+ public void WithSpecifiedAttributeArguments__ShouldGenerateWithoutErrors()
{
var source = @"using EnumClass.Attributes;
namespace Test;
[EnumClass(Namespace = ""Test"", ClassName = ""SampleEnum"")]
-public enum SampleEnum: long
+public enum SampleEnum
{
- Manager = long.MaxValue - 4,
+ Manager,
Programmer,
Tester,
CTO,
@@ -66,7 +65,8 @@ public enum SampleEnum: long
MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("netstandard")).Location),
}, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
- var driver = CSharpGeneratorDriver.Create(new EnumClassIncrementalGenerator())
- .RunGenerators(compilation);
+ CSharpGeneratorDriver.Create(new EnumClassIncrementalGenerator())
+ .RunGeneratorsAndUpdateCompilation(compilation, out _, out var diagnostics);
+ Assert.Empty(diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error));
}
}
\ No newline at end of file
diff --git a/tests/Generator/EnumClass.Generator.Tests/EnumInfoFactoryTests.cs b/tests/Generator/EnumClass.Generator.Tests/EnumInfoFactoryTests.cs
new file mode 100644
index 0000000..9388332
--- /dev/null
+++ b/tests/Generator/EnumClass.Generator.Tests/EnumInfoFactoryTests.cs
@@ -0,0 +1,146 @@
+using System.Reflection;
+using EnumClass.Attributes;
+using EnumClass.Core;
+using EnumClass.Core.Models;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+
+namespace EnumClass.Generator.Tests;
+
+public class EnumInfoFactoryTests
+{
+ public const string SampleEnumCode = @"using EnumClass.Attributes;
+
+namespace Test;
+
+[EnumClass]
+public enum SampleEnum
+{
+ One = 1,
+ Two = 2,
+ Three = 3
+}";
+
+ private List GetEnumInfos(params string[] sourceCodes)
+ {
+ var compilation = CSharpCompilation.Create("Test",
+ syntaxTrees: sourceCodes.Select(x => CSharpSyntaxTree.ParseText(x)),
+ references: new[]
+ {
+ MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
+ MetadataReference.CreateFromFile(typeof(EnumClassAttribute).Assembly.Location),
+ MetadataReference.CreateFromFile(typeof(EnumInfo).Assembly.Location),
+ MetadataReference.CreateFromFile(Assembly.GetCallingAssembly().Location),
+ MetadataReference.CreateFromFile(typeof(string).Assembly.Location),
+ MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("System.Runtime")).Location),
+ MetadataReference.CreateFromFile(Assembly.Load(new AssemblyName("netstandard")).Location),
+ },
+ options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
+
+ CSharpGeneratorDriver.Create(new EnumClassIncrementalGenerator())
+ .RunGeneratorsAndUpdateCompilation(compilation, out var resultCompilation, out var d);
+
+ // Pass SourceProductionContext safely,
+ // because there no errors expected
+ return EnumInfoFactory.GetAllEnumInfosFromCompilation(resultCompilation, new SourceProductionContext())!;
+ }
+
+ [Fact]
+ public void GetAllEnumsFromCompilation__WithSingleMarkedEnum__ShouldReturnListWithSingleElement()
+ {
+ var enums = GetEnumInfos(SampleEnumCode);
+ Assert.Single(enums);
+ }
+
+ [Fact]
+ public void GetAllEnumsFromCompilation__WithSingleMarkedEnumAnd3Members__ShouldReturnSingleEnumInfoWith3EnumMemberInfo()
+ {
+ var e = GetEnumInfos(SampleEnumCode).First();
+ Assert.Equal(3, e.Members.Length);
+ }
+
+ [Fact]
+ public void ShouldCorrectlyExtractClassName()
+ {
+ var e = GetEnumInfos(SampleEnumCode).First();
+ Assert.Equal("SampleEnum", e.ClassName);
+ }
+
+ [Fact]
+ public void ShouldCorrectlyExtractFullyQualifiedMemberClassNames()
+ {
+ var expected = new HashSet()
+ {
+ "global::Test.EnumClass.SampleEnum.OneEnumValue",
+ "global::Test.EnumClass.SampleEnum.TwoEnumValue",
+ "global::Test.EnumClass.SampleEnum.ThreeEnumValue",
+ };
+ var e = GetEnumInfos(SampleEnumCode).First();
+ var actual = e.Members.Select(x => x.FullyQualifiedClassName).ToHashSet();
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void ShouldCorrectlyExtractMemberClassNames()
+ {
+ var expected = new HashSet()
+ {
+ "OneEnumValue",
+ "TwoEnumValue",
+ "ThreeEnumValue",
+ };
+ var e = GetEnumInfos(SampleEnumCode).First();
+ var actual = e.Members.Select(x => x.ClassName).ToHashSet();
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void ShouldCorrectlyExtractFullyQualifiedEnumName()
+ {
+ var expected = "global::Test.SampleEnum";
+ var e = GetEnumInfos(SampleEnumCode).First();
+ var actual = e.FullyQualifiedEnumName;
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void ShouldCorrectlyExtractFullyQualifiedEnumMemberValueName()
+ {
+ var expected = new HashSet()
+ {
+ "global::Test.SampleEnum.One",
+ "global::Test.SampleEnum.Two",
+ "global::Test.SampleEnum.Three",
+ };
+ var e = GetEnumInfos(SampleEnumCode).First();
+ var actual = e.Members.Select(x => x.FullyQualifiedEnumMemberName).ToHashSet();
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void ShouldCorrectlyExtractNamespace()
+ {
+ var expected = "Test.EnumClass";
+ var actual = GetEnumInfos(SampleEnumCode).First().Namespace;
+ Assert.Equal(expected, actual);
+ }
+
+ public const string SecondEnumCode = @"using EnumClass.Attributes;
+
+namespace Test;
+
+[EnumClass]
+public enum SecondEnum
+{
+ Nope,
+ Yes,
+ No
+}";
+
+ [Fact]
+ public void GetAllEnumsFromCompilation_With2MarkedEnums_ShouldReturnListWith2Elements()
+ {
+ var enums = GetEnumInfos(SampleEnumCode, SecondEnumCode);
+ Assert.Equal(2, enums.Count);
+ }
+}
\ No newline at end of file