private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; if (UseBitwiseOperationInsteadOfCallingHasFlagAnalysis.IsFixable(invocation, context.SemanticModel, context.CancellationToken) && !invocation.SpanContainsDirectives()) { context.ReportDiagnostic(DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag, invocation); } RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocation); SimplifyLinqMethodChainAnalysis.AnalyzeWhereAndAny(context); if (!invocation.ContainsDiagnostics) { if (!invocation.SpanContainsDirectives()) { CallExtensionMethodAsInstanceMethodAnalysisResult analysis = CallExtensionMethodAsInstanceMethodAnalysis.Analyze(invocation, context.SemanticModel, allowAnyExpression: false, cancellationToken: context.CancellationToken); if (analysis.Success && context.SemanticModel .GetEnclosingNamedType(analysis.InvocationExpression.SpanStart, context.CancellationToken)? .Equals(analysis.MethodSymbol.ContainingType) == false) { context.ReportDiagnostic(DiagnosticDescriptors.CallExtensionMethodAsInstanceMethod, invocation); } } SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation); if (invocationInfo.Success) { if (!invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } string methodName = invocationInfo.NameText; AvoidNullReferenceExceptionAnalyzer.Analyze(context, invocationInfo); CallStringConcatInsteadOfStringJoinAnalysis.Analyze(context, invocationInfo); int argumentCount = invocationInfo.Arguments.Count; switch (argumentCount) { case 0: { switch (methodName) { case "Any": { UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo); SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo); break; } case "Cast": { SimplifyLinqMethodChainAnalysis.AnalyzeWhereAndCast(context, invocationInfo); RemoveRedundantCastAnalyzer.Analyze(context, invocationInfo); break; } case "Count": { UseInsteadOfCountMethodAnalysis.Analyze(context, invocationInfo); SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo); break; } case "First": { if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) && UseElementAccessInsteadOfFirstAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfFirst, invocationInfo.Name); } SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo); break; } case "ToString": { RemoveRedundantToStringCallAnalysis.Analyze(context, invocationInfo); UseNameOfOperatorAnalyzer.Analyze(context, invocationInfo); break; } case "ToLower": case "ToLowerInvariant": case "ToUpper": case "ToUpperInvariant": { UseStringComparisonAnalysis.Analyze(context, invocationInfo); break; } case "FirstOrDefault": case "Last": case "LastOrDefault": case "LongCount": case "Single": case "SingleOrDefault": { SimplifyLinqMethodChainAnalysis.AnalyzeWhere(context, invocationInfo); break; } } break; } case 1: { switch (methodName) { case "All": case "Any": { SimplifyLogicalNegationAnalyzer.Analyze(context, invocationInfo); break; } case "ElementAt": { if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) && UseElementAccessInsteadOfElementAtAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseElementAccessInsteadOfElementAt, invocationInfo.Name); } break; } case "FirstOrDefault": { SimplifyLinqMethodChainAnalysis.AnalyzeFirstOrDefault(context, invocationInfo); CallFindInsteadOfFirstOrDefaultAnalysis.Analyze(context, invocationInfo); break; } case "Where": { CombineEnumerableWhereMethodChainAnalysis.Analyze(context, invocationInfo); break; } } break; } } switch (methodName) { case "Append": case "AppendLine": case "AppendFormat": case "Insert": { OptimizeStringBuilderAppendCallAnalysis.Analyze(context, invocationInfo); break; } case "Select": { if (argumentCount == 1 || argumentCount == 2) { CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo); } break; } case "OrderBy": case "OrderByDescending": { if (argumentCount == 1 || argumentCount == 2 || argumentCount == 3) { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); } break; } } if (UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression); } } } }
private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; if (invocation.ContainsDiagnostics) { return; } SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation); if (!invocationInfo.Success) { return; } string methodName = invocationInfo.NameText; int argumentCount = invocationInfo.Arguments.Count; switch (argumentCount) { case 0: { switch (methodName) { case "Any": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCountOrLengthPropertyInsteadOfAnyMethod)) { UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo); } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeAny(context, invocationInfo); } break; } case "Cast": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndCast(context, invocationInfo); } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantCast)) { RemoveRedundantCastAnalyzer.Analyze(context, invocationInfo); } break; } case "Count": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) && !OptimizeLinqMethodCallAnalysis.AnalyzeSelectManyAndCount(context, invocationInfo)) { OptimizeLinqMethodCallAnalysis.AnalyzeCount(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); } break; } case "First": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { if (CanUseElementAccess(context, invocationInfo) && UseElementAccessAnalysis.IsFixableFirst(invocationInfo, context.SemanticModel, context.CancellationToken)) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseElementAccess, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End))); } OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeFirst(context, invocationInfo); } break; } case "Max": case "Min": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeSelectAndMinOrMax(context, invocationInfo); } break; } case "Reverse": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeOrderByAndReverse(context, invocationInfo); } break; } case "ToString": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantToStringCall)) { RemoveRedundantToStringCallAnalysis.Analyze(context, invocationInfo); } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseNameOfOperator) && ((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp6) { UseNameOfOperatorAnalyzer.Analyze(context, invocationInfo); } break; } case "ToLower": case "ToLowerInvariant": case "ToUpper": case "ToUpperInvariant": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseStringComparison)) { UseStringComparisonAnalysis.Analyze(context, invocationInfo); } break; } case "FirstOrDefault": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo); } break; } case "Last": case "LastOrDefault": case "LongCount": case "Single": case "SingleOrDefault": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); } break; } case "OfType": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) && !invocation.SpanContainsDirectives()) { OptimizeLinqMethodCallAnalysis.AnalyzeOfType(context, invocationInfo); } break; } case "ToCharArray": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.RemoveRedundantStringToCharArrayCall)) { RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocationInfo); } break; } } break; } case 1: { switch (methodName) { case "All": case "Any": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.SimplifyLogicalNegation)) { SimplifyLogicalNegationAnalyzer.Analyze(context, invocationInfo); } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) && !invocation.SpanContainsDirectives()) { OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndAny(context, invocationInfo); } break; } case "ContainsKey": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall)) { OptimizeMethodCallAnalysis.OptimizeDictionaryContainsKey(context, invocationInfo); } break; } case "ElementAt": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall) && CanUseElementAccess(context, invocationInfo) && UseElementAccessAnalysis.IsFixableElementAt(invocationInfo, context.SemanticModel, context.CancellationToken)) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseElementAccess, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End))); } break; } case "FirstOrDefault": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo); } break; } case "GetValueOrDefault": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression) && invocationInfo.Name.IsKind(SyntaxKind.IdentifierName) && !invocation.IsParentKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression) && context.SemanticModel .GetMethodSymbol(invocationInfo.InvocationExpression, context.CancellationToken)? .ContainingType .OriginalDefinition .SpecialType == SpecialType.System_Nullable_T) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, invocationInfo.Name); } break; } case "Where": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CombineEnumerableWhereMethodChain)) { CombineEnumerableWhereMethodChainAnalysis.Analyze(context, invocationInfo); } break; } case "HasFlag": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.ConvertHasFlagCallToBitwiseOperationOrViceVersa) && context.IsAnalyzerSuppressed(AnalyzerOptions.ConvertBitwiseOperationToHasFlagCall) && !invocation.SpanContainsDirectives() && ConvertHasFlagCallToBitwiseOperationAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { DiagnosticHelpers.ReportDiagnostic( context, DiagnosticDescriptors.ConvertHasFlagCallToBitwiseOperationOrViceVersa, invocation); } break; } case "Select": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo); } break; } case "OrderBy": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy)) { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); } break; } } break; } case 2: { switch (invocationInfo.NameText) { case "IsMatch": case "Match": case "Matches": case "Split": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) && !invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } break; } case "Select": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeLinqMethodCall)) { CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo); } break; } case "OrderBy": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy)) { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); } break; } } break; } case 3: { switch (invocationInfo.NameText) { case "IsMatch": case "Match": case "Matches": case "Split": case "Replace": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) && !invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } break; } case "OrderBy": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.CallThenByInsteadOfOrderBy)) { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); } break; } case "Compare": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall)) { OptimizeMethodCallAnalysis.OptimizeStringCompare(context, invocationInfo); } break; } } break; } case 4: { switch (invocationInfo.NameText) { case "Replace": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseRegexInstanceInsteadOfStaticMethod) && !invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } break; } } break; } } switch (methodName) { case "ElementAtOrDefault": case "FirstOrDefault": case "LastOrDefault": case "SingleOrDefault": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AvoidNullReferenceException)) { if (argumentCount == 0 || argumentCount == 1 || argumentCount == 2) { AvoidNullReferenceExceptionAnalyzer.Analyze(context, invocationInfo); } } break; } case "Append": case "AppendLine": case "AppendFormat": case "Insert": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeStringBuilderAppendCall)) { OptimizeStringBuilderAppendCallAnalysis.Analyze(context, invocationInfo); } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.AvoidBoxingOfValueType)) { AvoidBoxingOfValueTypeAnalysis.Analyze(context, invocationInfo); } break; } case "Assert": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall) && (argumentCount >= 1 && argumentCount <= 3)) { OptimizeMethodCallAnalysis.OptimizeDebugAssert(context, invocationInfo); } break; } case "Join": { if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.OptimizeMethodCall) && argumentCount >= 2) { OptimizeMethodCallAnalysis.OptimizeStringJoin(context, invocationInfo); } break; } } if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseMethodChaining) && UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression); } }
private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; if (invocation.ContainsDiagnostics) { return; } SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocation); if (!invocationInfo.Success) { return; } string methodName = invocationInfo.NameText; int argumentCount = invocationInfo.Arguments.Count; switch (argumentCount) { case 0: { switch (methodName) { case "Any": { UseCountOrLengthPropertyInsteadOfAnyMethodAnalysis.Analyze(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); break; } case "Cast": { OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndCast(context, invocationInfo); RemoveRedundantCastAnalyzer.Analyze(context, invocationInfo); break; } case "Count": { OptimizeLinqMethodCallAnalysis.AnalyzeCount(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); break; } case "First": { if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) && UseElementAccessAnalysis.IsFixableFirst(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.OptimizeLinqMethodCall, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End))); } OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeFirst(context, invocationInfo); break; } case "ToString": { RemoveRedundantToStringCallAnalysis.Analyze(context, invocationInfo); UseNameOfOperatorAnalyzer.Analyze(context, invocationInfo); break; } case "ToLower": case "ToLowerInvariant": case "ToUpper": case "ToUpperInvariant": { UseStringComparisonAnalysis.Analyze(context, invocationInfo); break; } case "FirstOrDefault": { OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo); break; } case "Last": case "LastOrDefault": case "LongCount": case "Single": case "SingleOrDefault": { OptimizeLinqMethodCallAnalysis.AnalyzeWhere(context, invocationInfo); break; } case "OfType": { if (!invocation.SpanContainsDirectives()) { OptimizeLinqMethodCallAnalysis.AnalyzeOfType(context, invocationInfo); } break; } case "ToCharArray": { RemoveRedundantStringToCharArrayCallAnalysis.Analyze(context, invocationInfo); break; } } break; } case 1: { switch (methodName) { case "All": case "Any": { SimplifyLogicalNegationAnalyzer.Analyze(context, invocationInfo); if (!invocation.SpanContainsDirectives()) { OptimizeLinqMethodCallAnalysis.AnalyzeWhereAndAny(context, invocationInfo); } break; } case "ElementAt": { if (!invocationInfo.Expression.IsKind(SyntaxKind.InvocationExpression) && UseElementAccessAnalysis.IsFixableElementAt(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.OptimizeLinqMethodCall, Location.Create(invocation.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationInfo.ArgumentList.Span.End))); } break; } case "FirstOrDefault": { OptimizeLinqMethodCallAnalysis.AnalyzeFirstOrDefault(context, invocationInfo); break; } case "Where": { CombineEnumerableWhereMethodChainAnalysis.Analyze(context, invocationInfo); break; } case "HasFlag": { if (!invocation.SpanContainsDirectives() && UseBitwiseOperationInsteadOfCallingHasFlagAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseBitwiseOperationInsteadOfCallingHasFlag, invocation); } break; } case "Select": { CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo); break; } case "OrderBy": { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); break; } } break; } case 2: { switch (invocationInfo.NameText) { case "IsMatch": case "Match": case "Matches": case "Split": { if (!invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } break; } case "Select": { CallCastInsteadOfSelectAnalysis.Analyze(context, invocationInfo); break; } case "OrderBy": { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); break; } } break; } case 3: { switch (invocationInfo.NameText) { case "IsMatch": case "Match": case "Matches": case "Split": case "Replace": { if (!invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } break; } case "OrderBy": { CallThenByInsteadOfOrderByAnalysis.Analyze(context, invocationInfo); break; } } break; } case 4: { switch (invocationInfo.NameText) { case "Replace": { if (!invocation.SpanContainsDirectives()) { UseRegexInstanceInsteadOfStaticMethodAnalysis.Analyze(context, invocationInfo); } break; } } break; } } switch (methodName) { case "ElementAtOrDefault": case "FirstOrDefault": case "LastOrDefault": { if (argumentCount == 0 || argumentCount == 1 || argumentCount == 2) { AvoidNullReferenceExceptionAnalyzer.Analyze(context, invocationInfo); } break; } case "Append": case "AppendLine": case "AppendFormat": case "Insert": { OptimizeStringBuilderAppendCallAnalysis.Analyze(context, invocationInfo); break; } case "Join": { if (argumentCount >= 2) { CallStringConcatInsteadOfStringJoinAnalysis.Analyze(context, invocationInfo); } break; } } if (UseMethodChainingAnalysis.IsFixable(invocationInfo, context.SemanticModel, context.CancellationToken)) { context.ReportDiagnostic(DiagnosticDescriptors.UseMethodChaining, invocationInfo.InvocationExpression); } }