Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
5 changes: 3 additions & 2 deletions .github/skills/authoring-errors-and-warnings/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ See [assigning-msb-error-code.md](../../../documentation/assigning-msb-error-cod

## Consuming Error Resources in Code

Use the standard formatting method that extracts and applies the error code:
Use the standard formatting method that extracts and applies the error code. Engine-level project
errors use `Microsoft.Build.Internal.ProjectErrorUtilities`:

```csharp
// For errors
Expand All @@ -100,7 +101,7 @@ Log.LogErrorWithCodeFromResources("Copy.Error", sourceFile, destFile, ex.Message
Log.LogWarningWithCodeFromResources("ResolveAssemblyReference.Conflict", assemblyName);

// For engine-level errors (not in tasks)
ProjectFileErrorUtilities.ThrowInvalidProjectFile(
ProjectErrorUtilities.ThrowInvalidProject(
elementLocation,
"InvalidProjectFile",
arg1, arg2);
Expand Down
2 changes: 1 addition & 1 deletion documentation/aot/aot-trimming-strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ the reference shape for "reachable incompatible path."

| Switch (in [`src/Framework/FeatureSwitches.cs`](../../src/Framework/FeatureSwitches.cs)) | Gated path | Disabled-branch failure |
| --- | --- | --- |
| `EnableSdkResolverDynamicLoading` (`[FeatureSwitchDefinition]`+`[FeatureGuard(RUC)]`) | `SdkResolverService.GetResolvers` — plugin SDK-resolver assembly load | `ProjectFileErrorUtilities.ThrowInvalidProjectFile("SdkResolverDynamicLoadingNotSupported")` → **MSB4282** |
| `EnableSdkResolverDynamicLoading` (`[FeatureSwitchDefinition]`+`[FeatureGuard(RUC)]`) | `SdkResolverService.GetResolvers` — plugin SDK-resolver assembly load | `ProjectErrorUtilities.ThrowInvalidProject("SdkResolverDynamicLoadingNotSupported")` → **MSB4282** |
| `EnableConfigurationFileToolsets` (`[FeatureSwitchDefinition]`) | `ToolsetReader.ReadAllToolsets` — `ToolsetConfigurationReader` / `System.Configuration` | `ErrorUtilities.ThrowArgument("OM_ConfigurationFileToolsetsNotSupported")` (and the whole `System.Configuration` dependency drops out of the trimmed closure) |
| `EnableCustomPluginProbing` (BuildCheck path) | `BuildCheckBuildEventHandler.HandleBuildCheckAcquisitionEvent` — custom-check load | `checkContext.DispatchAsErrorFromText(...)` — a reported build error instead of a silent skip |
| `EnableReflectiveTaskExecution` (`[FeatureSwitchDefinition]`+`[FeatureGuard(RUC)]`) | `TaskExecutionHost.FindTask` / `InitializeForBatch` / `SetTaskParameters` — the reflective task load/instantiate/bind leaves | `ProjectErrorUtilities.ThrowInvalidProject("ReflectiveTaskExecutionNotSupported")` → **MSB4283**. Gating the leaf freed the whole build-execution chain (nodes, `BuildRequestEngine`, `RequestBuilder`/`TargetBuilder`/`TaskBuilder`, `TaskHost`, their interfaces) of `[RequiresUnreferencedCode]`, removing 5 boundary suppressions — see [aot-trim-suppressions.md - Group A](aot-trim-suppressions.md#group-a--the-il2026-build-execution-boundary) |
Expand Down
10 changes: 5 additions & 5 deletions documentation/aot/sdk-resolution.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This document has two parts:
`<Project Sdk="Microsoft.NET.Sdk">` and a project with no `Sdk` at all).
2. **A plan** to stop the SDK-resolution path from surfacing `[RequiresUnreferencedCode]`
all the way up to the `Project` constructors, and instead **fail observably** (via
`ProjectFileErrorUtilities.ThrowInvalidProjectFile`) when an SDK actually needs a
`ProjectErrorUtilities.ThrowInvalidProject`) when an SDK actually needs a
dynamically loaded resolver.

See the [folder README](README.md) for the full map; this most directly complements the mechanics
Expand Down Expand Up @@ -60,7 +60,7 @@ On first use it builds a manifest registry via `RegisterResolversManifests` ->
</SdkResolver>
```
* `Foo\Foo.dll` - the resolver assembly directly (no pattern), if there is no manifest.
* If **neither** exists -> `ProjectFileErrorUtilities.ThrowInvalidProjectFile("SdkResolverNoDllOrManifest")`.
* If **neither** exists -> `ProjectErrorUtilities.ThrowInvalidProject("SdkResolverNoDllOrManifest")`.
* Manifest parsing (`SdkResolverManifest.Load`) reads the XML and, if present, compiles
`ResolvableSdkPattern` into a `Regex` (with a 500 ms match timeout). **This step is
reflection-free** - it only reads files and builds a registry; no resolver assembly is
Expand Down Expand Up @@ -193,7 +193,7 @@ resolution running up into the `Project` constructors. Instead:
under Native AOT.
* **Dynamically loaded resolvers fail observably.** When an SDK can only be resolved by a
plugin resolver that must be loaded by reflection (NuGet, workload, custom), the engine
raises a clean, reported evaluation error via `ProjectFileErrorUtilities.ThrowInvalidProjectFile`
raises a clean, reported evaluation error via `ProjectErrorUtilities.ThrowInvalidProject`
tied to the `<Project Sdk=...>` location - instead of attempting `Assembly.LoadFrom` (which
cannot work under AOT) and instead of carrying RUC up to evaluation.

Expand Down Expand Up @@ -262,7 +262,7 @@ private List<SdkResolver> GetResolvers(IReadOnlyList<SdkResolverManifest> resolv
{
// Trimmed / Native AOT host: we cannot load a plugin SDK resolver by reflection.
// Fail observably so the caller (e.g. the AOT dotnet CLI) can fall back to a JIT MSBuild.
ProjectFileErrorUtilities.ThrowInvalidProjectFile(
ProjectErrorUtilities.ThrowInvalidProject(
sdkReferenceLocation,
"SdkResolverDynamicLoadingNotSupported",
sdk.Name,
Expand All @@ -287,7 +287,7 @@ Why this placement is correct:
* If control reaches `GetResolvers`, the default resolver already failed, so the SDK
genuinely needs a plugin - and every manifest-based resolver requires loading its DLL.
Throwing is the right, detectable outcome.
* The throw uses `ProjectFileErrorUtilities.ThrowInvalidProjectFile` with the `<Project Sdk=...>`
* The throw uses `ProjectErrorUtilities.ThrowInvalidProject` with the `<Project Sdk=...>`
location, so the developer gets a precise error and an AOT host can detect it.

### 2.4 Step 3 - remove the now-unnecessary RUC up the chain
Expand Down
4 changes: 2 additions & 2 deletions src/Build.UnitTests/BackEnd/EventSourceSink_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -754,15 +754,15 @@ internal sealed class RaiseEventHelper
/// <summary>
/// Build Warning Event
/// </summary>
private static BuildWarningEventArgs s_buildWarning = new BuildWarningEventArgs("SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender")
private static BuildWarningEventArgs s_buildWarning = new BuildWarningEventArgs("subcategory", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender")
{
BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6)
};

/// <summary>
/// Build Error Event
/// </summary>
private static BuildErrorEventArgs s_buildError = new BuildErrorEventArgs("SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender");
private static BuildErrorEventArgs s_buildError = new BuildErrorEventArgs("subcategory", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender");

/// <summary>
/// Target Started Event
Expand Down
7 changes: 4 additions & 3 deletions src/Build.UnitTests/BackEnd/LoggingContext_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using Microsoft.Build.BackEnd.Logging;
using Microsoft.Build.Framework;
using Microsoft.Build.Internal;
using Shouldly;
using Xunit;

Expand Down Expand Up @@ -67,13 +68,13 @@ public void HasLoggedErrors()
NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 1, true);
context.HasLoggedErrors.ShouldBeFalse();

context.LogCommentFromText(Framework.MessageImportance.High, "Test message");
context.LogCommentFromText(MessageImportance.High, "Test message");
context.HasLoggedErrors.ShouldBeFalse();

context.LogWarningFromText(null, null, null, null, "Test warning");
context.LogWarningFromText(DiagnosticSubcategory.None, null, null, null, "Test warning");
context.HasLoggedErrors.ShouldBeFalse();

context.LogErrorFromText(null, null, null, null, "Test error");
context.LogErrorFromText(DiagnosticSubcategory.None, null, null, null, "Test error");
context.HasLoggedErrors.ShouldBeTrue();
}
}
Expand Down
Loading
Loading