<commit_before>﻿// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion.Providers;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Completion
{
    /// <summary>
    /// A subtype of <see cref="CompletionService"/> that aggregates completions from one or more <see cref="CompletionProvider"/>s.
    /// </summary>
    public abstract class CompletionServiceWithProviders : CompletionService, IEqualityComparer<ImmutableHashSet<string>>
    {
        private static readonly Func<string, List<CompletionItem>> s_createList = _ => new List<CompletionItem>();

        private readonly object _gate = new object();

        private readonly Dictionary<string, CompletionProvider> _nameToProvider = new Dictionary<string, CompletionProvider>();
        private readonly Dictionary<ImmutableHashSet<string>, ImmutableArray<CompletionProvider>> _rolesToProviders;
        private readonly Func<ImmutableHashSet<string>, ImmutableArray<CompletionProvider>> _createRoleProviders;
        private readonly Func<string, CompletionProvider> _getProviderByName;

        private readonly Workspace _workspace;

        private IEnumerable<Lazy<CompletionProvider, CompletionProviderMetadata>> _importedProviders;

        protected CompletionServiceWithProviders(Workspace workspace)
        {
            _workspace = workspace;
            _rolesToProviders = new Dictionary<ImmutableHashSet<string>, ImmutableArray<CompletionProvider>>(this);
            _createRoleProviders = CreateRoleProviders;
            _getProviderByName = GetProviderByName;
        }

        public override CompletionRules GetRules()
        {
            return CompletionRules.Default;
        }

        /// <summary>
        /// Returns the providers always available to the service.
        /// This does not included providers imported via MEF composition.
        /// </summary>
        [Obsolete("This method is no longer used.", error: true)]
        protected virtual ImmutableArray<CompletionProvider> GetBuiltInProviders()
        {
            return ImmutableArray<CompletionProvider>.Empty;
        }

        private IEnumerable<Lazy<CompletionProvider, CompletionProviderMetadata>> GetImportedProviders()
        {
            if (_importedProviders == null)
            {
                var language = Language;
                var mefExporter = (IMefHostExportProvider)_workspace.Services.HostServices;

                var providers = ExtensionOrderer.Order(
                        mefExporter.GetExports<CompletionProvider, CompletionProviderMetadata>()
                        .Where(lz => lz.Metadata.Language == language)
                        ).ToList();

                Interlocked.CompareExchange(ref _importedProviders, providers, null);
            }

            return _importedProviders;
        }

        private ImmutableArray<CompletionProvider> CreateRoleProviders(ImmutableHashSet<string> roles)
        {
            var providers = GetAllProviders(roles);

            foreach (var provider in providers)
            {
                _nameToProvider[provider.Name] = provider;
            }

            return providers;
        }

        private ImmutableArray<CompletionProvider> GetAllProviders(ImmutableHashSet<string> roles)
        {
            var imported = GetImportedProviders()
                .Where(lz => lz.Metadata.Roles == null || lz.Metadata.Roles.Length == 0 || roles.Overlaps(lz.Metadata.Roles))
                .Select(lz => lz.Value);

            return imported.ToImmutableArray();
        }

        protected ImmutableArray<CompletionProvider> GetProviders(ImmutableHashSet<string> roles)
        {
            roles ??= ImmutableHashSet<string>.Empty;

            lock (_gate)
            {
                return _rolesToProviders.GetOrAdd(roles, _createRoleProviders);
            }
        }

        private ImmutableArray<CompletionProvider> GetFilteredProviders(
            ImmutableHashSet<string> roles, CompletionTrigger trigger, OptionSet options)
        {
            return FilterProviders(GetProviders(roles, trigger), trigger, options);
        }
<commit_msg>Add back support for non MEF imported completion providers<commit_after>﻿// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Completion.Providers;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Completion
{
    /// <summary>
    /// A subtype of <see cref="CompletionService"/> that aggregates completions from one or more <see cref="CompletionProvider"/>s.
    /// </summary>
    public abstract class CompletionServiceWithProviders : CompletionService, IEqualityComparer<ImmutableHashSet<string>>
    {
        private static readonly Func<string, List<CompletionItem>> s_createList = _ => new List<CompletionItem>();

        private readonly object _gate = new object();

        private readonly Dictionary<string, CompletionProvider> _nameToProvider = new Dictionary<string, CompletionProvider>();
        private readonly Dictionary<ImmutableHashSet<string>, ImmutableArray<CompletionProvider>> _rolesToProviders;
        private readonly Func<ImmutableHashSet<string>, ImmutableArray<CompletionProvider>> _createRoleProviders;
        private readonly Func<string, CompletionProvider> _getProviderByName;

        private readonly Workspace _workspace;

        private IEnumerable<Lazy<CompletionProvider, CompletionProviderMetadata>> _importedProviders;

        protected CompletionServiceWithProviders(Workspace workspace)
        {
            _workspace = workspace;
            _rolesToProviders = new Dictionary<ImmutableHashSet<string>, ImmutableArray<CompletionProvider>>(this);
            _createRoleProviders = CreateRoleProviders;
            _getProviderByName = GetProviderByName;
        }

        public override CompletionRules GetRules()
        {
            return CompletionRules.Default;
        }

        /// <summary>
        /// Returns the providers always available to the service.
        /// This does not included providers imported via MEF composition.
        /// </summary>
        [Obsolete("Built-in providers will be ignored in a future release, please make them MEF exports instead.")]
        protected virtual ImmutableArray<CompletionProvider> GetBuiltInProviders()
        {
            return ImmutableArray<CompletionProvider>.Empty;
        }

        private IEnumerable<Lazy<CompletionProvider, CompletionProviderMetadata>> GetImportedProviders()
        {
            if (_importedProviders == null)
            {
                var language = Language;
                var mefExporter = (IMefHostExportProvider)_workspace.Services.HostServices;

                var providers = ExtensionOrderer.Order(
                        mefExporter.GetExports<CompletionProvider, CompletionProviderMetadata>()
                        .Where(lz => lz.Metadata.Language == language)
                        ).ToList();

                Interlocked.CompareExchange(ref _importedProviders, providers, null);
            }

            return _importedProviders;
        }

        private ImmutableArray<CompletionProvider> CreateRoleProviders(ImmutableHashSet<string> roles)
        {
            var providers = GetAllProviders(roles);

            foreach (var provider in providers)
            {
                _nameToProvider[provider.Name] = provider;
            }

            return providers;
        }

        private ImmutableArray<CompletionProvider> GetAllProviders(ImmutableHashSet<string> roles)
        {
            var imported = GetImportedProviders()
                .Where(lz => lz.Metadata.Roles == null || lz.Metadata.Roles.Length == 0 || roles.Overlaps(lz.Metadata.Roles))
                .Select(lz => lz.Value);

#pragma warning disable 0618
            // We need to keep supporting built-in providers for a while longer since this is a public API.
            var builtin = GetBuiltInProviders();
#pragma warning restore 0618

            return imported.Concat(builtin).ToImmutableArray();
        }

        protected ImmutableArray<CompletionProvider> GetProviders(ImmutableHashSet<string> roles)
        {
            roles ??= ImmutableHashSet<string>.Empty;

            lock (_gate)
            {
                return _rolesToProviders.GetOrAdd(roles, _createRoleProviders);
            }
        }

        private ImmutableArray<CompletionProvider> GetFilteredProviders(
            ImmutableHashSet<string> roles, CompletionTrigger trigger, OptionSet options)
        {
            return FilterProviders(GetProviders(roles, trigger), trigger, options);
        }

{'fraction_non_alphanumeric': 0.07776290040168915, 'fraction_numerical': 0.0010299721907508497, 'mean_word_length': 2.8183248132127408, 'pattern_counts': {'":': 0, '<': 81, '<?xml version=': 0, '>': 89, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '376964', 'n_tokens_mistral': 2349, 'n_tokens_neox': 2297, 'n_words': 581}