diff --git a/doc/Immutable Generation.md b/doc/Immutable Generation.md index d1ea328..8f8ab16 100644 --- a/doc/Immutable Generation.md +++ b/doc/Immutable Generation.md @@ -367,11 +367,11 @@ public class MyImmutable I'm getting this error: ``` csharp -#error: 'ImmutableGenerator: Property MyClass.SomeField type ExternalClass.SuperClass is not immutable. It cannot be used in an immutable entity.' +#error: 'ImmutableGenerator: Property MyClass.SomeField (BaseClass) is not immutable. It cannot be used in an immutable entity.' ``` To fix this, put this attribute on your assembly: ``` csharp -[assembly: Uno.KnownAsImmutable(typeof(ExternalClass.SuperClass))] +[assembly: Uno.TreatAsImmutable(typeof(BaseClass))] ``` diff --git a/src/Uno.CodeGen.Tests/Given_ImmutableEntity.KnownAsImmutable.cs b/src/Uno.CodeGen.Tests/Given_ImmutableEntity.TreatAsImmutable.cs similarity index 73% rename from src/Uno.CodeGen.Tests/Given_ImmutableEntity.KnownAsImmutable.cs rename to src/Uno.CodeGen.Tests/Given_ImmutableEntity.TreatAsImmutable.cs index b4e3b19..7c8cf84 100644 --- a/src/Uno.CodeGen.Tests/Given_ImmutableEntity.KnownAsImmutable.cs +++ b/src/Uno.CodeGen.Tests/Given_ImmutableEntity.TreatAsImmutable.cs @@ -14,22 +14,23 @@ // limitations under the License. // // ****************************************************************** +using System; using System.Net.Mail; using Uno; -[assembly: KnownAsImmutable(typeof(SmtpException))] +[assembly: TreatAsImmutable(typeof(DivideByZeroException))] namespace Uno.CodeGen.Tests { partial class Given_ImmutableEntity { - internal static readonly MyImmutableWithExternalKnownAsImmutable KnownAsImmutable = - MyImmutableWithExternalKnownAsImmutable.Default; + internal static readonly MyImmutableWithExternalTreatAsImmutable TreatAsImmutable = + MyImmutableWithExternalTreatAsImmutable.Default; } [GeneratedImmutable] - internal partial class MyImmutableWithExternalKnownAsImmutable + internal partial class MyImmutableWithExternalTreatAsImmutable { - private SmtpException Exception { get; } + private DivideByZeroException Exception { get; } } } diff --git a/src/Uno.CodeGen/ImmutableGenerator.cs b/src/Uno.CodeGen/ImmutableGenerator.cs index fa3601f..07bb515 100644 --- a/src/Uno.CodeGen/ImmutableGenerator.cs +++ b/src/Uno.CodeGen/ImmutableGenerator.cs @@ -47,7 +47,7 @@ namespace Uno private INamedTypeSymbol _immutableBuilderAttributeSymbol; private INamedTypeSymbol _immutableAttributeCopyIgnoreAttributeSymbol; private INamedTypeSymbol _immutableGenerationOptionsAttributeSymbol; - private INamedTypeSymbol _immutableKnownAsImmutableAttributeSymbol; + private INamedTypeSymbol _immutableTreatAsImmutableAttributeSymbol; private (bool generateOptionCode, bool treatArrayAsImmutable, bool generateEqualityByDefault, bool generateJsonNet) _generationOptions; private bool _generateOptionCode = true; @@ -67,7 +67,7 @@ namespace Uno _immutableBuilderAttributeSymbol = context.Compilation.GetTypeByMetadataName("Uno.ImmutableBuilderAttribute"); _immutableAttributeCopyIgnoreAttributeSymbol = context.Compilation.GetTypeByMetadataName("Uno.ImmutableAttributeCopyIgnoreAttribute"); _immutableGenerationOptionsAttributeSymbol = context.Compilation.GetTypeByMetadataName("Uno.ImmutableGenerationOptionsAttribute"); - _immutableKnownAsImmutableAttributeSymbol = context.Compilation.GetTypeByMetadataName("Uno.KnownAsImmutableAttribute"); + _immutableTreatAsImmutableAttributeSymbol = context.Compilation.GetTypeByMetadataName("Uno.TreatAsImmutableAttribute"); var generationData = EnumerateImmutableGeneratedEntities() .OrderBy(x => x.symbol.Name) @@ -80,7 +80,7 @@ namespace Uno return; // nothing to do } - _knownAsImmutableTypes = EnumerateKnownAsImmutables(); + _knownAsImmutableTypes = EnumerateTreatAsImmutables(); _copyIgnoreAttributeRegexes = ExtractCopyIgnoreAttributes(context.Compilation.Assembly) @@ -835,6 +835,8 @@ $@"public sealed class {symbolName}BuilderJsonConverterTo{symbolName}{genericArg void CheckTypeImmutable(ITypeSymbol type, string typeSource, bool constraintsChecked = false) { + var typeName = (type as INamedTypeSymbol)?.GetSymbolNames().SymbolNameWithGenerics ?? type.ToString(); + if (type is ITypeParameterSymbol typeParameter) { if (typeParameter.ConstraintTypes.Any()) @@ -850,7 +852,7 @@ $@"public sealed class {symbolName}BuilderJsonConverterTo{symbolName}{genericArg else { builder.AppendLineInvariant( - $"#error {nameof(ImmutableGenerator)}: {typeSource} is of generic type {type} which isn't restricted to immutable. You can also make your class abstract."); + $"#error {nameof(ImmutableGenerator)}: {typeSource} is of generic type {typeName} which isn't restricted to immutable. You can also make your class abstract."); } return; // ok @@ -859,22 +861,24 @@ $@"public sealed class {symbolName}BuilderJsonConverterTo{symbolName}{genericArg if (type.FindAttribute(_immutableBuilderAttributeSymbol) != null) { builder.AppendLineInvariant( - $"#error {nameof(ImmutableGenerator)}: {typeSource} type {type} IS A BUILDER! It cannot be used in an immutable entity."); + $"#error {nameof(ImmutableGenerator)}: {typeSource} ({typeName}) is a builder. It cannot be used in an immutable entity."); } else if (!type.IsImmutable(_generationOptions.treatArrayAsImmutable, _knownAsImmutableTypes)) { if (type is IArrayTypeSymbol) { builder.AppendLineInvariant( - $"#error {nameof(ImmutableGenerator)}: {typeSource} type {type} is an array, which is not immutable. " - + "You can treat arrays as immutable by setting a global attribute " + $"#error {nameof(ImmutableGenerator)}: {typeSource} ({typeName}) is an array, which is not immutable. " + + "You can treat arrays as immutable by setting a global attribute: " + "[assembly: Uno.ImmutableGenerationOptions(TreatArrayAsImmutable = true)]."); } else { builder.AppendLineInvariant( - $"#error {nameof(ImmutableGenerator)}: {typeSource} type {type} is not immutable. It cannot be used in an immutable entity."); + $"#error {nameof(ImmutableGenerator)}: {typeSource} ({typeName}) not immutable. It cannot be used in an immutable entity. " + + "If you know the type can safely be used as immutable, add a global attribyte: " + + $"[assembly: Uno.TreatAsImmutable(typeof({typeName}))]"); } } @@ -963,21 +967,21 @@ $@"public sealed class {symbolName}BuilderJsonConverterTo{symbolName}{genericArg //where (bool) moduleAttribute.ConstructorArguments[0].Value select (type, moduleAttribute); - private IReadOnlyList EnumerateKnownAsImmutables() + private IReadOnlyList EnumerateTreatAsImmutables() { var currentModuleAttributes = _context.Compilation.Assembly.GetAttributes(); var referencedAssembliesAttributes = _context.Compilation.SourceModule.ReferencedAssemblySymbols.SelectMany(a => a.GetAttributes()); - var knownTypeAttributes = currentModuleAttributes + var knownToBeImmutableTypes = currentModuleAttributes .Concat(referencedAssembliesAttributes) - .Where(a => a.AttributeClass.Equals(_immutableKnownAsImmutableAttributeSymbol)) + .Where(a => a.AttributeClass.Equals(_immutableTreatAsImmutableAttributeSymbol)) .Select(a => a.ConstructorArguments[0].Value) .Cast() .Distinct() .ToImmutableArray(); - return knownTypeAttributes; + return knownToBeImmutableTypes; } } } diff --git a/src/Uno.Immutables/KnownAsImmutableAttribute.cs b/src/Uno.Immutables/TreatAsImmutableAttribute.cs similarity index 91% rename from src/Uno.Immutables/KnownAsImmutableAttribute.cs rename to src/Uno.Immutables/TreatAsImmutableAttribute.cs index f724d60..2e0f9b6 100644 --- a/src/Uno.Immutables/KnownAsImmutableAttribute.cs +++ b/src/Uno.Immutables/TreatAsImmutableAttribute.cs @@ -22,7 +22,7 @@ namespace Uno /// Define a type (usually external) as immutable /// [System.AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class KnownAsImmutableAttribute : Attribute + public sealed class TreatAsImmutableAttribute : Attribute { /// /// The type known to be immutable @@ -33,7 +33,7 @@ namespace Uno /// .ctor /// /// - public KnownAsImmutableAttribute(Type type) + public TreatAsImmutableAttribute(Type type) { Type = type; }