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 @@ -30,16 +30,24 @@ 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;

// The diagnostic span covers the full invocation expression (Directory.GetFiles(...))
InvocationExpressionSyntax invocation = root.FindToken(diagnosticSpan.Start)
.Parent.AncestorsAndSelf()
InvocationExpressionSyntax? invocation = root.FindToken(diagnosticSpan.Start)
.Parent?.AncestorsAndSelf()
.OfType<InvocationExpressionSyntax>()
.First();
.FirstOrDefault();
if (invocation is null)
{
return;
}

bool isGetFiles = diagnostic.Id == Analyzers.FavorDirectoryEnumerationCalls.DiagnosticId301;
string title = isGetFiles ? TitleGetFiles : TitleGetDirectories;
Expand All @@ -61,7 +69,7 @@ private static async Task<Document> UseEnumerationMethodAsync(
{
var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression;

SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
SemanticModel? semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

// Rename: Directory.GetFiles(...) → Directory.EnumerateFiles(...)
InvocationExpressionSyntax renamedInvocation = invocation.WithExpression(
Expand All @@ -76,7 +84,8 @@ private static async Task<Document> UseEnumerationMethodAsync(
SyntaxFactory.IdentifierName("ToArray")))
: renamedInvocation;

SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)
?? throw new System.InvalidOperationException("Could not get syntax root");
SyntaxNode newRoot = oldRoot.ReplaceNode(invocation, replacement.WithAdditionalAnnotations(Formatter.Annotation));

if (replacement != renamedInvocation && newRoot is CompilationUnitSyntax compilationUnit)
Expand All @@ -89,10 +98,14 @@ private static async Task<Document> UseEnumerationMethodAsync(

private static bool NeedsToArrayWrapper(
InvocationExpressionSyntax invocation,
SemanticModel semanticModel,
SemanticModel? semanticModel,
CancellationToken ct)
{
SyntaxNode parent = invocation.Parent;
if (semanticModel is null)
{
return false;
}
SyntaxNode? parent = invocation.Parent;

// string[] files = Directory.GetFiles(...) or field/property initializer
if (parent is EqualsValueClauseSyntax equalsValue)
Expand Down Expand Up @@ -123,7 +136,7 @@ private static bool NeedsToArrayWrapper(
// return Directory.GetFiles(...) in a method or local function returning string[]
if (parent is ReturnStatementSyntax)
{
TypeSyntax returnType = invocation.Ancestors()
TypeSyntax? returnType = invocation.Ancestors()
.Select(a => a switch
{
MethodDeclarationSyntax m => m.ReturnType,
Expand All @@ -141,7 +154,7 @@ private static bool NeedsToArrayWrapper(
// Expression-bodied members: string[] GetFiles() => Directory.GetFiles(...)
if (parent is ArrowExpressionClauseSyntax arrow)
{
TypeSyntax returnType = arrow.Parent switch
TypeSyntax? returnType = arrow.Parent switch
{
MethodDeclarationSyntax m => m.ReturnType,
LocalFunctionStatementSyntax lf => lf.ReturnType,
Expand All @@ -160,7 +173,7 @@ private static bool NeedsToArrayWrapper(
&& argumentList.Parent is InvocationExpressionSyntax outerInvocation
&& semanticModel.GetSymbolInfo(outerInvocation, ct).Symbol is IMethodSymbol outerMethod)
{
IParameterSymbol targetParam;
IParameterSymbol? targetParam;

// Named argument: SomeMethod(param: Directory.GetFiles(...))
if (argument.NameColon != null)
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 @@ -22,11 +22,11 @@ public abstract partial class DiagnosticVerifier
private static readonly MetadataReference _CSharpSymbolsReference = MetadataReference.CreateFromFile(typeof(CSharpCompilation).Assembly.Location);
private static readonly MetadataReference _CodeAnalysisReference = MetadataReference.CreateFromFile(typeof(Compilation).Assembly.Location);
private static readonly MetadataReference _LinqExpressionsReference = MetadataReference.CreateFromFile(typeof(Expression<>).Assembly.Location);
private static readonly MetadataReference _SystemRuntimeReference = GetSystemRuntimeReference();
private static readonly MetadataReference? _SystemRuntimeReference = GetSystemRuntimeReference();

private static MetadataReference GetSystemRuntimeReference()
private static MetadataReference? GetSystemRuntimeReference()
{
string runtimeDir = Path.GetDirectoryName(typeof(object).Assembly.Location);
string? runtimeDir = Path.GetDirectoryName(typeof(object).Assembly.Location);
if (string.IsNullOrEmpty(runtimeDir))
{
return null;
Expand Down Expand Up @@ -76,7 +76,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 @@ -89,7 +91,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 @@ -193,7 +195,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
Loading
Loading