Skip to content

Commit

Permalink
Add accessibility check in validation
Browse files Browse the repository at this point in the history
  • Loading branch information
Genbox committed Jun 16, 2024
1 parent d6f096d commit 7f552dd
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
24 changes: 17 additions & 7 deletions Src/FastEnum.Tests.CodeGen/Code/TestHelper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
Expand Down Expand Up @@ -39,7 +40,20 @@ public static string ReadResource(string name)
return reader.ReadToEnd();
}

public static string GetGeneratedOutput<T>(string source) where T : IIncrementalGenerator, new()
public static string GetGeneratedOutput<T>(string source, bool checkForErrors = true) where T : IIncrementalGenerator, new()
{
string res = GetGeneratedOutput<T>(source, out ImmutableArray<Diagnostic> codeGenDiag, out IEnumerable<Diagnostic> compilerDiag);

if (checkForErrors)
Assert.Empty(codeGenDiag);

if (checkForErrors)
Assert.Empty(compilerDiag);

return res;
}

public static string GetGeneratedOutput<T>(string source, out ImmutableArray<Diagnostic> codeGenDiag, out IEnumerable<Diagnostic> compilerDiag) where T : IIncrementalGenerator, new()
{
//Add a few headers by default
source = GetHeader() + "\n" + source;
Expand All @@ -65,14 +79,10 @@ public static string ReadResource(string name)

CSharpGeneratorDriver driver = CSharpGeneratorDriver.Create(generator);

driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out ImmutableArray<Diagnostic> diagnostics);
Assert.Empty(diagnostics); //CodeGen diagnostics

IEnumerable<Diagnostic> compilerDiag = outputCompilation.GetDiagnostics().Where(x => !_ignore.Contains(x.Id));
Assert.Empty(compilerDiag); //C# compiler diagnostics
driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outputCompilation, out codeGenDiag);
compilerDiag = outputCompilation.GetDiagnostics().Where(x => !_ignore.Contains(x.Id));

List<SyntaxTree> trees = outputCompilation.SyntaxTrees.ToList();
Assert.True(trees.Count > 1);

StringBuilder sb = new StringBuilder();

Expand Down
26 changes: 26 additions & 0 deletions Src/FastEnum.Tests.CodeGen/ValidationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Immutable;
using Genbox.FastEnum.Tests.CodeGen.Code;
using Microsoft.CodeAnalysis;

namespace Genbox.FastEnum.Tests.CodeGen;

public class ValidationTests
{
[Fact]
public void TestLessVisibleClass()
{
string code = """
internal class MyInternalClass
{
[FastEnum]
public enum MyPublicEnum1
{
Value
}
}
""";
TestHelper.GetGeneratedOutput<EnumGenerator>(code, out ImmutableArray<Diagnostic> codeGenDiag, out _);
Diagnostic res = Assert.Single(codeGenDiag);
Assert.Equal("FE001", res.Id); //Enum visibility validation failed
}
}
17 changes: 13 additions & 4 deletions Src/FastEnum/EnumGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)

if (!IsSpecsValid(specs, out string? message))
{
DiagnosticDescriptor report = new DiagnosticDescriptor("ESG001", "FastEnum", $"Validation failed with message: {message}", "errors", DiagnosticSeverity.Error, true);
DiagnosticDescriptor report = new DiagnosticDescriptor("FE001", "FastEnum", $"Validation failed with message: {message}", "errors", DiagnosticSeverity.Error, true);
spc.ReportDiagnostic(Diagnostic.Create(report, Location.None));
return;
}
Expand Down Expand Up @@ -124,8 +124,17 @@ private static bool IsSpecsValid(ImmutableArray<EnumSpec> specs, out string? mes
return false;
}

//Now we need to satisfy C#'s invariant: parents must have equal or less accessibility than it's children
//TODO
//Now we need to satisfy C#'s invariant: parents must have equal or more visibility than it's children
if (es.AccessChain.Length > 1)
{
var parentAccess = es.AccessChain[1];

if (parentAccess < enumAccess)
{
message = $"Parent class is less visible ({parentAccess}) than enum '{es.FullName} ({enumAccess}). That is not supported";
return false;
}
}
}

message = null;
Expand Down Expand Up @@ -222,7 +231,7 @@ private static SourceText GetSource(StringBuilder sb, AssemblyName assemblyName,

while (curSym != null)
{
accessChain.Add(symbol.DeclaredAccessibility);
accessChain.Add(curSym.DeclaredAccessibility);
curSym = curSym.ContainingSymbol;
}

Expand Down

0 comments on commit 7f552dd

Please sign in to comment.