Skip to content

Improve polyfill generator by emitting a generated file for each source file, into a partial class#41

Merged
koenbeuk merged 3 commits intomainfrom
optimize-polyfill-gen
Apr 21, 2026
Merged

Improve polyfill generator by emitting a generated file for each source file, into a partial class#41
koenbeuk merged 3 commits intomainfrom
optimize-polyfill-gen

Conversation

@PhenX
Copy link
Copy Markdown
Member

@PhenX PhenX commented Apr 20, 2026

I noticed a single file was emitted for every generated polyfill, which might become problematic, here are the benchmarks, for multiple files :

image

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 93.02326% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...iveSharp.Generator/PolyfillInterceptorGenerator.cs 93.02% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment thread src/ExpressiveSharp.Generator/PolyfillInterceptorGenerator.cs Dismissed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the PolyfillInterceptorGenerator to emit one generated interceptor file per input source file by generating into a shared static partial interceptor class, aiming to reduce incremental-generator overhead as call site counts grow.

Changes:

  • Update generator pipeline to process/emit per CompilationUnitSyntax, producing one .g.cs per source file and using a partial PolyfillInterceptors class.
  • Change generated interceptor/method naming to include a file-derived tag + call-site line/column for uniqueness.
  • Update benchmarks and snapshot-verified test outputs to match the new emission strategy and identifiers.

Reviewed changes

Copilot reviewed 93 out of 93 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/ExpressiveSharp.Generator/PolyfillInterceptorGenerator.cs Refactors generator to emit one generated file per source file; updates naming, caching comparer, and emission logic.
benchmarks/ExpressiveSharp.Benchmarks/PolyfillGeneratorBenchmarks.cs Expands/renames benchmarks to measure cold vs incremental edits and single-file vs multi-file scenarios.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/WhereTests.cs Adds using System.Linq; (currently appears unused).
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.cs Adds using System.Linq; (currently appears unused).
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/OrderByTests.cs Adds using System.Linq; (currently appears unused).
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ZipTests.Zip_WithResultSelector_GeneratesInterceptor.verified.txt Updates snapshot to partial class + new method/variable identifiers.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/WhereTests.Where_SimpleCondition_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/WhereTests.Where_CapturedVariable_GeneratesClosureAccess.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/WhereTests.Where_CapturedInstanceField_GeneratesClosureAccess.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/WhereTests.ChainedWhereAndSelect_GeneratesTwoInterceptors.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.ThenByDescending_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.TakeWhile_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.SkipWhile_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.OrderByDescending_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.DistinctBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SingleLambdaQueryableTests.CountBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SetOperationTests.UnionBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SetOperationTests.IntersectBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SetOperationTests.ExceptBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SelectTests.Select_NamedType_GeneratesConcreteInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SelectTests.Select_AnonymousType_GeneratesGenericInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SelectTests.Select_AnonymousType_WithComputedExpression_GeneratesCorrectly.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SelectManyTests.SelectMany_CollectionSelector_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/SelectManyTests.SelectMany_WithResultSelector_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_NullableLongSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_NullableIntSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_NullableFloatSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_NullableDoubleSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_NullableDecimalSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_LongSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_IntSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_FloatSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_DoubleSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Sum_DecimalSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Single_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.SingleOrDefault_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Min_GenericSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.MinBy_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Max_GenericSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.MaxBy_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.LongCount_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Last_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.LastOrDefault_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.First_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.FirstOrDefault_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Count_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_NullableLongSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_NullableIntSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_NullableFloatSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_NullableDoubleSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_NullableDecimalSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_LongSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_IntSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_FloatSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_DoubleSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Average_DecimalSelector_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.Any_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ScalarMethodTests.All_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/PolyfillTests.Polyfill_SimpleLambda_GeneratesExpression.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/PolyfillTests.Polyfill_NullConditional_RewritesOperator.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/PolyfillTests.Polyfill_InferredTypeArgument_GeneratesExpression.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/PolyfillTests.Polyfill_CapturedVariable_GeneratesClosureAccess.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/PolyfillTargetTests.PolyfillTarget_WithoutAttribute_DefaultsToQueryable.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/PolyfillTargetTests.PolyfillTarget_RoutesToSpecifiedType.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/OrderByTests.ThenBy_CastsToIOrderedQueryable.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/OrderByTests.OrderBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/NullConditionalTests.NullConditionalRewrite_ExpandsInWhereBody.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/JoinTests.Join_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/JoinTests.Join_AnonymousResultSelector_GeneratesGenericInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/JoinTests.GroupJoin_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/JoinTests.GroupJoin_AnonymousResultSelector_GeneratesGenericInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GroupByTests.GroupBy_WithResultSelector_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GroupByTests.GroupBy_WithElementSelector_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GroupByTests.GroupBy_WithElementAndResultSelector_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GroupByTests.GroupBy_GeneratesGroupingReturnType.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GlobalOptionsTests.Where_PerCallOverridesGlobal.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GlobalOptionsTests.Where_GlobalNullConditionalRewrite_AppliesWithoutPerCallOverride.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/GlobalOptionsTests.Polyfill_GlobalNullConditionalIgnore_UsesIgnoreMode.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ExecuteUpdateTests.ExecuteUpdate_SetProperty_WithSwitchExpression.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ExecuteUpdateTests.ExecuteUpdate_SetProperty_WithNullConditional.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ExecuteUpdateTests.ExecuteUpdate_SetProperty_ConstantValue.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ExecuteUpdateTests.ExecuteUpdateAsync_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ComparerOverloadTests.OrderBy_WithComparer_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ComparerOverloadTests.GroupBy_WithComparer_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/ComparerOverloadTests.DistinctBy_WithComparer_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AnonymousElementTests.Where_AfterAnonymousSelect_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AnonymousElementTests.Select_AfterAnonymousSelect_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AnonymousElementTests.OrderByDescending_AfterAnonymousSelect_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AnonymousElementTests.GroupBy_AfterAnonymousSelect_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AnonymousElementTests.DistinctBy_AfterAnonymousSelect_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AnonymousElementTests.Count_AfterAnonymousSelect_GeneratesScalarInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AggregateByTests.AggregateBy_WithSeedSelector_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.
tests/ExpressiveSharp.Generator.Tests/PolyfillInterceptorGenerator/AggregateByTests.AggregateBy_GeneratesInterceptor.verified.txt Snapshot update for new naming/emission.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +121 to +133
// Combine with the compilation so ProcessFileAndEmit can build a SemanticModel.
//
// WithComparer uses REFERENCE equality on the CompilationUnitSyntax root node:
// • Roslyn syntax trees are immutable — editing a noise file creates a new
// Compilation but keeps every other file's syntax tree root as the EXACT
// SAME object reference across incremental runs.
// • All untouched source files compare as "equal" → RegisterSourceOutput
// skipped entirely → O(1) incremental cost for noise-file edits.
// • Only files that were actually edited get a new root reference → re-run.
var filesWithCompilation = candidateFiles
.Combine(context.CompilationProvider)
.WithComparer(CompilationUnitAndCompilationComparer.Instance);

Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

