From f08315c92b492ffd482932bbd4ce79c2c12a501a Mon Sep 17 00:00:00 2001 From: Stefan Ossendorf Date: Sat, 8 Mar 2025 21:52:19 +0100 Subject: [PATCH 1/3] Csla.Analyzers.Extensions nullable aware #1233 --- .../Csla.Analyzers/Csla.Analyzers.csproj | 2 ++ .../Extensions/ITypeSymbolExtensions.cs | 24 +++++++++---------- .../Extensions/SyntaxNodeExtensions.cs | 10 ++++---- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj b/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj index 6d7e36ce3a..d4dc04d472 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj +++ b/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj @@ -9,6 +9,8 @@ ..\..\..\Bin true true + enable + nullable diff --git a/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs b/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs index b664bbc913..47ba2d1cee 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs @@ -7,7 +7,7 @@ internal static class ITypeSymbolExtensions private static readonly Type[] SerializableTypesByMobileFormatter = [typeof(TimeSpan), typeof(DateTimeOffset), typeof(byte[]), typeof(byte[][]), typeof(char[]), typeof(Guid), typeof(List)]; - internal static bool IsBusinessRule(this ITypeSymbol @this) + internal static bool IsBusinessRule(this ITypeSymbol? @this) { return @this != null && (((@this.Name == CslaMemberConstants.Types.IBusinessRule || @this.Name == CslaMemberConstants.Types.IBusinessRuleAsync) && @@ -15,7 +15,7 @@ internal static bool IsBusinessRule(this ITypeSymbol @this) (@this.BaseType.IsBusinessRule() || @this.Interfaces.Any(_ => _.IsBusinessRule()))); } - internal static bool IsObjectFactory(this ITypeSymbol @this) + internal static bool IsObjectFactory(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.ObjectFactory && @@ -23,7 +23,7 @@ internal static bool IsObjectFactory(this ITypeSymbol @this) @this.BaseType.IsObjectFactory()); } - internal static bool IsBusinessBase(this ITypeSymbol @this) + internal static bool IsBusinessBase(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.BusinessBase && @@ -31,7 +31,7 @@ internal static bool IsBusinessBase(this ITypeSymbol @this) @this.BaseType.IsBusinessBase()); } - internal static bool IsInjectable(this ITypeSymbol @this) + internal static bool IsInjectable(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.InjectAttribute && @@ -39,7 +39,7 @@ internal static bool IsInjectable(this ITypeSymbol @this) @this.BaseType.IsInjectable()); } - internal static bool IsDataPortalOperationAttribute(this ITypeSymbol @this) + internal static bool IsDataPortalOperationAttribute(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.DataPortalOperationAttribute && @@ -47,7 +47,7 @@ internal static bool IsDataPortalOperationAttribute(this ITypeSymbol @this) @this.BaseType.IsDataPortalOperationAttribute()); } - internal static bool IsDataPortalRootOperationAttribute(this ITypeSymbol @this) + internal static bool IsDataPortalRootOperationAttribute(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.DataPortalRootOperationAttribute && @@ -55,7 +55,7 @@ internal static bool IsDataPortalRootOperationAttribute(this ITypeSymbol @this) @this.BaseType.IsDataPortalRootOperationAttribute()); } - internal static bool IsDataPortalChildOperationAttribute(this ITypeSymbol @this) + internal static bool IsDataPortalChildOperationAttribute(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.DataPortalChildOperationAttribute && @@ -114,7 +114,7 @@ internal static bool IsSpecialTypeSerializable(this ITypeSymbol @this) specialType == SpecialType.System_DateTime; } - internal static bool IsIPropertyInfo(this ITypeSymbol @this) + internal static bool IsIPropertyInfo(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.IPropertyInfo && @@ -122,7 +122,7 @@ internal static bool IsIPropertyInfo(this ITypeSymbol @this) @this.BaseType.IsIPropertyInfo() || @this.Interfaces.Any(_ => _.IsIPropertyInfo())); } - internal static bool IsEditableStereotype(this ITypeSymbol @this) + internal static bool IsEditableStereotype(this ITypeSymbol? @this) { return @this != null && (((@this.Name == CslaMemberConstants.Types.BusinessBase || @@ -133,7 +133,7 @@ internal static bool IsEditableStereotype(this ITypeSymbol @this) @this.BaseType.IsEditableStereotype()); } - internal static bool IsStereotype(this ITypeSymbol @this) + internal static bool IsStereotype(this ITypeSymbol? @this) { return @this != null && (((@this.Name == CslaMemberConstants.Types.IBusinessObject || @@ -142,7 +142,7 @@ internal static bool IsStereotype(this ITypeSymbol @this) (@this.BaseType.IsStereotype() || @this.Interfaces.Any(_ => _.IsStereotype()))); } - internal static bool IsMobileObject(this ITypeSymbol @this) + internal static bool IsMobileObject(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.IMobileObject && @@ -150,7 +150,7 @@ internal static bool IsMobileObject(this ITypeSymbol @this) (@this.BaseType.IsMobileObject() || @this.Interfaces.Any(_ => _.IsMobileObject()))); } - internal static bool IsObjectAuthorizationRulesAttribute(this ITypeSymbol @this) + internal static bool IsObjectAuthorizationRulesAttribute(this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.ObjectAuthorizationRulesAttribute && diff --git a/Source/Csla.Analyzers/Csla.Analyzers/Extensions/SyntaxNodeExtensions.cs b/Source/Csla.Analyzers/Csla.Analyzers/Extensions/SyntaxNodeExtensions.cs index e1d9372f55..cb64b62820 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/Extensions/SyntaxNodeExtensions.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/Extensions/SyntaxNodeExtensions.cs @@ -6,18 +6,16 @@ namespace Csla.Analyzers.Extensions { internal static class SyntaxNodeExtensions { - internal static bool HasUsing(this SyntaxNode @this, string qualifiedName) + internal static bool HasUsing(this SyntaxNode? @this, string qualifiedName) { if (@this == null) { return false; } - if (@this.IsKind(SyntaxKind.UsingDirective)) + if (@this.IsKind(SyntaxKind.UsingDirective) && @this is UsingDirectiveSyntax usingNode) { - var usingNode = @this as UsingDirectiveSyntax; - - if (usingNode.Name.ToFullString() == qualifiedName) + if (usingNode.Name?.ToFullString() == qualifiedName) { return true; } @@ -26,7 +24,7 @@ internal static bool HasUsing(this SyntaxNode @this, string qualifiedName) return @this.ChildNodes().Any(_ => _.HasUsing(qualifiedName)); } - internal static T FindParent(this SyntaxNode @this) + internal static T? FindParent(this SyntaxNode @this) where T : SyntaxNode { var parentNode = @this.Parent; From 71c814c13e18e615eaa0a7828e6097bdbd7dc7a2 Mon Sep 17 00:00:00 2001 From: Stefan Ossendorf Date: Sat, 8 Mar 2025 21:56:17 +0100 Subject: [PATCH 2/3] Csla.Analyzers.ManagedBackingFieldUsesNameof nullable aware #1233 --- ...EvaluateManagedBackingFieldsNameofAnalyzer.cs | 2 +- .../EvaluateManagedBackingFieldsNameofCodeFix.cs | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofAnalyzer.cs index 78a8c6d94d..2dfbd6a471 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofAnalyzer.cs @@ -51,7 +51,7 @@ private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext contex { context.CancellationToken.ThrowIfCancellationRequested(); - if (context.SemanticModel.GetDeclaredSymbol(variable) is IFieldSymbol fieldSymbol && variable.Initializer.Value is InvocationExpressionSyntax invocation) + if (context.SemanticModel.GetDeclaredSymbol(variable) is IFieldSymbol fieldSymbol && variable.Initializer?.Value is InvocationExpressionSyntax invocation) { if (fieldSymbol.Type.IsIPropertyInfo() && invocation.Expression is GenericNameSyntax invocationName) { diff --git a/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofCodeFix.cs index 880c05d234..d9fb6b99cf 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/ManagedBackingFieldUsesNameof/EvaluateManagedBackingFieldsNameofCodeFix.cs @@ -34,10 +34,19 @@ public sealed class EvaluateManagedBackingFieldsNameofCodeFix public override async Task RegisterCodeFixesAsync(CodeFixContext context) { var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root is null) + { + return; + } var diagnostic = context.Diagnostics.First(); var diagnosticSpan = diagnostic.Location.SourceSpan; - var argumentSyntax = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType().First(); + var parentToken = root.FindToken(diagnosticSpan.Start).Parent; + if (parentToken is null) + { + return; + } + var argumentSyntax = parentToken.AncestorsAndSelf().OfType().First(); context.RegisterCodeFix( CodeAction.Create( @@ -58,6 +67,11 @@ private async Task UseNameofAsync(Document document, ArgumentSyntax ar var nameofExpression = SyntaxFactory.ParseExpression($"nameof({propertyName})"); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + if (root is null) + { + return document; + } + var newRoot = root.ReplaceNode(argumentSyntax.Expression, nameofExpression); return document.WithSyntaxRoot(newRoot); From 4d94583f8e188e02c9febd29072d1c80a637b1b0 Mon Sep 17 00:00:00 2001 From: Stefan Ossendorf Date: Mon, 10 Mar 2025 22:28:14 +0100 Subject: [PATCH 3/3] Csla.Analyzers nullable aware #1233 --- ...sRuleInheritingFromBusinessRuleAnalyzer.cs | 5 ++ ...essRuleChangeToBusinessRuleAsyncCodeFix.cs | 24 +++++++-- ...leDoesNotUseAddMethodsOnContextAnalyzer.cs | 4 ++ .../CheckConstructorsAnalyzer.cs | 6 +-- ...ructorsAnalyzerPublicConstructorCodeFix.cs | 19 +++++-- .../Csla.Analyzers/Csla.Analyzers.csproj | 4 ++ .../DoesChildOperationHaveRunLocalAnalyzer.cs | 5 ++ ...ationHaveRunLocalRemoveAttributeCodeFix.cs | 24 ++++++++- ...erationHaveAttributeAddAttributeCodeFix.cs | 8 +++ .../DoesOperationHaveAttributeAnalyzer.cs | 4 ++ .../EvaluateManagedBackingFieldsAnalyzer.cs | 15 ++---- .../EvaluateManagedBackingFieldsCodeFix.cs | 4 ++ .../EvaluateManagedBackingFieldsWalker.cs | 6 ++- ...EvaluateOperationAttributeUsageAnalyzer.cs | 13 +++-- ...EvaluatePropertiesForSimplicityAnalyzer.cs | 33 ++++++++---- .../Extensions/ITypeSymbolExtensions.cs | 29 +++++----- .../FindGetOrReadInvocationsWalker.cs | 7 ++- ...rectReturnTypeResolveCorrectTypeCodeFix.cs | 25 ++++++--- ...rationsWithIncorrectReturnTypesAnalyzer.cs | 4 ++ ...onsWithNonSerializableArgumentsAnalyzer.cs | 4 ++ ...RefAndOutParametersInOperationsAnalyzer.cs | 7 ++- .../FindSaveAssignmentIssueAnalyzer.cs | 8 ++- ...gnmentIssueAnalyzerAddAssignmentCodeFix.cs | 11 +++- ...tIssueAnalyzerAddAsyncAssignmentCodeFix.cs | 54 +++++++++++-------- .../FindSetOrLoadInvocationsWalker.cs | 7 ++- ...alledInAsynchronousBusinessRuleAnalyzer.cs | 4 ++ ...ynchronousBusinessRuleRemoveCallCodeFix.cs | 29 ++++++++-- .../IsOperationMethodPublicAnalyzer.cs | 6 ++- ...erationMethodPublicMakeNonPublicCodeFix.cs | 8 +++ ...jectAuthorizationRulesAttributeAnalyzer.cs | 4 ++ 30 files changed, 276 insertions(+), 105 deletions(-) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleAnalyzer.cs index 80fd67b3f7..7c3c7d5130 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleAnalyzer.cs @@ -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) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleChangeToBusinessRuleAsyncCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleChangeToBusinessRuleAsyncCodeFix.cs index 44546c45e9..32a1ded619 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleChangeToBusinessRuleAsyncCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/AsynchronousBusinessRuleInheritingFromBusinessRuleChangeToBusinessRuleAsyncCodeFix.cs @@ -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; @@ -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(); - foreach (var baseTypeNode in typeNode.BaseList.DescendantNodes().OfType()) + foreach (var baseTypeNode in typeNode.BaseList!.DescendantNodes().OfType()) { var baseTypeNodeIdentifier = baseTypeNode.DescendantNodes().OfType().Single(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/BusinessRuleDoesNotUseAddMethodsOnContextAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/BusinessRuleDoesNotUseAddMethodsOnContextAnalyzer.cs index 293d6b6820..f6fe823b94 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/BusinessRuleDoesNotUseAddMethodsOnContextAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/BusinessRuleDoesNotUseAddMethodsOnContextAnalyzer.cs @@ -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() && diff --git a/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzer.cs index d4136e1d32..ad8cfa54a1 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzer.cs @@ -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) { @@ -86,7 +86,7 @@ private static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context) if (!hasPublicNoArgumentConstructor) { - var properties = new Dictionary + var properties = new Dictionary { [PublicNoArgumentConstructorIsMissingConstants.HasNonPublicNoArgumentConstructor] = hasNonPublicNoArgumentConstructor.ToString() }.ToImmutableDictionary(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzerPublicConstructorCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzerPublicConstructorCodeFix.cs index 251616f0d5..696ef952f1 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzerPublicConstructorCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/CheckConstructorsAnalyzerPublicConstructorCodeFix.cs @@ -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(); @@ -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); } } diff --git a/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj b/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj index d4dc04d472..9d86e04b87 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj +++ b/Source/Csla.Analyzers/Csla.Analyzers/Csla.Analyzers.csproj @@ -17,6 +17,10 @@ + + all + runtime; build; native; contentfiles; analyzers + diff --git a/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalAnalyzer.cs index 10ec100d86..908542e0a1 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalAnalyzer.cs @@ -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() && diff --git a/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalRemoveAttributeCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalRemoveAttributeCodeFix.cs index e6c50382c0..4ed2ada81a 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalRemoveAttributeCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/DoesChildOperationHaveRunLocalRemoveAttributeCodeFix.cs @@ -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; @@ -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; + } } } @@ -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( diff --git a/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAddAttributeCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAddAttributeCodeFix.cs index 5e3476c8eb..4fcde148f7 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAddAttributeCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAddAttributeCodeFix.cs @@ -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(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAnalyzer.cs index 87792a4e60..09cf9b59fd 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/DoesOperationHaveAttributeAnalyzer.cs @@ -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()) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsAnalyzer.cs index 7466405569..1faa2e7d0c 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsAnalyzer.cs @@ -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)) @@ -93,9 +91,7 @@ private static void CheckForDiagnostics(SyntaxNodeAnalysisContext context, Field } } - private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context, - IFieldSymbol fieldSymbol, IPropertySymbol classProperty, - Func propertyBody) + private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext context, IFieldSymbol fieldSymbol, IPropertySymbol classProperty, Func propertyBody) { var root = context.Node.SyntaxTree.GetRoot(); var rootSpan = root.FullSpan; @@ -117,15 +113,14 @@ 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))); } @@ -133,7 +128,7 @@ private static bool DetermineIfPropertyUsesField(SyntaxNodeAnalysisContext conte { return DetermineIfPropertyUsesField( context, fieldSymbol, classProperty, - propertyNode => propertyNode.AccessorList.Accessors.Single( + propertyNode => propertyNode.AccessorList?.Accessors.Single( _ => _.IsKind(SyntaxKind.SetAccessorDeclaration))); } diff --git a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsCodeFix.cs index 005c8c0ac3..2a4b686fce 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsCodeFix.cs @@ -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(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsWalker.cs b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsWalker.cs index 46ebcb4c5f..5143ca8a1e 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsWalker.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateManagedBackingFieldsWalker.cs @@ -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); @@ -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()) { diff --git a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateOperationAttributeUsageAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateOperationAttributeUsageAnalyzer.cs index 7e60349f30..08ff445fea 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/EvaluateOperationAttributeUsageAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/EvaluateOperationAttributeUsageAnalyzer.cs @@ -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(); + 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())); } } } diff --git a/Source/Csla.Analyzers/Csla.Analyzers/EvaluatePropertiesForSimplicityAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/EvaluatePropertiesForSimplicityAnalyzer.cs index bbf6721a94..523f6faa38 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/EvaluatePropertiesForSimplicityAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/EvaluatePropertiesForSimplicityAnalyzer.cs @@ -44,6 +44,10 @@ private static void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context if(!propertyNode.ContainsDiagnostics) { var propertySymbol = context.SemanticModel.GetDeclaredSymbol(propertyNode); + if (propertySymbol is null) + { + return; + } var classSymbol = propertySymbol.ContainingType; var fields = GetFieldDeclarations(propertyNode,context.SemanticModel); @@ -124,6 +128,10 @@ private static void AnalyzePropertyGetterWithGet(PropertyDeclarationSyntax prope if (getterWalkerBody.Invocation != null) { + if (getterBody is null) + { + return; + } var getterStatements = getterBody.Statements; if (getterStatements.Count != 1) @@ -134,7 +142,7 @@ private static void AnalyzePropertyGetterWithGet(PropertyDeclarationSyntax prope } else { - if (!(getterStatements[0] is ReturnStatementSyntax returnNode)) + if (getterStatements[0] is not ReturnStatementSyntax returnNode) { context.ReportDiagnostic(Diagnostic.Create( onlyUseCslaPropertyMethodsInGetSetRule, @@ -155,7 +163,7 @@ private static void AnalyzePropertyGetterWithGet(PropertyDeclarationSyntax prope } else if (getterWalkerExpression.Invocation != null) { - if (!(getterExpression.Expression is InvocationExpressionSyntax invocation) || invocation != getterWalkerExpression.Invocation) + if (getterExpression is not null && (getterExpression.Expression is not InvocationExpressionSyntax invocation || invocation != getterWalkerExpression.Invocation)) { context.ReportDiagnostic(Diagnostic.Create( onlyUseCslaPropertyMethodsInGetSetRule, @@ -186,6 +194,10 @@ private static void AnalyzePropertySetter(PropertyDeclarationSyntax propertyNode if (setterWalkerBody.Invocation != null) { + if (setterBody is null) + { + return; + } var setterStatements = setterBody.Statements; if (setterStatements.Count != 1) @@ -196,7 +208,7 @@ private static void AnalyzePropertySetter(PropertyDeclarationSyntax propertyNode } else { - if (!(setterStatements[0] is ExpressionStatementSyntax expressionNode)) + if (setterStatements[0] is not ExpressionStatementSyntax expressionNode) { context.ReportDiagnostic(Diagnostic.Create( onlyUseCslaPropertyMethodsInGetSetRule, @@ -217,7 +229,7 @@ private static void AnalyzePropertySetter(PropertyDeclarationSyntax propertyNode } else if (setterWalkerExpression.Invocation != null) { - if (!(setterExpression.Expression is InvocationExpressionSyntax invocation) || invocation != setterWalkerExpression.Invocation) + if (setterExpression is not null && (setterExpression.Expression is not InvocationExpressionSyntax invocation || invocation != setterWalkerExpression.Invocation)) { context.ReportDiagnostic(Diagnostic.Create( onlyUseCslaPropertyMethodsInGetSetRule, @@ -234,7 +246,7 @@ private static void AnalyzePropertySetter(PropertyDeclarationSyntax propertyNode /// /// /// - public static IEnumerable GetFieldDeclarations(PropertyDeclarationSyntax propertyDeclaration,SemanticModel semanticModel) + public static IEnumerable GetFieldDeclarations(PropertyDeclarationSyntax propertyDeclaration, SemanticModel semanticModel) { var classDeclaration = propertyDeclaration.FirstAncestorOrSelf(); var propertyType = semanticModel.GetTypeInfo(propertyDeclaration.Type).Type; @@ -245,15 +257,13 @@ public static IEnumerable GetFieldDeclarations(PropertyD } // Find all field declarations in the class - var fieldDeclarations = classDeclaration.Members - .OfType(); + var fieldDeclarations = classDeclaration.Members.OfType(); // Filter for static fields - return fieldDeclarations - .Where(field => FilterField(field,propertyDeclaration, propertyType,semanticModel)); + return fieldDeclarations.Where(field => FilterField(field,propertyDeclaration, propertyType, semanticModel)); } - private static bool FilterField(FieldDeclarationSyntax fieldDeclaration, PropertyDeclarationSyntax propertyDeclaration, ITypeSymbol propertyType,SemanticModel semanticModel) + private static bool FilterField(FieldDeclarationSyntax fieldDeclaration, PropertyDeclarationSyntax propertyDeclaration, ITypeSymbol? propertyType, SemanticModel semanticModel) { var fieldType = semanticModel.GetTypeInfo(fieldDeclaration.Declaration.Type).Type; if (fieldType != null && fieldType.OriginalDefinition.ToString() == "Csla.PropertyInfo") @@ -262,7 +272,8 @@ private static bool FilterField(FieldDeclarationSyntax fieldDeclaration, Propert if (SymbolEqualityComparer.Default.Equals(typeArgument, propertyType)) { var initializer = fieldDeclaration.Declaration.Variables - .Select(a => a.Initializer.Value) + .Where(a => a.Initializer != null) + .Select(a => a.Initializer!.Value) .OfType().Select(w=>w.ArgumentList.Arguments.FirstOrDefault()?.Expression); var lambda = initializer .OfType() diff --git a/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs b/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs index 47ba2d1cee..72ca87b44e 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/Extensions/ITypeSymbolExtensions.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; namespace Csla.Analyzers.Extensions { @@ -7,7 +8,7 @@ internal static class ITypeSymbolExtensions private static readonly Type[] SerializableTypesByMobileFormatter = [typeof(TimeSpan), typeof(DateTimeOffset), typeof(byte[]), typeof(byte[][]), typeof(char[]), typeof(Guid), typeof(List)]; - internal static bool IsBusinessRule(this ITypeSymbol? @this) + internal static bool IsBusinessRule([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && (((@this.Name == CslaMemberConstants.Types.IBusinessRule || @this.Name == CslaMemberConstants.Types.IBusinessRuleAsync) && @@ -15,7 +16,7 @@ internal static bool IsBusinessRule(this ITypeSymbol? @this) (@this.BaseType.IsBusinessRule() || @this.Interfaces.Any(_ => _.IsBusinessRule()))); } - internal static bool IsObjectFactory(this ITypeSymbol? @this) + internal static bool IsObjectFactory([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.ObjectFactory && @@ -23,7 +24,7 @@ internal static bool IsObjectFactory(this ITypeSymbol? @this) @this.BaseType.IsObjectFactory()); } - internal static bool IsBusinessBase(this ITypeSymbol? @this) + internal static bool IsBusinessBase([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.BusinessBase && @@ -31,7 +32,7 @@ internal static bool IsBusinessBase(this ITypeSymbol? @this) @this.BaseType.IsBusinessBase()); } - internal static bool IsInjectable(this ITypeSymbol? @this) + internal static bool IsInjectable([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.InjectAttribute && @@ -39,7 +40,7 @@ internal static bool IsInjectable(this ITypeSymbol? @this) @this.BaseType.IsInjectable()); } - internal static bool IsDataPortalOperationAttribute(this ITypeSymbol? @this) + internal static bool IsDataPortalOperationAttribute([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.DataPortalOperationAttribute && @@ -47,7 +48,7 @@ internal static bool IsDataPortalOperationAttribute(this ITypeSymbol? @this) @this.BaseType.IsDataPortalOperationAttribute()); } - internal static bool IsDataPortalRootOperationAttribute(this ITypeSymbol? @this) + internal static bool IsDataPortalRootOperationAttribute([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.DataPortalRootOperationAttribute && @@ -55,7 +56,7 @@ internal static bool IsDataPortalRootOperationAttribute(this ITypeSymbol? @this) @this.BaseType.IsDataPortalRootOperationAttribute()); } - internal static bool IsDataPortalChildOperationAttribute(this ITypeSymbol? @this) + internal static bool IsDataPortalChildOperationAttribute([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.DataPortalChildOperationAttribute && @@ -63,7 +64,7 @@ internal static bool IsDataPortalChildOperationAttribute(this ITypeSymbol? @this @this.BaseType.IsDataPortalChildOperationAttribute()); } - internal static bool IsRunLocalAttribute(this ITypeSymbol @this) + internal static bool IsRunLocalAttribute([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && @this.Name == CslaMemberConstants.Types.RunLocalAttribute && @@ -114,7 +115,7 @@ internal static bool IsSpecialTypeSerializable(this ITypeSymbol @this) specialType == SpecialType.System_DateTime; } - internal static bool IsIPropertyInfo(this ITypeSymbol? @this) + internal static bool IsIPropertyInfo([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.IPropertyInfo && @@ -122,7 +123,7 @@ internal static bool IsIPropertyInfo(this ITypeSymbol? @this) @this.BaseType.IsIPropertyInfo() || @this.Interfaces.Any(_ => _.IsIPropertyInfo())); } - internal static bool IsEditableStereotype(this ITypeSymbol? @this) + internal static bool IsEditableStereotype([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && (((@this.Name == CslaMemberConstants.Types.BusinessBase || @@ -133,7 +134,7 @@ internal static bool IsEditableStereotype(this ITypeSymbol? @this) @this.BaseType.IsEditableStereotype()); } - internal static bool IsStereotype(this ITypeSymbol? @this) + internal static bool IsStereotype([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && (((@this.Name == CslaMemberConstants.Types.IBusinessObject || @@ -142,7 +143,7 @@ internal static bool IsStereotype(this ITypeSymbol? @this) (@this.BaseType.IsStereotype() || @this.Interfaces.Any(_ => _.IsStereotype()))); } - internal static bool IsMobileObject(this ITypeSymbol? @this) + internal static bool IsMobileObject([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.IMobileObject && @@ -150,7 +151,7 @@ internal static bool IsMobileObject(this ITypeSymbol? @this) (@this.BaseType.IsMobileObject() || @this.Interfaces.Any(_ => _.IsMobileObject()))); } - internal static bool IsObjectAuthorizationRulesAttribute(this ITypeSymbol? @this) + internal static bool IsObjectAuthorizationRulesAttribute([NotNullWhen(true)] this ITypeSymbol? @this) { return @this != null && ((@this.Name == CslaMemberConstants.Types.ObjectAuthorizationRulesAttribute && diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindGetOrReadInvocationsWalker.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindGetOrReadInvocationsWalker.cs index 6f858be9fe..8ceaace52e 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindGetOrReadInvocationsWalker.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindGetOrReadInvocationsWalker.cs @@ -8,7 +8,7 @@ namespace Csla.Analyzers internal sealed class FindGetOrReadInvocationsWalker : CSharpSyntaxWalker { - internal FindGetOrReadInvocationsWalker(SyntaxNode node, SemanticModel model) + internal FindGetOrReadInvocationsWalker(SyntaxNode? node, SemanticModel model) { Model = model; Visit(node); @@ -17,15 +17,14 @@ internal FindGetOrReadInvocationsWalker(SyntaxNode node, SemanticModel model) public override void VisitInvocationExpression(InvocationExpressionSyntax node) { var symbol = Model.GetSymbolInfo(node); - var methodSymbol = symbol.Symbol as IMethodSymbol; - if (methodSymbol.IsPropertyInfoManagementMethod()) + if (symbol.Symbol is IMethodSymbol methodSymbol && methodSymbol.IsPropertyInfoManagementMethod()) { Invocation = node; } } - internal InvocationExpressionSyntax Invocation { get; private set; } + internal InvocationExpressionSyntax? Invocation { get; private set; } private SemanticModel Model { get; } } } diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeFix.cs index b8f10bd0dc..a70c75ef7b 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeFix.cs @@ -33,31 +33,44 @@ public sealed class FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeF 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; + } if(methodSymbol.IsAsync) { - var newRoot = root.ReplaceNode(methodNode.ReturnType, - SyntaxFactory.IdentifierName(typeof(Task).Name)); + var newRoot = root.ReplaceNode(methodNode.ReturnType, SyntaxFactory.IdentifierName(typeof(Task).Name)); if (!root.HasUsing(FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeFixConstants.SystemThreadingTasksNamespace)) { - newRoot = (newRoot as CompilationUnitSyntax).AddUsings( + if (newRoot is not CompilationUnitSyntax compilationUnitSyntax) + { + return; + } + newRoot = compilationUnitSyntax.AddUsings( SyntaxFactory.UsingDirective(SyntaxFactory.ParseName( FindOperationsWithIncorrectReturnTypeResolveCorrectTypeCodeFixConstants.SystemThreadingTasksNamespace))); } diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypesAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypesAnalyzer.cs index dab758e9d9..46d66aeb70 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypesAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithIncorrectReturnTypesAnalyzer.cs @@ -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() && methodSymbol.IsDataPortalOperation()) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithNonSerializableArgumentsAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithNonSerializableArgumentsAnalyzer.cs index 4c039c7152..28d45c354d 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithNonSerializableArgumentsAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindOperationsWithNonSerializableArgumentsAnalyzer.cs @@ -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() && methodSymbol.IsRootDataPortalOperation()) diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindRefAndOutParametersInOperationsAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindRefAndOutParametersInOperationsAnalyzer.cs index e37f661ac4..0a893720ac 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindRefAndOutParametersInOperationsAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindRefAndOutParametersInOperationsAnalyzer.cs @@ -46,14 +46,17 @@ 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.IsBusinessBase() && methodSymbol.IsDataPortalOperation()) { foreach(var parameterSymbol in methodSymbol.Parameters) { - if(parameterSymbol.RefKind == RefKind.Out || - parameterSymbol.RefKind == RefKind.Ref) + if(parameterSymbol.RefKind == RefKind.Out || parameterSymbol.RefKind == RefKind.Ref) { context.ReportDiagnostic(Diagnostic.Create( incorrectParameterRule, parameterSymbol.Locations[0])); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzer.cs index 448608cf4f..2f89432f34 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzer.cs @@ -61,20 +61,18 @@ private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context) if (invocationSymbol?.Name == Constants.SaveMethodNames.Save) { - CheckForCondition(context, invocationNode, - expressionStatementNode, saveResultIsNotAssignedRule); + CheckForCondition(context, invocationNode, expressionStatementNode, saveResultIsNotAssignedRule); } else if (invocationSymbol?.Name == Constants.SaveMethodNames.SaveAsync) { - CheckForCondition(context, invocationNode, - expressionStatementNode, saveAsyncResultIsNotAssignedRule); + CheckForCondition(context, invocationNode, expressionStatementNode, saveAsyncResultIsNotAssignedRule); } } } } private static void CheckForCondition(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocationNode, - ExpressionStatementSyntax expressionStatementParent, DiagnosticDescriptor descriptor) + ExpressionStatementSyntax? expressionStatementParent, DiagnosticDescriptor descriptor) { // Make sure the invocation's containing type is not the same as the class that contains it if ((invocationNode.DescendantNodesAndTokens().Any(_ => _.IsKind(SyntaxKind.DotToken)) && diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFix.cs index 1c638e3a67..7670c45970 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFix.cs @@ -32,14 +32,21 @@ public sealed class FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFix 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 invocationNode = root.FindNode(diagnostic.Location.SourceSpan) as InvocationExpressionSyntax; - var invocationIdentifier = ((invocationNode.Expression as MemberAccessExpressionSyntax) - .Expression as IdentifierNameSyntax).Identifier; + if (invocationNode?.Expression is not MemberAccessExpressionSyntax memberAccessExpressionSyntax || memberAccessExpressionSyntax.Expression is not IdentifierNameSyntax identifierNameSyntax) + { + return; + } + var invocationIdentifier = identifierNameSyntax.Identifier; var leadingTrivia = invocationIdentifier.HasLeadingTrivia ? invocationIdentifier.LeadingTrivia : new SyntaxTriviaList(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAsyncAssignmentCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAsyncAssignmentCodeFix.cs index 29c71f6cf1..27b7e8168b 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAsyncAssignmentCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindSaveAssignmentIssueAnalyzerAddAsyncAssignmentCodeFix.cs @@ -33,40 +33,50 @@ public sealed class FindSaveAssignmentIssueAnalyzerAddAsyncAssignmentCodeFix 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 invocationNode = root.FindNode(diagnostic.Location.SourceSpan) as InvocationExpressionSyntax; + if (root.FindNode(diagnostic.Location.SourceSpan) is not InvocationExpressionSyntax invocationNode) + { + return; + } - var awaitExpressionNode = invocationNode.FindParent(); + if (invocationNode.Expression is not MemberAccessExpressionSyntax memberAccessExpressionSyntax || memberAccessExpressionSyntax.Expression is not IdentifierNameSyntax identifierNameSyntax) + { + return; + } - if(awaitExpressionNode != null) + var awaitExpressionNode = invocationNode.FindParent(); + if (awaitExpressionNode == null) { - var awaitKeyword = awaitExpressionNode.AwaitKeyword; - var leadingTrivia = awaitKeyword.HasLeadingTrivia ? - awaitKeyword.LeadingTrivia : new SyntaxTriviaList(); + return; + } - var newAwaitExpressionNode = awaitExpressionNode.WithAwaitKeyword( - awaitKeyword.WithLeadingTrivia(new SyntaxTriviaList())); - var invocationIdentifier = ((invocationNode.Expression as MemberAccessExpressionSyntax) - .Expression as IdentifierNameSyntax).Identifier; - var newInvocationIdentifier = invocationIdentifier.WithLeadingTrivia(new SyntaxTriviaList()); + var awaitKeyword = awaitExpressionNode.AwaitKeyword; + var leadingTrivia = awaitKeyword.HasLeadingTrivia ? awaitKeyword.LeadingTrivia : new SyntaxTriviaList(); - context.CancellationToken.ThrowIfCancellationRequested(); + var newAwaitExpressionNode = awaitExpressionNode.WithAwaitKeyword(awaitKeyword.WithLeadingTrivia(new SyntaxTriviaList())); + var invocationIdentifier = identifierNameSyntax.Identifier; + var newInvocationIdentifier = invocationIdentifier.WithLeadingTrivia(new SyntaxTriviaList()); - var simpleAssignmentExpressionNode = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, - SyntaxFactory.IdentifierName(newInvocationIdentifier), newAwaitExpressionNode) - .WithLeadingTrivia(leadingTrivia); + context.CancellationToken.ThrowIfCancellationRequested(); - var newRoot = root.ReplaceNode(awaitExpressionNode, simpleAssignmentExpressionNode); + var simpleAssignmentExpressionNode = SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, + SyntaxFactory.IdentifierName(newInvocationIdentifier), newAwaitExpressionNode) + .WithLeadingTrivia(leadingTrivia); - context.RegisterCodeFix( - CodeAction.Create( - FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFixConstants.AddAssignmentDescription, - _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)), - FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFixConstants.AddAssignmentDescription), diagnostic); - } + var newRoot = root.ReplaceNode(awaitExpressionNode, simpleAssignmentExpressionNode); + + context.RegisterCodeFix( + CodeAction.Create( + FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFixConstants.AddAssignmentDescription, + _ => Task.FromResult(context.Document.WithSyntaxRoot(newRoot)), + FindSaveAssignmentIssueAnalyzerAddAssignmentCodeFixConstants.AddAssignmentDescription), diagnostic); } } } \ No newline at end of file diff --git a/Source/Csla.Analyzers/Csla.Analyzers/FindSetOrLoadInvocationsWalker.cs b/Source/Csla.Analyzers/Csla.Analyzers/FindSetOrLoadInvocationsWalker.cs index 0a29587fa8..81af14e1f6 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/FindSetOrLoadInvocationsWalker.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/FindSetOrLoadInvocationsWalker.cs @@ -8,7 +8,7 @@ namespace Csla.Analyzers internal sealed class FindSetOrLoadInvocationsWalker : CSharpSyntaxWalker { - internal FindSetOrLoadInvocationsWalker(SyntaxNode node, SemanticModel model) + internal FindSetOrLoadInvocationsWalker(SyntaxNode? node, SemanticModel model) { Model = model; Visit(node); @@ -17,15 +17,14 @@ internal FindSetOrLoadInvocationsWalker(SyntaxNode node, SemanticModel model) public override void VisitInvocationExpression(InvocationExpressionSyntax node) { var symbol = Model.GetSymbolInfo(node); - var methodSymbol = symbol.Symbol as IMethodSymbol; - if (methodSymbol.IsPropertyInfoManagementMethod()) + if (symbol.Symbol is IMethodSymbol methodSymbol && methodSymbol.IsPropertyInfoManagementMethod()) { Invocation = node; } } - internal InvocationExpressionSyntax Invocation { get; private set; } + internal InvocationExpressionSyntax? Invocation { get; private set; } private SemanticModel Model { get; } } } diff --git a/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleAnalyzer.cs index 8569f03b93..0b4dae2ece 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleAnalyzer.cs @@ -46,6 +46,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() && methodSymbol.Name == "ExecuteAsync" && diff --git a/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleRemoveCallCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleRemoveCallCodeFix.cs index f88370d3fb..a87b3f3bf5 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleRemoveCallCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/IsCompleteCalledInAsynchronousBusinessRuleRemoveCallCodeFix.cs @@ -35,21 +35,32 @@ public sealed class IsCompleteCalledInAsynchronousBusinessRuleRemoveCallCodeFix 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 contextParameter = methodSymbol.Parameters[0]; var newRoot = root; @@ -60,10 +71,18 @@ private static async Task AddCodeFixAsync(CodeFixContext context, SyntaxNode roo return model.GetSymbolInfo(invocation.Expression).Symbol is IMethodSymbol invocationSymbol && invocationSymbol.Name == "Complete" && SymbolEqualityComparer.Default.Equals(invocationSymbol.ContainingType, contextParameter.Type); }) - .Select(invocation => invocation.FindParent()); + .Select(invocation => invocation.FindParent()) + .Where(i => i is not null) + .Select(s => s!) + ; - newRoot = newRoot.RemoveNodes(completeInvocations, SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepDirectives) - .WithAdditionalAnnotations(Formatter.Annotation); + newRoot = newRoot.RemoveNodes(completeInvocations, SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepDirectives); + if (newRoot is null) + { + return; + } + + newRoot = newRoot.WithAdditionalAnnotations(Formatter.Annotation); context.RegisterCodeFix( CodeAction.Create( diff --git a/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicAnalyzer.cs index 79f9ed13fa..0dc0edb0de 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicAnalyzer.cs @@ -51,6 +51,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() && methodSymbol.IsDataPortalOperation() && @@ -63,7 +67,7 @@ private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) } else { - var properties = new Dictionary + var properties = new Dictionary { [IsOperationMethodPublicAnalyzerConstants.IsSealed] = typeSymbol.IsSealed.ToString() }.ToImmutableDictionary(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicMakeNonPublicCodeFix.cs b/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicMakeNonPublicCodeFix.cs index c349f5efaf..7f79577305 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicMakeNonPublicCodeFix.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/IsOperationMethodPublicMakeNonPublicCodeFix.cs @@ -32,11 +32,19 @@ public sealed class IsOperationMethodPublicMakeNonPublicCodeFix 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(); diff --git a/Source/Csla.Analyzers/Csla.Analyzers/ObjectAuthorizationRulesAttributeAnalyzer.cs b/Source/Csla.Analyzers/Csla.Analyzers/ObjectAuthorizationRulesAttributeAnalyzer.cs index a0fd61dc7e..0e1955f98b 100644 --- a/Source/Csla.Analyzers/Csla.Analyzers/ObjectAuthorizationRulesAttributeAnalyzer.cs +++ b/Source/Csla.Analyzers/Csla.Analyzers/ObjectAuthorizationRulesAttributeAnalyzer.cs @@ -56,6 +56,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())