mirror of https://github.com/icsharpcode/ILSpy.git
3 changed files with 326 additions and 136 deletions
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
// Copyright (c) 2022 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#nullable enable |
||||
|
||||
using System; |
||||
using System.Reflection.Metadata; |
||||
|
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
|
||||
namespace ICSharpCode.ILSpy.Analyzers.Builtin |
||||
{ |
||||
public enum TokenSearchResult : byte |
||||
{ |
||||
NoResult = 0, |
||||
Byte = PrimitiveTypeCode.Byte, |
||||
SByte = PrimitiveTypeCode.SByte, |
||||
Int16 = PrimitiveTypeCode.Int16, |
||||
UInt16 = PrimitiveTypeCode.UInt16, |
||||
Int32 = PrimitiveTypeCode.Int32, |
||||
UInt32 = PrimitiveTypeCode.UInt32, |
||||
Int64 = PrimitiveTypeCode.Int64, |
||||
UInt64 = PrimitiveTypeCode.UInt64, |
||||
IntPtr = PrimitiveTypeCode.IntPtr, |
||||
UIntPtr = PrimitiveTypeCode.UIntPtr, |
||||
|
||||
// lowest PrimitiveTypeCode is 1
|
||||
// highest PrimitiveTypeCode is 28 (0b0001_1100)
|
||||
// TokenSearchResult with a PrimitiveTypeCode set is only used when decoding an enum-type.
|
||||
// It is used for GetUnderlyingEnumType and should be masked out in all other uses.
|
||||
// MSB = Found
|
||||
// 127 = System.Type
|
||||
TypeCodeMask = 0b0111_1111, |
||||
Found = 0b1000_0000, |
||||
SystemType = 127, |
||||
} |
||||
|
||||
class FindTypeInAttributeDecoder : ICustomAttributeTypeProvider<TokenSearchResult> |
||||
{ |
||||
readonly PEFile declaringModule; |
||||
readonly MetadataModule currentModule; |
||||
readonly TypeDefinitionHandle handle; |
||||
readonly PrimitiveTypeCode primitiveType; |
||||
|
||||
/// <summary>
|
||||
/// Constructs a FindTypeInAttributeDecoder that can be used to find <paramref name="type"/> in signatures from <paramref name="currentModule"/>.
|
||||
/// </summary>
|
||||
public FindTypeInAttributeDecoder(MetadataModule currentModule, ITypeDefinition type) |
||||
{ |
||||
this.currentModule = currentModule; |
||||
this.declaringModule = type.ParentModule.PEFile ?? throw new InvalidOperationException("Cannot use MetadataModule without PEFile as context."); |
||||
this.handle = (TypeDefinitionHandle)type.MetadataToken; |
||||
this.primitiveType = type.KnownTypeCode == KnownTypeCode.None ? 0 : type.KnownTypeCode.ToPrimitiveTypeCode(); |
||||
} |
||||
|
||||
public TokenSearchResult GetPrimitiveType(PrimitiveTypeCode typeCode) |
||||
{ |
||||
return typeCode == primitiveType ? TokenSearchResult.Found : 0; |
||||
} |
||||
|
||||
public TokenSearchResult GetSystemType() => TokenSearchResult.SystemType; |
||||
|
||||
public TokenSearchResult GetSZArrayType(TokenSearchResult elementType) => elementType & TokenSearchResult.Found; |
||||
|
||||
public TokenSearchResult GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) |
||||
{ |
||||
TokenSearchResult result = TokenSearchResult.NoResult; |
||||
|
||||
if (handle.IsEnum(reader, out PrimitiveTypeCode underlyingType)) |
||||
{ |
||||
result = (TokenSearchResult)underlyingType; |
||||
} |
||||
else if (((EntityHandle)handle).IsKnownType(reader, KnownTypeCode.Type)) |
||||
{ |
||||
result = TokenSearchResult.SystemType; |
||||
} |
||||
if (this.handle == handle && reader == declaringModule.Metadata) |
||||
{ |
||||
result |= TokenSearchResult.Found; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public TokenSearchResult GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) |
||||
{ |
||||
var t = currentModule.ResolveType(handle, default); |
||||
return GetResultFromResolvedType(t); |
||||
} |
||||
|
||||
public TokenSearchResult GetTypeFromSerializedName(string name) |
||||
{ |
||||
if (name == null) |
||||
{ |
||||
return TokenSearchResult.NoResult; |
||||
} |
||||
try |
||||
{ |
||||
IType type = ReflectionHelper.ParseReflectionName(name) |
||||
.Resolve(new SimpleTypeResolveContext(currentModule)); |
||||
return GetResultFromResolvedType(type); |
||||
} |
||||
catch (ReflectionNameParseException) |
||||
{ |
||||
return TokenSearchResult.NoResult; |
||||
} |
||||
} |
||||
|
||||
private TokenSearchResult GetResultFromResolvedType(IType type) |
||||
{ |
||||
var td = type.GetDefinition(); |
||||
if (td == null) |
||||
return TokenSearchResult.NoResult; |
||||
|
||||
TokenSearchResult result = TokenSearchResult.NoResult; |
||||
var underlyingType = td.EnumUnderlyingType?.GetDefinition(); |
||||
if (underlyingType != null) |
||||
{ |
||||
result = (TokenSearchResult)underlyingType.KnownTypeCode.ToPrimitiveTypeCode(); |
||||
} |
||||
else if (td.KnownTypeCode == KnownTypeCode.Type) |
||||
{ |
||||
result = TokenSearchResult.SystemType; |
||||
} |
||||
if (td.MetadataToken == this.handle && td.ParentModule.PEFile == declaringModule) |
||||
{ |
||||
result |= TokenSearchResult.Found; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public PrimitiveTypeCode GetUnderlyingEnumType(TokenSearchResult type) |
||||
{ |
||||
TokenSearchResult typeCode = type & TokenSearchResult.TypeCodeMask; |
||||
if (typeCode == 0 || typeCode == TokenSearchResult.SystemType) |
||||
throw new EnumUnderlyingTypeResolveException(); |
||||
return (PrimitiveTypeCode)typeCode; |
||||
} |
||||
|
||||
public bool IsSystemType(TokenSearchResult type) => (type & TokenSearchResult.TypeCodeMask) == TokenSearchResult.SystemType; |
||||
} |
||||
} |
Loading…
Reference in new issue