The new .WithComparer(CompilationUnitAndCompilationComparer) ignores the Compilation entirely (reference-equality only on the CompilationUnitSyntax). This can cause stale generated interceptors when the compilation changes without this file’s syntax root changing (e.g., referenced assembly updates, symbol changes from other file edits that affect binding in this file). Consider incorporating relevant compilation identity into equality (at least ExternalReferences like MemberDeclarationSyntaxAndCompilationEqualityComparer does) so semantic-dependent output is recomputed when needed.

Copilot uses AI. Check for mistakes.
Comment on lines 156 to +268
@@ -181,26 +225,63 @@ public InterceptsLocationAttribute(int version, string data) { }
}
""";

spc.AddSource("PolyfillInterceptors.g.cs",
spc.AddSource(ComputeOutputFileName(sourcePath),
SourceText.From(source, Encoding.UTF8));
}

/// <summary>
/// Computes a stable output file name for a given source file.
/// One interceptor file is generated per source file, keyed by the full 32-bit
/// FNV-1a hash of the source path.
/// </summary>
private static string ComputeOutputFileName(string sourcePath)
{
unchecked
{
var hash = 2166136261u;
for (var i = 0; i < sourcePath.Length; i++)
{
hash ^= (uint)sourcePath[i];
hash *= 16777619u;
}
return "PolyfillInterceptors_" + hash.ToString("x8") + ".g.cs";
}
}

/// <summary>
/// Returns a short (4-char hex) tag derived from the source file path hash.
/// Used as a prefix in interceptor method names to prevent collisions between
/// files that have call sites at identical line/col positions.
/// </summary>
private static string GetFileTag(string sourcePath)
{
unchecked
{
var hash = 2166136261u;
for (var i = 0; i < sourcePath.Length; i++)
{
hash ^= (uint)sourcePath[i];
hash *= 16777619u;
}
return (hash & 0xFFFFu).ToString("x4");
}
}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

ComputeOutputFileName/GetFileTag are derived from SyntaxTree.FilePath. In real builds FilePath is often an absolute path, so method names + hint names may vary across machines, undermining deterministic/reproducible builds. Also, if FilePath is empty (possible for in-memory trees), multiple trees will hash to the same value, causing AddSource hint-name collisions. Consider basing the hash on a stable project-relative path (via AnalyzerConfigOptions) and/or including a fallback unique key when FilePath is empty.

Copilot uses AI. Check for mistakes.
Comment on lines +251 to +267
/// <summary>
/// Returns a short (4-char hex) tag derived from the source file path hash.
/// Used as a prefix in interceptor method names to prevent collisions between
/// files that have call sites at identical line/col positions.
/// </summary>
private static string GetFileTag(string sourcePath)
{
unchecked
{
var hash = 2166136261u;
for (var i = 0; i < sourcePath.Length; i++)
{
hash ^= (uint)sourcePath[i];
hash *= 16777619u;
}
return (hash & 0xFFFFu).ToString("x4");
}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

GetFileTag truncates the path hash to 16 bits. In solutions with a few hundred+ source files, collisions become plausible and would produce duplicate interceptor method names across files (same fileTag + line/col), causing compilation failures in the generated partial class. Use a larger tag (e.g., full 32-bit hash) or incorporate additional disambiguation.

Copilot uses AI. Check for mistakes.
Comment on lines 190 to 199
var lineSpan = inv.GetLocation().GetLineSpan();
spc.ReportDiagnostic(Diagnostic.Create(
Diagnostics.InterceptorEmissionFailed,
inv.GetLocation(),
Location.Create(
lineSpan.Path,
new TextSpan(0, 0),
new LinePositionSpan(
new LinePosition(lineSpan.StartLinePosition.Line, lineSpan.StartLinePosition.Character),
new LinePosition(lineSpan.StartLinePosition.Line, lineSpan.StartLinePosition.Character))),
ex.GetType().Name + ": " + ex.Message));
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

The diagnostic location built in the catch block uses TextSpan(0, 0), which can make the reported diagnostic point to the start of the file rather than the failing invocation span (affecting navigation/squiggles). Prefer reporting inv.GetLocation() (or Location.Create with inv.Span) so the diagnostic accurately highlights the call site.

Copilot uses AI. Check for mistakes.
Comment thread benchmarks/ExpressiveSharp.Benchmarks/PolyfillGeneratorBenchmarks.cs Outdated
Comment on lines +1 to 3
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VerifyMSTest;
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

This new using System.Linq; appears unused in this test file (it only appears inside the source string). With TreatWarningsAsErrors enabled, an unused using directive will fail the build. Please remove it unless it’s actually needed.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to 3
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VerifyMSTest;
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

This new using System.Linq; appears unused in this test file (it only appears inside the source string). With TreatWarningsAsErrors enabled, an unused using directive will fail the build. Please remove it unless it’s actually needed.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to 3
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using VerifyMSTest;
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

This new using System.Linq; appears unused in this test file (it only appears inside the source string). With TreatWarningsAsErrors enabled, an unused using directive will fail the build. Please remove it unless it’s actually needed.

Copilot uses AI. Check for mistakes.
PhenX and others added 2 commits April 20, 2026 22:49
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Thread SourceProductionContext through TryEmitPolyfill / TryEmit /
EmitGenericLambda / EmitLambdaBody so ExpressionTreeEmitter can report
EXP0007, EXP0008, EXP0009, EXP0011, and EXP0018 for lambdas in
IExpressiveQueryable LINQ calls and ExpressionPolyfill.Create.
Previously passing context: null silenced these warnings; users would
get runtime default-value behavior with no compile-time signal.

Also restore EXP0010 (InterceptorEmissionFailed) to use
inv.GetLocation() instead of a zero-width span at the invocation's
starting line/col, so IDEs highlight the full invocation again.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@koenbeuk koenbeuk merged commit efe0586 into main Apr 21, 2026
20 checks passed
@koenbeuk koenbeuk deleted the optimize-polyfill-gen branch April 21, 2026 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants