/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Basic/FileEntry.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- clang/Basic/FileEntry.h - File references ----------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | /// |
9 | | /// \file |
10 | | /// Defines interfaces for clang::FileEntry and clang::FileEntryRef. |
11 | | /// |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #ifndef LLVM_CLANG_BASIC_FILEENTRY_H |
15 | | #define LLVM_CLANG_BASIC_FILEENTRY_H |
16 | | |
17 | | #include "clang/Basic/DirectoryEntry.h" |
18 | | #include "clang/Basic/LLVM.h" |
19 | | #include "llvm/ADT/DenseMapInfo.h" |
20 | | #include "llvm/ADT/Hashing.h" |
21 | | #include "llvm/ADT/PointerUnion.h" |
22 | | #include "llvm/ADT/StringMap.h" |
23 | | #include "llvm/ADT/StringRef.h" |
24 | | #include "llvm/Support/ErrorOr.h" |
25 | | #include "llvm/Support/FileSystem/UniqueID.h" |
26 | | |
27 | | namespace llvm { |
28 | | |
29 | | class MemoryBuffer; |
30 | | |
31 | | namespace vfs { |
32 | | |
33 | | class File; |
34 | | |
35 | | } // namespace vfs |
36 | | } // namespace llvm |
37 | | |
38 | | namespace clang { |
39 | | |
40 | | class FileEntryRef; |
41 | | |
42 | | } // namespace clang |
43 | | |
44 | | namespace llvm { |
45 | | namespace optional_detail { |
46 | | |
47 | | /// Forward declare a template specialization for OptionalStorage. |
48 | | template <> |
49 | | class OptionalStorage<clang::FileEntryRef, /*is_trivially_copyable*/ true>; |
50 | | |
51 | | } // namespace optional_detail |
52 | | } // namespace llvm |
53 | | |
54 | | namespace clang { |
55 | | |
56 | | class FileEntry; |
57 | | |
58 | | /// A reference to a \c FileEntry that includes the name of the file as it was |
59 | | /// accessed by the FileManager's client. |
60 | | class FileEntryRef { |
61 | | public: |
62 | 122M | StringRef getName() const { return ME->first(); } |
63 | 39.2M | const FileEntry &getFileEntry() const { |
64 | 39.2M | return *ME->second->V.get<FileEntry *>(); |
65 | 39.2M | } |
66 | 19.6k | DirectoryEntryRef getDir() const { return *ME->second->Dir; } |
67 | | |
68 | | inline off_t getSize() const; |
69 | | inline unsigned getUID() const; |
70 | | inline const llvm::sys::fs::UniqueID &getUniqueID() const; |
71 | | inline time_t getModificationTime() const; |
72 | | inline bool isNamedPipe() const; |
73 | | inline void closeFile() const; |
74 | | |
75 | | /// Check if the underlying FileEntry is the same, intentially ignoring |
76 | | /// whether the file was referenced with the same spelling of the filename. |
77 | 50 | friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) { |
78 | 50 | return &LHS.getFileEntry() == &RHS.getFileEntry(); |
79 | 50 | } |
80 | | friend bool operator==(const FileEntry *LHS, const FileEntryRef &RHS) { |
81 | | return LHS == &RHS.getFileEntry(); |
82 | | } |
83 | | friend bool operator==(const FileEntryRef &LHS, const FileEntry *RHS) { |
84 | | return &LHS.getFileEntry() == RHS; |
85 | | } |
86 | | friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) { |
87 | | return !(LHS == RHS); |
88 | | } |
89 | | friend bool operator!=(const FileEntry *LHS, const FileEntryRef &RHS) { |
90 | | return !(LHS == RHS); |
91 | | } |
92 | | friend bool operator!=(const FileEntryRef &LHS, const FileEntry *RHS) { |
93 | | return !(LHS == RHS); |
94 | | } |
95 | | |
96 | | /// Hash code is based on the FileEntry, not the specific named reference, |
97 | | /// just like operator==. |
98 | 65 | friend llvm::hash_code hash_value(FileEntryRef Ref) { |
99 | 65 | return llvm::hash_value(&Ref.getFileEntry()); |
100 | 65 | } |
101 | | |
102 | | struct MapValue; |
103 | | |
104 | | /// Type used in the StringMap. |
105 | | using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>; |
106 | | |
107 | | /// Type stored in the StringMap. |
108 | | struct MapValue { |
109 | | /// The pointer at another MapEntry is used when the FileManager should |
110 | | /// silently forward from one name to another, which occurs in Redirecting |
111 | | /// VFSs that use external names. In that case, the \c FileEntryRef |
112 | | /// returned by the \c FileManager will have the external name, and not the |
113 | | /// name that was used to lookup the file. |
114 | | /// |
115 | | /// The second type is really a `const MapEntry *`, but that confuses |
116 | | /// gcc5.3. Once that's no longer supported, change this back. |
117 | | llvm::PointerUnion<FileEntry *, const void *> V; |
118 | | |
119 | | /// Directory the file was found in. Set if and only if V is a FileEntry. |
120 | | Optional<DirectoryEntryRef> Dir; |
121 | | |
122 | | MapValue() = delete; |
123 | 2.76M | MapValue(FileEntry &FE, DirectoryEntryRef Dir) : V(&FE), Dir(Dir) {} |
124 | 374 | MapValue(MapEntry &ME) : V(&ME) {} |
125 | | }; |
126 | | |
127 | | /// Check if RHS referenced the file in exactly the same way. |
128 | 1.47k | bool isSameRef(const FileEntryRef &RHS) const { return ME == RHS.ME; } |
129 | | |
130 | | /// Allow FileEntryRef to degrade into 'const FileEntry*' to facilitate |
131 | | /// incremental adoption. |
132 | | /// |
133 | | /// The goal is to avoid code churn due to dances like the following: |
134 | | /// \code |
135 | | /// // Old code. |
136 | | /// lvalue = rvalue; |
137 | | /// |
138 | | /// // Temporary code from an incremental patch. |
139 | | /// lvalue = &rvalue.getFileEntry(); |
140 | | /// |
141 | | /// // Final code. |
142 | | /// lvalue = rvalue; |
143 | | /// \endcode |
144 | | /// |
145 | | /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and |
146 | | /// FileEntry::getName have been deleted, delete this implicit conversion. |
147 | 11.0M | operator const FileEntry *() const { return &getFileEntry(); } |
148 | | |
149 | | FileEntryRef() = delete; |
150 | 10.6M | explicit FileEntryRef(const MapEntry &ME) : ME(&ME) { |
151 | 10.6M | assert(ME.second && "Expected payload"); |
152 | 0 | assert(ME.second->V && "Expected non-null"); |
153 | 0 | assert(ME.second->V.is<FileEntry *>() && "Expected FileEntry"); |
154 | 10.6M | } |
155 | | |
156 | | /// Expose the underlying MapEntry to simplify packing in a PointerIntPair or |
157 | | /// PointerUnion and allow construction in Optional. |
158 | 1.11M | const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; } |
159 | | |
160 | | private: |
161 | | friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>; |
162 | | struct optional_none_tag {}; |
163 | | |
164 | | // Private constructor for use by OptionalStorage. |
165 | 11.1M | FileEntryRef(optional_none_tag) : ME(nullptr) {} |
166 | 197M | bool hasOptionalValue() const { return ME; } |
167 | | |
168 | | friend struct llvm::DenseMapInfo<FileEntryRef>; |
169 | | struct dense_map_empty_tag {}; |
170 | | struct dense_map_tombstone_tag {}; |
171 | | |
172 | | // Private constructors for use by DenseMapInfo. |
173 | | FileEntryRef(dense_map_empty_tag) |
174 | 370 | : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {} |
175 | | FileEntryRef(dense_map_tombstone_tag) |
176 | 274 | : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {} |
177 | 290 | bool isSpecialDenseMapKey() const { |
178 | 290 | return isSameRef(FileEntryRef(dense_map_empty_tag())) || |
179 | 290 | isSameRef(FileEntryRef(dense_map_tombstone_tag()))215 ; |
180 | 290 | } |
181 | | |
182 | | const MapEntry *ME; |
183 | | }; |
184 | | |
185 | | static_assert(sizeof(FileEntryRef) == sizeof(const FileEntry *), |
186 | | "FileEntryRef must avoid size overhead"); |
187 | | |
188 | | static_assert(std::is_trivially_copyable<FileEntryRef>::value, |
189 | | "FileEntryRef must be trivially copyable"); |
190 | | |
191 | | } // end namespace clang |
192 | | |
193 | | namespace llvm { |
194 | | namespace optional_detail { |
195 | | |
196 | | /// Customize OptionalStorage<FileEntryRef> to use FileEntryRef and its |
197 | | /// optional_none_tag to keep it the size of a single pointer. |
198 | | template <> |
199 | | class OptionalStorage<clang::FileEntryRef> |
200 | | : public clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef> { |
201 | | using StorageImpl = |
202 | | clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef>; |
203 | | |
204 | | public: |
205 | 11.1M | OptionalStorage() = default; |
206 | | |
207 | | template <class... ArgTypes> |
208 | | explicit OptionalStorage(in_place_t, ArgTypes &&...Args) |
209 | 11.1M | : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {} llvm::optional_detail::OptionalStorage<clang::FileEntryRef, true>::OptionalStorage<clang::FileEntryRef>(llvm::in_place_t, clang::FileEntryRef&&) Line | Count | Source | 209 | 4.21M | : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {} |
llvm::optional_detail::OptionalStorage<clang::FileEntryRef, true>::OptionalStorage<clang::FileEntryRef const&>(llvm::in_place_t, clang::FileEntryRef const&) Line | Count | Source | 209 | 6.94M | : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {} |
|
210 | | |
211 | 2.79M | OptionalStorage &operator=(clang::FileEntryRef Ref) { |
212 | 2.79M | StorageImpl::operator=(Ref); |
213 | 2.79M | return *this; |
214 | 2.79M | } |
215 | | }; |
216 | | |
217 | | static_assert(sizeof(Optional<clang::FileEntryRef>) == |
218 | | sizeof(clang::FileEntryRef), |
219 | | "Optional<FileEntryRef> must avoid size overhead"); |
220 | | |
221 | | static_assert(std::is_trivially_copyable<Optional<clang::FileEntryRef>>::value, |
222 | | "Optional<FileEntryRef> should be trivially copyable"); |
223 | | |
224 | | } // end namespace optional_detail |
225 | | |
226 | | /// Specialisation of DenseMapInfo for FileEntryRef. |
227 | | template <> struct DenseMapInfo<clang::FileEntryRef> { |
228 | 80 | static inline clang::FileEntryRef getEmptyKey() { |
229 | 80 | return clang::FileEntryRef(clang::FileEntryRef::dense_map_empty_tag()); |
230 | 80 | } |
231 | | |
232 | 59 | static inline clang::FileEntryRef getTombstoneKey() { |
233 | 59 | return clang::FileEntryRef(clang::FileEntryRef::dense_map_tombstone_tag()); |
234 | 59 | } |
235 | | |
236 | 36 | static unsigned getHashValue(clang::FileEntryRef Val) { |
237 | 36 | return hash_value(Val); |
238 | 36 | } |
239 | | |
240 | 952 | static bool isEqual(clang::FileEntryRef LHS, clang::FileEntryRef RHS) { |
241 | | // Catch the easy cases: both empty, both tombstone, or the same ref. |
242 | 952 | if (LHS.isSameRef(RHS)) |
243 | 807 | return true; |
244 | | |
245 | | // Confirm LHS and RHS are valid. |
246 | 145 | if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey()) |
247 | 137 | return false; |
248 | | |
249 | | // It's safe to use operator==. |
250 | 8 | return LHS == RHS; |
251 | 145 | } |
252 | | }; |
253 | | |
254 | | } // end namespace llvm |
255 | | |
256 | | namespace clang { |
257 | | |
258 | | /// Wrapper around Optional<FileEntryRef> that degrades to 'const FileEntry*', |
259 | | /// facilitating incremental patches to propagate FileEntryRef. |
260 | | /// |
261 | | /// This class can be used as return value or field where it's convenient for |
262 | | /// an Optional<FileEntryRef> to degrade to a 'const FileEntry*'. The purpose |
263 | | /// is to avoid code churn due to dances like the following: |
264 | | /// \code |
265 | | /// // Old code. |
266 | | /// lvalue = rvalue; |
267 | | /// |
268 | | /// // Temporary code from an incremental patch. |
269 | | /// Optional<FileEntryRef> MaybeF = rvalue; |
270 | | /// lvalue = MaybeF ? &MaybeF.getFileEntry() : nullptr; |
271 | | /// |
272 | | /// // Final code. |
273 | | /// lvalue = rvalue; |
274 | | /// \endcode |
275 | | /// |
276 | | /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and |
277 | | /// FileEntry::getName have been deleted, delete this class and replace |
278 | | /// instances with Optional<FileEntryRef>. |
279 | | class OptionalFileEntryRefDegradesToFileEntryPtr |
280 | | : public Optional<FileEntryRef> { |
281 | | public: |
282 | 53.4k | OptionalFileEntryRefDegradesToFileEntryPtr() = default; |
283 | | OptionalFileEntryRefDegradesToFileEntryPtr( |
284 | | OptionalFileEntryRefDegradesToFileEntryPtr &&) = default; |
285 | | OptionalFileEntryRefDegradesToFileEntryPtr( |
286 | | const OptionalFileEntryRefDegradesToFileEntryPtr &) = default; |
287 | | OptionalFileEntryRefDegradesToFileEntryPtr & |
288 | | operator=(OptionalFileEntryRefDegradesToFileEntryPtr &&) = default; |
289 | | OptionalFileEntryRefDegradesToFileEntryPtr & |
290 | | operator=(const OptionalFileEntryRefDegradesToFileEntryPtr &) = default; |
291 | | |
292 | 1.11M | OptionalFileEntryRefDegradesToFileEntryPtr(llvm::NoneType) {} |
293 | | OptionalFileEntryRefDegradesToFileEntryPtr(FileEntryRef Ref) |
294 | 2.61M | : Optional<FileEntryRef>(Ref) {} |
295 | | OptionalFileEntryRefDegradesToFileEntryPtr(Optional<FileEntryRef> MaybeRef) |
296 | 2.76M | : Optional<FileEntryRef>(MaybeRef) {} |
297 | | |
298 | 0 | OptionalFileEntryRefDegradesToFileEntryPtr &operator=(llvm::NoneType) { |
299 | 0 | Optional<FileEntryRef>::operator=(None); |
300 | 0 | return *this; |
301 | 0 | } |
302 | 237 | OptionalFileEntryRefDegradesToFileEntryPtr &operator=(FileEntryRef Ref) { |
303 | 237 | Optional<FileEntryRef>::operator=(Ref); |
304 | 237 | return *this; |
305 | 237 | } |
306 | | OptionalFileEntryRefDegradesToFileEntryPtr & |
307 | 232 | operator=(Optional<FileEntryRef> MaybeRef) { |
308 | 232 | Optional<FileEntryRef>::operator=(MaybeRef); |
309 | 232 | return *this; |
310 | 232 | } |
311 | | |
312 | | /// Degrade to 'const FileEntry *' to allow FileEntry::LastRef and |
313 | | /// FileEntry::getName have been deleted, delete this class and replace |
314 | | /// instances with Optional<FileEntryRef> |
315 | 2.08M | operator const FileEntry *() const { |
316 | 2.08M | return has_value() ? &value().getFileEntry()2.07M : nullptr14.8k ; |
317 | 2.08M | } |
318 | | }; |
319 | | |
320 | | static_assert( |
321 | | std::is_trivially_copyable< |
322 | | OptionalFileEntryRefDegradesToFileEntryPtr>::value, |
323 | | "OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable"); |
324 | | |
325 | | /// Cached information about one file (either on disk |
326 | | /// or in the virtual file system). |
327 | | /// |
328 | | /// If the 'File' member is valid, then this FileEntry has an open file |
329 | | /// descriptor for the file. |
330 | | class FileEntry { |
331 | | friend class FileManager; |
332 | | friend class FileEntryTestHelper; |
333 | | FileEntry(); |
334 | | FileEntry(const FileEntry &) = delete; |
335 | | FileEntry &operator=(const FileEntry &) = delete; |
336 | | |
337 | | std::string RealPathName; // Real path to the file; could be empty. |
338 | | off_t Size = 0; // File size in bytes. |
339 | | time_t ModTime = 0; // Modification time of file. |
340 | | const DirectoryEntry *Dir = nullptr; // Directory file lives in. |
341 | | llvm::sys::fs::UniqueID UniqueID; |
342 | | unsigned UID = 0; // A unique (small) ID for the file. |
343 | | bool IsNamedPipe = false; |
344 | | |
345 | | /// The open file, if it is owned by the \p FileEntry. |
346 | | mutable std::unique_ptr<llvm::vfs::File> File; |
347 | | |
348 | | /// The file content, if it is owned by the \p FileEntry. |
349 | | std::unique_ptr<llvm::MemoryBuffer> Content; |
350 | | |
351 | | // First access name for this FileEntry. |
352 | | // |
353 | | // This is Optional only to allow delayed construction (FileEntryRef has no |
354 | | // default constructor). It should always have a value in practice. |
355 | | // |
356 | | // TODO: remove this once everyone that needs a name uses FileEntryRef. |
357 | | Optional<FileEntryRef> LastRef; |
358 | | |
359 | | public: |
360 | | ~FileEntry(); |
361 | 119M | StringRef getName() const { return LastRef->getName(); } |
362 | 920k | FileEntryRef getLastRef() const { return *LastRef; } |
363 | | |
364 | 5.03M | StringRef tryGetRealPathName() const { return RealPathName; } |
365 | 15.4M | off_t getSize() const { return Size; } |
366 | 28.5M | unsigned getUID() const { return UID; } |
367 | 26.7k | const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; } |
368 | 12.8M | time_t getModificationTime() const { return ModTime; } |
369 | | |
370 | | /// Return the directory the file lives in. |
371 | 2.95M | const DirectoryEntry *getDir() const { return Dir; } |
372 | | |
373 | | /// Check whether the file is a named pipe (and thus can't be opened by |
374 | | /// the native FileManager methods). |
375 | 4.86M | bool isNamedPipe() const { return IsNamedPipe; } |
376 | | |
377 | | void closeFile() const; |
378 | | }; |
379 | | |
380 | 1.12M | off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); } |
381 | | |
382 | | unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); } |
383 | | |
384 | 0 | const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const { |
385 | 0 | return getFileEntry().getUniqueID(); |
386 | 0 | } |
387 | | |
388 | 1.11M | time_t FileEntryRef::getModificationTime() const { |
389 | 1.11M | return getFileEntry().getModificationTime(); |
390 | 1.11M | } |
391 | | |
392 | 1.20M | bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); } |
393 | | |
394 | 4.32k | void FileEntryRef::closeFile() const { getFileEntry().closeFile(); } |
395 | | |
396 | | } // end namespace clang |
397 | | |
398 | | #endif // LLVM_CLANG_BASIC_FILEENTRY_H |