Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make csla.analyzers nullable aware #4587

Merged
merged 5 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
if (!methodNode.ContainsDiagnostics)
{
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
if (methodSymbol is null)
{
return;
}

var typeSymbol = methodSymbol.ContainingType;

if(typeSymbol.IsBusinessRule() && methodSymbol.Name == "Execute" && methodSymbol.IsAsync)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,31 @@ public sealed class AsynchronousBusinessRuleInheritingFromBusinessRuleChangeToBu
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

if (root is null)
{
return;
}
context.CancellationToken.ThrowIfCancellationRequested();

var diagnostic = context.Diagnostics.First();
var methodNode = root.FindNode(diagnostic.Location.SourceSpan) as MethodDeclarationSyntax;
if (methodNode is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();
await AddCodeFixAsync(context, root, diagnostic, methodNode);
}

private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode root,
Diagnostic diagnostic, MethodDeclarationSyntax methodNode)
private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode root, Diagnostic diagnostic, MethodDeclarationSyntax methodNode)
{
var model = await context.Document.GetSemanticModelAsync(context.CancellationToken);
var methodSymbol = model.GetDeclaredSymbol(methodNode);
if (methodSymbol is null)
{
return;
}
var typeSymbol = methodSymbol.ContainingType;

var newRoot = root;
Expand Down Expand Up @@ -91,13 +101,17 @@ private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode roo
AsynchronousBusinessRuleInheritingFromBusinessRuleChangeToBusinessRuleAsyncCodeFixConstants.UpdateToAsyncEquivalentsDescription), diagnostic);
}

