Skip to content

RemoveExtension() on a dotfile (.bashrc, .gitignore) returns the parent directory, or /, as a file path #325

Description

@matt-edmondson

What's wrong

AbsoluteFilePath.RemoveExtension() (Semantics.Paths/Implementations/AbsoluteFilePath.cs around lines 76–79) and the same method on RelativeFilePath do this:

string pathWithoutExtension = Path.ChangeExtension(WeakString, null) ?? "";
return Create<AbsoluteFilePath>(pathWithoutExtension);

.NET treats a leading-dot file name as consisting entirely of an extension. So Path.ChangeExtension("/home/user/.bashrc", null) returns "/home/user/". SemanticPath.MakeCanonical then strips the trailing separator, and the result is the parent directory, typed as a file path.

Repro (net10.0, Linux)

Call Result
AbsoluteFilePath.Create("/home/user/.bashrc").RemoveExtension() "/home/user", the same as its own AbsoluteDirectoryPath
AbsoluteFilePath.Create("/.profile").RemoveExtension() "/", the filesystem root as a file
RelativeFilePath.Create("src/.editorconfig").RemoveExtension() "src"
RelativeFilePath.Create(".gitignore").RemoveExtension() ""
ChangeExtension(".bak") on /home/user/.bashrc "/home/user/.bak", which renames the file instead of adding an extension

Why it matters

Code such as File.Move(path, path.RemoveExtension()) or a cleanup that deletes path.RemoveExtension() silently targets a directory. The strong typing is supposed to rule out exactly this kind of mistake.

Suggested fix

Operate on the file name only. If Path.GetFileName has no . after index 0, RemoveExtension() returns the path unchanged and ChangeExtension appends the new extension. Apply the same dotfile rule to the FileExtension/FullFileExtension getters that #287 is deciding, so all extension members agree.

Acceptance: tests cover /home/user/.bashrc, /.profile, .gitignore and src/.editorconfig for both RemoveExtension and ChangeExtension, on absolute and relative file paths. RemoveExtension returns a path whose file name is unchanged, and ChangeExtension(".bak") yields .bashrc.bak.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions