示例#1
0
        /// <summary>
        /// Returns True if the text has incorrect spelling.
        /// </summary>
        /// <param name="element">
        /// The element containing the text we're checking.
        /// </param>
        /// <param name="text">
        /// The text to check.
        /// </param>
        /// <param name="spellingError">
        /// Returns a comma separated list of words encountered as spelling errors.
        /// </param>
        /// <returns>
        /// True if the text contains an incorrect spelling.
        /// </returns>
        private static bool TextContainsIncorectSpelling(CsElement element, string text, out string spellingError)
        {
            NamingService namingService = NamingService.GetNamingService(element.Document.SourceCode.Project.Culture);

            spellingError = string.Empty;

            if (namingService.SupportsSpelling)
            {
                WordParser parser = new WordParser(text, WordParserOptions.SplitCompoundWords);
                if (parser.PeekWord() != null)
                {
                    ICollection <string> recognizedWords = element.Document.SourceCode.Project.RecognizedWords;

                    string word = parser.NextWord();
                    do
                    {
                        // Ignore words starting and ending with '$'.
                        // Ignore if in our recognized words list or correct spelling
                        if ((word.StartsWith("$") && word.EndsWith("$")) || (recognizedWords.Contains(word) || IsSpelledCorrectly(namingService, word)))
                        {
                            continue;
                        }

                        if (!string.IsNullOrEmpty(spellingError))
                        {
                            spellingError += ", ";
                        }

                        spellingError += word;
                    }while ((word = parser.NextWord()) != null);
                }
            }

            return(!string.IsNullOrEmpty(spellingError));
        }
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

            context.RegisterSymbolAction(context =>
            {
                var eventName = context.Symbol.Name;

                if (!eventName.StartsWith(BeforeKeyword, StringComparison.Ordinal) &&
                    !eventName.StartsWith(AfterKeyword, StringComparison.Ordinal))
                {
                    return;
                }

                var wordParse = new WordParser(eventName, WordParserOptions.SplitCompoundWords);

                if (wordParse.NextWord() is string firstWord &&
                    s_invalidPrefixes.Contains(firstWord) &&
                    wordParse.NextWord() is string) // Do not report if this is the only word
                {
                    context.ReportDiagnostic(context.Symbol.CreateDiagnostic(Rule));
                }
            }, SymbolKind.Event);
        }
