From 6289bb085a67b4ebe39d885d235571d88273aae9 Mon Sep 17 00:00:00 2001 From: Benjamin Michaelis Date: Tue, 24 Feb 2026 01:09:59 -0800 Subject: [PATCH] Enables Nullable Reference Types Enables Nullable Reference Types throughout the project. Adds null checks and throws exceptions where syntax root or semantic model retrieval fails, improving code safety and preventing potential null reference exceptions. --- Directory.Build.props | 1 + .../AsyncVoid.cs | 13 +++++++++++-- .../AttributesOnSeparateLines.cs | 18 +++++++++++++----- .../NamingFieldPascalUnderscore.cs | 18 +++++++++++++++--- .../NamingIdentifierPascal.cs | 18 +++++++++++++++--- .../AnalyzerTests.cs | 4 +++- .../Helpers/CodeFixVerifier.Helper.cs | 10 +++++++--- .../Helpers/DiagnosticVerifier.Helper.cs | 9 ++++++--- .../Verifiers/CodeFixVerifier.cs | 12 +++++++----- .../Verifiers/DiagnosticVerifier.cs | 9 +++++---- .../AnalyzerBlockMixins.cs | 8 ++++---- .../Analyzers/AsyncVoid.cs | 5 ++++- .../Analyzers/AttributesOnSeparateLines.cs | 8 ++++++-- ...plicitDateTimeToDateTimeOffsetConversion.cs | 2 +- .../Analyzers/UnusedLocalVariable.cs | 6 +++++- 15 files changed, 103 insertions(+), 38 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index f8045abc..3328ec27 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,5 +2,6 @@ true 14.0 + enable \ No newline at end of file diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AsyncVoid.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AsyncVoid.cs index 8bc67541..c30547d3 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AsyncVoid.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AsyncVoid.cs @@ -26,13 +26,21 @@ public sealed override FixAllProvider GetFixAllProvider() public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root is null) + { + return; + } Diagnostic diagnostic = context.Diagnostics.First(); Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; // Find the type declaration identified by the diagnostic. var declaration = root.FindToken(diagnosticSpan.Start).Parent as MethodDeclarationSyntax; + if (declaration is null) + { + return; + } // Register a code action that will invoke the fix. context.RegisterCodeFix( @@ -45,7 +53,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) private static async Task MakeReturnTask(Document document, MethodDeclarationSyntax declaration, CancellationToken cancellationToken) { - SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) + ?? throw new System.InvalidOperationException("Could not get syntax root"); SyntaxNode newRoot = root.ReplaceNode(declaration.ReturnType, SyntaxFactory.ParseTypeName(typeof(Task).Name).WithTrailingTrivia(SyntaxFactory.Space)); return document.WithSyntaxRoot(newRoot); } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AttributesOnSeparateLines.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AttributesOnSeparateLines.cs index bbdd2971..ec3548a9 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AttributesOnSeparateLines.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AttributesOnSeparateLines.cs @@ -29,7 +29,11 @@ public sealed override FixAllProvider GetFixAllProvider() public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root is null) + { + return; + } Diagnostic diagnostic = context.Diagnostics.First(); Microsoft.CodeAnalysis.Text.TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; @@ -38,14 +42,17 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) SyntaxToken declaration = root.FindToken(diagnosticSpan.Start); // Find the enclosing AttributeList - SyntaxNode attributeList = declaration.Parent; - while (!attributeList.IsKind(SyntaxKind.AttributeList)) + SyntaxNode? attributeList = declaration.Parent; + while (attributeList is not null && !attributeList.IsKind(SyntaxKind.AttributeList)) { attributeList = attributeList.Parent; } // Get the class, method or property adjacent to the AttributeList - SyntaxNode parentDeclaration = attributeList.Parent; + if (attributeList?.Parent is not SyntaxNode parentDeclaration) + { + return; + } // Register a code action that will invoke the fix. context.RegisterCodeFix( @@ -78,7 +85,8 @@ private static async Task PutOnSeparateLine(Document document, SyntaxN .WithAdditionalAnnotations(Formatter.Annotation); // Replace the old local declaration with the new local declaration. - SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); + SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) + ?? throw new InvalidOperationException("Could not get syntax root"); SyntaxNode newRoot = oldRoot.ReplaceNode(parentDeclaration, newNode); return document.WithSyntaxRoot(newRoot); diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingFieldPascalUnderscore.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingFieldPascalUnderscore.cs index db34911b..691bad77 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingFieldPascalUnderscore.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingFieldPascalUnderscore.cs @@ -27,7 +27,11 @@ public sealed override FixAllProvider GetFixAllProvider() public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root is null) + { + return; + } Diagnostic diagnostic = context.Diagnostics.First(); TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; @@ -50,8 +54,16 @@ private static async Task MakePascalWithUnderscore(Document document, string nameWithoutUnderscore = nameOfField.TrimStart('_'); string newName = "_" + char.ToUpper(nameWithoutUnderscore.First()) + nameWithoutUnderscore.Substring(1); - SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - ISymbol symbol = semanticModel.GetDeclaredSymbol(declaration.Parent, cancellationToken); + SemanticModel? semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (semanticModel is null || declaration.Parent is null) + { + return document.Project.Solution; + } + ISymbol? symbol = semanticModel.GetDeclaredSymbol(declaration.Parent, cancellationToken); + if (symbol is null) + { + return document.Project.Solution; + } Solution solution = document.Project.Solution; SymbolRenameOptions options = new() { diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingIdentifierPascal.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingIdentifierPascal.cs index d1b317fa..85026a4b 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingIdentifierPascal.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/NamingIdentifierPascal.cs @@ -27,7 +27,11 @@ public sealed override FixAllProvider GetFixAllProvider() public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { - SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + SyntaxNode? root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + if (root is null) + { + return; + } Diagnostic diagnostic = context.Diagnostics.First(); TextSpan diagnosticSpan = diagnostic.Location.SourceSpan; @@ -49,8 +53,16 @@ private static async Task MakePascal(Document document, SyntaxToken de string nameOfField = declaration.ValueText; string newName = char.ToUpper(nameOfField.First()) + nameOfField.Substring(1); - SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); - ISymbol symbol = semanticModel.GetDeclaredSymbol(declaration.Parent, cancellationToken); + SemanticModel? semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); + if (semanticModel is null || declaration.Parent is null) + { + return document.Project.Solution; + } + ISymbol? symbol = semanticModel.GetDeclaredSymbol(declaration.Parent, cancellationToken); + if (symbol is null) + { + return document.Project.Solution; + } Solution solution = document.Project.Solution; SymbolRenameOptions options = new() { diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Integration.Tests/AnalyzerTests.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Integration.Tests/AnalyzerTests.cs index 8705f45f..f7b98c28 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Integration.Tests/AnalyzerTests.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Integration.Tests/AnalyzerTests.cs @@ -34,7 +34,9 @@ public static async Task ProcessProject(FileInfo projectFile) using var workspace = MSBuildWorkspace.Create(); Project project = await workspace.OpenProjectAsync(projectFile.FullName).ConfigureAwait(false); - CompilationWithAnalyzers compilationWithAnalyzers = (await project.GetCompilationAsync().ConfigureAwait(false)) + Compilation compilation = await project.GetCompilationAsync().ConfigureAwait(false) + ?? throw new InvalidOperationException("Could not get compilation"); + CompilationWithAnalyzers compilationWithAnalyzers = compilation .WithAnalyzers(ImmutableArray.Create(GetAnalyzers().ToArray())); ImmutableArray diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false); diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs index 3bc42ae9..e2e47dcd 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/CodeFixVerifier.Helper.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -26,7 +27,8 @@ private static async Task ApplyFix(Document document, CodeAction codeA { System.Collections.Immutable.ImmutableArray operations = await codeAction.GetOperationsAsync(CancellationToken.None); Solution solution = operations.OfType().Single().ChangedSolution; - return solution.GetDocument(document.Id); + return solution.GetDocument(document.Id) + ?? throw new InvalidOperationException("Could not get document from solution"); } /// @@ -66,7 +68,8 @@ private static IEnumerable GetNewDiagnostics(IEnumerable /// The compiler diagnostics that were found in the code private static IEnumerable GetCompilerDiagnostics(Document document) { - return document.GetSemanticModelAsync().Result.GetDiagnostics(); + return (document.GetSemanticModelAsync().Result + ?? throw new InvalidOperationException("Could not get semantic model")).GetDiagnostics(); } /// @@ -77,7 +80,8 @@ private static IEnumerable GetCompilerDiagnostics(Document document) private static string GetStringFromDocument(Document document) { Document simplifiedDoc = Simplifier.ReduceAsync(document, Simplifier.Annotation).Result; - SyntaxNode root = simplifiedDoc.GetSyntaxRootAsync().Result; + SyntaxNode root = simplifiedDoc.GetSyntaxRootAsync().Result + ?? throw new InvalidOperationException("Could not get syntax root"); root = Formatter.Format(root, Formatter.Annotation, simplifiedDoc.Project.Solution.Workspace); return root.GetText().ToString(); } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs index 555e025c..53f81201 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Helpers/DiagnosticVerifier.Helper.cs @@ -61,7 +61,9 @@ protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyz var diagnostics = new List(); foreach (Project project in projects) { - CompilationWithAnalyzers compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer)); + CompilationWithAnalyzers compilationWithAnalyzers = (project.GetCompilationAsync().Result + ?? throw new InvalidOperationException("Could not get compilation")) + .WithAnalyzers(ImmutableArray.Create(analyzer)); ImmutableArray diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result; foreach (Diagnostic diag in diags) { @@ -74,7 +76,7 @@ protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyz for (int i = 0; i < documents.Length; i++) { Document document = documents[i]; - SyntaxTree tree = document.GetSyntaxTreeAsync().Result; + SyntaxTree? tree = document.GetSyntaxTreeAsync().Result; if (tree == diag.Location.SourceTree) { diagnostics.Add(diag); @@ -173,7 +175,8 @@ private static Project CreateProject(string[] sources, string language = Languag count++; } - return solution.GetProject(projectId); + return solution.GetProject(projectId) + ?? throw new InvalidOperationException("Could not get project from solution"); } #endregion } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/CodeFixVerifier.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/CodeFixVerifier.cs index 253c7b60..0f0b2bdb 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/CodeFixVerifier.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/CodeFixVerifier.cs @@ -22,7 +22,7 @@ public abstract partial class CodeFixVerifier : DiagnosticVerifier /// Returns the codefix being tested (C#) - to be implemented in non-abstract class /// /// The CodeFixProvider to be used for CSharp code - protected virtual CodeFixProvider GetCSharpCodeFixProvider() + protected virtual CodeFixProvider? GetCSharpCodeFixProvider() { return null; } @@ -31,7 +31,7 @@ protected virtual CodeFixProvider GetCSharpCodeFixProvider() /// Returns the codefix being tested (VB) - to be implemented in non-abstract class /// /// The CodeFixProvider to be used for VisualBasic code - protected virtual CodeFixProvider GetBasicCodeFixProvider() + protected virtual CodeFixProvider? GetBasicCodeFixProvider() { return null; } @@ -73,8 +73,10 @@ protected async Task VerifyBasicFix(string oldSource, string newSource, int? cod /// A class in the form of a string after the CodeFix was applied to it /// Index determining which codefix to apply if there are multiple /// A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied - private static async Task VerifyFix(string language, DiagnosticAnalyzer analyzer, CodeFixProvider codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) + private static async Task VerifyFix(string language, DiagnosticAnalyzer? analyzer, CodeFixProvider? codeFixProvider, string oldSource, string newSource, int? codeFixIndex, bool allowNewCompilerDiagnostics) { + ArgumentNullException.ThrowIfNull(analyzer); + ArgumentNullException.ThrowIfNull(codeFixProvider); Document document = CreateDocument(oldSource, language); Diagnostic[] analyzerDiagnostics = GetSortedDiagnosticsFromDocuments(analyzer, [document]); IEnumerable compilerDiagnostics = GetCompilerDiagnostics(document); @@ -106,11 +108,11 @@ private static async Task VerifyFix(string language, DiagnosticAnalyzer analyzer if (!allowNewCompilerDiagnostics && newCompilerDiagnostics.Any()) { // Format and get the compiler diagnostics again so that the locations make sense in the output - document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result, Formatter.Annotation, document.Project.Solution.Workspace)); + document = document.WithSyntaxRoot(Formatter.Format(document.GetSyntaxRootAsync().Result!, Formatter.Annotation, document.Project.Solution.Workspace)); newCompilerDiagnostics = GetNewDiagnostics(compilerDiagnostics, GetCompilerDiagnostics(document)); Assert.Fail($"Fix introduced new compiler diagnostics:{string.Join(Environment.NewLine, newCompilerDiagnostics.Select(d => d.ToString()))}" + - $"{Environment.NewLine}{Environment.NewLine}New document:{Environment.NewLine}{document.GetSyntaxRootAsync().Result.ToFullString()}{Environment.NewLine}"); + $"{Environment.NewLine}{Environment.NewLine}New document:{Environment.NewLine}{document.GetSyntaxRootAsync().Result!.ToFullString()}{Environment.NewLine}"); } //check if there are analyzer diagnostics left after the code fix diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/DiagnosticVerifier.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/DiagnosticVerifier.cs index 134d643f..83f4e4a9 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/DiagnosticVerifier.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer.Test/Verifiers/DiagnosticVerifier.cs @@ -17,7 +17,7 @@ public abstract partial class DiagnosticVerifier /// /// Get the CSharp analyzer being tested - to be implemented in non-abstract class /// - protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + protected virtual DiagnosticAnalyzer? GetCSharpDiagnosticAnalyzer() { return null; } @@ -25,7 +25,7 @@ protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() /// /// Get the Visual Basic analyzer being tested (C#) - to be implemented in non-abstract class /// - protected virtual DiagnosticAnalyzer GetBasicDiagnosticAnalyzer() + protected virtual DiagnosticAnalyzer? GetBasicDiagnosticAnalyzer() { return null; } @@ -85,8 +85,9 @@ protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[] /// The language of the classes represented by the source strings /// The analyzer to be run on the source code /// DiagnosticResults that should appear after the analyzer is run on the sources - private static void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer analyzer, params DiagnosticResult[] expected) + private static void VerifyDiagnostics(string[] sources, string language, DiagnosticAnalyzer? analyzer, params DiagnosticResult[] expected) { + ArgumentNullException.ThrowIfNull(analyzer); Diagnostic[] diagnostics = GetSortedDiagnostics(sources, language, analyzer); VerifyDiagnosticResults(diagnostics, analyzer, expected); } @@ -213,7 +214,7 @@ private static string FormatDiagnostics(DiagnosticAnalyzer analyzer, params Diag Assert.IsTrue(location.IsInSource, $"Test base does not currently handle diagnostics in metadata locations. Diagnostic in metadata: {diagnostics[i]}{Environment.NewLine}"); - string resultMethodName = diagnostics[i].Location.SourceTree.FilePath.EndsWith(".cs", StringComparison.Ordinal) ? "GetCSharpResultAt" : "GetBasicResultAt"; + string resultMethodName = diagnostics[i].Location.SourceTree!.FilePath.EndsWith(".cs", StringComparison.Ordinal) ? "GetCSharpResultAt" : "GetBasicResultAt"; Microsoft.CodeAnalysis.Text.LinePosition linePosition = diagnostics[i].Location.GetLineSpan().StartLinePosition; builder.AppendFormat("{0}({1}, {2}, {3}.{4})", diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/AnalyzerBlockMixins.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/AnalyzerBlockMixins.cs index 95554c2b..8bb6a772 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/AnalyzerBlockMixins.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/AnalyzerBlockMixins.cs @@ -5,17 +5,17 @@ namespace IntelliTect.Analyzer { public static class AnalyzerBlockMixins { - private static string GetEnumAttributeValue(Enum value, Func valueAccessor) + private static string? GetEnumAttributeValue(Enum value, Func valueAccessor) where TAttribute : Attribute { - FieldInfo fi = value.GetType().GetRuntimeField(value.ToString()); + FieldInfo? fi = value.GetType().GetRuntimeField(value.ToString()); - var attributes = (TAttribute[])fi?.GetCustomAttributes(typeof(TAttribute), false); + TAttribute[]? attributes = (TAttribute[]?)fi?.GetCustomAttributes(typeof(TAttribute), false); return attributes?.Length > 0 ? valueAccessor(attributes[0]) : null; } - public static string GetDescription(this AnalyzerBlock value) + public static string? GetDescription(this AnalyzerBlock value) { if (value == AnalyzerBlock.None) { diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AsyncVoid.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AsyncVoid.cs index 8ed2eb58..ee214227 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AsyncVoid.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AsyncVoid.cs @@ -35,7 +35,10 @@ public override void Initialize(AnalysisContext context) private static void AnalyzeSymbol(SymbolAnalysisContext context) { - var methodSymbol = context.Symbol as IMethodSymbol; + if (context.Symbol is not IMethodSymbol methodSymbol) + { + return; + } if (methodSymbol.IsAsync && methodSymbol.ReturnsVoid) { diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AttributesOnSeparateLines.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AttributesOnSeparateLines.cs index 7a9e6422..61314ec1 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AttributesOnSeparateLines.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/AttributesOnSeparateLines.cs @@ -43,7 +43,11 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) Dictionary lineDictionary = []; foreach (AttributeData attribute in namedTypeSymbol.GetAttributes()) { - SyntaxReference applicationSyntaxReference = attribute.ApplicationSyntaxReference; + SyntaxReference? applicationSyntaxReference = attribute.ApplicationSyntaxReference; + if (applicationSyntaxReference is null) + { + continue; + } Microsoft.CodeAnalysis.Text.TextSpan textSpan = applicationSyntaxReference.Span; SyntaxTree syntaxTree = applicationSyntaxReference.SyntaxTree; FileLinePositionSpan lineSpan = syntaxTree.GetLineSpan(textSpan); @@ -56,7 +60,7 @@ private static void AnalyzeSymbol(SymbolAnalysisContext context) if (lineDictionary.ContainsKey(attributeLineNo) || symbolLineNumbers.Contains(attributeLineNo)) { Location location = syntaxTree.GetLocation(textSpan); - Diagnostic diagnostic = Diagnostic.Create(_Rule, location, attribute.AttributeClass.Name); + Diagnostic diagnostic = Diagnostic.Create(_Rule, location, attribute.AttributeClass?.Name); context.ReportDiagnostic(diagnostic); } diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/BanImplicitDateTimeToDateTimeOffsetConversion.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/BanImplicitDateTimeToDateTimeOffsetConversion.cs index 303e11f1..728d3521 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/BanImplicitDateTimeToDateTimeOffsetConversion.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/BanImplicitDateTimeToDateTimeOffsetConversion.cs @@ -42,7 +42,7 @@ private void AnalyzeInvocation(OperationAnalysisContext context) if (conversionOperation.Conversion.IsImplicit && conversionOperation.Conversion.MethodSymbol is object && conversionOperation.Conversion.MethodSymbol.ContainingType is object) { INamedTypeSymbol containingType = conversionOperation.Conversion.MethodSymbol.ContainingType; - INamedTypeSymbol dateTimeOffsetType = context.Compilation.GetTypeByMetadataName("System.DateTimeOffset"); + INamedTypeSymbol? dateTimeOffsetType = context.Compilation.GetTypeByMetadataName("System.DateTimeOffset"); if (SymbolEqualityComparer.Default.Equals(containingType, dateTimeOffsetType)) { context.ReportDiagnostic(Diagnostic.Create(_Rule202, conversionOperation.Syntax.GetLocation())); diff --git a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/UnusedLocalVariable.cs b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/UnusedLocalVariable.cs index dfffffcc..484cc580 100644 --- a/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/UnusedLocalVariable.cs +++ b/IntelliTect.Analyzer/IntelliTect.Analyzer/Analyzers/UnusedLocalVariable.cs @@ -39,7 +39,11 @@ private static void AnalyzeMethod(SyntaxNodeAnalysisContext context) { if (context.Node is MethodDeclarationSyntax method && method.Body != null) { - DataFlowAnalysis dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body); + DataFlowAnalysis? dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body); + if (dataFlow is null) + { + return; + } ImmutableArray variablesDeclared = dataFlow.VariablesDeclared; IEnumerable variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside,