From 5abf8d4985d9ea4f27c6f66eaf4cd2727d3cca27 Mon Sep 17 00:00:00 2001
From: halgab <24685886+halgab@users.noreply.github.com>
Date: Thu, 11 May 2023 10:09:10 +0200
Subject: [PATCH 1/2] null-annotate CodeDomSerializer
---
.../src/PublicAPI.Shipped.txt | 16 +-
.../Design/Serialization/CodeDomSerializer.cs | 197 ++++++++----------
.../Serialization/CodeDomSerializerBase.cs | 4 +-
.../LocalizationCodeDomSerializer.cs | 2 +-
4 files changed, 93 insertions(+), 126 deletions(-)
diff --git a/src/System.Windows.Forms.Design/src/PublicAPI.Shipped.txt b/src/System.Windows.Forms.Design/src/PublicAPI.Shipped.txt
index ede1767e625..3dc9119ee78 100644
--- a/src/System.Windows.Forms.Design/src/PublicAPI.Shipped.txt
+++ b/src/System.Windows.Forms.Design/src/PublicAPI.Shipped.txt
@@ -219,8 +219,8 @@
~System.ComponentModel.Design.Serialization.CodeDomComponentSerializationService.CodeDomComponentSerializationService(System.IServiceProvider provider) -> void
~System.ComponentModel.Design.Serialization.CodeDomLocalizationProvider.CodeDomLocalizationProvider(System.IServiceProvider provider, System.ComponentModel.Design.Serialization.CodeDomLocalizationModel model) -> void
~System.ComponentModel.Design.Serialization.CodeDomLocalizationProvider.CodeDomLocalizationProvider(System.IServiceProvider provider, System.ComponentModel.Design.Serialization.CodeDomLocalizationModel model, System.Globalization.CultureInfo[] supportedCultures) -> void
-~System.ComponentModel.Design.Serialization.CodeDomSerializer.DeserializeStatementToInstance(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, System.CodeDom.CodeStatement statement) -> object
-~System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeToReferenceExpression(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, object value) -> System.CodeDom.CodeExpression
+System.ComponentModel.Design.Serialization.CodeDomSerializer.DeserializeStatementToInstance(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, System.CodeDom.CodeStatement! statement) -> object?
+System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeToReferenceExpression(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, object! value) -> System.CodeDom.CodeExpression?
~System.ComponentModel.Design.Serialization.CodeDomSerializerException.CodeDomSerializerException(string message, System.CodeDom.CodeLinePragma linePragma) -> void
~System.ComponentModel.Design.Serialization.CodeDomSerializerException.CodeDomSerializerException(string message, System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager) -> void
~System.ComponentModel.Design.Serialization.CodeDomSerializerException.CodeDomSerializerException(System.Exception ex, System.CodeDom.CodeLinePragma linePragma) -> void
@@ -420,13 +420,13 @@
~virtual System.ComponentModel.Design.Serialization.BasicDesignerLoader.OnEndLoad(bool successful, System.Collections.ICollection errors) -> void
~virtual System.ComponentModel.Design.Serialization.BasicDesignerLoader.ReportFlushErrors(System.Collections.ICollection errors) -> void
~virtual System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.OnComponentRename(object component, string oldName, string newName) -> void
-~virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.Deserialize(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, object codeObject) -> object
-~virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.GetTargetComponentName(System.CodeDom.CodeStatement statement, System.CodeDom.CodeExpression expression, System.Type targetType) -> string
-~virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.Serialize(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, object value) -> object
-~virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeAbsolute(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, object value) -> object
-~virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeMember(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, object owningObject, System.ComponentModel.MemberDescriptor member) -> System.CodeDom.CodeStatementCollection
-~virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeMemberAbsolute(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, object owningObject, System.ComponentModel.MemberDescriptor member) -> System.CodeDom.CodeStatementCollection
~virtual System.ComponentModel.Design.Serialization.CollectionCodeDomSerializer.SerializeCollection(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, System.CodeDom.CodeExpression targetExpression, System.Type targetType, System.Collections.ICollection originalCollection, System.Collections.ICollection valuesToSerialize) -> object
+virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.Deserialize(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, object! codeObject) -> object?
+virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.GetTargetComponentName(System.CodeDom.CodeStatement? statement, System.CodeDom.CodeExpression? expression, System.Type? targetType) -> string?
+virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.Serialize(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, object! value) -> object?
+virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeAbsolute(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, object! value) -> object?
+virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeMember(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, object! owningObject, System.ComponentModel.MemberDescriptor! member) -> System.CodeDom.CodeStatementCollection!
+virtual System.ComponentModel.Design.Serialization.CodeDomSerializer.SerializeMemberAbsolute(System.ComponentModel.Design.Serialization.IDesignerSerializationManager! manager, object! owningObject, System.ComponentModel.MemberDescriptor! member) -> System.CodeDom.CodeStatementCollection!
~virtual System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.Deserialize(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, System.CodeDom.CodeTypeDeclaration declaration) -> object
~virtual System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.GetInitializeMethod(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, System.CodeDom.CodeTypeDeclaration declaration, object value) -> System.CodeDom.CodeMemberMethod
~virtual System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.GetInitializeMethods(System.ComponentModel.Design.Serialization.IDesignerSerializationManager manager, System.CodeDom.CodeTypeDeclaration declaration) -> System.CodeDom.CodeMemberMethod[]
diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializer.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializer.cs
index c493c62953e..be3e49ccca4 100644
--- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializer.cs
+++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializer.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#nullable disable
-
using System.CodeDom;
namespace System.ComponentModel.Design.Serialization;
@@ -15,20 +13,13 @@ namespace System.ComponentModel.Design.Serialization;
[DefaultSerializationProvider(typeof(CodeDomSerializationProvider))]
public class CodeDomSerializer : CodeDomSerializerBase
{
- private static CodeDomSerializer s_default;
- private static readonly Attribute[] _runTimeFilter = new Attribute[] { DesignOnlyAttribute.No };
- private static readonly Attribute[] _designTimeFilter = new Attribute[] { DesignOnlyAttribute.Yes };
- private static readonly CodeThisReferenceExpression _thisRef = new();
-
- internal static CodeDomSerializer Default
- {
- get
- {
- s_default ??= new CodeDomSerializer();
+ private static CodeDomSerializer? s_default;
+ private static readonly Attribute[] s_runTimeFilter = { DesignOnlyAttribute.No };
+ private static readonly Attribute[] s_designTimeFilter = { DesignOnlyAttribute.Yes };
+ private static readonly Attribute[] s_deserializeFilter = { BrowsableAttribute.Yes };
+ private static readonly CodeThisReferenceExpression s_thisRef = new();
- return s_default;
- }
- }
+ internal static CodeDomSerializer Default => s_default ??= new CodeDomSerializer();
///
/// Determines which statement group the given statement should belong to. The expression parameter
@@ -36,19 +27,14 @@ internal static CodeDomSerializer Default
/// of this statement. This method returns the name of the component this statement should be grouped
/// with.
///
- public virtual string GetTargetComponentName(CodeStatement statement, CodeExpression expression, Type targetType)
+ public virtual string? GetTargetComponentName(CodeStatement? statement, CodeExpression? expression, Type? targetType)
{
- string name = null;
- if (expression is CodeVariableReferenceExpression variableReferenceEx)
+ return expression switch
{
- name = variableReferenceEx.VariableName;
- }
- else if (expression is CodeFieldReferenceExpression fieldReferenceEx)
- {
- name = fieldReferenceEx.FieldName;
- }
-
- return name;
+ CodeVariableReferenceExpression variableReferenceEx => variableReferenceEx.VariableName,
+ CodeFieldReferenceExpression fieldReferenceEx => fieldReferenceEx.FieldName,
+ _ => null,
+ };
}
///
@@ -56,9 +42,9 @@ public virtual string GetTargetComponentName(CodeStatement statement, CodeExpres
/// will use the serialization manager to create objects and resolve
/// data types. The root of the object graph is returned.
///
- public virtual object Deserialize(IDesignerSerializationManager manager, object codeObject)
+ public virtual object? Deserialize(IDesignerSerializationManager manager, object codeObject)
{
- object instance = null;
+ object? instance = null;
ArgumentNullException.ThrowIfNull(manager);
ArgumentNullException.ThrowIfNull(codeObject);
@@ -69,46 +55,40 @@ public virtual object Deserialize(IDesignerSerializationManager manager, object
{
instance = DeserializeExpression(manager, null, expression);
}
- else
+ else if (codeObject is CodeStatementCollection statements)
{
- if (codeObject is CodeStatementCollection statements)
+ foreach (CodeStatement element in statements)
{
- foreach (CodeStatement element in statements)
+ // If we do not yet have an instance, we will need to pick through the statements and see if we can find one.
+ if (instance is null)
{
- // If we do not yet have an instance, we will need to pick through the statements and see if we can find one.
- if (instance is null)
+ instance = DeserializeStatementToInstance(manager, element);
+ if (instance is not null)
{
- instance = DeserializeStatementToInstance(manager, element);
- if (instance is not null)
+ PropertyDescriptorCollection props = TypeDescriptor.GetProperties(instance, s_deserializeFilter);
+ foreach (PropertyDescriptor prop in props)
{
- PropertyDescriptorCollection props = TypeDescriptor.GetProperties(instance, new Attribute[] { BrowsableAttribute.Yes });
- foreach (PropertyDescriptor prop in props)
+ if (!prop.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden) &&
+ prop.Attributes.Contains(DesignerSerializationVisibilityAttribute.Content) &&
+ manager.GetSerializer(prop.PropertyType, typeof(CodeDomSerializer)) is not CollectionCodeDomSerializer)
{
- if (!prop.Attributes.Contains(DesignerSerializationVisibilityAttribute.Hidden) &&
- prop.Attributes.Contains(DesignerSerializationVisibilityAttribute.Content) &&
- !(manager.GetSerializer(prop.PropertyType, typeof(CodeDomSerializer)) is CollectionCodeDomSerializer))
- {
- ResetBrowsableProperties(prop.GetValue(instance));
- }
+ ResetBrowsableProperties(prop.GetValue(instance));
}
}
}
- else
- {
- DeserializeStatement(manager, element);
- }
}
- }
- else
- {
- if (!(codeObject is CodeStatement statement))
+ else
{
- Debug.Fail("CodeDomSerializer::Deserialize requires a CodeExpression, CodeStatement or CodeStatementCollection to parse");
- string supportedTypes = $"{nameof(CodeExpression)}, {nameof(CodeStatement)}, {nameof(CodeStatementCollection)}";
- throw new ArgumentException(string.Format(SR.SerializerBadElementTypes, codeObject.GetType().Name, supportedTypes));
+ DeserializeStatement(manager, element);
}
}
}
+ else if (codeObject is not CodeStatement)
+ {
+ Debug.Fail("CodeDomSerializer::Deserialize requires a CodeExpression, CodeStatement or CodeStatementCollection to parse");
+ string supportedTypes = $"{nameof(CodeExpression)}, {nameof(CodeStatement)}, {nameof(CodeStatementCollection)}";
+ throw new ArgumentException(string.Format(SR.SerializerBadElementTypes, codeObject.GetType().Name, supportedTypes));
+ }
}
return instance;
@@ -120,9 +100,9 @@ public virtual object Deserialize(IDesignerSerializationManager manager, object
/// resulting statement was a variable assign statement, a variable
/// declaration with an init expression, or a field assign statement.
///
- protected object DeserializeStatementToInstance(IDesignerSerializationManager manager, CodeStatement statement)
+ protected object? DeserializeStatementToInstance(IDesignerSerializationManager manager, CodeStatement statement)
{
- object instance = null;
+ object? instance = null;
if (statement is CodeAssignStatement assign)
{
if (assign.Left is CodeFieldReferenceExpression fieldRef)
@@ -130,20 +110,17 @@ protected object DeserializeStatementToInstance(IDesignerSerializationManager ma
Trace(TraceLevel.Verbose, $"Assigning instance to field {fieldRef.FieldName}");
instance = DeserializeExpression(manager, fieldRef.FieldName, assign.Right);
}
+ else if (assign.Left is CodeVariableReferenceExpression varRef)
+ {
+ Trace(TraceLevel.Verbose, $"Assigning instance to variable {varRef.VariableName}");
+ instance = DeserializeExpression(manager, varRef.VariableName, assign.Right);
+ }
else
{
- if (assign.Left is CodeVariableReferenceExpression varRef)
- {
- Trace(TraceLevel.Verbose, $"Assigning instance to variable {varRef.VariableName}");
- instance = DeserializeExpression(manager, varRef.VariableName, assign.Right);
- }
- else
- {
- DeserializeStatement(manager, assign);
- }
+ DeserializeStatement(manager, assign);
}
}
- else if (statement is CodeVariableDeclarationStatement varDecl && varDecl.InitExpression is not null)
+ else if (statement is CodeVariableDeclarationStatement { InitExpression: not null } varDecl)
{
Trace(TraceLevel.Verbose, $"Initializing variable declaration for variable {varDecl.Name}");
instance = DeserializeExpression(manager, varDecl.Name, varDecl.InitExpression);
@@ -160,9 +137,9 @@ protected object DeserializeStatementToInstance(IDesignerSerializationManager ma
///
/// Serializes the given object into a CodeDom object.
///
- public virtual object Serialize(IDesignerSerializationManager manager, object value)
+ public virtual object? Serialize(IDesignerSerializationManager manager, object value)
{
- object result = null;
+ object? result = null;
ArgumentNullException.ThrowIfNull(manager);
ArgumentNullException.ThrowIfNull(value);
@@ -170,31 +147,20 @@ public virtual object Serialize(IDesignerSerializationManager manager, object va
{
Trace(TraceLevel.Verbose, $"Type: {value.GetType().Name}");
- if (value is Type)
+ if (value is Type type)
{
- result = new CodeTypeOfExpression((Type)value);
+ result = new CodeTypeOfExpression(type);
}
else
{
bool isComplete = false;
- bool isPreset;
- CodeExpression expression = SerializeCreationExpression(manager, value, out bool isCompleteExpression);
+ CodeExpression? expression = SerializeCreationExpression(manager, value, out bool isCompleteExpression);
// if the object is not a component we will honor the return value from SerializeCreationExpression. For compat reasons we ignore the value if the object is a component.
- if (!(value is IComponent))
+ if (value is not IComponent)
{
isComplete = isCompleteExpression;
}
- // We need to find out if SerializeCreationExpression returned a preset expression.
- if (manager.Context[typeof(ExpressionContext)] is ExpressionContext ctx && ReferenceEquals(ctx.PresetValue, value))
- {
- isPreset = true;
- }
- else
- {
- isPreset = false;
- }
-
TraceIf(TraceLevel.Verbose, expression is null, "Unable to create object; aborting.");
// Short circuit common cases
if (expression is not null)
@@ -209,28 +175,30 @@ public virtual object Serialize(IDesignerSerializationManager manager, object va
// Ok, we have an incomplete expression. That means we've created the object but we will need to set properties on it to configure it. Therefore, we need to have a variable reference to it unless we were given a preset expression already.
CodeStatementCollection statements = new CodeStatementCollection();
+ // We need to find out if SerializeCreationExpression returned a preset expression.
+ bool isPreset = manager.TryGetContext(out ExpressionContext? ctx) && ReferenceEquals(ctx.PresetValue, value);
+
if (isPreset)
{
SetExpression(manager, value, expression, true);
}
else
{
- CodeExpression variableReference;
string varName = GetUniqueName(manager, value);
- string varTypeName = TypeDescriptor.GetClassName(value);
+ string? varTypeName = TypeDescriptor.GetClassName(value);
- CodeVariableDeclarationStatement varDecl = new CodeVariableDeclarationStatement(varTypeName, varName);
+ CodeVariableDeclarationStatement varDecl = new CodeVariableDeclarationStatement(varTypeName!, varName);
Trace(TraceLevel.Verbose, $"Generating local : {varName}");
varDecl.InitExpression = expression;
statements.Add(varDecl);
- variableReference = new CodeVariableReferenceExpression(varName);
+ CodeExpression variableReference = new CodeVariableReferenceExpression(varName);
SetExpression(manager, value, variableReference);
}
// Finally, we need to walk properties and events for this object
- SerializePropertiesToResources(manager, statements, value, _designTimeFilter);
- SerializeProperties(manager, statements, value, _runTimeFilter);
- SerializeEvents(manager, statements, value, _runTimeFilter);
+ SerializePropertiesToResources(manager, statements, value, s_designTimeFilter);
+ SerializeProperties(manager, statements, value, s_runTimeFilter);
+ SerializeEvents(manager, statements, value, s_runTimeFilter);
result = statements;
}
}
@@ -243,9 +211,9 @@ public virtual object Serialize(IDesignerSerializationManager manager, object va
///
/// Serializes the given object into a CodeDom object.
///
- public virtual object SerializeAbsolute(IDesignerSerializationManager manager, object value)
+ public virtual object? SerializeAbsolute(IDesignerSerializationManager manager, object value)
{
- object data;
+ object? data;
SerializeAbsoluteContext abs = new SerializeAbsoluteContext();
manager.Context.Push(abs);
try
@@ -272,7 +240,7 @@ public virtual CodeStatementCollection SerializeMember(IDesignerSerializationMan
CodeStatementCollection statements = new CodeStatementCollection();
// See if we have an existing expression for this member. If not, fabricate one
- CodeExpression expression = GetExpression(manager, owningObject);
+ CodeExpression? expression = GetExpression(manager, owningObject);
if (expression is null)
{
string name = GetUniqueName(manager, owningObject);
@@ -284,16 +252,13 @@ public virtual CodeStatementCollection SerializeMember(IDesignerSerializationMan
{
SerializeProperty(manager, statements, owningObject, property);
}
+ else if (member is EventDescriptor evt)
+ {
+ SerializeEvent(manager, statements, owningObject, evt);
+ }
else
{
- if (member is EventDescriptor evt)
- {
- SerializeEvent(manager, statements, owningObject, evt);
- }
- else
- {
- throw new NotSupportedException(string.Format(SR.SerializerMemberTypeNotSerializable, member.GetType().FullName));
- }
+ throw new NotSupportedException(string.Format(SR.SerializerMemberTypeNotSerializable, member.GetType().FullName));
}
return statements;
@@ -333,9 +298,9 @@ public virtual CodeStatementCollection SerializeMemberAbsolute(IDesignerSerializ
/// of a statement.
///
[Obsolete("This method has been deprecated. Use SerializeToExpression or GetExpression instead. https://go.microsoft.com/fwlink/?linkid=14202")]
- protected CodeExpression SerializeToReferenceExpression(IDesignerSerializationManager manager, object value)
+ protected CodeExpression? SerializeToReferenceExpression(IDesignerSerializationManager manager, object value)
{
- CodeExpression expression = null;
+ CodeExpression? expression = null;
using (TraceScope($"CodeDomSerializer::{nameof(SerializeToReferenceExpression)}"))
{
// First - try GetExpression
@@ -343,11 +308,11 @@ protected CodeExpression SerializeToReferenceExpression(IDesignerSerializationMa
// Next, we check for a named IComponent, and return a reference to it.
if (expression is null && value is IComponent)
{
- string name = manager.GetName(value);
+ string? name = manager.GetName(value);
bool referenceName = false;
if (name is null)
{
- IReferenceService referenceService = (IReferenceService)manager.GetService(typeof(IReferenceService));
+ IReferenceService? referenceService = manager.GetService();
if (referenceService is not null)
{
name = referenceService.GetName(value);
@@ -359,20 +324,22 @@ protected CodeExpression SerializeToReferenceExpression(IDesignerSerializationMa
{
Trace(TraceLevel.Verbose, $"Object is reference ({name}) Creating reference expression");
// Check to see if this is a reference to the root component. If it is, then use "this".
- RootContext root = (RootContext)manager.Context[typeof(RootContext)];
- if (root is not null && root.Value == value)
+ if (manager.TryGetContext(out RootContext? root) && root.Value == value)
{
expression = root.Expression;
}
- else if (referenceName && name.IndexOf('.') != -1)
- {
- // if it's a reference name with a dot, we've actually got a property here...
- int dotIndex = name.IndexOf('.');
- expression = new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(_thisRef, name.Substring(0, dotIndex)), name.Substring(dotIndex + 1));
- }
else
{
- expression = new CodeFieldReferenceExpression(_thisRef, name);
+ int dotIndex = name.IndexOf('.');
+ if (referenceName && dotIndex != -1)
+ {
+ // if it's a reference name with a dot, we've actually got a property here...
+ expression = new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(s_thisRef, name.Substring(0, dotIndex)), name.Substring(dotIndex + 1));
+ }
+ else
+ {
+ expression = new CodeFieldReferenceExpression(s_thisRef, name);
+ }
}
}
}
@@ -381,7 +348,7 @@ protected CodeExpression SerializeToReferenceExpression(IDesignerSerializationMa
return expression;
}
- private static void ResetBrowsableProperties(object instance)
+ private static void ResetBrowsableProperties(object? instance)
{
if (instance is null)
{
diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializerBase.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializerBase.cs
index 5b8607abb4f..01ec4fb4299 100644
--- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializerBase.cs
+++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/CodeDomSerializerBase.cs
@@ -581,7 +581,7 @@ private void DeserializeAssignStatement(IDesignerSerializationManager manager, C
{
// Since we're doing an assignment into something, we need to know what that something is. It can be a property, a variable, or a member. Anything else is invalid.
//Perf: is -> as changes, change ordering based on possibility of occurrence
- CodeExpression? expression = statement.Left;
+ CodeExpression expression = statement.Left;
Trace(TraceLevel.Verbose, "Processing LHS");
if (expression is CodePropertyReferenceExpression propertyReferenceEx)
@@ -2574,7 +2574,7 @@ protected void SerializeResourceInvariant(IDesignerSerializationManager manager,
object? result = null;
try
{
- result = serializer.Serialize(manager, value);
+ result = serializer.Serialize(manager, value!);
}
finally
{
diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/LocalizationCodeDomSerializer.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/LocalizationCodeDomSerializer.cs
index 9b3869f6755..8a8502950bb 100644
--- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/LocalizationCodeDomSerializer.cs
+++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/LocalizationCodeDomSerializer.cs
@@ -147,7 +147,7 @@ private static bool EmitApplyMethod(IDesignerSerializationManager manager, objec
}
return callExistingSerializer
- ? _currentSerializer?.Serialize(manager, value)
+ ? _currentSerializer?.Serialize(manager, value!)
: SerializeToResourceExpression(manager, value);
}
From bfd19e13bd89c501ea3fc61ef25d3eb3c706301d Mon Sep 17 00:00:00 2001
From: halgab <24685886+halgab@users.noreply.github.com>
Date: Fri, 12 May 2023 10:46:15 +0200
Subject: [PATCH 2/2] annotate ResourceCodeDomSerializer
---
.../ResourceCodeDomSerializer.cs | 155 +++++++-----------
1 file changed, 60 insertions(+), 95 deletions(-)
diff --git a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ResourceCodeDomSerializer.cs b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ResourceCodeDomSerializer.cs
index db4087a10e8..eef5d571340 100644
--- a/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ResourceCodeDomSerializer.cs
+++ b/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/Serialization/ResourceCodeDomSerializer.cs
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#nullable disable
-
using System.CodeDom;
using System.Collections;
using System.Globalization;
@@ -25,42 +23,27 @@ namespace System.ComponentModel.Design.Serialization;
///
internal partial class ResourceCodeDomSerializer : CodeDomSerializer
{
- private static ResourceCodeDomSerializer s_defaultSerializer;
+ private static ResourceCodeDomSerializer? s_defaultSerializer;
///
/// Retrieves a default static instance of this serializer.
///
- internal static new ResourceCodeDomSerializer Default
- {
- get
- {
- s_defaultSerializer ??= new ResourceCodeDomSerializer();
+ internal static new ResourceCodeDomSerializer Default => s_defaultSerializer ??= new ResourceCodeDomSerializer();
- return s_defaultSerializer;
- }
- }
-
- public override string GetTargetComponentName(CodeStatement statement, CodeExpression expression, Type type)
+ public override string? GetTargetComponentName(CodeStatement? statement, CodeExpression? expression, Type? type)
{
- string name = null;
- if (statement is CodeExpressionStatement expStatement)
+ string? name = null;
+ if (statement is CodeExpressionStatement { Expression: CodeMethodInvokeExpression methodInvokeEx })
{
- if (expStatement.Expression is CodeMethodInvokeExpression methodInvokeEx)
+ if (string.Equals(methodInvokeEx.Method?.MethodName, "ApplyResources", StringComparison.OrdinalIgnoreCase))
{
- if (methodInvokeEx.Method is CodeMethodReferenceExpression methodReferenceEx &&
- string.Equals(methodReferenceEx.MethodName, "ApplyResources", StringComparison.OrdinalIgnoreCase) &&
- methodInvokeEx.Parameters.Count > 0)
+ name = methodInvokeEx.Parameters switch
{
// We've found a call to the ApplyResources method on a ComponentResourceManager object. now we just need to figure out which component ApplyResources is being called for, and put it into that component's bucket.
- if (methodInvokeEx.Parameters[0] is CodeFieldReferenceExpression fieldReferenceEx && fieldReferenceEx.TargetObject is CodeThisReferenceExpression)
- {
- name = fieldReferenceEx.FieldName;
- }
- else if (methodInvokeEx.Parameters[0] is CodeVariableReferenceExpression variableReferenceEx)
- {
- name = variableReferenceEx.VariableName;
- }
- }
+ [CodeFieldReferenceExpression { TargetObject: CodeThisReferenceExpression } fieldReferenceEx, ..] => fieldReferenceEx.FieldName,
+ [CodeVariableReferenceExpression variableReferenceEx, ..] => variableReferenceEx.VariableName,
+ _ => null
+ };
}
}
@@ -75,17 +58,14 @@ public override string GetTargetComponentName(CodeStatement statement, CodeExpre
///
/// This is the name of the resource manager object we declare on the component surface.
///
- private static string ResourceManagerName
- {
- get => "resources";
- }
+ private const string ResourceManagerName = "resources";
///
/// Deserializes the given CodeDom object into a real object. This will use the serialization manager to create objects and resolve data types. The root of the object graph is returned.
///
- public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
+ public override object? Deserialize(IDesignerSerializationManager manager, object codeObject)
{
- object instance = null;
+ object? instance = null;
ArgumentNullException.ThrowIfNull(manager);
ArgumentNullException.ThrowIfNull(codeObject);
@@ -97,44 +77,38 @@ public override object Deserialize(IDesignerSerializationManager manager, object
{
instance = DeserializeExpression(manager, null, expression);
}
- else
+ else if (codeObject is CodeStatementCollection statements)
{
- if (codeObject is CodeStatementCollection statements)
+ foreach (CodeStatement element in statements)
{
- foreach (CodeStatement element in statements)
+ // We create the resource manager ourselves here because it's not just a straight parse of the code. Do special parsing of the resources statement
+ if (element is CodeVariableDeclarationStatement statement)
{
- // We create the resource manager ourselves here because it's not just a straight parse of the code. Do special parsing of the resources statement
- if (element is CodeVariableDeclarationStatement statement)
+ TraceIf(TraceLevel.Warning, !statement.Name.Equals(ResourceManagerName), "WARNING: Resource manager serializer being invoked to deserialize a collection we didn't create.");
+ if (statement.Name.Equals(ResourceManagerName))
{
- TraceIf(TraceLevel.Warning, !statement.Name.Equals(ResourceManagerName), "WARNING: Resource manager serializer being invoked to deserialize a collection we didn't create.");
- if (statement.Name.Equals(ResourceManagerName))
- {
- instance = CreateResourceManager(manager);
- }
+ instance = CreateResourceManager(manager);
+ }
+ }
+ else
+ {
+ // If we do not yet have an instance, we will need to pick through the statements and see if we can find one.
+ if (instance is null)
+ {
+ instance = DeserializeStatementToInstance(manager, element);
}
else
{
- // If we do not yet have an instance, we will need to pick through the statements and see if we can find one.
- if (instance is null)
- {
- instance = DeserializeStatementToInstance(manager, element);
- }
- else
- {
- DeserializeStatement(manager, element);
- }
+ DeserializeStatement(manager, element);
}
}
}
- else
- {
- if (!(codeObject is CodeStatement statement))
- {
- Debug.Fail("ResourceCodeDomSerializer::Deserialize requires a CodeExpression, CodeStatement or CodeStatementCollection to parse");
- string supportedTypes = $"{nameof(CodeExpression)}, {nameof(CodeStatement)}, {nameof(CodeStatementCollection)}";
- throw new ArgumentException(string.Format(SR.SerializerBadElementTypes, codeObject.GetType().Name, supportedTypes));
- }
- }
+ }
+ else if (codeObject is not CodeStatement)
+ {
+ Debug.Fail("ResourceCodeDomSerializer::Deserialize requires a CodeExpression, CodeStatement or CodeStatementCollection to parse");
+ string supportedTypes = $"{nameof(CodeExpression)}, {nameof(CodeStatement)}, {nameof(CodeStatementCollection)}";
+ throw new ArgumentException(string.Format(SR.SerializerBadElementTypes, codeObject.GetType().Name, supportedTypes));
}
}
@@ -158,7 +132,7 @@ private static SerializationResourceManager CreateResourceManager(IDesignerSeria
///
/// This method is invoked during deserialization to obtain an instance of an object. When this is called, an instance of the requested type should be returned. Our implementation provides a design time resource manager.
///
- protected override object DeserializeInstance(IDesignerSerializationManager manager, Type type, object[] parameters, string name, bool addToContainer)
+ protected override object DeserializeInstance(IDesignerSerializationManager manager, Type type, object?[]? parameters, string? name, bool addToContainer)
{
ArgumentNullException.ThrowIfNull(manager);
ArgumentNullException.ThrowIfNull(type);
@@ -177,7 +151,7 @@ protected override object DeserializeInstance(IDesignerSerializationManager mana
///
/// Deserializes the given CodeDom object into a real object. This will use the serialization manager to create objects and resolve data types. It uses the invariant resource blob to obtain resources.
///
- public static object DeserializeInvariant(IDesignerSerializationManager manager, string resourceName)
+ public static object? DeserializeInvariant(IDesignerSerializationManager manager, string resourceName)
{
SerializationResourceManager resources = GetResourceManager(manager);
return resources.GetObject(resourceName, true);
@@ -186,11 +160,11 @@ public static object DeserializeInvariant(IDesignerSerializationManager manager,
///
/// Try to discover the data type we should apply a cast for. To do this, we first search the context stack for an ExpressionContext to decrypt, and if we fail that we try the actual object. If we can't find a cast type we return null.
///
- private static Type GetCastType(IDesignerSerializationManager manager, object value)
+ [return: NotNullIfNotNull(nameof(value))]
+ private static Type? GetCastType(IDesignerSerializationManager manager, object? value)
{
// Is there an ExpressionContext we can work with?
- ExpressionContext tree = (ExpressionContext)manager.Context[typeof(ExpressionContext)];
- if (tree is not null)
+ if (manager.TryGetContext(out ExpressionContext? tree))
{
return tree.ExpressionType;
}
@@ -201,7 +175,7 @@ private static Type GetCastType(IDesignerSerializationManager manager, object va
Type castTo = value.GetType();
while (!castTo.IsPublic && !castTo.IsNestedPublic)
{
- castTo = castTo.BaseType;
+ castTo = castTo.BaseType!;
}
return castTo;
@@ -215,7 +189,7 @@ private static Type GetCastType(IDesignerSerializationManager manager, object va
///
/// Retrieves a dictionary enumerator for the requested culture, or null if no resources for that culture exist.
///
- public static IDictionaryEnumerator GetEnumerator(IDesignerSerializationManager manager, CultureInfo culture)
+ public static IDictionaryEnumerator? GetEnumerator(IDesignerSerializationManager manager, CultureInfo culture)
{
SerializationResourceManager resources = GetResourceManager(manager);
return resources.GetEnumerator(culture);
@@ -224,7 +198,7 @@ public static IDictionaryEnumerator GetEnumerator(IDesignerSerializationManager
///
/// Retrieves a dictionary enumerator for the requested culture, or null if no resources for that culture exist.
///
- public static IDictionaryEnumerator GetMetadataEnumerator(IDesignerSerializationManager manager)
+ public static IDictionaryEnumerator? GetMetadataEnumerator(IDesignerSerializationManager manager)
{
SerializationResourceManager resources = GetResourceManager(manager);
return resources.GetMetadataEnumerator();
@@ -235,7 +209,7 @@ public static IDictionaryEnumerator GetMetadataEnumerator(IDesignerSerialization
///
private static SerializationResourceManager GetResourceManager(IDesignerSerializationManager manager)
{
- if (!(manager.Context[typeof(SerializationResourceManager)] is SerializationResourceManager sm))
+ if (!manager.TryGetContext(out SerializationResourceManager? sm))
{
sm = new SerializationResourceManager(manager);
manager.Context.Append(sm);
@@ -265,7 +239,7 @@ public object Serialize(IDesignerSerializationManager manager, object value, boo
///
/// Serializes the given object into a CodeDom object. This expects the following values to be available on the context stack: A CodeStatementCollection that we can add our resource declaration to, if necessary. An ExpressionContext that contains the property, field or method that is being serialized, along with the object being serialized. We need this so we can create a unique resource name for the object.
///
- public object Serialize(IDesignerSerializationManager manager, object value, bool shouldSerializeInvariant, bool ensureInvariant)
+ public object Serialize(IDesignerSerializationManager manager, object? value, bool shouldSerializeInvariant, bool ensureInvariant)
{
return Serialize(manager, value, false, shouldSerializeInvariant, ensureInvariant);
}
@@ -273,16 +247,15 @@ public object Serialize(IDesignerSerializationManager manager, object value, boo
///
/// This performs the actual work of serialization between Serialize and SerializeInvariant.
///
- private object Serialize(IDesignerSerializationManager manager, object value, bool forceInvariant, bool shouldSerializeInvariant, bool ensureInvariant)
+ private object Serialize(IDesignerSerializationManager manager, object? value, bool forceInvariant, bool shouldSerializeInvariant, bool ensureInvariant)
{
- CodeExpression expression = null;
using (TraceScope("ResourceCodeDomSerializer::Serialize"))
{
// Resource serialization is a little inconsistent. We deserialize our own resource manager creation statement, but we will never be asked to serialize a resource manager, because it doesn't exist as a product of the design container; it is purely an artifact of serializing. Some not-so-obvious side effects of this are:
// This method will never ever be called by the serialization system directly. There is no attribute or metadata that will invoke it. Instead, other serializers will call this method to see if we should serialize to resources.
// We need a way to inject the local variable declaration into the method body for the resource manager if we actually do emit a resource, which we shove into the statements collection.
SerializationResourceManager sm = GetResourceManager(manager);
- CodeStatementCollection statements = (CodeStatementCollection)manager.Context[typeof(CodeStatementCollection)];
+ CodeStatementCollection? statements = manager.GetContext();
// If this serialization resource manager has never been used to output culture-sensitive statements, then we must emit the local variable hookup. Culture invariant statements are used to save random data that is not representable in code, so there is no need to emit a declaration.
if (!forceInvariant)
{
@@ -294,10 +267,10 @@ private object Serialize(IDesignerSerializationManager manager, object value, bo
if (statements is not null)
{
CodeExpression[] parameters;
- if (manager.Context[typeof(RootContext)] is RootContext rootCtx)
+ if (manager.TryGetContext(out RootContext? rootCtx))
{
- string baseType = manager.GetName(rootCtx.Value);
- parameters = new CodeExpression[] { new CodeTypeOfExpression(baseType) };
+ string? baseType = manager.GetName(rootCtx.Value);
+ parameters = new CodeExpression[] { new CodeTypeOfExpression(baseType!) };
}
else
{
@@ -327,7 +300,7 @@ private object Serialize(IDesignerSerializationManager manager, object value, bo
}
// Retrieve the ExpressionContext on the context stack, and save the value as a resource.
- ExpressionContext tree = (ExpressionContext)manager.Context[typeof(ExpressionContext)];
+ ExpressionContext? tree = manager.GetContext();
TraceIf(TraceLevel.Warning, tree is null, "No ExpressionContext on stack. We can serialize, but we cannot create a well-formed name.");
string resourceName = sm.SetValue(manager, tree, value, forceInvariant, shouldSerializeInvariant, ensureInvariant, false);
// Now the next step is to discover the type of the given value. If it is a string, we will invoke "GetString" Otherwise, we will invoke "GetObject" and supply a cast to the proper value.
@@ -354,24 +327,16 @@ private object Serialize(IDesignerSerializationManager manager, object value, bo
methodInvoke.Parameters.Add(new CodePrimitiveExpression(resourceName));
if (needCast)
{
- Type castTo = GetCastType(manager, value);
+ Type? castTo = GetCastType(manager, value);
if (castTo is not null)
{
Trace(TraceLevel.Verbose, $"Supplying cast to {castTo.Name}");
- expression = new CodeCastExpression(castTo, methodInvoke);
+ return new CodeCastExpression(castTo, methodInvoke);
}
- else
- {
- expression = methodInvoke;
- }
- }
- else
- {
- expression = methodInvoke;
}
- }
- return expression;
+ return methodInvoke;
+ }
}
///
@@ -386,7 +351,7 @@ public object SerializeInvariant(IDesignerSerializationManager manager, object v
///
/// Writes out the given metadata.
///
- public void SerializeMetadata(IDesignerSerializationManager manager, string name, object value, bool shouldSerializeValue)
+ public void SerializeMetadata(IDesignerSerializationManager manager, string name, object? value, bool shouldSerializeValue)
{
using (TraceScope($"ResourceCodeDomSerializer::{nameof(SerializeMetadata)}"))
{
@@ -400,7 +365,7 @@ public void SerializeMetadata(IDesignerSerializationManager manager, string name
///
/// Serializes the given resource value into the resource set. This does not effect the code dom values. The resource is written into the current culture.
///
- public void WriteResource(IDesignerSerializationManager manager, string name, object value)
+ public void WriteResource(IDesignerSerializationManager manager, string name, object? value)
{
SetValueUsingCommonTraceScope(manager, name, value, nameof(WriteResource), false, false, true, false);
}
@@ -408,12 +373,12 @@ public void WriteResource(IDesignerSerializationManager manager, string name, ob
///
/// Serializes the given resource value into the resource set. This does not effect the code dom values. The resource is written into the invariant culture.
///
- public void WriteResourceInvariant(IDesignerSerializationManager manager, string name, object value)
+ public void WriteResourceInvariant(IDesignerSerializationManager manager, string name, object? value)
{
SetValueUsingCommonTraceScope(manager, name, value, nameof(WriteResourceInvariant), true, true, true, false);
}
- private static void SetValueUsingCommonTraceScope(IDesignerSerializationManager manager, string name, object value, string calleeName,
+ private static void SetValueUsingCommonTraceScope(IDesignerSerializationManager manager, string name, object? value, string calleeName,
bool forceInvariant, bool shouldSerializeInvariant, bool ensureInvariant, bool applyingCachedResources)
{
using (TraceScope($"ResourceCodeDomSerializer::{calleeName}"))