Skip to content

[VFS] Add a "redirecting-with" field to overlays #3990

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions clang/test/VFS/Inputs/redirect-and-fallthrough.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
'redirecting-with': 'fallthrough',
'fallthrough': true,
'roots': [
{
'type': 'directory-remap',
'name': '//root/a',
'external-contents': '//root/b'
}
]
}
10 changes: 10 additions & 0 deletions clang/test/VFS/Inputs/unknown-redirect.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
'redirecting-with': 'none',
'roots': [
{
'type': 'directory-remap',
'name': '//root/a',
'external-contents': '//root/b'
}
]
}
86 changes: 86 additions & 0 deletions clang/test/VFS/fallback.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// RUN: rm -rf %t
// RUN: split-file %s %t

// Test fallback directory remapping, ie. a directory "Base" which is used as
// a fallback if files are missing from "UseFirst"

// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/Both/Base@g" -e "s@NAME_DIR@%{/t:regex_replacement}/Both/UseFirst@g" %t/vfs/base.yaml > %t/vfs/both.yaml

// RUN: cp -R %t/Both %t/UseFirstOnly
// RUN: rm -rf %t/UseFirstOnly/Base
// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/UseFirstOnly/Base@g" -e "s@NAME_DIR@%{/t:regex_replacement}/UseFirstOnly/UseFirst@g" %t/vfs/base.yaml > %t/vfs/use-first-only.yaml

// RUN: cp -R %t/Both %t/BaseOnly
// RUN: rm -rf %t/BaseOnly/UseFirst
// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/BaseOnly/Base@g" -e "s@NAME_DIR@%{/t:regex_replacement}/BaseOnly/UseFirst@g" %t/vfs/base.yaml > %t/vfs/base-only.yaml

// RUN: cp -R %t/Both %t/BFallback
// RUN: rm %t/BFallback/UseFirst/B.h
// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/BFallback/Base@g" -e "s@NAME_DIR@%{/t:regex_replacement}/BFallback/UseFirst@g" %t/vfs/base.yaml > %t/vfs/b-fallback.yaml

// RUN: cp -R %t/Both %t/CFallback
// RUN: rm %t/CFallback/UseFirst/C.h
// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/CFallback/Base@g" -e "s@NAME_DIR@%{/t:regex_replacement}/CFallback/UseFirst@g" %t/vfs/base.yaml > %t/vfs/c-fallback.yaml

// Both B.h and C.h are in both folders
// RUN: %clang_cc1 -Werror -I %t/Both/UseFirst -ivfsoverlay %t/vfs/both.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=IN_UF %s

// IN_UF: # 1 "{{.*(/|\\\\)UseFirst(/|\\\\)}}B.h"
// IN_UF-NEXT: // B.h in UseFirst
// IN_UF: # 1 "{{.*(/|\\\\)UseFirst(/|\\\\)}}C.h"
// IN_UF-NEXT: // C.h in UseFirst

// Base missing, so now they are only in UseFirst
// RUN: %clang_cc1 -Werror -I %t/UseFirstOnly/UseFirst -ivfsoverlay %t/vfs/use-first-only.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=IN_UF %s

// UseFirst missing, fallback to Base
// RUN: %clang_cc1 -Werror -I %t/BaseOnly/UseFirst -ivfsoverlay %t/vfs/base-only.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=IN_BASE %s

// IN_BASE: # 1 "{{.*(/|\\\\)Base(/|\\\\)}}B.h"
// IN_BASE-NEXT: // B.h in Base
// IN_BASE: # 1 "{{.*(/|\\\\)Base(/|\\\\)}}C.h"
// IN_BASE-NEXT: // C.h in Base

// B.h missing from UseFirst
// RUN: %clang_cc1 -Werror -I %t/BFallback/UseFirst -ivfsoverlay %t/vfs/b-fallback.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=B_FALLBACK %s

// B_FALLBACK: # 1 "{{.*(/|\\\\)Base(/|\\\\)}}B.h"
// B_FALLBACK-NEXT: // B.h in Base
// B_FALLBACK: # 1 "{{.*(/|\\\\)UseFirst(/|\\\\)}}C.h"
// B_FALLBACK-NEXT: // C.h in UseFirst

// C.h missing from UseFirst
// RUN: %clang_cc1 -Werror -I %t/CFallback/UseFirst -ivfsoverlay %t/vfs/c-fallback.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=C_FALLBACK %s

// C_FALLBACK: # 1 "{{.*(/|\\\\)UseFirst(/|\\\\)}}B.h"
// C_FALLBACK-NEXT: // B.h in UseFirst
// C_FALLBACK: # 1 "{{.*(/|\\\\)Base(/|\\\\)}}C.h"
// C_FALLBACK-NEXT: // C.h in Base

//--- main.c
#include "B.h"

