From 481dc8f65184dabd67c99d61e807b1c483f3bf19 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 3 Sep 2021 12:58:57 -0700 Subject: [PATCH] Nullable annotations part 1 (dotnet/linker#2253) * Nullable annotations part 1 Enable nullable annotations for LinkContext and the XML processing classes. Commit migrated from https://github.com/dotnet/linker/commit/39505a8e73d3ed4e6befa5b8bc7d32e2380c889a --- .../linker/Linker.Dataflow/FlowAnnotations.cs | 13 +- .../Linker.Dataflow/MethodBodyScanner.cs | 4 +- .../Linker.Steps/BodySubstitutionParser.cs | 96 +++++------- .../linker/Linker.Steps/CodeRewriterStep.cs | 3 + .../linker/Linker.Steps/DescriptorMarker.cs | 27 ++-- .../Linker.Steps/LinkAttributesParser.cs | 63 ++++---- .../src/linker/Linker.Steps/MarkStep.cs | 2 +- .../src/linker/Linker.Steps/OutputStep.cs | 5 +- .../Linker.Steps/OutputWarningSuppressions.cs | 2 +- .../Linker.Steps/ProcessLinkerXmlBase.cs | 121 +++++++-------- src/tools/illink/src/linker/Linker/Driver.cs | 3 +- .../illink/src/linker/Linker/LinkContext.cs | 141 ++++++------------ .../src/linker/Linker/SubstitutionInfo.cs | 14 +- .../linker/Linker/TypeReferenceExtensions.cs | 2 + .../Tests/AnnotationStoreTest.cs | 2 +- .../Tests/MessageContainerTests.cs | 2 +- 16 files changed, 212 insertions(+), 288 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs index 0c5e2795c1384a..da222099dc14f4 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -159,8 +159,9 @@ static bool IsDynamicallyAccessedMembersAttribute (CustomAttribute attribute) return attributeType.Name == "DynamicallyAccessedMembersAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis"; } - DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMembersAttribute (ICustomAttributeProvider provider, IMemberDefinition locationMember = null) + DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMembersAttribute (IMemberDefinition member, ICustomAttributeProvider providerIfNotMember = null) { + ICustomAttributeProvider provider = providerIfNotMember ?? member; if (!_context.CustomAttributes.HasAny (provider)) return DynamicallyAccessedMemberTypes.None; foreach (var attribute in _context.CustomAttributes.GetCustomAttributes (provider)) { @@ -171,7 +172,7 @@ DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMembersAttrib else _context.LogWarning ( $"Attribute 'System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute' doesn't have the required number of parameters specified.", - 2028, locationMember ?? (provider as IMemberDefinition)); + 2028, member); } return DynamicallyAccessedMemberTypes.None; } @@ -242,7 +243,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) for (int i = 0; i < method.Parameters.Count; i++) { var methodParameter = method.Parameters[i]; - DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute (methodParameter, method); + DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, providerIfNotMember: methodParameter); if (pa == DynamicallyAccessedMemberTypes.None) continue; @@ -259,7 +260,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) paramAnnotations[i + offset] = pa; } - DynamicallyAccessedMemberTypes returnAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (method.MethodReturnType, method); + DynamicallyAccessedMemberTypes returnAnnotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, providerIfNotMember: method.MethodReturnType); if (returnAnnotation != DynamicallyAccessedMemberTypes.None && !IsTypeInterestingForDataflow (method.ReturnType)) { _context.LogWarning ( $"Return type of method '{method.GetDisplayName ()}' has 'DynamicallyAccessedMembersAttribute', but that attribute can only be applied to properties of type 'System.Type' or 'System.String'.", @@ -270,7 +271,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (method.HasGenericParameters) { for (int genericParameterIndex = 0; genericParameterIndex < method.GenericParameters.Count; genericParameterIndex++) { var genericParameter = method.GenericParameters[genericParameterIndex]; - var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (genericParameter, method); + var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (method, providerIfNotMember: genericParameter); if (annotation != DynamicallyAccessedMemberTypes.None) { if (genericParameterAnnotations == null) genericParameterAnnotations = new DynamicallyAccessedMemberTypes[method.GenericParameters.Count]; @@ -392,7 +393,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (type.HasGenericParameters) { for (int genericParameterIndex = 0; genericParameterIndex < type.GenericParameters.Count; genericParameterIndex++) { var genericParameter = type.GenericParameters[genericParameterIndex]; - var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (genericParameter, type); + var annotation = GetMemberTypesForDynamicallyAccessedMembersAttribute (type, providerIfNotMember: genericParameter); if (annotation != DynamicallyAccessedMemberTypes.None) { if (typeGenericParameterAnnotations == null) typeGenericParameterAnnotations = new DynamicallyAccessedMemberTypes[type.GenericParameters.Count]; diff --git a/src/tools/illink/src/linker/Linker.Dataflow/MethodBodyScanner.cs b/src/tools/illink/src/linker/Linker.Dataflow/MethodBodyScanner.cs index fa8ca8dd19fa51..8c0ec0a15cbe45 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/MethodBodyScanner.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/MethodBodyScanner.cs @@ -791,7 +791,7 @@ private void ScanLdfld ( bool isByRef = code == Code.Ldflda || code == Code.Ldsflda; - FieldDefinition field = _context.TryResolve (operation.Operand as FieldReference); + FieldDefinition field = _context.TryResolve ((FieldReference) operation.Operand); if (field != null) { StackSlot slot = new StackSlot (GetFieldValue (thisMethod, field), isByRef); currentStack.Push (slot); @@ -819,7 +819,7 @@ private void ScanStfld ( if (operation.OpCode.Code == Code.Stfld) PopUnknown (currentStack, 1, methodBody, operation.Offset); - FieldDefinition field = _context.TryResolve (operation.Operand as FieldReference); + FieldDefinition field = _context.TryResolve ((FieldReference) operation.Operand); if (field != null) { HandleStoreField (thisMethod, field, operation, valueToStoreSlot.Value); } diff --git a/src/tools/illink/src/linker/Linker.Steps/BodySubstitutionParser.cs b/src/tools/illink/src/linker/Linker.Steps/BodySubstitutionParser.cs index 59b58d6c33eaf2..f79b34da356bc8 100644 --- a/src/tools/illink/src/linker/Linker.Steps/BodySubstitutionParser.cs +++ b/src/tools/illink/src/linker/Linker.Steps/BodySubstitutionParser.cs @@ -5,11 +5,13 @@ using System.Xml.XPath; using Mono.Cecil; +#nullable enable + namespace Mono.Linker.Steps { public class BodySubstitutionParser : ProcessLinkerXmlBase { - SubstitutionInfo _substitutionInfo; + SubstitutionInfo? _substitutionInfo; public BodySubstitutionParser (LinkContext context, Stream documentStream, string xmlDocumentLocation) : base (context, documentStream, xmlDocumentLocation) @@ -24,74 +26,49 @@ public BodySubstitutionParser (LinkContext context, Stream documentStream, Embed public void Parse (SubstitutionInfo xmlInfo) { _substitutionInfo = xmlInfo; - bool stripSubstitutions = _context.IsOptimizationEnabled (CodeOptimizations.RemoveSubstitutions, _resourceAssembly); + bool stripSubstitutions = _context.IsOptimizationEnabled (CodeOptimizations.RemoveSubstitutions, _resource?.Assembly); ProcessXml (stripSubstitutions, _context.IgnoreSubstitutions); } protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) { ProcessTypes (assembly, nav, warnOnUnresolvedTypes); - ProcessResources (assembly, nav.SelectChildren ("resource", "")); + ProcessResources (assembly, nav); } - protected override TypeDefinition ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) => null; + protected override TypeDefinition? ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) => null; protected override bool ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavigator nav) => false; protected override void ProcessType (TypeDefinition type, XPathNavigator nav) { Debug.Assert (ShouldProcessElement (nav)); - - if (!nav.HasChildren) - return; - - XPathNodeIterator methods = nav.SelectChildren ("method", ""); - if (methods.Count > 0) - ProcessMethods (type, methods); - - var fields = nav.SelectChildren ("field", ""); - if (fields.Count > 0) { - while (fields.MoveNext ()) { - if (!ShouldProcessElement (fields.Current)) - continue; - - ProcessField (type, fields); - } - } + ProcessTypeChildren (type, nav); } - void ProcessMethods (TypeDefinition type, XPathNodeIterator iterator) + protected override void ProcessMethod (TypeDefinition type, XPathNavigator methodNav, object? _customData) { - while (iterator.MoveNext ()) { - if (!ShouldProcessElement (iterator.Current)) - continue; - - ProcessMethod (type, iterator); - } - } - - void ProcessMethod (TypeDefinition type, XPathNodeIterator iterator) - { - string signature = GetAttribute (iterator.Current, "signature"); + Debug.Assert (_substitutionInfo != null); + string signature = GetSignature (methodNav); if (string.IsNullOrEmpty (signature)) return; - MethodDefinition method = FindMethod (type, signature); + MethodDefinition? method = FindMethod (type, signature); if (method == null) { - LogWarning ($"Could not find method '{signature}' on type '{type.GetDisplayName ()}'.", 2009, iterator.Current); + LogWarning ($"Could not find method '{signature}' on type '{type.GetDisplayName ()}'.", 2009, methodNav); return; } - string action = GetAttribute (iterator.Current, "body"); + string action = GetAttribute (methodNav, "body"); switch (action) { case "remove": _substitutionInfo.SetMethodAction (method, MethodAction.ConvertToThrow); return; case "stub": - string value = GetAttribute (iterator.Current, "value"); + string value = GetAttribute (methodNav, "value"); if (!string.IsNullOrEmpty (value)) { - if (!TryConvertValue (value, method.ReturnType, out object res)) { - LogWarning ($"Invalid value for '{method.GetDisplayName ()}' stub.", 2010, iterator.Current); + if (!TryConvertValue (value, method.ReturnType, out object? res)) { + LogWarning ($"Invalid value for '{method.GetDisplayName ()}' stub.", 2010, methodNav); return; } @@ -101,69 +78,68 @@ void ProcessMethod (TypeDefinition type, XPathNodeIterator iterator) _substitutionInfo.SetMethodAction (method, MethodAction.ConvertToStub); return; default: - LogWarning ($"Unknown body modification '{action}' for '{method.GetDisplayName ()}'.", 2011, iterator.Current); + LogWarning ($"Unknown body modification '{action}' for '{method.GetDisplayName ()}'.", 2011, methodNav); return; } } - void ProcessField (TypeDefinition type, XPathNodeIterator iterator) + protected override void ProcessField (TypeDefinition type, XPathNavigator fieldNav) { - string name = GetAttribute (iterator.Current, "name"); + Debug.Assert (_substitutionInfo != null); + string name = GetAttribute (fieldNav, "name"); if (string.IsNullOrEmpty (name)) return; var field = type.Fields.FirstOrDefault (f => f.Name == name); if (field == null) { - LogWarning ($"Could not find field '{name}' on type '{type.GetDisplayName ()}'.", 2012, iterator.Current); + LogWarning ($"Could not find field '{name}' on type '{type.GetDisplayName ()}'.", 2012, fieldNav); return; } if (!field.IsStatic || field.IsLiteral) { - LogWarning ($"Substituted field '{field.GetDisplayName ()}' needs to be static field.", 2013, iterator.Current); + LogWarning ($"Substituted field '{field.GetDisplayName ()}' needs to be static field.", 2013, fieldNav); return; } - string value = GetAttribute (iterator.Current, "value"); + string value = GetAttribute (fieldNav, "value"); if (string.IsNullOrEmpty (value)) { - LogWarning ($"Missing 'value' attribute for field '{field.GetDisplayName ()}'.", 2014, iterator.Current); + LogWarning ($"Missing 'value' attribute for field '{field.GetDisplayName ()}'.", 2014, fieldNav); return; } - if (!TryConvertValue (value, field.FieldType, out object res)) { - LogWarning ($"Invalid value '{value}' for '{field.GetDisplayName ()}'.", 2015, iterator.Current); + if (!TryConvertValue (value, field.FieldType, out object? res)) { + LogWarning ($"Invalid value '{value}' for '{field.GetDisplayName ()}'.", 2015, fieldNav); return; } _substitutionInfo.SetFieldValue (field, res); - string init = GetAttribute (iterator.Current, "initialize"); + string init = GetAttribute (fieldNav, "initialize"); if (init?.ToLowerInvariant () == "true") { _substitutionInfo.SetFieldInit (field); } } - void ProcessResources (AssemblyDefinition assembly, XPathNodeIterator iterator) + void ProcessResources (AssemblyDefinition assembly, XPathNavigator nav) { - while (iterator.MoveNext ()) { - XPathNavigator nav = iterator.Current; - - if (!ShouldProcessElement (nav)) + foreach (XPathNavigator resourceNav in nav.SelectChildren ("resource", "")) { + if (!ShouldProcessElement (resourceNav)) continue; - string name = GetAttribute (nav, "name"); + string name = GetAttribute (resourceNav, "name"); if (String.IsNullOrEmpty (name)) { - LogWarning ($"Missing 'name' attribute for resource.", 2038, iterator.Current); + LogWarning ($"Missing 'name' attribute for resource.", 2038, resourceNav); continue; } - string action = GetAttribute (nav, "action"); + string action = GetAttribute (resourceNav, "action"); if (action != "remove") { - LogWarning ($"Invalid value '{action}' for attribute 'action' for resource '{name}'.", 2039, iterator.Current); + LogWarning ($"Invalid value '{action}' for attribute 'action' for resource '{name}'.", 2039, resourceNav); continue; } EmbeddedResource resource = assembly.FindEmbeddedResource (name); if (resource == null) { - LogWarning ($"Could not find embedded resource '{name}' to remove in assembly '{assembly.Name.Name}'.", 2040, iterator.Current); + LogWarning ($"Could not find embedded resource '{name}' to remove in assembly '{assembly.Name.Name}'.", 2040, resourceNav); continue; } @@ -171,7 +147,7 @@ void ProcessResources (AssemblyDefinition assembly, XPathNodeIterator iterator) } } - static MethodDefinition FindMethod (TypeDefinition type, string signature) + static MethodDefinition? FindMethod (TypeDefinition type, string signature) { if (!type.HasMethods) return null; diff --git a/src/tools/illink/src/linker/Linker.Steps/CodeRewriterStep.cs b/src/tools/illink/src/linker/Linker.Steps/CodeRewriterStep.cs index bd730eb64bc73d..9b9f17010cf659 100644 --- a/src/tools/illink/src/linker/Linker.Steps/CodeRewriterStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/CodeRewriterStep.cs @@ -229,6 +229,9 @@ public static Instruction CreateConstantResultInstruction (LinkContext context, break; } + if (rtype == null) + return null; + switch (rtype.MetadataType) { case MetadataType.Boolean: if (value is int bintValue && bintValue == 1) diff --git a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs index 0de915a4375bc7..f7b8dceb3b1718 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs @@ -10,6 +10,8 @@ using Mono.Cecil; +#nullable enable + namespace Mono.Linker.Steps { public class DescriptorMarker : ProcessLinkerXmlBase @@ -35,7 +37,7 @@ public DescriptorMarker (LinkContext context, Stream documentStream, EmbeddedRes public void Mark () { - bool stripDescriptors = _context.IsOptimizationEnabled (CodeOptimizations.RemoveDescriptors, _resourceAssembly); + bool stripDescriptors = _context.IsOptimizationEnabled (CodeOptimizations.RemoveDescriptors, _resource?.Assembly); ProcessXml (stripDescriptors, _context.IgnoreDescriptors); } @@ -57,12 +59,11 @@ protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNavig void ProcessNamespaces (AssemblyDefinition assembly, XPathNavigator nav) { - var iterator = nav.SelectChildren (NamespaceElementName, XmlNamespace); - while (iterator.MoveNext ()) { - if (!ShouldProcessElement (iterator.Current)) + foreach (XPathNavigator namespaceNav in nav.SelectChildren (NamespaceElementName, XmlNamespace)) { + if (!ShouldProcessElement (namespaceNav)) continue; - string fullname = GetFullName (iterator.Current); + string fullname = GetFullName (namespaceNav); bool foundMatch = false; foreach (TypeDefinition type in assembly.MainModule.Types) { if (type.Namespace != fullname) @@ -73,7 +74,7 @@ void ProcessNamespaces (AssemblyDefinition assembly, XPathNavigator nav) } if (!foundMatch) { - LogWarning ($"Could not find any type in namespace '{fullname}'.", 2044, iterator.Current); + LogWarning ($"Could not find any type in namespace '{fullname}'.", 2044, namespaceNav); } } } @@ -90,7 +91,7 @@ void MarkAndPreserveAll (TypeDefinition type) MarkAndPreserveAll (nested); } - protected override TypeDefinition ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) + protected override TypeDefinition? ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) { _context.MarkingHelpers.MarkExportedType (exported, assembly.MainModule, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); return base.ProcessExportedType (exported, assembly); @@ -154,7 +155,7 @@ protected override void ProcessField (TypeDefinition type, FieldDefinition field _context.Annotations.Mark (field, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); } - protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object customData) + protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { if (_context.Annotations.IsMarked (method)) LogWarning ($"Duplicate preserve of '{method.GetDisplayName ()}'.", 2025, nav); @@ -162,14 +163,14 @@ protected override void ProcessMethod (TypeDefinition type, MethodDefinition met _context.Annotations.MarkIndirectlyCalledMethod (method); _context.Annotations.SetAction (method, MethodAction.Parse); - if (!(bool) customData) { + if (customData is bool required && !required) { _context.Annotations.AddPreservedMethod (type, method); } else { _context.Annotations.Mark (method, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation)); } } - void ProcessMethodIfNotNull (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object customData) + void ProcessMethodIfNotNull (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { if (method == null) return; @@ -177,7 +178,7 @@ void ProcessMethodIfNotNull (TypeDefinition type, MethodDefinition method, XPath ProcessMethod (type, method, nav, customData); } - protected override MethodDefinition GetMethod (TypeDefinition type, string signature) + protected override MethodDefinition? GetMethod (TypeDefinition type, string signature) { if (type.HasMethods) foreach (MethodDefinition meth in type.Methods) @@ -211,7 +212,7 @@ public static string GetMethodSignature (MethodDefinition meth, bool includeGene return sb.ToString (); } - protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object customData) + protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { if (_context.Annotations.IsMarked (@event)) LogWarning ($"Duplicate preserve of '{@event.FullName}'.", 2025, nav); @@ -221,7 +222,7 @@ protected override void ProcessEvent (TypeDefinition type, EventDefinition @even ProcessMethodIfNotNull (type, @event.InvokeMethod, nav, customData); } - protected override void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object customData, bool fromSignature) + protected override void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) { string[] accessors = fromSignature ? GetAccessors (nav) : _accessorsAll; diff --git a/src/tools/illink/src/linker/Linker.Steps/LinkAttributesParser.cs b/src/tools/illink/src/linker/Linker.Steps/LinkAttributesParser.cs index eec81cefcbcf0f..a7f24b176f12bf 100644 --- a/src/tools/illink/src/linker/Linker.Steps/LinkAttributesParser.cs +++ b/src/tools/illink/src/linker/Linker.Steps/LinkAttributesParser.cs @@ -4,17 +4,20 @@ using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text; using System.Xml.XPath; using Mono.Cecil; +#nullable enable + namespace Mono.Linker.Steps { public class LinkAttributesParser : ProcessLinkerXmlBase { - AttributeInfo _attributeInfo; + AttributeInfo? _attributeInfo; public LinkAttributesParser (LinkContext context, Stream documentStream, string xmlDocumentLocation) : base (context, documentStream, xmlDocumentLocation) @@ -29,7 +32,7 @@ public LinkAttributesParser (LinkContext context, Stream documentStream, Embedde public void Parse (AttributeInfo xmlInfo) { _attributeInfo = xmlInfo; - bool stripLinkAttributes = _context.IsOptimizationEnabled (CodeOptimizations.RemoveLinkAttributes, _resourceAssembly); + bool stripLinkAttributes = _context.IsOptimizationEnabled (CodeOptimizations.RemoveLinkAttributes, _resource?.Assembly); ProcessXml (stripLinkAttributes, _context.IgnoreLinkAttributes); } @@ -40,7 +43,7 @@ CustomAttribute[] ProcessAttributes (XPathNavigator nav, ICustomAttributeProvide if (!ShouldProcessElement (argumentNav)) continue; - TypeDefinition attributeType; + TypeDefinition? attributeType; string internalAttribute = GetAttribute (argumentNav, "internal"); if (!string.IsNullOrEmpty (internalAttribute)) { attributeType = GenerateRemoveAttributeInstancesAttribute (); @@ -63,7 +66,7 @@ CustomAttribute[] ProcessAttributes (XPathNavigator nav, ICustomAttributeProvide continue; } - CustomAttribute customAttribute = CreateCustomAttribute (argumentNav, attributeType); + CustomAttribute? customAttribute = CreateCustomAttribute (argumentNav, attributeType); if (customAttribute != null) { _context.LogMessage ($"Assigning external custom attribute '{FormatCustomAttribute (customAttribute)}' instance to '{provider}'."); builder.Add (customAttribute); @@ -90,7 +93,7 @@ static string FormatCustomAttribute (CustomAttribute ca) } } - TypeDefinition GenerateRemoveAttributeInstancesAttribute () + TypeDefinition? GenerateRemoveAttributeInstancesAttribute () { if (_context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition != null) return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition; @@ -130,11 +133,11 @@ TypeDefinition GenerateRemoveAttributeInstancesAttribute () return _context.MarkedKnownMembers.RemoveAttributeInstancesAttributeDefinition = td; } - CustomAttribute CreateCustomAttribute (XPathNavigator nav, TypeDefinition attributeType) + CustomAttribute? CreateCustomAttribute (XPathNavigator nav, TypeDefinition attributeType) { CustomAttributeArgument[] arguments = ReadCustomAttributeArguments (nav, attributeType); - MethodDefinition constructor = FindBestMatchingConstructor (attributeType, arguments); + MethodDefinition? constructor = FindBestMatchingConstructor (attributeType, arguments); if (constructor == null) { LogWarning ( $"Could not find matching constructor for custom attribute '{attributeType.GetDisplayName ()}' arguments.", @@ -152,7 +155,7 @@ CustomAttribute CreateCustomAttribute (XPathNavigator nav, TypeDefinition attrib return customAttribute; } - MethodDefinition FindBestMatchingConstructor (TypeDefinition attributeType, CustomAttributeArgument[] args) + MethodDefinition? FindBestMatchingConstructor (TypeDefinition attributeType, CustomAttributeArgument[] args) { var methods = attributeType.Methods; for (int i = 0; i < attributeType.Methods.Count; ++i) { @@ -190,7 +193,7 @@ void ReadCustomAttributeProperties (XPathNavigator nav, TypeDefinition attribute continue; } - PropertyDefinition property = attributeType.Properties.Where (prop => prop.Name == propertyName).FirstOrDefault (); + PropertyDefinition? property = attributeType.Properties.Where (prop => prop.Name == propertyName).FirstOrDefault (); if (property == null) { LogWarning ($"Property '{propertyName}' could not be found.", 2052, propertyNav); continue; @@ -219,7 +222,7 @@ CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNavigator nav, Type CustomAttributeArgument? ReadCustomAttributeArgument (XPathNavigator nav, IMemberDefinition memberWithAttribute) { - TypeReference typeref = ResolveArgumentType (nav, memberWithAttribute); + TypeReference? typeref = ResolveArgumentType (nav, memberWithAttribute); if (typeref is null) return null; @@ -239,7 +242,11 @@ CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNavigator nav, Type return null; } - var boxedValue = ReadCustomAttributeArgument (argumentIterator.Current!, _context.TryResolve (typeref)); + var typedef = _context.TryResolve (typeref); + if (typedef == null) + return null; + + var boxedValue = ReadCustomAttributeArgument (argumentIterator.Current!, typedef); if (boxedValue is null) return null; @@ -285,7 +292,7 @@ CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNavigator nav, Type return null; } - TypeReference ResolveArgumentType (XPathNavigator nav, IMemberDefinition memberWithAttribute) + TypeReference? ResolveArgumentType (XPathNavigator nav, IMemberDefinition memberWithAttribute) { string typeName = GetAttribute (nav, "type"); if (string.IsNullOrEmpty (typeName)) @@ -301,7 +308,7 @@ TypeReference ResolveArgumentType (XPathNavigator nav, IMemberDefinition memberW } } - object ConvertStringValue (object value, TypeReference targetType) + object? ConvertStringValue (object value, TypeReference targetType) { TypeCode typeCode; switch (targetType.MetadataType) { @@ -356,7 +363,7 @@ object ConvertStringValue (object value, TypeReference targetType) } } - bool GetAttributeType (XPathNavigator nav, string attributeFullName, out TypeDefinition attributeType) + bool GetAttributeType (XPathNavigator nav, string attributeFullName, [NotNullWhen (true)] out TypeDefinition? attributeType) { string assemblyName = GetAttribute (nav, "assembly"); if (string.IsNullOrEmpty (assemblyName)) { @@ -390,11 +397,11 @@ bool GetAttributeType (XPathNavigator nav, string attributeFullName, out TypeDef protected override AllowedAssemblies AllowedAssemblySelector { get { - if (_resourceAssembly == null) + if (_resource?.Assembly == null) return AllowedAssemblies.AllAssemblies; // Corelib XML may contain assembly wildcard to support compiler-injected attribute types - if (_resourceAssembly.Name.Name == PlatformAssemblies.CoreLib) + if (_resource?.Assembly.Name.Name == PlatformAssemblies.CoreLib) return AllowedAssemblies.AllAssemblies; return AllowedAssemblies.ContainingAssembly; @@ -417,11 +424,10 @@ protected override void ProcessType (TypeDefinition type, XPathNavigator nav) if (!type.HasNestedTypes) return; - var iterator = nav.SelectChildren ("type", string.Empty); - while (iterator.MoveNext ()) { + foreach (XPathNavigator nestedTypeNav in nav.SelectChildren ("type", string.Empty)) { foreach (TypeDefinition nested in type.NestedTypes) { - if (nested.Name == GetAttribute (iterator.Current, "name") && ShouldProcessElement (iterator.Current)) - ProcessType (nested, iterator.Current); + if (nested.Name == GetAttribute (nestedTypeNav, "name") && ShouldProcessElement (nestedTypeNav)) + ProcessType (nested, nestedTypeNav); } } } @@ -431,7 +437,7 @@ protected override void ProcessField (TypeDefinition type, FieldDefinition field PopulateAttributeInfo (field, nav); } - protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object customData) + protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { PopulateAttributeInfo (method, nav); ProcessReturnParameters (method, nav); @@ -440,6 +446,7 @@ protected override void ProcessMethod (TypeDefinition type, MethodDefinition met void ProcessParameters (MethodDefinition method, XPathNavigator nav) { + Debug.Assert (_attributeInfo != null); foreach (XPathNavigator parameterNav in nav.SelectChildren ("parameter", string.Empty)) { var attributes = ProcessAttributes (parameterNav, method); if (attributes != null) { @@ -460,21 +467,20 @@ void ProcessParameters (MethodDefinition method, XPathNavigator nav) void ProcessReturnParameters (MethodDefinition method, XPathNavigator nav) { - var iterator = nav.SelectChildren ("return", string.Empty); bool firstAppearance = true; - while (iterator.MoveNext ()) { + foreach (XPathNavigator returnNav in nav.SelectChildren ("return", string.Empty)) { if (firstAppearance) { firstAppearance = false; - PopulateAttributeInfo (method.MethodReturnType, iterator.Current); + PopulateAttributeInfo (method.MethodReturnType, returnNav); } else { LogWarning ( $"There is more than one 'return' child element specified for method '{method.GetDisplayName ()}'.", - 2023, iterator.Current); + 2023, returnNav); } } } - protected override MethodDefinition GetMethod (TypeDefinition type, string signature) + protected override MethodDefinition? GetMethod (TypeDefinition type, string signature) { if (type.HasMethods) foreach (MethodDefinition method in type.Methods) @@ -514,18 +520,19 @@ static string GetMethodSignature (MethodDefinition method, bool includeReturnTyp return sb.ToString (); } - protected override void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object customData, bool fromSignature) + protected override void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) { PopulateAttributeInfo (property, nav); } - protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object customData) + protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { PopulateAttributeInfo (@event, nav); } void PopulateAttributeInfo (ICustomAttributeProvider provider, XPathNavigator nav) { + Debug.Assert (_attributeInfo != null); var attributes = ProcessAttributes (nav, provider); if (attributes != null) _attributeInfo.AddCustomAttributes (provider, attributes); diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 00fd272eefd6ee..f21957c4905209 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -277,7 +277,7 @@ bool IsInternalsVisibleAttributeAssemblyMarked (CustomAttribute ca) return false; } - var assembly = _context.GetLoadedAssembly (an.Name); + var assembly = _context.GetLoadedAssembly (an.Name!); if (assembly == null) return false; diff --git a/src/tools/illink/src/linker/Linker.Steps/OutputStep.cs b/src/tools/illink/src/linker/Linker.Steps/OutputStep.cs index 566d334bc307f1..1917965a113e92 100644 --- a/src/tools/illink/src/linker/Linker.Steps/OutputStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/OutputStep.cs @@ -211,10 +211,7 @@ WriterParameters SaveSymbols (AssemblyDefinition assembly) if (Environment.OSVersion.Platform != PlatformID.Win32NT && assembly.MainModule.SymbolReader.GetType ().FullName == "Mono.Cecil.Pdb.NativePdbReader") return parameters; - if (Context.SymbolWriterProvider != null) - parameters.SymbolWriterProvider = Context.SymbolWriterProvider; - else - parameters.WriteSymbols = true; + parameters.WriteSymbols = true; return parameters; } diff --git a/src/tools/illink/src/linker/Linker.Steps/OutputWarningSuppressions.cs b/src/tools/illink/src/linker/Linker.Steps/OutputWarningSuppressions.cs index b27ad47b2016d9..e4ecc8213080a2 100644 --- a/src/tools/illink/src/linker/Linker.Steps/OutputWarningSuppressions.cs +++ b/src/tools/illink/src/linker/Linker.Steps/OutputWarningSuppressions.cs @@ -16,7 +16,7 @@ protected override bool ConditionToProcess () protected override void Process () { CheckOutputDirectory (); - Context.WarningSuppressionWriter.OutputSuppressions (Context.OutputDirectory); + Context.WarningSuppressionWriter?.OutputSuppressions (Context.OutputDirectory); } void CheckOutputDirectory () diff --git a/src/tools/illink/src/linker/Linker.Steps/ProcessLinkerXmlBase.cs b/src/tools/illink/src/linker/Linker.Steps/ProcessLinkerXmlBase.cs index fa122d85bbedb0..45b6ca16ac9a18 100644 --- a/src/tools/illink/src/linker/Linker.Steps/ProcessLinkerXmlBase.cs +++ b/src/tools/illink/src/linker/Linker.Steps/ProcessLinkerXmlBase.cs @@ -14,6 +14,8 @@ using System.Xml.XPath; using Mono.Cecil; +#nullable enable + namespace Mono.Linker.Steps { [Flags] @@ -40,8 +42,7 @@ public abstract class ProcessLinkerXmlBase protected readonly string _xmlDocumentLocation; readonly XPathNavigator _document; - readonly EmbeddedResource _resource; - protected readonly AssemblyDefinition _resourceAssembly; + protected readonly (EmbeddedResource Resource, AssemblyDefinition Assembly)? _resource; protected readonly LinkContext _context; protected ProcessLinkerXmlBase (LinkContext context, Stream documentStream, string xmlDocumentLocation) @@ -56,15 +57,17 @@ protected ProcessLinkerXmlBase (LinkContext context, Stream documentStream, stri protected ProcessLinkerXmlBase (LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation) : this (context, documentStream, xmlDocumentLocation) { - _resource = resource ?? throw new ArgumentNullException (nameof (resource)); - _resourceAssembly = resourceAssembly ?? throw new ArgumentNullException (nameof (resourceAssembly)); + _resource = ( + resource ?? throw new ArgumentNullException (nameof (resource)), + resourceAssembly ?? throw new ArgumentNullException (nameof (resourceAssembly)) + ); } protected virtual bool ShouldProcessElement (XPathNavigator nav) => FeatureSettings.ShouldProcessElement (nav, _context, _xmlDocumentLocation); protected virtual void ProcessXml (bool stripResource, bool ignoreResource) { - if (!AllowedAssemblySelector.HasFlag (AllowedAssemblies.AnyAssembly) && _resourceAssembly == null) + if (!AllowedAssemblySelector.HasFlag (AllowedAssemblies.AnyAssembly) && _resource == null) throw new InvalidOperationException ("The containing assembly must be specified for XML which is restricted to modifying that assembly only."); try { @@ -76,7 +79,7 @@ protected virtual void ProcessXml (bool stripResource, bool ignoreResource) if (_resource != null) { if (stripResource) - _context.Annotations.AddResourceToRemove (_resourceAssembly, _resource); + _context.Annotations.AddResourceToRemove (_resource.Value.Assembly, _resource.Value.Resource); if (ignoreResource) return; } @@ -87,17 +90,17 @@ protected virtual void ProcessXml (bool stripResource, bool ignoreResource) ProcessAssemblies (nav); // For embedded XML, allow not specifying the assembly explicitly in XML. - if (_resourceAssembly != null) - ProcessAssembly (_resourceAssembly, nav, warnOnUnresolvedTypes: true); + if (_resource != null) + ProcessAssembly (_resource.Value.Assembly, nav, warnOnUnresolvedTypes: true); } catch (Exception ex) when (!(ex is LinkerFatalErrorException)) { throw new LinkerFatalErrorException (MessageContainer.CreateErrorMessage ($"Error processing '{_xmlDocumentLocation}'", 1013), ex); } } - protected virtual AllowedAssemblies AllowedAssemblySelector { get => _resourceAssembly != null ? AllowedAssemblies.ContainingAssembly : AllowedAssemblies.AnyAssembly; } + protected virtual AllowedAssemblies AllowedAssemblySelector { get => _resource != null ? AllowedAssemblies.ContainingAssembly : AllowedAssemblies.AnyAssembly; } - bool ShouldProcessAllAssemblies (XPathNavigator nav, [NotNullWhen (false)] out AssemblyNameReference assemblyName) + bool ShouldProcessAllAssemblies (XPathNavigator nav, [NotNullWhen (false)] out AssemblyNameReference? assemblyName) { assemblyName = null; if (GetFullName (nav) == AllAssembliesFullName) @@ -112,20 +115,21 @@ protected virtual void ProcessAssemblies (XPathNavigator nav) foreach (XPathNavigator assemblyNav in nav.SelectChildren ("assembly", "")) { // Errors for invalid assembly names should show up even if this element will be // skipped due to feature conditions. - bool processAllAssemblies = ShouldProcessAllAssemblies (assemblyNav, out AssemblyNameReference name); + bool processAllAssemblies = ShouldProcessAllAssemblies (assemblyNav, out AssemblyNameReference? name); if (processAllAssemblies && AllowedAssemblySelector != AllowedAssemblies.AllAssemblies) { LogWarning ($"XML contains unsupported wildcard for assembly 'fullname' attribute.", 2100, assemblyNav); continue; } - AssemblyDefinition assemblyToProcess = null; + AssemblyDefinition? assemblyToProcess = null; if (!AllowedAssemblySelector.HasFlag (AllowedAssemblies.AnyAssembly)) { Debug.Assert (!processAllAssemblies); - if (_resourceAssembly.Name.Name != name.Name) { - LogWarning ($"Embedded XML in assembly '{_resourceAssembly.Name.Name}' contains assembly 'fullname' attribute for another assembly '{name}'.", 2101, assemblyNav); + Debug.Assert (_resource != null); + if (_resource.Value.Assembly.Name.Name != name!.Name) { + LogWarning ($"Embedded XML in assembly '{_resource.Value.Assembly.Name.Name}' contains assembly 'fullname' attribute for another assembly '{name}'.", 2101, assemblyNav); continue; } - assemblyToProcess = _resourceAssembly; + assemblyToProcess = _resource.Value.Assembly; } if (!ShouldProcessElement (assemblyNav)) @@ -136,10 +140,11 @@ protected virtual void ProcessAssemblies (XPathNavigator nav) foreach (AssemblyDefinition assembly in _context.GetReferencedAssemblies ()) ProcessAssembly (assembly, assemblyNav, warnOnUnresolvedTypes: false); } else { - AssemblyDefinition assembly = assemblyToProcess ?? _context.TryResolve (name); + Debug.Assert (!processAllAssemblies); + AssemblyDefinition assembly = assemblyToProcess ?? _context.TryResolve (name!); if (assembly == null) { - LogWarning ($"Could not resolve assembly '{name.Name}'.", 2007, assemblyNav); + LogWarning ($"Could not resolve assembly '{name!.Name}'.", 2007, assemblyNav); continue; } @@ -188,7 +193,7 @@ protected virtual void ProcessTypes (AssemblyDefinition assembly, XPathNavigator } } - protected virtual TypeDefinition ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) => exported.Resolve (); + protected virtual TypeDefinition? ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) => exported.Resolve (); void MatchType (TypeDefinition type, Regex regex, XPathNavigator nav) { @@ -226,7 +231,7 @@ protected virtual bool ProcessTypePattern (string fullname, AssemblyDefinition a protected abstract void ProcessType (TypeDefinition type, XPathNavigator nav); - protected void ProcessTypeChildren (TypeDefinition type, XPathNavigator nav, object customData = null) + protected void ProcessTypeChildren (TypeDefinition type, XPathNavigator nav, object? customData = null) { if (nav.HasChildren) { ProcessSelectedFields (nav, type); @@ -238,14 +243,10 @@ protected void ProcessTypeChildren (TypeDefinition type, XPathNavigator nav, obj void ProcessSelectedFields (XPathNavigator nav, TypeDefinition type) { - XPathNodeIterator fields = nav.SelectChildren (FieldElementName, XmlNamespace); - if (fields.Count == 0) - return; - - while (fields.MoveNext ()) { - if (!ShouldProcessElement (fields.Current)) + foreach (XPathNavigator fieldNav in nav.SelectChildren (FieldElementName, XmlNamespace)) { + if (!ShouldProcessElement (fieldNav)) continue; - ProcessField (type, fields.Current); + ProcessField (type, fieldNav); } } @@ -253,7 +254,7 @@ protected virtual void ProcessField (TypeDefinition type, XPathNavigator nav) { string signature = GetSignature (nav); if (!String.IsNullOrEmpty (signature)) { - FieldDefinition field = GetField (type, signature); + FieldDefinition? field = GetField (type, signature); if (field == null) { LogWarning ($"Could not find field '{signature}' on type '{type.GetDisplayName ()}'.", 2012, nav); return; @@ -262,7 +263,7 @@ protected virtual void ProcessField (TypeDefinition type, XPathNavigator nav) ProcessField (type, field, nav); } - string name = GetAttribute (nav, NameAttributeName); + string name = GetName (nav); if (!String.IsNullOrEmpty (name)) { bool foundMatch = false; if (type.HasFields) { @@ -280,7 +281,7 @@ protected virtual void ProcessField (TypeDefinition type, XPathNavigator nav) } } - protected static FieldDefinition GetField (TypeDefinition type, string signature) + protected static FieldDefinition? GetField (TypeDefinition type, string signature) { if (!type.HasFields) return null; @@ -294,24 +295,20 @@ protected static FieldDefinition GetField (TypeDefinition type, string signature protected virtual void ProcessField (TypeDefinition type, FieldDefinition field, XPathNavigator nav) { } - void ProcessSelectedMethods (XPathNavigator nav, TypeDefinition type, object customData) + void ProcessSelectedMethods (XPathNavigator nav, TypeDefinition type, object? customData) { - XPathNodeIterator methods = nav.SelectChildren (MethodElementName, XmlNamespace); - if (methods.Count == 0) - return; - - while (methods.MoveNext ()) { - if (!ShouldProcessElement (methods.Current)) + foreach (XPathNavigator methodNav in nav.SelectChildren (MethodElementName, XmlNamespace)) { + if (!ShouldProcessElement (methodNav)) continue; - ProcessMethod (type, methods.Current, customData); + ProcessMethod (type, methodNav, customData); } } - protected virtual void ProcessMethod (TypeDefinition type, XPathNavigator nav, object customData) + protected virtual void ProcessMethod (TypeDefinition type, XPathNavigator nav, object? customData) { string signature = GetSignature (nav); if (!String.IsNullOrEmpty (signature)) { - MethodDefinition method = GetMethod (type, signature); + MethodDefinition? method = GetMethod (type, signature); if (method == null) { LogWarning ($"Could not find method '{signature}' on type '{type.GetDisplayName ()}'.", 2009, nav); return; @@ -338,28 +335,24 @@ protected virtual void ProcessMethod (TypeDefinition type, XPathNavigator nav, o } } - protected virtual MethodDefinition GetMethod (TypeDefinition type, string signature) => null; + protected virtual MethodDefinition? GetMethod (TypeDefinition type, string signature) => null; - protected virtual void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object customData) { } + protected virtual void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { } - void ProcessSelectedEvents (XPathNavigator nav, TypeDefinition type, object customData) + void ProcessSelectedEvents (XPathNavigator nav, TypeDefinition type, object? customData) { - XPathNodeIterator events = nav.SelectChildren (EventElementName, XmlNamespace); - if (events.Count == 0) - return; - - while (events.MoveNext ()) { - if (!ShouldProcessElement (events.Current)) + foreach (XPathNavigator eventNav in nav.SelectChildren (EventElementName, XmlNamespace)) { + if (!ShouldProcessElement (eventNav)) continue; - ProcessEvent (type, events.Current, customData); + ProcessEvent (type, eventNav, customData); } } - protected virtual void ProcessEvent (TypeDefinition type, XPathNavigator nav, object customData) + protected virtual void ProcessEvent (TypeDefinition type, XPathNavigator nav, object? customData) { string signature = GetSignature (nav); if (!String.IsNullOrEmpty (signature)) { - EventDefinition @event = GetEvent (type, signature); + EventDefinition? @event = GetEvent (type, signature); if (@event == null) { LogWarning ($"Could not find event '{signature}' on type '{type.GetDisplayName ()}'.", 2016, nav); return; @@ -384,7 +377,7 @@ protected virtual void ProcessEvent (TypeDefinition type, XPathNavigator nav, ob } } - protected static EventDefinition GetEvent (TypeDefinition type, string signature) + protected static EventDefinition? GetEvent (TypeDefinition type, string signature) { if (!type.HasEvents) return null; @@ -396,26 +389,22 @@ protected static EventDefinition GetEvent (TypeDefinition type, string signature return null; } - protected virtual void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object customData) { } + protected virtual void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { } - void ProcessSelectedProperties (XPathNavigator nav, TypeDefinition type, object customData) + void ProcessSelectedProperties (XPathNavigator nav, TypeDefinition type, object? customData) { - XPathNodeIterator properties = nav.SelectChildren (PropertyElementName, XmlNamespace); - if (properties.Count == 0) - return; - - while (properties.MoveNext ()) { - if (!ShouldProcessElement (properties.Current)) + foreach (XPathNavigator propertyNav in nav.SelectChildren (PropertyElementName, XmlNamespace)) { + if (!ShouldProcessElement (propertyNav)) continue; - ProcessProperty (type, properties.Current, customData); + ProcessProperty (type, propertyNav, customData); } } - protected virtual void ProcessProperty (TypeDefinition type, XPathNavigator nav, object customData) + protected virtual void ProcessProperty (TypeDefinition type, XPathNavigator nav, object? customData) { string signature = GetSignature (nav); if (!String.IsNullOrEmpty (signature)) { - PropertyDefinition property = GetProperty (type, signature); + PropertyDefinition? property = GetProperty (type, signature); if (property == null) { LogWarning ($"Could not find property '{signature}' on type '{type.GetDisplayName ()}'.", 2017, nav); return; @@ -440,7 +429,7 @@ protected virtual void ProcessProperty (TypeDefinition type, XPathNavigator nav, } } - protected static PropertyDefinition GetProperty (TypeDefinition type, string signature) + protected static PropertyDefinition? GetProperty (TypeDefinition type, string signature) { if (!type.HasProperties) return null; @@ -452,7 +441,7 @@ protected static PropertyDefinition GetProperty (TypeDefinition type, string sig return null; } - protected virtual void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object customData, bool fromSignature) { } + protected virtual void ProcessProperty (TypeDefinition type, PropertyDefinition property, XPathNavigator nav, object? customData, bool fromSignature) { } protected virtual AssemblyNameReference GetAssemblyName (XPathNavigator nav) { @@ -492,7 +481,7 @@ protected void LogWarning (string message, int warningCode, XPathNavigator posit public override string ToString () => GetType ().Name + ": " + _xmlDocumentLocation; - public bool TryConvertValue (string value, TypeReference target, out object result) + public bool TryConvertValue (string value, TypeReference target, out object? result) { switch (target.MetadataType) { case MetadataType.Boolean: diff --git a/src/tools/illink/src/linker/Linker/Driver.cs b/src/tools/illink/src/linker/Linker/Driver.cs index 96f702309b74e9..daee3af52c4a7d 100644 --- a/src/tools/illink/src/linker/Linker/Driver.cs +++ b/src/tools/illink/src/linker/Linker/Driver.cs @@ -1208,10 +1208,9 @@ string GetNextStringValue () protected virtual LinkContext GetDefaultContext (Pipeline pipeline, ILogger logger) { - return new LinkContext (pipeline, logger ?? new ConsoleLogger ()) { + return new LinkContext (pipeline, logger ?? new ConsoleLogger (), "output") { TrimAction = AssemblyAction.Link, DefaultAction = AssemblyAction.Link, - OutputDirectory = "output", }; } diff --git a/src/tools/illink/src/linker/Linker/LinkContext.cs b/src/tools/illink/src/linker/Linker/LinkContext.cs index e8e9fd93b10120..e80f7e583042eb 100644 --- a/src/tools/illink/src/linker/Linker/LinkContext.cs +++ b/src/tools/illink/src/linker/Linker/LinkContext.cs @@ -26,9 +26,12 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +#nullable enable + using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using Mono.Cecil; using Mono.Cecil.Cil; @@ -51,8 +54,8 @@ public static class TargetRuntimeVersion public interface ITryResolveMetadata { - MethodDefinition TryResolve (MethodReference methodReference); - TypeDefinition TryResolve (TypeReference typeReference); + MethodDefinition? TryResolve (MethodReference methodReference); + TypeDefinition? TryResolve (TypeReference typeReference); } public class LinkContext : IMetadataResolver, ITryResolveMetadata, IDisposable @@ -60,19 +63,12 @@ public class LinkContext : IMetadataResolver, ITryResolveMetadata, IDisposable readonly Pipeline _pipeline; readonly Dictionary _actions; - string _outputDirectory; readonly Dictionary _parameters; - bool _linkSymbols; - bool _keepTypeForwarderOnlyAssemblies; - bool _ignoreUnresolved; int? _targetRuntime; readonly AssemblyResolver _resolver; readonly TypeNameResolver _typeNameResolver; - ISymbolReaderProvider _symbolReaderProvider; - ISymbolWriterProvider _symbolWriterProvider; - readonly AnnotationStore _annotations; readonly CustomAttributeSource _customAttributes; readonly CompilerGeneratedState _compilerGeneratedState; @@ -94,10 +90,7 @@ public Pipeline Pipeline { public int ErrorsCount { get; private set; } - public string OutputDirectory { - get { return _outputDirectory; } - set { _outputDirectory = value; } - } + public string OutputDirectory { get; set; } public MetadataTrimming MetadataTrimming { get; set; } @@ -105,22 +98,13 @@ public string OutputDirectory { public AssemblyAction DefaultAction { get; set; } - public bool LinkSymbols { - get { return _linkSymbols; } - set { _linkSymbols = value; } - } + public bool LinkSymbols { get; set; } - public bool KeepTypeForwarderOnlyAssemblies { - get { return _keepTypeForwarderOnlyAssemblies; } - set { _keepTypeForwarderOnlyAssemblies = value; } - } + public bool KeepTypeForwarderOnlyAssemblies { get; set; } public readonly bool KeepMembersForDebugger = true; - public bool IgnoreUnresolved { - get { return _ignoreUnresolved; } - set { _ignoreUnresolved = value; } - } + public bool IgnoreUnresolved { get; set; } public bool EnableReducedTracing { get; set; } @@ -144,11 +128,9 @@ public bool IgnoreUnresolved { public Dictionary FeatureSettings { get; init; } - public List AttributeDefinitions { get; private set; } - public List PInvokes { get; private set; } - public string PInvokesListFile; + public string? PInvokesListFile; public bool StripSecurity { get; set; } @@ -164,15 +146,7 @@ internal TypeNameResolver TypeNameResolver { get { return _typeNameResolver; } } - public ISymbolReaderProvider SymbolReaderProvider { - get { return _symbolReaderProvider; } - set { _symbolReaderProvider = value; } - } - - public ISymbolWriterProvider SymbolWriterProvider { - get { return _symbolWriterProvider; } - set { _symbolWriterProvider = value; } - } + public ISymbolReaderProvider SymbolReaderProvider { get; set; } public bool LogMessages { get; set; } @@ -180,7 +154,7 @@ public ISymbolWriterProvider SymbolWriterProvider { public KnownMembers MarkedKnownMembers { get; private set; } - public WarningSuppressionWriter WarningSuppressionWriter { get; set; } + public WarningSuppressionWriter? WarningSuppressionWriter { get; set; } public HashSet NoWarn { get; set; } @@ -200,7 +174,7 @@ public ISymbolWriterProvider SymbolWriterProvider { public bool AddReflectionAnnotations { get; set; } - public string AssemblyListFile { get; set; } + public string? AssemblyListFile { get; set; } public List MarkHandlers { get; } @@ -212,7 +186,7 @@ public ISymbolWriterProvider SymbolWriterProvider { public SerializationMarker SerializationMarker { get; } - public LinkContext (Pipeline pipeline, ILogger logger) + public LinkContext (Pipeline pipeline, ILogger logger, string outputDirectory) { _pipeline = pipeline; _logger = logger ?? throw new ArgumentNullException (nameof (logger)); @@ -225,6 +199,7 @@ public LinkContext (Pipeline pipeline, ILogger logger) _compilerGeneratedState = new CompilerGeneratedState (this); _cachedWarningMessageContainers = new List (); _isTrimmable = new Dictionary (); + OutputDirectory = outputDirectory; FeatureSettings = new Dictionary (StringComparer.Ordinal); SymbolReaderProvider = new DefaultSymbolReaderProvider (false); @@ -276,20 +251,7 @@ public bool HasFeatureValue (string feature, bool value) return FeatureSettings.TryGetValue (feature, out bool fvalue) && value == fvalue; } - public void AddAttributeDefinitionFile (string file) - { - if (AttributeDefinitions == null) { - AttributeDefinitions = new List { file }; - return; - } - - if (AttributeDefinitions.Contains (file)) - return; - - AttributeDefinitions.Add (file); - } - - public TypeDefinition GetType (string fullName) + public TypeDefinition? GetType (string fullName) { int pos = fullName.IndexOf (","); fullName = TypeReferenceExtensions.ToCecilName (fullName); @@ -348,11 +310,11 @@ public virtual void SafeReadSymbols (AssemblyDefinition assembly) if (assembly.MainModule.HasSymbols) return; - if (_symbolReaderProvider == null) + if (SymbolReaderProvider == null) throw new InvalidOperationException ("Symbol provider is not set"); try { - var symbolReader = _symbolReaderProvider.GetSymbolReader ( + var symbolReader = SymbolReaderProvider.GetSymbolReader ( assembly.MainModule, GetAssemblyLocation (assembly)); @@ -483,7 +445,7 @@ public virtual AssemblyDefinition[] GetAssemblies () return asms; } - public AssemblyDefinition GetLoadedAssembly (string name) + public AssemblyDefinition? GetLoadedAssembly (string name) { if (!string.IsNullOrEmpty (name) && _resolver.AssemblyCache.TryGetValue (name, out var ad)) return ad; @@ -527,7 +489,7 @@ public bool HasCustomData (string key) return _parameters.ContainsKey (key); } - public bool TryGetCustomData (string key, out string value) + public bool TryGetCustomData (string key, [NotNullWhen (true)] out string? value) { return _parameters.TryGetValue (key, out value); } @@ -542,7 +504,7 @@ public bool IsOptimizationEnabled (CodeOptimizations optimization, MemberReferen return Optimizations.IsEnabled (optimization, context?.Module.Assembly); } - public bool IsOptimizationEnabled (CodeOptimizations optimization, AssemblyDefinition context) + public bool IsOptimizationEnabled (CodeOptimizations optimization, AssemblyDefinition? context) { return Optimizations.IsEnabled (optimization, context); } @@ -709,11 +671,11 @@ public int GetTargetRuntimeVersion () return _targetRuntime.Value; } - readonly Dictionary methodresolveCache = new (); - readonly Dictionary fieldresolveCache = new (); - readonly Dictionary typeresolveCache = new (); + readonly Dictionary methodresolveCache = new (); + readonly Dictionary fieldresolveCache = new (); + readonly Dictionary typeresolveCache = new (); - public MethodDefinition Resolve (MethodReference methodReference) + public MethodDefinition? Resolve (MethodReference methodReference) { if (methodReference is MethodDefinition methodDefinition) return methodDefinition; @@ -721,23 +683,18 @@ public MethodDefinition Resolve (MethodReference methodReference) if (methodReference is null) return null; - if (methodresolveCache.TryGetValue (methodReference, out MethodDefinition md)) { - if (md == null && !IgnoreUnresolved) - ReportUnresolved (methodReference); - + if (methodresolveCache.TryGetValue (methodReference, out MethodDefinition? md)) return md; - } md = methodReference.Resolve (); - if (md == null && !IgnoreUnresolved) { + if (md == null && !IgnoreUnresolved) ReportUnresolved (methodReference); - } methodresolveCache.Add (methodReference, md); return md; } - public MethodDefinition TryResolve (MethodReference methodReference) + public MethodDefinition? TryResolve (MethodReference methodReference) { if (methodReference is MethodDefinition methodDefinition) return methodDefinition; @@ -745,7 +702,7 @@ public MethodDefinition TryResolve (MethodReference methodReference) if (methodReference is null) return null; - if (methodresolveCache.TryGetValue (methodReference, out MethodDefinition md)) + if (methodresolveCache.TryGetValue (methodReference, out MethodDefinition? md)) return md; md = methodReference.Resolve (); @@ -753,7 +710,7 @@ public MethodDefinition TryResolve (MethodReference methodReference) return md; } - public FieldDefinition Resolve (FieldReference fieldReference) + public FieldDefinition? Resolve (FieldReference fieldReference) { if (fieldReference is FieldDefinition fieldDefinition) return fieldDefinition; @@ -761,23 +718,18 @@ public FieldDefinition Resolve (FieldReference fieldReference) if (fieldReference is null) return null; - if (fieldresolveCache.TryGetValue (fieldReference, out FieldDefinition fd)) { - if (fd == null && !IgnoreUnresolved) - ReportUnresolved (fieldReference); - + if (fieldresolveCache.TryGetValue (fieldReference, out FieldDefinition? fd)) return fd; - } fd = fieldReference.Resolve (); - if (fd == null && !IgnoreUnresolved) { + if (fd == null && !IgnoreUnresolved) ReportUnresolved (fieldReference); - } fieldresolveCache.Add (fieldReference, fd); return fd; } - public FieldDefinition TryResolve (FieldReference fieldReference) + public FieldDefinition? TryResolve (FieldReference fieldReference) { if (fieldReference is FieldDefinition fieldDefinition) return fieldDefinition; @@ -785,7 +737,7 @@ public FieldDefinition TryResolve (FieldReference fieldReference) if (fieldReference is null) return null; - if (fieldresolveCache.TryGetValue (fieldReference, out FieldDefinition fd)) + if (fieldresolveCache.TryGetValue (fieldReference, out FieldDefinition? fd)) return fd; fd = fieldReference.Resolve (); @@ -793,7 +745,7 @@ public FieldDefinition TryResolve (FieldReference fieldReference) return fd; } - public TypeDefinition Resolve (TypeReference typeReference) + public TypeDefinition? Resolve (TypeReference typeReference) { if (typeReference is TypeDefinition typeDefinition) return typeDefinition; @@ -801,12 +753,8 @@ public TypeDefinition Resolve (TypeReference typeReference) if (typeReference is null) return null; - if (typeresolveCache.TryGetValue (typeReference, out TypeDefinition td)) { - if (td == null && !IgnoreUnresolved) - ReportUnresolved (typeReference); - + if (typeresolveCache.TryGetValue (typeReference, out TypeDefinition? td)) return td; - } // // Types which never have TypeDefinition or can have ambiguous definition should not be passed in @@ -817,15 +765,14 @@ public TypeDefinition Resolve (TypeReference typeReference) #pragma warning disable RS0030 td = typeReference.Resolve (); #pragma warning restore RS0030 - if (td == null && !IgnoreUnresolved) { + if (td == null && !IgnoreUnresolved) ReportUnresolved (typeReference); - } typeresolveCache.Add (typeReference, td); return td; } - public TypeDefinition TryResolve (TypeReference typeReference) + public TypeDefinition? TryResolve (TypeReference typeReference) { if (typeReference is TypeDefinition typeDefinition) return typeDefinition; @@ -833,7 +780,7 @@ public TypeDefinition TryResolve (TypeReference typeReference) if (typeReference is null || typeReference is GenericParameter) return null; - if (typeresolveCache.TryGetValue (typeReference, out TypeDefinition td)) + if (typeresolveCache.TryGetValue (typeReference, out TypeDefinition? td)) return td; if (typeReference is TypeSpecification ts) { @@ -855,7 +802,7 @@ public TypeDefinition TryResolve (TypeReference typeReference) return td; } - public TypeDefinition TryResolve (AssemblyDefinition assembly, string typeNameString) + public TypeDefinition? TryResolve (AssemblyDefinition assembly, string typeNameString) { // It could be cached if it shows up on fast path return TryResolve (_typeNameResolver.ResolveTypeName (assembly, typeNameString)); @@ -905,12 +852,12 @@ public CodeOptimizationsSettings (CodeOptimizations globalOptimizations) public CodeOptimizations Global { get; private set; } - internal bool IsEnabled (CodeOptimizations optimizations, AssemblyDefinition context) + internal bool IsEnabled (CodeOptimizations optimizations, AssemblyDefinition? context) { return IsEnabled (optimizations, context?.Name.Name); } - public bool IsEnabled (CodeOptimizations optimizations, string assemblyName) + public bool IsEnabled (CodeOptimizations optimizations, string? assemblyName) { // Only one bit is set Debug.Assert (optimizations != 0 && (optimizations & (optimizations - 1)) == 0); @@ -924,7 +871,7 @@ public bool IsEnabled (CodeOptimizations optimizations, string assemblyName) return (Global & optimizations) != 0; } - public void Enable (CodeOptimizations optimizations, string assemblyContext = null) + public void Enable (CodeOptimizations optimizations, string? assemblyContext = null) { if (assemblyContext == null) { Global |= optimizations; @@ -940,7 +887,7 @@ public void Enable (CodeOptimizations optimizations, string assemblyContext = nu assemblySetting.Values |= optimizations; } - public void Disable (CodeOptimizations optimizations, string assemblyContext = null) + public void Disable (CodeOptimizations optimizations, string? assemblyContext = null) { if (assemblyContext == null) { Global &= ~optimizations; diff --git a/src/tools/illink/src/linker/Linker/SubstitutionInfo.cs b/src/tools/illink/src/linker/Linker/SubstitutionInfo.cs index b66351235fb149..f19b9ca613b8a6 100644 --- a/src/tools/illink/src/linker/Linker/SubstitutionInfo.cs +++ b/src/tools/illink/src/linker/Linker/SubstitutionInfo.cs @@ -5,20 +5,22 @@ using System.Collections.Generic; using Mono.Cecil; +#nullable enable + namespace Mono.Linker { public class SubstitutionInfo { public Dictionary MethodActions { get; } - public Dictionary MethodStubValues { get; } - public Dictionary FieldValues { get; } + public Dictionary MethodStubValues { get; } + public Dictionary FieldValues { get; } public HashSet FieldInit { get; } public SubstitutionInfo () { MethodActions = new Dictionary (); - MethodStubValues = new Dictionary (); - FieldValues = new Dictionary (); + MethodStubValues = new Dictionary (); + FieldValues = new Dictionary (); FieldInit = new HashSet (); } @@ -27,12 +29,12 @@ public void SetMethodAction (MethodDefinition method, MethodAction action) MethodActions[method] = action; } - public void SetMethodStubValue (MethodDefinition method, object value) + public void SetMethodStubValue (MethodDefinition method, object? value) { MethodStubValues[method] = value; } - public void SetFieldValue (FieldDefinition field, object value) + public void SetFieldValue (FieldDefinition field, object? value) { FieldValues[field] = value; } diff --git a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs index 6d05f7861bdff8..9077971cfb40fd 100644 --- a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs @@ -180,6 +180,8 @@ public static TypeReference InflateGenericType (GenericInstanceType genericInsta return genericParameter; var elementType = resolver.TryResolve (genericInstanceProvider.ElementType); + if (elementType == null) + return null; var parameter = elementType.GenericParameters.Single (p => p == genericParameter); return genericInstanceProvider.GenericArguments[parameter.Position]; } diff --git a/src/tools/illink/test/Mono.Linker.Tests/Tests/AnnotationStoreTest.cs b/src/tools/illink/test/Mono.Linker.Tests/Tests/AnnotationStoreTest.cs index 36ee6b5c6bad54..325929981b3ee0 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/Tests/AnnotationStoreTest.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/Tests/AnnotationStoreTest.cs @@ -10,7 +10,7 @@ public class AnnotationStoreTest [SetUp] public void Setup () { - var ctx = new LinkContext (null, new ConsoleLogger ()); + var ctx = new LinkContext (null, new ConsoleLogger (), string.Empty); store = new AnnotationStore (ctx); } diff --git a/src/tools/illink/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs b/src/tools/illink/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs index 8aaafb74986f60..b81d7a6e7651e6 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/Tests/MessageContainerTests.cs @@ -8,7 +8,7 @@ public class MessageContainerTests [Test] public void MSBuildFormat () { - LinkContext context = new LinkContext (new Pipeline (), new ConsoleLogger ()); + LinkContext context = new LinkContext (new Pipeline (), new ConsoleLogger (), string.Empty); var msg = MessageContainer.CreateCustomErrorMessage ("text", 6001); Assert.AreEqual ("ILLink: error IL6001: text", msg.ToMSBuildString ());