mirror of https://github.com/icsharpcode/ILSpy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
9.6 KiB
254 lines
9.6 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Collections.Immutable; |
|
using System.Linq; |
|
using System.Reflection.Metadata; |
|
using System.Reflection.Metadata.Ecma335; |
|
using System.Reflection.PortableExecutable; |
|
using System.Text; |
|
using System.Threading.Tasks; |
|
using ICSharpCode.Decompiler.Disassembler; |
|
using ICSharpCode.Decompiler.Metadata; |
|
using ICSharpCode.Decompiler.Semantics; |
|
using ICSharpCode.Decompiler.TypeSystem; |
|
using ICSharpCode.Decompiler.TypeSystem.Implementation; |
|
using ICSharpCode.Decompiler.Util; |
|
|
|
using static ICSharpCode.Decompiler.Metadata.ILOpCodeExtensions; |
|
|
|
namespace ICSharpCode.Decompiler.CSharp |
|
{ |
|
class RequiredNamespaceCollector |
|
{ |
|
public static void CollectNamespaces(DecompilerTypeSystem typeSystem, HashSet<string> namespaces) |
|
{ |
|
foreach (var type in typeSystem.MainAssembly.TypeDefinitions) { |
|
CollectNamespaces(type, typeSystem, namespaces); |
|
} |
|
CollectAttributeNamespaces(typeSystem, namespaces); |
|
} |
|
|
|
public static void CollectAttributeNamespaces(DecompilerTypeSystem typeSystem, HashSet<string> namespaces) |
|
{ |
|
HandleAttributes(typeSystem.MainAssembly.GetAssemblyAttributes(), namespaces); |
|
HandleAttributes(typeSystem.MainAssembly.GetModuleAttributes(), namespaces); |
|
} |
|
|
|
public static void CollectNamespaces(IEntity entity, DecompilerTypeSystem typeSystem, HashSet<string> namespaces, bool scanningFullType = false) |
|
{ |
|
if (entity == null) |
|
return; |
|
switch (entity) { |
|
case ITypeDefinition td: |
|
namespaces.Add(td.Namespace); |
|
HandleAttributes(td.GetAttributes(), namespaces); |
|
|
|
foreach (var typeParam in td.TypeParameters) { |
|
HandleAttributes(typeParam.GetAttributes(), namespaces); |
|
} |
|
|
|
foreach (var baseType in td.DirectBaseTypes) { |
|
CollectNamespacesForTypeReference(baseType, namespaces); |
|
} |
|
|
|
foreach (var nestedType in td.NestedTypes) { |
|
CollectNamespaces(nestedType, typeSystem, namespaces, scanningFullType: true); |
|
} |
|
|
|
foreach (var field in td.Fields) { |
|
CollectNamespaces(field, typeSystem, namespaces, scanningFullType: true); |
|
} |
|
|
|
foreach (var property in td.Properties) { |
|
CollectNamespaces(property, typeSystem, namespaces, scanningFullType: true); |
|
} |
|
|
|
foreach (var @event in td.Events) { |
|
CollectNamespaces(@event, typeSystem, namespaces, scanningFullType: true); |
|
} |
|
|
|
foreach (var method in td.Methods) { |
|
CollectNamespaces(method, typeSystem, namespaces, scanningFullType: true); |
|
} |
|
break; |
|
case IField field: |
|
HandleAttributes(field.GetAttributes(), namespaces); |
|
CollectNamespacesForTypeReference(field.ReturnType, namespaces); |
|
break; |
|
case IMethod method: |
|
HandleAttributes(method.GetAttributes(), namespaces); |
|
HandleAttributes(method.GetReturnTypeAttributes(), namespaces); |
|
CollectNamespacesForTypeReference(method.ReturnType, namespaces); |
|
foreach (var param in method.Parameters) { |
|
HandleAttributes(param.GetAttributes(), namespaces); |
|
CollectNamespacesForTypeReference(param.Type, namespaces); |
|
} |
|
foreach (var typeParam in method.TypeParameters) { |
|
HandleAttributes(typeParam.GetAttributes(), namespaces); |
|
} |
|
if (!method.MetadataToken.IsNil && method.HasBody) { |
|
var reader = typeSystem.ModuleDefinition.Reader; |
|
var methodDef = typeSystem.ModuleDefinition.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken); |
|
var body = reader.GetMethodBody(methodDef.RelativeVirtualAddress); |
|
CollectNamespacesFromMethodBody(body, reader, typeSystem, namespaces, scanningFullType: scanningFullType); |
|
} |
|
break; |
|
case IProperty property: |
|
HandleAttributes(property.GetAttributes(), namespaces); |
|
CollectNamespaces(property.Getter, typeSystem, namespaces); |
|
CollectNamespaces(property.Setter, typeSystem, namespaces); |
|
break; |
|
case IEvent @event: |
|
HandleAttributes(@event.GetAttributes(), namespaces); |
|
CollectNamespaces(@event.AddAccessor, typeSystem, namespaces); |
|
CollectNamespaces(@event.RemoveAccessor, typeSystem, namespaces); |
|
break; |
|
} |
|
} |
|
|
|
static void CollectNamespacesForTypeReference(IType type, HashSet<string> namespaces) |
|
{ |
|
switch (type) { |
|
case ArrayType arrayType: |
|
namespaces.Add(arrayType.Namespace); |
|
CollectNamespacesForTypeReference(arrayType.ElementType, namespaces); |
|
break; |
|
case ParameterizedType parameterizedType: |
|
namespaces.Add(parameterizedType.Namespace); |
|
CollectNamespacesForTypeReference(parameterizedType.GenericType, namespaces); |
|
foreach (var arg in parameterizedType.TypeArguments) |
|
CollectNamespacesForTypeReference(arg, namespaces); |
|
break; |
|
case ByReferenceType byReferenceType: |
|
CollectNamespacesForTypeReference(byReferenceType.ElementType, namespaces); |
|
break; |
|
case PointerType pointerType: |
|
CollectNamespacesForTypeReference(pointerType.ElementType, namespaces); |
|
break; |
|
case TupleType tupleType: |
|
foreach (var elementType in tupleType.ElementTypes) { |
|
CollectNamespacesForTypeReference(elementType, namespaces); |
|
} |
|
break; |
|
default: |
|
namespaces.Add(type.Namespace); |
|
break; |
|
} |
|
} |
|
|
|
public static void CollectNamespaces(EntityHandle entity, DecompilerTypeSystem typeSystem, HashSet<string> namespaces) |
|
{ |
|
if (entity.Kind.IsTypeKind()) { |
|
CollectNamespaces(typeSystem.ResolveAsType(entity).GetDefinition(), typeSystem, namespaces); |
|
} else { |
|
CollectNamespaces(typeSystem.ResolveAsMember(entity), typeSystem, namespaces); |
|
} |
|
} |
|
|
|
public static void HandleAttributes(IEnumerable<IAttribute> attributes, HashSet<string> namespaces) |
|
{ |
|
foreach (var attr in attributes) { |
|
namespaces.Add(attr.AttributeType.Namespace); |
|
foreach (var arg in attr.FixedArguments) { |
|
HandleAttributeValue(arg.Type, arg.Value, namespaces); |
|
} |
|
foreach (var arg in attr.NamedArguments) { |
|
HandleAttributeValue(arg.Type, arg.Value, namespaces); |
|
} |
|
} |
|
} |
|
|
|
static void HandleAttributeValue(IType type, object value, HashSet<string> namespaces) |
|
{ |
|
CollectNamespacesForTypeReference(type, namespaces); |
|
if (value is IType typeofType) |
|
CollectNamespacesForTypeReference(typeofType, namespaces); |
|
if (value is ImmutableArray<CustomAttributeTypedArgument<IType>> arr) { |
|
foreach (var element in arr) { |
|
HandleAttributeValue(element.Type, element.Value, namespaces); |
|
} |
|
} |
|
} |
|
|
|
static void CollectNamespacesFromMethodBody(MethodBodyBlock method, PEReader reader, DecompilerTypeSystem typeSystem, HashSet<string> namespaces, bool scanningFullType = false) |
|
{ |
|
var instructions = method.GetILReader(); |
|
var metadata = reader.GetMetadataReader(); |
|
|
|
if (!method.LocalSignature.IsNil) { |
|
var localSignature = typeSystem.DecodeLocalSignature(method.LocalSignature); |
|
foreach (var type in localSignature) |
|
CollectNamespacesForTypeReference(type, namespaces); |
|
} |
|
|
|
foreach (var region in method.ExceptionRegions) { |
|
if (region.CatchType.IsNil) continue; |
|
CollectNamespacesForTypeReference(typeSystem.ResolveAsType(region.CatchType), namespaces); |
|
} |
|
|
|
while (instructions.RemainingBytes > 0) { |
|
var opCode = instructions.DecodeOpCode(); |
|
switch (opCode.GetOperandType()) { |
|
case Metadata.OperandType.Field: |
|
case Metadata.OperandType.Method: |
|
case Metadata.OperandType.Sig: |
|
case Metadata.OperandType.Tok: |
|
case Metadata.OperandType.Type: |
|
var handle = MetadataTokenHelpers.EntityHandleOrNil(instructions.ReadInt32()); |
|
if (handle.IsNil) break; |
|
switch (handle.Kind) { |
|
case HandleKind.TypeDefinition: |
|
case HandleKind.TypeReference: |
|
case HandleKind.TypeSpecification: |
|
CollectNamespacesForTypeReference(typeSystem.ResolveAsType(handle), namespaces); |
|
break; |
|
case HandleKind.FieldDefinition: |
|
case HandleKind.MethodDefinition: |
|
case HandleKind.MethodSpecification: |
|
case HandleKind.MemberReference: |
|
CollectNamespacesForMemberReference(typeSystem.ResolveAsMember(handle), typeSystem, namespaces, scanningFullType: scanningFullType); |
|
break; |
|
case HandleKind.StandaloneSignature: |
|
var sig = metadata.GetStandaloneSignature((StandaloneSignatureHandle)handle); |
|
if (sig.GetKind() == StandaloneSignatureKind.Method) { |
|
var methodSig = typeSystem.DecodeMethodSignature((StandaloneSignatureHandle)handle); |
|
CollectNamespacesForTypeReference(methodSig.ReturnType, namespaces); |
|
foreach (var paramType in methodSig.ParameterTypes) { |
|
CollectNamespacesForTypeReference(paramType, namespaces); |
|
} |
|
} |
|
break; |
|
} |
|
break; |
|
default: |
|
instructions.SkipOperand(opCode); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
static void CollectNamespacesForMemberReference(IMember member, DecompilerTypeSystem typeSystem, HashSet<string> namespaces, bool scanningFullType = false) |
|
{ |
|
switch (member) { |
|
case IField field: |
|
if (!scanningFullType && field.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) |
|
CollectNamespaces(field, typeSystem, namespaces); |
|
else |
|
CollectNamespacesForTypeReference(field.DeclaringType, namespaces); |
|
CollectNamespacesForTypeReference(field.ReturnType, namespaces); |
|
break; |
|
case IMethod method: |
|
if (!scanningFullType && method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) |
|
CollectNamespaces(method, typeSystem, namespaces); |
|
else |
|
CollectNamespacesForTypeReference(method.DeclaringType, namespaces); |
|
CollectNamespacesForTypeReference(method.ReturnType, namespaces); |
|
foreach (var param in method.Parameters) |
|
CollectNamespacesForTypeReference(param.Type, namespaces); |
|
foreach (var arg in method.TypeArguments) |
|
CollectNamespacesForTypeReference(arg, namespaces); |
|
break; |
|
} |
|
} |
|
} |
|
}
|
|
|