clang API Documentation
00001 //===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // Collect the dependencies of a set of modules. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "clang/Frontend/Utils.h" 00015 #include "clang/Serialization/ASTReader.h" 00016 #include "llvm/ADT/iterator_range.h" 00017 #include "llvm/ADT/StringSet.h" 00018 #include "llvm/Support/FileSystem.h" 00019 #include "llvm/Support/Path.h" 00020 #include "llvm/Support/raw_ostream.h" 00021 00022 using namespace clang; 00023 00024 namespace { 00025 /// Private implementation for ModuleDependencyCollector 00026 class ModuleDependencyListener : public ASTReaderListener { 00027 ModuleDependencyCollector &Collector; 00028 00029 std::error_code copyToRoot(StringRef Src); 00030 public: 00031 ModuleDependencyListener(ModuleDependencyCollector &Collector) 00032 : Collector(Collector) {} 00033 bool needsInputFileVisitation() override { return true; } 00034 bool needsSystemInputFileVisitation() override { return true; } 00035 bool visitInputFile(StringRef Filename, bool IsSystem, 00036 bool IsOverridden) override; 00037 }; 00038 } 00039 00040 void ModuleDependencyCollector::attachToASTReader(ASTReader &R) { 00041 R.addListener(llvm::make_unique<ModuleDependencyListener>(*this)); 00042 } 00043 00044 void ModuleDependencyCollector::writeFileMap() { 00045 if (Seen.empty()) 00046 return; 00047 00048 SmallString<256> Dest = getDest(); 00049 llvm::sys::path::append(Dest, "vfs.yaml"); 00050 00051 std::error_code EC; 00052 llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text); 00053 if (EC) { 00054 setHasErrors(); 00055 return; 00056 } 00057 VFSWriter.write(OS); 00058 } 00059 00060 /// Remove traversal (ie, . or ..) from the given absolute path. 00061 static void removePathTraversal(SmallVectorImpl<char> &Path) { 00062 using namespace llvm::sys; 00063 SmallVector<StringRef, 16> ComponentStack; 00064 StringRef P(Path.data(), Path.size()); 00065 00066 // Skip the root path, then look for traversal in the components. 00067 StringRef Rel = path::relative_path(P); 00068 for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) { 00069 if (C == ".") 00070 continue; 00071 if (C == "..") { 00072 assert(ComponentStack.size() && "Path traverses out of parent"); 00073 ComponentStack.pop_back(); 00074 } else 00075 ComponentStack.push_back(C); 00076 } 00077 00078 // The stack is now the path without any directory traversal. 00079 SmallString<256> Buffer = path::root_path(P); 00080 for (StringRef C : ComponentStack) 00081 path::append(Buffer, C); 00082 00083 // Put the result in Path. 00084 Path.swap(Buffer); 00085 } 00086 00087 std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) { 00088 using namespace llvm::sys; 00089 00090 // We need an absolute path to append to the root. 00091 SmallString<256> AbsoluteSrc = Src; 00092 fs::make_absolute(AbsoluteSrc); 00093 removePathTraversal(AbsoluteSrc); 00094 00095 // Build the destination path. 00096 SmallString<256> Dest = Collector.getDest(); 00097 path::append(Dest, path::relative_path(AbsoluteSrc)); 00098 00099 // Copy the file into place. 00100 if (std::error_code EC = fs::create_directories(path::parent_path(Dest), 00101 /*IgnoreExisting=*/true)) 00102 return EC; 00103 if (std::error_code EC = fs::copy_file(AbsoluteSrc.str(), Dest.str())) 00104 return EC; 00105 // Use the absolute path under the root for the file mapping. 00106 Collector.addFileMapping(AbsoluteSrc.str(), Dest.str()); 00107 return std::error_code(); 00108 } 00109 00110 bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem, 00111 bool IsOverridden) { 00112 if (Collector.insertSeen(Filename)) 00113 if (copyToRoot(Filename)) 00114 Collector.setHasErrors(); 00115 return true; 00116 }