From 9c88abd291fafd57076ca4c26deaaf3c6c0a4c7a Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 10 Dec 2020 13:29:23 -0800 Subject: [PATCH] Restrict embedded XML (#1675) * Restrict embedded XML Embedded attributes and substitutions may only modify the containing assembly. * Allow specifying resource name in referenced assembly In the test infrastructure. * Fix formatting * PR feedback - Allow '*' in corelib embedded attribute XML - Reword warning messages - Avoid calling virtual method from ctor * Fix test on mono Macking the core library causes problems for PEVerify: - Removed reference to corelib creates invalid typerefs - System types like Object aren't found * PR feedback * PR feedback --- docs/error-codes.md | 26 ++++++++++ .../Linker.Steps/BodySubstituterStep.cs | 6 +-- src/linker/Linker.Steps/LinkAttributesStep.cs | 24 +++++++-- .../Linker.Steps/ProcessLinkerXmlStepBase.cs | 50 ++++++++++++++---- src/linker/Linker.Steps/ResolveFromXmlStep.cs | 16 +++--- .../Metadata/SetupCompileAfterAttribute.cs | 17 +++++- .../Metadata/SetupCompileBeforeAttribute.cs | 32 ++++++++++-- ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 4 +- ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 4 +- .../EmbeddedAttributeErrorCases.cs | 6 +++ .../EmbeddedAttributeErrorCases.xml | 10 ++++ .../Dependencies/MockCorelib.cs | 14 +++++ .../Dependencies/MockCorelib.xml | 7 +++ .../LinkAttributes/EmbeddedLinkAttributes.cs | 19 ++++++- .../LinkAttributes/EmbeddedLinkAttributes.xml | 7 +++ .../EmbeddedLinkAttributesInCorelib.cs | 52 +++++++++++++++++++ .../LinkAttributes/LinkAttributeErrorCases.cs | 13 +++-- ...eddedLinkXmlFromCopyAssemblyIsProcessed.cs | 2 +- ...sAdditionalAssemblyWithOverriddenMethod.cs | 4 +- .../LinkXml/LinkXmlErrorCases.cs | 1 + .../LinkXml/LinkXmlErrorCases.xml | 3 ++ ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 4 +- ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 4 +- .../EmbeddedLinkXmlFileIsProcessed.xml | 1 + ...cedAssemblyIsNotProcessedIfActionIsCopy.cs | 4 +- ...otProcessedIfNameDoesNotMatchAnAssembly.cs | 4 +- ...rencedAssemblyIsProcessedIfActionIsLink.cs | 4 +- .../EmbeddedLinkXmlFileIsProcessed.cs | 6 +++ .../Dependencies/EmbeddedSubstitutions.xml | 3 ++ .../EmbeddedSubstitutionsErrorCases.cs | 6 +++ .../EmbeddedSubstitutionsErrorCases.xml | 8 +++ .../Substitutions/EmbeddedSubstitutions.cs | 11 ++++ .../Substitutions/SubstitutionsErrorCases.cs | 16 +++++- .../Substitutions/SubstitutionsErrorCases.xml | 2 + .../CanCompileReferencesWithResources.cs | 6 +-- ...anCompileReferencesWithResourcesWithCsc.cs | 6 +-- ...anCompileReferencesWithResourcesWithMcs.cs | 6 +-- .../Extensions/CecilExtensions.cs | 2 +- .../TestCasesRunner/ResultChecker.cs | 10 ++-- .../TestCasesRunner/SetupCompileInfo.cs | 4 +- .../TestCasesRunner/TestCaseMetadaProvider.cs | 25 ++++++++- .../TestCasesRunner/TestCaseSandbox.cs | 16 ++++-- 42 files changed, 389 insertions(+), 76 deletions(-) create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.cs create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.xml create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.cs create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.xml create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributesInCorelib.cs create mode 100644 test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.cs create mode 100644 test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.xml diff --git a/docs/error-codes.md b/docs/error-codes.md index 401a26ef5cc8..3f622124d32e 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -1467,3 +1467,29 @@ This is technically possible if a custom assembly defines `DynamicDependencyAttr [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] object TestProperty { get; set; } ``` + +### 'IL2100': XML contains unsupported wildcard for assembly "fullname" attribute + +- A wildcard "fullname" for an assembly in XML is only valid for link attribute XML on the command-line, not for descriptor or substitution XML or for embedded attribute XML. Specify a specific assembly name instead. + + ```XML + + + + + + + ``` + +### 'IL2101': Embedded XML in assembly 'assembly' contains assembly "fullname" attribute for another assembly 'assembly' + +- Embedded attribute or substitution XML may only contain elements that apply to the containing assembly. Attempting to modify another assembly will not have any effect. + + ```XML + + + + + + + ``` \ No newline at end of file diff --git a/src/linker/Linker.Steps/BodySubstituterStep.cs b/src/linker/Linker.Steps/BodySubstituterStep.cs index 5901f80e8c60..09039c9f0b63 100644 --- a/src/linker/Linker.Steps/BodySubstituterStep.cs +++ b/src/linker/Linker.Steps/BodySubstituterStep.cs @@ -24,10 +24,10 @@ protected override void Process () ProcessXml (Context.StripSubstitutions, Context.IgnoreSubstitutions); } - protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator, bool warnOnUnresolvedTypes) + protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) { - ProcessTypes (assembly, iterator, warnOnUnresolvedTypes); - ProcessResources (assembly, iterator.Current.SelectChildren ("resource", "")); + ProcessTypes (assembly, nav, warnOnUnresolvedTypes); + ProcessResources (assembly, nav.SelectChildren ("resource", "")); } protected override TypeDefinition ProcessExportedType (ExportedType exported, AssemblyDefinition assembly) => null; diff --git a/src/linker/Linker.Steps/LinkAttributesStep.cs b/src/linker/Linker.Steps/LinkAttributesStep.cs index e0be36e38bec..fb70da000dad 100644 --- a/src/linker/Linker.Steps/LinkAttributesStep.cs +++ b/src/linker/Linker.Steps/LinkAttributesStep.cs @@ -197,14 +197,30 @@ protected override void Process () ProcessXml (Context.StripLinkAttributes, Context.IgnoreLinkAttributes); } - protected override bool AllowAllAssembliesSelector { get => true; } + protected override AllowedAssemblies AllowedAssemblySelector { + get { + if (_resourceAssembly == null) + return AllowedAssemblies.AllAssemblies; + + // Corelib XML may contain assembly wildcard to support compiler-injected attribute types +#if NETCOREAPP + const string coreLib = "System.Private.CoreLib"; +#else + const string coreLib = "mscorlib"; +#endif + if (_resourceAssembly.Name.Name == coreLib) + return AllowedAssemblies.AllAssemblies; + + return AllowedAssemblies.ContainingAssembly; + } + } - protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator, bool warnOnUnresolvedTypes) + protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) { - IEnumerable attributes = ProcessAttributes (iterator.Current, assembly); + IEnumerable attributes = ProcessAttributes (nav, assembly); if (attributes.Any ()) Context.CustomAttributes.AddCustomAttributes (assembly, attributes); - ProcessTypes (assembly, iterator, warnOnUnresolvedTypes); + ProcessTypes (assembly, nav, warnOnUnresolvedTypes); } protected override void ProcessType (TypeDefinition type, XPathNavigator nav) diff --git a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs index 264bd821b2f7..7a65547c9045 100644 --- a/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs +++ b/src/linker/Linker.Steps/ProcessLinkerXmlStepBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; @@ -7,6 +7,14 @@ namespace Mono.Linker.Steps { + [Flags] + public enum AllowedAssemblies + { + ContainingAssembly = 0x1, + AnyAssembly = 0x2 | ContainingAssembly, + AllAssemblies = 0x4 | AnyAssembly + } + public abstract class ProcessLinkerXmlStepBase : LoadReferencesStep { const string FullNameAttributeName = "fullname"; @@ -25,7 +33,7 @@ public abstract class ProcessLinkerXmlStepBase : LoadReferencesStep protected readonly string _xmlDocumentLocation; readonly XPathDocument _document; readonly EmbeddedResource _resource; - readonly AssemblyDefinition _resourceAssembly; + protected readonly AssemblyDefinition _resourceAssembly; protected ProcessLinkerXmlStepBase (XPathDocument document, string xmlDocumentLocation) { @@ -44,6 +52,9 @@ protected ProcessLinkerXmlStepBase (XPathDocument document, EmbeddedResource res protected virtual void ProcessXml (bool stripResource, bool ignoreResource) { + if (!AllowedAssemblySelector.HasFlag (AllowedAssemblies.AnyAssembly) && _resourceAssembly == null) + throw new InvalidOperationException ("The containing assembly must be specified for XML which is restricted to modifying that assembly only."); + try { XPathNavigator nav = _document.CreateNavigator (); @@ -63,48 +74,65 @@ protected virtual void ProcessXml (bool stripResource, bool ignoreResource) ProcessAssemblies (nav.SelectChildren ("assembly", "")); + // For embedded XML, allow not specifying the assembly explicitly in XML. + if (_resourceAssembly != null) + ProcessAssembly (_resourceAssembly, nav, warnOnUnresolvedTypes: true); + } catch (Exception ex) when (!(ex is LinkerFatalErrorException)) { throw new LinkerFatalErrorException (MessageContainer.CreateErrorMessage ($"Error processing '{_xmlDocumentLocation}'", 1013), ex); } } - protected virtual bool AllowAllAssembliesSelector { get => false; } + protected virtual AllowedAssemblies AllowedAssemblySelector { get => _resourceAssembly != null ? AllowedAssemblies.ContainingAssembly : AllowedAssemblies.AnyAssembly; } protected virtual void ProcessAssemblies (XPathNodeIterator iterator) { while (iterator.MoveNext ()) { - bool processAllAssemblies = AllowAllAssembliesSelector && GetFullName (iterator.Current) == AllAssembliesFullName; + bool processAllAssemblies = GetFullName (iterator.Current) == AllAssembliesFullName; + if (processAllAssemblies && AllowedAssemblySelector != AllowedAssemblies.AllAssemblies) { + Context.LogWarning ($"XML contains unsupported wildcard for assembly \"fullname\" attribute", 2100, _xmlDocumentLocation); + continue; + } // Errors for invalid assembly names should show up even if this element will be // skipped due to feature conditions. var name = processAllAssemblies ? null : GetAssemblyName (iterator.Current); + AssemblyDefinition assemblyToProcess = null; + if (!AllowedAssemblySelector.HasFlag (AllowedAssemblies.AnyAssembly)) { + if (_resourceAssembly.Name.Name != name.Name) { + Context.LogWarning ($"Embedded XML in assembly '{_resourceAssembly.Name.Name}' contains assembly \"fullname\" attribute for another assembly '{name}'", 2101, _xmlDocumentLocation); + continue; + } + assemblyToProcess = _resourceAssembly; + } + if (!ShouldProcessElement (iterator.Current)) continue; if (processAllAssemblies) { foreach (AssemblyDefinition assembly in Context.GetAssemblies ()) - ProcessAssembly (assembly, iterator, warnOnUnresolvedTypes: false); + ProcessAssembly (assembly, iterator.Current, warnOnUnresolvedTypes: false); } else { - AssemblyDefinition assembly = GetAssembly (Context, name); + AssemblyDefinition assembly = assemblyToProcess ?? GetAssembly (Context, name); if (assembly == null) { Context.LogWarning ($"Could not resolve assembly '{name.Name}'", 2007, _xmlDocumentLocation); continue; } - ProcessAssembly (assembly, iterator, warnOnUnresolvedTypes: true); + ProcessAssembly (assembly, iterator.Current, warnOnUnresolvedTypes: true); } } } - protected abstract void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator, bool warnOnUnresolvedTypes); + protected abstract void ProcessAssembly (AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes); - protected virtual void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator, bool warnOnUnresolvedTypes) + protected virtual void ProcessTypes (AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) { - iterator = iterator.Current.SelectChildren (TypeElementName, XmlNamespace); + var iterator = nav.SelectChildren (TypeElementName, XmlNamespace); while (iterator.MoveNext ()) { - XPathNavigator nav = iterator.Current; + nav = iterator.Current; if (!ShouldProcessElement (nav)) continue; diff --git a/src/linker/Linker.Steps/ResolveFromXmlStep.cs b/src/linker/Linker.Steps/ResolveFromXmlStep.cs index f7cd9a5e59ff..ff8ab43780d4 100644 --- a/src/linker/Linker.Steps/ResolveFromXmlStep.cs +++ b/src/linker/Linker.Steps/ResolveFromXmlStep.cs @@ -67,25 +67,27 @@ protected override void Process () ProcessXml (Context.StripDescriptors, Context.IgnoreDescriptors); } - protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNodeIterator iterator, bool warnOnUnresolvedTypes) + protected override AllowedAssemblies AllowedAssemblySelector { get => AllowedAssemblies.AnyAssembly; } + + protected override void ProcessAssembly (AssemblyDefinition assembly, XPathNavigator nav, bool warnOnUnresolvedTypes) { #if !FEATURE_ILLINK - if (IsExcluded (iterator.Current)) + if (IsExcluded (nav)) return; #endif - if (GetTypePreserve (iterator.Current) == TypePreserve.All) { + if (GetTypePreserve (nav) == TypePreserve.All) { foreach (var type in assembly.MainModule.Types) MarkAndPreserveAll (type); } else { - ProcessTypes (assembly, iterator, warnOnUnresolvedTypes); - ProcessNamespaces (assembly, iterator); + ProcessTypes (assembly, nav, warnOnUnresolvedTypes); + ProcessNamespaces (assembly, nav); } } - void ProcessNamespaces (AssemblyDefinition assembly, XPathNodeIterator iterator) + void ProcessNamespaces (AssemblyDefinition assembly, XPathNavigator nav) { - iterator = iterator.Current.SelectChildren (NamespaceElementName, XmlNamespace); + var iterator = nav.SelectChildren (NamespaceElementName, XmlNamespace); while (iterator.MoveNext ()) { if (!ShouldProcessElement (iterator.Current)) continue; diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs index 60a54a1a8b75..199d9b4951a4 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileAfterAttribute.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Mono.Linker.Tests.Cases.Expectations.Metadata { @@ -8,13 +8,26 @@ namespace Mono.Linker.Tests.Cases.Expectations.Metadata [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] public class SetupCompileAfterAttribute : BaseMetadataAttribute { - public SetupCompileAfterAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, string[] resources = null, string additionalArguments = null, string compilerToUse = null) + public SetupCompileAfterAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null) { if (sourceFiles == null) throw new ArgumentNullException (nameof (sourceFiles)); if (string.IsNullOrEmpty (outputName)) throw new ArgumentException ("Value cannot be null or empty.", nameof (outputName)); + + if (resources != null) { + foreach (var res in resources) { + if (res is string) + continue; + if (res is string[] stringArray) { + if (stringArray.Length != 2) + throw new ArgumentException ("Entry in object[] cannot be a string[] unless it has exactly two elements, for the resource path and name", nameof (resources)); + continue; + } + throw new ArgumentException ("Each value in the object[] must be a string or a string[], either a resource path, or a path and name", nameof (resources)); + } + } } } } diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs index 0ede197cf061..bad07736de2f 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Metadata/SetupCompileBeforeAttribute.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Mono.Linker.Tests.Cases.Expectations.Metadata { @@ -8,22 +8,48 @@ namespace Mono.Linker.Tests.Cases.Expectations.Metadata [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)] public class SetupCompileBeforeAttribute : BaseMetadataAttribute { - public SetupCompileBeforeAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, string[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) + public SetupCompileBeforeAttribute (string outputName, string[] sourceFiles, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) { if (sourceFiles == null) throw new ArgumentNullException (nameof (sourceFiles)); if (string.IsNullOrEmpty (outputName)) throw new ArgumentException ("Value cannot be null or empty.", nameof (outputName)); + + if (resources != null) { + foreach (var res in resources) { + if (res is string) + continue; + if (res is string[] stringArray) { + if (stringArray.Length != 2) + throw new ArgumentException ("Entry in object[] cannot be a string[] unless it has exactly two elements, for the resource path and name", nameof (resources)); + continue; + } + throw new ArgumentException ("Each value in the object[] must be a string or a string[], either a resource path, or a path and name", nameof (resources)); + } + } } - public SetupCompileBeforeAttribute (string outputName, Type[] typesToIncludeSourceFor, string[] references = null, string[] defines = null, string[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) + public SetupCompileBeforeAttribute (string outputName, Type[] typesToIncludeSourceFor, string[] references = null, string[] defines = null, object[] resources = null, string additionalArguments = null, string compilerToUse = null, bool addAsReference = true, bool removeFromLinkerInput = false) { if (typesToIncludeSourceFor == null) throw new ArgumentNullException (nameof (typesToIncludeSourceFor)); if (string.IsNullOrEmpty (outputName)) throw new ArgumentException ("Value cannot be null or empty.", nameof (outputName)); + + if (resources != null) { + foreach (var res in resources) { + if (res is string) + continue; + if (res is string[] stringArray) { + if (stringArray.Length != 2) + throw new ArgumentException ("Entry in object[] cannot be a string[] unless it has exactly two elements, for the resource path and name", nameof (resources)); + continue; + } + throw new ArgumentException ("Each value in the object[] must be a string or a string[], either a resource path, or a path and name", nameof (resources)); + } + } } } } diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs index b596ad04c671..bc66f59da446 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; using Mono.Linker.Tests.Cases.Expectations.Assertions; @@ -15,7 +15,7 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies "DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, - resources: new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" }, + resources: new object[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" }, addAsReference: false)] [KeptAssembly ("base.dll")] [RemovedMemberInAssembly ("DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "UnusedMethod()")] diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs index 747e3362da22..a1bbb263dcb5 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; using Mono.Linker.Tests.Cases.Expectations.Assertions; @@ -15,7 +15,7 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies "DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, - resources: new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" }, + resources: new object[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" }, addAsReference: false)] [KeptAssembly ("base.dll")] [RemovedAssembly ("DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll")] diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.cs new file mode 100644 index 000000000000..9943876b4284 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.cs @@ -0,0 +1,6 @@ +namespace Mono.Linker.Tests.Cases.LinkAttributes.Dependencies +{ + public class EmbeddedAttributeErrorCases + { + } +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.xml new file mode 100644 index 000000000000..bdf245917a7e --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/EmbeddedAttributeErrorCases.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.cs new file mode 100644 index 000000000000..cd6e37a01c39 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.cs @@ -0,0 +1,14 @@ +#if INCLUDE_MOCK_CORELIB + +using System; + +[assembly: MockCorelibAttributeToRemove] + +namespace System +{ + public class MockCorelibAttributeToRemove : Attribute + { + } +} + +#endif \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.xml new file mode 100644 index 000000000000..203be555ed03 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/MockCorelib.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.cs index 5a5f8e6811a8..b4c5f8d3ac93 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.cs +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.cs @@ -3,9 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Text; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; @@ -22,6 +20,7 @@ public static void Main () var instance = new EmbeddedLinkAttributes (); instance.ReadFromInstanceField (); + instance.ReadFromInstanceField2 (); } Type _typeWithPublicParameterlessConstructor; @@ -52,5 +51,21 @@ private void ReadFromInstanceField () Type type) { } + + Type _typeWithPublicFields; + + [UnrecognizedReflectionAccessPattern (typeof (EmbeddedLinkAttributes), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [RecognizedReflectionAccessPattern] + private void ReadFromInstanceField2 () + { + RequirePublicConstructors (_typeWithPublicFields); + RequirePublicFields (_typeWithPublicFields); + } + + private static void RequirePublicFields ( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + Type type) + { + } } } diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml index 6a3c143dca95..00916a33816d 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml @@ -8,4 +8,11 @@ + + + + PublicFields + + + diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributesInCorelib.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributesInCorelib.cs new file mode 100644 index 000000000000..3453597c29c9 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributesInCorelib.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace System +{ + public class MockCorelibAttributeToRemove : Attribute + { + } +} + +namespace Mono.Linker.Tests.Cases.LinkAttributes +{ + [IgnoreLinkAttributes (false)] + [SetupLinkerCoreAction ("link")] // Ensure that corelib gets linked so that its attribtues are processed + [SetupLinkerArgument ("--skip-unresolved", "true")] // Allow unresolved references to types missing from mock corelib + [SetupCompileBefore (PlatformAssemblies.CoreLib, new string[] { "Dependencies/MockCorelib.cs" }, + resources: new object[] { new string[] { "Dependencies/MockCorelib.xml", "ILLink.LinkAttributes.xml" } }, + defines: new[] { "INCLUDE_MOCK_CORELIB" })] + [SkipPeVerify] +#if NETCOREAPP + [RemovedAttributeInAssembly ("System.Private.CoreLib", "System.MockCorelibAttributeToRemove")] + [RemovedTypeInAssembly ("System.Private.CoreLib", "System.MockCorelibAttributeToRemove")] +#else + [RemovedAttributeInAssembly ("mscorlib", "System.MockCorelibAttributeToRemove")] + [RemovedTypeInAssembly ("mscorlib", "System.MockCorelibAttributeToRemove")] +#endif + class EmbeddedLinkAttributesInCorelib + { + public static void Main () + { + AttributedMethod (); + var _ = new AttributedClass (); + } + + [Kept] + [MockCorelibAttributeToRemove] + public static void AttributedMethod () + { + } + + [Kept] + [KeptMember (".ctor()")] + [MockCorelibAttributeToRemove] + public class AttributedClass + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs index 3d9e90262064..6f2e214f7d2b 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs @@ -1,14 +1,15 @@ using System; -using System.Collections.Generic; -using System.Text; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.LinkAttributes.Dependencies; namespace Mono.Linker.Tests.Cases.LinkAttributes { [SetupLinkAttributesFile ("LinkAttributeErrorCases.xml")] [IgnoreLinkAttributes (false)] [SetupLinkerArgument ("--skip-unresolved", "true")] + [SetupCompileBefore ("library.dll", new string[] { "Dependencies/EmbeddedAttributeErrorCases.cs" }, + resources: new object[] { new string[] { "Dependencies/EmbeddedAttributeErrorCases.xml", "ILLink.LinkAttributes.xml" } })] [ExpectedWarning ("IL2007", "NonExistentAssembly2", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2030", "NonExistentAssembly1", FileName = "LinkAttributeErrorCases.xml")] @@ -24,11 +25,13 @@ namespace Mono.Linker.Tests.Cases.LinkAttributes [ExpectedWarning ("IL2051", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2052", "NonExistentPropertyName", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2053", "StringValue", "IntProperty", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2100", FileName = "ILLink.LinkAttributes.xml")] + [ExpectedWarning ("IL2101", "library", "test", FileName = "ILLink.LinkAttributes.xml")] class LinkAttributeErrorCases { public static void Main () { - + var _ = new EmbeddedAttributeErrorCases (); } public enum AttributeEnum @@ -72,5 +75,9 @@ public class SecondAttribute : Attribute { } public Type GetTypeMethod () => null; public void MethodWithParameter (int methodParameter) { } + + public class ReferencedFromOtherAssembly + { + } } } diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlFromCopyAssemblyIsProcessed.cs b/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlFromCopyAssemblyIsProcessed.cs index a5e3271042de..96d7e941f6a4 100644 --- a/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlFromCopyAssemblyIsProcessed.cs +++ b/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlFromCopyAssemblyIsProcessed.cs @@ -8,7 +8,7 @@ namespace Mono.Linker.Tests.Cases.LinkXml new[] { "Dependencies/EmbeddedLinkXmlFromCopyAssemblyIsProcessed/OtherLibrary.cs" })] [SetupCompileBefore ("CopyLibrary.dll", new[] { "Dependencies/EmbeddedLinkXmlFromCopyAssemblyIsProcessed/CopyLibrary.cs" }, - resources: new[] { "Dependencies/EmbeddedLinkXmlFromCopyAssemblyIsProcessed/CopyLibrary.xml" })] + resources: new object[] { "Dependencies/EmbeddedLinkXmlFromCopyAssemblyIsProcessed/CopyLibrary.xml" })] [IgnoreDescriptors (false)] [SetupLinkerAction ("copy", "CopyLibrary")] diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod.cs b/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod.cs index 37a8265ea0a7..99fa7f39e150 100644 --- a/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod.cs +++ b/test/Mono.Linker.Tests.Cases/LinkXml/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.LinkXml.Dependencies.EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod; @@ -9,7 +9,7 @@ namespace Mono.Linker.Tests.Cases.LinkXml [SetupCompileBefore ("Library1.dll", new[] { "Dependencies/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod/Library1.cs" }, new[] { "Base.dll" }, - resources: new[] { "Dependencies/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod/Library1.xml" })] + resources: new object[] { "Dependencies/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod/Library1.xml" })] [SetupCompileBefore ("Library2.dll", new[] { "Dependencies/EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod/Library2.cs" }, new[] { "Base.dll" }, diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs index 6b5303a5dfea..cd737ab4cd9a 100644 --- a/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs +++ b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs @@ -20,6 +20,7 @@ namespace Mono.Linker.Tests.Cases.LinkXml [ExpectedWarning ("IL2025", "Event", FileName = "LinkXmlErrorCases.xml")] [ExpectedWarning ("IL2025", "Field", FileName = "LinkXmlErrorCases.xml")] [ExpectedWarning ("IL2025", "Property", FileName = "LinkXmlErrorCases.xml")] + [ExpectedWarning ("IL2100", FileName = "LinkXmlErrorCases.xml")] class LinkXmlErrorCases { public static void Main () diff --git a/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml index dca7c7d2d735..9ae9842be0e3 100644 --- a/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml +++ b/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.xml @@ -43,4 +43,7 @@ + + + diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs index d7bd3c54fedc..2c3e4cebef42 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies; @@ -15,7 +15,7 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies "PreserveDependencyMethodInNonReferencedAssemblyLibrary.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, - resources: new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.xml" }, + resources: new object[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.xml" }, addAsReference: false)] [KeptAssembly ("base.dll")] [RemovedMemberInAssembly ("PreserveDependencyMethodInNonReferencedAssemblyLibrary.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInNonReferencedAssemblyLibrary", "UnusedMethod()")] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs index 770657112366..b9faa471676c 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies; @@ -15,7 +15,7 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies "PreserveDependencyMethodInNonReferencedAssemblyLibrary.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, - resources: new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.xml" }, + resources: new object[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.xml" }, addAsReference: false)] [KeptAssembly ("base.dll")] [RemovedAssembly ("PreserveDependencyMethodInNonReferencedAssemblyLibrary.dll")] diff --git a/test/Mono.Linker.Tests.Cases/Resources/Dependencies/EmbeddedLinkXmlFileIsProcessed.xml b/test/Mono.Linker.Tests.Cases/Resources/Dependencies/EmbeddedLinkXmlFileIsProcessed.xml index 518addf3df29..2b04a8f94926 100644 --- a/test/Mono.Linker.Tests.Cases/Resources/Dependencies/EmbeddedLinkXmlFileIsProcessed.xml +++ b/test/Mono.Linker.Tests.Cases/Resources/Dependencies/EmbeddedLinkXmlFileIsProcessed.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy.cs b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy.cs index ebf100b07cc3..2fdd8238d6da 100644 --- a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy.cs +++ b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.Resources.Dependencies; @@ -7,7 +7,7 @@ namespace Mono.Linker.Tests.Cases.Resources [SetupCompileBefore ( "EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy_Lib1.dll", new[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy_Lib1.cs" }, - resources: new[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy_Lib1.xml" })] + resources: new object[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy_Lib1.xml" })] [SetupLinkerAction ("copy", "EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfActionIsCopy_Lib1")] [IgnoreDescriptors (false)] diff --git a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly.cs b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly.cs index 1dcbe78704b1..1dc2741862df 100644 --- a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.Resources.Dependencies; @@ -7,7 +7,7 @@ namespace Mono.Linker.Tests.Cases.Resources [SetupCompileBefore ( "library.dll", new[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly_Lib1.cs" }, - resources: new[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly_Lib1_NotMatchingName.xml" })] + resources: new object[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly_Lib1_NotMatchingName.xml" })] [IgnoreDescriptors (false)] [KeptResourceInAssembly ("library.dll", "EmbeddedLinkXmlFileInReferencedAssemblyIsNotProcessedIfNameDoesNotMatchAnAssembly_Lib1_NotMatchingName.xml")] diff --git a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink.cs b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink.cs index c8926980b39d..b1e45f2506f5 100644 --- a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink.cs +++ b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.Resources.Dependencies; @@ -7,7 +7,7 @@ namespace Mono.Linker.Tests.Cases.Resources [SetupCompileBefore ( "EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink_Lib1.dll", new[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink_Lib1.cs" }, - resources: new[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink_Lib1.xml" })] + resources: new object[] { "Dependencies/EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink_Lib1.xml" })] [SetupLinkerAction ("link", "EmbeddedLinkXmlFileInReferencedAssemblyIsProcessedIfActionIsLink_Lib1")] [IgnoreDescriptors (false)] diff --git a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileIsProcessed.cs b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileIsProcessed.cs index ae502329cdc0..170ad28ddfd0 100644 --- a/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileIsProcessed.cs +++ b/test/Mono.Linker.Tests.Cases/Resources/EmbeddedLinkXmlFileIsProcessed.cs @@ -19,5 +19,11 @@ public static void Main () public class Unused { } + + [Kept] + [KeptMember (".ctor()")] + public class Unused2 + { + } } } diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutions.xml b/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutions.xml index 3bd0175a6485..00c9a0e583a7 100644 --- a/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutions.xml +++ b/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutions.xml @@ -4,4 +4,7 @@ + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.cs b/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.cs new file mode 100644 index 000000000000..ad0331b4fe62 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.cs @@ -0,0 +1,6 @@ +namespace Mono.Linker.Tests.Cases.Substitutions.Dependencies +{ + public class EmbeddedSubstitutionsErrorCases + { + } +} diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.xml b/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.xml new file mode 100644 index 000000000000..fdf8c332a264 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Substitutions/Dependencies/EmbeddedSubstitutionsErrorCases.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/EmbeddedSubstitutions.cs b/test/Mono.Linker.Tests.Cases/Substitutions/EmbeddedSubstitutions.cs index 3306aee24d1b..3faba8259c33 100644 --- a/test/Mono.Linker.Tests.Cases/Substitutions/EmbeddedSubstitutions.cs +++ b/test/Mono.Linker.Tests.Cases/Substitutions/EmbeddedSubstitutions.cs @@ -11,6 +11,7 @@ public class EmbeddedSubstitutions public static void Main () { ConvertToThrowMethod (); + ConvertToThrowMethod2 (); } [Kept] @@ -22,5 +23,15 @@ public static void Main () public static void ConvertToThrowMethod () { } + + [Kept] + [ExpectedInstructionSequence (new[] { + "ldstr", + "newobj", + "throw" + })] + public static void ConvertToThrowMethod2 () + { + } } } diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs index 1789eb9634d4..2aa9c306488c 100644 --- a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs +++ b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.cs @@ -1,10 +1,13 @@ -using System; -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.Substitutions.Dependencies; namespace Mono.Linker.Tests.Cases.Substitutions { [SetupLinkerSubstitutionFile ("SubstitutionsErrorCases.xml")] + [IgnoreSubstitutions (false)] + [SetupCompileBefore ("library.dll", new string[] { "Dependencies/EmbeddedSubstitutionsErrorCases.cs" }, + resources: new object[] { new string[] { "Dependencies/EmbeddedSubstitutionsErrorCases.xml", "ILLink.Substitutions.xml" } })] [ExpectedWarning ("IL2010", "TestMethod_1", "stub", FileName = "SubstitutionsErrorCases.xml")] [ExpectedWarning ("IL2011", "TestMethod_2", "noaction", FileName = "SubstitutionsErrorCases.xml")] @@ -12,6 +15,8 @@ namespace Mono.Linker.Tests.Cases.Substitutions [ExpectedWarning ("IL2014", "SubstitutionsErrorCases::IntField", FileName = "SubstitutionsErrorCases.xml")] [ExpectedWarning ("IL2015", "SubstitutionsErrorCases::IntField", "NonNumber", FileName = "SubstitutionsErrorCases.xml")] [ExpectedWarning ("IL2007", "NonExistentAssembly", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2100", FileName = "SubstitutionsErrorCases.xml")] + [ExpectedWarning ("IL2101", "library", "test", FileName = "ILLink.Substitutions.xml")] [KeptMember (".ctor()")] class SubstitutionsErrorCases @@ -24,6 +29,8 @@ public static void Main () var instance = new SubstitutionsErrorCases (); instance.InstanceField = 42; IntField = 42; + + var _ = new EmbeddedSubstitutionsErrorCases (); } [Kept] @@ -37,5 +44,10 @@ public static void Main () [Kept] public static int IntField; + + public class ReferencedFromOtherAssembly + { + public static int TestMethod () { return 42; } + } } } diff --git a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml index 272ccbc30af3..f39691a204a5 100644 --- a/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml +++ b/test/Mono.Linker.Tests.Cases/Substitutions/SubstitutionsErrorCases.xml @@ -11,4 +11,6 @@ + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResources.cs b/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResources.cs index b6bfba94abcd..bcbc70ec5418 100644 --- a/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResources.cs +++ b/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResources.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.TestFramework.Dependencies; @@ -6,12 +6,12 @@ namespace Mono.Linker.Tests.Cases.TestFramework { [SetupCompileBefore ("library.dll", new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.cs" }, - resources: new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt" })] + resources: new object[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt" })] // Compile the same assembly again with another resource to get coverage on SetupCompileAfter [SetupCompileAfter ("library.dll", new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.cs" }, - resources: new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt", "Dependencies/CanCompileReferencesWithResources_Lib1.log" })] + resources: new object[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt", "Dependencies/CanCompileReferencesWithResources_Lib1.log" })] [KeptResourceInAssembly ("library.dll", "CanCompileReferencesWithResources_Lib1.txt")] [KeptResourceInAssembly ("library.dll", "CanCompileReferencesWithResources_Lib1.log")] diff --git a/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithCsc.cs b/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithCsc.cs index 62431c05b152..845f353dadcb 100644 --- a/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithCsc.cs +++ b/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithCsc.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.TestFramework.Dependencies; @@ -6,13 +6,13 @@ namespace Mono.Linker.Tests.Cases.TestFramework { [SetupCompileBefore ("library.dll", new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.cs" }, - resources: new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt" }, + resources: new object[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt" }, compilerToUse: "csc")] // Compile the same assembly again with another resource to get coverage on SetupCompileAfter [SetupCompileAfter ("library.dll", new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.cs" }, - resources: new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt", "Dependencies/CanCompileReferencesWithResources_Lib1.log" }, + resources: new object[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt", "Dependencies/CanCompileReferencesWithResources_Lib1.log" }, compilerToUse: "csc")] [KeptResourceInAssembly ("library.dll", "CanCompileReferencesWithResources_Lib1.txt")] diff --git a/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithMcs.cs b/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithMcs.cs index 4b6a828d08a1..d166fb115a8c 100644 --- a/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithMcs.cs +++ b/test/Mono.Linker.Tests.Cases/TestFramework/CanCompileReferencesWithResourcesWithMcs.cs @@ -1,4 +1,4 @@ -using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.TestFramework.Dependencies; @@ -9,13 +9,13 @@ namespace Mono.Linker.Tests.Cases.TestFramework #endif [SetupCompileBefore ("library.dll", new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.cs" }, - resources: new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt" }, + resources: new object[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt" }, compilerToUse: "mcs")] // Compile the same assembly again with another resource to get coverage on SetupCompileAfter [SetupCompileAfter ("library.dll", new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.cs" }, - resources: new[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt", "Dependencies/CanCompileReferencesWithResources_Lib1.log" }, + resources: new object[] { "Dependencies/CanCompileReferencesWithResources_Lib1.txt", "Dependencies/CanCompileReferencesWithResources_Lib1.log" }, compilerToUse: "mcs")] [KeptResourceInAssembly ("library.dll", "CanCompileReferencesWithResources_Lib1.txt")] diff --git a/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs b/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs index 598d28789484..f188033773ac 100644 --- a/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs +++ b/test/Mono.Linker.Tests/Extensions/CecilExtensions.cs @@ -109,7 +109,7 @@ public static bool DerivesFrom (this TypeDefinition type, string baseTypeName) if (type.BaseType.Name == baseTypeName) return true; - return type.BaseType.Resolve ().DerivesFrom (baseTypeName); + return type.BaseType.Resolve ()?.DerivesFrom (baseTypeName) ?? false; } public static PropertyDefinition GetPropertyDefinition (this MethodDefinition method) diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index d4024f24f284..ab7eb2da6027 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -708,7 +708,7 @@ void VerifyRecordedDependencies (AssemblyDefinition original, TestDependencyReco { foreach (var typeWithRemoveInAssembly in original.AllDefinedTypes ()) { foreach (var attr in typeWithRemoveInAssembly.CustomAttributes) { - if (attr.AttributeType.Resolve ().Name == nameof (DependencyRecordedAttribute)) { + if (attr.AttributeType.Resolve ()?.Name == nameof (DependencyRecordedAttribute)) { var expectedSource = (string) attr.ConstructorArguments[0].Value; var expectedTarget = (string) attr.ConstructorArguments[1].Value; var expectedMarked = (string) attr.ConstructorArguments[2].Value; @@ -758,7 +758,7 @@ void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflecti foreach (var expectedSourceMemberDefinition in original.MainModule.AllDefinedTypes ().SelectMany (t => t.AllMembers ().Append (t)).Distinct ()) { bool foundAttributesToVerify = false; foreach (var attr in expectedSourceMemberDefinition.CustomAttributes) { - if (attr.AttributeType.Resolve ().Name == nameof (RecognizedReflectionAccessPatternAttribute)) { + if (attr.AttributeType.Resolve ()?.Name == nameof (RecognizedReflectionAccessPatternAttribute)) { foundAttributesToVerify = true; // Special case for default .ctor - just trigger the overall verification on the method @@ -800,7 +800,7 @@ void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflecti $"Potential patterns matching the reflection member: {Environment.NewLine}{reflectionMemberCandidates}{Environment.NewLine}" + $"If there's no matches, try to specify just a part of the source member or reflection member name and rerun the test to get potential matches."); } - } else if (attr.AttributeType.Resolve ().Name == nameof (UnrecognizedReflectionAccessPatternAttribute) && + } else if (attr.AttributeType.Resolve ()?.Name == nameof (UnrecognizedReflectionAccessPatternAttribute) && attr.ConstructorArguments[0].Type.MetadataType != MetadataType.String) { foundAttributesToVerify = true; string expectedSourceMember = GetFullMemberNameFromDefinition (expectedSourceMemberDefinition); @@ -881,7 +881,7 @@ void VerifyRecordedReflectionPatterns (AssemblyDefinition original, TestReflecti foreach (var typeToVerify in original.MainModule.AllDefinedTypes ()) { foreach (var attr in typeToVerify.CustomAttributes) { - if (attr.AttributeType.Resolve ().Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute)) { + if (attr.AttributeType.Resolve ()?.Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute)) { // By now all verified recorded patterns were removed from the test recorder lists, so validate // that there are no remaining patterns for this type. var recognizedPatternsForType = reflectionPatternRecorder.RecognizedPatterns @@ -1071,7 +1071,7 @@ protected virtual void UnhandledOtherAssemblyAssertion (string expectedTypeName, bool IsTypeInOtherAssemblyAssertion (CustomAttribute attr) { - return attr.AttributeType.Resolve ().DerivesFrom (nameof (BaseInAssemblyAttribute)); + return attr.AttributeType.Resolve ()?.DerivesFrom (nameof (BaseInAssemblyAttribute)) ?? false; } bool HasAttribute (ICustomAttributeProvider caProvider, string attributeName) diff --git a/test/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs b/test/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs index 7f1e92b6439e..da329fbb1f79 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/SetupCompileInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using Mono.Linker.Tests.Extensions; namespace Mono.Linker.Tests.TestCasesRunner @@ -9,7 +9,7 @@ public class SetupCompileInfo public NPath[] SourceFiles; public string[] Defines; public string[] References; - public NPath[] Resources; + public SourceAndDestinationPair[] Resources; public string AdditionalArguments; public string CompilerToUse; public bool AddAsReference; diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs index e1474914d695..5f0e362ec35b 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -329,7 +329,7 @@ private SetupCompileInfo CreateSetupCompileAssemblyInfo (CustomAttribute attribu SourceFiles = SourceFilesForAttributeArgument (ctorArguments[1]), References = ((CustomAttributeArgument[]) ctorArguments[2].Value)?.Select (arg => arg.Value.ToString ()).ToArray (), Defines = ((CustomAttributeArgument[]) ctorArguments[3].Value)?.Select (arg => arg.Value.ToString ()).ToArray (), - Resources = ((CustomAttributeArgument[]) ctorArguments[4].Value)?.Select (arg => MakeSourceTreeFilePathAbsolute (arg.Value.ToString ())).ToArray (), + Resources = ResourcesForAttributeArgument (ctorArguments[4]), AdditionalArguments = (string) ctorArguments[5].Value, CompilerToUse = (string) ctorArguments[6].Value, AddAsReference = ctorArguments.Count >= 8 ? (bool) ctorArguments[7].Value : true, @@ -350,6 +350,27 @@ protected NPath[] SourceFilesForAttributeArgument (CustomAttributeArgument attri .ToArray (); } + protected SourceAndDestinationPair[] ResourcesForAttributeArgument (CustomAttributeArgument attributeArgument) + { + return ((CustomAttributeArgument[]) attributeArgument.Value) + ?.Select (arg => { + var referenceArg = (CustomAttributeArgument) arg.Value; + if (referenceArg.Value is string source) { + var fullSource = MakeSourceTreeFilePathAbsolute (source); + return new SourceAndDestinationPair { + Source = fullSource, + DestinationFileName = fullSource.FileName + }; + } + var sourceAndDestination = (CustomAttributeArgument[]) referenceArg.Value; + return new SourceAndDestinationPair { + Source = MakeSourceTreeFilePathAbsolute (sourceAndDestination[0].Value.ToString ()), + DestinationFileName = sourceAndDestination[1].Value.ToString () + }; + }) + ?.ToArray (); + } + protected virtual NPath SourceFileForAttributeArgumentValue (object value) { if (value is TypeReference valueAsTypeRef) { diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs index 5c8b2900f67f..5ad5eed4df50 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseSandbox.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using Mono.Linker.Tests.Cases.Expectations.Assertions; @@ -113,7 +113,12 @@ public virtual void Populate (TestCaseMetadaProvider metadataProvider) compileRefInfo.SourceFiles.Copy (destination); destination = BeforeReferenceResourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists (); - compileRefInfo.Resources?.Copy (destination); + + if (compileRefInfo.Resources == null) + continue; + + foreach (var res in compileRefInfo.Resources) + res.Source.FileMustExist ().Copy (destination.Combine (res.DestinationFileName)); } foreach (var compileRefInfo in metadataProvider.GetSetupCompileAssembliesAfter ()) { @@ -121,7 +126,12 @@ public virtual void Populate (TestCaseMetadaProvider metadataProvider) compileRefInfo.SourceFiles.Copy (destination); destination = AfterReferenceResourceDirectoryFor (compileRefInfo.OutputName).EnsureDirectoryExists (); - compileRefInfo.Resources?.Copy (destination); + + if (compileRefInfo.Resources == null) + continue; + + foreach (var res in compileRefInfo.Resources) + res.Source.FileMustExist ().Copy (destination.Combine (res.DestinationFileName)); } }