diff --git a/clang/test/VFS/Inputs/root-relative-overlay.yaml b/clang/test/VFS/Inputs/root-relative-overlay.yaml new file mode 100644 --- /dev/null +++ b/clang/test/VFS/Inputs/root-relative-overlay.yaml @@ -0,0 +1,11 @@ +{ + 'version': 0, + 'case-sensitive': false, + 'overlay-relative': true, + 'root-relative': 'yaml-dir', + 'roots': [ + { 'name': 'not_real.h', 'type': 'file', + 'external-contents': 'actual_header.h' + }, + ] +} diff --git a/clang/test/VFS/relative-path.c b/clang/test/VFS/relative-path.c --- a/clang/test/VFS/relative-path.c +++ b/clang/test/VFS/relative-path.c @@ -3,6 +3,8 @@ // RUN: sed -e "s@INPUT_DIR@%{/S:regex_replacement}/Inputs@g" -e "s@OUT_DIR@%{/t:regex_replacement}@g" %S/Inputs/vfsoverlay.yaml > %t.yaml // RUN: %clang_cc1 -Werror -I . -ivfsoverlay %t.yaml -fsyntax-only %s +// RUN: %clang_cc1 -Werror -I %S/Inputs -ivfsoverlay %S/Inputs/root-relative-overlay.yaml -fsyntax-only %s + #include "not_real.h" void foo(void) { diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -651,11 +651,13 @@ /// \endverbatim /// /// The roots may be absolute or relative. If relative they will be made -/// absolute against the current working directory. +/// absolute against either current working directory or the directory where +/// the YAML file is located, depending on the 'root-relative' configuration. /// /// All configuration options are optional. /// 'case-sensitive': /// 'use-external-names': +/// 'root-relative': /// 'overlay-relative': /// 'fallthrough': @@ -745,6 +747,14 @@ RedirectOnly }; + /// The type of relative path used by Roots. + enum class RootRelativeKind { + /// The roots are relative to the current working directory. + CWD, + /// The roots are relative to the directory where the YAML file locates. + YAMLDir + }; + /// A single file or directory in the VFS. class Entry { EntryKind Kind; @@ -910,10 +920,11 @@ /// The file system to use for external references. IntrusiveRefCntPtr ExternalFS; - /// If IsRelativeOverlay is set, this represents the directory - /// path that should be prefixed to each 'external-contents' entry - /// when reading from YAML files. - std::string ExternalContentsPrefixDir; + /// This represents the directory path that the YAML file is located. + /// This will be prefixed to each 'external-contents' if IsRelativeOverlay + /// is set. This will also be prefixed to each 'roots->name' if RootRelative + /// is set to RootRelativeKind::YAMLDir. + std::string YAMLFileDir; /// @name Configuration /// @{ @@ -923,7 +934,7 @@ /// Currently, case-insensitive matching only works correctly with ASCII. bool CaseSensitive = is_style_posix(sys::path::Style::native); - /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must + /// IsRelativeOverlay marks whether a YAMLFileDir path must /// be prefixed in every 'external-contents' when reading from YAML files. bool IsRelativeOverlay = false; @@ -934,6 +945,10 @@ /// Determines the lookups to perform, as well as their order. See /// \c RedirectKind for details. RedirectKind Redirection = RedirectKind::Fallthrough; + + /// Determine the prefix directory if the roots are relative paths. See + /// \c RootRelativeKind for details. + RootRelativeKind RootRelative = RootRelativeKind::CWD; /// @} RedirectingFileSystem(IntrusiveRefCntPtr ExternalFS); @@ -984,9 +999,9 @@ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; - void setExternalContentsPrefixDir(StringRef PrefixDir); + void setYAMLFileDir(StringRef PrefixDir); - StringRef getExternalContentsPrefixDir() const; + StringRef getYAMLFileDir() const; /// Sets the redirection kind to \c Fallthrough if true or \c RedirectOnly /// otherwise. Will removed in the future, use \c setRedirection instead. diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1482,13 +1482,11 @@ return Combined; } -void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) { - ExternalContentsPrefixDir = PrefixDir.str(); +void RedirectingFileSystem::setYAMLFileDir(StringRef Dir) { + YAMLFileDir = Dir.str(); } -StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const { - return ExternalContentsPrefixDir; -} +StringRef RedirectingFileSystem::getYAMLFileDir() const { return YAMLFileDir; } void RedirectingFileSystem::setFallthrough(bool Fallthrough) { if (Fallthrough) { @@ -1621,6 +1619,20 @@ return None; } + Optional + parseRootRelativeKind(yaml::Node *N) { + SmallString<9> Storage; + StringRef Value; + if (!parseScalarString(N, Value, Storage)) + return None; + if (Value.equals_insensitive("cwd")) { + return RedirectingFileSystem::RootRelativeKind::CWD; + } else if (Value.equals_insensitive("yaml-dir")) { + return RedirectingFileSystem::RootRelativeKind::YAMLDir; + } + return None; + } + struct KeyStatus { bool Required; bool Seen = false; @@ -1828,7 +1840,7 @@ SmallString<256> FullPath; if (FS->IsRelativeOverlay) { - FullPath = FS->getExternalContentsPrefixDir(); + FullPath = FS->getYAMLFileDir(); assert(!FullPath.empty() && "External contents prefix directory must exist"); llvm::sys::path::append(FullPath, Value); @@ -1884,6 +1896,15 @@ } else if (sys::path::is_absolute(Name, sys::path::Style::windows_backslash)) { path_style = sys::path::Style::windows_backslash; + } else if (FS->RootRelative == + RedirectingFileSystem::RootRelativeKind::YAMLDir) { + SmallString<256> FullPath = FS->getYAMLFileDir(); + assert(!FullPath.empty() && "YAML file directory must exist"); + sys::fs::make_absolute(FS->getYAMLFileDir(), Name); + Name = canonicalize(Name); + path_style = sys::path::is_absolute(Name, sys::path::Style::posix) + ? sys::path::Style::posix + : sys::path::Style::windows_backslash; } else { // Relative VFS root entries are made absolute to the current working // directory, then we can determine the path style from that. @@ -1962,6 +1983,7 @@ KeyStatusPair("version", true), KeyStatusPair("case-sensitive", false), KeyStatusPair("use-external-names", false), + KeyStatusPair("root-relative", false), KeyStatusPair("overlay-relative", false), KeyStatusPair("fallthrough", false), KeyStatusPair("redirecting-with", false), @@ -2051,6 +2073,13 @@ error(I.getValue(), "expected valid redirect kind"); return false; } + } else if (Key == "root-relative") { + if (auto Kind = parseRootRelativeKind(I.getValue())) { + FS->RootRelative = *Kind; + } else { + error(I.getValue(), "expected valid root-relative kind"); + return false; + } } else { llvm_unreachable("key missing from Keys"); } @@ -2100,13 +2129,13 @@ // Example: // -ivfsoverlay dummy.cache/vfs/vfs.yaml // yields: - // FS->ExternalContentsPrefixDir => //dummy.cache/vfs + // FS->YAMLFileDir => //dummy.cache/vfs // SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath); std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir); assert(!EC && "Overlay dir final path must be absolute"); (void)EC; - FS->setExternalContentsPrefixDir(OverlayAbsDir); + FS->setYAMLFileDir(OverlayAbsDir); } if (!P.parse(Root, FS.get()))