File: Panels\TelemetryPanel.xaml.cs
Web Access
Project: src\src\VisualStudio\VisualStudioDiagnosticsToolWindow\Roslyn.VisualStudio.DiagnosticsWindow.csproj (Roslyn.VisualStudio.DiagnosticsWindow)
// 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.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Shared.Extensions;
 
namespace Roslyn.VisualStudio.DiagnosticsWindow
{
    /// <summary>
    /// Interaction logic for TelemetryPanel.xaml
    /// </summary>
    public partial class TelemetryPanel : UserControl
    {
        public TelemetryPanel()
        {
            InitializeComponent();
        }
 
        private void OnDump(object sender, RoutedEventArgs e)
        {
            _ = OnDumpImplAsync();
 
            async Task OnDumpImplAsync()
            {
                using (Disable(DumpButton))
                using (Disable(CopyButton))
                {
                    GenerationProgresBar.IsIndeterminate = true;
 
                    var text = await Task.Run(GetTelemetryString).ConfigureAwait(true);
 
                    this.Result.Text = text;
 
                    GenerationProgresBar.IsIndeterminate = false;
                }
            }
        }
 
        private void OnCopy(object sender, RoutedEventArgs e)
        {
            Clipboard.SetText(this.Result.Text);
        }
 
        private static string GetTelemetryString()
        {
            var fixAllScopeValues = Enum.GetValues(typeof(FixAllScope));
 
            var sb = new StringBuilder();
            var seenType = new HashSet<Type>();
 
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                var result = ScanAssembly(assembly);
                if (result.Length > 0)
                {
                    sb.AppendLine($"Searching: {assembly.FullName}");
                    sb.AppendLine(result);
                }
            }
 
            return sb.ToString();
 
            string ScanAssembly(Assembly assembly)
            {
                var typeDiscovered = new StringBuilder();
                try
                {
                    foreach (var module in assembly.GetModules())
                    {
                        foreach (var type in module.GetTypes())
                        {
                            ScanType(type, typeDiscovered);
                        }
                    }
                }
                catch
                {
                    // ignore
                }
 
                return typeDiscovered.ToString();
            }
 
            void ScanType(Type type, StringBuilder typeDiscovered)
            {
                type = type.GetTypeForTelemetry();
 
                if (!seenType.Add(type))
                {
                    return;
                }
 
                RecordIfCodeAction(type, typeDiscovered);
 
                foreach (var nestedTypeInfo in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
                {
                    ScanType(nestedTypeInfo, typeDiscovered);
                }
            }
 
            void RecordIfCodeAction(Type type, StringBuilder typeDiscovered)
            {
                if (!IsCodeAction(type))
                {
                    return;
                }
 
                var telemetryId = type.GetTelemetryId();
 
                typeDiscovered.AppendLine($"Found: {type.FullName}: {telemetryId.ToString()}");
            }
 
            bool IsCodeAction(Type type)
            {
                if (type == null)
                {
                    return false;
                }
 
                var codeActionType = typeof(CodeAction);
                return codeActionType.IsAssignableFrom(type);
            }
        }
 
        private static IDisposable Disable(UIElement control)
        {
            control.IsEnabled = false;
            return new RAII(() => control.IsEnabled = true);
        }
 
        private sealed class RAII : IDisposable
        {
            private readonly Action _action;
 
            public RAII(Action disposeAction)
            {
                _action = disposeAction;
            }
            public void Dispose()
            {
                _action?.Invoke();
            }
        }
    }
}