mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* spelling: accessor Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: accommodates Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: argument Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: associated Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: availability Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: available Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: belongs Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: bookkeeping Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: building Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: clazz Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: clonable Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: closure Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: concatenated Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: conformance Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: context Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: conversion Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: correspondence Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: declarations Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: declared Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: defining Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: delayed Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: dependency Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: deployed Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: descendants Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: diagnose Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: diagnostic Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: equitable Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: evaluation Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: exclusivity Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: existence Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: existential Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: explicit Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: expressed Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: for Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: foreign Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: function Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: identifier Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: implicit Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: indices Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: information Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: instance Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: interchangeable Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: interface Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: introduced Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: invalid Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: kind-in Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: least Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: library Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: location Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: namespace Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: necessary Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: nonexistent Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: not Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: number Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: obtains Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: occurs Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: opaque Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: overridden Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: parameter Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: precede Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: preceding Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: property Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: protocol Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: qualified Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: recognized Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: recursively Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: references Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: relaxing Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: represented Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: request Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: requirement Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: requirements Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: retrieve Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: returned Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: satisfied Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: satisfy Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: scanner Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: siblings Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: simplified Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: something Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: source Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: specializations Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: specially Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: statement Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: stripped Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: structure Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: substitution Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: the Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: transform Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: transformed Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: transitively Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: transparent Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: typecheck Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unknown Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unlabeled Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: unqualified Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: whether Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: with Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> * spelling: scanner Signed-off-by: Josh Soref <jsoref@users.noreply.github.com> Co-authored-by: Josh Soref <jsoref@users.noreply.github.com>
384 lines
14 KiB
C++
384 lines
14 KiB
C++
//===---- FineGrainedDependencies.cpp - Generates swiftdeps files ---------===//
|
|
//
|
|
// 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/AST/FineGrainedDependencies.h"
|
|
|
|
// may not all be needed
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/DiagnosticsCommon.h"
|
|
#include "swift/AST/DiagnosticsFrontend.h"
|
|
#include "swift/AST/FileSystem.h"
|
|
#include "swift/AST/FineGrainedDependencyFormat.h"
|
|
#include "swift/Basic/FileSystem.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Demangling/Demangle.h"
|
|
#include "swift/Frontend/FrontendOptions.h"
|
|
|
|
#include "llvm/ADT/MapVector.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
|
|
// This file holds the definitions for the fine-grained dependency system
|
|
// that are likely to be stable as it moves away from the status quo.
|
|
// These include the graph structures common to both programs and also
|
|
// the frontend graph, which must be read by the driver.
|
|
|
|
using namespace swift;
|
|
using namespace fine_grained_dependencies;
|
|
|
|
//==============================================================================
|
|
// MARK: Emitting and reading SourceFileDepGraph
|
|
//==============================================================================
|
|
|
|
Optional<SourceFileDepGraph>
|
|
SourceFileDepGraph::loadFromPath(StringRef path, const bool allowSwiftModule) {
|
|
const bool treatAsModule =
|
|
allowSwiftModule &&
|
|
path.endswith(file_types::getExtension(file_types::TY_SwiftModuleFile));
|
|
auto bufferOrError = llvm::MemoryBuffer::getFile(path);
|
|
if (!bufferOrError)
|
|
return None;
|
|
return treatAsModule ? loadFromSwiftModuleBuffer(*bufferOrError.get())
|
|
: loadFromBuffer(*bufferOrError.get());
|
|
}
|
|
|
|
Optional<SourceFileDepGraph>
|
|
SourceFileDepGraph::loadFromBuffer(llvm::MemoryBuffer &buffer) {
|
|
SourceFileDepGraph fg;
|
|
if (swift::fine_grained_dependencies::readFineGrainedDependencyGraph(
|
|
buffer, fg))
|
|
return None;
|
|
return Optional<SourceFileDepGraph>(std::move(fg));
|
|
}
|
|
|
|
Optional<SourceFileDepGraph>
|
|
SourceFileDepGraph::loadFromSwiftModuleBuffer(llvm::MemoryBuffer &buffer) {
|
|
SourceFileDepGraph fg;
|
|
if (swift::fine_grained_dependencies::
|
|
readFineGrainedDependencyGraphFromSwiftModule(buffer, fg))
|
|
return None;
|
|
return Optional<SourceFileDepGraph>(std::move(fg));
|
|
}
|
|
|
|
//==============================================================================
|
|
// MARK: SourceFileDepGraph access
|
|
//==============================================================================
|
|
|
|
SourceFileDepGraphNode *
|
|
SourceFileDepGraph::getNode(size_t sequenceNumber) const {
|
|
assert(sequenceNumber < allNodes.size() && "Bad node index");
|
|
SourceFileDepGraphNode *n = allNodes[sequenceNumber];
|
|
assert(n->getSequenceNumber() == sequenceNumber &&
|
|
"Bad sequence number in node or bad entry in allNodes.");
|
|
return n;
|
|
}
|
|
|
|
InterfaceAndImplementationPair<SourceFileDepGraphNode>
|
|
SourceFileDepGraph::getSourceFileNodePair() const {
|
|
return InterfaceAndImplementationPair<SourceFileDepGraphNode>(
|
|
getNode(
|
|
SourceFileDepGraphNode::sourceFileProvidesInterfaceSequenceNumber),
|
|
getNode(SourceFileDepGraphNode::
|
|
sourceFileProvidesImplementationSequenceNumber));
|
|
}
|
|
|
|
StringRef SourceFileDepGraph::getSwiftDepsOfJobThatProducedThisGraph() const {
|
|
return getSourceFileNodePair()
|
|
.getInterface()
|
|
->getKey()
|
|
.getSwiftDepsFromASourceFileProvideNodeKey();
|
|
}
|
|
|
|
void SourceFileDepGraph::forEachArc(
|
|
function_ref<void(const SourceFileDepGraphNode *def,
|
|
const SourceFileDepGraphNode *use)>
|
|
fn) const {
|
|
forEachNode([&](const SourceFileDepGraphNode *useNode) {
|
|
forEachDefDependedUponBy(useNode, [&](SourceFileDepGraphNode *defNode) {
|
|
fn(defNode, useNode);
|
|
});
|
|
});
|
|
}
|
|
|
|
InterfaceAndImplementationPair<SourceFileDepGraphNode>
|
|
SourceFileDepGraph::findExistingNodePairOrCreateAndAddIfNew(
|
|
const DependencyKey &interfaceKey, Optional<Fingerprint> fingerprint) {
|
|
|
|
// Optimization for whole-file users:
|
|
if (interfaceKey.getKind() == NodeKind::sourceFileProvide &&
|
|
!allNodes.empty())
|
|
return getSourceFileNodePair();
|
|
|
|
assert(interfaceKey.isInterface());
|
|
const DependencyKey implementationKey =
|
|
interfaceKey.correspondingImplementation();
|
|
auto *interfaceNode = findExistingNodeOrCreateIfNew(interfaceKey, fingerprint,
|
|
true /* = isProvides */);
|
|
auto *implementationNode = findExistingNodeOrCreateIfNew(
|
|
implementationKey, fingerprint, true /* = isProvides */);
|
|
|
|
InterfaceAndImplementationPair<SourceFileDepGraphNode> nodePair{
|
|
interfaceNode, implementationNode};
|
|
|
|
// if interface changes, have to rebuild implementation.
|
|
// This dependency used to be represented by
|
|
// addArc(nodePair.getInterface(), nodePair.getImplementation());
|
|
// However, recall that the dependency scheme as of 1/2020 chunks
|
|
// declarations together by base name.
|
|
// So if the arc were added, a dirtying of a same-based-named interface
|
|
// in a different file would dirty the implementation in this file,
|
|
// causing the needless recompilation of this file.
|
|
// But, if an arc is added for this, then *any* change that causes
|
|
// a same-named interface to be dirty will dirty this implementation,
|
|
// even if that interface is in another file.
|
|
// Therefor no such arc is added here, and any dirtying of either
|
|
// the interface or implementation of this declaration will cause
|
|
// the driver to recompile this source file.
|
|
return nodePair;
|
|
}
|
|
|
|
SourceFileDepGraphNode *SourceFileDepGraph::findExistingNodeOrCreateIfNew(
|
|
const DependencyKey &key, const Optional<Fingerprint> fingerprint,
|
|
const bool isProvides) {
|
|
SourceFileDepGraphNode *result = memoizedNodes.findExistingOrCreateIfNew(
|
|
key, [&](DependencyKey key) -> SourceFileDepGraphNode * {
|
|
SourceFileDepGraphNode *n =
|
|
new SourceFileDepGraphNode(key, fingerprint, isProvides);
|
|
addNode(n);
|
|
return n;
|
|
});
|
|
assert(result->getKey() == key && "Keys must match.");
|
|
if (!isProvides)
|
|
return result;
|
|
// If have provides and depends with same key, result is one node that
|
|
// isProvides
|
|
if (!result->getIsProvides() && fingerprint) {
|
|
result->setIsProvides();
|
|
assert(!result->getFingerprint() && "Depends should not have fingerprints");
|
|
result->setFingerprint(fingerprint);
|
|
return result;
|
|
}
|
|
// If there are two Decls with same base name but differ only in fingerprint,
|
|
// since we won't be able to tell which Decl is depended-upon (is this right?)
|
|
// just use the one node, but erase its print:
|
|
if (fingerprint != result->getFingerprint())
|
|
result->setFingerprint(None);
|
|
return result;
|
|
}
|
|
|
|
NullablePtr<SourceFileDepGraphNode>
|
|
SourceFileDepGraph::findExistingNode(const DependencyKey &key) {
|
|
auto existing = memoizedNodes.findExisting(key);
|
|
return existing ? existing.getValue() : NullablePtr<SourceFileDepGraphNode>();
|
|
}
|
|
|
|
std::string DependencyKey::demangleTypeAsContext(StringRef s) {
|
|
return swift::Demangle::demangleTypeAsString(s.str());
|
|
}
|
|
|
|
DependencyKey DependencyKey::createKeyForWholeSourceFile(DeclAspect aspect,
|
|
StringRef swiftDeps) {
|
|
assert(!swiftDeps.empty());
|
|
return DependencyKey::Builder(NodeKind::sourceFileProvide, aspect)
|
|
.withName(swiftDeps)
|
|
.build();
|
|
}
|
|
|
|
//==============================================================================
|
|
// MARK: Debugging
|
|
//==============================================================================
|
|
|
|
bool SourceFileDepGraph::verify() const {
|
|
DependencyKey::verifyNodeKindNames();
|
|
DependencyKey::verifyDeclAspectNames();
|
|
// Ensure Keys are unique
|
|
std::unordered_map<DependencyKey, SourceFileDepGraphNode *> nodesSeen;
|
|
// Ensure each node only appears once.
|
|
std::unordered_set<void *> nodes;
|
|
forEachNode([&](SourceFileDepGraphNode *n) {
|
|
n->verify();
|
|
assert(nodes.insert(n).second && "Frontend nodes are identified by "
|
|
"sequence number, therefore must be "
|
|
"unique.");
|
|
|
|
auto iterInserted = nodesSeen.insert(std::make_pair(n->getKey(), n));
|
|
if (!iterInserted.second) {
|
|
llvm::errs() << "Duplicate frontend keys: ";
|
|
iterInserted.first->second->dump(llvm::errs());
|
|
llvm::errs() << " and ";
|
|
n->dump(llvm::errs());
|
|
llvm::errs() << "\n";
|
|
llvm_unreachable("duplicate frontend keys");
|
|
}
|
|
|
|
forEachDefDependedUponBy(n, [&](SourceFileDepGraphNode *def) {
|
|
assert(def != n && "Uses should be irreflexive.");
|
|
});
|
|
});
|
|
return true;
|
|
}
|
|
|
|
bool SourceFileDepGraph::verifyReadsWhatIsWritten(StringRef path) const {
|
|
auto loadedGraph = SourceFileDepGraph::loadFromPath(path);
|
|
assert(loadedGraph.hasValue() &&
|
|
"Should be able to read the exported graph.");
|
|
verifySame(loadedGraph.getValue());
|
|
return true;
|
|
}
|
|
|
|
std::string DependencyKey::humanReadableName() const {
|
|
switch (kind) {
|
|
case NodeKind::member:
|
|
return demangleTypeAsContext(context) + "." + name;
|
|
case NodeKind::externalDepend:
|
|
case NodeKind::sourceFileProvide:
|
|
return llvm::sys::path::filename(name).str();
|
|
case NodeKind::potentialMember:
|
|
return demangleTypeAsContext(context) + ".*";
|
|
case NodeKind::nominal:
|
|
return demangleTypeAsContext(context);
|
|
case NodeKind::topLevel:
|
|
case NodeKind::dynamicLookup:
|
|
return name;
|
|
default:
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
}
|
|
|
|
std::string DependencyKey::asString() const {
|
|
return NodeKindNames[size_t(kind)] + " " + "aspect: " + aspectName().str() +
|
|
", " + humanReadableName();
|
|
}
|
|
|
|
/// Needed for TwoStageMap::verify:
|
|
raw_ostream &fine_grained_dependencies::operator<<(raw_ostream &out,
|
|
const DependencyKey &key) {
|
|
out << key.asString();
|
|
return out;
|
|
}
|
|
|
|
bool DependencyKey::verify() const {
|
|
assert((getKind() != NodeKind::externalDepend || isInterface()) &&
|
|
"All external dependencies must be interfaces.");
|
|
switch (getKind()) {
|
|
case NodeKind::topLevel:
|
|
case NodeKind::dynamicLookup:
|
|
case NodeKind::externalDepend:
|
|
case NodeKind::sourceFileProvide:
|
|
assert(context.empty() && !name.empty() && "Must only have a name");
|
|
break;
|
|
case NodeKind::nominal:
|
|
case NodeKind::potentialMember:
|
|
assert(!context.empty() && name.empty() && "Must only have a context");
|
|
break;
|
|
case NodeKind::member:
|
|
assert(!context.empty() && !name.empty() && "Must have both");
|
|
break;
|
|
case NodeKind::kindCount:
|
|
llvm_unreachable("impossible");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// Since I don't have Swift enums, ensure name correspondence here.
|
|
void DependencyKey::verifyNodeKindNames() {
|
|
for (size_t i = 0; i < size_t(NodeKind::kindCount); ++i)
|
|
switch (NodeKind(i)) {
|
|
#define CHECK_NAME(n) \
|
|
case NodeKind::n: \
|
|
assert(#n == NodeKindNames[i]); \
|
|
break;
|
|
CHECK_NAME(topLevel)
|
|
CHECK_NAME(nominal)
|
|
CHECK_NAME(potentialMember)
|
|
CHECK_NAME(member)
|
|
CHECK_NAME(dynamicLookup)
|
|
CHECK_NAME(externalDepend)
|
|
CHECK_NAME(sourceFileProvide)
|
|
case NodeKind::kindCount:
|
|
llvm_unreachable("impossible");
|
|
}
|
|
#undef CHECK_NAME
|
|
}
|
|
|
|
/// Since I don't have Swift enums, ensure name correspondence here.
|
|
void DependencyKey::verifyDeclAspectNames() {
|
|
for (size_t i = 0; i < size_t(DeclAspect::aspectCount); ++i)
|
|
switch (DeclAspect(i)) {
|
|
#define CHECK_NAME(n) \
|
|
case DeclAspect::n: \
|
|
assert(#n == DeclAspectNames[i]); \
|
|
break;
|
|
CHECK_NAME(interface)
|
|
CHECK_NAME(implementation)
|
|
case DeclAspect::aspectCount:
|
|
llvm_unreachable("impossible");
|
|
}
|
|
#undef CHECK_NAME
|
|
}
|
|
|
|
void DepGraphNode::dump() const {
|
|
dump(llvm::errs());
|
|
}
|
|
|
|
void DepGraphNode::dump(raw_ostream &os) const {
|
|
key.dump(os);
|
|
if (fingerprint.hasValue())
|
|
os << "fingerprint: " << fingerprint.getValue() << "";
|
|
else
|
|
os << "no fingerprint";
|
|
}
|
|
|
|
void SourceFileDepGraphNode::dump() const {
|
|
dump(llvm::errs());
|
|
}
|
|
|
|
void SourceFileDepGraphNode::dump(raw_ostream &os) const {
|
|
DepGraphNode::dump(os);
|
|
os << " sequence number: " << sequenceNumber;
|
|
os << " is provides: " << isProvides;
|
|
os << " depends on:";
|
|
for (auto def : defsIDependUpon)
|
|
os << " " << def;
|
|
}
|
|
|
|
std::string DepGraphNode::humanReadableName(StringRef where) const {
|
|
|
|
return getKey().humanReadableName() +
|
|
(getKey().getKind() == NodeKind::sourceFileProvide || where.empty()
|
|
? std::string()
|
|
: std::string(" in ") + where.str());
|
|
}
|
|
|
|
void SourceFileDepGraph::verifySame(const SourceFileDepGraph &other) const {
|
|
assert(allNodes.size() == other.allNodes.size() &&
|
|
"Both graphs must have same number of nodes.");
|
|
#ifndef NDEBUG
|
|
for (size_t i : indices(allNodes)) {
|
|
assert(*allNodes[i] == *other.allNodes[i] &&
|
|
"Both graphs must have corresponding nodes");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void SourceFileDepGraph::emitDotFile(StringRef outputPath,
|
|
DiagnosticEngine &diags) {
|
|
std::string dotFileName = outputPath.str() + ".dot";
|
|
withOutputFile(diags, dotFileName, [&](llvm::raw_pwrite_stream &out) {
|
|
DotFileEmitter<SourceFileDepGraph>(out, *this, false, false).emit();
|
|
return false;
|
|
});
|
|
}
|