1 //===-- FileSpec.h ----------------------------------------------*- 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 #ifndef LLDB_UTILITY_FILESPEC_H 10 #define LLDB_UTILITY_FILESPEC_H 11 12 #include <functional> 13 #include <optional> 14 #include <string> 15 16 #include "lldb/Utility/Checksum.h" 17 #include "lldb/Utility/ConstString.h" 18 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Support/FileSystem.h" 21 #include "llvm/Support/FormatVariadic.h" 22 #include "llvm/Support/Path.h" 23 24 #include <cstddef> 25 #include <cstdint> 26 27 namespace lldb_private { 28 class Stream; 29 } 30 namespace llvm { 31 class Triple; 32 } 33 namespace llvm { 34 class raw_ostream; 35 } 36 namespace llvm { 37 template <typename T> class SmallVectorImpl; 38 } 39 40 namespace lldb_private { 41 42 /// \class FileSpec FileSpec.h "lldb/Utility/FileSpec.h" 43 /// A file utility class. 44 /// 45 /// A file specification class that divides paths up into a directory 46 /// and basename. These string values of the paths are put into uniqued string 47 /// pools for fast comparisons and efficient memory usage. 48 /// 49 /// Another reason the paths are split into the directory and basename is to 50 /// allow efficient debugger searching. Often in a debugger the user types in 51 /// the basename of the file, for example setting a breakpoint by file and 52 /// line, or specifying a module (shared library) to limit the scope in which 53 /// to execute a command. The user rarely types in a full path. When the paths 54 /// are already split up, it makes it easy for us to compare only the 55 /// basenames of a lot of file specifications without having to split up the 56 /// file path each time to get to the basename. 57 class FileSpec { 58 public: 59 using Style = llvm::sys::path::Style; 60 61 FileSpec(); 62 63 /// Constructor with path. 64 /// 65 /// Takes a path to a file which can be just a filename, or a full path. If 66 /// \a path is not nullptr or empty, this function will call 67 /// FileSpec::SetFile (const char *path). 68 /// 69 /// \param[in] path 70 /// The full or partial path to a file. 71 /// 72 /// \param[in] style 73 /// The style of the path 74 /// 75 /// \param[in] checksum 76 /// The MD5 checksum of the path. 77 /// 78 /// \see FileSpec::SetFile (const char *path) 79 explicit FileSpec(llvm::StringRef path, Style style = Style::native, 80 const Checksum &checksum = {}); 81 82 explicit FileSpec(llvm::StringRef path, const llvm::Triple &triple); 83 84 bool DirectoryEquals(const FileSpec &other) const; 85 86 bool FileEquals(const FileSpec &other) const; 87 88 /// Equal to operator 89 /// 90 /// Tests if this object is equal to \a rhs. 91 /// 92 /// \param[in] rhs 93 /// A const FileSpec object reference to compare this object 94 /// to. 95 /// 96 /// \return 97 /// \b true if this object is equal to \a rhs, \b false 98 /// otherwise. 99 bool operator==(const FileSpec &rhs) const; 100 101 /// Not equal to operator 102 /// 103 /// Tests if this object is not equal to \a rhs. 104 /// 105 /// \param[in] rhs 106 /// A const FileSpec object reference to compare this object 107 /// to. 108 /// 109 /// \return 110 /// \b true if this object is equal to \a rhs, \b false 111 /// otherwise. 112 bool operator!=(const FileSpec &rhs) const; 113 114 /// Less than to operator 115 /// 116 /// Tests if this object is less than \a rhs. 117 /// 118 /// \param[in] rhs 119 /// A const FileSpec object reference to compare this object 120 /// to. 121 /// 122 /// \return 123 /// \b true if this object is less than \a rhs, \b false 124 /// otherwise. 125 bool operator<(const FileSpec &rhs) const; 126 127 /// Convert to pointer operator. 128 /// 129 /// This allows code to check a FileSpec object to see if it contains 130 /// anything valid using code such as: 131 /// 132 /// \code 133 /// FileSpec file_spec(...); 134 /// if (file_spec) 135 /// { ... 136 /// \endcode 137 /// 138 /// \return 139 /// A pointer to this object if either the directory or filename 140 /// is valid, nullptr otherwise. 141 explicit operator bool() const; 142 143 /// Logical NOT operator. 144 /// 145 /// This allows code to check a FileSpec object to see if it is invalid 146 /// using code such as: 147 /// 148 /// \code 149 /// FileSpec file_spec(...); 150 /// if (!file_spec) 151 /// { ... 152 /// \endcode 153 /// 154 /// \return 155 /// Returns \b true if the object has an empty directory and 156 /// filename, \b false otherwise. 157 bool operator!() const; 158 159 /// Clears the object state. 160 /// 161 /// Clear this object by releasing both the directory and filename string 162 /// values and reverting them to empty strings. 163 void Clear(); 164 165 /// Compare two FileSpec objects. 166 /// 167 /// If \a full is true, then both the directory and the filename must match. 168 /// If \a full is false, then the directory names for \a lhs and \a rhs are 169 /// only compared if they are both not empty. This allows a FileSpec object 170 /// to only contain a filename and it can match FileSpec objects that have 171 /// matching filenames with different paths. 172 /// 173 /// \param[in] lhs 174 /// A const reference to the Left Hand Side object to compare. 175 /// 176 /// \param[in] rhs 177 /// A const reference to the Right Hand Side object to compare. 178 /// 179 /// \param[in] full 180 /// If true, then both the directory and filenames will have to 181 /// match for a compare to return zero (equal to). If false 182 /// and either directory from \a lhs or \a rhs is empty, then 183 /// only the filename will be compared, else a full comparison 184 /// is done. 185 /// 186 /// \return -1 if \a lhs is less than \a rhs, 0 if \a lhs is equal to \a rhs, 187 /// 1 if \a lhs is greater than \a rhs 188 static int Compare(const FileSpec &lhs, const FileSpec &rhs, bool full); 189 190 static bool Equal(const FileSpec &a, const FileSpec &b, bool full); 191 192 /// Match FileSpec \a pattern against FileSpec \a file. If \a pattern has a 193 /// directory component, then the \a file must have the same directory 194 /// component. Otherwise, just it matches just the filename. An empty \a 195 /// pattern matches everything. 196 static bool Match(const FileSpec &pattern, const FileSpec &file); 197 198 /// Attempt to guess path style for a given path string. It returns a style, 199 /// if it was able to make a reasonable guess, or std::nullopt if it wasn't. 200 /// The guess will be correct if the input path was a valid absolute path on 201 /// the system which produced it. On other paths the result of this function 202 /// is unreliable (e.g. "c:\foo.txt" is a valid relative posix path). 203 static std::optional<Style> GuessPathStyle(llvm::StringRef absolute_path); 204 205 /// Case sensitivity of path. 206 /// 207 /// \return 208 /// \b true if the file path is case sensitive (POSIX), false 209 /// if case insensitive (Windows). 210 bool IsCaseSensitive() const { return is_style_posix(m_style); } 211 212 /// Dump this object to a Stream. 213 /// 214 /// Dump the object to the supplied stream \a s. If the object contains a 215 /// valid directory name, it will be displayed followed by a directory 216 /// delimiter, and the filename. 217 /// 218 /// \param[in] s 219 /// The stream to which to dump the object description. 220 void Dump(llvm::raw_ostream &s) const; 221 222 Style GetPathStyle() const; 223 224 /// Directory string const get accessor. 225 /// 226 /// \return 227 /// A const reference to the directory string object. 228 const ConstString &GetDirectory() const { return m_directory; } 229 230 /// Directory string set accessor. 231 /// 232 /// \param[in] directory 233 /// The value to replace the directory with. 234 void SetDirectory(ConstString directory); 235 void SetDirectory(llvm::StringRef directory); 236 237 /// Clear the directory in this object. 238 void ClearDirectory(); 239 240 241 /// Filename string const get accessor. 242 /// 243 /// \return 244 /// A const reference to the filename string object. 245 const ConstString &GetFilename() const { return m_filename; } 246 247 /// Filename string set accessor. 248 /// 249 /// \param[in] filename 250 /// The const string to replace the directory with. 251 void SetFilename(ConstString filename); 252 void SetFilename(llvm::StringRef filename); 253 254 /// Clear the filename in this object. 255 void ClearFilename(); 256 257 /// Returns true if the filespec represents an implementation source file 258 /// (files with a ".c", ".cpp", ".m", ".mm" (many more) extension). 259 /// 260 /// \return 261 /// \b true if the FileSpec represents an implementation source 262 /// file, \b false otherwise. 263 bool IsSourceImplementationFile() const; 264 265 /// Returns true if the filespec represents a relative path. 266 /// 267 /// \return 268 /// \b true if the filespec represents a relative path, 269 /// \b false otherwise. 270 bool IsRelative() const; 271 272 /// Returns true if the filespec represents an absolute path. 273 /// 274 /// \return 275 /// \b true if the filespec represents an absolute path, 276 /// \b false otherwise. 277 bool IsAbsolute() const; 278 279 /// Make the FileSpec absolute by treating it relative to \a dir. Absolute 280 /// FileSpecs are never changed by this function. 281 void MakeAbsolute(const FileSpec &dir); 282 283 /// Temporary helper for FileSystem change. 284 void SetPath(llvm::StringRef p) { SetFile(p); } 285 286 /// Extract the full path to the file. 287 /// 288 /// Extract the directory and path into a fixed buffer. This is needed as 289 /// the directory and path are stored in separate string values. 290 /// 291 /// \param[out] path 292 /// The buffer in which to place the extracted full path. 293 /// 294 /// \param[in] max_path_length 295 /// The maximum length of \a path. 296 /// 297 /// \return 298 /// Returns the number of characters that would be needed to 299 /// properly copy the full path into \a path. If the returned 300 /// number is less than \a max_path_length, then the path is 301 /// properly copied and terminated. If the return value is 302 /// >= \a max_path_length, then the path was truncated (but is 303 /// still NULL terminated). 304 size_t GetPath(char *path, size_t max_path_length, 305 bool denormalize = true) const; 306 307 /// Extract the full path to the file. 308 /// 309 /// Extract the directory and path into a std::string, which is returned. 310 /// 311 /// \return 312 /// Returns a std::string with the directory and filename 313 /// concatenated. 314 std::string GetPath(bool denormalize = true) const; 315 316 /// Get the full path as a ConstString. 317 /// 318 /// This method should only be used when you need a ConstString or the 319 /// const char * from a ConstString to ensure permanent lifetime of C string. 320 /// Anyone needing the path temporarily should use the GetPath() method that 321 /// returns a std:string. 322 ConstString GetPathAsConstString(bool denormalize = true) const; 323 324 /// Extract the full path to the file. 325 /// 326 /// Extract the directory and path into an llvm::SmallVectorImpl<> 327 void GetPath(llvm::SmallVectorImpl<char> &path, 328 bool denormalize = true) const; 329 330 /// Extract the extension of the file. 331 /// 332 /// Returns a ConstString that represents the extension of the filename for 333 /// this FileSpec object. If this object does not represent a file, or the 334 /// filename has no extension, ConstString(nullptr) is returned. The dot 335 /// ('.') character is the first character in the returned string. 336 /// 337 /// \return Returns the extension of the file as a StringRef. 338 llvm::StringRef GetFileNameExtension() const; 339 340 /// Return the filename without the extension part 341 /// 342 /// Returns a ConstString that represents the filename of this object 343 /// without the extension part (e.g. for a file named "foo.bar", "foo" is 344 /// returned) 345 /// 346 /// \return Returns the filename without extension as a ConstString object. 347 ConstString GetFileNameStrippingExtension() const; 348 349 /// Get the memory cost of this object. 350 /// 351 /// Return the size in bytes that this object takes in memory. This returns 352 /// the size in bytes of this object, not any shared string values it may 353 /// refer to. 354 /// 355 /// \return 356 /// The number of bytes that this object occupies in memory. 357 size_t MemorySize() const; 358 359 /// Change the file specified with a new path. 360 /// 361 /// Update the contents of this object with a new path. The path will be 362 /// split up into a directory and filename and stored as uniqued string 363 /// values for quick comparison and efficient memory usage. 364 /// 365 /// \param[in] path 366 /// A full, partial, or relative path to a file. 367 /// 368 /// \param[in] style 369 /// The style for the given path. 370 /// 371 /// \param[in] checksum 372 /// The checksum for the given path. 373 void SetFile(llvm::StringRef path, Style style, 374 const Checksum &checksum = {}); 375 376 /// Change the file specified with a new path. 377 /// 378 /// Update the contents of this object with a new path. The path will be 379 /// split up into a directory and filename and stored as uniqued string 380 /// values for quick comparison and efficient memory usage. 381 /// 382 /// \param[in] path 383 /// A full, partial, or relative path to a file. 384 /// 385 /// \param[in] triple 386 /// The triple which is used to set the Path style. 387 void SetFile(llvm::StringRef path, const llvm::Triple &triple); 388 389 bool IsResolved() const { return m_is_resolved; } 390 391 /// Set if the file path has been resolved or not. 392 /// 393 /// If you know a file path is already resolved and avoided passing a \b 394 /// true parameter for any functions that take a "bool resolve_path" 395 /// parameter, you can set the value manually using this call to make sure 396 /// we don't try and resolve it later, or try and resolve a path that has 397 /// already been resolved. 398 /// 399 /// \param[in] is_resolved 400 /// A boolean value that will replace the current value that 401 /// indicates if the paths in this object have been resolved. 402 void SetIsResolved(bool is_resolved) { m_is_resolved = is_resolved; } 403 404 FileSpec CopyByAppendingPathComponent(llvm::StringRef component) const; 405 FileSpec CopyByRemovingLastPathComponent() const; 406 407 void PrependPathComponent(llvm::StringRef component); 408 void PrependPathComponent(const FileSpec &new_path); 409 410 void AppendPathComponent(llvm::StringRef component); 411 void AppendPathComponent(const FileSpec &new_path); 412 413 /// Removes the last path component by replacing the current path with its 414 /// parent. When the current path has no parent, this is a no-op. 415 /// 416 /// \return 417 /// A boolean value indicating whether the path was updated. 418 bool RemoveLastPathComponent(); 419 420 /// Gets the components of the FileSpec's path. 421 /// For example, given the path: 422 /// /System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation 423 /// 424 /// This function returns: 425 /// {"System", "Library", "PrivateFrameworks", "UIFoundation.framework", 426 /// "UIFoundation"} 427 /// \return 428 /// A std::vector of llvm::StringRefs for each path component. 429 /// The lifetime of the StringRefs is tied to the lifetime of the FileSpec. 430 std::vector<llvm::StringRef> GetComponents() const; 431 432 /// Return the checksum for this FileSpec or all zeros if there is none. 433 const Checksum &GetChecksum() const { return m_checksum; }; 434 435 protected: 436 // Convenience method for setting the file without changing the style. 437 void SetFile(llvm::StringRef path); 438 439 /// Called anytime m_directory or m_filename is changed to clear any cached 440 /// state in this object. 441 void PathWasModified() { 442 m_checksum = Checksum(); 443 m_is_resolved = false; 444 m_absolute = Absolute::Calculate; 445 } 446 447 enum class Absolute : uint8_t { 448 Calculate, 449 Yes, 450 No 451 }; 452 453 /// The unique'd directory path. 454 ConstString m_directory; 455 456 /// The unique'd filename path. 457 ConstString m_filename; 458 459 /// The optional MD5 checksum of the file. 460 Checksum m_checksum; 461 462 /// True if this path has been resolved. 463 mutable bool m_is_resolved = false; 464 465 /// Cache whether this path is absolute. 466 mutable Absolute m_absolute = Absolute::Calculate; 467 468 /// The syntax that this path uses. (e.g. Windows / Posix) 469 Style m_style; 470 }; 471 472 /// Dump a FileSpec object to a stream 473 Stream &operator<<(Stream &s, const FileSpec &f); 474 } // namespace lldb_private 475 476 namespace llvm { 477 478 /// Implementation of format_provider<T> for FileSpec. 479 /// 480 /// The options string of a FileSpec has the grammar: 481 /// 482 /// file_spec_options :: (empty) | F | D 483 /// 484 /// ======================================================= 485 /// | style | Meaning | Example | 486 /// ------------------------------------------------------- 487 /// | | | Input | Output | 488 /// ======================================================= 489 /// | F | Only print filename | /foo/bar | bar | 490 /// | D | Only print directory | /foo/bar | /foo/ | 491 /// | (empty) | Print file and dir | | | 492 /// ======================================================= 493 /// 494 /// Any other value is considered an invalid format string. 495 /// 496 template <> struct format_provider<lldb_private::FileSpec> { 497 static void format(const lldb_private::FileSpec &F, llvm::raw_ostream &Stream, 498 StringRef Style); 499 }; 500 501 } // namespace llvm 502 503 #endif // LLDB_UTILITY_FILESPEC_H 504