Generate a unique filename for a given header

This patch is in preparation for writing the header replacement to disk.
Added getUniqueHeaderName() that generates a unique header filename in
the same directory as the header file.

Differential Revision: http://llvm-reviews.chandlerc.com/D1104

llvm-svn: 186007
This commit is contained in:
Tareq A. Siraj 2013-07-10 16:09:36 +00:00
parent aafb84be9e
commit 9c7750eeae
4 changed files with 123 additions and 1 deletions

View File

@ -16,6 +16,10 @@
#include "Core/FileOverrides.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
void SourceOverrides::applyOverrides(clang::SourceManager &SM) const {
clang::FileManager &FM = SM.getFileManager();
@ -32,3 +36,35 @@ void SourceOverrides::applyOverrides(clang::SourceManager &SM) const {
llvm::MemoryBuffer::getMemBuffer(I->second.FileOverride));
}
}
bool generateReplacementsFileName(llvm::StringRef SourceFile,
llvm::StringRef HeaderFile,
llvm::SmallVectorImpl<char> &Result,
llvm::SmallVectorImpl<char> &Error) {
using namespace llvm::sys;
std::string UniqueHeaderNameModel;
// Get the filename portion of the path.
llvm::StringRef SourceFileRef(path::filename(SourceFile));
llvm::StringRef HeaderFileRef(path::filename(HeaderFile));
// Get the actual path for the header file.
llvm::SmallString<128> HeaderPath(HeaderFile);
path::remove_filename(HeaderPath);
// Build the model of the filename.
llvm::raw_string_ostream UniqueHeaderNameStream(UniqueHeaderNameModel);
UniqueHeaderNameStream << SourceFileRef << "_" << HeaderFileRef
<< "_%%_%%_%%_%%_%%_%%" << ".yaml";
path::append(HeaderPath, UniqueHeaderNameStream.str());
Error.clear();
if (llvm::error_code EC =
fs::createUniqueFile(HeaderPath.c_str(), Result)) {
Error.append(EC.message().begin(), EC.message().end());
return false;
}
return true;
}

View File

@ -22,6 +22,10 @@
#include <string>
// Forward Declarations
namespace llvm {
template <typename T>
class SmallVectorImpl;
} // namespace llvm
namespace clang {
class SourceManager;
class FileManager;
@ -62,4 +66,24 @@ struct SourceOverrides {
/// \brief Maps source file names to content override information.
typedef std::map<std::string, SourceOverrides> FileOverrides;
/// \brief Generate a unique filename to store the replacements.
///
/// Generates a unique filename in the same directory as the header file. The
/// filename is based on the following model:
///
/// source.cpp_header.h_%%_%%_%%_%%_%%_%%.yaml
///
/// where all '%' will be replaced by a randomly chosen hex number.
///
/// @param SourceFile Full path to the source file.
/// @param HeaderFile Full path to the header file.
/// @param Result The resulting unique filename in the same directory as the
/// header file.
/// @param Error Description of the error if there is any.
/// @returns true if succeeded, false otherwise.
bool generateReplacementsFileName(llvm::StringRef SourceFile,
llvm::StringRef HeaderFile,
llvm::SmallVectorImpl<char> &Result,
llvm::SmallVectorImpl<char> &Error);
#endif // CPP11_MIGRATE_FILE_OVERRIDES_H

View File

@ -9,7 +9,8 @@ include_directories(${CPP11_MIGRATE_SOURCE_DIR})
add_extra_unittest(Cpp11MigrateTests
TransformTest.cpp
IncludeExcludeTest.cpp
PerfSupportTest.cpp)
PerfSupportTest.cpp
UniqueHeaderNameTest.cpp)
target_link_libraries(Cpp11MigrateTests
migrateCore

View File

@ -0,0 +1,61 @@
//===- unittests/cpp11-migrate/UniqueHeaderNameTest.cpp -------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Test for the generateReplacementsFileName() in FileOverrides.h
//
//===----------------------------------------------------------------------===//
#include "gtest/gtest.h"
#include "Core/FileOverrides.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/system_error.h"
TEST(UniqueHeaderName, testUniqueHeaderName) {
using namespace llvm::sys::path;
llvm::SmallString<32> TmpDir;
system_temp_directory(true, TmpDir);
llvm::SmallString<128> SourceFile(TmpDir);
append(SourceFile, "project/lib/feature.cpp");
native(SourceFile.c_str(), SourceFile);
llvm::SmallString<128> HeaderFile(TmpDir);
append(HeaderFile, "project/include/feature.h");
native(HeaderFile.c_str(), HeaderFile);
llvm::SmallString<128> ExpectedName("^feature.cpp_feature.h_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}_[0-9a-f]{2}.yaml$");
llvm::SmallString<128> ActualName;
llvm::SmallString<128> Error;
bool Result =
generateReplacementsFileName(SourceFile, HeaderFile, ActualName, Error);
ASSERT_TRUE(Result);
EXPECT_TRUE(Error.empty());
// We need to check the directory name and filename separately since on
// Windows, the path separator is '\' which is a regex escape character.
llvm::SmallString<128> ExpectedHeaderPath =
llvm::sys::path::parent_path(HeaderFile);
llvm::SmallString<128> ActualHeaderPath =
llvm::sys::path::parent_path(ActualName);
llvm::SmallString<128> ActualHeaderName =
llvm::sys::path::filename(ActualName);
EXPECT_STREQ(ExpectedHeaderPath.c_str(), ActualHeaderPath.c_str());
llvm::Regex R(ExpectedName);
ASSERT_TRUE(R.match(ActualHeaderName))
<< "ExpectedName: " << ExpectedName.c_str()
<< "\nActualName: " << ActualName.c_str();
ASSERT_TRUE(Error.empty()) << "Error: " << Error.c_str();
}