return TestNamesBySuiteName ();
}
+ public static IEnumerable<object[]> InlineArrays ()
+ {
+ return TestNamesBySuiteName();
+ }
+
public static IEnumerable<object[]> LinkXml()
{
return TestNamesBySuiteName();
}
[Theory]
+ [MemberData(nameof(TestDatabase.InlineArrays), MemberType = typeof(TestDatabase))]
+ public void InlineArrays(string t)
+ {
+ Run(t);
+ }
+
+ [Theory]
[MemberData (nameof (TestDatabase.LinkXml), MemberType = typeof (TestDatabase))]
public void LinkXml (string t)
{
yield return Path.Combine (referenceDir, "mscorlib.dll");
yield return Path.Combine (referenceDir, "System.Collections.dll");
+ yield return Path.Combine (referenceDir, "System.Collections.Immutable.dll");
yield return Path.Combine (referenceDir, "System.ComponentModel.TypeConverter.dll");
yield return Path.Combine (referenceDir, "System.Console.dll");
yield return Path.Combine (referenceDir, "System.Linq.Expressions.dll");
+ yield return Path.Combine (referenceDir, "System.Memory.dll");
yield return Path.Combine (referenceDir, "System.ObjectModel.dll");
yield return Path.Combine (referenceDir, "System.Runtime.dll");
yield return Path.Combine (referenceDir, "System.Runtime.Extensions.dll");
if (type?.HasFields != true)
return;
- // keep fields for types with explicit layout and for enums
- if (!type.IsAutoLayout || type.IsEnum)
+ // keep fields for types with explicit layout, for enums and for InlineArray types
+ if (!type.IsAutoLayout || type.IsEnum || TypeIsInlineArrayType(type))
MarkFields (type, includeStatic: type.IsEnum, reason: new DependencyInfo (DependencyKind.MemberOfType, type));
}
+ static bool TypeIsInlineArrayType(TypeDefinition type)
+ {
+ if (!type.IsValueType)
+ return false;
+
+ foreach (var customAttribute in type.CustomAttributes)
+ if (customAttribute.AttributeType.IsTypeOf ("System.Runtime.CompilerServices", "InlineArrayAttribute"))
+ return true;
+
+ return false;
+ }
+
protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type)
{
if (Annotations.IsInstantiated (type))
}
[Fact]
+ public Task InlineArrayDataflow ()
+ {
+ return RunTest ();
+ }
+
+ [Fact]
public Task MakeGenericDataFlow ()
{
return RunTest ();
--- /dev/null
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Threading.Tasks;
+using Xunit;
+
+namespace ILLink.RoslynAnalyzer.Tests
+{
+ public sealed partial class InlineArraysTests : LinkerTestBase
+ {
+ protected override string TestSuiteName => "InlineArrays";
+
+ [Fact]
+ public Task InlineArray ()
+ {
+ return RunTest (nameof (InlineArray));
+ }
+
+ }
+}
--- /dev/null
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.DataFlow
+{
+ [SkipKeptItemsValidation]
+ [ExpectedNoWarnings]
+ public class InlineArrayDataflow
+ {
+ public static void Main()
+ {
+ AccessPrimitiveTypeArray ();
+ AccessUnannotatedTypeArray ();
+ AccessAnnotatedTypeArray ();
+ }
+
+ public int TestProperty { get; set; }
+
+ [InlineArray (5)]
+ struct PrimitiveTypeArray
+ {
+ public BindingFlags value;
+ }
+
+ // This case will fallback to not understanding the binding flags and will end up marking all properties
+ static void AccessPrimitiveTypeArray ()
+ {
+ PrimitiveTypeArray a = new PrimitiveTypeArray ();
+ ref var item = ref a[1];
+ item = BindingFlags.Public;
+
+ typeof (InlineArrayDataflow).GetProperty (nameof (TestProperty), a[1]);
+ }
+
+ [InlineArray (5)]
+ struct UnannotatedTypeArray
+ {
+ public Type value;
+ }
+
+ // Analyzer doesn't understand inline arrays currently - so it doesn't produce a warning here
+ [ExpectedWarning ("IL2065", "GetProperty", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
+ static void AccessUnannotatedTypeArray ()
+ {
+ UnannotatedTypeArray a = new UnannotatedTypeArray ();
+ ref var item = ref a[2];
+ item = typeof (InlineArrayDataflow);
+
+ a[2].GetProperty (nameof (TestProperty));
+ }
+
+ [InlineArray (5)]
+ struct AnnotatedTypeArray
+ {
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)]
+ public Type value;
+ }
+
+ // Currently tracking of annotations on inline array values is not implemented
+ [ExpectedWarning("IL2065", "GetProperty", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
+ static void AccessAnnotatedTypeArray ()
+ {
+ AnnotatedTypeArray a = new AnnotatedTypeArray ();
+ ref var item = ref a[3];
+ item = typeof (InlineArrayDataflow);
+
+ a[3].GetProperty (nameof (TestProperty));
+ }
+ }
+}
--- /dev/null
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Collections.Immutable;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+
+namespace Mono.Linker.Tests.Cases.InlineArrays
+{
+ [ExpectedNoWarnings]
+ public class InlineArray
+ {
+ public static void Main()
+ {
+ InlineArrayUsage.Test ();
+ CollectionLiteralsOfArrays.Test ();
+ }
+
+ [Kept]
+ class InlineArrayUsage
+ {
+ // NativeAOT will remove most of the struct type information as it's not needed
+ // in the generated native code. Eventually we might come up with a better test infra to validate this.
+ [Kept (By = Tool.Trimmer)]
+ public struct StructWithFixedBuffer
+ {
+ [Kept (By = Tool.Trimmer)]
+ public FixedBuffer Buffer;
+
+ [Kept (By = Tool.Trimmer)]
+ [KeptAttributeAttribute (typeof(InlineArrayAttribute), By = Tool.Trimmer)]
+ [InlineArray (8)]
+ public partial struct FixedBuffer
+ {
+ [Kept (By = Tool.Trimmer)]
+ public int e0;
+ }
+ }
+
+ [Kept (By = Tool.Trimmer)]
+ public struct StructWithAutoLayoutBuffer
+ {
+ [Kept (By = Tool.Trimmer)]
+ public AutoLayoutBuffer Buffer;
+
+ [Kept (By = Tool.Trimmer)]
+ [KeptAttributeAttribute (typeof (InlineArrayAttribute), By = Tool.Trimmer)]
+ [InlineArray (8)]
+ [StructLayout (LayoutKind.Auto)]
+ public struct AutoLayoutBuffer
+ {
+ [Kept (By = Tool.Trimmer)]
+ public int e0;
+ }
+ }
+
+ [Kept]
+ public static void Test ()
+ {
+ var s = new StructWithFixedBuffer ();
+ s.Buffer[0] = 5;
+
+ var sa = new StructWithAutoLayoutBuffer ();
+ _ = sa.Buffer[1];
+ }
+ }
+
+ [Kept]
+ [KeptMember (".cctor()")]
+ class CollectionLiteralsOfArrays
+ {
+ [Kept]
+ public static readonly ImmutableArray<string> ImmutableValues = ["one", "two"];
+ [Kept]
+ public static readonly string[] ArrayValues = ["one", "two"];
+
+ [Kept]
+ public static void Test()
+ {
+ _ = CollectionLiteralsOfArrays.ImmutableValues[0];
+ _ = CollectionLiteralsOfArrays.ArrayValues[1];
+ }
+ }
+ }
+}
return NUnitCasesBySuiteName ("Inheritance.VirtualMethods");
}
+ public static IEnumerable<TestCaseData> InlineArrayTests ()
+ {
+ return NUnitCasesBySuiteName ("InlineArrays");
+ }
+
public static IEnumerable<TestCaseData> InteropTests ()
{
return NUnitCasesBySuiteName ("Interop");
Run (testCase);
}
+ [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.InlineArrayTests))]
+ public void InlineArrayTests (TestCase testCase)
+ {
+ Run (testCase);
+ }
+
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.InteropTests))]
public void InteropTests (TestCase testCase)
{
yield return Path.Combine (referenceDir, "mscorlib.dll");
yield return Path.Combine (referenceDir, "System.Collections.dll");
+ yield return Path.Combine (referenceDir, "System.Collections.Immutable.dll");
yield return Path.Combine (referenceDir, "System.ComponentModel.TypeConverter.dll");
yield return Path.Combine (referenceDir, "System.Console.dll");
yield return Path.Combine (referenceDir, "System.Linq.Expressions.dll");
+ yield return Path.Combine (referenceDir, "System.Memory.dll");
yield return Path.Combine (referenceDir, "System.ObjectModel.dll");
yield return Path.Combine (referenceDir, "System.Runtime.dll");
yield return Path.Combine (referenceDir, "System.Runtime.Extensions.dll");