CSLA.NET 6.0.0
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
FindSaveAssignmentIssueAnalyzer.cs
Go to the documentation of this file.
2using Microsoft.CodeAnalysis;
3using Microsoft.CodeAnalysis.CSharp;
4using Microsoft.CodeAnalysis.CSharp.Syntax;
5using Microsoft.CodeAnalysis.Diagnostics;
6using System.Collections.Immutable;
7using System.Linq;
9
10namespace Csla.Analyzers
11{
12 [DiagnosticAnalyzer(LanguageNames.CSharp)]
14 : DiagnosticAnalyzer
15 {
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(
21 Constants.AnalyzerIdentifiers.FindSaveAssignmentIssue, nameof(FindSaveAssignmentIssueAnalyzer)));
22
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(
28 Constants.AnalyzerIdentifiers.FindSaveAsyncAssignmentIssue, nameof(FindSaveAssignmentIssueAnalyzer)));
29
30 public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
31 ImmutableArray.Create(saveResultIsNotAssignedRule, saveAsyncResultIsNotAssignedRule);
32
33 public override void Initialize(AnalysisContext context)
34 {
35 context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
36 context.EnableConcurrentExecution();
37 context.RegisterSyntaxNodeAction(AnalyzeInvocation, SyntaxKind.InvocationExpression);
38 }
39
40 private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
41 {
42 // http://stackoverflow.com/questions/29614112/how-to-get-invoked-method-name-in-roslyn
43 var invocationNode = (InvocationExpressionSyntax)context.Node;
44
45 if (!invocationNode.ContainsDiagnostics)
46 {
47 var symbol = context.SemanticModel.GetSymbolInfo(invocationNode.Expression);
48 var invocationSymbol = symbol.Symbol;
49
50 if (invocationSymbol?.ContainingType?.IsBusinessBase() ?? false)
51 {
52 context.CancellationToken.ThrowIfCancellationRequested();
53 var expressionStatementNode = invocationNode.FindParent<ExpressionStatementSyntax>();
54
55 if (invocationSymbol?.Name == Constants.SaveMethodNames.Save)
56 {
57 CheckForCondition(context, invocationNode,
58 expressionStatementNode, saveResultIsNotAssignedRule);
59 }
60 else if (invocationSymbol?.Name == Constants.SaveMethodNames.SaveAsync)
61 {
62 CheckForCondition(context, invocationNode,
63 expressionStatementNode, saveAsyncResultIsNotAssignedRule);
64 }
65 }
66 }
67 }
68
69 private static void CheckForCondition(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocationNode,
70 ExpressionStatementSyntax expressionStatementParent, DiagnosticDescriptor descriptor)
71 {
72 // Make sure the invocation's containing type is not the same as the class that contains it
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))
78 {
79 context.ReportDiagnostic(Diagnostic.Create(descriptor, invocationNode.GetLocation()));
80 }
81 }
82
83 private static bool IsReturnValue(InvocationExpressionSyntax invocationNode)
84 {
85 var parentNode = invocationNode?.Parent;
86 var foundReturn = false;
87
88 while (parentNode != null && !(parentNode is BlockSyntax))
89 {
90 foundReturn = parentNode is ReturnStatementSyntax ||
91 parentNode is ParenthesizedLambdaExpressionSyntax;
92
93 if (foundReturn)
94 {
95 break;
96 }
97
98 parentNode = parentNode.Parent;
99 }
100
101 return foundReturn;
102 }
103 }
104}
override ImmutableArray< DiagnosticDescriptor > SupportedDiagnostics