示例#3
0
        /// <summary>
        /// Returns True if the text has incorrect spelling.
        /// </summary>
        /// <param name="element">
        /// The element containing the text we're checking.
        /// </param>
        /// <param name="text">
        /// The text to check.
        /// </param>
        /// <param name="spellingError">
        /// Returns a comma separated list of words encountered as spelling errors.
        /// </param>
        /// <returns>
        /// True if the text contains an incorrect spelling.
        /// </returns>
        private static bool TextContainsIncorectSpelling(CsElement element, string text, out string spellingError)
        {
            NamingService namingService = NamingService.GetNamingService(element.Document.SourceCode.Project.Culture);

            spellingError = string.Empty;

            if (namingService.SupportsSpelling)
            {
                ICollection <string> recognizedWords = element.Document.SourceCode.Project.RecognizedWords;

                WordParser parser = new WordParser(text, WordParserOptions.SplitCompoundWords, recognizedWords);
                if (parser.PeekWord() != null)
                {
                    string word = parser.NextWord();
                    do
                    {
                        // Ignore words starting and ending with '$'.
                        // Ignore if in our recognized words list or correct spelling
                        string hint = null;
                        if ((word.StartsWith("$") && word.EndsWith("$")) || (recognizedWords.Contains(word) || IsSpelledCorrectly(namingService, word, out hint)))
                        {
                            continue;
                        }

                        // If we already have a spelling error for this element, add a comma to separate them.
                        if (!string.IsNullOrEmpty(spellingError))
                        {
                            spellingError += ", ";
                        }

                        spellingError += "'" + word + "'";

                        // Append a hint message to this spelling error if we have one.
                        if (hint != null && hint.Trim().Length > 0)
                        {
                            spellingError += " " + hint;
                        }
                    }while ((word = parser.NextWord()) != null);
                }
            }

            return(!string.IsNullOrEmpty(spellingError));
        }
        private static bool HasEventLikeName(IMethodSymbol method)
        {
            WordParser parser = new WordParser(method.Name, WordParserOptions.SplitCompoundWords);

            string word = parser.NextWord();

            // Check for 'FireXXX', 'RaiseXXX'
            if (string.Equals(word, "fire", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(word, "raise", StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            // Check for 'AddOnXXX', 'RemoveOnXXX'
            if (string.Equals(word, "add", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(word, "remove", StringComparison.OrdinalIgnoreCase))
            {
                return(string.Equals(parser.NextWord(), "on", StringComparison.OrdinalIgnoreCase));
            }

            return(false);
        }
        private static bool HasCorrectPrefix(ISymbol symbol, char prefix)
        {
            WordParser parser = new WordParser(symbol.Name, WordParserOptions.SplitCompoundWords, prefix);

            string firstWord = parser.NextWord();

            if (firstWord == null || firstWord.Length > 1)
            {
                return(false);
            }

            return(firstWord[0] == prefix);
        }
        public static bool SymbolNameContainsUriWords(this ISymbol symbol, CancellationToken cancellationToken)
        {
            if (symbol.Name == null || !symbol.SymbolNameContainsUriWordSubstring(cancellationToken))
            {
                // quick check failed
                return false;
            }

            string word;
            var parser = new WordParser(symbol.Name, WordParserOptions.SplitCompoundWords);
            while ((word = parser.NextWord()) != null)
            {
                if (s_uriWords.Contains(word))
                {
                    return true;
                }
            }

            return false;
        }
        public static bool SymbolNameContainsUriWords(this ISymbol symbol, CancellationToken cancellationToken)
        {
            if (symbol.Name == null || !symbol.SymbolNameContainsUriWordSubstring(cancellationToken))
            {
                // quick check failed
                return(false);
            }

            string word;
            var    parser = new WordParser(symbol.Name, WordParserOptions.SplitCompoundWords);

            while ((word = parser.NextWord()) != null)
            {
                if (s_uriWords.Contains(word))
                {
                    return(true);
                }
            }

            return(false);
        }
示例#8
0
            private IEnumerable <IParameterSymbol> GetStringParametersThatContainsUriWords(IEnumerable <IParameterSymbol> stringParameters, CancellationToken cancellationToken)
            {
                foreach (IParameterSymbol parameter in stringParameters)
                {
                    if (parameter.Name == null || !CheckStringParameterContainsUriWords(parameter, cancellationToken))
                    {
                        // quick check failed
                        continue;
                    }

                    string word;
                    var    parser = new WordParser(parameter.Name, WordParserOptions.SplitCompoundWords);
                    while ((word = parser.NextWord()) != null)
                    {
                        if (s_uriWords.Contains(word))
                        {
                            yield return(parameter);

                            break;
                        }
                    }
                }
            }
示例#9
0
        private static void OnCompilationStart(CompilationStartAnalysisContext compilationStartContext)
        {
            var dictionaries      = ReadDictionaries();
            var projectDictionary = CodeAnalysisDictionary.CreateFromDictionaries(dictionaries.Concat(s_mainDictionary));

            compilationStartContext.RegisterOperationAction(AnalyzeVariable, OperationKind.VariableDeclarator);
            compilationStartContext.RegisterCompilationEndAction(AnalyzeAssembly);
            compilationStartContext.RegisterSymbolAction(
                AnalyzeSymbol,
                SymbolKind.Namespace,
                SymbolKind.NamedType,
                SymbolKind.Method,
                SymbolKind.Property,
                SymbolKind.Event,
                SymbolKind.Field,
                SymbolKind.Parameter);

            IEnumerable <CodeAnalysisDictionary> ReadDictionaries()
            {
                var fileProvider = AdditionalFileProvider.FromOptions(compilationStartContext.Options);

                return(fileProvider.GetMatchingFiles(@"(?:dictionary|custom).*?\.(?:xml|dic)$")
                       .Select(CreateDictionaryFromAdditionalText)
                       .Where(x => x != null)
                       .ToList());

                CodeAnalysisDictionary CreateDictionaryFromAdditionalText(AdditionalText additionalFile)
                {
                    var text     = additionalFile.GetText(compilationStartContext.CancellationToken);
                    var isXml    = additionalFile.Path.EndsWith(".xml", StringComparison.OrdinalIgnoreCase);
                    var provider = isXml ? s_xmlDictionaryProvider : s_dicDictionaryProvider;

                    if (!compilationStartContext.TryGetValue(text, provider, out var dictionary))
                    {
                        try
                        {
                            // Annoyingly (and expectedly), TryGetValue swallows the parsing exception,
                            // so we have to parse again to get it.
                            var unused = isXml ? ParseXmlDictionary(text) : ParseDicDictionary(text);
                            ReportFileParseDiagnostic(additionalFile.Path, "Unknown error");
                        }
#pragma warning disable CA1031 // Do not catch general exception types
                        catch (Exception ex)
#pragma warning restore CA1031 // Do not catch general exception types
                        {
                            ReportFileParseDiagnostic(additionalFile.Path, ex.Message);
                        }
                    }

                    return(dictionary);
                }

                void ReportFileParseDiagnostic(string filePath, string message)
                {
                    var diagnostic = Diagnostic.Create(FileParseRule, Location.None, filePath, message);

                    compilationStartContext.RegisterCompilationEndAction(x => x.ReportDiagnostic(diagnostic));
                }
            }

            void AnalyzeVariable(OperationAnalysisContext operationContext)
            {
                var variableOperation = (IVariableDeclaratorOperation)operationContext.Operation;
                var variable          = variableOperation.Symbol;

                ReportDiagnosticsForSymbol(variable, variable.Name, operationContext.ReportDiagnostic, checkForUnmeaningful: false);
            }

            void AnalyzeAssembly(CompilationAnalysisContext context)
            {
                var assembly = context.Compilation.Assembly;

                ReportDiagnosticsForSymbol(assembly, assembly.Name, context.ReportDiagnostic);
            }

            void AnalyzeSymbol(SymbolAnalysisContext symbolContext)
            {
                var typeParameterDiagnostics = Enumerable.Empty <Diagnostic>();

                ISymbol symbol = symbolContext.Symbol;

                if (symbol.IsOverride)
                {
                    return;
                }

                var symbolName = symbol.Name;

                switch (symbol)
                {
                case IFieldSymbol:
                    symbolName = RemovePrefixIfPresent('_', symbolName);
                    break;

                case IMethodSymbol method:
                    switch (method.MethodKind)
                    {
                    case MethodKind.PropertyGet:
                    case MethodKind.PropertySet:
                        return;

                    case MethodKind.Constructor:
                    case MethodKind.StaticConstructor:
                        symbolName = symbol.ContainingType.Name;
                        break;
                    }

                    foreach (var typeParameter in method.TypeParameters)
                    {
                        ReportDiagnosticsForSymbol(typeParameter, RemovePrefixIfPresent('T', typeParameter.Name), symbolContext.ReportDiagnostic);
                    }

                    break;

                case INamedTypeSymbol type:
                    if (type.TypeKind == TypeKind.Interface)
                    {
                        symbolName = RemovePrefixIfPresent('I', symbolName);
                    }

                    foreach (var typeParameter in type.TypeParameters)
                    {
                        ReportDiagnosticsForSymbol(typeParameter, RemovePrefixIfPresent('T', typeParameter.Name), symbolContext.ReportDiagnostic);
                    }

                    break;
                }

                ReportDiagnosticsForSymbol(symbol, symbolName, symbolContext.ReportDiagnostic);
            }

            void ReportDiagnosticsForSymbol(ISymbol symbol, string symbolName, Action <Diagnostic> reportDiagnostic, bool checkForUnmeaningful = true)
            {
                foreach (var misspelledWord in GetMisspelledWords(symbolName))
                {
                    reportDiagnostic(GetMisspelledWordDiagnostic(symbol, misspelledWord));
                }

                if (checkForUnmeaningful && symbolName.Length == 1)
                {
                    reportDiagnostic(GetUnmeaningfulIdentifierDiagnostic(symbol, symbolName));
                }
            }

            IEnumerable <string> GetMisspelledWords(string symbolName)
            {
                var parser = new WordParser(symbolName, WordParserOptions.SplitCompoundWords);

                string?word;

                while ((word = parser.NextWord()) != null)
                {
                    if (!IsWordAcronym(word) && !IsWordNumeric(word) && !IsWordSpelledCorrectly(word))
                    {
                        yield return(word);
                    }
                }
            }
        private void OnCompilationStart(CompilationStartAnalysisContext compilationStartContext)
        {
            if (IsRunningInProduction && InDebugMode)
            {
                System.Diagnostics.Debugger.Launch();
            }

            var projectDictionary = _mainDictionary.Clone();
            var dictionaries      = ReadDictionaries();

            if (dictionaries.Any())
            {
                var aggregatedDictionary = dictionaries.Aggregate((x, y) => x.CombineWith(y));
                projectDictionary = projectDictionary.CombineWith(aggregatedDictionary);
            }

            compilationStartContext.RegisterOperationAction(AnalyzeVariable, OperationKind.VariableDeclarator);
            compilationStartContext.RegisterCompilationEndAction(AnalyzeAssembly);
            compilationStartContext.RegisterSymbolAction(
                AnalyzeSymbol,
                SymbolKind.Namespace,
                SymbolKind.NamedType,
                SymbolKind.Method,
                SymbolKind.Property,
                SymbolKind.Event,
                SymbolKind.Field,
                SymbolKind.Parameter);

            IEnumerable <CodeAnalysisDictionary> ReadDictionaries()
            {
                var fileProvider = AdditionalFileProvider.FromOptions(compilationStartContext.Options);

                return(fileProvider.GetMatchingFiles(@"(?:dictionary|custom).*?\.(?:xml|dic)$")
                       .Select(CreateDictionaryFromAdditionalText)
                       .Where(x => x != null));

                CodeAnalysisDictionary CreateDictionaryFromAdditionalText(AdditionalText additionalFile)
                {
                    var text     = additionalFile.GetText(compilationStartContext.CancellationToken);
                    var isXml    = additionalFile.Path.EndsWith("xml", StringComparison.OrdinalIgnoreCase);
                    var provider = isXml ? _xmlDictionaryProvider : _dicDictionaryProvider;

                    if (!compilationStartContext.TryGetValue(text, provider, out var dictionary))
                    {
                        try
                        {
                            // Annoyingly (and expectedly), TryGetValue swallows the parsing exception,
                            // so we have to parse again to get it.
                            var unused = isXml ? ParseXmlDictionary(text) : ParseDicDictionary(text);
                            ReportFileParseDiagnostic(additionalFile.Path, "Unknown error");
                        }
                        catch (Exception ex)
                        {
                            ReportFileParseDiagnostic(additionalFile.Path, ex.Message);
                        }
                    }

                    return(dictionary);
                }

                void ReportFileParseDiagnostic(string filePath, string message)
                {
                    var diagnostic = Diagnostic.Create(FileParseRule, Location.None, filePath, message);

                    compilationStartContext.RegisterCompilationEndAction(x => x.ReportDiagnostic(diagnostic));
                }
            }

            void AnalyzeVariable(OperationAnalysisContext operationContext)
            {
                var variableOperation = (IVariableDeclaratorOperation)operationContext.Operation;
                var variable          = variableOperation.Symbol;

                var diagnostics = GetDiagnosticsForSymbol(variable, variable.Name, checkForUnmeaningful: false);

                foreach (var diagnostic in diagnostics)
                {
                    operationContext.ReportDiagnostic(diagnostic);
                }
            }

            void AnalyzeAssembly(CompilationAnalysisContext context)
            {
                var assembly    = context.Compilation.Assembly;
                var diagnostics = GetDiagnosticsForSymbol(assembly, assembly.Name);

                foreach (var diagnostic in diagnostics)
                {
                    context.ReportDiagnostic(diagnostic);
                }
            }

            void AnalyzeSymbol(SymbolAnalysisContext symbolContext)
            {
                var typeParameterDiagnostics = Enumerable.Empty <Diagnostic>();

                ISymbol symbol = symbolContext.Symbol;

                if (symbol.IsOverride)
                {
                    return;
                }

                var symbolName = symbol.Name;

                switch (symbol)
                {
                case IFieldSymbol field:
                    symbolName = RemovePrefixIfPresent("_", symbolName);
                    break;

                case IMethodSymbol method:
                    switch (method.MethodKind)
                    {
                    case MethodKind.PropertyGet:
                    case MethodKind.PropertySet:
                        return;

                    case MethodKind.Constructor:
                    case MethodKind.StaticConstructor:
                        symbolName = symbol.ContainingType.Name;
                        break;
                    }

                    foreach (var typeParameter in method.TypeParameters)
                    {
                        typeParameterDiagnostics = GetDiagnosticsForSymbol(typeParameter, RemovePrefixIfPresent("T", typeParameter.Name));
                    }

                    break;

                case INamedTypeSymbol type:
                    if (type.TypeKind == TypeKind.Interface)
                    {
                        symbolName = RemovePrefixIfPresent("I", symbolName);
                    }

                    foreach (var typeParameter in type.TypeParameters)
                    {
                        typeParameterDiagnostics = GetDiagnosticsForSymbol(typeParameter, RemovePrefixIfPresent("T", typeParameter.Name));
                    }

                    break;
                }

                var diagnostics    = GetDiagnosticsForSymbol(symbol, symbolName);
                var allDiagnostics = typeParameterDiagnostics.Concat(diagnostics);

                foreach (var diagnostic in allDiagnostics)
                {
                    symbolContext.ReportDiagnostic(diagnostic);
                }
            }

            IEnumerable <Diagnostic> GetDiagnosticsForSymbol(ISymbol symbol, string symbolName, bool checkForUnmeaningful = true)
            {
                var diagnostics = new List <Diagnostic>();

                if (checkForUnmeaningful && symbolName.Length == 1)
                {
                    // diagnostics.AddRange(GetUnmeaningfulIdentifierDiagnostics(symbol, symbolName));
                }
                else
                {
                    foreach (var misspelledWord in GetMisspelledWords(symbolName))
                    {
                        diagnostics.AddRange(GetMisspelledWordDiagnostics(symbol, misspelledWord));
                    }
                }

                return(diagnostics);
            }

            IEnumerable <string> GetMisspelledWords(string symbolName)
            {
                var parser = new WordParser(symbolName, WordParserOptions.SplitCompoundWords);

                if (parser.PeekWord() != null)
                {
                    var word = parser.NextWord();

                    do
                    {
                        if (IsWordAcronym(word) || IsWordNumeric(word) || IsWordSpelledCorrectly(word))
                        {
                            continue;
                        }

                        yield return(word);
                    }while ((word = parser.NextWord()) != null);
                }
            }

            bool IsWordAcronym(string word) => word.All(char.IsUpper);

            bool IsWordNumeric(string word) => char.IsDigit(word[0]);

            bool IsWordSpelledCorrectly(string word)
            => !projectDictionary.UnrecognizedWords.Contains(word) && projectDictionary.RecognizedWords.Contains(word);
        }