File: PEWriter\MetadataVisitor.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Collections.Generic;
using System.Diagnostics;
using Roslyn.Utilities;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Emit.EditAndContinue;
 
namespace Microsoft.Cci
{
    /// <summary>
    /// A visitor base class that traverses the object model in depth first, left to right order.
    /// </summary>
    internal abstract class MetadataVisitor
    {
        public readonly EmitContext Context;
 
        public MetadataVisitor(EmitContext context)
        {
            this.Context = context;
        }
 
        public virtual void Visit(IArrayTypeReference arrayTypeReference)
        {
            this.Visit(arrayTypeReference.GetElementType(Context));
        }
 
        public void Visit(IEnumerable<IAssemblyReference> assemblyReferences)
        {
            foreach (IAssemblyReference assemblyReference in assemblyReferences)
            {
                this.Visit((IUnitReference)assemblyReference);
            }
        }
 
        public virtual void Visit(IAssemblyReference assemblyReference)
        {
        }
 
        public void Visit(IEnumerable<ICustomAttribute> customAttributes)
        {
            foreach (ICustomAttribute customAttribute in customAttributes)
            {
                this.Visit(customAttribute);
            }
        }
 
        public virtual void Visit(ICustomAttribute customAttribute)
        {
            IMethodReference constructor = customAttribute.Constructor(Context, reportDiagnostics: false);
            if (constructor is null)
            {
                return;
            }
 
            this.Visit(customAttribute.GetArguments(Context));
            this.Visit(constructor);
            this.Visit(customAttribute.GetNamedArguments(Context));
        }
 
        public void Visit(ImmutableArray<ICustomModifier> customModifiers)
        {
            foreach (ICustomModifier customModifier in customModifiers)
            {
                this.Visit(customModifier);
            }
        }
 
        public virtual void Visit(ICustomModifier customModifier)
        {
            this.Visit(customModifier.GetModifier(Context));
        }
 
        public void Visit(IEnumerable<IEventDefinition> events)
        {
            foreach (IEventDefinition eventDef in events)
            {
                this.Visit((ITypeDefinitionMember)eventDef);
            }
        }
 
        public virtual void Visit(IEventDefinition eventDefinition)
        {
            this.Visit(eventDefinition.GetAccessors(Context));
            this.Visit(eventDefinition.GetType(Context));
        }
 
        public void Visit(IEnumerable<IFieldDefinition> fields)
        {
            foreach (IFieldDefinition field in fields)
            {
                this.Visit((ITypeDefinitionMember)field);
            }
        }
 
        public virtual void Visit(IFieldDefinition fieldDefinition)
        {
            var constant = fieldDefinition.GetCompileTimeValue(Context);
            var marshalling = fieldDefinition.MarshallingInformation;
 
            Debug.Assert((constant != null) == fieldDefinition.IsCompileTimeConstant);
            Debug.Assert((marshalling != null || !fieldDefinition.MarshallingDescriptor.IsDefaultOrEmpty) == fieldDefinition.IsMarshalledExplicitly);
 
            if (constant != null)
            {
                this.Visit((IMetadataExpression)constant);
            }
 
            if (marshalling != null)
            {
                // Note, we are not visiting MarshallingDescriptor. It is used only for 
                // NoPia embedded/local types and VB Dev11 simply copies the bits without
                // cracking them.
                this.Visit(marshalling);
            }
 
            this.Visit(fieldDefinition.RefCustomModifiers);
            this.Visit(fieldDefinition.GetType(Context));
        }
 
        public virtual void Visit(IFieldReference fieldReference)
        {
            this.Visit((ITypeMemberReference)fieldReference);
        }
 
        public void Visit(IEnumerable<IFileReference> fileReferences)
        {
            foreach (IFileReference fileReference in fileReferences)
            {
                this.Visit(fileReference);
            }
        }
 
        public virtual void Visit(IFileReference fileReference)
        {
        }
 
        public virtual void Visit(IGenericMethodInstanceReference genericMethodInstanceReference)
        {
        }
 
        public void Visit(IEnumerable<IGenericMethodParameter> genericParameters)
        {
            foreach (IGenericMethodParameter genericParameter in genericParameters)
            {
                this.Visit((IGenericParameter)genericParameter);
            }
        }
 
