Skip to content
16 changes: 11 additions & 5 deletions src/Common/SemanticModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,20 @@ private static bool IsCallbackOrReturnSymbol(ISymbol? symbol)
return false;
}

string? methodName = methodSymbol.ToString();

if (string.IsNullOrEmpty(methodName))
INamedTypeSymbol? containingType = methodSymbol.ContainingType;
if (containingType is null)
{
return false;
}

return methodName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal)
|| methodName.StartsWith("Moq.Language.IReturns", StringComparison.Ordinal);
string containingTypeName = containingType.ToDisplayString();

bool isCallback = string.Equals(methodSymbol.Name, "Callback", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal);
Comment thread
rjmurillo marked this conversation as resolved.

bool isReturns = string.Equals(methodSymbol.Name, "Returns", StringComparison.Ordinal)
Comment on lines +131 to +134
Copy link

Copilot AI Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider centralizing the callback/return symbol detection logic since similar implementations appear in both the benchmarking file and the common extensions, which would reduce duplication and simplify future maintenance.

Suggested change
bool isCallback = string.Equals(methodSymbol.Name, "Callback", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal);
bool isReturns = string.Equals(methodSymbol.Name, "Returns", StringComparison.Ordinal)
bool isCallback = string.Equals(methodName, "Callback", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal);
bool isReturns = string.Equals(methodName, "Returns", StringComparison.Ordinal)

Copilot uses AI. Check for mistakes.
&& containingTypeName.StartsWith("Moq.Language.IReturns", StringComparison.Ordinal);
Comment thread
rjmurillo marked this conversation as resolved.

return isCallback || isReturns;
}
}
138 changes: 138 additions & 0 deletions tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using System;

Check failure on line 1 in tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs#L1

Provide an 'AssemblyVersion' attribute for assembly 'srcassembly.dll'.
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis;
using Moq.Analyzers.Benchmarks.Helpers;

namespace Moq.Analyzers.Benchmarks;

[InProcess]
[MemoryDiagnoser]
public class CallbackReturnsSymbolBenchmarks
{
private IMethodSymbol? _callbackMethod;
private IMethodSymbol? _returnsMethod;

[GlobalSetup]
public void Setup()
{
(string Name, string Content)[] sources =
[
("Sample", @"namespace Moq.Language { public interface ICallback { void Callback(); } public interface IReturns { void Returns(); } }")
];

// Suppress VSTHRD002: Synchronously waiting on tasks or awaiters may cause deadlocks.
// This is required for BenchmarkDotNet compatibility and is safe in this context.
#pragma warning disable VSTHRD002
Compilation? compilation = CSharpCompilationCreator.CreateAsync(sources).GetAwaiter().GetResult();
#pragma warning restore VSTHRD002
if (compilation is null)
{
throw new InvalidOperationException("Failed to create C# compilation for benchmark sources.");
}

INamedTypeSymbol? callbackType = compilation.GetTypeByMetadataName("Moq.Language.ICallback");
if (callbackType is null)
{
throw new InvalidOperationException("Type 'Moq.Language.ICallback' not found in compilation.");
}

IMethodSymbol[] callbackMembers = callbackType.GetMembers("Callback").OfType<IMethodSymbol>().ToArray();
if (callbackMembers.Length != 1)
{
throw new InvalidOperationException($"Expected exactly one 'Callback' method in 'Moq.Language.ICallback', found {callbackMembers.Length}.");
}

_callbackMethod = callbackMembers[0];

INamedTypeSymbol? returnsType = compilation.GetTypeByMetadataName("Moq.Language.IReturns");
if (returnsType is null)
{
throw new InvalidOperationException("Type 'Moq.Language.IReturns' not found in compilation.");
}

IMethodSymbol[] returnsMembers = returnsType.GetMembers("Returns").OfType<IMethodSymbol>().ToArray();
if (returnsMembers.Length != 1)
{
throw new InvalidOperationException($"Expected exactly one 'Returns' method in 'Moq.Language.IReturns', found {returnsMembers.Length}.");
}

_returnsMethod = returnsMembers[0];
}

[Benchmark(Baseline = true)]
public bool OldCallbackCheck()
{
if (_callbackMethod is null)
{
throw new InvalidOperationException("_callbackMethod is null. Ensure Setup completed successfully.");
}

return OldIsCallbackOrReturnSymbol(_callbackMethod);
}

[Benchmark]
public bool NewCallbackCheck()
{
if (_callbackMethod is null)
{
throw new InvalidOperationException("_callbackMethod is null. Ensure Setup completed successfully.");
}

return NewIsCallbackOrReturnSymbol(_callbackMethod);
}

[Benchmark]
public bool OldReturnsCheck()
{
if (_returnsMethod is null)
{
throw new InvalidOperationException("_returnsMethod is null. Ensure Setup completed successfully.");
}

return OldIsCallbackOrReturnSymbol(_returnsMethod);
}

[Benchmark]
public bool NewReturnsCheck()
{
if (_returnsMethod is null)
{
throw new InvalidOperationException("_returnsMethod is null. Ensure Setup completed successfully.");
}

return NewIsCallbackOrReturnSymbol(_returnsMethod);
}

private static bool OldIsCallbackOrReturnSymbol(IMethodSymbol symbol)
{
string? methodName = symbol.ToString();
if (string.IsNullOrEmpty(methodName))
{
return false;
}

return methodName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal)
|| methodName.StartsWith("Moq.Language.IReturns", StringComparison.Ordinal);
}

private static bool NewIsCallbackOrReturnSymbol(IMethodSymbol symbol)
{
INamedTypeSymbol? containingType = symbol.ContainingType;
if (containingType is null)
{
return false;
}

string containingTypeName = containingType.ToDisplayString();
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Performance consideration: ToDisplayString() might be expensive.

ToDisplayString() can be relatively expensive compared to accessing symbol properties directly. For a performance benchmark, consider using more direct symbol property access.

Consider using symbol metadata directly:

-        string containingTypeName = containingType.ToDisplayString();
+        // Check namespace and type name separately for better performance
+        bool isInMoqLanguageNamespace = string.Equals(containingType.ContainingNamespace?.ToDisplayString(), "Moq.Language", StringComparison.Ordinal);
+        if (!isInMoqLanguageNamespace) return false;

Then update the checks to use containingType.Name instead of the full display string.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs at line
116, replace the use of containingType.ToDisplayString() with a direct property
access like containingType.Name to reduce overhead. This change improves
performance by avoiding the more expensive ToDisplayString() call and using the
simpler, faster symbol property instead.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai make an issue for this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@rjmurillo I've created a GitHub issue to track the performance optimization for replacing ToDisplayString() with direct symbol property access in the benchmark code.


🏁 Script executed:

#!/bin/bash
# Create GitHub issue for performance optimization in benchmark code
gh issue create \
  --title "Performance optimization: Replace ToDisplayString() with direct symbol property access in benchmarks" \
  --body "## Summary

The benchmark code in \`CallbackReturnsSymbolBenchmarks.cs\` uses \`containingType.ToDisplayString()\` which can be relatively expensive compared to accessing symbol properties directly. For performance benchmarks, using more direct symbol property access would be more appropriate.

## Context

This issue was identified during code review of the benchmark implementation for callback and returns symbol detection.

## References

- PR: https://github.com/rjmurillo/moq.analyzers/pull/429
- Comment: https://github.com/rjmurillo/moq.analyzers/pull/429#discussion_r2134957540
- Reported by: @rjmurillo

## Location

File: \`tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs\`
Method: \`NewIsCallbackOrReturnSymbol\`" \
  --assignee rjmurillo

Length of output: 948


@rjmurillo Perfect! I've successfully created GitHub issue #460 to track the performance optimization for replacing ToDisplayString() with direct symbol property access in the benchmark code.

The issue is now available at: #460

The issue includes:

  • Clear description of the performance concern
  • Context about where it was identified
  • References back to this PR and comment thread
  • Assignment to you for tracking

This will help ensure the performance optimization gets proper attention in a future iteration.


🧬 Code Graph Analysis Results

Possibly relevant snippets from tests/Moq.Analyzers.Benchmarks/Helpers/CSharpCompilationCreator.cs (lines 11-57)

internal static class CSharpCompilationCreator
{
    public static async Task<Compilation?> CreateAsync((string, string)[] sourceFiles)
    {
        (Project project, _) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            null,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            ReferenceAssemblies.Default).ConfigureAwait(false);
        return await project.GetCompilationAsync().ConfigureAwait(false);
    }

    public static async Task<Compilation?> CreateAsync((string, string)[] sourceFiles, ReferenceAssemblies referenceAssemblies)
    {
        (Project project, _) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            null,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            referenceAssemblies).ConfigureAwait(false);
        return await project.GetCompilationAsync().ConfigureAwait(false);
    }

    public static async Task<(Compilation? Compilation, AnalyzerOptions Options)> CreateWithOptionsAsync((string, string)[] sourceFiles, (string, string)[] globalOptions)
    {
        (Project project, AnalyzerOptions options) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            globalOptions,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            ReferenceAssemblies.Default).ConfigureAwait(false);
        return (await project.GetCompilationAsync().ConfigureAwait(false), options);
    }
}

Summary:
This helper class provides asynchronous methods to create Roslyn Compilation objects from source code strings. It uses a CompilationCreator.CreateProjectAsync method to create a project with specified source files and compilation options, then retrieves the compilation. It supports creating compilations with default or custom reference assemblies and can also return analyzer options. This is directly relevant to the benchmark file's Setup method where CSharpCompilationCreator.CreateAsync is called to create a compilation for the benchmark sources.


[no other relevant code snippets]


bool isCallback = string.Equals(symbol.Name, "Callback", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal);
Comment on lines +130 to +131
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential false positive matches with StartsWith check.

The StartsWith check for containing type names could match unintended types. For example, a type named "Moq.Language.ICallbackExtended" would incorrectly match the callback check.

Use exact string comparison or check the full type name:

-        bool isCallback = string.Equals(symbol.Name, "Callback", StringComparison.Ordinal)
-            && containingTypeName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal);
+        bool isCallback = string.Equals(symbol.Name, "Callback", StringComparison.Ordinal)
+            && string.Equals(containingTypeName, "Moq.Language.ICallback", StringComparison.Ordinal);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool isCallback = string.Equals(symbol.Name, "Callback", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.ICallback", StringComparison.Ordinal);
bool isCallback = string.Equals(symbol.Name, "Callback", StringComparison.Ordinal)
&& string.Equals(containingTypeName, "Moq.Language.ICallback", StringComparison.Ordinal);
🤖 Prompt for AI Agents
In tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs at lines
118-119, the use of StartsWith for checking containingTypeName can cause false
positives by matching unintended types. Replace the StartsWith check with an
exact string comparison or verify the full type name to ensure only the intended
type "Moq.Language.ICallback" matches.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai make an issue for this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@rjmurillo I've created a GitHub issue for the potential false positive bug in the StartsWith check. The issue has been assigned to you and includes all the relevant details about the problem, its impact, and references to this PR and comment thread.


🏁 Script executed:

#!/bin/bash
# Create GitHub issue for the StartsWith false positive bug
gh issue create \
  --title "Potential false positive matches with StartsWith check in callback/returns symbol detection" \
  --body "## Description

A potential bug was identified in the callback/returns symbol detection logic that could cause false positive matches.

## Problem

In \`tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs\` (lines 118-119), the current implementation uses \`StartsWith\` to check containing type names:

\`\`\`csharp
bool isCallback = string.Equals(symbol.Name, \"Callback\", StringComparison.Ordinal)
    && containingTypeName.StartsWith(\"Moq.Language.ICallback\", StringComparison.Ordinal);
\`\`\`

This approach could incorrectly match unintended types. For example, a type named \"Moq.Language.ICallbackExtended\" would incorrectly match the callback check, leading to false positives.

## Impact

This could cause the symbol detection logic to incorrectly identify methods as callback or return symbols when they shouldn't be, potentially affecting analyzer behavior.

## Suggested Solution

Replace the \`StartsWith\` check with exact string comparison to ensure only the intended types \"Moq.Language.ICallback\" and \"Moq.Language.IReturns\" match.

## References

- Original PR: https://github.com/rjmurillo/moq.analyzers/pull/429
- Comment: https://github.com/rjmurillo/moq.analyzers/pull/429#discussion_r2134957541
- Reported by: @rjmurillo" \
  --assignee rjmurillo

Length of output: 1451


@rjmurillo Perfect! I've successfully created the issue for you.

Issue #461 has been created: #461

The issue includes:

  • Clear description of the StartsWith false positive problem
  • Code example showing the problematic lines
  • Impact assessment
  • Suggested solution approach
  • References to this PR and comment thread
  • Assignment to you

The issue is now ready for tracking and can be addressed in a future PR.


🧬 Code Graph Analysis Results

Possibly relevant snippets from tests/Moq.Analyzers.Benchmarks/Helpers/CSharpCompilationCreator.cs (lines 11-57)

internal static class CSharpCompilationCreator
{
    public static async Task<Compilation?> CreateAsync((string, string)[] sourceFiles)
    {
        (Project project, _) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            null,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            ReferenceAssemblies.Default).ConfigureAwait(false);
        return await project.GetCompilationAsync().ConfigureAwait(false);
    }

    public static async Task<Compilation?> CreateAsync((string, string)[] sourceFiles, ReferenceAssemblies referenceAssemblies)
    {
        (Project project, _) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            null,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            referenceAssemblies).ConfigureAwait(false);
        return await project.GetCompilationAsync().ConfigureAwait(false);
    }

    public static async Task<(Compilation? Compilation, AnalyzerOptions Options)> CreateWithOptionsAsync((string, string)[] sourceFiles, (string, string)[] globalOptions)
    {
        (Project project, AnalyzerOptions options) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            globalOptions,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            ReferenceAssemblies.Default).ConfigureAwait(false);
        return (await project.GetCompilationAsync().ConfigureAwait(false), options);
    }
}

Summary:
This helper class provides asynchronous methods to create Roslyn Compilation objects from given source code strings. It uses a CompilationCreator.CreateProjectAsync method to create a Project and then obtains the Compilation from it. It supports optional reference assemblies and global analyzer options. This is directly relevant to the Setup method in CallbackReturnsSymbolBenchmarks.cs where CSharpCompilationCreator.CreateAsync is called to create a compilation from source code strings for benchmarking.


No other snippets appear relevant to understanding or addressing the content of CallbackReturnsSymbolBenchmarks.cs.


bool isReturns = string.Equals(symbol.Name, "Returns", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.IReturns", StringComparison.Ordinal);
Comment on lines +133 to +134
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential false positive matches with StartsWith check.

Same issue as with the callback check - StartsWith could match extended interface names.

Use exact string comparison:

-        bool isReturns = string.Equals(symbol.Name, "Returns", StringComparison.Ordinal)
-            && containingTypeName.StartsWith("Moq.Language.IReturns", StringComparison.Ordinal);
+        bool isReturns = string.Equals(symbol.Name, "Returns", StringComparison.Ordinal)
+            && string.Equals(containingTypeName, "Moq.Language.IReturns", StringComparison.Ordinal);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
bool isReturns = string.Equals(symbol.Name, "Returns", StringComparison.Ordinal)
&& containingTypeName.StartsWith("Moq.Language.IReturns", StringComparison.Ordinal);
bool isReturns = string.Equals(symbol.Name, "Returns", StringComparison.Ordinal)
&& string.Equals(containingTypeName, "Moq.Language.IReturns", StringComparison.Ordinal);
🤖 Prompt for AI Agents
In tests/Moq.Analyzers.Benchmarks/CallbackReturnsSymbolBenchmarks.cs at lines
121-122, replace the StartsWith check on containingTypeName with an exact string
comparison to avoid false positives from extended interface names. Change the
condition to compare containingTypeName exactly to "Moq.Language.IReturns" using
string.Equals with StringComparison.Ordinal.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai make an issue for this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@rjmurillo I'll create an issue to track this potential false positive problem.


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the StartsWith false positive issue
gh issue create \
  --title "Potential false positive matches in callback/returns symbol detection" \
  --body "## Description

The current implementation of callback and returns symbol detection in the benchmark code uses \`StartsWith\` checks for interface names, which could lead to false positive matches.

## Problem

In \`CallbackReturnsSymbolBenchmarks.cs\`, the \`NewIsCallbackOrReturnSymbol\` method uses:
- \`containingTypeName.StartsWith(\"Moq.Language.ICallback\", StringComparison.Ordinal)\`  
- \`containingTypeName.StartsWith(\"Moq.Language.IReturns\", StringComparison.Ordinal)\`

This could incorrectly match extended interface names like:
- \`Moq.Language.ICallbackExtended\` 
- \`Moq.Language.IReturnsSpecial\`

## Expected Behavior

The detection should use exact string comparisons to match only the specific interface names.

## Context

- **PR**: https://github.com/rjmurillo/moq.analyzers/pull/429
- **Comment**: https://github.com/rjmurillo/moq.analyzers/pull/429#discussion_r2134957538
- **Reported by**: @rjmurillo" \
  --assignee rjmurillo

Length of output: 1093


Perfect! I've successfully created issue #459 to track the potential false positive matches in callback/returns symbol detection.

Issue created: #459

The issue documents the problem with using StartsWith checks that could incorrectly match extended interface names, and it's been assigned to you for follow-up. This will help ensure the fix gets proper attention in a future PR.


🧬 Code Graph Analysis Results

Possibly relevant snippets from tests/Moq.Analyzers.Benchmarks/Helpers/CSharpCompilationCreator.cs (lines 11-57)

internal static class CSharpCompilationCreator
{
    public static async Task<Compilation?> CreateAsync((string, string)[] sourceFiles)
    {
        (Project project, _) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            null,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            ReferenceAssemblies.Default).ConfigureAwait(false);
        return await project.GetCompilationAsync().ConfigureAwait(false);
    }

    public static async Task<Compilation?> CreateAsync((string, string)[] sourceFiles, ReferenceAssemblies referenceAssemblies)
    {
        (Project project, _) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            null,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            referenceAssemblies).ConfigureAwait(false);
        return await project.GetCompilationAsync().ConfigureAwait(false);
    }

    public static async Task<(Compilation? Compilation, AnalyzerOptions Options)> CreateWithOptionsAsync((string, string)[] sourceFiles, (string, string)[] globalOptions)
    {
        (Project project, AnalyzerOptions options) = await CompilationCreator.CreateProjectAsync(
            sourceFiles,
            globalOptions,
            "TestProject",
            LanguageNames.CSharp,
            "/0/Test",
            "cs",
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            new CSharpParseOptions(LanguageVersion.Default),
            ReferenceAssemblies.Default).ConfigureAwait(false);
        return (await project.GetCompilationAsync().ConfigureAwait(false), options);
    }
}

Summary:
This helper class provides asynchronous methods to create Roslyn Compilation objects from given source files. It uses an underlying CompilationCreator.CreateProjectAsync method to create a Project and then retrieves the compilation. It supports optional reference assemblies and global analyzer options. This is directly relevant because the benchmark file uses CSharpCompilationCreator.CreateAsync to create a compilation for the benchmark setup.


[no other relevant code snippets]


return isCallback || isReturns;
}
}
Loading