| File: CodeGen\ReferenceDependencyWalker.cs | Web Access |
| Project: src\roslyn\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.Immutable; using Microsoft.CodeAnalysis.Emit; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen { /// <summary> /// Some features of the compiler (such as anonymous types, pay-as-you-go, NoPIA, ...) /// rely on all referenced symbols to go through translate mechanism. Because by default /// symbol translator does not translate some of indirectly referenced symbols, such as /// type argument, we have to force translation here /// /// This class provides unified implementation for this functionality. /// </summary> internal static class ReferenceDependencyWalker { public static void VisitReference(Cci.IReference reference, EmitContext context) { var typeReference = reference as Cci.ITypeReference; if (typeReference != null) { VisitTypeReference(typeReference, context); return; } var methodReference = reference as Cci.IMethodReference; if (methodReference != null) { VisitMethodReference(methodReference, context); return; } var fieldReference = reference as Cci.IFieldReference; if (fieldReference != null) { VisitFieldReference(fieldReference, context); return; } } private static void VisitTypeReference(Cci.ITypeReference typeReference, EmitContext context) { RoslynDebug.Assert(typeReference != null); Cci.IArrayTypeReference? arrayType = typeReference as Cci.IArrayTypeReference; if (arrayType != null) { VisitTypeReference(arrayType.GetElementType(context), context); return; } Cci.IPointerTypeReference? pointerType = typeReference as Cci.IPointerTypeReference; if (pointerType != null) { VisitTypeReference(pointerType.GetTargetType(context), context); return; } //Cci.IManagedPointerTypeReference managedPointerType = typeReference as Cci.IManagedPointerTypeReference; //if (managedPointerType != null) //{ // VisitTypeReference(managedPointerType.GetTargetType(this.context)); // return; //} Cci.IModifiedTypeReference? modifiedType = typeReference as Cci.IModifiedTypeReference; if (modifiedType != null) { VisitCustomModifiers(modifiedType.CustomModifiers, context); VisitTypeReference(modifiedType.UnmodifiedType, context); return; } // Visit containing type Cci.INestedTypeReference? nestedType = typeReference.AsNestedTypeReference; if (nestedType != null) { VisitTypeReference(nestedType.GetContainingType(context), context); } // Visit generic arguments Cci.IGenericTypeInstanceReference? genericInstance = typeReference.AsGenericTypeInstanceReference; if (genericInstance != null) { foreach (var arg in genericInstance.GetGenericArguments(context)) { VisitTypeReference(arg, context); } } if (typeReference is Cci.IFunctionPointerTypeReference functionPointer) { VisitSignature(functionPointer.Signature, context); } } private static void VisitMethodReference(Cci.IMethodReference methodReference, EmitContext context) { RoslynDebug.Assert(methodReference != null); // Visit containing type VisitTypeReference(methodReference.GetContainingType(context), context); // Visit generic arguments if any Cci.IGenericMethodInstanceReference? genericInstance = methodReference.AsGenericMethodInstanceReference; if (genericInstance != null) { foreach (var arg in genericInstance.GetGenericArguments(context)) { VisitTypeReference(arg, context); } methodReference = genericInstance.GetGenericMethod(context); } // Translate substituted method to original definition Cci.ISpecializedMethodReference? specializedMethod = methodReference.AsSpecializedMethodReference; if (specializedMethod != null) { methodReference = specializedMethod.UnspecializedVersion; } VisitSignature(methodReference, context); if (methodReference.AcceptsExtraArguments) { VisitParameters(methodReference.ExtraParameters, context); } } internal static void VisitSignature(Cci.ISignature signature, EmitContext context) { // Visit parameter types VisitParameters(signature.GetParameters(context), context); // Visit return value type VisitTypeReference(signature.GetType(context), context); VisitCustomModifiers(signature.RefCustomModifiers, context); foreach (var typeModifier in signature.ReturnValueCustomModifiers) { VisitTypeReference(typeModifier.GetModifier(context), context); } } private static void VisitParameters(ImmutableArray<Cci.IParameterTypeInformation> parameters, EmitContext context) { foreach (var param in parameters) { VisitTypeReference(param.GetType(context), context); VisitCustomModifiers(param.RefCustomModifiers, context); VisitCustomModifiers(param.CustomModifiers, context); } } private static void VisitFieldReference(Cci.IFieldReference fieldReference, EmitContext context) { RoslynDebug.Assert(fieldReference != null); // Visit containing type VisitTypeReference(fieldReference.GetContainingType(context), context); // Translate substituted field to original definition Cci.ISpecializedFieldReference? specializedField = fieldReference.AsSpecializedFieldReference; if (specializedField != null) { fieldReference = specializedField.UnspecializedVersion; } // Visit field type VisitTypeReference(fieldReference.GetType(context), context); VisitCustomModifiers(fieldReference.RefCustomModifiers, context); } private static void VisitCustomModifiers(ImmutableArray<Cci.ICustomModifier> customModifiers, in EmitContext context) { foreach (var typeModifier in customModifiers) { VisitTypeReference(typeModifier.GetModifier(context), context); } } } }