Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REFL008 should not warn here. #222

Open
JohanLarsson opened this issue Aug 17, 2019 · 0 comments
Open

REFL008 should not warn here. #222

JohanLarsson opened this issue Aug 17, 2019 · 0 comments
Labels
bug Something isn't working

Comments

@JohanLarsson
Copy link
Collaborator

namespace Gu.Wpf.ValidationScope.UiTests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using NUnit.Framework;

    [Explicit("Script")]
    public class DumpAppDomain
    {
        [Test]
        public void DumpNotExcludedAssemblies()
        {
            var excludedAssemblies = ExcludedAssemblies();
            var notExcluded = AppDomain.CurrentDomain.GetAssemblies()
                                      .Where(a => !excludedAssemblies.Contains(a.GetName().Name))
                                      .Select(a => a.GetName().Name)
                                      .OrderBy(x => x)
                                      .ToList();
            foreach (var assemblyName in notExcluded)
            {
                Console.WriteLine($"\"{assemblyName}\",");
            }
        }

        [Test]
        public void DumpExcludedAssembliesSorted()
        {
            var excludedAssemblies = ExcludedAssemblies()
                .OrderBy(x => x)
                .ToArray();
            foreach (var name in excludedAssemblies)
            {
                Console.WriteLine($"\"{name}\",");
            }
        }

        private static HashSet<string> ExcludedAssemblies()
        {
            // ReSharper disable once PossibleNullReferenceException
            var hashSet = (HashSet<string>)typeof(InputTypeCollectionConverter).GetNestedType("CompatibleTypeCache", BindingFlags.Static | BindingFlags.NonPublic)
                                                                               .GetField("ExcludedAssemblies", BindingFlags.Static | BindingFlags.NonPublic)
                                                                               .GetValue(null);
            return new HashSet<string>(hashSet);
        }
    }
}
namespace Gu.Wpf.ValidationScope
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Security;
    using System.Text;
    using System.Windows.Controls;
    using System.Windows.Markup;

    public class InputTypeCollectionConverter : TypeConverter
    {
        private static readonly char[] SeparatorChars = { ',', ' ' };

        public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType)
        {
            return sourceType == typeof(string) ||
                   sourceType == typeof(Type) ||
                   sourceType == typeof(TypeExtension) ||
                   typeof(IEnumerable<Type>).IsAssignableFrom(sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType)
        {
            return false;
        }

        public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object source)
        {
            var text = source as string;
            if (text != null)
            {
                return ConvertFromText(text);
            }

            var types = source as IEnumerable<Type>;
            if (types != null)
            {
                return new InputTypeCollection(types);
            }

            var type = source as Type;
            if (type != null)
            {
                return new InputTypeCollection { type };
            }

            var typeExtension = source as TypeExtension;
            if (typeExtension != null)
            {
                return new InputTypeCollection { typeExtension.Type };
            }

            return base.ConvertFrom(typeDescriptorContext, cultureInfo, source);
        }

        [SecurityCritical]
        public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType)
        {
            throw new NotSupportedException();
        }

        private static InputTypeCollection ConvertFromText(string text)
        {
            var typeNames = text.Split(SeparatorChars, StringSplitOptions.RemoveEmptyEntries)
                .Select(x => x.Trim())
                .ToArray();
            var inputTypeCollection = new InputTypeCollection();
            foreach (var typeName in typeNames)
            {
                var match = CompatibleTypeCache.FindType(typeName);
                inputTypeCollection.Add(match);
            }

            return inputTypeCollection;
        }

        private static class CompatibleTypeCache
        {
            private static readonly object Gate = new object();
            private static readonly HashSet<Type> Types = new HashSet<Type>();

            private static readonly List<Type> KnownInputTypes = InputTypeCollection.Default.ToList();

            private static readonly HashSet<string> ExcludedAssemblies = new HashSet<string>
                                                                             {
                                                                                 "Castle.Core",
                                                                                 "JetBrains.ReSharper.TaskRunnerFramework",
                                                                                 "JetBrains.ReSharper.UnitTestRunner.nUnit",
                                                                                 "JetBrains.ReSharper.UnitTestRunner.nUnit30",
                                                                                 "Mono.Cecil",
                                                                                 "Microsoft.Windows.Design.Extensibility",
                                                                                 "Microsoft.Windows.Design.Interaction",
                                                                                 "Microsoft.VisualStudio.DesignTools.Designer",
                                                                                 "Microsoft.VisualStudio.DesignTools.Designer.resources",
                                                                                 "Microsoft.VisualStudio.DesignTools.DesignerContract",
                                                                                 "Microsoft.VisualStudio.DesignTools.DesignerHost",
                                                                                 "Microsoft.VisualStudio.DesignTools.DesignerHost.resources",
                                                                                 "Microsoft.VisualStudio.DesignTools.Markup",
                                                                                 "Microsoft.VisualStudio.DesignTools.Platform",
                                                                                 "Microsoft.VisualStudio.DesignTools.Platform.resources",
                                                                                 "Microsoft.VisualStudio.DesignTools.Utility",
                                                                                 "Microsoft.VisualStudio.DesignTools.Utility.resources",
                                                                                 "Microsoft.VisualStudio.DesignTools.WpfDesigner",
                                                                                 "Microsoft.VisualStudio.DesignTools.XamlDesigner",
                                                                                 "Microsoft.VisualStudio.DesignTools.XamlDesigner.resources",
                                                                                 "Microsoft.VisualStudio.RemoteControl",
                                                                                 "Microsoft.VisualStudio.Telemetry",
                                                                                 "Microsoft.VisualStudio.Utilities.Internal",
                                                                                 "mscorlib",
                                                                                 "Newtonsoft.Json",
                                                                                 "nunit.engine",
                                                                                 "nunit.engine.api",
                                                                                 "nunit.framework",
                                                                                 "PresentationFramework.Aero",
                                                                                 "SMDiagnostics",
                                                                                 "System",
                                                                                 "System.ComponentModel.DataAnnotations",
                                                                                 "System.Configuration",
                                                                                 "System.Core",
                                                                                 "System.Data",
                                                                                 "System.Drawing",
                                                                                 "System.Numerics",
                                                                                 "System.Runtime.Remoting",
                                                                                 "System.Runtime.Serialization",
                                                                                 "System.ServiceModel.Internals",
                                                                                 "System.Web",
                                                                                 "System.Xml",
                                                                                 "System.Xml.Linq",
                                                                                 "System.Security",
                                                                                 "System.Windows.Forms",
                                                                                 "TestStack.White",
                                                                                 "UIAutomationClient",
                                                                                 "UIAutomationProvider",
                                                                                 "UIAutomationTypes",
                                                                                 "XDesProc",
                                                                             };

            private static readonly StringBuilder ErrorBuilder = new StringBuilder();

            static CompatibleTypeCache()
            {
                foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                {
                    AddCompatibleTypes(assembly);
                }

                AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => AddCompatibleTypes(args.LoadedAssembly);
            }

            // ReSharper disable once UnusedMember.Local
            internal static string ErrorText => ErrorBuilder.ToString();

            internal static Type FindType(string typeName)
            {
                Type match;
                try
                {
                    lock (Gate)
                    {
                        match = KnownInputTypes.Find(t => IsMatch(t, typeName));
                        if (match != null)
                        {
                            return match;
                        }

                        match = Types.SingleOrDefault(t => IsMatch(t, typeName));
                    }
                }
                catch (Exception)
                {
                    var errorBuilder = new StringBuilder();
                    errorBuilder.AppendLine($"Found more than one match for {typeName}");
                    lock (Gate)
                    {
                        var matches = Types.Where(t => IsMatch(t, typeName));
                        foreach (var type in matches)
                        {
                            errorBuilder.AppendLine($"  - {type.FullName} in assembly: {type.Assembly.FullName}");
                        }
                    }

                    if (!IsFullName(typeName))
                    {
                        errorBuilder.AppendLine($"Try specifying full name: {typeof(TextBox).FullName}");
                    }

                    throw new InvalidOperationException(errorBuilder.ToString());
                }

                if (match == null)
                {
                    throw new InvalidOperationException($"Did not find a match for for {typeName}");
                }

                return match;
            }

            private static bool IsMatch(Type type, string name)
            {
                return type.Name == name || type.FullName == name;
            }

            private static bool IsFullName(string typeName)
            {
                return typeName.Contains('.');
            }

            private static void AddCompatibleTypes(Assembly assembly)
            {
                Debug.WriteLine(assembly.FullName);
                if (ExcludedAssemblies.Contains(assembly.GetName().Name))
                {
                    return;
                }

                try
                {
                    lock (Gate)
                    {
                        foreach (var compatibleType in assembly.GetTypes().Where(InputTypeCollection.IsCompatibleType))
                        {
                            if (Types.Add(compatibleType))
                            {
                                if (KnownInputTypes.Contains(compatibleType))
                                {
                                    continue;
                                }

                                if (KnownInputTypes.Any(t => t.IsAssignableFrom(compatibleType)))
                                {
                                    KnownInputTypes.Add(compatibleType);
                                }
                            }
                            else
                            {
                                Trace.WriteLine($"Type {compatibleType.FullName} was already added");
                            }
                        }
                    }
                }
                catch (ReflectionTypeLoadException ex)
                {
                    // http://stackoverflow.com/a/8824250/1069200
                    foreach (var exSub in ex.LoaderExceptions)
                    {
                        ErrorBuilder.AppendLine(exSub.Message);
                        var exFileNotFound = exSub as FileNotFoundException;
                        if (!string.IsNullOrEmpty(exFileNotFound?.FusionLog))
                        {
                            ErrorBuilder.AppendLine(exFileNotFound.FusionLog);
                        }

                        ErrorBuilder.AppendLine();
                    }
                }
                catch (Exception e)
                {
                    var message = $"Could not process assembly {assembly.FullName}. Exception: {e.Message}";
                    Trace.WriteLine(message);
                    ErrorBuilder.AppendLine(message);
                }
            }
        }
    }
}

image

@JohanLarsson JohanLarsson added the bug Something isn't working label Aug 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant