Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly handle assembly qualified names in generic parameters #1546

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,7 @@ void ProcessCreateInstanceByName (ref ReflectionPatternContext reflectionContext
continue;
}

var resolvedType = (TypeNameResolver.ResolveTypeName (resolvedAssembly, typeNameStringValue.Contents))?.Resolve ();
var resolvedType = (_context.TypeNameResolver.ResolveTypeName (resolvedAssembly, typeNameStringValue.Contents))?.Resolve ();
if (resolvedType == null) {
// It's not wrong to have a reference to non-existing type - the code may well expect to get an exception in this case
// Note that we did find the assembly, so it's not a linker config problem, it's either intentional, or wrong versions of assemblies
Expand Down
2 changes: 1 addition & 1 deletion src/linker/Linker.Steps/LinkAttributesStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ bool GetAttributeType (XPathNodeIterator iterator, string attributeFullName, out
return false;
}

attributeType = TypeNameResolver.ResolveTypeName (assembly, attributeFullName)?.Resolve ();
attributeType = Context.TypeNameResolver.ResolveTypeName (assembly, attributeFullName)?.Resolve ();
}

if (attributeType == null) {
Expand Down
6 changes: 3 additions & 3 deletions src/linker/Linker.Steps/MarkStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ protected virtual void MarkUserDependency (MemberReference context, CustomAttrib

TypeDefinition td;
if (args.Count >= 2 && args[1].Value is string typeName) {
td = TypeNameResolver.ResolveTypeName (assembly ?? context.Module.Assembly, typeName)?.Resolve ();
td = _context.TypeNameResolver.ResolveTypeName (assembly ?? context.Module.Assembly, typeName)?.Resolve ();
if (td == null) {
_context.LogWarning (
$"Could not resolve dependency type '{typeName}' specified in a `PreserveDependency` attribute", 2004, context.Resolve ());
Expand Down Expand Up @@ -1562,10 +1562,10 @@ TypeDefinition GetDebuggerAttributeTargetType (CustomAttribute ca, AssemblyDefin
TypeName typeName = TypeParser.ParseTypeName (targetTypeName);
if (typeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) {
AssemblyDefinition assembly = _context.GetLoadedAssembly (assemblyQualifiedTypeName.AssemblyName.Name);
return TypeNameResolver.ResolveTypeName (assembly, targetTypeName)?.Resolve ();
return _context.TypeNameResolver.ResolveTypeName (assembly, targetTypeName)?.Resolve ();
}

return TypeNameResolver.ResolveTypeName (asm, targetTypeName)?.Resolve ();
return _context.TypeNameResolver.ResolveTypeName (asm, targetTypeName)?.Resolve ();
}
}

Expand Down
17 changes: 10 additions & 7 deletions src/linker/Linker/TypeNameResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ public TypeReference ResolveTypeName (string typeNameString)
}

if (parsedTypeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) {
AssemblyDefinition assembly = _context.GetLoadedAssembly (assemblyQualifiedTypeName.AssemblyName.Name);
return ResolveTypeName (assembly, assemblyQualifiedTypeName.TypeName);
return ResolveTypeName (null, assemblyQualifiedTypeName);
}

foreach (var assemblyDefiniton in _context.GetAssemblies ()) {
Expand All @@ -41,19 +40,23 @@ public TypeReference ResolveTypeName (string typeNameString)
return null;
}

public static TypeReference ResolveTypeName (AssemblyDefinition assembly, string typeNameString)
public TypeReference ResolveTypeName (AssemblyDefinition assembly, string typeNameString)
{
return ResolveTypeName (assembly, TypeParser.ParseTypeName (typeNameString));
}

static TypeReference ResolveTypeName (AssemblyDefinition assembly, TypeName typeName)
TypeReference ResolveTypeName (AssemblyDefinition assembly, TypeName typeName)
{
if (typeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) {
// In this case we ignore the assembly parameter since the type name has assembly in it
var assemblyFromName = _context.GetLoadedAssembly (assemblyQualifiedTypeName.AssemblyName.Name);
return ResolveTypeName (assemblyFromName, assemblyQualifiedTypeName.TypeName);
}

if (assembly == null || typeName == null)
return null;

if (typeName is AssemblyQualifiedTypeName assemblyQualifiedTypeName) {
return ResolveTypeName (assembly, assemblyQualifiedTypeName.TypeName);
} else if (typeName is ConstructedGenericTypeName constructedGenericTypeName) {
if (typeName is ConstructedGenericTypeName constructedGenericTypeName) {
var genericTypeRef = ResolveTypeName (assembly, constructedGenericTypeName.GenericType);
if (genericTypeRef == null)
return null;
Expand Down
64 changes: 64 additions & 0 deletions test/Mono.Linker.Tests.Cases/DataFlow/ApplyTypeAnnotations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public static void Main ()
TestFromTypeOf ();
TestFromTypeGetTypeOverConstant ();
TestFromStringContantWithAnnotation ();
TestFromStringConstantWithGeneric ();
TestFromStringConstantWithGenericAndAssemblyQualified ();
TestFromStringConstantWithGenericAndAssemblyQualifiedInvalidAssembly ();
TestFromStringConstantWithGenericAndAssemblyQualifiedNonExistingAssembly ();
}

[Kept]
Expand Down Expand Up @@ -123,5 +127,65 @@ private static void RequireCombinationOnString (
string typeName)
{
}

// Issue: https://github.com/mono/linker/issues/1537
//[Kept]
//[KeptMember (".ctor()")]
class FromStringConstantWithGenericInner
{
}

[Kept]
[KeptMember (".ctor()")]
class FromStringConstantWithGeneric<T>
{
[Kept]
public T GetValue () { return default (T); }
}

[Kept]
static void TestFromStringConstantWithGeneric ()
{
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGeneric`1[[Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericInner]]");
vitek-karas marked this conversation as resolved.
Show resolved Hide resolved
}

[Kept]
[KeptMember (".ctor()")]
class FromStringConstantWithGenericAndAssemblyQualified<T>
{
[Kept]
public T GetValue () { return default (T); }
}

[Kept]
// This is a workaround for the inability to lazy load assemblies. The type name resolver will not load new assemblies
// and since the KeptAttribute is otherwise not referenced by the test anywhere (the test-validation attributes are removed before processing normally)
// it would not resolve from name - since its assembly is not loaded.
// Adding DynamicDependency solves this problem as it is basically the only attribute which has the ability to load new assemblies.
[DynamicDependency (DynamicallyAccessedMemberTypes.None, typeof (KeptAttribute))]
static void TestFromStringConstantWithGenericAndAssemblyQualified ()
{
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+FromStringConstantWithGenericAndAssemblyQualified`1[[Mono.Linker.Tests.Cases.Expectations.Assertions.KeptAttribute,Mono.Linker.Tests.Cases.Expectations]]");
}

class InvalidAssemblyNameType
{
}

[Kept]
static void TestFromStringConstantWithGenericAndAssemblyQualifiedInvalidAssembly ()
{
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+InvalidAssemblyNameType,Invalid/Assembly/Name");
}

class NonExistingAssemblyType
{
}

[Kept]
static void TestFromStringConstantWithGenericAndAssemblyQualifiedNonExistingAssembly ()
{
RequireCombinationOnString ("Mono.Linker.Tests.Cases.DataFlow.ApplyTypeAnnotations+InvalidAssemblyNameType,NonExistingAssembly");
}
}
}