        public virtual void Visit(IGenericMethodParameter genericMethodParameter)
        {
        }
 
        public virtual void Visit(IGenericMethodParameterReference genericMethodParameterReference)
        {
        }
 
        public virtual void Visit(IGenericParameter genericParameter)
        {
            this.Visit(genericParameter.GetAttributes(Context));
            this.Visit(genericParameter.GetConstraints(Context));
 
            genericParameter.Dispatch(this);
        }
 
        public abstract void Visit(IGenericTypeInstanceReference genericTypeInstanceReference);
 
        public void Visit(IEnumerable<IGenericParameter> genericParameters)
        {
            foreach (IGenericTypeParameter genericParameter in genericParameters)
            {
                this.Visit((IGenericParameter)genericParameter);
            }
        }
 
        public virtual void Visit(IGenericTypeParameter genericTypeParameter)
        {
        }
 
        public virtual void Visit(IGenericTypeParameterReference genericTypeParameterReference)
        {
        }
 
        public virtual void Visit(IGlobalFieldDefinition globalFieldDefinition)
        {
            this.Visit((IFieldDefinition)globalFieldDefinition);
        }
 
        public virtual void Visit(IGlobalMethodDefinition globalMethodDefinition)
        {
            this.Visit((IMethodDefinition)globalMethodDefinition);
        }
 
        public void Visit(ImmutableArray<ILocalDefinition> localDefinitions)
        {
            foreach (ILocalDefinition localDefinition in localDefinitions)
            {
                this.Visit(localDefinition);
            }
        }
 
        public virtual void Visit(ILocalDefinition localDefinition)
        {
            this.Visit(localDefinition.CustomModifiers);
            this.Visit(localDefinition.Type);
        }
 
        public virtual void Visit(IMarshallingInformation marshallingInformation)
        {
            throw ExceptionUtilities.Unreachable();
        }
 
        public virtual void Visit(MetadataConstant constant)
        {
        }
 
        public virtual void Visit(MetadataCreateArray createArray)
        {
            this.Visit(createArray.ElementType);
            this.Visit(createArray.Elements);
        }
 
        public void Visit(IEnumerable<IMetadataExpression> expressions)
        {
            foreach (IMetadataExpression expression in expressions)
            {
                this.Visit(expression);
            }
        }
 
        public virtual void Visit(IMetadataExpression expression)
        {
            this.Visit(expression.Type);
            expression.Dispatch(this);
        }
 
        public void Visit(IEnumerable<IMetadataNamedArgument> namedArguments)
        {
            foreach (IMetadataNamedArgument namedArgument in namedArguments)
            {
                this.Visit((IMetadataExpression)namedArgument);
            }
        }
 
        public virtual void Visit(IMetadataNamedArgument namedArgument)
        {
            this.Visit(namedArgument.ArgumentValue);
        }
 
        public virtual void Visit(MetadataTypeOf typeOf)
        {
            if (typeOf.TypeToGet != null)
            {
                this.Visit(typeOf.TypeToGet);
            }
        }
 
        public virtual void Visit(IMethodBody methodBody)
        {
            foreach (var scope in methodBody.LocalScopes)
            {
                this.Visit(scope.Constants);
            }
 
            this.Visit(methodBody.LocalVariables);
            //this.Visit(methodBody.Operations);    //in Roslyn we don't break out each instruction as it's own operation.
            this.Visit(methodBody.ExceptionRegions);
        }
 
        public void Visit(IEnumerable<IMethodDefinition> methods)
        {
            foreach (IMethodDefinition method in methods)
            {
                this.Visit((ITypeDefinitionMember)method);
            }
        }
 
        public virtual void Visit(IMethodDefinition method)
        {
            // Only visit signature components for EnC-deleted methods (generic parameters and attributes are not emitted). 
            bool signatureOnly = method.IsEncDeleted;
 
            // Deletes of PE methods should not be visited since their signature is reused from the deleted PE symbol.
            if (signatureOnly && method is DeletedPEMethodDefinition { MetadataSignatureHandle.IsNil: false })
            {
                return;
            }
 
            if (!signatureOnly)
            {
                this.Visit(method.GetReturnValueAttributes(Context));
            }
 
            this.Visit(method.RefCustomModifiers);
            this.Visit(method.ReturnValueCustomModifiers);
 
            if (!signatureOnly && method.HasDeclarativeSecurity)
            {
                this.Visit(method.SecurityAttributes);
            }
 
            if (!signatureOnly && method.GenericParameterCount > 0)
            {
                this.Visit(method.GenericParameters);
            }
 
            this.Visit(method.GetType(Context));
            this.Visit(method.Parameters);
 
            if (!signatureOnly && method.IsPlatformInvoke)
            {
                this.Visit(method.PlatformInvokeData);
            }
        }
 
        public void Visit(IEnumerable<MethodImplementation> methodImplementations)
        {
            foreach (MethodImplementation methodImplementation in methodImplementations)
            {
                this.Visit(methodImplementation);
            }
        }
 
        public virtual void Visit(MethodImplementation methodImplementation)
        {
            this.Visit(methodImplementation.ImplementedMethod);
            this.Visit(methodImplementation.ImplementingMethod);
        }
 
        public void Visit(IEnumerable<IMethodReference> methodReferences)
        {
            foreach (IMethodReference methodReference in methodReferences)
            {
                this.Visit(methodReference);
            }
        }
 
        public virtual void Visit(IMethodReference methodReference)
        {
            IGenericMethodInstanceReference? genericMethodInstanceReference = methodReference.AsGenericMethodInstanceReference;
            if (genericMethodInstanceReference != null)
            {
                this.Visit(genericMethodInstanceReference);
            }
            else
            {
                this.Visit((ITypeMemberReference)methodReference);
            }
        }
 
        public virtual void Visit(IModifiedTypeReference modifiedTypeReference)
        {
            this.Visit(modifiedTypeReference.CustomModifiers);
            this.Visit(modifiedTypeReference.UnmodifiedType);
        }
 
        public abstract void Visit(CommonPEModuleBuilder module);
 
        public void Visit(IEnumerable<IModuleReference> moduleReferences)
        {
            foreach (IModuleReference moduleReference in moduleReferences)
            {
                this.Visit((IUnitReference)moduleReference);
            }
        }
 
        public virtual void Visit(IModuleReference moduleReference)
        {
        }
 
        public void Visit(IEnumerable<INamedTypeDefinition> types)
        {
            foreach (INamedTypeDefinition type in types)
            {
                this.Visit(type);
            }
        }
 
        public virtual void Visit(INamespaceTypeDefinition namespaceTypeDefinition)
        {
        }
 
        public virtual void Visit(INamespaceTypeReference namespaceTypeReference)
        {
        }
 
        public void VisitNestedTypes(IEnumerable<INamedTypeDefinition> nestedTypes)
        {
            foreach (ITypeDefinitionMember nestedType in nestedTypes)
            {
                this.Visit(nestedType);
            }
        }
 
        public virtual void Visit(INestedTypeDefinition nestedTypeDefinition)
        {
        }
 
        public virtual void Visit(INestedTypeReference nestedTypeReference)
        {
            this.Visit(nestedTypeReference.GetContainingType(Context));
        }
 
        public void Visit(ImmutableArray<ExceptionHandlerRegion> exceptionRegions)
        {
            foreach (ExceptionHandlerRegion region in exceptionRegions)
            {
                this.Visit(region);
            }
        }
 
        public virtual void Visit(ExceptionHandlerRegion exceptionRegion)
        {
            var exceptionType = exceptionRegion.ExceptionType;
            if (exceptionType != null)
            {
                this.Visit(exceptionType);
            }
        }
 
        public void Visit(ImmutableArray<IParameterDefinition> parameters)
        {
            foreach (IParameterDefinition parameter in parameters)
            {
                this.Visit(parameter);
            }
        }
 
