Skip to content
Open
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
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<LangVersion>14.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
13 changes: 11 additions & 2 deletions IntelliTect.Analyzer/IntelliTect.Analyzer.CodeFixes/AsyncVoid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -45,7 +53,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)

private static async Task<Document> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(
Expand Down Expand Up @@ -78,7 +85,8 @@ private static async Task<Document> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,8 +54,16 @@ private static async Task<Solution> 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()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -49,8 +53,16 @@ private static async Task<Solution> 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()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Diagnostic> diags = await compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -26,7 +27,8 @@ private static async Task<Document> ApplyFix(Document document, CodeAction codeA
{
System.Collections.Immutable.ImmutableArray<CodeActionOperation> operations = await codeAction.GetOperationsAsync(CancellationToken.None);
Solution solution = operations.OfType<ApplyChangesOperation>().Single().ChangedSolution;
return solution.GetDocument(document.Id);
return solution.GetDocument(document.Id)
?? throw new InvalidOperationException("Could not get document from solution");
}

/// <summary>
Expand Down Expand Up @@ -66,7 +68,8 @@ private static IEnumerable<Diagnostic> GetNewDiagnostics(IEnumerable<Diagnostic>
/// <returns>The compiler diagnostics that were found in the code</returns>
private static IEnumerable<Diagnostic> GetCompilerDiagnostics(Document document)
{
return document.GetSemanticModelAsync().Result.GetDiagnostics();
return (document.GetSemanticModelAsync().Result
?? throw new InvalidOperationException("Could not get semantic model")).GetDiagnostics();
}

/// <summary>
Expand All @@ -77,7 +80,8 @@ private static IEnumerable<Diagnostic> 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ protected static Diagnostic[] GetSortedDiagnosticsFromDocuments(DiagnosticAnalyz
var diagnostics = new List<Diagnostic>();
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<Diagnostic> diags = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result;
foreach (Diagnostic diag in diags)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public abstract partial class CodeFixVerifier : DiagnosticVerifier
/// Returns the codefix being tested (C#) - to be implemented in non-abstract class
/// </summary>
/// <returns>The CodeFixProvider to be used for CSharp code</returns>
protected virtual CodeFixProvider GetCSharpCodeFixProvider()
protected virtual CodeFixProvider? GetCSharpCodeFixProvider()
{
return null;
}
Expand All @@ -31,7 +31,7 @@ protected virtual CodeFixProvider GetCSharpCodeFixProvider()
/// Returns the codefix being tested (VB) - to be implemented in non-abstract class
/// </summary>
/// <returns>The CodeFixProvider to be used for VisualBasic code</returns>
protected virtual CodeFixProvider GetBasicCodeFixProvider()
protected virtual CodeFixProvider? GetBasicCodeFixProvider()
{
return null;
}
Expand Down Expand Up @@ -73,8 +73,10 @@ protected async Task VerifyBasicFix(string oldSource, string newSource, int? cod
/// <param name="newSource">A class in the form of a string after the CodeFix was applied to it</param>
/// <param name="codeFixIndex">Index determining which codefix to apply if there are multiple</param>
/// <param name="allowNewCompilerDiagnostics">A bool controlling whether or not the test will fail if the CodeFix introduces other warnings after being applied</param>
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<Diagnostic> compilerDiagnostics = GetCompilerDiagnostics(document);
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ public abstract partial class DiagnosticVerifier
/// <summary>
/// Get the CSharp analyzer being tested - to be implemented in non-abstract class
/// </summary>
protected virtual DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
protected virtual DiagnosticAnalyzer? GetCSharpDiagnosticAnalyzer()
{
return null;
}

/// <summary>
/// Get the Visual Basic analyzer being tested (C#) - to be implemented in non-abstract class
/// </summary>
protected virtual DiagnosticAnalyzer GetBasicDiagnosticAnalyzer()
protected virtual DiagnosticAnalyzer? GetBasicDiagnosticAnalyzer()
{
return null;
}
Expand Down Expand Up @@ -85,8 +85,9 @@ protected void VerifyBasicDiagnostic(string[] sources, params DiagnosticResult[]
/// <param name="language">The language of the classes represented by the source strings</param>
/// <param name="analyzer">The analyzer to be run on the source code</param>
/// <param name="expected">DiagnosticResults that should appear after the analyzer is run on the sources</param>
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);
}
Expand Down Expand Up @@ -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})",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ namespace IntelliTect.Analyzer
{
public static class AnalyzerBlockMixins
{
private static string GetEnumAttributeValue<TAttribute>(Enum value, Func<TAttribute, string> valueAccessor)
private static string? GetEnumAttributeValue<TAttribute>(Enum value, Func<TAttribute, string> 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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
Loading
Loading