diff options
author | Jackson Schuster <36744439+jtschuster@users.noreply.github.com> | 2022-03-18 22:20:24 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-18 22:20:24 +0300 |
commit | 1d774126b2aed67d61bb3bab54881555458e9452 (patch) | |
tree | 44df127135c0470e0f3d7e0fd5b405fa1bde0b2c | |
parent | ed8b22a192b585f169446b1a4a14f3f81eda6154 (diff) |
Create shared WellKnownTypes enum (#2692)
-rw-r--r-- | src/ILLink.RoslynAnalyzer/COMAnalyzer.cs | 10 | ||||
-rw-r--r-- | src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs | 5 | ||||
-rw-r--r-- | src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs | 24 | ||||
-rw-r--r-- | src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeProxy.cs | 8 | ||||
-rw-r--r-- | src/ILLink.RoslynAnalyzer/TrimAnalysis/WellKnownTypeExtensions.cs | 23 | ||||
-rw-r--r-- | src/ILLink.Shared/TypeSystemProxy/WellKnownType.cs | 37 | ||||
-rw-r--r-- | src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs | 5 | ||||
-rw-r--r-- | src/linker/Linker.Dataflow/TypeProxy.cs | 8 | ||||
-rw-r--r-- | src/linker/Linker/TypeReferenceExtensions.cs | 7 |
9 files changed, 108 insertions, 19 deletions
diff --git a/src/ILLink.RoslynAnalyzer/COMAnalyzer.cs b/src/ILLink.RoslynAnalyzer/COMAnalyzer.cs index d9e2d48cd..798bb8462 100644 --- a/src/ILLink.RoslynAnalyzer/COMAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/COMAnalyzer.cs @@ -6,6 +6,7 @@ using System; 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; @@ -88,11 +89,11 @@ namespace ILLink.RoslynAnalyzer 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; } @@ -103,8 +104,7 @@ namespace ILLink.RoslynAnalyzer } 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") || diff --git a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs index ecf1cc1bf..c5cca0afd 100644 --- a/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs +++ b/src/ILLink.RoslynAnalyzer/ISymbolExtensions.cs @@ -113,7 +113,7 @@ namespace ILLink.RoslynAnalyzer // 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. @@ -147,8 +147,7 @@ namespace ILLink.RoslynAnalyzer return false; while (typeSymbol != null) { - if (typeSymbol.ContainingNamespace.Name == ns && - typeSymbol.ContainingType.Name == type) + if (typeSymbol.IsTypeOf (ns, type)) return true; typeSymbol = typeSymbol.ContainingType; diff --git a/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs b/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs index ab2487e1b..0560fa049 100644 --- a/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs +++ b/src/ILLink.RoslynAnalyzer/ITypeSymbolExtensions.cs @@ -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 @@ -27,17 +29,17 @@ namespace ILLink.RoslynAnalyzer 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; } } @@ -50,5 +52,21 @@ namespace ILLink.RoslynAnalyzer 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); + } } } diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeProxy.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeProxy.cs index d66ed455b..8ccad1bad 100644 --- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeProxy.cs +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeProxy.cs @@ -14,12 +14,14 @@ namespace ILLink.Shared.TypeSystemProxy 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; } } diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/WellKnownTypeExtensions.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/WellKnownTypeExtensions.cs new file mode 100644 index 000000000..73f619082 --- /dev/null +++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/WellKnownTypeExtensions.cs @@ -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; + } + } +}
\ No newline at end of file diff --git a/src/ILLink.Shared/TypeSystemProxy/WellKnownType.cs b/src/ILLink.Shared/TypeSystemProxy/WellKnownType.cs new file mode 100644 index 000000000..b4f061e6d --- /dev/null +++ b/src/ILLink.Shared/TypeSystemProxy/WellKnownType.cs @@ -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; + } +}
\ No newline at end of file diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index fdc39bc02..4ea6b848d 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -10,6 +10,7 @@ using System.Linq; 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; @@ -894,10 +895,10 @@ namespace Mono.Linker.Dataflow 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; diff --git a/src/linker/Linker.Dataflow/TypeProxy.cs b/src/linker/Linker.Dataflow/TypeProxy.cs index 9fa5f5c09..d629b8524 100644 --- a/src/linker/Linker.Dataflow/TypeProxy.cs +++ b/src/linker/Linker.Dataflow/TypeProxy.cs @@ -16,12 +16,14 @@ namespace ILLink.Shared.TypeSystemProxy 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); } } diff --git a/src/linker/Linker/TypeReferenceExtensions.cs b/src/linker/Linker/TypeReferenceExtensions.cs index ea2239479..232f10a63 100644 --- a/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/linker/Linker/TypeReferenceExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; +using ILLink.Shared.TypeSystemProxy; using Mono.Cecil; namespace Mono.Linker @@ -358,6 +359,12 @@ namespace Mono.Linker 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); |