//--- Both/UseFirst/B.h
// B.h in UseFirst
#include "C.h"

//--- Both/UseFirst/C.h
// C.h in UseFirst

//--- Both/Base/B.h
// B.h in Base
#include "C.h"

//--- Both/Base/C.h
// C.h in Base

//--- vfs/base.yaml
{
'version' : 0,
'redirecting-with' : 'fallback',
'roots' : [
{'name' : 'NAME_DIR',
'type' : 'directory-remap',
'external-contents' : 'EXTERNAL_DIR'}
]
}
8 changes: 8 additions & 0 deletions clang/test/VFS/parse-errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@
// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/unknown-value.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-VALUE %s
// CHECK-UNKNOWN-VALUE: expected boolean value
// CHECK-UNKNOWN-VALUE: invalid virtual filesystem overlay file

// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/unknown-redirect.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-REDIRECT %s
// CHECK-REDIRECT: expected valid redirect kind
// CHECK-REDIRECT: invalid virtual filesystem overlay file

// RUN: not %clang_cc1 -ivfsoverlay %S/Inputs/redirect-and-fallthrough.yaml -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXCLUSIVE-KEYS %s
// CHECK-EXCLUSIVE-KEYS: 'fallthrough' and 'redirecting-with' are mutually exclusive
// CHECK-EXCLUSIVE-KEYS: invalid virtual filesystem overlay file
35 changes: 25 additions & 10 deletions llvm/include/llvm/Support/VirtualFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,10 @@ class RedirectingFileSystemParser;
/// 'case-sensitive': <boolean, default=(true for Posix, false for Windows)>
/// 'use-external-names': <boolean, default=true>
/// 'overlay-relative': <boolean, default=false>
/// 'fallthrough': <boolean, default=true>
/// 'fallthrough': <boolean, default=true, deprecated - use 'redirecting-with'
/// instead>
/// 'redirecting-with': <string, one of 'fallthrough', 'fallback', or
/// 'redirect-only', default='fallthrough'>
///
/// Virtual directories that list their contents are represented as
/// \verbatim
Expand Down Expand Up @@ -620,6 +623,20 @@ class RedirectingFileSystem : public vfs::FileSystem {
enum EntryKind { EK_Directory, EK_DirectoryRemap, EK_File };
enum NameKind { NK_NotSet, NK_External, NK_Virtual };

/// The type of redirection to perform.
enum class RedirectKind {
/// Lookup the redirected path first (ie. the one specified in
/// 'external-contents') and if that fails "fallthrough" to a lookup of the
/// originally provided path.
Fallthrough,
/// Lookup the provided path first and if that fails, "fallback" to a
/// lookup of the redirected path.
Fallback,
/// Only lookup the redirected path, do not lookup the originally provided
/// path.
RedirectOnly
};

/// A single file or directory in the VFS.
class Entry {
EntryKind Kind;
Expand Down Expand Up @@ -754,17 +771,11 @@ class RedirectingFileSystem : public vfs::FileSystem {
friend class RedirectingFSDirIterImpl;
friend class RedirectingFileSystemParser;

bool shouldUseExternalFS() const { return IsFallthrough; }

/// Canonicalize path by removing ".", "..", "./", components. This is
/// a VFS request, do not bother about symlinks in the path components
/// but canonicalize in order to perform the correct entry search.
std::error_code makeCanonical(SmallVectorImpl<char> &Path) const;

/// Whether to fall back to the external file system when an operation fails
/// with the given error code on a path associated with the provided Entry.
bool shouldFallBackToExternalFS(std::error_code EC, Entry *E = nullptr) const;

/// Get the File status, or error, from the underlying external file system.
/// This returns the status with the originally requested name, while looking
/// up the entry using the canonical path.
Expand Down Expand Up @@ -817,9 +828,9 @@ class RedirectingFileSystem : public vfs::FileSystem {
/// names of files. This global value is overridable on a per-file basis.
bool UseExternalNames = true;

/// Whether to attempt a file lookup in external file system after it wasn't
/// found in VFS.
bool IsFallthrough = true;
/// Determines the lookups to perform, as well as their order. See
/// \c RedirectKind for details.
RedirectKind Redirection = RedirectKind::Fallthrough;
/// @}

RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS);
Expand Down Expand Up @@ -874,8 +885,12 @@ class RedirectingFileSystem : public vfs::FileSystem {

StringRef getExternalContentsPrefixDir() const;

/// Sets the redirection kind to \c Fallthrough if true or \c RedirectOnly
/// otherwise. Will removed in the future, use \c setRedirection instead.
void setFallthrough(bool Fallthrough);

void setRedirection(RedirectingFileSystem::RedirectKind Kind);

std::vector<llvm::StringRef> getRoots() const;

void dump(raw_ostream &OS) const;
Expand Down
Loading