File: TLens.Analyzers\InterfacesAnalyzer.cs
Web Access
Project: src\src\runtime\src\tools\illink\src\tlens\tlens.csproj (tlens)
// 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.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace TLens.Analyzers
{
    abstract class InterfacesAnalyzer : Analyzer
    {
        protected readonly Dictionary<TypeDefinition, List<TypeDefinition>> interfaces = new Dictionary<TypeDefinition, List<TypeDefinition>>();
        protected readonly Dictionary<TypeDefinition, HashSet<MethodDefinition>> usage = new Dictionary<TypeDefinition, HashSet<MethodDefinition>>();

        protected override void ProcessType(TypeDefinition type)
        {
            if (!type.HasInterfaces)
                return;

            foreach (var iface in type.Interfaces)
            {
                TypeDefinition id = iface.InterfaceType.Resolve();
                if (id == null)
                    continue;

                if (!interfaces.TryGetValue(id, out var types))
                {
                    types = new List<TypeDefinition>();
                    interfaces.Add(id, types);
                }

                types.Add(type);
            }
        }

        protected override void ProcessMethod(MethodDefinition method)
        {
            var instrs = method.Body.Instructions;
            TypeDefinition td;

            foreach (var instr in instrs)
            {
                switch (instr.OpCode.OperandType)
                {
                    case OperandType.InlineType:
                    case OperandType.InlineTok:
                        var tr = instr.Operand as TypeReference;
                        td = tr?.Resolve();
                        break;

                    case OperandType.InlineMethod:
                        if (instr.Operand is not MethodReference mr)
                            continue;

                        td = mr.Resolve()?.DeclaringType;
                        break;
                    default:
                        continue;
                }

                if (td == null || !td.IsInterface)
                    continue;

                if (!usage.ContainsKey(td))
                    usage.Add(td, new HashSet<MethodDefinition>());

                usage[td].Add(method);
            }
        }

        protected int GetImplementationCount(TypeDefinition iface)
        {
            return interfaces.TryGetValue(iface, out var types) ? types.Count : 0;
        }
    }
}