//===--- OutputFileMap.cpp - Driver output file map -----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/Driver/OutputFileMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include using namespace swift; using namespace swift::driver; std::unique_ptr OutputFileMap::loadFromPath(StringRef Path, StringRef workingDirectory) { llvm::ErrorOr> FileBufOrErr = llvm::MemoryBuffer::getFile(Path); if (!FileBufOrErr) return nullptr; return loadFromBuffer(std::move(FileBufOrErr.get()), workingDirectory); } std::unique_ptr OutputFileMap::loadFromBuffer(StringRef Data, StringRef workingDirectory) { std::unique_ptr Buffer{ llvm::MemoryBuffer::getMemBuffer(Data) }; return loadFromBuffer(std::move(Buffer), workingDirectory); } std::unique_ptr OutputFileMap::loadFromBuffer(std::unique_ptr Buffer, StringRef workingDirectory) { std::unique_ptr OFM(new OutputFileMap()); if (OFM->parse(std::move(Buffer), workingDirectory)) return nullptr; return OFM; } const TypeToPathMap *OutputFileMap::getOutputMapForInput(StringRef Input) const{ auto iter = InputToOutputsMap.find(Input); if (iter == InputToOutputsMap.end()) return nullptr; else return &iter->second; } TypeToPathMap & OutputFileMap::getOrCreateOutputMapForInput(StringRef Input) { return InputToOutputsMap[Input]; } const TypeToPathMap *OutputFileMap::getOutputMapForSingleOutput() const { return getOutputMapForInput(StringRef()); } TypeToPathMap & OutputFileMap::getOrCreateOutputMapForSingleOutput() { return InputToOutputsMap[StringRef()]; } void OutputFileMap::dump(llvm::raw_ostream &os, bool Sort) const { typedef std::pair TypePathPair; auto printOutputPair = [&os] (StringRef InputPath, const TypePathPair &OutputPair) -> void { os << InputPath << " -> " << types::getTypeName(OutputPair.first) << ": \"" << OutputPair.second << "\"\n"; }; if (Sort) { typedef std::pair PathMapPair; std::vector Maps; for (auto &InputPair : InputToOutputsMap) { Maps.emplace_back(InputPair.first(), InputPair.second); } std::sort(Maps.begin(), Maps.end(), [] (const PathMapPair &LHS, const PathMapPair &RHS) -> bool { return LHS.first < RHS.first; }); for (auto &InputPair : Maps) { const TypeToPathMap &Map = InputPair.second; std::vector Pairs; Pairs.insert(Pairs.end(), Map.begin(), Map.end()); std::sort(Pairs.begin(), Pairs.end()); for (auto &OutputPair : Pairs) { printOutputPair(InputPair.first, OutputPair); } } } else { for (auto &InputPair : InputToOutputsMap) { const TypeToPathMap &Map = InputPair.second; for (const TypePathPair &OutputPair : Map) { printOutputPair(InputPair.first(), OutputPair); } } } } bool OutputFileMap::parse(std::unique_ptr Buffer, StringRef workingDirectory) { llvm::SourceMgr SM; llvm::yaml::Stream YAMLStream(Buffer->getMemBufferRef(), SM); auto I = YAMLStream.begin(); if (I == YAMLStream.end()) return true; auto Root = I->getRoot(); if (!Root) return true; auto *Map = dyn_cast(Root); if (!Map) return true; auto resolvePath = [workingDirectory]( llvm::yaml::ScalarNode *Path, llvm::SmallVectorImpl &PathStorage) -> StringRef { StringRef PathStr = Path->getValue(PathStorage); if (workingDirectory.empty() || PathStr.empty() || PathStr == "-" || llvm::sys::path::is_absolute(PathStr)) { return PathStr; } // Copy the path to avoid making assumptions about how getValue deals with // Storage. SmallString<128> PathStrCopy(PathStr); PathStorage.clear(); PathStorage.reserve(PathStrCopy.size() + workingDirectory.size() + 1); PathStorage.insert(PathStorage.begin(), workingDirectory.begin(), workingDirectory.end()); llvm::sys::path::append(PathStorage, PathStrCopy); return StringRef(PathStorage.data(), PathStorage.size()); }; for (auto Pair : *Map) { llvm::yaml::Node *Key = Pair.getKey(); llvm::yaml::Node *Value = Pair.getValue(); if (!Key) return true; if (!Value) return true; auto *InputPath = dyn_cast(Key); if (!InputPath) return true; llvm::yaml::MappingNode *OutputMapNode = dyn_cast(Value); if (!OutputMapNode) return true; TypeToPathMap OutputMap; for (auto OutputPair : *OutputMapNode) { llvm::yaml::Node *Key = OutputPair.getKey(); llvm::yaml::Node *Value = OutputPair.getValue(); auto *KindNode = dyn_cast(Key); if (!KindNode) return true; auto *Path = dyn_cast(Value); if (!Path) return true; llvm::SmallString<16> KindStorage; types::ID Kind = types::lookupTypeForName(KindNode->getValue(KindStorage)); // Ignore unknown types, so that an older swiftc can be used with a newer // build system. if (Kind == types::TY_INVALID) continue; llvm::SmallString<128> PathStorage; OutputMap.insert(std::pair( Kind, resolvePath(Path, PathStorage))); } llvm::SmallString<128> InputStorage; InputToOutputsMap[resolvePath(InputPath, InputStorage)] = std::move(OutputMap); } return false; }