diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs index f8fef4984b9663..20dac81c48d75c 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexLWCGCompiler.cs @@ -8,6 +8,7 @@ namespace System.Text.RegularExpressions { + [RequiresDynamicCode("Compiling a RegEx requires dynamic code.")] internal sealed class RegexLWCGCompiler : RegexCompiler { /// @@ -31,7 +32,6 @@ internal sealed class RegexLWCGCompiler : RegexCompiler private static int s_regexCount; /// The top-level driver. Initializes everything then calls the Generate* methods. - [RequiresDynamicCode("Compiling a RegEx requires dynamic code.")] public RegexRunnerFactory? FactoryInstanceFromCode(string pattern, RegexTree regexTree, RegexOptions options, bool hasTimeout) { if (!regexTree.Root.SupportsCompilation(out _)) @@ -67,7 +67,6 @@ internal sealed class RegexLWCGCompiler : RegexCompiler } /// Begins the definition of a new method (no args) with a specified return value. - [RequiresDynamicCode("Compiling a RegEx requires dynamic code.")] private DynamicMethod DefineDynamicMethod(string methname, Type? returntype, Type hostType, Type[] paramTypes) { // We're claiming that these are static methods, but really they are instance methods. diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs index a8b010bdc292d7..b501fe4e6480a5 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs @@ -128,6 +128,9 @@ public override void Initialize(AnalysisContext context) foreach (var extraSyntaxNodeAction in ExtraSyntaxNodeActions) context.RegisterSyntaxNodeAction(extraSyntaxNodeAction.Action, extraSyntaxNodeAction.SyntaxKind); + // Register the implicit base constructor analysis for all analyzers + context.RegisterSymbolAction(AnalyzeImplicitBaseCtor, SymbolKind.NamedType); + foreach (var extraSymbolAction in ExtraSymbolActions) context.RegisterSymbolAction(extraSymbolAction.Action, extraSymbolAction.SymbolKind); @@ -197,6 +200,33 @@ internal void CheckAndCreateRequiresDiagnostic( CreateRequiresDiagnostic(member, requiresAttribute, diagnosticContext); } + private void AnalyzeImplicitBaseCtor(SymbolAnalysisContext context) + { + var typeSymbol = (INamedTypeSymbol)context.Symbol; + + if (typeSymbol.TypeKind != TypeKind.Class || typeSymbol.BaseType == null) + return; + + if (typeSymbol.InstanceConstructors.Length != 1 || !typeSymbol.InstanceConstructors[0].IsImplicitlyDeclared) + return; + + var implicitCtor = typeSymbol.InstanceConstructors[0]; + + var baseCtor = typeSymbol.BaseType.InstanceConstructors.FirstOrDefault(ctor => ctor.Parameters.IsEmpty); + if (baseCtor == null) + return; + + var diagnosticContext = new DiagnosticContext( + typeSymbol.Locations[0], + context.ReportDiagnostic); + + CheckAndCreateRequiresDiagnostic( + baseCtor, + implicitCtor, + ImmutableArray.Empty, + diagnosticContext); + } + [Flags] protected enum DiagnosticTargets { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresExcludeStatics.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresExcludeStatics.cs index 524a0c0f3a2866..57b01bb7611fd9 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresExcludeStatics.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresExcludeStatics.cs @@ -145,6 +145,10 @@ public static void Test() } } + [ExpectedWarning("IL2026", "BaseWithRequires.BaseWithRequires()", "--BaseWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning("IL2026", "BaseWithRequires.BaseWithRequires()", "--BaseWithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning("IL3050", "BaseWithRequires.BaseWithRequires()", "--BaseWithRequires--", Tool.Analyzer, "NativeAOT Specific warning")] + [ExpectedWarning("IL3050", "BaseWithRequires.BaseWithRequires()", "--BaseWithRequires--", Tool.NativeAot, "NativeAOT Specific warning", CompilerGeneratedCode = true)] class DerivedWithoutRequires : BaseWithRequires { [ExpectedWarning("IL2026", "--Requires--")] @@ -157,6 +161,9 @@ public static void Test() { StaticMethod(); DerivedStaticMethod(); + + // Instantiate for linker test consistency + new DerivedWithoutRequires(); } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs index 886743417bb549..714bf9a2598fc2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs @@ -36,6 +36,10 @@ public static void Main() AttributeParametersAndProperties.Test(); MembersOnClassWithRequires.Test(); ConstFieldsOnClassWithRequires.Test(); + + // Instantiate classes so linker warnings match analyzer warnings + new TestUnconditionalSuppressMessage(); + new DerivedWithoutRequiresOnType(); } [RequiresUnreferencedCode("Message for --ClassWithRequires--")] @@ -128,6 +132,10 @@ public DerivedFromNestedInRequiresClass() { } public static void StaticMethod() { } } + [ExpectedWarning("IL2026", "ClassWithRequires.ClassWithRequires()", "--ClassWithRequires--", Tool.Analyzer, "")] + [ExpectedWarning("IL2026", "ClassWithRequires.ClassWithRequires()", "--ClassWithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning("IL3050", "ClassWithRequires.ClassWithRequires()", "--ClassWithRequires--", Tool.Analyzer, "NativeAOT Specific warning")] + [ExpectedWarning("IL3050", "ClassWithRequires.ClassWithRequires()", "--ClassWithRequires--", Tool.NativeAot, "NativeAOT Specific warning", CompilerGeneratedCode = true)] class TestUnconditionalSuppressMessage : ClassWithRequires { public static void StaticMethodInTestSuppressionClass() { } @@ -339,6 +347,10 @@ class BaseWithRequiresOnType public virtual void Method() { } } + [ExpectedWarning("IL2026", "BaseWithRequiresOnType.BaseWithRequiresOnType()", "RUC", Tool.Analyzer, "")] + [ExpectedWarning("IL2026", "BaseWithRequiresOnType.BaseWithRequiresOnType()", "RUC", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning("IL3050", "BaseWithRequiresOnType.BaseWithRequiresOnType()", "RDC", Tool.Analyzer, "NativeAOT Specific warning")] + [ExpectedWarning("IL3050", "BaseWithRequiresOnType.BaseWithRequiresOnType()", "RDC", Tool.NativeAot, "NativeAOT Specific warning", CompilerGeneratedCode = true)] class DerivedWithoutRequiresOnType : BaseWithRequiresOnType { public override void Method() { } @@ -694,6 +706,10 @@ class WithRequiresOnlyInstanceFields public int InstanceField; } + [ExpectedWarning("IL2026", "WithRequires.WithRequires()", "--WithRequires--", Tool.Analyzer, "")] + [ExpectedWarning("IL2026", "WithRequires.WithRequires()", "--WithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning("IL3050", "WithRequires.WithRequires()", "--WithRequires--", Tool.Analyzer, "NativeAOT Specific warning")] + [ExpectedWarning("IL3050", "WithRequires.WithRequires()", "--WithRequires--", Tool.NativeAot, "NativeAOT Specific warning", CompilerGeneratedCode = true)] class DerivedWithoutRequires : WithRequires { public static int DerivedStaticField; @@ -831,6 +847,9 @@ public static void Test() TestDAMOnTypeAccessInRUCScope(new DAMAnnotatedClassAccessedFromRUCScope()); TestDAMAccessOnOpenGeneric(); TestDAMAccessOnInstantiatedGeneric(); + + // Instantiate for linker test consistency + new DerivedWithoutRequires(); } } @@ -854,6 +873,10 @@ class DerivedRequires : WithRequires private event EventHandler DerivedPrivateInstanceEvent; } + [ExpectedWarning("IL2026", "WithRequires.WithRequires()", "--WithRequires--", Tool.Analyzer, "")] + [ExpectedWarning("IL2026", "WithRequires.WithRequires()", "--WithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning("IL3050", "WithRequires.WithRequires()", "--WithRequires--", Tool.Analyzer, "NativeAOT Specific warning")] + [ExpectedWarning("IL3050", "WithRequires.WithRequires()", "--WithRequires--", Tool.NativeAot, "NativeAOT Specific warning", CompilerGeneratedCode = true)] class DerivedWithoutRequires : WithRequires { public static event EventHandler DerivedStaticEvent; @@ -1029,6 +1052,9 @@ public static void Test() DerivedRequiresPublicEvents(); DerivedRequiresNonPublicEvents(); DerivedRequiresAllEvents(); + + // Instantiate for linker test consistency + new DerivedWithoutRequires(); } } @@ -1050,6 +1076,10 @@ class WithRequiresOnlyInstanceProperties public int InstanceProperty { get; set; } } + [ExpectedWarning("IL2026", "WithRequires.WithRequires()", "--WithRequires--", Tool.Analyzer, "")] + [ExpectedWarning("IL2026", "WithRequires.WithRequires()", "--WithRequires--", Tool.Trimmer | Tool.NativeAot, "", CompilerGeneratedCode = true)] + [ExpectedWarning("IL3050", "WithRequires.WithRequires()", "--WithRequires--", Tool.Analyzer, "NativeAOT Specific warning")] + [ExpectedWarning("IL3050", "WithRequires.WithRequires()", "--WithRequires--", Tool.NativeAot, "NativeAOT Specific warning", CompilerGeneratedCode = true)] class DerivedWithoutRequires : WithRequires { public static int DerivedStaticProperty { get; set; } @@ -1217,6 +1247,9 @@ public static void Test() TestDirectReflectionAccess(); TestDynamicDependencyAccess(); TestDAMOnTypeAccess(new DAMAnnotatedClass()); + + // Instantiate for linker test consistency + new DerivedWithoutRequires(); } }