Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ dotnet_diagnostic.CA1707.severity = none # Identifiers should not contain unders
dotnet_diagnostic.CA1716.severity = none # Identifiers should not match keywords
dotnet_diagnostic.CA1806.severity = none # Ignore method results (not working properly on all cases)
dotnet_diagnostic.CA2007.severity = none # Consider calling ConfigureAwait on the awaited task
dotnet_diagnostic.VSTHRD202.severity = warning # Remove unnecessary async state machine (flagged by SonarQube)

dotnet_diagnostic.CS1574.severity = none # XML comment has cref attribute that could not be resolved (boring with {} generics)
dotnet_diagnostic.CS1591.severity = none # Missing XML comment for publicly visible type or member
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ public class ClassAnalysisService(
: IClassAnalysisService
{
/// <inheritdoc />
public async Task<ClassModel> AnalyzeFileAsync(
public Task<ClassModel> AnalyzeFileAsync(
string filePath,
AnalysisOptions? options = null)
{
return await analyzeFileUseCase.ExecuteAsync(filePath, options);
return analyzeFileUseCase.ExecuteAsync(filePath, options);
}

/// <inheritdoc />
public async Task<ClassModel> AnalyzeDirectoryAsync(
public Task<ClassModel> AnalyzeDirectoryAsync(
string directoryPath,
AnalysisOptions? options = null)
{
return await analyzeDirectoryUseCase.ExecuteAsync(directoryPath, options);
return analyzeDirectoryUseCase.ExecuteAsync(directoryPath, options);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ public sealed class TypeProcessor(ISymbolResolver symbolResolver) : ITypeProcess
/// <param name="context">The <see cref="AnalysisContext"/> containing the current state of the analysis.</param>
/// <param name="options">The <see cref="AnalysisOptions"/> controlling the analysis behavior.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public async Task ProcessTypeQueueAsync(
public Task ProcessTypeQueueAsync(
Queue<(INamedTypeSymbol Symbol, int Depth)> typesToAnalyze,
AnalysisContext context,
AnalysisOptions options)
{
await ProcessTypeQueueInternalAsync(typesToAnalyze, context, options);
return ProcessTypeQueueInternalAsync(typesToAnalyze, context, options);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ internal sealed class WorkspaceTypeDiscovery(IFileSystem fileSystem) : IWorkspac
/// A task that represents the asynchronous operation. The task result contains the full path of the file
/// containing the type definition if found; otherwise, null.
/// </returns>
public async Task<string?> FindTypeDefinitionFileAsync(string typeName, string startDirectory)
public Task<string?> FindTypeDefinitionFileAsync(string typeName, string startDirectory)
{
var root = WorkspaceRootResolver.FindWorkspaceRoot(startDirectory) ?? startDirectory;

// A single scan from the workspace root keeps resolution deterministic: a partial
// "common directory" pre-pass would return its first hit and override the path-sorted
// tie-break applied below. Lookups are memoized per type name by the caller.
return await SearchDirectoryForTypeAsync(root, typeName);
return SearchDirectoryForTypeAsync(root, typeName);
}

/// <summary>
Expand Down
8 changes: 4 additions & 4 deletions src/ProjGraph.Lib.Core/Infrastructure/SpectreOutputConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,23 +125,23 @@ public void WriteMarkup(string markup)
}

/// <inheritdoc />
public async Task<string> PromptSelectionAsync(string title, IEnumerable<string> choices,
public Task<string> PromptSelectionAsync(string title, IEnumerable<string> choices,
CancellationToken cancellationToken = default)
{
return await AnsiConsole.PromptAsync(
return AnsiConsole.PromptAsync(
new SelectionPrompt<string>()
.Title(title)
.AddChoices(choices),
cancellationToken);
}

/// <inheritdoc />
public async Task RunWithStatusAsync(string statusMessage, Func<Task> action,
public Task RunWithStatusAsync(string statusMessage, Func<Task> action,
CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();

await AnsiConsole.Status()
return AnsiConsole.Status()
.Spinner(Spinner.Known.Dots)
.StartAsync(statusMessage, async ctx =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,26 @@ public class EfAnalysisService(
DiscoverSnapshotsUseCase discoverSnapshotsUseCase) : IEfAnalysisService
{
/// <inheritdoc />
public async Task<List<string>> DiscoverContextsAsync(string path)
public Task<List<string>> DiscoverContextsAsync(string path)
{
return await discoverContextsUseCase.ExecuteAsync(path);
return discoverContextsUseCase.ExecuteAsync(path);
}

/// <inheritdoc />
public async Task<EfModel> AnalyzeContextAsync(string path, string? contextName = null)
public Task<EfModel> AnalyzeContextAsync(string path, string? contextName = null)
{
return await analyzeContextUseCase.ExecuteAsync(path, contextName);
return analyzeContextUseCase.ExecuteAsync(path, contextName);
}

/// <inheritdoc />
public async Task<List<string>> DiscoverSnapshotsAsync(string path)
public Task<List<string>> DiscoverSnapshotsAsync(string path)
{
return await discoverSnapshotsUseCase.ExecuteAsync(path);
return discoverSnapshotsUseCase.ExecuteAsync(path);
}

/// <inheritdoc />
public async Task<EfModel> AnalyzeSnapshotAsync(string path, string? snapshotName = null)
public Task<EfModel> AnalyzeSnapshotAsync(string path, string? snapshotName = null)
{
return await analyzeSnapshotUseCase.ExecuteAsync(path, snapshotName);
return analyzeSnapshotUseCase.ExecuteAsync(path, snapshotName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ public class AnalyzeContextUseCase(IEfModelAnalyzer modelAnalyzer)
/// <param name="contextName">The optional name of the DbContext class to analyze.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the analyzed Entity Framework model.</returns>
/// <exception cref="ArgumentException">Thrown when the provided file path is not a .cs file.</exception>
public async Task<EfModel> ExecuteAsync(string path, string? contextName = null)
public Task<EfModel> ExecuteAsync(string path, string? contextName = null)
{
FilePathGuard.RequireCsFile(path);
return await modelAnalyzer.AnalyzeContextAsync(path, contextName);
return modelAnalyzer.AnalyzeContextAsync(path, contextName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public class AnalyzeSnapshotUseCase(IEfModelAnalyzer modelAnalyzer)
/// <param name="snapshotName">The optional name of the ModelSnapshot class to analyze.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the analyzed Entity Framework model.</returns>
/// <exception cref="ArgumentException">Thrown when the provided file path is not a .cs file.</exception>
public async Task<EfModel> ExecuteAsync(string path, string? snapshotName = null)
public Task<EfModel> ExecuteAsync(string path, string? snapshotName = null)
{
FilePathGuard.RequireCsFile(path);

return await modelAnalyzer.AnalyzeSnapshotAsync(path, snapshotName);
return modelAnalyzer.AnalyzeSnapshotAsync(path, snapshotName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,13 @@ private static bool IsMigrationClass(TypeDeclarationSyntax typeDecl)
/// Any access errors encountered during directory traversal are ignored.
/// Directories like bin, obj, .git, and node_modules are skipped during traversal for performance.
/// </remarks>
private async Task SearchDirectoryForEntitiesAsync(
private Task SearchDirectoryForEntitiesAsync(
string searchDir,
HashSet<string> entityTypeNames,
string normalizedContextPath,
Dictionary<string, string> entityFiles)
{
await SearchDirectoryRecursiveAsync(searchDir, entityTypeNames, normalizedContextPath, entityFiles);
return SearchDirectoryRecursiveAsync(searchDir, entityTypeNames, normalizedContextPath, entityFiles);
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/ProjGraph.Mcp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace ProjGraph.Mcp;

internal static class Program
{
public static async Task Main(string[] args)
public static Task Main(string[] args)
{
var version = typeof(Program).Assembly
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
Expand Down Expand Up @@ -70,6 +70,6 @@ public static async Task Main(string[] args)
builder.Services.AddSingleton<ProjGraphTools>();

var host = builder.Build();
await host.RunAsync();
return host.RunAsync();
}
}
4 changes: 2 additions & 2 deletions src/ProjGraph.Mcp/ProjGraphTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ private static async Task<T> RunAnalysisAsync<T>(Func<Task<T>> analysis)
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The resolved absolute path.</returns>
/// <exception cref="McpException">Thrown when the path is empty or cannot be resolved.</exception>
private async Task<string> PreparePathAsync(string path, McpServer server, CancellationToken cancellationToken)
private Task<string> PreparePathAsync(string path, McpServer server, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (string.IsNullOrWhiteSpace(path))
Expand All @@ -469,7 +469,7 @@ private async Task<string> PreparePathAsync(string path, McpServer server, Cance
throw new McpException("path must not be empty.");
}

return await rootService.TryResolveAsync(path, server, cancellationToken);
return rootService.TryResolveAsync(path, server, cancellationToken);
}

private static void RequireCsFile(string path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ internal static class McpServerProcess
/// The client deliberately advertises no capabilities — in particular no workspace roots.
/// </summary>
/// <returns>A connected client; disposing it stops the server process.</returns>
public static async Task<McpClient> ConnectAsync()
public static Task<McpClient> ConnectAsync()
{
var transport = new StdioClientTransport(new StdioClientTransportOptions
{
Name = "ProjGraph e2e",
Command = LocateServerExecutable()
});

return await McpClient.CreateAsync(transport);
return McpClient.CreateAsync(transport);
}

private static string LocateServerExecutable()
Expand Down
56 changes: 28 additions & 28 deletions tests/ProjGraph.Tests.Smoke.Aot/CliParityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,74 +20,74 @@ public void Dispose()
}

[AotSmokeFact]
public async Task Visualize_Mermaid_ShouldMatchReference()
public Task Visualize_Mermaid_ShouldMatchReference()
{
await AssertDiagramParityAsync("visualize", ModularSolution, "--format", "mermaid");
return AssertDiagramParityAsync("visualize", ModularSolution, "--format", "mermaid");
}

[AotSmokeFact]
public async Task Visualize_Tree_ShouldMatchReference()
public Task Visualize_Tree_ShouldMatchReference()
{
await AssertDiagramParityAsync("visualize", ModularSolution, "--format", "tree");
return AssertDiagramParityAsync("visualize", ModularSolution, "--format", "tree");
}

[AotSmokeFact]
public async Task Visualize_Flat_ShouldMatchReference()
public Task Visualize_Flat_ShouldMatchReference()
{
await AssertDiagramParityAsync("visualize", ModularSolution, "--format", "flat");
return AssertDiagramParityAsync("visualize", ModularSolution, "--format", "flat");
}

[AotSmokeFact]
public async Task Visualize_LegacySln_ShouldMatchReference()
public Task Visualize_LegacySln_ShouldMatchReference()
{
await AssertDiagramParityAsync(
return AssertDiagramParityAsync(
"visualize", "tests/ProjGraph.Tests.Smoke.Aot/Fixtures/legacy.sln", "--format", "mermaid");
}

[AotSmokeFact]
public async Task Erd_ComplexEcommerce_ShouldMatchReference()
public Task Erd_ComplexEcommerce_ShouldMatchReference()
{
await AssertDiagramParityAsync("erd", "samples/erd/complex-ecommerce/Data/MyDbContext.cs");
return AssertDiagramParityAsync("erd", "samples/erd/complex-ecommerce/Data/MyDbContext.cs");
}

[AotSmokeFact]
public async Task Erd_SimpleContext_ShouldMatchReference()
public Task Erd_SimpleContext_ShouldMatchReference()
{
await AssertDiagramParityAsync("erd", "samples/erd/simple-context/EntityFramework/MyDbContext.cs");
return AssertDiagramParityAsync("erd", "samples/erd/simple-context/EntityFramework/MyDbContext.cs");
}

[AotSmokeFact]
public async Task ClassDiagram_DesignPatterns_ShouldMatchReference()
public Task ClassDiagram_DesignPatterns_ShouldMatchReference()
{
await AssertDiagramParityAsync(
return AssertDiagramParityAsync(
"classdiagram", "samples/classdiagram/design-patterns/Domain/Order.cs",
"--inheritance", "--dependencies", "--depth", "2", "--properties", "true", "--functions", "true");
}

[AotSmokeFact]
public async Task ClassDiagram_ComplexHierarchy_ShouldMatchReference()
public Task ClassDiagram_ComplexHierarchy_ShouldMatchReference()
{
await AssertDiagramParityAsync(
return AssertDiagramParityAsync(
"classdiagram", "samples/classdiagram/complex-hierarchy/Domain/Models/CEO.cs",
"--inheritance", "--dependencies", "--depth", "5", "--properties", "true", "--functions", "true");
}

[AotSmokeFact]
public async Task ClassDiagram_SimpleHierarchy_ShouldMatchReference()
public Task ClassDiagram_SimpleHierarchy_ShouldMatchReference()
{
await AssertDiagramParityAsync(
return AssertDiagramParityAsync(
"classdiagram", "samples/classdiagram/simple-hierarchy/Models/Admin.cs",
"--inheritance", "--dependencies", "--depth", "2", "--properties", "true", "--functions", "true");
}

[AotSmokeFact]
public async Task ClassDiagram_SourceDirectory_ShouldMatchReference()
public Task ClassDiagram_SourceDirectory_ShouldMatchReference()
{
await AssertDiagramParityAsync("classdiagram", "src", "--inheritance", "--dependencies");
return AssertDiagramParityAsync("classdiagram", "src", "--inheritance", "--dependencies");
}

[AotSmokeFact]
public async Task ClassDiagram_ConcurrencyAndAnnotationTypes_ShouldMatchReference()
public Task ClassDiagram_ConcurrencyAndAnnotationTypes_ShouldMatchReference()
{
// BCL types that bind only through the embedded reference assemblies (spec §1.5).
_temp.CreateFile("Types/Types.csproj",
Expand Down Expand Up @@ -116,15 +116,15 @@ public class Inventory : Dictionary<string, int>, IDisposable
public record StockItem(string Sku, decimal Price);
""");

await AssertDiagramParityAsync("classdiagram", file, "--inheritance", "--dependencies");
return AssertDiagramParityAsync("classdiagram", file, "--inheritance", "--dependencies");
}

[AotSmokeFact]
public async Task Visualize_SolutionWithMalformedProject_ShouldMatchReference()
public Task Visualize_SolutionWithMalformedProject_ShouldMatchReference()
{
var solution = CreateSolutionWithMalformedProject();

await AssertDiagramParityAsync("visualize", solution, "--format", "mermaid");
return AssertDiagramParityAsync("visualize", solution, "--format", "mermaid");
}

[AotSmokeFact]
Expand All @@ -145,17 +145,17 @@ public async Task Visualize_SlnListingAProjectTwice_ShouldFailLikeReference()
}

[AotSmokeFact]
public async Task Stats_Repository_ShouldMatchReferenceApartFromTiming()
public Task Stats_Repository_ShouldMatchReferenceApartFromTiming()
{
await AssertStatsParityAsync("stats", "ProjGraph.slnx");
return AssertStatsParityAsync("stats", "ProjGraph.slnx");
}

[AotSmokeFact]
public async Task Stats_SolutionWithMalformedProject_ShouldMatchReferenceApartFromTiming()
public Task Stats_SolutionWithMalformedProject_ShouldMatchReferenceApartFromTiming()
{
var solution = CreateSolutionWithMalformedProject();

await AssertStatsParityAsync("stats", solution);
return AssertStatsParityAsync("stats", solution);
}

[AotSmokeFact]
Expand Down
4 changes: 2 additions & 2 deletions tests/ProjGraph.Tests.Smoke.Aot/Helpers/McpServerPair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public async Task DisposeAsync()
}
}

private static async Task<McpClient> ConnectAsync(SmokeCommand command, ConcurrentQueue<string> standardError)
private static Task<McpClient> ConnectAsync(SmokeCommand command, ConcurrentQueue<string> standardError)
{
var transport = new StdioClientTransport(new StdioClientTransportOptions
{
Expand All @@ -68,6 +68,6 @@ private static async Task<McpClient> ConnectAsync(SmokeCommand command, Concurre
StandardErrorLines = standardError.Enqueue
});

return await McpClient.CreateAsync(transport);
return McpClient.CreateAsync(transport);
}
}
Loading