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