public void Execute()

in resharper/resharper-unity/src/Unity/Core/Feature/Internal/DumpSpellCheckWordListsAction.cs [36:181]


        public void Execute(IDataContext context, DelegateExecute nextExecute)
        {
            var solution = context.GetData(ProjectModelDataConstants.SOLUTION);
            if (solution == null)
                return;

            var wordsPerAssembly = new OneToSetMap<string, string>(valueComparer: StringComparer.InvariantCultureIgnoreCase);
            var abbreviationsWithOriginalWord = new OneToSetMap<string, string>(valueComparer: StringComparer.InvariantCultureIgnoreCase);

            // TODO: This should be in a background task
            var psiModules = solution.GetComponent<IPsiModules>();
            var symbolCache = solution.GetComponent<ISymbolCache>();
            foreach (var assemblyPsiModule in psiModules.GetAssemblyModules().OrderBy(m => m.DisplayName))
            {
                if (!ShouldProcessAssembly(assemblyPsiModule))
                    continue;

                var symbolScope = symbolCache.GetSymbolScope(assemblyPsiModule, false, true);
                var typeElements = symbolScope.GetAllTypeElementsGroupedByName();
                foreach (var typeElement in typeElements)
                {
                    if (!typeElement.CanBeVisibleToSolution())
                        continue;

                    AddWords(wordsPerAssembly, abbreviationsWithOriginalWord, assemblyPsiModule,
                        typeElement is IInterface ? typeElement.ShortName.RemoveStart("I") : typeElement.ShortName);

                    foreach (var namespaceName in typeElement.GetClrName().NamespaceNames)
                        AddWords(wordsPerAssembly, abbreviationsWithOriginalWord, assemblyPsiModule, namespaceName);

                    // TODO: Should we skip enum values?
                    // It's unlikely that a user would name a method or variable after a value such as AdvertisingNetwork.Aarki,
                    // but on the other hand, if it's used in a comment, it'll show up as a typo.

                    foreach (var typeMember in typeElement.GetMembers())
                    {
                        if (!ShouldProcessTypeMember(typeMember))
                            continue;

                        // Don't use any enum values as abbreviations. Avoids false positives with ALL_UPPER_CASE style
                        AddWords(wordsPerAssembly,
                            typeElement is IEnum ? new OneToSetMap<string, string>() : abbreviationsWithOriginalWord,
                            assemblyPsiModule, typeMember.ShortName);

                        // TODO: Include parameter names?
                        // Respeller will not check parameter names of overriding or implementing functions, so this is
                        // probably unnecessary
                    }
                }
            }

            // Case insensitive. There will not be duplicates
            var allWords = (from pair in wordsPerAssembly
                from word in pair.Value
                select word).ToJetHashSet(StringComparer.InvariantCultureIgnoreCase);

            var spellService = solution.GetComponent<ISpellServiceBackendProvider>().SpellService;
            if (spellService == null) return;

            var wordsCheckResult = spellService.CheckWords(
                Lifetime.Eternal,
                allWords.Concat(abbreviationsWithOriginalWord.Keys).AsList()
            );
            if (wordsCheckResult == null)
            {
                var logger = Logger.GetLogger<DumpSpellCheckWordListsAction>();
                logger.Error("Failed to check words");
                return;
            }
            var unknownWords = (from word in allWords
                where !wordsCheckResult.TryGetValue(word)
                select word).ToJetHashSet(StringComparer.InvariantCultureIgnoreCase);

            // Add abbreviations separately. If added to the dictionary, we don't get typo warnings, but we can get
            // naming standard inspection warnings. E.g. BlahBlahAABB is converted to BlahBlahAabb. Don't add anything
            // that's already known, but the spell checker will only check for words of 4 characters or more.
            // TODO: Ideally, we should disable AbbreviationsSettingsProvider, or we'll ignore our own abbreviations
            // Merge files by hand
            var unknownAbbreviations = (from word in abbreviationsWithOriginalWord.Keys
                where (word.Length > 1 && word.Length < 4) || !wordsCheckResult.TryGetValue(word)
                select word).ToJetHashSet();

            Dumper.DumpToNotepad(w =>
            {
                w.WriteLine("Abbreviations:");
                w.WriteLine();

                foreach (var (abbr, originalWords) in abbreviationsWithOriginalWord.OrderBy(kv => kv.Key))
                {
                    w.Write(abbr);
                    w.Write(": ");
                    foreach (var word in originalWords)
                    {
                        w.Write(word);
                        w.Write(", ");
                    }
                    w.WriteLine();
                }
            });

            // Remove non-abbreviations, known typos or exclusions. Yes, this is all done by hand
            RemoveNonAbbreviations(unknownAbbreviations);
            RemoveTyposAndExclusions(unknownWords);

            // Dump all words for diagnostics
            Dumper.DumpToNotepad(w =>
            {
                w.WriteLine("All words");
                w.WriteLine();

                foreach (var (assembly, words) in wordsPerAssembly)
                {
                    w.WriteLine("Words for assembly: " + assembly);
                    w.WriteLine();

                    foreach (var word in words.OrderBy(IdentityFunc<string>.Instance))
                        w.WriteLine(word.ToLowerInvariant());
                    w.WriteLine();
                }
            });

            // Dump all abbreviations, so we can avoid naming standards inspections when an abbreviation is used.
            // E.g. BlahBlahAABB is accepted instead of converted to BlahBlahAabb
            Dumper.DumpToNotepad(w =>
            {
                w.WriteLine("Abbreviations");
                w.WriteLine();

                foreach (var abbreviation in unknownAbbreviations.OrderBy(IdentityFunc<string>.Instance))
                    w.WriteLine(abbreviation.ToUpperInvariant());
            });

            // Dump all unknown words, minus abbreviations, for use as a dictionary
            Dumper.DumpToNotepad(w =>
            {
                var dictionary = new JetHashSet<string>(unknownWords, StringComparer.InvariantCultureIgnoreCase);
                dictionary.ExceptWith(abbreviationsWithOriginalWord.Keys);

                w.WriteLine("Dictionary (unknown words minus abbreviations)");
                w.WriteLine();
                w.WriteLine(dictionary.Count);    // Hunspell dictionaries start with the number of words

                foreach (var word in dictionary.OrderBy(IdentityFunc<string>.Instance))
                    w.WriteLine(word.ToLowerInvariant());
            });
        }