Skip to content

Expose import tree as MSBuildImportedProject items#13681

Open
drewnoakes wants to merge 5 commits intodotnet:mainfrom
drewnoakes:imported-project-items
Open

Expose import tree as MSBuildImportedProject items#13681
drewnoakes wants to merge 5 commits intodotnet:mainfrom
drewnoakes:imported-project-items

Conversation

@drewnoakes
Copy link
Copy Markdown
Member

@drewnoakes drewnoakes commented May 5, 2026

Replaces #13680

When the MSBuild property MSBuildProvideImportedProjects is set to true, the engine synthesizes MSBuildImportedProject items from the import closure during ProjectInstance construction.

Each item's identity is the full path of the imported project file, with metadata:

  • ImportingProjectPath — the file that contains the <Import> element
  • Sdk — the SDK name if this was an SDK-resolved import
<PropertyGroup>
  <MSBuildProvideImportedProjects>true</MSBuildProvideImportedProjects>
</PropertyGroup>

<Target Name="ShowImports">
  <Message Text="%(MSBuildImportedProject.Identity) imported by %(MSBuildImportedProject.ImportingProjectPath)" />
</Target>

Items are regular MSBuild items, so they naturally serialize to out-of-proc worker nodes and are available to any target or task. No new API surface is required. Projects that don't set the property pay zero cost.

When the MSBuild property `MSBuildProvideImportedProjects` is set to `true`,
the engine synthesizes `MSBuildImportedProject` items from the import closure
during ProjectInstance construction.

Each item's identity is the full path of the imported project file, with metadata:
- `ImportingProjectPath` — the file that contains the `<Import>` element
- `Sdk` — the SDK name if this was an SDK-resolved import

```xml
<PropertyGroup>
  <MSBuildProvideImportedProjects>true</MSBuildProvideImportedProjects>
</PropertyGroup>

<Target Name="ShowImports">
  <Message Text="%(MSBuildImportedProject.Identity) imported by %(MSBuildImportedProject.ImportingProjectPath)" />
</Target>
```

Items are regular MSBuild items, so they naturally serialize to out-of-proc
worker nodes and are available to any target or task. No new API surface is
required. Projects that don't set the property pay zero cost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 5, 2026 02:47
@drewnoakes drewnoakes force-pushed the imported-project-items branch from 80ba8d1 to 90ef9fe Compare May 5, 2026 02:48
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 adds an opt-in mechanism (MSBuildProvideImportedProjects=true) to expose the evaluated import closure as regular MSBuild items (MSBuildImportedProject) on ProjectInstance, enabling targets/tasks to query the import graph without introducing new public API.

Changes:

  • Introduces a new internal constant for the opt-in property name (MSBuildProvideImportedProjects).
  • Synthesizes MSBuildImportedProject items from the evaluated import closure during ProjectInstance construction, including ImportingProjectPath and Sdk metadata.
  • Adds unit tests validating item creation behavior, metadata, and target visibility.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
src/Framework/Constants.cs Adds an internal constant for the opt-in property name.
src/Build/Instance/ProjectInstance.cs Creates MSBuildImportedProject items from the import closure when opted in.
src/Build.UnitTests/Instance/ProjectInstance_ImportedProjectItems_Tests.cs New tests validating opt-in behavior and metadata for standard and SDK imports.

Comment thread src/Build/Instance/ProjectInstance.cs Outdated
Comment thread src/Build/Instance/ProjectInstance.cs
Comment thread src/Build/Instance/ProjectInstance.cs
Comment thread src/Build/Instance/ProjectInstance.cs
Comment thread src/Build.UnitTests/Instance/ProjectInstance_ImportedProjectItems_Tests.cs Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

