diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 144348d79344..d5af5cab45c6 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -613,7 +613,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference IEnumerable members; if (dynamicDependency.MemberSignature is string memberSignature) { - members = DocumentationSignatureParser.GetMembersByDocumentationSignature (type, memberSignature); + members = DocumentationSignatureParser.GetMembersByDocumentationSignature (type, memberSignature, acceptName: true); if (!members.Any ()) { _context.LogWarning ($"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context.Resolve ())); return; diff --git a/src/linker/Linker/DocumentationSignatureParser.cs b/src/linker/Linker/DocumentationSignatureParser.cs index 36a3027582a7..77d731ed6fe5 100644 --- a/src/linker/Linker/DocumentationSignatureParser.cs +++ b/src/linker/Linker/DocumentationSignatureParser.cs @@ -65,13 +65,13 @@ public static IEnumerable GetMembersForDocumentationSignature } // Takes a member signature (not including the declaring type) and returns the matching members on the type. - public static IEnumerable GetMembersByDocumentationSignature (TypeDefinition type, string signature) + public static IEnumerable GetMembersByDocumentationSignature (TypeDefinition type, string signature, bool acceptName = false) { int index = 0; var results = new List (); var nameBuilder = new StringBuilder (); var (name, arity) = DocumentationSignatureParser.ParseTypeOrNamespaceName (signature, ref index, nameBuilder); - DocumentationSignatureParser.GetMatchingMembers (signature, ref index, type.Module, type, name, arity, DocumentationSignatureParser.MemberType.All, results); + DocumentationSignatureParser.GetMatchingMembers (signature, ref index, type.Module, type, name, arity, DocumentationSignatureParser.MemberType.All, results, acceptName); return results; } @@ -195,7 +195,7 @@ public static void ParseSignaturePart (string id, ref int index, ModuleDefinitio // Gets all members of the specified member kinds of the containing type, with // mathing name, arity, and signature at the current index (for methods and properties). // This will also resolve types from the given module if no containing type is given. - public static void GetMatchingMembers (string id, ref int index, ModuleDefinition module, TypeDefinition? containingType, string memberName, int arity, MemberType memberTypes, List results) + public static void GetMatchingMembers (string id, ref int index, ModuleDefinition module, TypeDefinition? containingType, string memberName, int arity, MemberType memberTypes, List results, bool acceptName = false) { if (memberTypes.HasFlag (MemberType.Type)) GetMatchingTypes (module, containingType, memberName, arity, results); @@ -207,13 +207,13 @@ public static void GetMatchingMembers (string id, ref int index, ModuleDefinitio int endIndex = index; if (memberTypes.HasFlag (MemberType.Method)) { - GetMatchingMethods (id, ref index, containingType, memberName, arity, results); + GetMatchingMethods (id, ref index, containingType, memberName, arity, results, acceptName); endIndex = index; index = startIndex; } if (memberTypes.HasFlag (MemberType.Property)) { - GetMatchingProperties (id, ref index, containingType, memberName, results); + GetMatchingProperties (id, ref index, containingType, memberName, results, acceptName); endIndex = index; index = startIndex; } @@ -527,7 +527,7 @@ static void GetMatchingTypes (ModuleDefinition module, TypeDefinition? declaring } } - static void GetMatchingMethods (string id, ref int index, TypeDefinition? type, string memberName, int arity, List results) + static void GetMatchingMethods (string id, ref int index, TypeDefinition? type, string memberName, int arity, List results, bool acceptName = false) { if (type == null) return; @@ -546,7 +546,9 @@ static void GetMatchingMethods (string id, ref int index, TypeDefinition? type, continue; parameters.Clear (); + bool isNameOnly = true; if (PeekNextChar (id, index) == '(') { + isNameOnly = false; // if the parameters cannot be identified (some error), then the symbol cannot match, try next method symbol if (!ParseParameterList (id, ref index, method, parameters)) continue; @@ -554,30 +556,31 @@ static void GetMatchingMethods (string id, ref int index, TypeDefinition? type, // note: this allows extra characters at the end - if (!AllParametersMatch (method.Parameters, parameters)) - continue; - if (PeekNextChar (id, index) == '~') { + isNameOnly = false; index++; string? returnType = ParseTypeSymbol (id, ref index, method); if (returnType == null) continue; // if return type is specified, then it must match - if (GetSignaturePart (method.ReturnType) == returnType) { - results.Add (method); - endIndex = index; - } - } else { - // no return type specified, then any matches - results.Add (method); - endIndex = index; + if (GetSignaturePart (method.ReturnType) != returnType) + continue; } + + if (!isNameOnly || !acceptName) { + // check parameters unless we are matching a name only + if (!AllParametersMatch (method.Parameters, parameters)) + continue; + } + + results.Add (method); + endIndex = index; } index = endIndex; } - static void GetMatchingProperties (string id, ref int index, TypeDefinition? type, string memberName, List results) + static void GetMatchingProperties (string id, ref int index, TypeDefinition? type, string memberName, List results, bool acceptName = false) { if (type == null) return; @@ -598,16 +601,16 @@ static void GetMatchingProperties (string id, ref int index, TypeDefinition? typ } else { parameters.Clear (); } - - if (ParseParameterList (id, ref index, property.DeclaringType, parameters) - && AllParametersMatch (property.Parameters, parameters)) { - results.Add (property); - endIndex = index; - } - } else if (property.Parameters.Count == 0) { - results.Add (property); - endIndex = index; + if (!ParseParameterList (id, ref index, property.DeclaringType, parameters)) + continue; + if (!AllParametersMatch (property.Parameters, parameters)) + continue; + } else { + if (!acceptName && property.Parameters.Count != 0) + continue; } + results.Add (property); + endIndex = index; } index = endIndex; diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs index 9a1085fd3a89..0491a419afd2 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs @@ -36,12 +36,15 @@ void Method2 (out sbyte arg) [Kept] [DynamicDependency ("Dependency1()", typeof (C))] [DynamicDependency ("Dependency2``1(``0[],System.Int32", typeof (C))] + [DynamicDependency ("Dependency3", typeof (C))] + [DynamicDependency ("RecursiveDependency", typeof (C))] [DynamicDependency ("#ctor()", typeof (C))] // To avoid lazy body marking stubbing [DynamicDependency ("field", typeof (C))] [DynamicDependency ("NextOne(Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Nested@)", typeof (Nested))] [DynamicDependency ("#cctor()", typeof (Nested))] // Dependency on a property itself should be expressed as a dependency on one or both accessor methods [DynamicDependency ("get_Property()", typeof (C))] + [DynamicDependency ("get_Property2", typeof (C))] [DynamicDependency ("M``1(Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.S{" + "Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.G{" + "Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.A,``0}}" + @@ -134,10 +137,30 @@ internal void Dependency2 (T[] arg1, int arg2) { } + [Kept] + internal void Dependency3 (string str) + { + } + + [Kept] + [DynamicDependency ("#ctor", typeof (NestedInC))] + internal void RecursiveDependency () + { + } + + [KeptMember (".ctor()")] + class NestedInC + { + } + [Kept] [KeptBackingField] internal string Property { [Kept] get; set; } + [Kept] + [KeptBackingField] + internal string Property2 { [Kept] get; set; } + // For now, Condition has no effect: https://github.com/mono/linker/issues/1231 [Kept] internal void ConditionalTest () diff --git a/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs b/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs index 1c4ada9f26c0..f6e3c19808bd 100644 --- a/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs +++ b/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs @@ -368,6 +368,10 @@ public int this[int i] { [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.op_Addition(Mono.Linker.Tests.DocumentationSignatureParserTests.A,Mono.Linker.Tests.DocumentationSignatureParserTests.A)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.op_Addition(Mono.Linker.Tests.DocumentationSignatureParserTests.A,Mono.Linker.Tests.DocumentationSignatureParserTests.A)")] public static A operator + (A left, A right) => null; + + [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MWithReturnType")] + [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MWithReturnType~System.Boolean")] + public static bool MWithReturnType () => false; } public struct S