From d624eaff335c67fcbadc35fab2ca767b4612182b Mon Sep 17 00:00:00 2001 From: Vitor Rodrigues Date: Tue, 13 Jul 2021 01:26:03 +0200 Subject: [PATCH 1/2] Added MaybeNullAttribute to ModelsBuilder generated files The added attribute will enable consuming projects that have Nullable Reference Types enabled to receive proper warnings when access null checks aren't performed. --- .../ModelsBuilder/Building/TextBuilder.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Umbraco.Infrastructure/ModelsBuilder/Building/TextBuilder.cs b/src/Umbraco.Infrastructure/ModelsBuilder/Building/TextBuilder.cs index 9084cc902f..a5186963ab 100644 --- a/src/Umbraco.Infrastructure/ModelsBuilder/Building/TextBuilder.cs +++ b/src/Umbraco.Infrastructure/ModelsBuilder/Building/TextBuilder.cs @@ -98,6 +98,13 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building sb.AppendFormat("{0}[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"Umbraco.ModelsBuilder.Embedded\", \"{1}\")]\n", tabs, ApiVersion.Current.Version); } + // writes an attribute that specifies that an output may be null. + // (useful for consuming projects with nullable reference types enabled) + private static void WriteMaybeNullAttribute(StringBuilder sb, string tabs, bool isReturn = false) + { + sb.AppendFormat("{0}[{1}global::System.Diagnostics.CodeAnalysis.MaybeNull]\n", tabs, isReturn ? "return: " : ""); + } + private void WriteContentType(StringBuilder sb, TypeModel type) { string sep; @@ -185,9 +192,11 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building sb.AppendFormat("\t\tpublic new const PublishedItemType ModelItemType = PublishedItemType.{0};\n", itemType); WriteGeneratedCodeAttribute(sb, "\t\t"); + WriteMaybeNullAttribute(sb, "\t\t", true); sb.Append("\t\tpublic new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor)\n"); sb.Append("\t\t\t=> PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias);\n"); WriteGeneratedCodeAttribute(sb, "\t\t"); + WriteMaybeNullAttribute(sb, "\t\t", true); sb.AppendFormat("\t\tpublic static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector)\n", type.ClrName); sb.Append("\t\t\t=> PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector);\n"); @@ -305,6 +314,8 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building } WriteGeneratedCodeAttribute(sb, "\t\t"); + if (!property.ModelClrType.IsValueType) + WriteMaybeNullAttribute(sb, "\t\t"); sb.AppendFormat("\t\t[ImplementPropertyType(\"{0}\")]\n", property.Alias); if (mixinStatic) @@ -349,6 +360,8 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building sb.AppendFormat("\t\t/// Static getter for {0}\n", XmlCommentString(property.Name)); WriteGeneratedCodeAttribute(sb, "\t\t"); + if (!property.ModelClrType.IsValueType) + WriteMaybeNullAttribute(sb, "\t\t", true); sb.Append("\t\tpublic static "); WriteClrType(sb, property.ClrTypeName); sb.AppendFormat(" {0}(I{1} that, IPublishedValueFallback publishedValueFallback) => that.Value", @@ -404,6 +417,9 @@ namespace Umbraco.Cms.Infrastructure.ModelsBuilder.Building if (!string.IsNullOrWhiteSpace(property.Name)) sb.AppendFormat("\t\t/// {0}\n", XmlCommentString(property.Name)); WriteGeneratedCodeAttribute(sb, "\t\t"); + if (!property.ModelClrType.IsValueType) + WriteMaybeNullAttribute(sb, "\t\t"); + sb.Append("\t\t"); WriteClrType(sb, property.ClrTypeName); sb.AppendFormat(" {0} {{ get; }}\n", From 89e758127dd9c96b7a23ad61543f16a868886cb5 Mon Sep 17 00:00:00 2001 From: Vitor Rodrigues Date: Tue, 13 Jul 2021 10:15:03 +0200 Subject: [PATCH 2/2] Updated ModelsBuilder unit tests --- .../Umbraco.ModelsBuilder.Embedded/BuilderTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs index 346ac0239d..4dea81facb 100644 --- a/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs +++ b/src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs @@ -77,9 +77,11 @@ namespace Umbraco.Cms.Web.Common.PublishedModels [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const PublishedItemType ModelItemType = PublishedItemType.Content; [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] + [return: global::System.Diagnostics.CodeAnalysis.MaybeNull] public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor) => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias); [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] + [return: global::System.Diagnostics.CodeAnalysis.MaybeNull] public static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector) => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector); #pragma warning restore 0109 @@ -96,6 +98,7 @@ namespace Umbraco.Cms.Web.Common.PublishedModels // properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] + [global::System.Diagnostics.CodeAnalysis.MaybeNull] [ImplementPropertyType(""prop1"")] public virtual string Prop1 => this.Value(_publishedValueFallback, ""prop1""); } @@ -183,9 +186,11 @@ namespace Umbraco.Cms.Web.Common.PublishedModels [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] public new const PublishedItemType ModelItemType = PublishedItemType.Content; [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] + [return: global::System.Diagnostics.CodeAnalysis.MaybeNull] public new static IPublishedContentType GetModelContentType(IPublishedSnapshotAccessor publishedSnapshotAccessor) => PublishedModelUtility.GetModelContentType(publishedSnapshotAccessor, ModelItemType, ModelTypeAlias); [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] + [return: global::System.Diagnostics.CodeAnalysis.MaybeNull] public static IPublishedPropertyType GetModelPropertyType(IPublishedSnapshotAccessor publishedSnapshotAccessor, Expression> selector) => PublishedModelUtility.GetModelPropertyType(GetModelContentType(publishedSnapshotAccessor), selector); #pragma warning restore 0109 @@ -202,6 +207,7 @@ namespace Umbraco.Cms.Web.Common.PublishedModels // properties [global::System.CodeDom.Compiler.GeneratedCodeAttribute(""Umbraco.ModelsBuilder.Embedded"", """ + version + @""")] + [global::System.Diagnostics.CodeAnalysis.MaybeNull] [ImplementPropertyType(""foo"")] public virtual global::System.Collections.Generic.IEnumerable Foo => this.Value>(_publishedValueFallback, ""foo""); }