Skip to content

Remove FEATURE_LEGACY_GETFULLPATH and use Microsoft.IO.Path.GetFullPath in .NET Framework.#13769

Open
teo-tsirpanis wants to merge 4 commits into
dotnet:mainfrom
teo-tsirpanis:newpath-getfullname
Open

Remove FEATURE_LEGACY_GETFULLPATH and use Microsoft.IO.Path.GetFullPath in .NET Framework.#13769
teo-tsirpanis wants to merge 4 commits into
dotnet:mainfrom
teo-tsirpanis:newpath-getfullname

Conversation

@teo-tsirpanis

@teo-tsirpanis teo-tsirpanis commented May 15, 2026

Copy link
Copy Markdown
Contributor

Context

Extracted from #12231.

The use of Microsoft.IO.Path.GetFullPath in .NET Framework is expected to improve performance by forgoing path validation, and improve consistency with modern .NET.

Changes Made

Removed FileUtilities.GetFullPath and replaced its uses with NewPath.GetFullPath. Also removed other newly dead code.

Testing

Existing testing coverage. Some test code under #if FEATURE_LEGACY_GETFULLPATH was removed.

Notes

…lPath` in .NET Framework.

The use of the new `Path.GetFullPath` in .NET Framework
This is expected to improve performance by forgoing path validation, and improve consistency with modern .NET.
@teo-tsirpanis

Copy link
Copy Markdown
Contributor Author

This is ready for review. Let me know how you feel about this behavior change.

@teo-tsirpanis teo-tsirpanis marked this pull request as ready for review May 16, 2026 02:20
@OvesN OvesN self-assigned this May 19, 2026
@OvesN

OvesN commented May 19, 2026

Copy link
Copy Markdown
Contributor

I will run experimental VS insertion on this PR

@OvesN

OvesN commented May 20, 2026

Copy link
Copy Markdown
Contributor

Insertion seems fine. https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/740089

@rainersigwald can you please take a look on this PR?

@rainersigwald rainersigwald left a comment

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.

In general, while I'd love to have the consistency, I'm concerned about removing/shifting errors in the VS MSBuild. Most of these paths weren't already moved because of the tests pinning the current early-failure behavior, which can be user-visible.

I'm not 100% on this, though--mostly it will shift the failure to a later spot (when the path is used rather than constructed). But I'm leery of introducing silent failures that would have been caught before.


#if FEATURE_WINDOWSINTEROP
[SupportedOSPlatform("windows6.1")]
internal static unsafe string GetFullPath(string path)

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.

@JeremyKuhne since you both fixed this and did Microsoft.IO.Redist -- what do you think of this change?

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 like simplicity and consistency. There is a bit more logic in the .NET Framework implementation than what is here, but it isn't that much more expensive. The biggest hit was all of the pre-parsing of the path for correctness. While nice in theory, it was super expensive and fundamentally wrong. NTFS is not the only file system that shows up on a path in Windows. :)

@teo-tsirpanis We should double check that .NET Framework scenarios aren't opting back into legacy path handling. https://learn.microsoft.com/dotnet/framework/migration-guide/mitigation-path-normalization I presume devenv isn't in compat mode, but I haven't checked.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

devenv.exe.config has not enabled Switch.System.IO.UseLegacyPathHandling.

Copilot AI review requested due to automatic review settings June 23, 2026 11:13

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 removes the FEATURE_LEGACY_GETFULLPATH code path and standardizes .NET Framework path normalization on Microsoft.IO.Path.GetFullPath (via NewPath.GetFullPath) to improve performance and align behavior with modern .NET, along with deleting newly-dead code and associated test conditionals.

Changes:

  • Removed FEATURE_LEGACY_GETFULLPATH and the associated FileUtilities.GetFullPath implementation (and related UNC/security validation helpers).
  • Switched key FileUtilities callers to NewPath.GetFullPath on .NET Framework.
  • Cleaned up tests that depended on the legacy validation behavior and updated one evaluation test expectation.

Reviewed changes

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

Show a summary per file
File Description
src/Utilities.UnitTests/TrackedDependencies/TrackedDependenciesTests.cs Removes tests that asserted warnings/exceptions for malformed tlog paths/rooting markers under the legacy behavior.
src/Framework/NativeMethods.cs Removes the Windows interop-based GetFullPath helper previously used by the legacy implementation.
src/Framework/FileUtilities.cs Replaces internal uses of the removed helper with NewPath.GetFullPath and deletes the legacy GetFullPath/UNC validation code.
src/Framework.UnitTests/FileUtilities_Tests.cs Removes .NET Framework-only path validation tests and simplifies one conditional assertion tied to the legacy symbol.
src/Directory.BeforeCommon.targets Stops defining FEATURE_LEGACY_GETFULLPATH.
src/Build.UnitTests/Evaluation/ImportFromMSBuildExtensionsPath_Tests.cs Updates the expected logging behavior for invalid import project values (no longer expecting MSB4102 in one case).
src/Build.UnitTests/Evaluation/Expander_Tests.cs Removes tests that were compiled only under FEATURE_LEGACY_GETFULLPATH.

@@ -378,34 +366,6 @@ public void EmptyTLog()
Assert.Equal(outofdate[0].ItemSpec, Path.Combine("TestFiles", "one.cpp"));
}

@@ -537,21 +497,6 @@ public void ReadTLogWithDuplicateInRoot()
Assert.NotEmpty(d.DependencyTable); // "Dependency Table should not be empty."
}

@@ -2970,27 +2915,6 @@ public void SaveCompactedReadTlog_MaintainCompositeRootingMarkers()
Assert.True(d2.DependencyTable[Path.GetFullPath(Path.Combine("TestFiles", "three.cpp")) + "|" + Path.GetFullPath(Path.Combine("TestFiles", "two.cpp"))].Values.Count == 4);
}

<DefineConstants>$(DefineConstants);FEATURE_HANDLEPROCESSCORRUPTEDSTATEEXCEPTIONS</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_INSTALLED_MSBUILD</DefineConstants>
<!-- Path.GetFullPath The pre .Net 4.6.2 implementation of Path.GetFullPath is slow and creates strings in its work. -->
<DefineConstants>$(DefineConstants);FEATURE_LEGACY_GETFULLPATH</DefineConstants>

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.

🎉

@DustinCampbell DustinCampbell left a comment

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.

What a lovely almost-completely-red change. 😄

@JeremyKuhne might want to have a look too, since he's the source of Microsoft.IO.Redist knowledge and is pretty deep in the MSBuild code base these days.

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.

6 participants