blob: d773eb24e1c418e15d6eb11ba7bb50f941851c4f [file] [log] [blame]
//===--- swift-dependency-tool.cpp - Convert binary swiftdeps to YAML -----===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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/AST/FileSystem.h"
#include "swift/AST/FineGrainedDependencies.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/FineGrainedDependencyFormat.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/LLVMInitialize.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLParser.h"
#include "llvm/Support/YAMLTraits.h"
using namespace swift;
using namespace fine_grained_dependencies;
//==============================================================================
// MARK: SourceFileDepGraph YAML reading & writing
//==============================================================================
// This introduces a redefinition where ever std::is_same_t<size_t, uint64_t>
// holds
#if !(defined(__linux__) || defined(_WIN64))
LLVM_YAML_DECLARE_SCALAR_TRAITS(size_t, QuotingType::None)
#endif
LLVM_YAML_DECLARE_ENUM_TRAITS(swift::fine_grained_dependencies::NodeKind)
LLVM_YAML_DECLARE_ENUM_TRAITS(swift::fine_grained_dependencies::DeclAspect)
LLVM_YAML_DECLARE_MAPPING_TRAITS(
swift::fine_grained_dependencies::DependencyKey)
LLVM_YAML_DECLARE_MAPPING_TRAITS(swift::fine_grained_dependencies::DepGraphNode)
namespace llvm {
namespace yaml {
template <>
struct MappingContextTraits<
swift::fine_grained_dependencies::SourceFileDepGraphNode,
swift::fine_grained_dependencies::SourceFileDepGraph> {
using SourceFileDepGraphNode =
swift::fine_grained_dependencies::SourceFileDepGraphNode;
using SourceFileDepGraph =
swift::fine_grained_dependencies::SourceFileDepGraph;
static void mapping(IO &io, SourceFileDepGraphNode &node,
SourceFileDepGraph &g);
};
template <>
struct SequenceTraits<
std::vector<swift::fine_grained_dependencies::SourceFileDepGraphNode *>> {
using SourceFileDepGraphNode =
swift::fine_grained_dependencies::SourceFileDepGraphNode;
using NodeVec = std::vector<SourceFileDepGraphNode *>;
static size_t size(IO &, NodeVec &vec);
static SourceFileDepGraphNode &element(IO &, NodeVec &vec, size_t index);
};
template <> struct ScalarTraits<swift::Fingerprint> {
static void output(const swift::Fingerprint &fp, void *c, raw_ostream &os) {
os << fp.getRawValue();
}
static StringRef input(StringRef s, void *, swift::Fingerprint &fp) {
fp = swift::Fingerprint::fromString(s);
return StringRef();
}
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
};
} // namespace yaml
} // namespace llvm
LLVM_YAML_DECLARE_MAPPING_TRAITS(
swift::fine_grained_dependencies::SourceFileDepGraph)
namespace llvm {
namespace yaml {
// This introduces a redefinition for Linux.
#if !(defined(__linux__) || defined(_WIN64))
void ScalarTraits<size_t>::output(const size_t &Val, void *, raw_ostream &out) {
out << Val;
}
StringRef ScalarTraits<size_t>::input(StringRef scalar, void *ctxt,
size_t &value) {
return scalar.getAsInteger(10, value) ? "could not parse size_t" : "";
}
#endif
void ScalarEnumerationTraits<swift::fine_grained_dependencies::NodeKind>::
enumeration(IO &io, swift::fine_grained_dependencies::NodeKind &value) {
using NodeKind = swift::fine_grained_dependencies::NodeKind;
io.enumCase(value, "topLevel", NodeKind::topLevel);
io.enumCase(value, "nominal", NodeKind::nominal);
io.enumCase(value, "potentialMember", NodeKind::potentialMember);
io.enumCase(value, "member", NodeKind::member);
io.enumCase(value, "dynamicLookup", NodeKind::dynamicLookup);
io.enumCase(value, "externalDepend", NodeKind::externalDepend);
io.enumCase(value, "incrementalExternalDepend",
NodeKind::incrementalExternalDepend);
io.enumCase(value, "sourceFileProvide", NodeKind::sourceFileProvide);
}
void ScalarEnumerationTraits<DeclAspect>::enumeration(
IO &io, swift::fine_grained_dependencies::DeclAspect &value) {
using DeclAspect = swift::fine_grained_dependencies::DeclAspect;
io.enumCase(value, "interface", DeclAspect::interface);
io.enumCase(value, "implementation", DeclAspect::implementation);
}
void MappingTraits<DependencyKey>::mapping(
IO &io, swift::fine_grained_dependencies::DependencyKey &key) {
io.mapRequired("kind", key.kind);
io.mapRequired("aspect", key.aspect);
io.mapRequired("context", key.context);
io.mapRequired("name", key.name);
}
void MappingTraits<DepGraphNode>::mapping(
IO &io, swift::fine_grained_dependencies::DepGraphNode &node) {
io.mapRequired("key", node.key);
io.mapOptional("fingerprint", node.fingerprint);
}
void MappingContextTraits<SourceFileDepGraphNode, SourceFileDepGraph>::mapping(
IO &io, SourceFileDepGraphNode &node, SourceFileDepGraph &g) {
MappingTraits<DepGraphNode>::mapping(io, node);
io.mapRequired("sequenceNumber", node.sequenceNumber);
std::vector<size_t> defsIDependUponVec(node.defsIDependUpon.begin(),
node.defsIDependUpon.end());
io.mapRequired("defsIDependUpon", defsIDependUponVec);
io.mapRequired("isProvides", node.isProvides);
if (!io.outputting()) {
for (size_t u : defsIDependUponVec)
node.defsIDependUpon.insert(u);
}
assert(g.getNode(node.sequenceNumber) && "Bad sequence number");
}
size_t SequenceTraits<std::vector<SourceFileDepGraphNode *>>::size(
IO &, std::vector<SourceFileDepGraphNode *> &vec) {
return vec.size();
}
SourceFileDepGraphNode &
SequenceTraits<std::vector<SourceFileDepGraphNode *>>::element(
IO &, std::vector<SourceFileDepGraphNode *> &vec, size_t index) {
while (vec.size() <= index)
vec.push_back(new SourceFileDepGraphNode());
return *vec[index];
}
void MappingTraits<SourceFileDepGraph>::mapping(IO &io, SourceFileDepGraph &g) {
io.mapRequired("allNodes", g.allNodes, g);
}
} // namespace yaml
} // namespace llvm
enum class ActionType : unsigned {
None,
BinaryToYAML,
YAMLToBinary
};
namespace options {
static llvm::cl::OptionCategory Category("swift-dependency-tool Options");
static llvm::cl::opt<std::string>
InputFilename("input-filename",
llvm::cl::desc("Name of the input file"),
llvm::cl::cat(Category));
static llvm::cl::opt<std::string>
OutputFilename("output-filename",
llvm::cl::desc("Name of the output file"),
llvm::cl::cat(Category));
static llvm::cl::opt<ActionType>
Action(llvm::cl::desc("Mode:"), llvm::cl::init(ActionType::None),
llvm::cl::cat(Category),
llvm::cl::values(
clEnumValN(ActionType::BinaryToYAML,
"to-yaml", "Convert new binary .swiftdeps format to YAML"),
clEnumValN(ActionType::YAMLToBinary,
"from-yaml", "Convert YAML to new binary .swiftdeps format")));
}
int main(int argc, char *argv[]) {
PROGRAM_START(argc, argv);
INITIALIZE_LLVM();
llvm::cl::HideUnrelatedOptions(options::Category);
llvm::cl::ParseCommandLineOptions(argc, argv, "Swift Dependency Tool\n");
SourceManager sourceMgr;
DiagnosticEngine diags(sourceMgr);
switch (options::Action) {
case ActionType::None: {
llvm::errs() << "action required\n";
llvm::cl::PrintHelpMessage();
return 1;
}
case ActionType::BinaryToYAML: {
auto fg = SourceFileDepGraph::loadFromPath(options::InputFilename);
if (!fg) {
llvm::errs() << "Failed to read dependency file\n";
return 1;
}
bool hadError =
withOutputFile(diags, options::OutputFilename,
[&](llvm::raw_pwrite_stream &out) {
out << "# Fine-grained v0\n";
llvm::yaml::Output yamlWriter(out);
yamlWriter << *fg;
return false;
});
if (hadError) {
llvm::errs() << "Failed to write YAML swiftdeps\n";
}
break;
}
case ActionType::YAMLToBinary: {
auto bufferOrError = llvm::MemoryBuffer::getFile(options::InputFilename);
if (!bufferOrError) {
llvm::errs() << "Failed to read dependency file\n";
return 1;
}
auto &buffer = *bufferOrError.get();
SourceFileDepGraph fg;
llvm::yaml::Input yamlReader(llvm::MemoryBufferRef(buffer), nullptr);
yamlReader >> fg;
if (yamlReader.error()) {
llvm::errs() << "Failed to parse YAML swiftdeps\n";
return 1;
}
if (writeFineGrainedDependencyGraphToPath(
diags, options::OutputFilename, fg)) {
llvm::errs() << "Failed to write binary swiftdeps\n";
return 1;
}
break;
}
}
return 0;
}