From 6e3bdb5eeb619b281041fa4b22b27137adf12657 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 16 Jun 2026 17:34:08 +0200 Subject: [PATCH 1/3] [Mono.Android] Compile RuntimeFeature into a single assembly `Microsoft.Android.Runtime.RuntimeFeature` was compiled into both `Mono.Android.Runtime.dll` and `Mono.Android.dll`. Because `Mono.Android` references `Mono.Android.Runtime` (which exposes its internals to `Mono.Android` via `InternalsVisibleTo`), building `Mono.Android.dll` emitted 58 `CS0436` warnings: warning CS0436: The type 'RuntimeFeature' in 'src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs' conflicts with the imported type 'RuntimeFeature' in 'Mono.Android.Runtime'. Compile `RuntimeFeature.cs` only into `Mono.Android.Runtime.dll` (the lower-level assembly that already owns it) and let the other assemblies use it through `InternalsVisibleTo`: * Remove the duplicate `` from `Mono.Android.csproj`. * Grant `Mono.Android.Runtime` internals to `Microsoft.Android.Runtime.NativeAOT` and `Mono.Android.NET-Tests`, which previously accessed `RuntimeFeature` through `Mono.Android.dll`. * Once `RuntimeFeature` is only imported (no longer source-compiled) into `Mono.Android`, the unqualified name `RuntimeFeature` becomes ambiguous with `System.Runtime.CompilerServices.RuntimeFeature`. Add `using RuntimeFeature = Microsoft.Android.Runtime.RuntimeFeature;` to the three affected files, matching the alias already used in `JNIEnvInit.cs`. `Microsoft.Android.Runtime.RuntimeFeature` is now defined in exactly one assembly (`Mono.Android.Runtime.dll`), and the 58 `CS0436` warnings are gone. This is a focused subset of #11625 that addresses only the `RuntimeFeature` duplication, without that PR's class rename or unrelated warning cleanups. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Mono.Android.Runtime/Properties/AssemblyInfo.cs.in | 2 ++ src/Mono.Android/Android.Runtime/AndroidRuntime.cs | 1 + src/Mono.Android/Android.Runtime/JNIEnv.cs | 1 + src/Mono.Android/Java.Interop/TypeManager.cs | 1 + src/Mono.Android/Mono.Android.csproj | 1 - 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Mono.Android.Runtime/Properties/AssemblyInfo.cs.in b/src/Mono.Android.Runtime/Properties/AssemblyInfo.cs.in index fee83c88b9c..5f28384bdc6 100644 --- a/src/Mono.Android.Runtime/Properties/AssemblyInfo.cs.in +++ b/src/Mono.Android.Runtime/Properties/AssemblyInfo.cs.in @@ -19,3 +19,5 @@ using System.Runtime.Versioning; [assembly: SupportedOSPlatform("Android@MIN_API_LEVEL@.0")] [assembly: InternalsVisibleTo("Mono.Android, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] +[assembly: InternalsVisibleTo("Microsoft.Android.Runtime.NativeAOT, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] +[assembly: InternalsVisibleTo("Mono.Android.NET-Tests, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index 918b8377b54..8bc52554abd 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -11,6 +11,7 @@ using Java.Interop.Tools.TypeNameMappings; using Microsoft.Android.Runtime; using System.Diagnostics.CodeAnalysis; +using RuntimeFeature = Microsoft.Android.Runtime.RuntimeFeature; #if JAVA_INTEROP namespace Android.Runtime { diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index ebfc81cc39b..471296b6ac6 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -14,6 +14,7 @@ using Java.Interop; using Java.Interop.Tools.TypeNameMappings; using Microsoft.Android.Runtime; +using RuntimeFeature = Microsoft.Android.Runtime.RuntimeFeature; namespace Android.Runtime { public static partial class JNIEnv { diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index cc0b22936bd..1339d295633 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -9,6 +9,7 @@ using Android.Runtime; using Microsoft.Android.Runtime; +using RuntimeFeature = Microsoft.Android.Runtime.RuntimeFeature; namespace Java.Interop { diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index 611ef7edf07..1918821f5c7 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -366,7 +366,6 @@ - From 7824101428647bfc6a49ff186f631a31c861b565 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:14:53 +0000 Subject: [PATCH 2/3] [Xamarin.Android.Build.Tests] Improve trimmer warning assertions and adjust warning totals Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 05a317d6669..d79d459cb00 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using System.Text.RegularExpressions; using System.Text; using System.Threading.Tasks; using System.Xml; @@ -501,9 +502,9 @@ static IEnumerable Get_BuildHasTrimmerWarningsData () } else { AddTestData (runtime, "", new string [0], true); } - AddTestData (runtime, "SuppressTrimAnalysisWarnings=false", new string [] { "IL2055" }, true, 2); + AddTestData (runtime, "SuppressTrimAnalysisWarnings=false", new string [] { "IL2055" }, true, runtime == AndroidRuntime.NativeAOT ? 2 : 1); AddTestData (runtime, "TrimMode=full", new string [] { "IL2055" }, false, 1); - AddTestData (runtime, "TrimMode=full", new string [] { "IL2055" }, true, 2); + AddTestData (runtime, "TrimMode=full", new string [] { "IL2055" }, true, runtime == AndroidRuntime.NativeAOT ? 2 : 1); AddTestData (runtime, "IsAotCompatible=true", new string [] { "IL2055", "IL3050" }, false); if (runtime == AndroidRuntime.NativeAOT) { @@ -570,9 +571,30 @@ public void BuildHasTrimmerWarnings (AndroidRuntime runtime, string properties, b.AssertHasNoWarnings (); } else { totalWarnings ??= codes.Length; - Assert.True (StringAssertEx.ContainsText (b.LastBuildOutput, $"{totalWarnings} Warning(s)"), $"Should receive {totalWarnings} warnings"); + + string warningSummaryLine = b.LastBuildOutput.LastOrDefault (line => + line.Contains (" Warning(s)", StringComparison.Ordinal) && + line.Contains (" Error(s)", StringComparison.Ordinal) + ) ?? ""; + Match totalWarningMatch = Regex.Match (warningSummaryLine, @"\s(?\d+)\sWarning\(s\)", RegexOptions.CultureInvariant); + var actualWarnings = totalWarningMatch.Success ? int.Parse (totalWarningMatch.Groups ["count"].Value) : -1; + + var allWarningLines = b.LastBuildOutput + .Where (line => line.Contains (": warning ", StringComparison.OrdinalIgnoreCase)) + .Take (25) + .ToArray (); + Assert.AreEqual ( + totalWarnings.Value, + actualWarnings, + $"{b.BuildLogFile} should have {totalWarnings} warnings. Summary line: '{warningSummaryLine}'. " + + $"Warnings found ({allWarningLines.Length} shown):{Environment.NewLine}{string.Join (Environment.NewLine, allWarningLines)}" + ); foreach (var code in codes) { - Assert.True (StringAssertEx.ContainsText (b.LastBuildOutput, code), $"Should receive {code} warning"); + Assert.True ( + StringAssertEx.ContainsText (b.LastBuildOutput, code), + $"{b.BuildLogFile} should contain warning {code}. Summary line: '{warningSummaryLine}'. " + + $"Warnings found ({allWarningLines.Length} shown):{Environment.NewLine}{string.Join (Environment.NewLine, allWarningLines)}" + ); } } } From f54cbc808f3f1471e7c41529d4c92f619133f349 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:22:06 +0000 Subject: [PATCH 3/3] [Xamarin.Android.Build.Tests] Refine warning summary parsing in BuildHasTrimmerWarnings Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com> --- .../Xamarin.Android.Build.Tests/BuildTest2.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index d79d459cb00..58b13f5f292 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Reflection; using System.Runtime.InteropServices; -using System.Text.RegularExpressions; using System.Text; using System.Threading.Tasks; using System.Xml; @@ -532,6 +531,8 @@ void AddTestData (AndroidRuntime runtime, string properties, string [] codes, bo [TestCaseSource (nameof (Get_BuildHasTrimmerWarningsData))] public void BuildHasTrimmerWarnings (AndroidRuntime runtime, string properties, string [] codes, bool isRelease, int? totalWarnings = null) { + const int maxWarningLinesToShow = 25; + if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) { return; } @@ -572,16 +573,12 @@ public void BuildHasTrimmerWarnings (AndroidRuntime runtime, string properties, } else { totalWarnings ??= codes.Length; - string warningSummaryLine = b.LastBuildOutput.LastOrDefault (line => - line.Contains (" Warning(s)", StringComparison.Ordinal) && - line.Contains (" Error(s)", StringComparison.Ordinal) - ) ?? ""; - Match totalWarningMatch = Regex.Match (warningSummaryLine, @"\s(?\d+)\sWarning\(s\)", RegexOptions.CultureInvariant); - var actualWarnings = totalWarningMatch.Success ? int.Parse (totalWarningMatch.Groups ["count"].Value) : -1; + string warningSummaryLine = b.LastBuildOutput.LastOrDefault (line => line.Contains ("Warning(s)", StringComparison.Ordinal)) ?? ""; + var actualWarnings = GetWarningCount (warningSummaryLine); var allWarningLines = b.LastBuildOutput .Where (line => line.Contains (": warning ", StringComparison.OrdinalIgnoreCase)) - .Take (25) + .Take (maxWarningLinesToShow) .ToArray (); Assert.AreEqual ( totalWarnings.Value, @@ -597,6 +594,17 @@ public void BuildHasTrimmerWarnings (AndroidRuntime runtime, string properties, ); } } + + static int GetWarningCount (string warningSummaryLine) + { + string [] tokens = warningSummaryLine.Split (new [] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 1; i < tokens.Length; i++) { + if (tokens [i] == "Warning(s)" && int.TryParse (tokens [i - 1], out var warningCount)) { + return warningCount; + } + } + return -1; + } } [Test]