Coverage Report

Created: 2018-07-22 10:17

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/include/clang/Basic/VirtualFileSystem.h
Line
Count
Source (jump to first uncovered line)
1
//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===//
2
//
3
//                     The LLVM Compiler Infrastructure
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
//
10
/// \file
11
/// Defines the virtual file system interface vfs::FileSystem.
12
//
13
//===----------------------------------------------------------------------===//
14
15
#ifndef LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H
16
#define LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H
17
18
#include "clang/Basic/LLVM.h"
19
#include "llvm/ADT/IntrusiveRefCntPtr.h"
20
#include "llvm/ADT/None.h"
21
#include "llvm/ADT/Optional.h"
22
#include "llvm/ADT/SmallVector.h"
23
#include "llvm/ADT/StringRef.h"
24
#include "llvm/ADT/Twine.h"
25
#include "llvm/Support/Chrono.h"
26
#include "llvm/Support/ErrorOr.h"
27
#include "llvm/Support/FileSystem.h"
28
#include "llvm/Support/SourceMgr.h"
29
#include <cassert>
30
#include <cstdint>
31
#include <ctime>
32
#include <memory>
33
#include <stack>
34
#include <string>
35
#include <system_error>
36
#include <utility>
37
#include <vector>
38
39
namespace llvm {
40
41
class MemoryBuffer;
42
43
} // namespace llvm
44
45
namespace clang {
46
namespace vfs {
47
48
/// The result of a \p status operation.
49
class Status {
50
  std::string Name;
51
  llvm::sys::fs::UniqueID UID;
52
  llvm::sys::TimePoint<> MTime;
53
  uint32_t User;
54
  uint32_t Group;
55
  uint64_t Size;
56
  llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::status_error;
57
  llvm::sys::fs::perms Perms;
58
59
public:
60
   // FIXME: remove when files support multiple names
61
  bool IsVFSMapped = false;
62
63
259k
  Status() = default;
64
  Status(const llvm::sys::fs::file_status &Status);
65
  Status(StringRef Name, llvm::sys::fs::UniqueID UID,
66
         llvm::sys::TimePoint<> MTime, uint32_t User, uint32_t Group,
67
         uint64_t Size, llvm::sys::fs::file_type Type,
68
         llvm::sys::fs::perms Perms);
69
70
  /// Get a copy of a Status with a different name.
71
  static Status copyWithNewName(const Status &In, StringRef NewName);
72
  static Status copyWithNewName(const llvm::sys::fs::file_status &In,
73
                                StringRef NewName);
74
75
  /// Returns the name that should be used for this file or directory.
76
1.33M
  StringRef getName() const { return Name; }
77
78
  /// @name Status interface from llvm::sys::fs
79
  /// @{
80
835k
  llvm::sys::fs::file_type getType() const { return Type; }
81
510
  llvm::sys::fs::perms getPermissions() const { return Perms; }
82
835k
  llvm::sys::TimePoint<> getLastModificationTime() const { return MTime; }
83
836k
  llvm::sys::fs::UniqueID getUniqueID() const { return UID; }
84
502
  uint32_t getUser() const { return User; }
85
502
  uint32_t getGroup() const { return Group; }
86
835k
  uint64_t getSize() const { return Size; }
87
  /// @}
88
  /// @name Status queries
89
  /// These are static queries in llvm::sys::fs.
90
  /// @{
91
  bool equivalent(const Status &Other) const;
92
  bool isDirectory() const;
93
  bool isRegularFile() const;
94
  bool isOther() const;
95
  bool isSymlink() const;
96
  bool isStatusKnown() const;
97
  bool exists() const;
98
  /// @}
99
};
100
101
/// Represents an open file.
102
class File {
103
public:
104
  /// Destroy the file after closing it (if open).
105
  /// Sub-classes should generally call close() inside their destructors.  We
106
  /// cannot do that from the base class, since close is virtual.
107
  virtual ~File();
108
109
  /// Get the status of the file.
110
  virtual llvm::ErrorOr<Status> status() = 0;
111
112
  /// Get the name of the file
113
4.53k
  virtual llvm::ErrorOr<std::string> getName() {
114
4.53k
    if (auto Status = status())
115
4.53k
      return Status->getName().str();
116
18.4E
    else
117
18.4E
      return Status.getError();
118
4.53k
  }
119
120
  /// Get the contents of the file as a \p MemoryBuffer.
121
  virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
122
  getBuffer(const Twine &Name, int64_t FileSize = -1,
123
            bool RequiresNullTerminator = true, bool IsVolatile = false) = 0;
124
125
  /// Closes the file.
126
  virtual std::error_code close() = 0;
127
};
128
129
namespace detail {
130
131
/// An interface for virtual file systems to provide an iterator over the
132
/// (non-recursive) contents of a directory.
133
struct DirIterImpl {
134
  virtual ~DirIterImpl();
135
136
  /// Sets \c CurrentEntry to the next entry in the directory on success,
137
  /// or returns a system-defined \c error_code.
138
  virtual std::error_code increment() = 0;
139
140
  Status CurrentEntry;
141
};
142
143
} // namespace detail
144
145
/// An input iterator over the entries in a virtual path, similar to
146
/// llvm::sys::fs::directory_iterator.
147
class directory_iterator {
148
  std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy
149
150
public:
151
  directory_iterator(std::shared_ptr<detail::DirIterImpl> I)
152
254k
      : Impl(std::move(I)) {
153
254k
    assert(Impl.get() != nullptr && "requires non-null implementation");
154
254k
    if (!Impl->CurrentEntry.isStatusKnown())
155
253k
      Impl.reset(); // Normalize the end iterator to Impl == nullptr.
156
254k
  }
157
158
  /// Construct an 'end' iterator.
159
256k
  directory_iterator() = default;
160
161
  /// Equivalent to operator++, with an error code.
162
6.71k
  directory_iterator &increment(std::error_code &EC) {
163
6.71k
    assert(Impl && "attempting to increment past end");
164
6.71k
    EC = Impl->increment();
165
6.71k
    if (!Impl->CurrentEntry.isStatusKnown())
166
1.66k
      Impl.reset(); // Normalize the end iterator to Impl == nullptr.
167
6.71k
    return *this;
168
6.71k
  }
169
170
2.27k
  const Status &operator*() const { return Impl->CurrentEntry; }
171
12.8k
  const Status *operator->() const { return &Impl->CurrentEntry; }
172
173
8.81k
  bool operator==(const directory_iterator &RHS) const {
174
8.81k
    if (Impl && 
RHS.Impl6.81k
)
175
0
      return Impl->CurrentEntry.equivalent(RHS.Impl->CurrentEntry);
176
8.81k
    return !Impl && 
!RHS.Impl1.99k
;
177
8.81k
  }
178
7.38k
  bool operator!=(const directory_iterator &RHS) const {
179
7.38k
    return !(*this == RHS);
180
7.38k
  }
181
};
182
183
class FileSystem;
184
185
/// An input iterator over the recursive contents of a virtual path,
186
/// similar to llvm::sys::fs::recursive_directory_iterator.
187
class recursive_directory_iterator {
188
  using IterState =
189
      std::stack<directory_iterator, std::vector<directory_iterator>>;
190
191
  FileSystem *FS;
192
  std::shared_ptr<IterState> State; // Input iterator semantics on copy.
193
194
public:
195
  recursive_directory_iterator(FileSystem &FS, const Twine &Path,
196
                               std::error_code &EC);
197
198
  /// Construct an 'end' iterator.
199
285
  recursive_directory_iterator() = default;
200
201
  /// Equivalent to operator++, with an error code.
202
  recursive_directory_iterator &increment(std::error_code &EC);
203
204
0
  const Status &operator*() const { return *State->top(); }
205
2.18k
  const Status *operator->() const { return &*State->top(); }
206
207
1.42k
  bool operator==(const recursive_directory_iterator &Other) const {
208
1.42k
    return State == Other.State; // identity
209
1.42k
  }
210
1.41k
  bool operator!=(const recursive_directory_iterator &RHS) const {
211
1.41k
    return !(*this == RHS);
212
1.41k
  }
213
214
  /// Gets the current level. Starting path is at level 0.
215
89
  int level() const {
216
89
    assert(!State->empty() && "Cannot get level without any iteration state");
217
89
    return State->size()-1;
218
89
  }
219
};
220
221
/// The virtual file system interface.
222
class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> {
223
public:
224
  virtual ~FileSystem();
225
226
  /// Get the status of the entry at \p Path, if one exists.
227
  virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0;
228
229
  /// Get a \p File object for the file at \p Path, if one exists.
230
  virtual llvm::ErrorOr<std::unique_ptr<File>>
231
  openFileForRead(const Twine &Path) = 0;
232
233
  /// This is a convenience method that opens a file, gets its content and then
234
  /// closes the file.
235
  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
236
  getBufferForFile(const Twine &Name, int64_t FileSize = -1,
237
                   bool RequiresNullTerminator = true, bool IsVolatile = false);
238
239
  /// Get a directory_iterator for \p Dir.
240
  /// \note The 'end' iterator is directory_iterator().
241
  virtual directory_iterator dir_begin(const Twine &Dir,
242
                                       std::error_code &EC) = 0;
243
244
  /// Set the working directory. This will affect all following operations on
245
  /// this file system and may propagate down for nested file systems.
246
  virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0;
247
248
  /// Get the working directory of this file system.
249
  virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0;
250
251
  /// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve
252
  /// symlinks. For real file system, this uses `llvm::sys::fs::real_path`.
253
  /// This returns errc::operation_not_permitted if not implemented by subclass.
254
  virtual std::error_code getRealPath(const Twine &Path,
255
                                      SmallVectorImpl<char> &Output) const;
256
257
  /// Check whether a file exists. Provided for convenience.
258
  bool exists(const Twine &Path);
259
260
  /// Make \a Path an absolute path.
261
  ///
262
  /// Makes \a Path absolute using the current directory if it is not already.
263
  /// An empty \a Path will result in the current directory.
264
  ///
265
  /// /absolute/path   => /absolute/path
266
  /// relative/../path => <current-directory>/relative/../path
267
  ///
268
  /// \param Path A path that is modified to be an absolute path.
269
  /// \returns success if \a path has been made absolute, otherwise a
270
  ///          platform-specific error_code.
271
  std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
272
};
273
274
/// Gets an \p vfs::FileSystem for the 'real' file system, as seen by
275
/// the operating system.
276
IntrusiveRefCntPtr<FileSystem> getRealFileSystem();
277
278
/// A file system that allows overlaying one \p AbstractFileSystem on top
279
/// of another.
280
///
281
/// Consists of a stack of >=1 \p FileSystem objects, which are treated as being
282
/// one merged file system. When there is a directory that exists in more than
283
/// one file system, the \p OverlayFileSystem contains a directory containing
284
/// the union of their contents.  The attributes (permissions, etc.) of the
285
/// top-most (most recently added) directory are used.  When there is a file
286
/// that exists in more than one file system, the file in the top-most file
287
/// system overrides the other(s).
288
class OverlayFileSystem : public FileSystem {
289
  using FileSystemList = SmallVector<IntrusiveRefCntPtr<FileSystem>, 1>;
290
291
  /// The stack of file systems, implemented as a list in order of
292
  /// their addition.
293
  FileSystemList FSList;
294
295
public:
296
  OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> Base);
297
298
  /// Pushes a file system on top of the stack.
299
  void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS);
300
301
  llvm::ErrorOr<Status> status(const Twine &Path) override;
302
  llvm::ErrorOr<std::unique_ptr<File>>
303
  openFileForRead(const Twine &Path) override;
304
  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
305
  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
306
  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
307
  std::error_code getRealPath(const Twine &Path,
308
                              SmallVectorImpl<char> &Output) const override;
309
310
  using iterator = FileSystemList::reverse_iterator;
311
  using const_iterator = FileSystemList::const_reverse_iterator;
312
313
  /// Get an iterator pointing to the most recently added file system.
314
109k
  iterator overlays_begin() { return FSList.rbegin(); }
315
0
  const_iterator overlays_begin() const { return FSList.rbegin(); }
316
317
  /// Get an iterator pointing one-past the least recently added file
318
  /// system.
319
109k
  iterator overlays_end() { return FSList.rend(); }
320
0
  const_iterator overlays_end() const { return FSList.rend(); }
321
};
322
323
namespace detail {
324
325
class InMemoryDirectory;
326
327
} // namespace detail
328
329
/// An in-memory file system.
330
class InMemoryFileSystem : public FileSystem {
331
  std::unique_ptr<detail::InMemoryDirectory> Root;
332
  std::string WorkingDirectory;
333
  bool UseNormalizedPaths = true;
334
335
public:
336
  explicit InMemoryFileSystem(bool UseNormalizedPaths = true);
337
  ~InMemoryFileSystem() override;
338
339
  /// Add a file containing a buffer or a directory to the VFS with a
340
  /// path. The VFS owns the buffer.  If present, User, Group, Type
341
  /// and Perms apply to the newly-created file or directory.
342
  /// \return true if the file or directory was successfully added,
343
  /// false if the file or directory already exists in the file system with
344
  /// different contents.
345
  bool addFile(const Twine &Path, time_t ModificationTime,
346
               std::unique_ptr<llvm::MemoryBuffer> Buffer,
347
               Optional<uint32_t> User = None, Optional<uint32_t> Group = None,
348
               Optional<llvm::sys::fs::file_type> Type = None,
349
               Optional<llvm::sys::fs::perms> Perms = None);
350
351
  /// Add a buffer to the VFS with a path. The VFS does not own the buffer.
352
  /// If present, User, Group, Type and Perms apply to the newly-created file
353
  /// or directory.
354
  /// \return true if the file or directory was successfully added,
355
  /// false if the file or directory already exists in the file system with
356
  /// different contents.
357
  bool addFileNoOwn(const Twine &Path, time_t ModificationTime,
358
                    llvm::MemoryBuffer *Buffer,
359
                    Optional<uint32_t> User = None,
360
                    Optional<uint32_t> Group = None,
361
                    Optional<llvm::sys::fs::file_type> Type = None,
362
                    Optional<llvm::sys::fs::perms> Perms = None);
363
364
  std::string toString() const;
365
366
  /// Return true if this file system normalizes . and .. in paths.
367
288k
  bool useNormalizedPaths() const { return UseNormalizedPaths; }
368
369
  llvm::ErrorOr<Status> status(const Twine &Path) override;
370
  llvm::ErrorOr<std::unique_ptr<File>>
371
  openFileForRead(const Twine &Path) override;
372
  directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
373
374
212k
  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
375
212k
    return WorkingDirectory;
376
212k
  }