private static BaseListSyntax GetBaseTypes(TypeDeclarationSyntax typeNode)
private static BaseListSyntax? GetBaseTypes(TypeDeclarationSyntax typeNode)
{
var currentBaseList = typeNode.BaseList;
if (currentBaseList is null)
{
return null;
}

var list = new SeparatedSyntaxList<BaseTypeSyntax>();

foreach (var baseTypeNode in typeNode.BaseList.DescendantNodes().OfType<SimpleBaseTypeSyntax>())
foreach (var baseTypeNode in typeNode.BaseList!.DescendantNodes().OfType<SimpleBaseTypeSyntax>())
{
var baseTypeNodeIdentifier = baseTypeNode.DescendantNodes().OfType<IdentifierNameSyntax>().Single();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
if (!methodNode.ContainsDiagnostics)
{
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
if (methodSymbol is null)
{
return;
}
var typeSymbol = methodSymbol.ContainingType;

if (typeSymbol.IsBusinessRule() &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ private static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context)
var classNode = (ClassDeclarationSyntax)context.Node;
var classSymbol = context.SemanticModel.GetDeclaredSymbol(classNode);

if (classSymbol.IsStereotype() && !(classSymbol?.IsAbstract).Value)
if (classSymbol.IsStereotype() && !classSymbol.IsAbstract)
{
foreach (var constructor in classSymbol?.Constructors)
foreach (var constructor in classSymbol.Constructors)
{
if (!constructor.IsStatic)
{
Expand Down Expand Up @@ -86,7 +86,7 @@ private static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context)

if (!hasPublicNoArgumentConstructor)
{
var properties = new Dictionary<string, string>
var properties = new Dictionary<string, string?>
{
[PublicNoArgumentConstructorIsMissingConstants.HasNonPublicNoArgumentConstructor] = hasNonPublicNoArgumentConstructor.ToString()
}.ToImmutableDictionary();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ public sealed class CheckConstructorsAnalyzerPublicConstructorCodeFix
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

if (root is null)
{
return;
}
context.CancellationToken.ThrowIfCancellationRequested();

var diagnostic = context.Diagnostics.First();
var classNode = root.FindNode(diagnostic.Location.SourceSpan) as ClassDeclarationSyntax;
if (classNode is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();

Expand All @@ -51,14 +58,16 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
if (context.Document.SupportsSemanticModel)
{
var model = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
AddCodeFixWithUpdatingNonPublicConstructor(
context, root, diagnostic, classNode, model);
if (model is null)
{
return;
}
AddCodeFixWithUpdatingNonPublicConstructor(context, root, diagnostic, classNode, model);
}
}
else
{
AddCodeFixWithNewPublicConstructor(
context, root, diagnostic, classNode);
AddCodeFixWithNewPublicConstructor(context, root, diagnostic, classNode);
}
}

Expand Down
6 changes: 6 additions & 0 deletions Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
<BaseOutputPath>..\..\..\Bin</BaseOutputPath>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsRoslynComponent>true</IsRoslynComponent>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" PrivateAssets="all" />
<PackageReference Update="NETStandard.Library" PrivateAssets="all" />
<PackageReference Include="Polyfill" Version="7.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
var methodNode = (MethodDeclarationSyntax)context.Node;

var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
if (methodSymbol is null)
{
return;
}

var typeSymbol = methodSymbol.ContainingType;

if (typeSymbol.IsStereotype() && methodSymbol.IsChildDataPortalOperation() &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,25 @@ public sealed class DoesChildOperationHaveRunLocalRemoveAttributeCodeFix
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();

var diagnostic = context.Diagnostics.First();
var methodNode = root.FindNode(diagnostic.Location.SourceSpan) as MethodDeclarationSyntax;
if (methodNode is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();
await AddCodeFixAsync(context, root, diagnostic, methodNode);
}

private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode root,
Diagnostic diagnostic, MethodDeclarationSyntax methodNode)
private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode root, Diagnostic diagnostic, MethodDeclarationSyntax methodNode)
{
var newRoot = root;

Expand All @@ -55,7 +62,16 @@ private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode roo
{
foreach (var attribute in methodSymbol.GetAttributes().Where(_ => _.AttributeClass.IsRunLocalAttribute()))
{
if (attribute.ApplicationSyntaxReference is null)
{
continue;
}

newRoot = newRoot.RemoveNode(await attribute.ApplicationSyntaxReference.GetSyntaxAsync(), SyntaxRemoveOptions.KeepNoTrivia);
if (newRoot is null)
{
return;
}
}
}

Expand All @@ -72,6 +88,10 @@ private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode roo
foreach(var attributeListToRemove in attributeListsToRemove)
{
newRoot = newRoot.RemoveNode(attributeListToRemove, SyntaxRemoveOptions.KeepEndOfLine);
if (newRoot is null)
{
return;
}
}

context.RegisterCodeFix(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,19 @@ public sealed class DoesOperationHaveAttributeAddAttributeCodeFix
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();

var diagnostic = context.Diagnostics.First();
var methodNode = root.FindNode(diagnostic.Location.SourceSpan) as MethodDeclarationSyntax;
if (methodNode is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
var methodNode = (MethodDeclarationSyntax)context.Node;

var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
if (methodSymbol is null)
{
return;
}
var typeSymbol = methodSymbol.ContainingType;

if (typeSymbol.IsStereotype())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
{
foreach (var classMember in classSymbol.GetMembers())
{
if (classMember.Kind == SymbolKind.Property)
if (classMember.Kind == SymbolKind.Property && classMember is IPropertySymbol classProperty)
{
var classProperty = classMember as IPropertySymbol;

if (!classProperty.IsIndexer)
{
if (DetermineIfPropertyUsesField(context, fieldSymbol, classProperty))
Expand Down Expand Up @@ -93,9 +91,7 @@ private static void CheckForDiagnostics(SyntaxNodeAnalysisContext context, Field
}
}

private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context,
IFieldSymbol fieldSymbol, IPropertySymbol classProperty,
Func<PropertyDeclarationSyntax, SyntaxNode> propertyBody)
private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol, IPropertySymbol classProperty, Func<PropertyDeclarationSyntax, SyntaxNode?> propertyBody)
{
var root = context.Node.SyntaxTree.GetRoot();
var rootSpan = root.FullSpan;
Expand All @@ -117,23 +113,22 @@ private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext conte
return false;
}

private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context,
IFieldSymbol fieldSymbol, IPropertySymbol classProperty)
private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol, IPropertySymbol classProperty)
{
if (classProperty.GetMethod != null)
{
return DetermineIfPropertyUsesField(
context, fieldSymbol, classProperty,
propertyNode => propertyNode.ExpressionBody as SyntaxNode ??
propertyNode.AccessorList.Accessors.Single(
propertyNode.AccessorList?.Accessors.Single(
_ => _.IsKind(SyntaxKind.GetAccessorDeclaration)));
}

if (classProperty.SetMethod != null)
{
return DetermineIfPropertyUsesField(
context, fieldSymbol, classProperty,
propertyNode => propertyNode.AccessorList.Accessors.Single(
propertyNode => propertyNode.AccessorList?.Accessors.Single(
_ => _.IsKind(SyntaxKind.SetAccessorDeclaration)));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ public sealed class EvaluateManagedBackingFieldsCodeFix
public override async Task RegisterCodeFixesAsync(CodeFixContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
if (root is null)
{
return;
}

context.CancellationToken.ThrowIfCancellationRequested();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Csla.Analyzers
internal sealed class EvaluateManagedBackingFieldsWalker
: CSharpSyntaxWalker
{
internal EvaluateManagedBackingFieldsWalker(SyntaxNode node, SemanticModel model, IFieldSymbol fieldSymbol)
internal EvaluateManagedBackingFieldsWalker(SyntaxNode? node, SemanticModel model, IFieldSymbol fieldSymbol)
{
(FieldSymbol, Model) = (fieldSymbol, model);
Visit(node);
Expand All @@ -17,6 +17,10 @@ internal EvaluateManagedBackingFieldsWalker(SyntaxNode node, SemanticModel model
public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
var invocationSymbol = Model.GetSymbolInfo(node).Symbol as IMethodSymbol;
if (invocationSymbol is null)
{
return;
}

if (invocationSymbol.IsPropertyInfoManagementMethod())
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,25 @@ public override void Initialize(AnalysisContext context)
private static void AnalyzerAttributeDeclaration(SyntaxNodeAnalysisContext context)
{
var attributeNode = (AttributeSyntax)context.Node;
var attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeNode).Symbol.ContainingSymbol as ITypeSymbol;
var attributeSymbol = context.SemanticModel.GetSymbolInfo(attributeNode).Symbol?.ContainingSymbol as ITypeSymbol;

if (attributeSymbol.IsDataPortalOperationAttribute())
{
var methodNode = attributeNode.FindParent<MethodDeclarationSyntax>();
if (methodNode is null)
{
return;
}
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
if (methodSymbol is null)
{
return;
}
var typeSymbol = methodSymbol.ContainingType;

if (!typeSymbol.IsStereotype() || methodSymbol.IsStatic)
{
context.ReportDiagnostic(Diagnostic.Create(
operationUsageRule, attributeNode.GetLocation()));
context.ReportDiagnostic(Diagnostic.Create(operationUsageRule, attributeNode.GetLocation()));
}
}
}
Expand Down
Loading
Loading