@@ -31,16 +31,32 @@ class File;
3131
3232namespace clang {
3333
34+ class FileEntryRef ;
35+
36+ } // namespace clang
37+
38+ namespace llvm {
39+ namespace optional_detail {
40+
41+ // / Forward declare a template specialization for OptionalStorage.
42+ template <>
43+ class OptionalStorage <clang::FileEntryRef, /* is_trivially_copyable*/ true >;
44+
45+ } // namespace optional_detail
46+ } // namespace llvm
47+
48+ namespace clang {
49+
3450class DirectoryEntry ;
3551class FileEntry ;
3652
3753// / A reference to a \c FileEntry that includes the name of the file as it was
3854// / accessed by the FileManager's client.
3955class FileEntryRef {
4056public:
41- const StringRef getName () const { return Entry ->first (); }
57+ StringRef getName () const { return ME ->first (); }
4258 const FileEntry &getFileEntry () const {
43- return *Entry ->second ->V .get <FileEntry *>();
59+ return *ME ->second ->V .get <FileEntry *>();
4460 }
4561
4662 inline bool isValid () const ;
@@ -49,12 +65,26 @@ class FileEntryRef {
4965 inline const llvm::sys::fs::UniqueID &getUniqueID () const ;
5066 inline time_t getModificationTime () const ;
5167
68+ // / Check if the underlying FileEntry is the same, intentially ignoring
69+ // / whether the file was referenced with the same spelling of the filename.
5270 friend bool operator ==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
53- return LHS.Entry == RHS.Entry ;
71+ return &LHS.getFileEntry () == &RHS.getFileEntry ();
72+ }
73+ friend bool operator ==(const FileEntry *LHS, const FileEntryRef &RHS) {
74+ return LHS == &RHS.getFileEntry ();
75+ }
76+ friend bool operator ==(const FileEntryRef &LHS, const FileEntry *RHS) {
77+ return &LHS.getFileEntry () == RHS;
5478 }
5579 friend bool operator !=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
5680 return !(LHS == RHS);
5781 }
82+ friend bool operator !=(const FileEntry *LHS, const FileEntryRef &RHS) {
83+ return !(LHS == RHS);
84+ }
85+ friend bool operator !=(const FileEntryRef &LHS, const FileEntry *RHS) {
86+ return !(LHS == RHS);
87+ }
5888
5989 struct MapValue ;
6090
@@ -78,20 +108,190 @@ class FileEntryRef {
78108 MapValue (MapEntry &ME) : V(&ME) {}
79109 };
80110
81- private:
82- friend class FileManager ;
111+ // / Check if RHS referenced the file in exactly the same way.
112+ bool isSameRef (const FileEntryRef &RHS) const { return ME == RHS.ME ; }
113+
114+ // / Allow FileEntryRef to degrade into 'const FileEntry*' to facilitate
115+ // / incremental adoption.
116+ // /
117+ // / The goal is to avoid code churn due to dances like the following:
118+ // / \code
119+ // / // Old code.
120+ // / lvalue = rvalue;
121+ // /
122+ // / // Temporary code from an incremental patch.
123+ // / lvalue = &rvalue.getFileEntry();
124+ // /
125+ // / // Final code.
126+ // / lvalue = rvalue;
127+ // / \endcode
128+ // /
129+ // / FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
130+ // / FileEntry::getName have been deleted, delete this implicit conversion.
131+ operator const FileEntry *() const { return &getFileEntry (); }
83132
84133 FileEntryRef () = delete ;
85- explicit FileEntryRef (const MapEntry &Entry)
86- : Entry(&Entry) {
87- assert (Entry.second && " Expected payload" );
88- assert (Entry.second ->V && " Expected non-null" );
89- assert (Entry.second ->V .is <FileEntry *>() && " Expected FileEntry" );
134+ explicit FileEntryRef (const MapEntry &ME) : ME(&ME) {
135+ assert (ME.second && " Expected payload" );
136+ assert (ME.second ->V && " Expected non-null" );
137+ assert (ME.second ->V .is <FileEntry *>() && " Expected FileEntry" );
138+ }
139+
140+ // / Expose the underlying MapEntry to simplify packing in a PointerIntPair or
141+ // / PointerUnion and allow construction in Optional.
142+ const clang::FileEntryRef::MapEntry &getMapEntry () const { return *ME; }
143+
144+ private:
145+ friend class llvm ::optional_detail::OptionalStorage<
146+ FileEntryRef, /* is_trivially_copyable*/ true >;
147+ struct optional_none_tag {};
148+
149+ // Private constructor for use by OptionalStorage.
150+ FileEntryRef (optional_none_tag) : ME(nullptr ) {}
151+ bool hasOptionalValue () const { return ME; }
152+
153+ const MapEntry *ME;
154+ };
155+
156+ static_assert (sizeof (FileEntryRef) == sizeof (const FileEntry *),
157+ " FileEntryRef must avoid size overhead" );
158+
159+ static_assert (std::is_trivially_copyable<FileEntryRef>::value,
160+ " FileEntryRef must be trivially copyable" );
161+
162+ } // end namespace clang
163+
164+ namespace llvm {
165+ namespace optional_detail {
166+
167+ // / Customize OptionalStorage<FileEntryRef> to use FileEntryRef and its
168+ // / optional_none_tag to keep it the size of a single pointer.
169+ template <> class OptionalStorage <clang::FileEntryRef> {
170+ clang::FileEntryRef MaybeRef = clang::FileEntryRef::optional_none_tag{};
171+
172+ public:
173+ ~OptionalStorage () = default ;
174+ constexpr OptionalStorage () noexcept = default;
175+ constexpr OptionalStorage (OptionalStorage const &Other) = default;
176+ constexpr OptionalStorage (OptionalStorage &&Other) = default;
177+ OptionalStorage &operator =(OptionalStorage const &Other) = default ;
178+ OptionalStorage &operator =(OptionalStorage &&Other) = default ;
179+
180+ template <class ... ArgTypes>
181+ constexpr explicit OptionalStorage (in_place_t , ArgTypes &&...Args)
182+ : MaybeRef(std::forward<ArgTypes>(Args)...) {}
183+
184+ void reset () noexcept { MaybeRef = clang::FileEntryRef::optional_none_tag (); }
185+
186+ constexpr bool hasValue () const noexcept {
187+ return MaybeRef.hasOptionalValue ();
188+ }
189+
190+ clang::FileEntryRef &getValue () LLVM_LVALUE_FUNCTION noexcept {
191+ assert (hasValue ());
192+ return MaybeRef;
193+ }
194+ constexpr clang::FileEntryRef const &
195+ getValue () const LLVM_LVALUE_FUNCTION noexcept {
196+ assert (hasValue ());
197+ return MaybeRef;
198+ }
199+ #if LLVM_HAS_RVALUE_REFERENCE_THIS
200+ clang::FileEntryRef &&getValue() &&noexcept {
201+ assert (hasValue ());
202+ return std::move (MaybeRef);
203+ }
204+ #endif
205+
206+ template <class ... Args> void emplace (Args &&...args) {
207+ MaybeRef = clang::FileEntryRef (std::forward<Args>(args)...);
90208 }
91209
92- const MapEntry *Entry;
210+ OptionalStorage &operator =(clang::FileEntryRef Ref) {
211+ MaybeRef = Ref;
212+ return *this ;
213+ }
93214};
94215
216+ static_assert (sizeof (Optional<clang::FileEntryRef>) ==
217+ sizeof (clang::FileEntryRef),
218+ " Optional<FileEntryRef> must avoid size overhead" );
219+
220+ static_assert (std::is_trivially_copyable<Optional<clang::FileEntryRef>>::value,
221+ " Optional<FileEntryRef> should be trivially copyable" );
222+
223+ } // end namespace optional_detail
224+ } // end namespace llvm
225+
226+ namespace clang {
227+
228+ // / Wrapper around Optional<FileEntryRef> that degrades to 'const FileEntry*',
229+ // / facilitating incremental patches to propagate FileEntryRef.
230+ // /
231+ // / This class can be used as return value or field where it's convenient for
232+ // / an Optional<FileEntryRef> to degrade to a 'const FileEntry*'. The purpose
233+ // / is to avoid code churn due to dances like the following:
234+ // / \code
235+ // / // Old code.
236+ // / lvalue = rvalue;
237+ // /
238+ // / // Temporary code from an incremental patch.
239+ // / Optional<FileEntryRef> MaybeF = rvalue;
240+ // / lvalue = MaybeF ? &MaybeF.getFileEntry() : nullptr;
241+ // /
242+ // / // Final code.
243+ // / lvalue = rvalue;
244+ // / \endcode
245+ // /
246+ // / FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
247+ // / FileEntry::getName have been deleted, delete this class and replace
248+ // / instances with Optional<FileEntryRef>.
249+ class OptionalFileEntryRefDegradesToFileEntryPtr
250+ : public Optional<FileEntryRef> {
251+ public:
252+ constexpr OptionalFileEntryRefDegradesToFileEntryPtr () noexcept = default;
253+ constexpr OptionalFileEntryRefDegradesToFileEntryPtr (
254+ OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
255+ constexpr OptionalFileEntryRefDegradesToFileEntryPtr (
256+ const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
257+ OptionalFileEntryRefDegradesToFileEntryPtr &
258+ operator =(OptionalFileEntryRefDegradesToFileEntryPtr &&) = default ;
259+ OptionalFileEntryRefDegradesToFileEntryPtr &
260+ operator =(const OptionalFileEntryRefDegradesToFileEntryPtr &) = default ;
261+
262+ OptionalFileEntryRefDegradesToFileEntryPtr (llvm::NoneType) {}
263+ OptionalFileEntryRefDegradesToFileEntryPtr (FileEntryRef Ref)
264+ : Optional<FileEntryRef>(Ref) {}
265+ OptionalFileEntryRefDegradesToFileEntryPtr (Optional<FileEntryRef> MaybeRef)
266+ : Optional<FileEntryRef>(MaybeRef) {}
267+
268+ OptionalFileEntryRefDegradesToFileEntryPtr &operator =(llvm::NoneType) {
269+ Optional<FileEntryRef>::operator =(None);
270+ return *this ;
271+ }
272+ OptionalFileEntryRefDegradesToFileEntryPtr &operator =(FileEntryRef Ref) {
273+ Optional<FileEntryRef>::operator =(Ref);
274+ return *this ;
275+ }
276+ OptionalFileEntryRefDegradesToFileEntryPtr &
277+ operator =(Optional<FileEntryRef> MaybeRef) {
278+ Optional<FileEntryRef>::operator =(MaybeRef);
279+ return *this ;
280+ }
281+
282+ // / Degrade to 'const FileEntry *' to allow FileEntry::LastRef and
283+ // / FileEntry::getName have been deleted, delete this class and replace
284+ // / instances with Optional<FileEntryRef>
285+ operator const FileEntry *() const {
286+ return hasValue () ? &getValue ().getFileEntry () : nullptr ;
287+ }
288+ };
289+
290+ static_assert (
291+ std::is_trivially_copyable<
292+ OptionalFileEntryRefDegradesToFileEntryPtr>::value,
293+ " OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable" );
294+
95295// / Cached information about one file (either on disk
96296// / or in the virtual file system).
97297// /
@@ -147,10 +347,6 @@ class FileEntry {
147347 bool isNamedPipe () const { return IsNamedPipe; }
148348
149349 void closeFile () const ;
150-
151- // Only for use in tests to see if deferred opens are happening, rather than
152- // relying on RealPathName being empty.
153- bool isOpenForTests () const { return File != nullptr ; }
154350};
155351
156352bool FileEntryRef::isValid () const { return getFileEntry ().isValid (); }
0 commit comments