        public virtual void Visit(IParameterDefinition parameterDefinition)
        {
            var marshalling = parameterDefinition.MarshallingInformation;
 
            Debug.Assert((marshalling != null || !parameterDefinition.MarshallingDescriptor.IsDefaultOrEmpty) == parameterDefinition.IsMarshalledExplicitly);
 
            if (!parameterDefinition.IsEncDeleted)
            {
                this.Visit(parameterDefinition.GetAttributes(Context));
            }
 
            this.Visit(parameterDefinition.RefCustomModifiers);
            this.Visit(parameterDefinition.CustomModifiers);
 
            MetadataConstant? defaultValue = parameterDefinition.GetDefaultValue(Context);
            if (defaultValue != null)
            {
                this.Visit((IMetadataExpression)defaultValue);
            }
 
            if (marshalling != null)
            {
                // Note, we are not visiting MarshallingDescriptor. It is used only for 
                // NoPia embedded/local types and VB Dev11 simply copies the bits without
                // cracking them.
                this.Visit(marshalling);
            }
 
            this.Visit(parameterDefinition.GetType(Context));
        }
 
        public void Visit(ImmutableArray<IParameterTypeInformation> parameterTypeInformations)
        {
            foreach (IParameterTypeInformation parameterTypeInformation in parameterTypeInformations)
            {
                this.Visit(parameterTypeInformation);
            }
        }
 
        public virtual void Visit(IParameterTypeInformation parameterTypeInformation)
        {
            this.Visit(parameterTypeInformation.RefCustomModifiers);
            this.Visit(parameterTypeInformation.CustomModifiers);
            this.Visit(parameterTypeInformation.GetType(Context));
        }
 
        public virtual void Visit(IPlatformInvokeInformation platformInvokeInformation)
        {
        }
 
        public virtual void Visit(IPointerTypeReference pointerTypeReference)
        {
            this.Visit(pointerTypeReference.GetTargetType(Context));
        }
 
        public virtual void Visit(IFunctionPointerTypeReference functionPointerTypeReference)
        {
            this.Visit(functionPointerTypeReference.Signature.RefCustomModifiers);
            this.Visit(functionPointerTypeReference.Signature.ReturnValueCustomModifiers);
            this.Visit(functionPointerTypeReference.Signature.GetType(Context));
 
            foreach (var param in functionPointerTypeReference.Signature.GetParameters(Context))
            {
                this.Visit(param);
            }
        }
 
        public void Visit(IEnumerable<IPropertyDefinition> properties)
        {
            foreach (IPropertyDefinition property in properties)
            {
                this.Visit((ITypeDefinitionMember)property);
            }
        }
 
        public virtual void Visit(IPropertyDefinition propertyDefinition)
        {
            this.Visit(propertyDefinition.GetAccessors(Context));
            this.Visit(propertyDefinition.Parameters);
        }
 
        public void Visit(IEnumerable<ManagedResource> resources)
        {
            foreach (var resource in resources)
            {
                this.Visit(resource);
            }
        }
 
        public virtual void Visit(ManagedResource resource)
        {
        }
 
        public virtual void Visit(SecurityAttribute securityAttribute)
        {
            this.Visit(securityAttribute.Attribute);
        }
 
        public void Visit(IEnumerable<SecurityAttribute> securityAttributes)
        {
            foreach (SecurityAttribute securityAttribute in securityAttributes)
            {
                this.Visit(securityAttribute);
            }
        }
 
        public void Visit(IEnumerable<ITypeDefinitionMember> typeMembers)
        {
            foreach (ITypeDefinitionMember typeMember in typeMembers)
            {
                this.Visit(typeMember);
            }
        }
 
        public void Visit(IEnumerable<ITypeDefinition> types)
        {
            foreach (ITypeDefinition type in types)
            {
                this.Visit(type);
            }
        }
 
        public abstract void Visit(ITypeDefinition typeDefinition);
 
        public virtual void Visit(ITypeDefinitionMember typeMember)
        {
            ITypeDefinition? nestedType = typeMember as INestedTypeDefinition;
            if (nestedType != null)
            {
                this.Visit(nestedType);
            }
            else
            {
                if (!typeMember.IsEncDeleted)
                {
                    this.Visit(typeMember.GetAttributes(Context));
                }
 
                typeMember.Dispatch(this);
            }
        }
 
        public virtual void Visit(ITypeMemberReference typeMemberReference)
        {
            if (typeMemberReference.AsDefinition(Context) == null)
            {
                this.Visit(typeMemberReference.GetAttributes(Context)); // In principle, references can have attributes that are distinct from the definitions they refer to.
            }
        }
 
        public void Visit(IEnumerable<ITypeReference> typeReferences)
        {
            foreach (ITypeReference typeReference in typeReferences)
            {
                this.Visit(typeReference);
            }
        }
 
