From: Eugene Zelenko Date: Wed, 28 Mar 2018 22:09:09 +0000 (+0000) Subject: [Basic] Fix some Clang-tidy modernize and Include What You Use warnings; other minor... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4654818441b2653140055e9f2726cdb30c20eecd;p=clang [Basic] Fix some Clang-tidy modernize and Include What You Use warnings; other minor fixes (NFC). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@328735 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/AddressSpaces.h b/include/clang/Basic/AddressSpaces.h index 67019f6925..286b0330f4 100644 --- a/include/clang/Basic/AddressSpaces.h +++ b/include/clang/Basic/AddressSpaces.h @@ -1,4 +1,4 @@ -//===--- AddressSpaces.h - Language-specific address spaces -----*- C++ -*-===// +//===- AddressSpaces.h - Language-specific address spaces -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,17 +6,17 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Provides definitions for the various language-specific address /// spaces. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H #define LLVM_CLANG_BASIC_ADDRESSSPACES_H -#include +#include namespace clang { @@ -51,7 +51,7 @@ enum class LangAS : unsigned { /// The type of a lookup table which maps from language-specific address spaces /// to target-specific ones. -typedef unsigned LangASMap[(unsigned)LangAS::FirstTargetAddressSpace]; +using LangASMap = unsigned[(unsigned)LangAS::FirstTargetAddressSpace]; /// \return whether \p AS is a target-specific address space rather than a /// clang AST address space @@ -71,4 +71,4 @@ inline LangAS getLangASFromTargetAS(unsigned TargetAS) { } // namespace clang -#endif +#endif // LLVM_CLANG_BASIC_ADDRESSSPACES_H diff --git a/include/clang/Basic/CommentOptions.h b/include/clang/Basic/CommentOptions.h index 92419f91b7..efd94e6e35 100644 --- a/include/clang/Basic/CommentOptions.h +++ b/include/clang/Basic/CommentOptions.h @@ -1,4 +1,4 @@ -//===--- CommentOptions.h - Options for parsing comments -----*- C++ -*-===// +//===- CommentOptions.h - Options for parsing comments ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::CommentOptions interface. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_COMMENTOPTIONS_H @@ -22,18 +22,18 @@ namespace clang { /// \brief Options for controlling comment parsing. struct CommentOptions { - typedef std::vector BlockCommandNamesTy; + using BlockCommandNamesTy = std::vector; /// \brief Command names to treat as block commands in comments. /// Should not include the leading backslash. BlockCommandNamesTy BlockCommandNames; /// \brief Treat ordinary comments as documentation comments. - bool ParseAllComments; + bool ParseAllComments = false; - CommentOptions() : ParseAllComments(false) { } + CommentOptions() = default; }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_BASIC_COMMENTOPTIONS_H diff --git a/include/clang/Basic/FileSystemStatCache.h b/include/clang/Basic/FileSystemStatCache.h index 75f986b59b..7bd2267232 100644 --- a/include/clang/Basic/FileSystemStatCache.h +++ b/include/clang/Basic/FileSystemStatCache.h @@ -1,4 +1,4 @@ -//===--- FileSystemStatCache.h - Caching for 'stat' calls -------*- C++ -*-===// +//===- FileSystemStatCache.h - Caching for 'stat' calls ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the FileSystemStatCache interface. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_FILESYSTEMSTATCACHE_H @@ -17,29 +17,38 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/FileSystem.h" +#include +#include #include +#include +#include namespace clang { namespace vfs { + class File; class FileSystem; -} + +} // namespace vfs // FIXME: should probably replace this with vfs::Status struct FileData { std::string Name; - uint64_t Size; - time_t ModTime; + uint64_t Size = 0; + time_t ModTime = 0; llvm::sys::fs::UniqueID UniqueID; - bool IsDirectory; - bool IsNamedPipe; - bool InPCH; - bool IsVFSMapped; // FIXME: remove this when files support multiple names - FileData() - : Size(0), ModTime(0), IsDirectory(false), IsNamedPipe(false), - InPCH(false), IsVFSMapped(false) {} + bool IsDirectory = false; + bool IsNamedPipe = false; + bool InPCH = false; + + // FIXME: remove this when files support multiple names + bool IsVFSMapped = false; + + FileData() = default; }; /// \brief Abstract interface for introducing a FileManager cache for 'stat' @@ -47,15 +56,19 @@ struct FileData { /// improve performance. class FileSystemStatCache { virtual void anchor(); + protected: std::unique_ptr NextStatCache; public: - virtual ~FileSystemStatCache() {} + virtual ~FileSystemStatCache() = default; enum LookupResult { - CacheExists, ///< We know the file exists and its cached stat data. - CacheMissing ///< We know that the file doesn't exist. + /// We know the file exists and its cached stat data. + CacheExists, + + /// We know that the file doesn't exist. + CacheMissing }; /// \brief Get the 'stat' information for the specified path, using the cache @@ -115,8 +128,8 @@ public: /// \brief The set of stat() calls that have been seen. llvm::StringMap StatCalls; - typedef llvm::StringMap::const_iterator - iterator; + using iterator = + llvm::StringMap::const_iterator; iterator begin() const { return StatCalls.begin(); } iterator end() const { return StatCalls.end(); } @@ -126,6 +139,6 @@ public: vfs::FileSystem &FS) override; }; -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_BASIC_FILESYSTEMSTATCACHE_H diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h index 6ec8763f24..adf1d08954 100644 --- a/include/clang/Basic/Linkage.h +++ b/include/clang/Basic/Linkage.h @@ -1,4 +1,4 @@ -//===--- Linkage.h - Linkage enumeration and utilities ----------*- C++ -*-===// +//===- Linkage.h - Linkage enumeration and utilities ------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,16 +6,15 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the Linkage enumeration and various utility functions. -/// +// //===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_BASIC_LINKAGE_H #define LLVM_CLANG_BASIC_LINKAGE_H -#include -#include #include namespace clang { @@ -125,6 +124,6 @@ inline Linkage minLinkage(Linkage L1, Linkage L2) { return L1 < L2 ? L1 : L2; } -} // end namespace clang +} // namespace clang #endif // LLVM_CLANG_BASIC_LINKAGE_H diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h index 3926c0c9b7..c41803c3bb 100644 --- a/include/clang/Basic/ObjCRuntime.h +++ b/include/clang/Basic/ObjCRuntime.h @@ -1,4 +1,4 @@ -//===--- ObjCRuntime.h - Objective-C Runtime Configuration ------*- C++ -*-===// +//===- ObjCRuntime.h - Objective-C Runtime Configuration --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,18 +6,21 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines types useful for describing an Objective-C runtime. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_OBJCRUNTIME_H #define LLVM_CLANG_BASIC_OBJCRUNTIME_H +#include "clang/Basic/LLVM.h" #include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" +#include namespace clang { @@ -57,15 +60,14 @@ public: }; private: - Kind TheKind; + Kind TheKind = MacOSX; VersionTuple Version; public: /// A bogus initialization of the runtime. - ObjCRuntime() : TheKind(MacOSX) {} - + ObjCRuntime() = default; ObjCRuntime(Kind kind, const VersionTuple &version) - : TheKind(kind), Version(version) {} + : TheKind(kind), Version(version) {} void set(Kind kind, VersionTuple version) { TheKind = kind; @@ -182,9 +184,8 @@ public: return true; case GNUstep: return getVersion() >= VersionTuple(1, 7); - default: - return false; + return false; } } @@ -320,7 +321,6 @@ public: return getVersion() >= VersionTuple(2); case GNUstep: return false; - default: return false; } @@ -360,6 +360,6 @@ public: raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_BASIC_OBJCRUNTIME_H diff --git a/include/clang/Basic/Sanitizers.h b/include/clang/Basic/Sanitizers.h index 1b936c7d11..fad22b2a75 100644 --- a/include/clang/Basic/Sanitizers.h +++ b/include/clang/Basic/Sanitizers.h @@ -1,4 +1,4 @@ -//===--- Sanitizers.h - C Language Family Language Options ------*- C++ -*-===// +//===- Sanitizers.h - C Language Family Language Options --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -6,10 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// +// /// \file /// \brief Defines the clang::SanitizerKind enum. -/// +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_SANITIZERS_H @@ -18,10 +18,12 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MathExtras.h" +#include +#include namespace clang { -typedef uint64_t SanitizerMask; +using SanitizerMask = uint64_t; namespace SanitizerKind { @@ -43,7 +45,7 @@ enum SanitizerOrdinal : uint64_t { const SanitizerMask ID##Group = 1ULL << SO_##ID##Group; #include "clang/Basic/Sanitizers.def" -} +} // namespace SanitizerKind struct SanitizerSet { /// \brief Check if a certain (single) sanitizer is enabled. @@ -85,6 +87,6 @@ inline SanitizerMask getPPTransparentSanitizers() { SanitizerKind::Nullability | SanitizerKind::Undefined; } -} // end namespace clang +} // namespace clang -#endif +#endif // LLVM_CLANG_BASIC_SANITIZERS_H diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h index 245452dd12..ec7cd6f5e8 100644 --- a/include/clang/Basic/VirtualFileSystem.h +++ b/include/clang/Basic/VirtualFileSystem.h @@ -6,8 +6,10 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// /// \file /// \brief Defines the virtual file system interface vfs::FileSystem. +// //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H @@ -15,6 +17,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -23,8 +26,6 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/raw_ostream.h" -#include #include #include #include @@ -39,7 +40,7 @@ namespace llvm { class MemoryBuffer; -} // end namespace llvm +} // namespace llvm namespace clang { namespace vfs { @@ -52,14 +53,14 @@ class Status { uint32_t User; uint32_t Group; uint64_t Size; - llvm::sys::fs::file_type Type; + llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::status_error; llvm::sys::fs::perms Perms; public: - bool IsVFSMapped; // FIXME: remove when files support multiple names + // FIXME: remove when files support multiple names + bool IsVFSMapped = false; -public: - Status() : Type(llvm::sys::fs::file_type::status_error) {} + Status() = default; Status(const llvm::sys::fs::file_status &Status); Status(StringRef Name, llvm::sys::fs::UniqueID UID, llvm::sys::TimePoint<> MTime, uint32_t User, uint32_t Group, @@ -139,7 +140,7 @@ struct DirIterImpl { Status CurrentEntry; }; -} // end namespace detail +} // namespace detail /// \brief An input iterator over the entries in a virtual path, similar to /// llvm::sys::fs::directory_iterator. @@ -184,8 +185,8 @@ class FileSystem; /// \brief An input iterator over the recursive contents of a virtual path, /// similar to llvm::sys::fs::recursive_directory_iterator. class recursive_directory_iterator { - typedef std::stack> - IterState; + using IterState = + std::stack>; FileSystem *FS; std::shared_ptr State; // Input iterator semantics on copy. @@ -193,6 +194,7 @@ class recursive_directory_iterator { public: recursive_directory_iterator(FileSystem &FS, const Twine &Path, std::error_code &EC); + /// \brief Construct an 'end' iterator. recursive_directory_iterator() = default; @@ -211,7 +213,7 @@ public: /// \brief Gets the current level. Starting path is at level 0. int level() const { - assert(State->size() && "Cannot get level without any iteration state"); + assert(!State->empty() && "Cannot get level without any iteration state"); return State->size()-1; } }; @@ -223,6 +225,7 @@ public: /// \brief Get the status of the entry at \p Path, if one exists. virtual llvm::ErrorOr status(const Twine &Path) = 0; + /// \brief Get a \p File object for the file at \p Path, if one exists. virtual llvm::ErrorOr> openFileForRead(const Twine &Path) = 0; @@ -241,6 +244,7 @@ public: /// Set the working directory. This will affect all following operations on /// this file system and may propagate down for nested file systems. virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0; + /// Get the working directory of this file system. virtual llvm::ErrorOr getCurrentWorkingDirectory() const = 0; @@ -276,13 +280,15 @@ IntrusiveRefCntPtr getRealFileSystem(); /// that exists in more than one file system, the file in the top-most file /// system overrides the other(s). class OverlayFileSystem : public FileSystem { - typedef SmallVector, 1> FileSystemList; + using FileSystemList = SmallVector, 1>; + /// \brief The stack of file systems, implemented as a list in order of /// their addition. FileSystemList FSList; public: OverlayFileSystem(IntrusiveRefCntPtr Base); + /// \brief Pushes a file system on top of the stack. void pushOverlay(IntrusiveRefCntPtr FS); @@ -293,7 +299,7 @@ public: llvm::ErrorOr getCurrentWorkingDirectory() const override; std::error_code setCurrentWorkingDirectory(const Twine &Path) override; - typedef FileSystemList::reverse_iterator iterator; + using iterator = FileSystemList::reverse_iterator; /// \brief Get an iterator pointing to the most recently added file system. iterator overlays_begin() { return FSList.rbegin(); } @@ -307,7 +313,7 @@ namespace detail { class InMemoryDirectory; -} // end namespace detail +} // namespace detail /// An in-memory file system. class InMemoryFileSystem : public FileSystem { @@ -330,6 +336,7 @@ public: Optional User = None, Optional Group = None, Optional Type = None, Optional Perms = None); + /// Add a buffer to the VFS with a path. The VFS does not own the buffer. /// If present, User, Group, Type and Perms apply to the newly-created file /// or directory. @@ -344,6 +351,7 @@ public: Optional Perms = None); std::string toString() const; + /// Return true if this file system normalizes . and .. in paths. bool useNormalizedPaths() const { return UseNormalizedPaths; } @@ -351,9 +359,11 @@ public: llvm::ErrorOr> openFileForRead(const Twine &Path) override; directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + llvm::ErrorOr getCurrentWorkingDirectory() const override { return WorkingDirectory; } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; }; @@ -419,7 +429,7 @@ public: void write(llvm::raw_ostream &OS); }; -} // end namespace vfs -} // end namespace clang +} // namespace vfs +} // namespace clang #endif // LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp index 799df1d3c3..ebee32670e 100644 --- a/lib/Basic/FileSystemStatCache.cpp +++ b/lib/Basic/FileSystemStatCache.cpp @@ -1,4 +1,4 @@ -//===--- FileSystemStatCache.cpp - Caching for 'stat' calls ---------------===// +//===- FileSystemStatCache.cpp - Caching for 'stat' calls -----------------===// // // The LLVM Compiler Infrastructure // @@ -13,11 +13,14 @@ #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/VirtualFileSystem.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/Path.h" +#include using namespace clang; -void FileSystemStatCache::anchor() { } +void FileSystemStatCache::anchor() {} static void copyStatusToFileData(const vfs::Status &Status, FileData &Data) { diff --git a/lib/Basic/ObjCRuntime.cpp b/lib/Basic/ObjCRuntime.cpp index 133c66945d..15f38d1156 100644 --- a/lib/Basic/ObjCRuntime.cpp +++ b/lib/Basic/ObjCRuntime.cpp @@ -1,4 +1,4 @@ -//===- ObjCRuntime.cpp - Objective-C Runtime Handling -----------*- C++ -*-===// +//===- ObjCRuntime.cpp - Objective-C Runtime Handling ---------------------===// // // The LLVM Compiler Infrastructure // @@ -11,8 +11,13 @@ // target Objective-C runtime. // //===----------------------------------------------------------------------===// + #include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" +#include +#include using namespace clang; diff --git a/lib/Basic/Sanitizers.cpp b/lib/Basic/Sanitizers.cpp index 91b6b2dc74..8faf17b8f2 100644 --- a/lib/Basic/Sanitizers.cpp +++ b/lib/Basic/Sanitizers.cpp @@ -1,4 +1,4 @@ -//===--- Sanitizers.cpp - C Language Family Language Options ----*- C++ -*-===// +//===- Sanitizers.cpp - C Language Family Language Options ----------------===// // // The LLVM Compiler Infrastructure // @@ -10,9 +10,8 @@ // This file defines the classes from Sanitizers.h // //===----------------------------------------------------------------------===// + #include "clang/Basic/Sanitizers.h" -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp index e95b32a22d..a854576959 100644 --- a/lib/Basic/VirtualFileSystem.cpp +++ b/lib/Basic/VirtualFileSystem.cpp @@ -1,4 +1,4 @@ -//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===// +//===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===// // // The LLVM Compiler Infrastructure // @@ -6,30 +6,57 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// // This file implements the VirtualFileSystem interface. +// //===----------------------------------------------------------------------===// #include "clang/Basic/VirtualFileSystem.h" -#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Chrono.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/Support/raw_ostream.h" +#include #include +#include +#include +#include +#include +#include #include +#include +#include #include +#include using namespace clang; -using namespace clang::vfs; +using namespace vfs; using namespace llvm; + using llvm::sys::fs::file_status; using llvm::sys::fs::file_type; using llvm::sys::fs::perms; @@ -38,13 +65,13 @@ using llvm::sys::fs::UniqueID; Status::Status(const file_status &Status) : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()), User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()), - Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {} + Type(Status.type()), Perms(Status.permissions()) {} Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime, uint32_t User, uint32_t Group, uint64_t Size, file_type Type, perms Perms) : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size), - Type(Type), Perms(Perms), IsVFSMapped(false) {} + Type(Type), Perms(Perms) {} Status Status::copyWithNewName(const Status &In, StringRef NewName) { return Status(NewName, In.getUniqueID(), In.getLastModificationTime(), @@ -62,28 +89,34 @@ bool Status::equivalent(const Status &Other) const { assert(isStatusKnown() && Other.isStatusKnown()); return getUniqueID() == Other.getUniqueID(); } + bool Status::isDirectory() const { return Type == file_type::directory_file; } + bool Status::isRegularFile() const { return Type == file_type::regular_file; } + bool Status::isOther() const { return exists() && !isRegularFile() && !isDirectory() && !isSymlink(); } + bool Status::isSymlink() const { return Type == file_type::symlink_file; } + bool Status::isStatusKnown() const { return Type != file_type::status_error; } + bool Status::exists() const { return isStatusKnown() && Type != file_type::file_not_found; } -File::~File() {} +File::~File() = default; -FileSystem::~FileSystem() {} +FileSystem::~FileSystem() = default; ErrorOr> FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, @@ -97,7 +130,7 @@ FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, std::error_code FileSystem::makeAbsolute(SmallVectorImpl &Path) const { if (llvm::sys::path::is_absolute(Path)) - return std::error_code(); + return {}; auto WorkingDir = getCurrentWorkingDirectory(); if (!WorkingDir) @@ -118,6 +151,7 @@ static bool isTraversalComponent(StringRef Component) { static bool pathHasTraversal(StringRef Path) { using namespace llvm::sys; + for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) if (isTraversalComponent(Comp)) return true; @@ -130,12 +164,15 @@ static bool pathHasTraversal(StringRef Path) { //===-----------------------------------------------------------------------===/ namespace { + /// \brief Wrapper around a raw file descriptor. class RealFile : public File { + friend class RealFileSystem; + int FD; Status S; std::string RealName; - friend class RealFileSystem; + RealFile(int FD, StringRef NewName, StringRef NewRealPathName) : FD(FD), S(NewName, {}, {}, {}, {}, {}, llvm::sys::fs::file_type::status_error, {}), @@ -145,6 +182,7 @@ class RealFile : public File { public: ~RealFile() override; + ErrorOr status() override; ErrorOr getName() override; ErrorOr> getBuffer(const Twine &Name, @@ -153,7 +191,9 @@ public: bool IsVolatile) override; std::error_code close() override; }; -} // end anonymous namespace + +} // namespace + RealFile::~RealFile() { close(); } ErrorOr RealFile::status() { @@ -186,6 +226,7 @@ std::error_code RealFile::close() { } namespace { + /// \brief The file system according to your operating system. class RealFileSystem : public FileSystem { public: @@ -196,7 +237,8 @@ public: llvm::ErrorOr getCurrentWorkingDirectory() const override; std::error_code setCurrentWorkingDirectory(const Twine &Path) override; }; -} // end anonymous namespace + +} // namespace ErrorOr RealFileSystem::status(const Twine &Path) { sys::fs::file_status RealStatus; @@ -238,8 +280,10 @@ IntrusiveRefCntPtr vfs::getRealFileSystem() { } namespace { + class RealFSDirIter : public clang::vfs::detail::DirIterImpl { llvm::sys::fs::directory_iterator Iter; + public: RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) { if (!EC && Iter != llvm::sys::fs::directory_iterator()) { @@ -264,7 +308,8 @@ public: return EC; } }; -} + +} // namespace directory_iterator RealFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { @@ -274,6 +319,7 @@ directory_iterator RealFileSystem::dir_begin(const Twine &Dir, //===-----------------------------------------------------------------------===/ // OverlayFileSystem implementation //===-----------------------------------------------------------------------===/ + OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr BaseFS) { FSList.push_back(std::move(BaseFS)); } @@ -311,17 +357,19 @@ OverlayFileSystem::getCurrentWorkingDirectory() const { // All file systems are synchronized, just take the first working directory. return FSList.front()->getCurrentWorkingDirectory(); } + std::error_code OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) { for (auto &FS : FSList) if (std::error_code EC = FS->setCurrentWorkingDirectory(Path)) return EC; - return std::error_code(); + return {}; } -clang::vfs::detail::DirIterImpl::~DirIterImpl() { } +clang::vfs::detail::DirIterImpl::~DirIterImpl() = default; namespace { + class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl { OverlayFileSystem &Overlays; std::string Path; @@ -340,7 +388,7 @@ class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl { if (CurrentDirIter != directory_iterator()) break; // found } - return std::error_code(); + return {}; } std::error_code incrementDirIter(bool IsFirstTime) { @@ -379,7 +427,8 @@ public: std::error_code increment() override { return incrementImpl(false); } }; -} // end anonymous namespace + +} // namespace directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { @@ -389,6 +438,7 @@ directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, namespace clang { namespace vfs { + namespace detail { enum InMemoryNodeKind { IME_File, IME_Directory }; @@ -402,13 +452,15 @@ class InMemoryNode { public: InMemoryNode(Status Stat, InMemoryNodeKind Kind) : Stat(std::move(Stat)), Kind(Kind) {} - virtual ~InMemoryNode() {} + virtual ~InMemoryNode() = default; + const Status &getStatus() const { return Stat; } InMemoryNodeKind getKind() const { return Kind; } virtual std::string toString(unsigned Indent) const = 0; }; namespace { + class InMemoryFile : public InMemoryNode { std::unique_ptr Buffer; @@ -417,9 +469,11 @@ public: : InMemoryNode(std::move(Stat), IME_File), Buffer(std::move(Buffer)) {} llvm::MemoryBuffer *getBuffer() { return Buffer.get(); } + std::string toString(unsigned Indent) const override { return (std::string(Indent, ' ') + getStatus().getName() + "\n").str(); } + static bool classof(const InMemoryNode *N) { return N->getKind() == IME_File; } @@ -433,6 +487,7 @@ public: explicit InMemoryFileAdaptor(InMemoryFile &Node) : Node(Node) {} llvm::ErrorOr status() override { return Node.getStatus(); } + llvm::ErrorOr> getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) override { @@ -440,9 +495,11 @@ public: return llvm::MemoryBuffer::getMemBuffer( Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator); } - std::error_code close() override { return std::error_code(); } + + std::error_code close() override { return {}; } }; -} // end anonymous namespace + +} // namespace class InMemoryDirectory : public InMemoryNode { std::map> Entries; @@ -450,34 +507,38 @@ class InMemoryDirectory : public InMemoryNode { public: InMemoryDirectory(Status Stat) : InMemoryNode(std::move(Stat), IME_Directory) {} + InMemoryNode *getChild(StringRef Name) { auto I = Entries.find(Name); if (I != Entries.end()) return I->second.get(); return nullptr; } + InMemoryNode *addChild(StringRef Name, std::unique_ptr Child) { return Entries.insert(make_pair(Name, std::move(Child))) .first->second.get(); } - typedef decltype(Entries)::const_iterator const_iterator; + using const_iterator = decltype(Entries)::const_iterator; + const_iterator begin() const { return Entries.begin(); } const_iterator end() const { return Entries.end(); } std::string toString(unsigned Indent) const override { std::string Result = (std::string(Indent, ' ') + getStatus().getName() + "\n").str(); - for (const auto &Entry : Entries) { + for (const auto &Entry : Entries) Result += Entry.second->toString(Indent + 2); - } return Result; } + static bool classof(const InMemoryNode *N) { return N->getKind() == IME_Directory; } }; -} + +} // namespace detail InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) : Root(new detail::InMemoryDirectory( @@ -486,7 +547,7 @@ InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) llvm::sys::fs::perms::all_all))), UseNormalizedPaths(UseNormalizedPaths) {} -InMemoryFileSystem::~InMemoryFileSystem() {} +InMemoryFileSystem::~InMemoryFileSystem() = default; std::string InMemoryFileSystem::toString() const { return Root->toString(/*Indent=*/0); @@ -645,13 +706,15 @@ InMemoryFileSystem::openFileForRead(const Twine &Path) { } namespace { + /// Adaptor from InMemoryDir::iterator to directory_iterator. class InMemoryDirIterator : public clang::vfs::detail::DirIterImpl { detail::InMemoryDirectory::const_iterator I; detail::InMemoryDirectory::const_iterator E; public: - InMemoryDirIterator() {} + InMemoryDirIterator() = default; + explicit InMemoryDirIterator(detail::InMemoryDirectory &Dir) : I(Dir.begin()), E(Dir.end()) { if (I != E) @@ -663,10 +726,11 @@ public: // When we're at the end, make CurrentEntry invalid and DirIterImpl will do // the rest. CurrentEntry = I != E ? I->second->getStatus() : Status(); - return std::error_code(); + return {}; } }; -} // end anonymous namespace + +} // namespace directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { @@ -697,11 +761,12 @@ std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) { if (!Path.empty()) WorkingDirectory = Path.str(); - return std::error_code(); -} -} + return {}; } +} // namespace vfs +} // namespace clang + //===-----------------------------------------------------------------------===/ // RedirectingFileSystem implementation //===-----------------------------------------------------------------------===/ @@ -719,8 +784,9 @@ class Entry { std::string Name; public: - virtual ~Entry(); Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} + virtual ~Entry() = default; + StringRef getName() const { return Name; } EntryKind getKind() const { return Kind; } }; @@ -737,14 +803,20 @@ public: S(std::move(S)) {} RedirectingDirectoryEntry(StringRef Name, Status S) : Entry(EK_Directory, Name), S(std::move(S)) {} + Status getStatus() { return S; } + void addContent(std::unique_ptr Content) { Contents.push_back(std::move(Content)); } + Entry *getLastContent() const { return Contents.back().get(); } - typedef decltype(Contents)::iterator iterator; + + using iterator = decltype(Contents)::iterator; + iterator contents_begin() { return Contents.begin(); } iterator contents_end() { return Contents.end(); } + static bool classof(const Entry *E) { return E->getKind() == EK_Directory; } }; @@ -755,21 +827,27 @@ public: NK_External, NK_Virtual }; + private: std::string ExternalContentsPath; NameKind UseName; + public: RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName) : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath), UseName(UseName) {} + StringRef getExternalContentsPath() const { return ExternalContentsPath; } + /// \brief whether to use the external path as the name for this file. bool useExternalName(bool GlobalUseExternalName) const { return UseName == NK_NotSet ? GlobalUseExternalName : (UseName == NK_External); } + NameKind getUseName() const { return UseName; } + static bool classof(const Entry *E) { return E->getKind() == EK_File; } }; @@ -785,6 +863,7 @@ public: RedirectingDirectoryEntry::iterator Begin, RedirectingDirectoryEntry::iterator End, std::error_code &EC); + std::error_code increment() override; }; @@ -844,10 +923,14 @@ public: /// /path/to/file). However, any directory that contains more than one child /// must be uniquely represented by a directory entry. class RedirectingFileSystem : public vfs::FileSystem { + friend class RedirectingFileSystemParser; + /// The root(s) of the virtual file system. std::vector> Roots; + /// \brief The file system to use for external references. IntrusiveRefCntPtr ExternalFS; + /// If IsRelativeOverlay is set, this represents the directory /// path that should be prefixed to each 'external-contents' entry /// when reading from YAML files. @@ -888,8 +971,6 @@ class RedirectingFileSystem : public vfs::FileSystem { true; #endif - friend class RedirectingFileSystemParser; - private: RedirectingFileSystem(IntrusiveRefCntPtr ExternalFS) : ExternalFS(std::move(ExternalFS)) {} @@ -919,6 +1000,7 @@ public: llvm::ErrorOr getCurrentWorkingDirectory() const override { return ExternalFS->getCurrentWorkingDirectory(); } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { return ExternalFS->setCurrentWorkingDirectory(Path); } @@ -927,17 +1009,17 @@ public: ErrorOr E = lookupPath(Dir); if (!E) { EC = E.getError(); - return directory_iterator(); + return {}; } ErrorOr S = status(Dir, *E); if (!S) { EC = S.getError(); - return directory_iterator(); + return {}; } if (!S->isDirectory()) { EC = std::error_code(static_cast(errc::not_a_directory), std::system_category()); - return directory_iterator(); + return {}; } auto *D = cast(*E); @@ -959,7 +1041,7 @@ public: #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { - for (const std::unique_ptr &Root : Roots) + for (const auto &Root : Roots) dumpEntry(Root.get()); } @@ -979,7 +1061,6 @@ LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const { } } #endif - }; /// \brief A helper class to hold the common YAML parsing state. @@ -993,7 +1074,8 @@ class RedirectingFileSystemParser { // false on error bool parseScalarString(yaml::Node *N, StringRef &Result, SmallVectorImpl &Storage) { - yaml::ScalarNode *S = dyn_cast(N); + const auto *S = dyn_cast(N); + if (!S) { error(N, "expected string"); return false; @@ -1024,11 +1106,13 @@ class RedirectingFileSystemParser { } struct KeyStatus { - KeyStatus(bool Required=false) : Required(Required), Seen(false) {} bool Required; - bool Seen; + bool Seen = false; + + KeyStatus(bool Required = false) : Required(Required) {} }; - typedef std::pair KeyStatusPair; + + using KeyStatusPair = std::pair; // false on error bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key, @@ -1048,11 +1132,9 @@ class RedirectingFileSystemParser { // false on error bool checkMissingKeys(yaml::Node *Obj, DenseMap &Keys) { - for (DenseMap::iterator I = Keys.begin(), - E = Keys.end(); - I != E; ++I) { - if (I->second.Required && !I->second.Seen) { - error(Obj, Twine("missing key '") + I->first + "'"); + for (const auto &I : Keys) { + if (I.second.Required && !I.second.Seen) { + error(Obj, Twine("missing key '") + I.first + "'"); return false; } } @@ -1062,7 +1144,7 @@ class RedirectingFileSystemParser { Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, Entry *ParentEntry = nullptr) { if (!ParentEntry) { // Look for a existent root - for (const std::unique_ptr &Root : FS->Roots) { + for (const auto &Root : FS->Roots) { if (Name.equals(Root->getName())) { ParentEntry = Root.get(); return ParentEntry; @@ -1125,7 +1207,7 @@ class RedirectingFileSystemParser { } std::unique_ptr parseEntry(yaml::Node *N, RedirectingFileSystem *FS) { - yaml::MappingNode *M = dyn_cast(N); + auto *M = dyn_cast(N); if (!M) { error(N, "expected mapping node for file or directory entry"); return nullptr; @@ -1148,21 +1230,20 @@ class RedirectingFileSystemParser { auto UseExternalName = RedirectingFileEntry::NK_NotSet; EntryKind Kind; - for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E; - ++I) { + for (auto &I : *M) { StringRef Key; // Reuse the buffer for key and value, since we don't look at key after // parsing value. SmallString<256> Buffer; - if (!parseScalarString(I->getKey(), Key, Buffer)) + if (!parseScalarString(I.getKey(), Key, Buffer)) return nullptr; - if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys)) + if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys)) return nullptr; StringRef Value; if (Key == "name") { - if (!parseScalarString(I->getValue(), Value, Buffer)) + if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; if (FS->UseCanonicalizedPaths) { @@ -1176,47 +1257,44 @@ class RedirectingFileSystemParser { Name = Value; } } else if (Key == "type") { - if (!parseScalarString(I->getValue(), Value, Buffer)) + if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; if (Value == "file") Kind = EK_File; else if (Value == "directory") Kind = EK_Directory; else { - error(I->getValue(), "unknown value for 'type'"); + error(I.getValue(), "unknown value for 'type'"); return nullptr; } } else if (Key == "contents") { if (HasContents) { - error(I->getKey(), + error(I.getKey(), "entry already has 'contents' or 'external-contents'"); return nullptr; } HasContents = true; - yaml::SequenceNode *Contents = - dyn_cast(I->getValue()); + auto *Contents = dyn_cast(I.getValue()); if (!Contents) { // FIXME: this is only for directories, what about files? - error(I->getValue(), "expected array"); + error(I.getValue(), "expected array"); return nullptr; } - for (yaml::SequenceNode::iterator I = Contents->begin(), - E = Contents->end(); - I != E; ++I) { - if (std::unique_ptr E = parseEntry(&*I, FS)) + for (auto &I : *Contents) { + if (std::unique_ptr E = parseEntry(&I, FS)) EntryArrayContents.push_back(std::move(E)); else return nullptr; } } else if (Key == "external-contents") { if (HasContents) { - error(I->getKey(), + error(I.getKey(), "entry already has 'contents' or 'external-contents'"); return nullptr; } HasContents = true; - if (!parseScalarString(I->getValue(), Value, Buffer)) + if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; SmallString<256> FullPath; @@ -1238,7 +1316,7 @@ class RedirectingFileSystemParser { ExternalContentsPath = FullPath.str(); } else if (Key == "use-external-name") { bool Val; - if (!parseScalarBool(I->getValue(), Val)) + if (!parseScalarBool(I.getValue(), Val)) return nullptr; UseExternalName = Val ? RedirectingFileEntry::NK_External : RedirectingFileEntry::NK_Virtual; @@ -1311,7 +1389,7 @@ public: // false on error bool parse(yaml::Node *Root, RedirectingFileSystem *FS) { - yaml::MappingNode *Top = dyn_cast(Root); + auto *Top = dyn_cast(Root); if (!Top) { error(Root, "expected mapping node"); return false; @@ -1330,26 +1408,24 @@ public: std::vector> RootEntries; // Parse configuration and 'roots' - for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E; - ++I) { + for (auto &I : *Top) { SmallString<10> KeyBuffer; StringRef Key; - if (!parseScalarString(I->getKey(), Key, KeyBuffer)) + if (!parseScalarString(I.getKey(), Key, KeyBuffer)) return false; - if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys)) + if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys)) return false; if (Key == "roots") { - yaml::SequenceNode *Roots = dyn_cast(I->getValue()); + auto *Roots = dyn_cast(I.getValue()); if (!Roots) { - error(I->getValue(), "expected array"); + error(I.getValue(), "expected array"); return false; } - for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end(); - I != E; ++I) { - if (std::unique_ptr E = parseEntry(&*I, FS)) + for (auto &I : *Roots) { + if (std::unique_ptr E = parseEntry(&I, FS)) RootEntries.push_back(std::move(E)); else return false; @@ -1357,32 +1433,32 @@ public: } else if (Key == "version") { StringRef VersionString; SmallString<4> Storage; - if (!parseScalarString(I->getValue(), VersionString, Storage)) + if (!parseScalarString(I.getValue(), VersionString, Storage)) return false; int Version; if (VersionString.getAsInteger(10, Version)) { - error(I->getValue(), "expected integer"); + error(I.getValue(), "expected integer"); return false; } if (Version < 0) { - error(I->getValue(), "invalid version number"); + error(I.getValue(), "invalid version number"); return false; } if (Version != 0) { - error(I->getValue(), "version mismatch, expected 0"); + error(I.getValue(), "version mismatch, expected 0"); return false; } } else if (Key == "case-sensitive") { - if (!parseScalarBool(I->getValue(), FS->CaseSensitive)) + if (!parseScalarBool(I.getValue(), FS->CaseSensitive)) return false; } else if (Key == "overlay-relative") { - if (!parseScalarBool(I->getValue(), FS->IsRelativeOverlay)) + if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay)) return false; } else if (Key == "use-external-names") { - if (!parseScalarBool(I->getValue(), FS->UseExternalNames)) + if (!parseScalarBool(I.getValue(), FS->UseExternalNames)) return false; } else if (Key == "ignore-non-existent-contents") { - if (!parseScalarBool(I->getValue(), FS->IgnoreNonExistentContents)) + if (!parseScalarBool(I.getValue(), FS->IgnoreNonExistentContents)) return false; } else { llvm_unreachable("key missing from Keys"); @@ -1398,22 +1474,20 @@ public: // Now that we sucessefully parsed the YAML file, canonicalize the internal // representation to a proper directory tree so that we can search faster // inside the VFS. - for (std::unique_ptr &E : RootEntries) + for (auto &E : RootEntries) uniqueOverlayTree(FS, E.get()); return true; } }; -} // end of anonymous namespace -Entry::~Entry() = default; +} // namespace RedirectingFileSystem * RedirectingFileSystem::create(std::unique_ptr Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr ExternalFS) { - SourceMgr SM; yaml::Stream Stream(Buffer->getMemBufferRef(), SM); @@ -1473,7 +1547,7 @@ ErrorOr RedirectingFileSystem::lookupPath(const Twine &Path_) { sys::path::const_iterator Start = sys::path::begin(Path); sys::path::const_iterator End = sys::path::end(Path); - for (const std::unique_ptr &Root : Roots) { + for (const auto &Root : Roots) { ErrorOr Result = lookupPath(Start, End, Root.get()); if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) return Result; @@ -1557,6 +1631,7 @@ ErrorOr RedirectingFileSystem::status(const Twine &Path) { } namespace { + /// Provide a file wrapper with an overriden status. class FileWithFixedStatus : public File { std::unique_ptr InnerFile; @@ -1568,14 +1643,17 @@ public: ErrorOr status() override { return S; } ErrorOr> + getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) override { return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); } + std::error_code close() override { return InnerFile->close(); } }; -} // end anonymous namespace + +} // namespace ErrorOr> RedirectingFileSystem::openFileForRead(const Twine &Path) { @@ -1670,11 +1748,13 @@ void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { } namespace { + class JSONWriter { llvm::raw_ostream &OS; SmallVector DirStack; - inline unsigned getDirIndent() { return 4 * DirStack.size(); } - inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); } + + unsigned getDirIndent() { return 4 * DirStack.size(); } + unsigned getFileIndent() { return 4 * (DirStack.size() + 1); } bool containedIn(StringRef Parent, StringRef Path); StringRef containedPart(StringRef Parent, StringRef Path); void startDirectory(StringRef Path); @@ -1683,14 +1763,17 @@ class JSONWriter { public: JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} + void write(ArrayRef Entries, Optional UseExternalNames, Optional IsCaseSensitive, Optional IsOverlayRelative, Optional IgnoreNonExistentContents, StringRef OverlayDir); }; -} + +} // namespace bool JSONWriter::containedIn(StringRef Parent, StringRef Path) { using namespace llvm::sys; + // Compare each path component. auto IParent = path::begin(Parent), EParent = path::end(Parent); for (auto IChild = path::begin(Path), EChild = path::end(Path); @@ -1868,7 +1951,7 @@ std::error_code VFSFromYamlDirIterImpl::increment() { if (Current == End) CurrentEntry = Status(); - return std::error_code(); + return {}; } vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,