@@ -201,6 +201,21 @@ class ErrorDummyFileSystem : public DummyFileSystem {
201201 }
202202};
203203
204+ // / A version of \c DummyFileSystem that aborts on \c status() to test that
205+ // / \c exists() is being used.
206+ class NoStatusDummyFileSystem : public DummyFileSystem {
207+ public:
208+ ErrorOr<vfs::Status> status (const Twine &Path) override {
209+ llvm::report_fatal_error (
210+ " unexpected call to NoStatusDummyFileSystem::status" );
211+ }
212+
213+ bool exists (const Twine &Path) override {
214+ auto Status = DummyFileSystem::status (Path);
215+ return Status && Status->exists ();
216+ }
217+ };
218+
204219// / Replace back-slashes by front-slashes.
205220std::string getPosixPath (const Twine &S) {
206221 SmallString<128 > Result;
@@ -968,6 +983,30 @@ TEST(OverlayFileSystemTest, PrintOutput) {
968983 Output);
969984}
970985
986+ TEST (OverlayFileSystemTest, Exists) {
987+ IntrusiveRefCntPtr<DummyFileSystem> Lower (new NoStatusDummyFileSystem ());
988+ IntrusiveRefCntPtr<DummyFileSystem> Upper (new NoStatusDummyFileSystem ());
989+ IntrusiveRefCntPtr<vfs::OverlayFileSystem> O (
990+ new vfs::OverlayFileSystem (Lower));
991+ O->pushOverlay (Upper);
992+
993+ Lower->addDirectory (" /both" );
994+ Upper->addDirectory (" /both" );
995+ Lower->addRegularFile (" /both/lower_file" );
996+ Upper->addRegularFile (" /both/upper_file" );
997+ Lower->addDirectory (" /lower" );
998+ Upper->addDirectory (" /upper" );
999+
1000+ EXPECT_TRUE (O->exists (" /both" ));
1001+ EXPECT_TRUE (O->exists (" /both" ));
1002+ EXPECT_TRUE (O->exists (" /both/lower_file" ));
1003+ EXPECT_TRUE (O->exists (" /both/upper_file" ));
1004+ EXPECT_TRUE (O->exists (" /lower" ));
1005+ EXPECT_TRUE (O->exists (" /upper" ));
1006+ EXPECT_FALSE (O->exists (" /both/nope" ));
1007+ EXPECT_FALSE (O->exists (" /nope" ));
1008+ }
1009+
9711010TEST (ProxyFileSystemTest, Basic) {
9721011 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base (
9731012 new vfs::InMemoryFileSystem ());
@@ -3364,6 +3403,11 @@ TEST(RedirectingFileSystemTest, ExternalPaths) {
33643403 SeenPaths.push_back (Dir.str ());
33653404 return ProxyFileSystem::dir_begin (Dir, EC);
33663405 }
3406+
3407+ bool exists (const Twine &Path) override {
3408+ SeenPaths.push_back (Path.str ());
3409+ return ProxyFileSystem::exists (Path);
3410+ }
33673411 };
33683412
33693413 std::error_code EC;
@@ -3395,3 +3439,124 @@ TEST(RedirectingFileSystemTest, ExternalPaths) {
33953439
33963440 EXPECT_EQ (CheckFS->SeenPaths , Expected);
33973441}
3442+
3443+ TEST (RedirectingFileSystemTest, Exists) {
3444+ IntrusiveRefCntPtr<DummyFileSystem> Dummy (new NoStatusDummyFileSystem ());
3445+ auto YAML =
3446+ MemoryBuffer::getMemBuffer (" {\n "
3447+ " 'version': 0,\n "
3448+ " 'roots': [\n "
3449+ " {\n "
3450+ " 'type': 'directory-remap',\n "
3451+ " 'name': '/dremap',\n "
3452+ " 'external-contents': '/a',\n "
3453+ " },"
3454+ " {\n "
3455+ " 'type': 'directory-remap',\n "
3456+ " 'name': '/dmissing',\n "
3457+ " 'external-contents': '/dmissing',\n "
3458+ " },"
3459+ " {\n "
3460+ " 'type': 'directory',\n "
3461+ " 'name': '/both',\n "
3462+ " 'contents': [\n "
3463+ " {\n "
3464+ " 'type': 'file',\n "
3465+ " 'name': 'vfile',\n "
3466+ " 'external-contents': '/c'\n "
3467+ " }\n "
3468+ " ]\n "
3469+ " },\n "
3470+ " {\n "
3471+ " 'type': 'directory',\n "
3472+ " 'name': '/vdir',\n "
3473+ " 'contents': ["
3474+ " {\n "
3475+ " 'type': 'directory-remap',\n "
3476+ " 'name': 'dremap',\n "
3477+ " 'external-contents': '/b'\n "
3478+ " },\n "
3479+ " {\n "
3480+ " 'type': 'file',\n "
3481+ " 'name': 'missing',\n "
3482+ " 'external-contents': '/missing'\n "
3483+ " },\n "
3484+ " {\n "
3485+ " 'type': 'file',\n "
3486+ " 'name': 'vfile',\n "
3487+ " 'external-contents': '/c'\n "
3488+ " }]\n "
3489+ " }]\n "
3490+ " }" );
3491+
3492+ Dummy->addDirectory (" /a" );
3493+ Dummy->addRegularFile (" /a/foo" );
3494+ Dummy->addDirectory (" /b" );
3495+ Dummy->addRegularFile (" /c" );
3496+ Dummy->addRegularFile (" /both/foo" );
3497+
3498+ auto Redirecting = vfs::RedirectingFileSystem::create (
3499+ std::move (YAML), nullptr , " " , nullptr , Dummy);
3500+
3501+ EXPECT_TRUE (Redirecting->exists (" /dremap" ));
3502+ EXPECT_FALSE (Redirecting->exists (" /dmissing" ));
3503+ EXPECT_FALSE (Redirecting->exists (" /unknown" ));
3504+ EXPECT_TRUE (Redirecting->exists (" /both" ));
3505+ EXPECT_TRUE (Redirecting->exists (" /both/foo" ));
3506+ EXPECT_TRUE (Redirecting->exists (" /both/vfile" ));
3507+ EXPECT_TRUE (Redirecting->exists (" /vdir" ));
3508+ EXPECT_TRUE (Redirecting->exists (" /vdir/dremap" ));
3509+ EXPECT_FALSE (Redirecting->exists (" /vdir/missing" ));
3510+ EXPECT_TRUE (Redirecting->exists (" /vdir/vfile" ));
3511+ EXPECT_FALSE (Redirecting->exists (" /vdir/unknown" ));
3512+ }
3513+
3514+ TEST (RedirectingFileSystemTest, ExistsFallback) {
3515+ IntrusiveRefCntPtr<DummyFileSystem> Dummy (new NoStatusDummyFileSystem ());
3516+ auto YAML =
3517+ MemoryBuffer::getMemBuffer (" {\n "
3518+ " 'version': 0,\n "
3519+ " 'redirecting-with': 'fallback',\n "
3520+ " 'roots': [\n "
3521+ " {\n "
3522+ " 'type': 'file',\n "
3523+ " 'name': '/fallback',\n "
3524+ " 'external-contents': '/missing',\n "
3525+ " },"
3526+ " ]\n "
3527+ " }" );
3528+
3529+ Dummy->addRegularFile (" /fallback" );
3530+
3531+ auto Redirecting = vfs::RedirectingFileSystem::create (
3532+ std::move (YAML), nullptr , " " , nullptr , Dummy);
3533+
3534+ EXPECT_TRUE (Redirecting->exists (" /fallback" ));
3535+ EXPECT_FALSE (Redirecting->exists (" /missing" ));
3536+ }
3537+
3538+ TEST (RedirectingFileSystemTest, ExistsRedirectOnly) {
3539+ IntrusiveRefCntPtr<DummyFileSystem> Dummy (new NoStatusDummyFileSystem ());
3540+ auto YAML =
3541+ MemoryBuffer::getMemBuffer (" {\n "
3542+ " 'version': 0,\n "
3543+ " 'redirecting-with': 'redirect-only',\n "
3544+ " 'roots': [\n "
3545+ " {\n "
3546+ " 'type': 'file',\n "
3547+ " 'name': '/vfile',\n "
3548+ " 'external-contents': '/a',\n "
3549+ " },"
3550+ " ]\n "
3551+ " }" );
3552+
3553+ Dummy->addRegularFile (" /a" );
3554+ Dummy->addRegularFile (" /b" );
3555+
3556+ auto Redirecting = vfs::RedirectingFileSystem::create (
3557+ std::move (YAML), nullptr , " " , nullptr , Dummy);
3558+
3559+ EXPECT_FALSE (Redirecting->exists (" /a" ));
3560+ EXPECT_FALSE (Redirecting->exists (" /b" ));
3561+ EXPECT_TRUE (Redirecting->exists (" /vfile" ));
3562+ }
0 commit comments