There were a couple of problems with this function on Windows. Different separators and differences in how tilde expressions are resolved for starters, but in addition there was no clear indication of what the function's inputs or outputs were supposed to be, and there were no tests to demonstrate its use.
To more easily paper over the differences between Windows paths, non-Windows paths, and tilde expressions, I've ported this function to use LLVM-based directory iteration (in fact, I would like to eliminate all of LLDB's directory iteration code entirely since LLVM's is cleaner / more efficient (i.e. it invokes fewer stat calls)). and llvm's portable path manipulation library.
Since file and directory completion assumes you are referring to files and directories on your local machine, it's safe to assume the path syntax properties of the host in doing so, so LLVM's APIs are perfect for this.
I've also added a fairly robust set of unit tests. Since you can't really predict what users will be on your machine, or what their home directories will be, I added an interface called TildeExpressionResolver, and in the unit test I've mocked up a fake implementation that acts like a unix password database. This allows us to configure some fake users and home directories in the test, so we can exercise all of those hard-to-test codepaths that normally otherwise depend on the host.
After this patch, file and directory completion works on Windows, and the same tests pass without my patch which suggests that I have not broken anything.
Note that I think there was a bug in the original implementation regarding symlinks which I've tried to fix. Previously, if you tried to complete /foo/bar/baz, and it finds /foo/bar/bazel which is a symlink, then it treats this as a directory as long as /foo/bar is a directory, which doesn't make any sense.
To fix this, if /foo/bar/bazel is a symlink, I stat it again with symlink-following on (which the previous code did not do), and check if the result is a directory.
There's no good way to test this, however.
Is there a reason why one these is a struct and the other a class?
btw, if you move the destructor definition into the .cpp file, it will also serve as a key method.