377
  /// Canonicalizes \p Path by combining with the current working
378
  /// directory and normalizing the path (e.g. remove dots). If the current
379
  /// working directory is not set, this returns errc::operation_not_permitted.
380
  ///
381
  /// This doesn't resolve symlinks as they are not supported in in-memory file
382
  /// system.
383
  std::error_code getRealPath(const Twine &Path,
384
                              SmallVectorImpl<char> &Output) const override;
385
386
  std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
387
};
388
389
/// Get a globally unique ID for a virtual file or directory.
390
llvm::sys::fs::UniqueID getNextVirtualUniqueID();
391
392
/// Gets a \p FileSystem for a virtual file system described in YAML
393
/// format.
394
IntrusiveRefCntPtr<FileSystem>
395
getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer,
396
               llvm::SourceMgr::DiagHandlerTy DiagHandler,
397
               StringRef YAMLFilePath,
398
               void *DiagContext = nullptr,
399
               IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
400
401
struct YAMLVFSEntry {
402
  template <typename T1, typename T2> YAMLVFSEntry(T1 &&VPath, T2 &&RPath)
403
539
      : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
clang::vfs::YAMLVFSEntry::YAMLVFSEntry<char const*, llvm::StringRef>(char const*&&, llvm::StringRef&&)
Line
Count
Source
403
2
      : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
clang::vfs::YAMLVFSEntry::YAMLVFSEntry<llvm::StringRef&, llvm::StringRef&>(llvm::StringRef&&&, llvm::StringRef&&&)
Line
Count
Source
403
537
      : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
404
  std::string VPath;
405
  std::string RPath;
406
};
407
408
/// Collect all pairs of <virtual path, real path> entries from the
409
/// \p YAMLFilePath. This is used by the module dependency collector to forward
410
/// the entries into the reproducer output VFS YAML file.
411
void collectVFSFromYAML(
412
    std::unique_ptr<llvm::MemoryBuffer> Buffer,
413
    llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
414
    SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
415
    void *DiagContext = nullptr,
416
    IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
417
418
class YAMLVFSWriter {
419
  std::vector<YAMLVFSEntry> Mappings;
420
  Optional<bool> IsCaseSensitive;
421
  Optional<bool> IsOverlayRelative;
422
  Optional<bool> UseExternalNames;
423
  Optional<bool> IgnoreNonExistentContents;
424
  std::string OverlayDir;
425
426
public:
427
25
  YAMLVFSWriter() = default;
428
429
  void addFileMapping(StringRef VirtualPath, StringRef RealPath);
430
431
17
  void setCaseSensitivity(bool CaseSensitive) {
432
17
    IsCaseSensitive = CaseSensitive;
433
17
  }
434
435
16
  void setUseExternalNames(bool UseExtNames) {
436
16
    UseExternalNames = UseExtNames;
437
16
  }
438
439
16
  void setIgnoreNonExistentContents(bool IgnoreContents) {
440
16
    IgnoreNonExistentContents = IgnoreContents;
441
16
  }
442
443
16
  void setOverlayDir(StringRef OverlayDirectory) {
444
16
    IsOverlayRelative = true;
445
16
    OverlayDir.assign(OverlayDirectory.str());
446
16
  }
447
448
  void write(llvm::raw_ostream &OS);
449
};
450
451
} // namespace vfs
452
} // namespace clang
453
454
#endif // LLVM_CLANG_BASIC_VIRTUALFILESYSTEM_H