Skip to content

Commit

Permalink
Implemented NoImplicitConversionAttribute (#56)
Browse files Browse the repository at this point in the history
Allow the user to disable implicit construction of a variant from a
value by adding the `[NoImplicitConversion]` attribute to the
`VariantOf` parameter. This also silences the warning about no implicit
conversions form interfaces or base classes.
  • Loading branch information
jvbsl authored Sep 23, 2022
1 parent 86f0d68 commit 0ca8300
Show file tree
Hide file tree
Showing 12 changed files with 1,455 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/dotVariant.Generator.Test/GeneratorTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ DiagnosticExpectation ToExpectation(Match m)
new Dictionary<string, string>()
{
{ "VariantAttribute.cs", LoadSample("VariantAttribute.cs") },
{ "NoImplicitConversionAttribute.cs", LoadSample("NoImplicitConversionAttribute.cs") },
}
.ToImmutableDictionary();
}
Expand Down
10 changes: 10 additions & 0 deletions src/dotVariant.Generator.Test/RenderInfo.Params.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ public partial class Variant
}",
ri => Assert.That(ri.Params[0].EmitImplicitCast, Is.True)
),
(
"emit no implicit cast for explicitly attributed parameters",
@"
[dotVariant.Variant]
public partial class Variant
{
static partial void VariantOf([dotVariant.NoImplicitConversion] int a);
}",
ri => Assert.That(ri.Params[0].EmitImplicitCast, Is.False)
),
(
"emit no implicit cast for base types",
@"
Expand Down
1 change: 1 addition & 0 deletions src/dotVariant.Generator.Test/SourceGenerator.Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public static IEnumerable<TestCaseData> TranslationCases()
("Variant-generic-unbounded", "Foo.Variant{T}"),
("Variant-nullable-value-type", "Foo.Variant_nullable_value_type"),
("Variant-public", "Foo.Variant_public"),
("Variant-no-implicit-conversion", "Foo.Variant_no_implicit_conversion"),
("Variant-struct-nullable-disable", "Foo.Variant_struct_nullable_disable"),
("Variant-struct-nullable-enable", "Foo.Variant_struct_nullable_enable"),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ partial class Variant1
{
static partial void VariantOf(int a, object b); // expected-warning:49 dotVariant.NoImplicitConversionForBaseClasses
}

[dotVariant.Variant]
partial class Variant2
{
static partial void VariantOf(int a, [dotVariant.NoImplicitConversion] object b);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ partial class Variant1
{
static partial void VariantOf(int a, System.Collections.IEnumerable b); // expected-warning:73 dotVariant.NoImplicitConversionForInterfaces
}

[dotVariant.Variant]
partial class Variant2
{
static partial void VariantOf(int a, [dotVariant.NoImplicitConversion] System.Collections.IEnumerable b);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

<ItemGroup>
<EmbeddedResource Include="diagnostics/**/*" />
<EmbeddedResource Include="samples/**/*" />
<EmbeddedResource Include="samples/**/*" WithCulture="false" />
<!--
Embed the support sources so we don't have a dependency on the runtime library
(which might contain generated code and fail to build while generator tests are failing)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Copyright Miro Knejp 2021.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
//

#nullable disable

namespace Foo
{
[dotVariant.Variant]
partial class Variant_no_implicit_conversion
{
static partial void VariantOf([dotVariant.NoImplicitConversion] int i, string s);
}
}
1,389 changes: 1,389 additions & 0 deletions src/dotVariant.Generator.Test/samples/Variant-no-implicit-conversion.out.cs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/dotVariant.Generator/Diagnose.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public static IEnumerable<Diagnostic> NoImplicitConversionForBaseClasses(
{
foreach (var p in options)
{
if (Inspect.IsAncestorOf(p.Type, type))
if (Inspect.IsAncestorOf(p.Type, type) && !Inspect.HasImplicitConversionDisabled(p))
{
yield return MakeWarning(
nameof(NoImplicitConversionForBaseClasses),
Expand All @@ -240,7 +240,7 @@ public static IEnumerable<Diagnostic> NoImplicitConversionForInterfaces(
{
foreach (var p in options)
{
if (p.Type.TypeKind == TypeKind.Interface)
if (p.Type.TypeKind == TypeKind.Interface && !Inspect.HasImplicitConversionDisabled(p))
{
yield return MakeWarning(
nameof(NoImplicitConversionForInterfaces),
Expand Down
6 changes: 6 additions & 0 deletions src/dotVariant.Generator/Inspect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ public static bool Implements(IParameterSymbol param, INamedTypeSymbol interface
public static int NumReferenceFields(IParameterSymbol param)
=> NumReferenceFields(param.Type);

public static bool HasImplicitConversionDisabled(IParameterSymbol param)
{
const string attributeName = nameof(dotVariant) + "." + nameof(NoImplicitConversionAttribute);
return param.GetAttributes().Any(a => a.AttributeClass?.ToDisplayString() == attributeName);
}

public static int NumReferenceFields(ITypeSymbol type)
=> type.IsReferenceType
? 1
Expand Down
2 changes: 1 addition & 1 deletion src/dotVariant.Generator/RenderInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public static RenderInfo FromDescriptor(
.Select((p, i) => new ParamInfo(
CanBeNull: CanBeNull(p, desc.NullableContext),
DiagType: p.Type.WithNullableAnnotation(p.NullableAnnotation).ToDisplayString(DiagFormat),
EmitImplicitCast: !(p.Type.TypeKind == TypeKind.Interface || IsAncestorOf(p.Type, desc.Type)),
EmitImplicitCast: !(p.Type.TypeKind == TypeKind.Interface || IsAncestorOf(p.Type, desc.Type) || HasImplicitConversionDisabled(p)),
Identifier: p.ToDisplayString(IdentifierFormat),
Index: i + 1,
IsDisposable: Implements(p, disposable),
Expand Down
16 changes: 16 additions & 0 deletions src/dotVariant.Runtime/NoImplicitConversionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Copyright Miro Knejp 2021.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
//

using System;

namespace dotVariant
{
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NoImplicitConversionAttribute : Attribute
{
public NoImplicitConversionAttribute() { }
}
}

0 comments on commit 0ca8300

Please sign in to comment.