Skip to content

Commit

Permalink
Merge pull request #5 from ashenBlade/feature/refactoring
Browse files Browse the repository at this point in the history
Refactoring
  • Loading branch information
ashenBlade authored May 28, 2023
2 parents 2c52882 + 53dfbe7 commit 8d4e8d2
Show file tree
Hide file tree
Showing 19 changed files with 370 additions and 113 deletions.
43 changes: 31 additions & 12 deletions .github/ISSUE_TEMPLATE/bug-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
29 changes: 14 additions & 15 deletions .github/ISSUE_TEMPLATE/feature-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions src/EnumClass.Core/EnumClass.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</ItemGroup>

<ItemGroup>
<AdditionalFiles Include="../../docs/AnalyzerReleases.Shipped.md"/>
<AdditionalFiles Include="../../docs/AnalyzerReleases.Unshipped.md"/>
<AdditionalFiles Include="../../docs/AnalyzerReleases.Shipped.md" />
<AdditionalFiles Include="../../docs/AnalyzerReleases.Unshipped.md" />
</ItemGroup>
</Project>
41 changes: 30 additions & 11 deletions src/EnumClass.Core/EnumInfoFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<IFieldSymbol>()
.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)
Expand Down
14 changes: 14 additions & 0 deletions src/EnumClass.Core/EnumMemberInfoCreationContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using EnumClass.Core.SymbolName;

namespace EnumClass.Core;

/// <summary>
/// Helpful information for constructing enum member class types
/// </summary>
/// <param name="EnumClassName">
/// Name for generating enum class
/// </param>
/// <param name="Namespace">
/// Namespace where enum class will be generated
/// </param>
internal readonly record struct EnumMemberInfoCreationContext(ISymbolName EnumClassName, ISymbolName Namespace, ISymbolName EnumName);
30 changes: 18 additions & 12 deletions src/EnumClass.Core/EnumMemberInfoFactory.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -12,12 +15,13 @@ namespace EnumClass.Core;
/// </remarks>
internal static class EnumMemberInfoFactory
{
/// <summary>
/// <summary>
/// Create enum value info with passed 'raw' values
/// </summary>
/// <returns>Instance of created enum value info</returns>
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)
Expand All @@ -26,27 +30,29 @@ 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);

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]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace EnumClass.Core;
namespace EnumClass.Core.Infrastructure;

public static class Constants
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.CodeAnalysis;

namespace EnumClass.Core;
namespace EnumClass.Core.Infrastructure;

public static class Diagnostics
{
Expand Down
16 changes: 16 additions & 0 deletions src/EnumClass.Core/Infrastructure/ImmutableArrayExtensions.cs
Original file line number Diff line number Diff line change
@@ -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<T1, T2>(this IEnumerable<T1> array, T2 value)
{
foreach (var element in array)
{
yield return ( element, value );
}
}
}
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Only class name without namespace
/// </summary>
public string ClassName { get; }
public string ClassName => _className.Plain;

/// <summary>
/// Fully qualified name of generated class
/// </summary>
public string FullyQualifiedClassName { get; }
public string FullyQualifiedClassName => _className.FullyQualified;

/// <summary>
/// Fully qualified name of original enum
/// </summary>
public string FullyQualifiedEnumName { get; }
public string FullyQualifiedEnumName => _enumName.FullyQualified;

/// <summary>
/// Namespace of original enum
/// Namespace of generated class
/// </summary>
public string Namespace { get; }
public string Namespace => _namespace.Plain;

/// <summary>
/// Members of enum
Expand All @@ -48,21 +50,19 @@ public class EnumInfo
/// </summary>
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;
}

/// <summary>
Expand Down
Loading

0 comments on commit 8d4e8d2

Please sign in to comment.