diff --git a/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h b/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h --- a/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h +++ b/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include #include #include @@ -101,7 +102,7 @@ /// Returns nullptr if \param Path doesn't exist or isn't a directory. /// Returns nullptr if OS kernel API told us we can't start watching. In such /// case it's unclear whether just retrying has any chance to succeeed. - static std::unique_ptr + static llvm::Expected> create(llvm::StringRef Path, std::function Events, bool IsInitial)> diff --git a/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp b/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp --- a/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp +++ b/clang/lib/DirectoryWatcher/default/DirectoryWatcher-not-implemented.cpp @@ -11,9 +11,11 @@ using namespace llvm; using namespace clang; -std::unique_ptr clang::DirectoryWatcher::create( +llvm::Expected> clang::DirectoryWatcher::create( StringRef Path, std::function, bool)> Receiver, bool WaitForInitialSync) { - return nullptr; + return llvm::make_error( + "DirectoryWatcher is not implemented for this platform!", + llvm::inconvertibleErrorCode()); } \ No newline at end of file diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp --- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp +++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Path.h" #include @@ -321,16 +322,19 @@ } // namespace -std::unique_ptr clang::DirectoryWatcher::create( +llvm::Expected> clang::DirectoryWatcher::create( StringRef Path, std::function, bool)> Receiver, bool WaitForInitialSync) { if (Path.empty()) - return nullptr; + return llvm::make_error( + std::string("Path.empty() error: "), llvm::inconvertibleErrorCode()); const int InotifyFD = inotify_init1(IN_CLOEXEC); if (InotifyFD == -1) - return nullptr; + return llvm::make_error( + std::string("inotify_init1() error: ") + strerror(errno), + llvm::inconvertibleErrorCode()); const int InotifyWD = inotify_add_watch( InotifyFD, Path.str().c_str(), @@ -341,12 +345,16 @@ #endif ); if (InotifyWD == -1) - return nullptr; + return llvm::make_error( + std::string("inotify_add_watch() error: ") + strerror(errno), + llvm::inconvertibleErrorCode()); auto InotifyPollingStopper = SemaphorePipe::create(); if (!InotifyPollingStopper) - return nullptr; + return llvm::make_error( + std::string("SemaphorePipe::create() error: ") + strerror(errno), + llvm::inconvertibleErrorCode()); return llvm::make_unique( Path, Receiver, WaitForInitialSync, InotifyFD, InotifyWD, diff --git a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp --- a/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp +++ b/clang/lib/DirectoryWatcher/mac/DirectoryWatcher-mac.cpp @@ -11,16 +11,13 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include using namespace llvm; using namespace clang; -static FSEventStreamRef createFSEventStream( - StringRef Path, - std::function, bool)>, - dispatch_queue_t); static void stopFSEventStream(FSEventStreamRef); namespace { @@ -131,12 +128,13 @@ } } -FSEventStreamRef createFSEventStream( +llvm::Expected createFSEventStream( StringRef Path, std::function, bool)> Receiver, dispatch_queue_t Queue) { if (Path.empty()) - return nullptr; + return llvm::make_error( + std::string("Path.empty() error: "), llvm::inconvertibleErrorCode()); CFMutableArrayRef PathsToWatch = [&]() { CFMutableArrayRef PathsToWatch = @@ -187,7 +185,7 @@ FSEventStreamRelease(EventStream); } -std::unique_ptr clang::DirectoryWatcher::create( +llvm::Expected> clang::DirectoryWatcher::create( StringRef Path, std::function, bool)> Receiver, bool WaitForInitialSync) { @@ -195,12 +193,14 @@ dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL); if (Path.empty()) - return nullptr; + return llvm::make_error( + std::string("Path.empty() error: "), llvm::inconvertibleErrorCode()); + + auto EventStreamOrErr = createFSEventStream(Path, Receiver, Queue); + if (!EventStreamOrErr) + return EventStreamOrErr.takeError(); + auto EventStream = EventStreamOrErr.get(); - auto EventStream = createFSEventStream(Path, Receiver, Queue); - if (!EventStream) { - return nullptr; - } std::unique_ptr Result = llvm::make_unique(EventStream, Receiver, Path); diff --git a/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp b/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp --- a/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp +++ b/clang/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp @@ -280,6 +280,7 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/true); + if (!DW) return; checkEventualResultWithTimeout(TestConsumer); } @@ -311,6 +312,7 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/false); + if (!DW) return; checkEventualResultWithTimeout(TestConsumer); } @@ -331,6 +333,7 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/true); + if (!DW) return; fixture.addFile("a"); fixture.addFile("b"); @@ -356,6 +359,7 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/true); + if (!DW) return; // modify the file { @@ -386,6 +390,7 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/true); + if (!DW) return; fixture.deleteFile("a"); @@ -407,6 +412,7 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/true); + if (!DW) return; remove_directories(fixture.TestWatchedDir); @@ -427,7 +433,8 @@ TestConsumer.consume(Events, IsInitial); }, /*waitForInitialSync=*/true); + if (!DW) return; } // DW is destructed here. checkEventualResultWithTimeout(TestConsumer); } \ No newline at end of file