Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/BuildAndTest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build and Test

on:
pull_request:
branches:
- '**'
push:
branches:
- 'main'

jobs:
build-and-test:
name: Build and Test on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2022]

steps:
- uses: actions/checkout@v4

- name: Setup .NET 8 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: 'Build'
run: dotnet build "./FluentBuilder Solution.sln" -c Release

- name: 'Test'
run: dotnet test ./tests/FluentBuilderGeneratorTests/FluentBuilderGeneratorTests.csproj --no-build -c Release
1 change: 1 addition & 0 deletions FluentBuilder Solution.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuilderConsumerFileScopedNa
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GitHub Actions", "GitHub Actions", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
.github\workflows\BuildAndTest.yml = .github\workflows\BuildAndTest.yml
.github\workflows\CreateRelease.yml = .github\workflows\CreateRelease.yml
EndProjectSection
EndProject
Expand Down
4 changes: 4 additions & 0 deletions FluentBuilder Solution.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=FBGERR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=FBGINF/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Parameterless/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SGERR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=SGINF/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Usings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
<ProjectReference Include="..\..\src\FluentBuilderGenerator\FluentBuilderGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup Condition=" '$(Configuration)' == 'Release' ">
<PackageReference Include="FluentBuilder" Version="0.4.3">
<ItemGroup Condition=" '$(Configuration)' == 'Release' or '$(Configuration)' == 'Debug' ">
<PackageReference Include="FluentBuilder" Version="0.11.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentBuilder" Version="0.9.1">
<PackageReference Include="FluentBuilder" Version="0.10.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src-examples/BuilderConsumerNET45/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ static void Main(string[] args)
Console.WriteLine("t0 = " + JsonConvert.SerializeObject(t0));

var t1 = new ThingWithOnlyParameterizedConstructorsBuilder()
.WithConstructor(1,2,"xxx")
.UsingConstructor(1,2,"xxx")
.Build();
Console.WriteLine("t1 = " + JsonConvert.SerializeObject(t1));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentBuilder" Version="0.10.0.4-preview-01">
<PackageReference Include="FluentBuilder" Version="0.11.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,11 @@ public class ClassWithPrivateSetter
public int Value1 { get; private set; }

public int Value2 { get; set; }

[AutoGenerateBuilder(FluentBuilderAccessibility.PublicAndPrivate)]
private class PrivateClass
{
public int Test { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Authors>Stef Heyenrath</Authors>
<Description>Some extensions for a ISourceGenerator which can be used to execute a SourceGenerator manually which makes unit-testing easy.</Description>
<Description>Some extensions for a ISourceGenerator and IIncrementalGenerator which can be used to execute a SourceGenerator manually which makes unit-testing easy.</Description>
<PackageTags>CSharp;SourceGenerator;SourceGenerators;Extensions;Execute;UnitTest;Test</PackageTags>
<PackageIcon>icon.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand All @@ -27,8 +27,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="AnyOf" Version="0.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
<PackageReference Include="AnyOf" Version="0.5.0.1" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
internal sealed class RequiredMemberAttribute : Attribute;

[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]
internal sealed class CompilerFeatureRequiredAttribute(string featureName) : Attribute
{
public string FeatureName { get; } = featureName;

public bool IsOptional { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,32 @@ public class ExecuteResult
/// <summary>
/// The internally used GeneratorDriver is also returned here to support using https://github.com/VerifyTests/Verify.SourceGenerators.
/// </summary>
public GeneratorDriver GeneratorDriver { get; set; } = null!;
public required GeneratorDriver GeneratorDriver { get; init; }

/// <summary>
/// A list of generated files.
/// </summary>
public IReadOnlyList<FileResult> Files { get; set; } = new List<FileResult>();
public required IReadOnlyList<FileResult> Files { get; init; }

/// <summary>
/// A list of Errors
/// Gets the collection of diagnostics associated with the current operation or state.
/// </summary>
public IReadOnlyList<string> ErrorMessages { get; set; } = new List<string>();
public required IReadOnlyList<Diagnostic> Diagnostics { get; init; }

/// <summary>
/// A list of Warnings
/// A list of Error messages
/// </summary>
public IReadOnlyList<string> WarningMessages { get; set; } = new List<string>();
public required IReadOnlyList<string> ErrorMessages { get; init; }

/// <summary>
/// A list of Warning messages
/// </summary>
public required IReadOnlyList<string> WarningMessages { get; init; }

/// <summary>
/// A list of Information messages
/// </summary>
public required IReadOnlyList<string> InformationMessages { get; init; }

/// <summary>
/// Is the result valid.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static ExecuteResult Execute(
IReadOnlyList<string>? additionalTextPaths = null
)
{
return Execute(sourceGenerator, $"GeneratedNamespace_{Guid.NewGuid().ToString().Replace("-", "")}", sources, additionalTextPaths);
return Execute(sourceGenerator, GetRandomAssemblyName(), sources, additionalTextPaths);
}

/// <summary>
Expand All @@ -47,6 +47,52 @@ public static ExecuteResult Execute(
IReadOnlyList<string>? additionalTextPaths = null
)
{
return ExecuteInternal(() => CSharpGeneratorDriver.Create(sourceGenerator), assemblyName, sources, additionalTextPaths);
}

/// <summary>
/// Executes and runs the specified <see cref="IIncrementalGenerator"/>.
/// </summary>
/// <param name="sourceGenerator">The SourceGenerator to execute.</param>
/// <param name="sources">Provide a list of sources which need to be analyzed and processed.</param>
/// <param name="additionalTextPaths">A list of additional files.</param>
/// <returns><see cref="ExecuteResult"/></returns>
public static ExecuteResult Execute(
this IIncrementalGenerator sourceGenerator,
IReadOnlyList<SourceFile> sources,
IReadOnlyList<string>? additionalTextPaths = null
)
{
return Execute(sourceGenerator, GetRandomAssemblyName(), sources, additionalTextPaths);
}

/// <summary>
/// Executes and runs the specified <see cref="IIncrementalGenerator"/>.
/// </summary>
/// <param name="sourceGenerator">The SourceGenerator to execute.</param>
/// <param name="assemblyName">The assembly name.</param>
/// <param name="sources">Provide a list of sources which need to be analyzed and processed.</param>
/// <param name="additionalTextPaths">A list of additional files.</param>
/// <returns><see cref="ExecuteResult"/></returns>
public static ExecuteResult Execute(
this IIncrementalGenerator sourceGenerator,
string assemblyName,
IReadOnlyList<SourceFile> sources,
IReadOnlyList<string>? additionalTextPaths = null
)
{
return ExecuteInternal(() => CSharpGeneratorDriver.Create(sourceGenerator), assemblyName, sources, additionalTextPaths);
}

private static ExecuteResult ExecuteInternal(
Func<GeneratorDriver> driverFactory,
string assemblyName,
IReadOnlyList<SourceFile> sources,
IReadOnlyList<string>? additionalTextPaths = null
)
{
var driver = driverFactory();

var metadataReferences = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(a => MetadataReference.CreateFromFile(a.Location))
Expand All @@ -62,9 +108,7 @@ public static ExecuteResult Execute(
metadataReferences,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

var driver = CSharpGeneratorDriver
.Create(sourceGenerator)
.AddAdditionalTexts(ImmutableArray.CreateRange(additionalTexts));
driver = driver.AddAdditionalTexts(ImmutableArray.CreateRange(additionalTexts));

var executedDriver = driver.RunGeneratorsAndUpdateCompilation(
compilation,
Expand All @@ -74,8 +118,10 @@ public static ExecuteResult Execute(
return new ExecuteResult
{
GeneratorDriver = executedDriver,
WarningMessages = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Warning).Select(d => d.GetMessage()).ToList(),
ErrorMessages = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(d => d.GetMessage()).ToList(),
Diagnostics = diagnostics,
InformationMessages = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Info).Select(d => d.GetMessage()).ToArray(),
WarningMessages = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Warning).Select(d => d.GetMessage()).ToArray(),
ErrorMessages = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).Select(d => d.GetMessage()).ToArray(),
Files = outputCompilation.SyntaxTrees
.Where(st => !sources.Any(s => s.Path == st.FilePath))
.Select(st => new FileResult
Expand Down Expand Up @@ -110,7 +156,7 @@ private static SyntaxTree GetSyntaxTree(SourceFile source)
}
else
{
throw new InvalidOperationException("If AttributeToAddToClass is defined, the target must be a record or class.");
throw new InvalidOperationException("If AttributeToAddToClass is defined, the target must be a class or record.");
}
}
else if (source.AttributeToAddToInterface is not null && TryAddExtraAttribute<InterfaceDeclarationSyntax>(syntaxTree, source.AttributeToAddToInterface.Value, out var interfaceNode))
Expand Down Expand Up @@ -187,4 +233,9 @@ private static bool TryParseArguments(AnyOf<string, ExtraAttribute> attributeToA
attributeArgumentListSyntax = null;
return false;
}

private static string GetRandomAssemblyName()
{
return $"CSharp.SourceGenerators.Extensions.Generated_{Guid.NewGuid().ToString().Replace("-", "")}";
}
}
3 changes: 3 additions & 0 deletions src/FluentBuilderGenerator/AnalyzerReleases.Shipped.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; Shipped analyzer releases
; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

10 changes: 10 additions & 0 deletions src/FluentBuilderGenerator/AnalyzerReleases.Unshipped.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; Unshipped analyzer release
; https://github.com/dotnet/roslyn/blob/main/src/RoslynAnalyzers/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

### New Rules

Rule ID | Category | Severity | Notes
--------|----------|----------|-------
FBGERR0001 | FluentBuilderGenerator | Error | DiagnosticDescriptors
FBGINF0001 | FluentBuilderGenerator | Info | DiagnosticDescriptors
FBGINF0002 | FluentBuilderGenerator | Info | DiagnosticDescriptors
1 change: 1 addition & 0 deletions src/FluentBuilderGenerator/Compatibility/IsExternalInit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices;

// ReSharper disable once RedundantTypeDeclarationBody
internal class IsExternalInit { }
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace System.Diagnostics.CodeAnalysis;

/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
[AttributeUsage(AttributeTargets.Parameter)]
internal sealed class NotNullWhenAttribute : Attribute
{
/// <summary>Initializes the attribute with the specified return value condition.</summary>
Expand Down
34 changes: 34 additions & 0 deletions src/FluentBuilderGenerator/Constants/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.CodeAnalysis;

namespace FluentBuilderGenerator.Constants;

internal static class DiagnosticDescriptors
{
internal static readonly DiagnosticDescriptor Error = new(
"FBGERR0001",
"Source generator exception",
"An exception occurred during source generation: {0}",
nameof(FluentBuilderGenerator),
DiagnosticSeverity.Error,
true,
"An unhandled exception occurred while generating source code."
);

internal static readonly DiagnosticDescriptor ClassOrRecordModifierShouldBeInternalOrPublic = new(
"FBGINF0001",
"Information",
"Class or Record modifier should be 'public' or 'internal'",
nameof(FluentBuilderGenerator),
DiagnosticSeverity.Info,
true
);

internal static readonly DiagnosticDescriptor CustomBuilderClassModifierShouldBePartialAndInternalOrPublic = new(
"FBGINF0002",
"Information",
"Custom builder class should be 'partial' and 'public' or 'internal'",
nameof(FluentBuilderGenerator),
DiagnosticSeverity.Info,
true
);
}
12 changes: 12 additions & 0 deletions src/FluentBuilderGenerator/Extensions/ExceptionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using FluentBuilderGenerator.Constants;
using Microsoft.CodeAnalysis;

namespace FluentBuilderGenerator.Extensions;

internal static class ExceptionExtensions
{
internal static Diagnostic ToDiagnostic(this Exception exception)
{
return Diagnostic.Create(DiagnosticDescriptors.Error, Location.None, exception);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ internal static bool TryGetIDictionaryElementTypes(this IPropertyOrParameterSymb

if (type == FluentTypeKind.IDictionary && property.Type is INamedTypeSymbol namedTypeSymbol)
{
if (namedTypeSymbol.IsGenericType && namedTypeSymbol.TypeArguments.Length == 2)
if (namedTypeSymbol is { IsGenericType: true, TypeArguments.Length: 2 })
{
if (namedTypeSymbol.TypeArguments[0] is INamedTypeSymbol key && namedTypeSymbol.TypeArguments[1] is INamedTypeSymbol value)
{
Expand All @@ -47,7 +47,7 @@ internal static bool TryGetIDictionaryElementTypes(this IPropertyOrParameterSymb
}
}

tuple = default;
tuple = null;
return false;
}

Expand Down
Loading
Loading