Skip to content

Commit

Permalink
Create shared WellKnownTypes enum (dotnet/linker#2692)
Browse files Browse the repository at this point in the history
Commit migrated from dotnet/linker@1d77412
  • Loading branch information
jtschuster authored Mar 18, 2022
1 parent bd9f220 commit 40f5127
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 19 deletions.
10 changes: 5 additions & 5 deletions src/tools/illink/src/ILLink.RoslynAnalyzer/COMAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Collections.Immutable;
using System.Runtime.InteropServices;
using ILLink.Shared;
using ILLink.Shared.TypeSystemProxy;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
Expand Down Expand Up @@ -88,11 +89,11 @@ static bool IsComInterop (ISymbol symbol)
if (typeSymbol == null)
return false;

if (typeSymbol.ContainingNamespace.Name == "System" && typeSymbol.Name == "Array") {
if (typeSymbol.IsTypeOf (WellKnownType.System_Array)) {
// System.Array marshals as IUnknown by default
return true;
} else if (typeSymbol.ContainingNamespace.Name == "System" && typeSymbol.Name == "String" ||
typeSymbol.ContainingNamespace.Name == "System.Text" && typeSymbol.Name == "StringBuilder") {
} else if (typeSymbol.IsTypeOf (WellKnownType.System_String) ||
typeSymbol.IsTypeOf ("System.Text", "StringBuilder")) {
// String and StringBuilder are special cased by interop
return false;
}
Expand All @@ -103,8 +104,7 @@ static bool IsComInterop (ISymbol symbol)
} else if (typeSymbol.IsInterface ()) {
// Interface types marshal as COM by default
return true;
} else if (typeSymbol.ContainingNamespace.Name == "System" &&
typeSymbol.Name == "MulticastDelegate") {
} else if (typeSymbol.IsTypeOf ("System", "MulticastDelegate")) {
// Delegates are special cased by interop
return false;
} else if (typeSymbol.IsSubclassOf ("System.Runtime.InteropServices", "CriticalHandle") ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static string GetDisplayName (this ISymbol symbol)
// Use definition type parameter names, not instance type parameters
methodSymbol = methodSymbol.OriginalDefinition;
// Format the declaring type with namespace and containing types.
if (methodSymbol.ContainingSymbol.Kind == SymbolKind.NamedType) {
if (methodSymbol.ContainingSymbol?.Kind == SymbolKind.NamedType) {
// If the containing symbol is a method (for example for local functions),
// don't include the containing type's name. This matches the behavior of
// CSharpErrorMessageFormat.
Expand Down Expand Up @@ -147,8 +147,7 @@ public static bool IsSubclassOf (this ISymbol symbol, string ns, string type)
return false;

while (typeSymbol != null) {
if (typeSymbol.ContainingNamespace.Name == ns &&
typeSymbol.ContainingType.Name == type)
if (typeSymbol.IsTypeOf (ns, type))
return true;

typeSymbol = typeSymbol.ContainingType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using ILLink.Shared.TypeSystemProxy;
using Microsoft.CodeAnalysis;

namespace ILLink.RoslynAnalyzer
Expand All @@ -27,17 +29,17 @@ public static bool IsTypeInterestingForDataflow (this ITypeSymbol type)
private static HierarchyFlags GetFlags (ITypeSymbol type)
{
HierarchyFlags flags = 0;
if (type.Name == "IReflect" && type.ContainingNamespace.GetDisplayName () == "System.Reflection") {
if (type.IsTypeOf (WellKnownType.System_Reflection_IReflect)) {
flags |= HierarchyFlags.IsSystemReflectionIReflect;
}

ITypeSymbol? baseType = type;
while (baseType != null) {
if (baseType.Name == "Type" && baseType.ContainingNamespace.GetDisplayName () == "System")
if (baseType.IsTypeOf (WellKnownType.System_Type))
flags |= HierarchyFlags.IsSystemType;

foreach (var iface in baseType.Interfaces) {
if (iface.Name == "IReflect" && iface.ContainingNamespace.GetDisplayName () == "System.Reflection") {
if (iface.IsTypeOf (WellKnownType.System_Reflection_IReflect)) {
flags |= HierarchyFlags.IsSystemReflectionIReflect;
}
}
Expand All @@ -50,5 +52,21 @@ private static HierarchyFlags GetFlags (ITypeSymbol type)
private static bool IsSystemType (HierarchyFlags flags) => (flags & HierarchyFlags.IsSystemType) != 0;

private static bool IsSystemReflectionIReflect (HierarchyFlags flags) => (flags & HierarchyFlags.IsSystemReflectionIReflect) != 0;

public static bool IsTypeOf (this ITypeSymbol symbol, string @namespace, string name)
{
return symbol.ContainingNamespace?.GetDisplayName () == @namespace && symbol.MetadataName == name;
}

public static bool IsTypeOf (this ITypeSymbol symbol, WellKnownType wellKnownType)
{
if (wellKnownType.TryGetSpecialType (out var specialType)) {
// Make sure checking the special type is the same as checking the metadata string names.
Debug.Assert (symbol.IsTypeOf (wellKnownType.GetNamespace (), wellKnownType.GetName ()) == (symbol.SpecialType == specialType));
return symbol.SpecialType == specialType;
}
var (Namespace, Name) = wellKnownType.GetNamespaceAndName ();
return symbol.IsTypeOf (Namespace, Name);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ internal readonly partial struct TypeProxy

public string Name { get => Type.MetadataName; }

public string Namespace { get => Type.ContainingNamespace.Name; }
public string? Namespace { get => Type.ContainingNamespace?.Name; }

public bool IsTypeOf (string @namespace, string name) => Type.IsTypeOf (@namespace, name);

public bool IsTypeOf (WellKnownType wellKnownType) => Type.IsTypeOf (wellKnownType);

public string GetDisplayName () => Type.GetDisplayName ();

public override string ToString () => Type.ToString ();

public bool IsTypeOf (string @namespace, string name) => Namespace == @namespace && Name == name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;

namespace ILLink.Shared.TypeSystemProxy
{
public static partial class WellKnownTypeExtensions
{
public static bool TryGetSpecialType (this WellKnownType wellKnownType, [NotNullWhen (true)] out SpecialType? specialType)
{
specialType = wellKnownType switch {
WellKnownType.System_String => SpecialType.System_String,
WellKnownType.System_Nullable_T => SpecialType.System_Nullable_T,
WellKnownType.System_Array => SpecialType.System_Array,
WellKnownType.System_Object => SpecialType.System_Object,
_ => null,
};
return specialType is not null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace ILLink.Shared.TypeSystemProxy
{
public enum WellKnownType
{
System_String,
System_Nullable_T,
System_Type,
System_Reflection_IReflect,
System_Array,
System_Object,
System_Attribute
}

public static partial class WellKnownTypeExtensions
{
public static (string Namespace, string Name) GetNamespaceAndName (this WellKnownType type)
{
return type switch {
WellKnownType.System_String => ("System", "String"),
WellKnownType.System_Nullable_T => ("System", "Nullable`1"),
WellKnownType.System_Type => ("System", "Type"),
WellKnownType.System_Reflection_IReflect => ("System.Reflection", "IReflect"),
WellKnownType.System_Array => ("System", "Array"),
WellKnownType.System_Object => ("System", "Object"),
WellKnownType.System_Attribute => ("System", "Attribute"),
_ => throw new ArgumentException ($"{nameof (type)} is not a well-known type."),
};
}
public static string GetNamespace (this WellKnownType type) => GetNamespaceAndName (type).Namespace;
public static string GetName (this WellKnownType type) => GetNamespaceAndName (type).Name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using ILLink.Shared;
using ILLink.Shared.DataFlow;
using ILLink.Shared.TrimAnalysis;
using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Linker.Steps;
Expand Down Expand Up @@ -894,10 +895,10 @@ bool IsComInterop (IMarshalInfoProvider marshalInfoProvider, TypeReference param
var parameterTypeDef = _context.TryResolve (parameterType);

if (parameterTypeDef != null) {
if (parameterTypeDef.IsTypeOf ("System", "Array")) {
if (parameterTypeDef.IsTypeOf (WellKnownType.System_Array)) {
// System.Array marshals as IUnknown by default
return true;
} else if (parameterTypeDef.IsTypeOf ("System", "String") ||
} else if (parameterTypeDef.IsTypeOf (WellKnownType.System_String) ||
parameterTypeDef.IsTypeOf ("System.Text", "StringBuilder")) {
// String and StringBuilder are special cased by interop
return false;
Expand Down
8 changes: 5 additions & 3 deletions src/tools/illink/src/linker/Linker.Dataflow/TypeProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ internal readonly partial struct TypeProxy

public string Name { get => Type.Name; }

public string Namespace { get => Type.Namespace; }
public string? Namespace { get => Type.Namespace; }

public bool IsTypeOf (string @namespace, string name) => Type.IsTypeOf (@namespace, name);

public bool IsTypeOf (WellKnownType wellKnownType) => Type.IsTypeOf (wellKnownType);

public string GetDisplayName () => Type.GetDisplayName ();

public override string ToString () => Type.ToString ();

public bool IsTypeOf (string @namespace, string name) => Type.IsTypeOf (@namespace, name);
}
}
7 changes: 7 additions & 0 deletions src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Diagnostics;
using System.Linq;
using System.Text;
using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;

namespace Mono.Linker
Expand Down Expand Up @@ -358,6 +359,12 @@ public static bool IsTypeOf<T> (this TypeReference tr)
return tr.Name == type.Name && tr.Namespace == tr.Namespace;
}

public static bool IsTypeOf (this TypeReference tr, WellKnownType type)
{
var (@namespace, name) = type.GetNamespaceAndName ();
return tr.IsTypeOf (@namespace, name);
}

public static bool IsSubclassOf (this TypeReference type, string ns, string name, ITryResolveMetadata resolver)
{
TypeDefinition? baseType = resolver.TryResolve (type);
Expand Down

0 comments on commit 40f5127

Please sign in to comment.