Design-Level Observations

  • Missing spec/documentation: This introduces a new opt-in MSBuild feature (a new well-known property MSBuildProvideImportedProjects and a new well-known item type MSBuildImportedProject), but there's no linked design spec in documentation/specs/ and no update to documentation/Built-in-Properties.md. For discoverability and long-term maintenance, both the property and the synthesized items should be documented.

  • Interaction with _itemsByEvaluatedInclude cache: When ProjectInstanceSettings.ImmutableWithFastItemLookup is set, the _itemsByEvaluatedInclude index is built before CreateImportsSnapshot runs. This means the synthesized MSBuildImportedProject items will not be in the fast-lookup cache, causing GetItemsByItemTypeAndEvaluatedInclude to potentially miss them or fall back to linear scan depending on its implementation path. This inconsistency should be documented or addressed.

  • No test for property set via global properties: The tests only verify the property set in the project file. Since global properties take precedence, a test verifying MSBuildProvideImportedProjects works as a global property (passed via ProjectCollection.GlobalProperties or command-line /p:) would strengthen coverage and also validate the intended usage pattern (tooling passing it externally without modifying project files).

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

  • #13681 pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Expert Code Review (on open) for issue #13681 · ● 26.1M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

# Dimension Verdict
3 Performance & Allocation Awareness 🟡 1 MODERATE
18 Documentation Accuracy 🟡 1 NIT
22 Correctness & Edge Cases 🟡 2 (1 MAJOR, 1 MODERATE)

✅ 21/24 dimensions clean.

  • Correctness — unescaped path passed to includeEscaped parameter; paths with % chars will be corrupted
  • Correctness — potential NRE if SdkResult.SdkReference is null
  • Performance — per-iteration array allocation in import closure loop
  • Documentation — constant XML doc says "during evaluation" but occurs during ProjectInstance creation

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

  • #13681 pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

Generated by Expert Code Review (on open) for issue #13681 · ● 26.1M

Comment thread src/Build/Instance/ProjectInstance.cs Outdated
Comment thread src/Build/Instance/ProjectInstance.cs Outdated
Comment thread src/Build/Instance/ProjectInstance.cs Outdated
Comment thread src/Framework/Constants.cs Outdated
@drewnoakes drewnoakes force-pushed the imported-project-items branch from 90ef9fe to 6c88efa Compare May 5, 2026 05:33
drewnoakes and others added 3 commits May 6, 2026 11:25
- Use EscapedFullPath for include and ImportingProjectPath metadata
- Use EscapingUtilities.Escape(FullPath) for definingFileEscaped
- Add null-conditional on SdkReference (SdkResult?.SdkReference?.Name)
- Reuse metadata list with Clear() instead of allocating per iteration
- Early-continue for root project (clarity)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix doc comment: 'during evaluation' -> 'during ProjectInstance creation'
- Add test verifying MSBuildProvideImportedProjects works as a global property

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Document MSBuildProvideImportedProjects property and MSBuildImportedProject
  items in Built-in-Properties.md
- Add MSBuildProvideImportedProjects property to Microsoft.Build.CommonTypes.xsd
  for tooling completion and documentation
- Add MSBuildImportedProject item type with ImportingProjectPath and Sdk metadata
  to Microsoft.Build.CommonTypes.xsd

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@drewnoakes drewnoakes force-pushed the imported-project-items branch from 6c88efa to e5985a5 Compare May 6, 2026 03:24

_importPathsIncludingDuplicates = importPathsIncludingDuplicates;
ImportPathsIncludingDuplicates = importPathsIncludingDuplicates.AsReadOnly();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would prefer to make this a separate helper method instead, if we would keep this code here.

metadata ??= [];
metadata.Clear();

metadata.Add(new("ImportingProjectPath", import.ImportingElement.ContainingProject.EscapedFullPath));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's make the constants for item and metadata names as well.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not convinced this is the right place for the code. From the conversation with @rainersigwald, my understanding was that we'd place this in the evaluation stage: at the start of the items pass, after the property evaluation pass. This change runs after evaluation, during ProjectInstance construction, which means the synthesized items only appear on ProjectInstance, not on Project. I am not entirely sure how important this distinction is for your use case, but I can imagine there being cases (edge or otherwise) where it could make a difference.

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