Vogen icon indicating copy to clipboard operation
Vogen copied to clipboard

Compilation Error - Generated code not aliased completely

Open jonmotos opened this issue 5 months ago • 3 comments

Describe the bug

I (unfortunately) have a namespace "System" in my project, that causes issues if the "System" namespace is not aliased with global:: Most places are correct, but in the implemented interfaces, the type parameters are not correctly aliased. Same with the properties, when for example the backing type is "string"

Actual:

    public partial struct ContainerFormat : global::System.IEquatable<ContainerFormat>, global::System.IEquatable<System.String>, global::System.IComparable<ContainerFormat>, global::System.IComparable
    private readonly System.String _value;

Expected:

    public partial struct ContainerFormat : global::System.IEquatable<ContainerFormat>, global::System.IEquatable<global::System.String>, global::System.IComparable<ContainerFormat>, global::System.IComparable
    private readonly global::System.String _value;

Steps to reproduce

Generate a value object with backing type string:

    [ValueObject<string>()]
    public partial struct ContainerFormat { }

Expected behaviour

All "System" namespaced types to be aliased with global::

jonmotos avatar Jul 23 '25 13:07 jonmotos

Many thanks for the bug report. I'll get around to this soon.

SteveDunn avatar Aug 01 '25 05:08 SteveDunn

Greetings,

I just stumbled across a slightly different variant of this situation when trying to declare a ValueObject on types from the Nuget API.

The following code also produces a non-compilable codebehind:

using PackageIdentity = global::NuGet.Packaging.Core.PackageIdentity;
using LicenseMetadata = global::NuGet.Packaging.LicenseMetadata;
using PackageDeprecationMetadata = global::NuGet.Protocol.PackageDeprecationMetadata;
using PackageVulnerabilityMetadata = global::NuGet.Protocol.PackageVulnerabilityMetadata;
using Vogen;

[ValueObject<ValueTuple<PackageIdentity, LicenseMetadata, Uri, PackageDeprecationMetadata, PackageVulnerabilityMetadata>>]
internal partial record class PackageMetadata
{
	public PackageIdentity Identity => Value.Item1;

	public LicenseMetadata License => Value.Item2;

	public Uri LicenseUrl => Value.Item3;

	public PackageDeprecationMetadata DeprecationMetadata => Value.Item4;

	public PackageVulnerabilityMetadata VulnerabilityMetadata => Value.Item5;

	private static Validation Validate((PackageIdentity Identity, LicenseMetadata LicenseMetadata, Uri LicenseUrl, PackageDeprecationMetadata DeprecationMetadata, PackageVulnerabilityMetadata VulnerabilityMetadata) input)
		=> input.Identity != null && input.LicenseMetadata != null
			? Validation.Ok
			: Validation.Invalid($"'{input}' is not a valid {nameof(PackageMetadata)}.");
}

and it makes no difference if namespace aliases or fully qualified type names are used.

Actual generated code:

    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "8.0.0.0")]
    [global::System.Text.Json.Serialization.JsonConverter(typeof(PackageMetadataSystemTextJsonConverter))]
    [global::System.ComponentModel.TypeConverter(typeof(PackageMetadataTypeConverter))]
    [global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(PackageMetadataDebugView))]
    [global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.ValueTuple<NuGet.Packaging.Core.PackageIdentity, NuGet.Packaging.LicenseMetadata, System.Uri, NuGet.Protocol.PackageDeprecationMetadata, NuGet.Protocol.PackageVulnerabilityMetadata>, Value = { _value }")]
    internal partial record class PackageMetadata : global::System.IEquatable<PackageMetadata>, global::System.IEquatable<System.ValueTuple<NuGet.Packaging.Core.PackageIdentity, NuGet.Packaging.LicenseMetadata, System.Uri, NuGet.Protocol.PackageDeprecationMetadata, NuGet.Protocol.PackageVulnerabilityMetadata>>, global::System.IComparable<PackageMetadata>, global::System.IComparable
    {

Expected generated code:

    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "8.0.0.0")]
    [global::System.Text.Json.Serialization.JsonConverter(typeof(PackageMetadataSystemTextJsonConverter))]
    [global::System.ComponentModel.TypeConverter(typeof(PackageMetadataTypeConverter))]
    [global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(PackageMetadataDebugView))]
    [global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.ValueTuple<NuGet.Packaging.Core.PackageIdentity, NuGet.Packaging.LicenseMetadata, System.Uri, NuGet.Protocol.PackageDeprecationMetadata, NuGet.Protocol.PackageVulnerabilityMetadata>, Value = { _value }")]
    internal partial record class PackageMetadata : global::System.IEquatable<PackageMetadata>, global::System.IEquatable<System.ValueTuple<global::NuGet.Packaging.Core.PackageIdentity, global::NuGet.Packaging.LicenseMetadata, System.Uri, global::NuGet.Protocol.PackageDeprecationMetadata, global::NuGet.Protocol.PackageVulnerabilityMetadata>>, global::System.IComparable<PackageMetadata>, global::System.IComparable
    {

P.S.: Yes, I know that this declaration stretches the concept of Value :-P - but it does nicely demonstrate the alias bug.

djo-schleupen avatar Aug 13 '25 11:08 djo-schleupen

Thanks for the feedback. I'll take a look when I get time, but I'm surprised it even partially works! :)

SteveDunn avatar Aug 27 '25 11:08 SteveDunn

This has now been fixed in the latest version

SteveDunn avatar Dec 19 '25 15:12 SteveDunn