diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-12-11 20:50:24 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-12-11 20:50:24 +0000 |
commit | 54cc3c2f231846e110dcfbc04ff52f266aa6dfb9 (patch) | |
tree | 40917c9ba0ce4b23b2f98595f012d5ab5d50a332 /clang/lib | |
parent | 72b05aa59c0268f3404af9c3e61c706d1661fd03 (diff) | |
download | bcm5719-llvm-54cc3c2f231846e110dcfbc04ff52f266aa6dfb9.tar.gz bcm5719-llvm-54cc3c2f231846e110dcfbc04ff52f266aa6dfb9.zip |
[modules] When constructing paths relative to a module, strip out /./ directory
components. These sometimes get synthetically added, and we don't want -Ifoo
and -I./foo to be treated fundamentally differently here.
llvm-svn: 224055
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/FileManager.cpp | 43 | ||||
-rw-r--r-- | clang/lib/Frontend/ModuleDependencyCollector.cpp | 29 | ||||
-rw-r--r-- | clang/lib/Lex/HeaderSearch.cpp | 26 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 34 |
4 files changed, 76 insertions, 56 deletions
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index af6022fdc92..214e0f35a52 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -513,15 +513,47 @@ void FileManager::modifyFileEntry(FileEntry *File, File->ModTime = ModificationTime; } +/// Remove '.' path components from the given absolute path. +/// \return \c true if any changes were made. +// FIXME: Move this to llvm::sys::path. +bool FileManager::removeDotPaths(SmallVectorImpl<char> &Path) { + using namespace llvm::sys; + + SmallVector<StringRef, 16> ComponentStack; + StringRef P(Path.data(), Path.size()); + + // Skip the root path, then look for traversal in the components. + StringRef Rel = path::relative_path(P); + bool AnyDots = false; + for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) { + if (C == ".") { + AnyDots = true; + continue; + } + ComponentStack.push_back(C); + } + + if (!AnyDots) + return false; + + SmallString<256> Buffer = path::root_path(P); + for (StringRef C : ComponentStack) + path::append(Buffer, C); + + Path.swap(Buffer); + return true; +} + StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { // FIXME: use llvm::sys::fs::canonical() when it gets implemented -#ifdef LLVM_ON_UNIX llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known = CanonicalDirNames.find(Dir); if (Known != CanonicalDirNames.end()) return Known->second; StringRef CanonicalName(Dir->getName()); + +#ifdef LLVM_ON_UNIX char CanonicalNameBuf[PATH_MAX]; if (realpath(Dir->getName(), CanonicalNameBuf)) { unsigned Len = strlen(CanonicalNameBuf); @@ -529,12 +561,15 @@ StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { memcpy(Mem, CanonicalNameBuf, Len); CanonicalName = StringRef(Mem, Len); } +#else + SmallString<256> CanonicalNameBuf(CanonicalName); + llvm::sys::fs::make_absolute(CanonicalNameBuf); + llvm::sys::path::native(CanonicalNameBuf); + removeDotPaths(CanonicalNameBuf); +#endif CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName)); return CanonicalName; -#else - return StringRef(Dir->getName()); -#endif } void FileManager::PrintStats() const { diff --git a/clang/lib/Frontend/ModuleDependencyCollector.cpp b/clang/lib/Frontend/ModuleDependencyCollector.cpp index 882bf8ee240..1ac7e36eff1 100644 --- a/clang/lib/Frontend/ModuleDependencyCollector.cpp +++ b/clang/lib/Frontend/ModuleDependencyCollector.cpp @@ -57,40 +57,13 @@ void ModuleDependencyCollector::writeFileMap() { VFSWriter.write(OS); } -/// Remove traversal (ie, . or ..) from the given absolute path. -static void removePathTraversal(SmallVectorImpl<char> &Path) { - using namespace llvm::sys; - SmallVector<StringRef, 16> ComponentStack; - StringRef P(Path.data(), Path.size()); - - // Skip the root path, then look for traversal in the components. - StringRef Rel = path::relative_path(P); - for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) { - if (C == ".") - continue; - if (C == "..") { - assert(ComponentStack.size() && "Path traverses out of parent"); - ComponentStack.pop_back(); - } else - ComponentStack.push_back(C); - } - - // The stack is now the path without any directory traversal. - SmallString<256> Buffer = path::root_path(P); - for (StringRef C : ComponentStack) - path::append(Buffer, C); - - // Put the result in Path. - Path.swap(Buffer); -} - std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) { using namespace llvm::sys; // We need an absolute path to append to the root. SmallString<256> AbsoluteSrc = Src; fs::make_absolute(AbsoluteSrc); - removePathTraversal(AbsoluteSrc); + FileManager::removeDotPaths(AbsoluteSrc); // Build the destination path. SmallString<256> Dest = Collector.getDest(); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 02fd87c8226..d6b255fb014 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -131,16 +131,24 @@ std::string HeaderSearch::getModuleFileName(StringRef ModuleName, llvm::sys::path::append(Result, ModuleName + ".pcm"); } else { // Construct the name <ModuleName>-<hash of ModuleMapPath>.pcm which should - // be globally unique to this particular module. To avoid false-negatives - // on case-insensitive filesystems, we use lower-case, which is safe because - // to cause a collision the modules must have the same name, which is an - // error if they are imported in the same translation. - SmallString<256> AbsModuleMapPath(ModuleMapPath); - llvm::sys::fs::make_absolute(AbsModuleMapPath); - llvm::sys::path::native(AbsModuleMapPath); - llvm::APInt Code(64, llvm::hash_value(AbsModuleMapPath.str().lower())); + // ideally be globally unique to this particular module. Name collisions + // in the hash are safe (because any translation unit can only import one + // module with each name), but result in a loss of caching. + // + // To avoid false-negatives, we form as canonical a path as we can, and map + // to lower-case in case we're on a case-insensitive file system. + auto *Dir = + FileMgr.getDirectory(llvm::sys::path::parent_path(ModuleMapPath)); + if (!Dir) + return std::string(); + auto DirName = FileMgr.getCanonicalName(Dir); + auto FileName = llvm::sys::path::filename(ModuleMapPath); + + llvm::hash_code Hash = + llvm::hash_combine(DirName.lower(), FileName.lower()); + SmallString<128> HashStr; - Code.toStringUnsigned(HashStr, /*Radix*/36); + llvm::APInt(64, size_t(Hash)).toStringUnsigned(HashStr, /*Radix*/36); llvm::sys::path::append(Result, ModuleName + "-" + HashStr.str() + ".pcm"); } return Result.str().str(); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index adecf9dab7a..02663ad43d4 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1058,6 +1058,21 @@ void ASTWriter::WriteBlockInfoBlock() { Stream.ExitBlock(); } +/// \brief Prepares a path for being written to an AST file by converting it +/// to an absolute path and removing nested './'s. +/// +/// \return \c true if the path was changed. +bool cleanPathForOutput(FileManager &FileMgr, SmallVectorImpl<char> &Path) { + bool Changed = false; + + if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { + llvm::sys::fs::make_absolute(Path); + Changed = true; + } + + return Changed | FileMgr.removeDotPaths(Path); +} + /// \brief Adjusts the given filename to only write out the portion of the /// filename that is not part of the system root directory. /// @@ -1170,8 +1185,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Record.push_back(MODULE_DIRECTORY); SmallString<128> BaseDir(WritingModule->Directory->getName()); - Context.getSourceManager().getFileManager().FixupRelativePath(BaseDir); - llvm::sys::fs::make_absolute(BaseDir); + cleanPathForOutput(Context.getSourceManager().getFileManager(), BaseDir); Stream.EmitRecordWithBlob(AbbrevCode, Record, BaseDir); // Write out all other paths relative to the base directory if possible. @@ -4076,20 +4090,10 @@ void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) { } bool ASTWriter::PreparePathForOutput(SmallVectorImpl<char> &Path) { - bool Changed = false; - - if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { - // Ask the file manager to fixup the relative path for us. This will - // honor the working directory. - if (Context) - Context->getSourceManager().getFileManager().FixupRelativePath(Path); + assert(Context && "should have context when outputting path"); - // We want an absolute path even if we weren't given a spelling for the - // current working directory. - llvm::sys::fs::make_absolute(Path); - - Changed = true; - } + bool Changed = + cleanPathForOutput(Context->getSourceManager().getFileManager(), Path); // Remove a prefix to make the path relative, if relevant. const char *PathBegin = Path.data(); |