Browse Source

Make RequiredNamespaceCollector an instance

pull/1505/head
Siegfried Pammer 6 years ago
parent
commit
1e3b3090e0
  1. 159
      ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

159
ICSharpCode.Decompiler/CSharp/RequiredNamespaceCollector.cs

@ -3,16 +3,10 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Reflection.Metadata; 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.Disassembler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using static ICSharpCode.Decompiler.Metadata.ILOpCodeExtensions; using static ICSharpCode.Decompiler.Metadata.ILOpCodeExtensions;
@ -20,24 +14,39 @@ namespace ICSharpCode.Decompiler.CSharp
{ {
class RequiredNamespaceCollector class RequiredNamespaceCollector
{ {
static readonly Decompiler.TypeSystem.GenericContext genericContext = default;
readonly HashSet<string> namespaces;
public RequiredNamespaceCollector(HashSet<string> namespaces)
{
this.namespaces = namespaces;
}
public static void CollectNamespaces(MetadataModule module, HashSet<string> namespaces) public static void CollectNamespaces(MetadataModule module, HashSet<string> namespaces)
{ {
var collector = new RequiredNamespaceCollector(namespaces);
foreach (var type in module.TypeDefinitions) { foreach (var type in module.TypeDefinitions) {
CollectNamespaces(type, module, namespaces); collector.CollectNamespaces(type, module, (CodeMappingInfo)null);
} }
CollectAttributeNamespaces(module, namespaces); collector.HandleAttributes(module.GetAssemblyAttributes());
collector.HandleAttributes(module.GetModuleAttributes());
} }
public static void CollectAttributeNamespaces(MetadataModule module, HashSet<string> namespaces) public static void CollectAttributeNamespaces(MetadataModule module, HashSet<string> namespaces)
{ {
HandleAttributes(module.GetAssemblyAttributes(), namespaces); var collector = new RequiredNamespaceCollector(namespaces);
HandleAttributes(module.GetModuleAttributes(), namespaces); collector.HandleAttributes(module.GetAssemblyAttributes());
collector.HandleAttributes(module.GetModuleAttributes());
} }
static readonly Decompiler.TypeSystem.GenericContext genericContext = default; public static void CollectNamespaces(IEntity entity, MetadataModule module, HashSet<string> namespaces)
{
var collector = new RequiredNamespaceCollector(namespaces);
collector.CollectNamespaces(entity, module);
}
public static void CollectNamespaces(IEntity entity, MetadataModule module, void CollectNamespaces(IEntity entity, MetadataModule module, CodeMappingInfo mappingInfo = null)
HashSet<string> namespaces, CodeMappingInfo mappingInfo = null)
{ {
if (entity == null || entity.MetadataToken.IsNil) if (entity == null || entity.MetadataToken.IsNil)
return; return;
@ -46,53 +55,53 @@ namespace ICSharpCode.Decompiler.CSharp
if (mappingInfo == null) if (mappingInfo == null)
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken); mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken);
namespaces.Add(td.Namespace); namespaces.Add(td.Namespace);
HandleAttributes(td.GetAttributes(), namespaces); HandleAttributes(td.GetAttributes());
HandleTypeParameters(td.TypeParameters, namespaces); HandleTypeParameters(td.TypeParameters);
foreach (var baseType in td.DirectBaseTypes) { foreach (var baseType in td.DirectBaseTypes) {
CollectNamespacesForTypeReference(baseType, namespaces); CollectNamespacesForTypeReference(baseType);
} }
foreach (var nestedType in td.NestedTypes) { foreach (var nestedType in td.NestedTypes) {
CollectNamespaces(nestedType, module, namespaces, mappingInfo); CollectNamespaces(nestedType, module, mappingInfo);
} }
foreach (var field in td.Fields) { foreach (var field in td.Fields) {
CollectNamespaces(field, module, namespaces, mappingInfo); CollectNamespaces(field, module, mappingInfo);
} }
foreach (var property in td.Properties) { foreach (var property in td.Properties) {
CollectNamespaces(property, module, namespaces, mappingInfo); CollectNamespaces(property, module, mappingInfo);
} }
foreach (var @event in td.Events) { foreach (var @event in td.Events) {
CollectNamespaces(@event, module, namespaces, mappingInfo); CollectNamespaces(@event, module, mappingInfo);
} }
foreach (var method in td.Methods) { foreach (var method in td.Methods) {
CollectNamespaces(method, module, namespaces, mappingInfo); CollectNamespaces(method, module, mappingInfo);
} }
break; break;
case IField field: case IField field:
HandleAttributes(field.GetAttributes(), namespaces); HandleAttributes(field.GetAttributes());
CollectNamespacesForTypeReference(field.ReturnType, namespaces); CollectNamespacesForTypeReference(field.ReturnType);
break; break;
case IMethod method: case IMethod method:
HandleAttributes(method.GetAttributes(), namespaces); HandleAttributes(method.GetAttributes());
HandleAttributes(method.GetReturnTypeAttributes(), namespaces); HandleAttributes(method.GetReturnTypeAttributes());
CollectNamespacesForTypeReference(method.ReturnType, namespaces); CollectNamespacesForTypeReference(method.ReturnType);
foreach (var param in method.Parameters) { foreach (var param in method.Parameters) {
HandleAttributes(param.GetAttributes(), namespaces); HandleAttributes(param.GetAttributes());
CollectNamespacesForTypeReference(param.Type, namespaces); CollectNamespacesForTypeReference(param.Type);
} }
HandleTypeParameters(method.TypeParameters, namespaces); HandleTypeParameters(method.TypeParameters);
if (!method.MetadataToken.IsNil) { if (!method.MetadataToken.IsNil) {
if (mappingInfo == null) if (mappingInfo == null)
mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken); mappingInfo = CSharpDecompiler.GetCodeMappingInfo(entity.ParentModule.PEFile, entity.MetadataToken);
var reader = module.PEFile.Reader; var reader = module.PEFile.Reader;
var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList(); var parts = mappingInfo.GetMethodParts((MethodDefinitionHandle)method.MetadataToken).ToList();
foreach (var part in parts) { foreach (var part in parts) {
HandleOverrides(part.GetMethodImplementations(module.metadata), module, namespaces); HandleOverrides(part.GetMethodImplementations(module.metadata), module);
var methodDef = module.metadata.GetMethodDefinition(part); var methodDef = module.metadata.GetMethodDefinition(part);
if (method.HasBody) { if (method.HasBody) {
MethodBodyBlock body; MethodBodyBlock body;
@ -101,49 +110,49 @@ namespace ICSharpCode.Decompiler.CSharp
} catch (BadImageFormatException) { } catch (BadImageFormatException) {
continue; continue;
} }
CollectNamespacesFromMethodBody(body, module, namespaces); CollectNamespacesFromMethodBody(body, module);
} }
} }
} }
break; break;
case IProperty property: case IProperty property:
HandleAttributes(property.GetAttributes(), namespaces); HandleAttributes(property.GetAttributes());
CollectNamespaces(property.Getter, module, namespaces); CollectNamespaces(property.Getter, module);
CollectNamespaces(property.Setter, module, namespaces); CollectNamespaces(property.Setter, module);
break; break;
case IEvent @event: case IEvent @event:
HandleAttributes(@event.GetAttributes(), namespaces); HandleAttributes(@event.GetAttributes());
CollectNamespaces(@event.AddAccessor, module, namespaces); CollectNamespaces(@event.AddAccessor, module);
CollectNamespaces(@event.RemoveAccessor, module, namespaces); CollectNamespaces(@event.RemoveAccessor, module);
break; break;
} }
} }
static void HandleOverrides(ImmutableArray<MethodImplementationHandle> immutableArray, MetadataModule module, HashSet<string> namespaces) void HandleOverrides(ImmutableArray<MethodImplementationHandle> immutableArray, MetadataModule module)
{ {
foreach (var h in immutableArray) { foreach (var h in immutableArray) {
var methodImpl = module.metadata.GetMethodImplementation(h); var methodImpl = module.metadata.GetMethodImplementation(h);
CollectNamespacesForTypeReference(module.ResolveType(methodImpl.Type, genericContext), namespaces); CollectNamespacesForTypeReference(module.ResolveType(methodImpl.Type, genericContext));
CollectNamespacesForMemberReference(module.ResolveMethod(methodImpl.MethodBody, genericContext), module, namespaces); CollectNamespacesForMemberReference(module.ResolveMethod(methodImpl.MethodBody, genericContext));
CollectNamespacesForMemberReference(module.ResolveMethod(methodImpl.MethodDeclaration, genericContext), module, namespaces); CollectNamespacesForMemberReference(module.ResolveMethod(methodImpl.MethodDeclaration, genericContext));
} }
} }
static void CollectNamespacesForTypeReference(IType type, HashSet<string> namespaces) void CollectNamespacesForTypeReference(IType type)
{ {
switch (type) { switch (type) {
case ParameterizedType parameterizedType: case ParameterizedType parameterizedType:
namespaces.Add(parameterizedType.Namespace); namespaces.Add(parameterizedType.Namespace);
CollectNamespacesForTypeReference(parameterizedType.GenericType, namespaces); CollectNamespacesForTypeReference(parameterizedType.GenericType);
foreach (var arg in parameterizedType.TypeArguments) foreach (var arg in parameterizedType.TypeArguments)
CollectNamespacesForTypeReference(arg, namespaces); CollectNamespacesForTypeReference(arg);
break; break;
case TypeWithElementType typeWithElementType: case TypeWithElementType typeWithElementType:
CollectNamespacesForTypeReference(typeWithElementType.ElementType, namespaces); CollectNamespacesForTypeReference(typeWithElementType.ElementType);
break; break;
case TupleType tupleType: case TupleType tupleType:
foreach (var elementType in tupleType.ElementTypes) { foreach (var elementType in tupleType.ElementTypes) {
CollectNamespacesForTypeReference(elementType, namespaces); CollectNamespacesForTypeReference(elementType);
} }
break; break;
default: default:
@ -161,43 +170,43 @@ namespace ICSharpCode.Decompiler.CSharp
CollectNamespaces(module.ResolveEntity(entity, genericContext), module, namespaces); CollectNamespaces(module.ResolveEntity(entity, genericContext), module, namespaces);
} }
public static void HandleAttributes(IEnumerable<IAttribute> attributes, HashSet<string> namespaces) void HandleAttributes(IEnumerable<IAttribute> attributes)
{ {
foreach (var attr in attributes) { foreach (var attr in attributes) {
namespaces.Add(attr.AttributeType.Namespace); namespaces.Add(attr.AttributeType.Namespace);
foreach (var arg in attr.FixedArguments) { foreach (var arg in attr.FixedArguments) {
HandleAttributeValue(arg.Type, arg.Value, namespaces); HandleAttributeValue(arg.Type, arg.Value);
} }
foreach (var arg in attr.NamedArguments) { foreach (var arg in attr.NamedArguments) {
HandleAttributeValue(arg.Type, arg.Value, namespaces); HandleAttributeValue(arg.Type, arg.Value);
} }
} }
} }
static void HandleAttributeValue(IType type, object value, HashSet<string> namespaces) void HandleAttributeValue(IType type, object value)
{ {
CollectNamespacesForTypeReference(type, namespaces); CollectNamespacesForTypeReference(type);
if (value is IType typeofType) if (value is IType typeofType)
CollectNamespacesForTypeReference(typeofType, namespaces); CollectNamespacesForTypeReference(typeofType);
if (value is ImmutableArray<CustomAttributeTypedArgument<IType>> arr) { if (value is ImmutableArray<CustomAttributeTypedArgument<IType>> arr) {
foreach (var element in arr) { foreach (var element in arr) {
HandleAttributeValue(element.Type, element.Value, namespaces); HandleAttributeValue(element.Type, element.Value);
} }
} }
} }
static void HandleTypeParameters(IEnumerable<ITypeParameter> typeParameters, HashSet<string> namespaces) void HandleTypeParameters(IEnumerable<ITypeParameter> typeParameters)
{ {
foreach (var typeParam in typeParameters) { foreach (var typeParam in typeParameters) {
HandleAttributes(typeParam.GetAttributes(), namespaces); HandleAttributes(typeParam.GetAttributes());
foreach (var constraint in typeParam.DirectBaseTypes) { foreach (var constraint in typeParam.DirectBaseTypes) {
CollectNamespacesForTypeReference(constraint, namespaces); CollectNamespacesForTypeReference(constraint);
} }
} }
} }
static void CollectNamespacesFromMethodBody(MethodBodyBlock method, MetadataModule module, HashSet<string> namespaces) void CollectNamespacesFromMethodBody(MethodBodyBlock method, MetadataModule module)
{ {
var metadata = module.metadata; var metadata = module.metadata;
var instructions = method.GetILReader(); var instructions = method.GetILReader();
@ -211,7 +220,7 @@ namespace ICSharpCode.Decompiler.CSharp
localSignature = ImmutableArray<IType>.Empty; localSignature = ImmutableArray<IType>.Empty;
} }
foreach (var type in localSignature) foreach (var type in localSignature)
CollectNamespacesForTypeReference(type, namespaces); CollectNamespacesForTypeReference(type);
} }
foreach (var region in method.ExceptionRegions) { foreach (var region in method.ExceptionRegions) {
@ -223,7 +232,7 @@ namespace ICSharpCode.Decompiler.CSharp
} catch (BadImageFormatException) { } catch (BadImageFormatException) {
continue; continue;
} }
CollectNamespacesForTypeReference(ty, namespaces); CollectNamespacesForTypeReference(ty);
} }
while (instructions.RemainingBytes > 0) { while (instructions.RemainingBytes > 0) {
@ -234,11 +243,11 @@ namespace ICSharpCode.Decompiler.CSharp
return; return;
} }
switch (opCode.GetOperandType()) { switch (opCode.GetOperandType()) {
case Metadata.OperandType.Field: case OperandType.Field:
case Metadata.OperandType.Method: case OperandType.Method:
case Metadata.OperandType.Sig: case OperandType.Sig:
case Metadata.OperandType.Tok: case OperandType.Tok:
case Metadata.OperandType.Type: case OperandType.Type:
var handle = MetadataTokenHelpers.EntityHandleOrNil(instructions.ReadInt32()); var handle = MetadataTokenHelpers.EntityHandleOrNil(instructions.ReadInt32());
if (handle.IsNil) if (handle.IsNil)
break; break;
@ -252,7 +261,7 @@ namespace ICSharpCode.Decompiler.CSharp
} catch (BadImageFormatException) { } catch (BadImageFormatException) {
break; break;
} }
CollectNamespacesForTypeReference(type, namespaces); CollectNamespacesForTypeReference(type);
break; break;
case HandleKind.FieldDefinition: case HandleKind.FieldDefinition:
case HandleKind.MethodDefinition: case HandleKind.MethodDefinition:
@ -264,7 +273,7 @@ namespace ICSharpCode.Decompiler.CSharp
} catch (BadImageFormatException) { } catch (BadImageFormatException) {
break; break;
} }
CollectNamespacesForMemberReference(member, module, namespaces); CollectNamespacesForMemberReference(member);
break; break;
case HandleKind.StandaloneSignature: case HandleKind.StandaloneSignature:
StandaloneSignature sig; StandaloneSignature sig;
@ -280,9 +289,9 @@ namespace ICSharpCode.Decompiler.CSharp
} catch (BadImageFormatException) { } catch (BadImageFormatException) {
break; break;
} }
CollectNamespacesForTypeReference(methodSig.ReturnType, namespaces); CollectNamespacesForTypeReference(methodSig.ReturnType);
foreach (var paramType in methodSig.ParameterTypes) { foreach (var paramType in methodSig.ParameterTypes) {
CollectNamespacesForTypeReference(paramType, namespaces); CollectNamespacesForTypeReference(paramType);
} }
} }
break; break;
@ -299,20 +308,20 @@ namespace ICSharpCode.Decompiler.CSharp
} }
} }
static void CollectNamespacesForMemberReference(IMember member, MetadataModule module, HashSet<string> namespaces) void CollectNamespacesForMemberReference(IMember member)
{ {
switch (member) { switch (member) {
case IField field: case IField field:
CollectNamespacesForTypeReference(field.DeclaringType, namespaces); CollectNamespacesForTypeReference(field.DeclaringType);
CollectNamespacesForTypeReference(field.ReturnType, namespaces); CollectNamespacesForTypeReference(field.ReturnType);
break; break;
case IMethod method: case IMethod method:
CollectNamespacesForTypeReference(method.DeclaringType, namespaces); CollectNamespacesForTypeReference(method.DeclaringType);
CollectNamespacesForTypeReference(method.ReturnType, namespaces); CollectNamespacesForTypeReference(method.ReturnType);
foreach (var param in method.Parameters) foreach (var param in method.Parameters)
CollectNamespacesForTypeReference(param.Type, namespaces); CollectNamespacesForTypeReference(param.Type);
foreach (var arg in method.TypeArguments) foreach (var arg in method.TypeArguments)
CollectNamespacesForTypeReference(arg, namespaces); CollectNamespacesForTypeReference(arg);
break; break;
} }
} }

Loading…
Cancel
Save