File: Linker\TypeNameResolver.WithDiagnostics.cs
Web Access
Project: src\src\tools\illink\src\linker\Mono.Linker.csproj (illink)
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using ILLink.Shared;
using ILLink.Shared.TrimAnalysis;
using Mono.Cecil;
 
using TypeName = System.Reflection.Metadata.TypeName;
 
namespace Mono.Linker
{
    internal sealed partial class TypeNameResolver
    {
        public bool TryResolveTypeName(
            string typeNameString,
            in DiagnosticContext diagnosticContext,
            [NotNullWhen(true)] out TypeReference? typeReference,
            [NotNullWhen(true)] out List<TypeResolutionRecord>? typeResolutionRecords,
            bool needsAssemblyName)
        {
            typeReference = null;
            typeResolutionRecords = null;
            if (string.IsNullOrEmpty(typeNameString))
                return false;
 
            if (!TypeName.TryParse(typeNameString, out TypeName? parsedTypeName, s_typeNameParseOptions))
                return false;
 
            if (needsAssemblyName && !IsFullyQualified(parsedTypeName))
            {
                diagnosticContext.AddDiagnostic(DiagnosticId.TypeNameIsNotAssemblyQualified, typeNameString);
                return false;
            }
 
            // If parsedTypeName doesn't have an assembly name in it but it does have a namespace,
            // search for the type in the calling object's assembly. If not found, look in the core
            // assembly.
            ICustomAttributeProvider? provider = diagnosticContext.Origin.Provider;
            AssemblyDefinition? referencingAssembly = provider switch
            {
                AssemblyDefinition asm => asm,
                TypeDefinition type => type.Module?.Assembly,
                IMemberDefinition member => member.DeclaringType.Module.Assembly,
                null => null,
                _ => throw new NotSupportedException()
            };
 
            if (referencingAssembly is null)
                return false;
 
            typeResolutionRecords = new List<TypeResolutionRecord>();
            typeReference = ResolveTypeName(referencingAssembly, parsedTypeName, typeResolutionRecords);
            return typeReference != null;
 
            static bool IsFullyQualified(TypeName typeName)
            {
                if (typeName.AssemblyName is null)
                    return false;
 
                if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef)
                    return IsFullyQualified(typeName.GetElementType());
 
                if (typeName.IsConstructedGenericType)
                {
                    foreach (var typeArgument in typeName.GetGenericArguments())
                    {
                        if (!IsFullyQualified(typeArgument))
                            return false;
                    }
                }
 
                return true;
            }
        }
    }
}