diff --git a/include/clang/DirectoryWatcher/DirectoryWatcher.h b/include/clang/DirectoryWatcher/DirectoryWatcher.h index 2739955a113..a96b09ad1e4 100644 --- a/include/clang/DirectoryWatcher/DirectoryWatcher.h +++ b/include/clang/DirectoryWatcher/DirectoryWatcher.h @@ -1,13 +1,9 @@ //===- DirectoryWatcher.h - Listens for directory file changes --*- C++ -*-===// // -// The LLVM Compiler Infrastructure +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// \file -/// \brief Utility class for listening for file system changes in a directory. //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H @@ -41,7 +37,6 @@ class DirectoryWatcher { struct Event { EventKind Kind; std::string Filename; - llvm::sys::TimePoint<> ModTime; }; typedef std::function Events, bool isInitial)> EventReceiver; @@ -64,4 +59,4 @@ class DirectoryWatcher { } // namespace clang -#endif +#endif // LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H diff --git a/lib/DirectoryWatcher/CMakeLists.txt b/lib/DirectoryWatcher/CMakeLists.txt index 5b506166b7a..4b5ddb364b0 100644 --- a/lib/DirectoryWatcher/CMakeLists.txt +++ b/lib/DirectoryWatcher/CMakeLists.txt @@ -6,13 +6,29 @@ add_clang_library(clangDirectoryWatcher DirectoryWatcher.cpp ) -if(BUILD_SHARED_LIBS) - if(APPLE) - check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES_H) - if(HAVE_CORESERVICES_H) - set(DIRECTORY_WATCHER_FLAGS "${DIRECTORY_WATCHER_FLAGS} -framework CoreServices") - endif() +if(APPLE) + check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES) + if(HAVE_CORESERVICES) + set(DIRECTORY_WATCHER_FLAGS "${DIRECTORY_WATCHER_FLAGS} -framework CoreServices") set_property(TARGET clangDirectoryWatcher APPEND_STRING PROPERTY - LINK_FLAGS ${DIRECTORY_WATCHER_FLAGS}) + LINK_FLAGS ${DIRECTORY_WATCHER_FLAGS}) endif() +elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") + check_include_files("sys/inotify.h" HAVE_INOTIFY) endif() + +llvm_canonicalize_cmake_booleans( + HAVE_CORESERVICES) +llvm_canonicalize_cmake_booleans( + HAVE_INOTIFY) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/Config.inc.in + ${CMAKE_CURRENT_BINARY_DIR}/Config.inc +) + +if(BUILD_SHARED_LIBS AND APPLE AND HAVE_CORESERVICES) + set(DIRECTORY_WATCHER_FLAGS "${DIRECTORY_WATCHER_FLAGS} -framework CoreServices") + set_property(TARGET clangDirectoryWatcher APPEND_STRING PROPERTY + LINK_FLAGS ${DIRECTORY_WATCHER_FLAGS}) +endif() \ No newline at end of file diff --git a/lib/DirectoryWatcher/Config.inc.in b/lib/DirectoryWatcher/Config.inc.in new file mode 100644 index 00000000000..e01bbf4ca88 --- /dev/null +++ b/lib/DirectoryWatcher/Config.inc.in @@ -0,0 +1,2 @@ +#define HAVE_CORESERVICES @HAVE_CORESERVICES@ +#define HAVE_INOTIFY @HAVE_INOTIFY@ \ No newline at end of file diff --git a/lib/DirectoryWatcher/DirectoryWatcher-linux.inc.h b/lib/DirectoryWatcher/DirectoryWatcher-linux.inc.h index ddb492ab2ff..53ad9d05c1d 100644 --- a/lib/DirectoryWatcher/DirectoryWatcher-linux.inc.h +++ b/lib/DirectoryWatcher/DirectoryWatcher-linux.inc.h @@ -1,18 +1,17 @@ //===- DirectoryWatcher-linux.inc.h - Linux-platform directory listening --===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/Support/Errno.h" -#include "llvm/Support/Path.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/Path.h" +#include #include #include -#include namespace { @@ -29,9 +28,7 @@ class EventQueue { std::vector PendingEvents; DirectoryWatcher::Event toDirEvent(const INotifyEvent &evt) { - llvm::sys::TimePoint<> modTime{}; - if (evt.Status.hasValue()) modTime = evt.Status->getLastModificationTime(); - return DirectoryWatcher::Event{evt.K, evt.Filename, modTime}; + return DirectoryWatcher::Event{evt.K, evt.Filename}; } public: @@ -76,14 +73,12 @@ class EventQueue { PendingEvents.clear(); } }; -} // namespace +} // namespace struct DirectoryWatcher::Implementation { - bool initialize(StringRef Path, EventReceiver Receiver, - bool waitInitialSync, std::string &Error); - ~Implementation() { - stopListening(); - }; + bool initialize(StringRef Path, EventReceiver Receiver, bool waitInitialSync, + std::string &Error); + ~Implementation() { stopListening(); }; private: int inotifyFD = -1; @@ -93,18 +88,19 @@ struct DirectoryWatcher::Implementation { static void runWatcher(std::string pathToWatch, int inotifyFD, std::shared_ptr evtQueue) { - #define EVT_BUF_LEN (30 * (sizeof(struct inotify_event) + NAME_MAX + 1)) - char buf[EVT_BUF_LEN] __attribute__ ((aligned(8))); + constexpr size_t EventBufferLength = + 30 * (sizeof(struct inotify_event) + NAME_MAX + 1); + char buf[EventBufferLength] __attribute__((aligned(8))); while (1) { - ssize_t numRead = read(inotifyFD, buf, EVT_BUF_LEN); - if (numRead == -1) { - return; // watcher is stopped. - } + ssize_t numRead = llvm::sys::RetryAfterSignal( + -1, read, inotifyFD, reinterpret_cast(buf), EventBufferLength); SmallVector iEvents; for (char *p = buf; p < buf + numRead;) { - struct inotify_event *ievt = (struct inotify_event *)p; + assert(p + sizeof(struct inotify_event) <= buf + numRead && + "a whole inotify_event was read"); + struct inotify_event *ievt = reinterpret_cast(p); p += sizeof(struct inotify_event) + ievt->len; if (ievt->mask & IN_DELETE_SELF) { @@ -114,27 +110,21 @@ static void runWatcher(std::string pathToWatch, int inotifyFD, break; } - DirectoryWatcher::EventKind K = DirectoryWatcher::EventKind::Added; - if (ievt->mask & IN_MODIFY) { - K = DirectoryWatcher::EventKind::Modified; - } - if (ievt->mask & IN_MOVED_TO) { - K = DirectoryWatcher::EventKind::Added; - } - if (ievt->mask & IN_DELETE) { - K = DirectoryWatcher::EventKind::Removed; - } + DirectoryWatcher::EventKind K = [&ievt]() { + if (ievt->mask & IN_MODIFY) + return DirectoryWatcher::EventKind::Modified; + if (ievt->mask & IN_MOVED_TO) + return DirectoryWatcher::EventKind::Added; + if (ievt->mask & IN_DELETE) + return DirectoryWatcher::EventKind::Removed; + llvm_unreachable("Unknown event type."); + }(); assert(ievt->len > 0 && "expected a filename from inotify"); SmallString<256> fullPath{pathToWatch}; sys::path::append(fullPath, ievt->name); Optional statusOpt; - if (K != DirectoryWatcher::EventKind::Removed) { - statusOpt = getFileStatus(fullPath); - if (!statusOpt.hasValue()) - K = DirectoryWatcher::EventKind::Removed; - } INotifyEvent iEvt{K, fullPath.str(), statusOpt}; iEvents.push_back(iEvt); } @@ -155,16 +145,16 @@ bool DirectoryWatcher::Implementation::initialize(StringRef Path, return true; }; - auto evtQueue = std::make_shared(std::move(Receiver)); + auto evtQueue = std::make_shared(std::move(Receiver)); inotifyFD = inotify_init(); if (inotifyFD == -1) return error("inotify_init failed"); std::string pathToWatch = Path; - int wd = inotify_add_watch( - inotifyFD, pathToWatch.c_str(), - IN_MOVED_TO | IN_DELETE | IN_MODIFY | IN_DELETE_SELF | IN_ONLYDIR); + int wd = inotify_add_watch(inotifyFD, pathToWatch.c_str(), + IN_MOVED_TO | IN_DELETE | IN_MODIFY | + IN_DELETE_SELF | IN_ONLYDIR); if (wd == -1) return error("inotify_add_watch failed"); @@ -191,6 +181,6 @@ bool DirectoryWatcher::Implementation::initialize(StringRef Path, void DirectoryWatcher::Implementation::stopListening() { if (inotifyFD == -1) return; - close(inotifyFD); + llvm::sys::RetryAfterSignal(-1, close, inotifyFD); inotifyFD = -1; } diff --git a/lib/DirectoryWatcher/DirectoryWatcher-mac.inc.h b/lib/DirectoryWatcher/DirectoryWatcher-mac.inc.h index 826e9bea4fd..bdfb3e9a2e8 100644 --- a/lib/DirectoryWatcher/DirectoryWatcher-mac.inc.h +++ b/lib/DirectoryWatcher/DirectoryWatcher-mac.inc.h @@ -1,20 +1,18 @@ //===- DirectoryWatcher-mac.inc.h - Mac-platform directory listening ------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include struct DirectoryWatcher::Implementation { - bool initialize(StringRef Path, EventReceiver Receiver, - bool waitInitialSync, std::string &Error); - ~Implementation() { - stopFSEventStream(); - }; + bool initialize(StringRef Path, EventReceiver Receiver, bool waitInitialSync, + std::string &Error); + ~Implementation() { stopFSEventStream(); }; + private: FSEventStreamRef EventStream = nullptr; @@ -30,35 +28,34 @@ struct EventStreamContextData { DirectoryWatcher::EventReceiver Receiver; std::shared_ptr InitialScan; - EventStreamContextData(std::string watchedPath, DirectoryWatcher::EventReceiver receiver, + EventStreamContextData(std::string watchedPath, + DirectoryWatcher::EventReceiver receiver, std::shared_ptr initialScanPtr) - : WatchedPath(std::move(watchedPath)), - Receiver(std::move(receiver)), - InitialScan(std::move(initialScanPtr)) { - } + : WatchedPath(std::move(watchedPath)), Receiver(std::move(receiver)), + InitialScan(std::move(initialScanPtr)) {} static void dispose(const void *ctx) { - delete static_cast(ctx); + delete static_cast(ctx); } }; -} +} // namespace -static void eventStreamCallback( - ConstFSEventStreamRef stream, - void *clientCallBackInfo, - size_t numEvents, - void *eventPaths, - const FSEventStreamEventFlags eventFlags[], - const FSEventStreamEventId eventIds[]) { - auto *ctx = static_cast(clientCallBackInfo); +static void eventStreamCallback(ConstFSEventStreamRef stream, + void *clientCallBackInfo, size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) { + auto *ctx = static_cast(clientCallBackInfo); std::vector Events; for (size_t i = 0; i < numEvents; ++i) { StringRef path = ((const char **)eventPaths)[i]; const FSEventStreamEventFlags flags = eventFlags[i]; if (!(flags & kFSEventStreamEventFlagItemIsFile)) { - if ((flags & kFSEventStreamEventFlagItemRemoved) && path == ctx->WatchedPath) { - DirectoryWatcher::Event Evt{DirectoryWatcher::EventKind::DirectoryDeleted, path, llvm::sys::TimePoint<>{} }; + if ((flags & kFSEventStreamEventFlagItemRemoved) && + path == ctx->WatchedPath) { + DirectoryWatcher::Event Evt{ + DirectoryWatcher::EventKind::DirectoryDeleted, path}; Events.push_back(Evt); break; } @@ -98,10 +95,7 @@ static void eventStreamCallback( } } - llvm::sys::TimePoint<> modTime{}; - if (statusOpt.hasValue()) - modTime = statusOpt->getLastModificationTime(); - DirectoryWatcher::Event Evt{K, path, modTime}; + DirectoryWatcher::Event Evt{K, path}; Events.push_back(Evt); } @@ -113,15 +107,17 @@ static void eventStreamCallback( } } -bool DirectoryWatcher::Implementation::setupFSEventStream(StringRef path, - EventReceiver receiver, - dispatch_queue_t queue, - std::shared_ptr initialScanPtr) { +bool DirectoryWatcher::Implementation::setupFSEventStream( + StringRef path, EventReceiver receiver, dispatch_queue_t queue, + std::shared_ptr initialScanPtr) { if (path.empty()) return true; - CFMutableArrayRef pathsToWatch = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); - CFStringRef cfPathStr = CFStringCreateWithBytes(nullptr, (const UInt8 *)path.data(), path.size(), kCFStringEncodingUTF8, false); + CFMutableArrayRef pathsToWatch = + CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); + CFStringRef cfPathStr = + CFStringCreateWithBytes(nullptr, (const UInt8 *)path.data(), path.size(), + kCFStringEncodingUTF8, false); CFArrayAppendValue(pathsToWatch, cfPathStr); CFRelease(cfPathStr); CFAbsoluteTime latency = 0.0; // Latency in seconds. @@ -138,9 +134,8 @@ bool DirectoryWatcher::Implementation::setupFSEventStream(StringRef path, realPath = path; } - EventStreamContextData *ctxData = - new EventStreamContextData(std::move(realPath), std::move(receiver), - std::move(initialScanPtr)); + EventStreamContextData *ctxData = new EventStreamContextData( + std::move(realPath), std::move(receiver), std::move(initialScanPtr)); FSEventStreamContext context; context.version = 0; context.info = ctxData; @@ -148,14 +143,10 @@ bool DirectoryWatcher::Implementation::setupFSEventStream(StringRef path, context.release = EventStreamContextData::dispose; context.copyDescription = nullptr; - EventStream = FSEventStreamCreate(nullptr, - eventStreamCallback, - &context, - pathsToWatch, - kFSEventStreamEventIdSinceNow, - latency, - kFSEventStreamCreateFlagFileEvents | - kFSEventStreamCreateFlagNoDefer); + EventStream = FSEventStreamCreate( + nullptr, eventStreamCallback, &context, pathsToWatch, + kFSEventStreamEventIdSinceNow, latency, + kFSEventStreamCreateFlagFileEvents | kFSEventStreamCreateFlagNoDefer); CFRelease(pathsToWatch); if (!EventStream) { return true; @@ -175,10 +166,13 @@ void DirectoryWatcher::Implementation::stopFSEventStream() { } bool DirectoryWatcher::Implementation::initialize(StringRef Path, - EventReceiver Receiver, bool waitInitialSync, std::string &Error) { + EventReceiver Receiver, + bool waitInitialSync, + std::string &Error) { auto initialScan = std::make_shared(); - dispatch_queue_t queue = dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL); + dispatch_queue_t queue = + dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL); dispatch_semaphore_t initScanSema = dispatch_semaphore_create(0); dispatch_semaphore_t setupFSEventsSema = dispatch_semaphore_create(0); @@ -206,7 +200,8 @@ bool DirectoryWatcher::Implementation::initialize(StringRef Path, dispatch_release(queue); if (fsErr) { - raw_string_ostream(Error) << "failed to setup FSEvents stream for path: " << Path; + raw_string_ostream(Error) + << "failed to setup FSEvents stream for path: " << Path; return true; } diff --git a/lib/DirectoryWatcher/DirectoryWatcher.cpp b/lib/DirectoryWatcher/DirectoryWatcher.cpp index 0feaacefe7a..5b457434d64 100644 --- a/lib/DirectoryWatcher/DirectoryWatcher.cpp +++ b/lib/DirectoryWatcher/DirectoryWatcher.cpp @@ -1,9 +1,8 @@ //===- DirectoryWatcher.cpp - Listens for directory file changes ----------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// \file @@ -46,11 +45,12 @@ template <> struct DenseMapInfo { std::make_pair(val.getDevice(), val.getFile())); } - static bool isEqual(const sys::fs::UniqueID &LHS, const sys::fs::UniqueID &RHS) { + static bool isEqual(const sys::fs::UniqueID &LHS, + const sys::fs::UniqueID &RHS) { return LHS == RHS; } }; -} +} // namespace llvm namespace { /// Used for initial directory scan. @@ -65,12 +65,14 @@ struct DirectoryScan { using namespace llvm::sys; std::error_code EC; - for (auto It = fs::directory_iterator(Path, EC), End = fs::directory_iterator(); - !EC && It != End; It.increment(EC)) { + for (auto It = fs::directory_iterator(Path, EC), + End = fs::directory_iterator(); + !EC && It != End; It.increment(EC)) { auto status = getFileStatus(It->path()); if (!status.hasValue()) continue; - Files.push_back(std::make_tuple(It->path(), status->getLastModificationTime())); + Files.push_back( + std::make_tuple(It->path(), status->getLastModificationTime())); FileIDSet.insert(status->getUniqueID()); } } @@ -78,29 +80,27 @@ struct DirectoryScan { std::vector getAsFileEvents() const { std::vector Events; for (const auto &info : Files) { - DirectoryWatcher::Event Event{DirectoryWatcher::EventKind::Added, std::get<0>(info), std::get<1>(info)}; + DirectoryWatcher::Event Event{DirectoryWatcher::EventKind::Added, + std::get<0>(info)}; Events.push_back(std::move(Event)); } return Events; } }; -} +} // namespace // Add platform-specific functionality. +#include "Config.inc" -#if !defined(__has_include) -# define __has_include(x) 0 -#endif - -#if __has_include() -# include "DirectoryWatcher-mac.inc.h" -#elif __has_include() -# include "DirectoryWatcher-linux.inc.h" +#if HAVE_CORESERVICES +#include "DirectoryWatcher-mac.inc.h" +#elif HAVE_INOTIFY +#include "DirectoryWatcher-linux.inc.h" #else struct DirectoryWatcher::Implementation { - bool initialize(StringRef Path, EventReceiver Receiver, - bool waitInitialSync, std::string &Error) { + bool initialize(StringRef Path, EventReceiver Receiver, bool waitInitialSync, + std::string &Error) { Error = "directory listening not supported for this platform"; return true; } @@ -108,16 +108,13 @@ struct DirectoryWatcher::Implementation { #endif +DirectoryWatcher::DirectoryWatcher() : Impl(*new Implementation()) {} -DirectoryWatcher::DirectoryWatcher() - : Impl(*new Implementation()) {} - -DirectoryWatcher::~DirectoryWatcher() { - delete &Impl; -} +DirectoryWatcher::~DirectoryWatcher() { delete &Impl; } -std::unique_ptr DirectoryWatcher::create(StringRef Path, - EventReceiver Receiver, bool waitInitialSync, std::string &Error) { +std::unique_ptr +DirectoryWatcher::create(StringRef Path, EventReceiver Receiver, + bool waitInitialSync, std::string &Error) { using namespace llvm::sys; if (!fs::exists(Path)) { @@ -143,7 +140,8 @@ std::unique_ptr DirectoryWatcher::create(StringRef Path, std::unique_ptr DirWatch; DirWatch.reset(new DirectoryWatcher()); auto &Impl = DirWatch->Impl; - bool hasError = Impl.initialize(Path, std::move(Receiver), waitInitialSync, Error); + bool hasError = + Impl.initialize(Path, std::move(Receiver), waitInitialSync, Error); if (hasError) return nullptr; diff --git a/lib/IndexDataStore/IndexDataStore.cpp b/lib/IndexDataStore/IndexDataStore.cpp index ec7a346935c..6fdf64e9c7a 100644 --- a/lib/IndexDataStore/IndexDataStore.cpp +++ b/lib/IndexDataStore/IndexDataStore.cpp @@ -8,10 +8,11 @@ //===----------------------------------------------------------------------===// #include "clang/Index/IndexDataStore.h" -#include "clang/DirectoryWatcher/DirectoryWatcher.h" #include "../lib/Index/IndexDataStoreUtils.h" +#include "clang/DirectoryWatcher/DirectoryWatcher.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Chrono.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/Path.h" @@ -126,7 +127,8 @@ bool IndexDataStoreImpl::startEventListening(bool waitInitialSync, std::string & UnitName = StringRef(); break; } - UnitEvents.push_back(IndexDataStore::UnitEvent{K, UnitName, evt.ModTime}); + UnitEvents.push_back( + IndexDataStore::UnitEvent{K, UnitName, llvm::sys::TimePoint<>{}}); } if (auto handler = localUnitEventHandlerData->getHandler()) { diff --git a/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp b/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp index 5fec06a64d6..e7941a18eb3 100644 --- a/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp +++ b/unittests/DirectoryWatcher/DirectoryWatcherTest.cpp @@ -1,9 +1,8 @@ //===- unittests/DirectoryWatcher/DirectoryWatcherTest.cpp ----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -48,10 +47,10 @@ class EventCollection { for (unsigned i = 0, e = filenames.size(); i < e; ++i) { StringRef fname = filenames[i]; DirectoryWatcher::EventKind kind = kinds[i]; - file_status stat = stats[i]; - auto it = std::find_if(evts.begin(), evts.end(), [&](const DirectoryWatcher::Event &evt)->bool { - return path::filename(evt.Filename) == fname; - }); + auto it = std::find_if(evts.begin(), evts.end(), + [&](const DirectoryWatcher::Event &evt) -> bool { + return path::filename(evt.Filename) == fname; + }); if (it == evts.end()) { hadError = err(Twine("expected filename '"+fname+"' not found")); continue; @@ -61,9 +60,6 @@ class EventCollection { std::to_string((int)it->Kind) + ", expected ") + std::to_string((int)kind)); } - if (it->Kind != DirectoryWatcher::EventKind::Removed && - it->ModTime != stat.getLastModificationTime()) - hadError = err(Twine("filename '"+fname+"' has different mod time")); evts.erase(it); } for (const auto &evt : evts) {