Skip to content

Filter re-resolved analyzers from the WPF temporary project#11739

Open
wnvko-msft wants to merge 2 commits into
dotnet:mainfrom
wnvko-msft:mvenkov/fix-temp-assembly-analyzer-filtering
Open

Filter re-resolved analyzers from the WPF temporary project#11739
wnvko-msft wants to merge 2 commits into
dotnet:mainfrom
wnvko-msft:mvenkov/fix-temp-assembly-analyzer-filtering

Conversation

@wnvko-msft

@wnvko-msft wnvko-msft commented Jun 30, 2026

Copy link
Copy Markdown

Fixes #9660

Main PR

Description

When a XAML file references a locally defined type, GenerateTemporaryTargetAssembly generates and builds a temporary *_wpftmp project to resolve those types. That temporary project re-runs analyzer resolution (ResolveLockFileAnalyzers) and re-adds analyzers from NuGet packages, without importing those packages' build targets that would normally remove them. In the Visual Studio in-process build, this reintroduces the Microsoft.Extensions.Configuration.Binder source generator - which requires C#12 - into the temporary compilation, failing it with SYSLIB1102.

This change tags every analyzer flowed from the parent project with WpfTempProjectAnalyzers metadata and sets a _WpfTempProjectIncludesPackageReferences marker property on the temporary project. A new FilterTemporaryAssemblyAnalyzers target (running only inside that temporary project, after RemoveDuplicateAnalyzers and before CoreCompile) then removes any analyzer lacking the marker, restoring the authoritative analyzer set the parent project already resolved.

Customer Impact

WPF customers cannot publish (or, in some cases, build) self-contained apps from Visual Studio when they reference Microsoft.Extensions.Configuration.Binder (8.0.x) and use config binding such as config.Get<T>(). Publish fails with a generic "Publish has encountered an error" backed by SYSLIB1102. There is no straightforward workaround other than avoiding the package or forcing LangVersion, both undesirable.

Regression

Yes - this regressed for customers when the Microsoft.Extensions.Configuration.Binder package introduced its C#12 source generator (.NET 8 timeframe), combined with the Visual Studio 17.10 in-process build pipeline. It does not reproduce via dotnet build / publish from the command line, only through the Visual Studio in-process Publish path.

Testing

  • Reproduced the original failure: a WPF app referencing Microsoft.Extensions.Configuration.Binder 8.0.2 with a local type referenced in XAML, published self-contained from Visual Studio 17.10 (SDK 8.0.401) - failed with SYSLIB1102 in the *_wpftmp compilation.
  • Built PresentationBuildTasks from the corresponding release branch with this fix, staged it plus the updated targets into the local SDK, and re-ran the same Visual Studio Publish - succeeds, SYSLIB1102 is gone.
  • The new target is gated on _WpfTempProjectIncludesPackageReferences, which is set only in the package-reference temporary-build path, so normal (non-temp) builds and the legacy markup-compilation path are unaffected.

Risk

Low. The behavior change is scoped tightly:

  • The filtering target only runs inside the generated temporary project (guarded by the new _WpfTempProjectIncludesPackageReferences property), so it cannot affect normal builds or the legacy path.
  • It only removes analyzers that lack the parent-applied marker - i.e., duplicates the temporary project re-resolved on its own. All analyzers the parent project legitimately resolved are preserved, so it does not silently disable analyzers/generators a customer relies on.
  • The metadata-stamping is additive and inert outside the new target. The change is small (33 added / 2 removed lines across two files).
Microsoft Reviewers: Open in CodeFlow

GenerateTemporaryTargetAssembly builds a temporary *_wpftmp project to resolve local types referenced from XAML. That temporary project re-runs analyzer resolution and re-adds package analyzers the parent project had intentionally removed, without honoring the packages' removal targets. In the Visual Studio in-process build this may reintroduces unnecessary analyzers and to fail.

Tag the analyzers flowed from the parent project with pfTempProjectAnalyzers metadata and set _WpfTempProjectIncludesPackageReferences on the temporary project. A new FilterTemporaryAssemblyAnalyzers target then removes any analyzer lacking that marker, restoring the authoritative analyzer set the parent project already resolved.

Fixes dotnet#9660
@wnvko-msft wnvko-msft requested review from a team and Copilot June 30, 2026 08:43
@wnvko-msft wnvko-msft requested a review from a team as a code owner June 30, 2026 08:43

Copilot AI left a comment

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.

Pull request overview

This PR fixes a Visual Studio in-process WPF publish/build failure where the generated *_wpftmp temporary project re-resolves NuGet analyzers/source generators (e.g., Microsoft.Extensions.Configuration.Binder’s C# 12 generator) and ends up with an incorrect analyzer set that can break the temporary compilation.

Changes:

  • Stamp analyzer items flowed from the parent project with WpfTempProjectAnalyzers metadata when generating the temporary project.
  • Add a _WpfTempProjectIncludesPackageReferences marker property to gate temp-project-only behavior.
  • Introduce an MSBuild target to remove analyzers in the temporary project that don’t have the parent-applied marker.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Microsoft.DotNet.Wpf/src/PresentationBuildTasks/Microsoft/Build/Tasks/Windows/GenerateTemporaryTargetAssembly.cs Tags flowed analyzer items and sets a marker property in the generated temp project.
src/Microsoft.DotNet.Wpf/src/PresentationBuildTasks/Microsoft.WinFX.targets Adds FilterTemporaryAssemblyAnalyzers target to drop unmarked analyzers during temp project compilation.

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

@amarinov-msft amarinov-msft added the PR metadata: Label to tag PRs, to facilitate with triage label Jul 1, 2026
@wnvko-msft

Copy link
Copy Markdown
Author

Verification: this fix resolves a family of related issues

I reproduced each of the issues below on a pristine SDK (no fix), then verified the same repro builds cleanly with this PR's change applied. All are the same root cause: in the *_wpftmp markup-compile project, a source generator gets added to @(Analyzer) twice via different paths (framework/shared copy + NuGet package copy). The pre-existing RemoveDuplicateAnalyzers only de-dupes identical paths, so the different-path duplicate survives and the generator runs twice. This PR marks the parent's analyzers and drops any re-resolved (unmarked) analyzers in the temp project.

Issue Source generator Baseline error (no fix) With this PR
#9660 Microsoft.Extensions.Configuration.Binder SYSLIB1102 -> self-contained Publish fails (VS 17.10) ✅ Publish succeeds
#9589 [LoggerMessage] (Microsoft.Extensions.Logging) CS0757 / CS0102 ✅ builds clean
#7624 System.Text.Json CS0579 / CS0102 / CS0111 / CS8646 (19 errors) ✅ builds clean
#10175 System.Text.Json (dup of #7624) same as #7624 ✅ builds clean
#10553 [LoggerMessage] on .NET 9 CS0757 / CS0102 ✅ builds clean

Each repro was a minimal WPF app: UseWPF, a local type referenced in XAML (to trigger temp-assembly generation), plus the relevant analyzer-bearing package. #9660 reproduces only through the VS 17.10 Publish pipeline; the others reproduce via dotnet build -c Release.

**.NET 9 note: ** #10553 is on .NET 9, whereas this PR targets release/8.0. I verified it by cherry-picking this change onto release/9.0 and building - it applied cleanly and resolved the issue. A separate port to release/9.0 will be needed to ship the fix to .NET 9 users.

Suggest closing #9660, #9589, #7624, #10175, and #10553 when this merges.

@wnvko-msft

wnvko-msft commented Jul 1, 2026

Copy link
Copy Markdown
Author

Why re-running the duplicate-analyzer removal doesn't fix these

It's a reasonable question: since the SDK already has RemoveDuplicateAnalyzers, why not just rely on it (or run it again) instead of adding the marker plumbing? It won't work, and here's the concrete reason.

RemoveDuplicateAnalyzers de-dupes by exact item path:

<FilteredAnalyzer Include="@(Analyzer->Distinct())" />

Distinct() compares the item's Identity (the full path). But in these bugs the duplicate is the same generator resolved from two different locations - so the two items have different paths and Distinct() keeps both. Real example captured from the #9589 temp project (@(Analyzer) for the Logging generator):

C:\Program Files\dotnet\packs\Microsoft.AspNetCore.App.Ref\8.0.28\analyzers\...\Microsoft.Extensions.Logging.Generators.dll - from the parent
 Q:\...\.nuget\packages\microsoft.extensions.logging.abstractions\8.0.1\analyzers\...\Microsoft.Extensions.Logging.Generators.dll - re-resolved in the temp project

Same generator, two paths -> Distinct() treats them as distinct -> the generator runs twice -> CS0757 / CS0102 (and the equivalent duplicate-definition errors for STJ and the Configuration Binder). Running the path-based de-dup again changes nothing: it's idempotent, and no number of passes will collapse two different paths.

De-duping by file name / assembly identity instead is not a safe fix either:

  • It would pick an arbitrary winner between the framework/ref-pack copy and the NuGet-package copy, which can differ in version and behavior.
  • It risks dropping genuinely different analyzers that happen to share a file name.

This PR fixes the cause rather than the symptom: it marks the analyzers the parent project resolved (WpfTempProjectAnalyzers=true) and, in the temporary project, drops only the analyzers that were re-resolved on their own (unmarked). That keeps exactly the set the real project compiled with - regardless of path - so each generator runs once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR metadata: Label to tag PRs, to facilitate with triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Microsoft.Extensions.Configuration.Binder" v8.x causes WPF self-contained publish failed

3 participants