6using System.Collections.Immutable;
12 [DiagnosticAnalyzer(LanguageNames.CSharp)]
16 private static readonly DiagnosticDescriptor saveResultIsNotAssignedRule =
new DiagnosticDescriptor(
17 Constants.AnalyzerIdentifiers.FindSaveAssignmentIssue, FindSaveAssignmentIssueAnalyzerConstants.Title,
18 FindSaveAssignmentIssueAnalyzerConstants.Message, Constants.Categories.Usage,
19 DiagnosticSeverity.Error,
true,
20 helpLinkUri: HelpUrlBuilder.Build(
23 private static readonly DiagnosticDescriptor saveAsyncResultIsNotAssignedRule =
new DiagnosticDescriptor(
24 Constants.AnalyzerIdentifiers.FindSaveAsyncAssignmentIssue, FindSaveAsyncAssignmentIssueAnalyzerConstants.Title,
25 FindSaveAsyncAssignmentIssueAnalyzerConstants.Message, Constants.Categories.Usage,
26 DiagnosticSeverity.Error,
true,
27 helpLinkUri: HelpUrlBuilder.Build(
31 ImmutableArray.Create(saveResultIsNotAssignedRule, saveAsyncResultIsNotAssignedRule);
35 context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
36 context.EnableConcurrentExecution();
37 context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression);
40 private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
43 var invocationNode = (InvocationExpressionSyntax)context.Node;
45 if (!invocationNode.ContainsDiagnostics)
47 var symbol = context.SemanticModel.GetSymbolInfo(invocationNode.Expression);
48 var invocationSymbol = symbol.Symbol;
50 if (invocationSymbol?.ContainingType?.IsBusinessBase() ??
false)
52 context.CancellationToken.ThrowIfCancellationRequested();
53 var expressionStatementNode = invocationNode.FindParent<ExpressionStatementSyntax>();
55 if (invocationSymbol?.Name == Constants.SaveMethodNames.Save)
57 CheckForCondition(context, invocationNode,
58 expressionStatementNode, saveResultIsNotAssignedRule);
60 else if (invocationSymbol?.Name == Constants.SaveMethodNames.SaveAsync)
62 CheckForCondition(context, invocationNode,
63 expressionStatementNode, saveAsyncResultIsNotAssignedRule);
69 private static void CheckForCondition(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocationNode,
70 ExpressionStatementSyntax expressionStatementParent, DiagnosticDescriptor descriptor)
73 if ((invocationNode.DescendantNodesAndTokens().Any(_ => _.IsKind(SyntaxKind.DotToken)) &&
74 !invocationNode.DescendantNodesAndTokens().Any(_ => _.IsKind(SyntaxKind.ThisExpression) || _.IsKind(SyntaxKind.BaseExpression))) &&
75 (!expressionStatementParent?.DescendantNodesAndTokens()?.Any(_ => _.IsKind(SyntaxKind.EqualsToken)) ??
false) &&
76 !(invocationNode.DescendantNodes()?.Any(_ =>
new ContainsInvocationExpressionWalker(_).HasIssue) ??
false) &&
77 !IsReturnValue(invocationNode))
79 context.ReportDiagnostic(Diagnostic.Create(descriptor, invocationNode.GetLocation()));
83 private static bool IsReturnValue(InvocationExpressionSyntax invocationNode)
85 var parentNode = invocationNode?.Parent;
86 var foundReturn =
false;
88 while (parentNode !=
null && !(parentNode is BlockSyntax))
90 foundReturn = parentNode is ReturnStatementSyntax ||
91 parentNode is ParenthesizedLambdaExpressionSyntax;
98 parentNode = parentNode.Parent;
override void Initialize(AnalysisContext context)
override ImmutableArray< DiagnosticDescriptor > SupportedDiagnostics