        public void Visit(IEnumerable<TypeReferenceWithAttributes> typeRefsWithAttributes)
        {
            foreach (var typeRefWithAttributes in typeRefsWithAttributes)
            {
                this.Visit(typeRefWithAttributes.TypeRef);
                this.Visit(typeRefWithAttributes.Attributes);
            }
        }
 
        public virtual void Visit(ITypeReference typeReference)
        {
            this.DispatchAsReference(typeReference);
        }
 
        /// <summary>
        /// Use this routine, rather than ITypeReference.Dispatch, to call the appropriate derived overload of an ITypeReference.
        /// The former routine will call Visit(INamespaceTypeDefinition) rather than Visit(INamespaceTypeReference), etc., 
        /// in the case where a definition is used as a reference to itself.
        /// </summary>
        /// <param name="typeReference">A reference to a type definition. Note that a type definition can serve as a reference to itself.</param>
        protected void DispatchAsReference(ITypeReference typeReference)
        {
            INamespaceTypeReference? namespaceTypeReference = typeReference.AsNamespaceTypeReference;
            if (namespaceTypeReference != null)
            {
                this.Visit(namespaceTypeReference);
                return;
            }
 
            IGenericTypeInstanceReference? genericTypeInstanceReference = typeReference.AsGenericTypeInstanceReference;
            if (genericTypeInstanceReference != null)
            {
                this.Visit(genericTypeInstanceReference);
                return;
            }
 
            INestedTypeReference? nestedTypeReference = typeReference.AsNestedTypeReference;
            if (nestedTypeReference != null)
            {
                this.Visit(nestedTypeReference);
                return;
            }
 
            IArrayTypeReference? arrayTypeReference = typeReference as IArrayTypeReference;
            if (arrayTypeReference != null)
            {
                this.Visit(arrayTypeReference);
                return;
            }
 
            IGenericTypeParameterReference? genericTypeParameterReference = typeReference.AsGenericTypeParameterReference;
            if (genericTypeParameterReference != null)
            {
                this.Visit(genericTypeParameterReference);
                return;
            }
 
            IGenericMethodParameterReference? genericMethodParameterReference = typeReference.AsGenericMethodParameterReference;
            if (genericMethodParameterReference != null)
            {
                this.Visit(genericMethodParameterReference);
                return;
            }
 
            IPointerTypeReference? pointerTypeReference = typeReference as IPointerTypeReference;
            if (pointerTypeReference != null)
            {
                this.Visit(pointerTypeReference);
                return;
            }
 
            IFunctionPointerTypeReference? functionPointerTypeReference = typeReference as IFunctionPointerTypeReference;
            if (functionPointerTypeReference != null)
            {
                this.Visit(functionPointerTypeReference);
                return;
            }
 
            IModifiedTypeReference? modifiedTypeReference = typeReference as IModifiedTypeReference;
            if (modifiedTypeReference != null)
            {
                this.Visit(modifiedTypeReference);
                return;
            }
        }
 
        public void Visit(IEnumerable<IUnitReference> unitReferences)
        {
            foreach (IUnitReference unitReference in unitReferences)
            {
                this.Visit(unitReference);
            }
        }
 
        public virtual void Visit(IUnitReference unitReference)
        {
            this.DispatchAsReference(unitReference);
        }
 
        /// <summary>
        /// Use this routine, rather than IUnitReference.Dispatch, to call the appropriate derived overload of an IUnitReference.
        /// The former routine will call Visit(IAssembly) rather than Visit(IAssemblyReference), etc.
        /// in the case where a definition is used as the reference to itself.
        /// </summary>
        /// <param name="unitReference">A reference to a unit. Note that a unit can serve as a reference to itself.</param>
        private void DispatchAsReference(IUnitReference unitReference)
        {
            IAssemblyReference? assemblyReference = unitReference as IAssemblyReference;
            if (assemblyReference != null)
            {
                this.Visit(assemblyReference);
                return;
            }
 
            IModuleReference? moduleReference = unitReference as IModuleReference;
            if (moduleReference != null)
            {
                this.Visit(moduleReference);
                return;
            }
        }
 
        public virtual void Visit(IWin32Resource win32Resource)
        {
        }
    }
}