forked from OSchip/llvm-project
Extend -remap-file=from;to to permit mapping from a non-existent
file. This is accomplished by introducing the notion of a "virtual" file into the file manager, which provides a FileEntry* for a named file whose size and modification time are known but which may not exist on disk. Added a cute little test that remaps both a .c file and a .h file it includes to alternative files. llvm-svn: 90329
This commit is contained in:
parent
f98849eb8a
commit
407e2124bf
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_FILEMANAGER_H
|
||||
#define LLVM_CLANG_FILEMANAGER_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
|
@ -151,6 +152,9 @@ class FileManager {
|
|||
///
|
||||
unsigned NextFileUID;
|
||||
|
||||
/// \brief The virtual files that we have allocated.
|
||||
llvm::SmallVector<FileEntry *, 4> VirtualFileEntries;
|
||||
|
||||
// Statistics.
|
||||
unsigned NumDirLookups, NumFileLookups;
|
||||
unsigned NumDirCacheMisses, NumFileCacheMisses;
|
||||
|
@ -199,6 +203,11 @@ public:
|
|||
const FileEntry *getFile(const char *FilenameStart,
|
||||
const char *FilenameEnd);
|
||||
|
||||
/// \brief Retrieve a file entry for a "virtual" file that acts as
|
||||
/// if there were a file with the given name on disk. The file
|
||||
/// itself is not accessed.
|
||||
const FileEntry *getVirtualFile(const llvm::StringRef &Filename,
|
||||
off_t Size, time_t ModificationTime);
|
||||
void PrintStats() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -147,6 +147,12 @@ FileManager::FileManager()
|
|||
FileManager::~FileManager() {
|
||||
delete &UniqueDirs;
|
||||
delete &UniqueFiles;
|
||||
for (llvm::SmallVectorImpl<FileEntry *>::iterator
|
||||
V = VirtualFileEntries.begin(),
|
||||
VEnd = VirtualFileEntries.end();
|
||||
V != VEnd;
|
||||
++V)
|
||||
delete *V;
|
||||
}
|
||||
|
||||
void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
|
||||
|
@ -184,6 +190,30 @@ void FileManager::removeStatCache(StatSysCallCache *statCache) {
|
|||
assert(false && "Stat cache not found for removal");
|
||||
}
|
||||
|
||||
/// \brief Retrieve the directory that the given file name resides in.
|
||||
static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
|
||||
const char *NameStart,
|
||||
const char *NameEnd) {
|
||||
// Figure out what directory it is in. If the string contains a / in it,
|
||||
// strip off everything after it.
|
||||
// FIXME: this logic should be in sys::Path.
|
||||
const char *SlashPos = NameEnd-1;
|
||||
while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
|
||||
--SlashPos;
|
||||
// Ignore duplicate //'s.
|
||||
while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
|
||||
--SlashPos;
|
||||
|
||||
if (SlashPos < NameStart) {
|
||||
// Use the current directory if file has no path component.
|
||||
const char *Name = ".";
|
||||
return FileMgr.getDirectory(Name, Name+1);
|
||||
} else if (SlashPos == NameEnd-1)
|
||||
return 0; // If filename ends with a /, it's a directory.
|
||||
else
|
||||
return FileMgr.getDirectory(NameStart, SlashPos);
|
||||
}
|
||||
|
||||
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||
/// returns null if the directory doesn't exist.
|
||||
///
|
||||
|
@ -252,33 +282,16 @@ const FileEntry *FileManager::getFile(const char *NameStart,
|
|||
// By default, initialize it to invalid.
|
||||
NamedFileEnt.setValue(NON_EXISTENT_FILE);
|
||||
|
||||
// Figure out what directory it is in. If the string contains a / in it,
|
||||
// strip off everything after it.
|
||||
// FIXME: this logic should be in sys::Path.
|
||||
const char *SlashPos = NameEnd-1;
|
||||
while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
|
||||
--SlashPos;
|
||||
// Ignore duplicate //'s.
|
||||
while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
|
||||
--SlashPos;
|
||||
|
||||
const DirectoryEntry *DirInfo;
|
||||
if (SlashPos < NameStart) {
|
||||
// Use the current directory if file has no path component.
|
||||
const char *Name = ".";
|
||||
DirInfo = getDirectory(Name, Name+1);
|
||||
} else if (SlashPos == NameEnd-1)
|
||||
return 0; // If filename ends with a /, it's a directory.
|
||||
else
|
||||
DirInfo = getDirectory(NameStart, SlashPos);
|
||||
|
||||
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
|
||||
return 0;
|
||||
|
||||
// Get the null-terminated file name as stored as the key of the
|
||||
// FileEntries map.
|
||||
const char *InterndFileName = NamedFileEnt.getKeyData();
|
||||
|
||||
const DirectoryEntry *DirInfo
|
||||
= getDirectoryFromFile(*this, NameStart, NameEnd);
|
||||
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
|
||||
return 0;
|
||||
|
||||
// FIXME: Use the directory info to prune this, before doing the stat syscall.
|
||||
// FIXME: This will reduce the # syscalls.
|
||||
|
||||
|
@ -312,6 +325,44 @@ const FileEntry *FileManager::getFile(const char *NameStart,
|
|||
return &UFE;
|
||||
}
|
||||
|
||||
const FileEntry *
|
||||
FileManager::getVirtualFile(const llvm::StringRef &Filename,
|
||||
off_t Size, time_t ModificationTime) {
|
||||
const char *NameStart = Filename.begin(), *NameEnd = Filename.end();
|
||||
|
||||
++NumFileLookups;
|
||||
|
||||
// See if there is already an entry in the map.
|
||||
llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
|
||||
FileEntries.GetOrCreateValue(NameStart, NameEnd);
|
||||
|
||||
// See if there is already an entry in the map.
|
||||
if (NamedFileEnt.getValue())
|
||||
return NamedFileEnt.getValue() == NON_EXISTENT_FILE
|
||||
? 0 : NamedFileEnt.getValue();
|
||||
|
||||
++NumFileCacheMisses;
|
||||
|
||||
// By default, initialize it to invalid.
|
||||
NamedFileEnt.setValue(NON_EXISTENT_FILE);
|
||||
|
||||
const DirectoryEntry *DirInfo
|
||||
= getDirectoryFromFile(*this, NameStart, NameEnd);
|
||||
if (DirInfo == 0) // Directory doesn't exist, file can't exist.
|
||||
return 0;
|
||||
|
||||
FileEntry *UFE = new FileEntry();
|
||||
VirtualFileEntries.push_back(UFE);
|
||||
NamedFileEnt.setValue(UFE);
|
||||
|
||||
UFE->Name = NamedFileEnt.getKeyData();
|
||||
UFE->Size = Size;
|
||||
UFE->ModTime = ModificationTime;
|
||||
UFE->Dir = DirInfo;
|
||||
UFE->UID = NextFileUID++;
|
||||
return UFE;
|
||||
}
|
||||
|
||||
void FileManager::PrintStats() const {
|
||||
llvm::errs() << "\n*** File Manager Stats:\n";
|
||||
llvm::errs() << UniqueFiles.size() << " files found, "
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/System/Path.h"
|
||||
|
@ -502,11 +503,11 @@ static void InitializeFileRemapping(Diagnostic &Diags,
|
|||
continue;
|
||||
}
|
||||
|
||||
// Find the file that we're mapping from.
|
||||
const FileEntry *FromFile = FileMgr.getFile(Remap->first);
|
||||
// Create the file entry for the file that we're mapping from.
|
||||
const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
|
||||
ToFile->getSize(),
|
||||
0);
|
||||
if (!FromFile) {
|
||||
// FIXME: We could actually recover from this, by faking a
|
||||
// FileEntry based on the "ToFile".
|
||||
Diags.Report(diag::err_fe_remap_missing_from_file)
|
||||
<< Remap->first;
|
||||
continue;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#include "nonexistent.h"
|
||||
|
||||
int *f() { return fp; }
|
|
@ -0,0 +1,2 @@
|
|||
extern float *fp;
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
// RUN: clang-cc -remap-file="%s;%S/Inputs/remapped-file" -fsyntax-only %s 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: remap-file.c:1:28: warning: incompatible pointer types
|
||||
// RUN: clang-cc -remap-file="%s;%S/Inputs/remapped-file" -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXIST %s
|
||||
// RUN: clang-cc -remap-file="%S/nonexistent.c;%S/Inputs/remapped-file" -fsyntax-only %S/nonexistent.c 2>&1 | FileCheck -check-prefix=CHECK-NONEXIST %s
|
||||
// RUN: clang-cc -remap-file="%S/nonexistent.c;%S/Inputs/remapped-file-2" -remap-file="%S/nonexistent.h;%S/Inputs/remapped-file-3" -fsyntax-only %S/nonexistent.c 2>&1 | FileCheck -check-prefix=CHECK-HEADER %s
|
||||
|
||||
// CHECK-EXIST: remap-file.c:1:28: warning: incompatible pointer types
|
||||
// CHECK-NONEXIST: nonexistent.c:1:28: warning: incompatible pointer types
|
||||
// CHECK-HEADER: nonexistent.c:3:19: warning: incompatible pointer types
|
||||
int
|
||||
|
|
Loading…
Reference in New Issue