Further reorganization.

This commit is contained in:
David Ungar
2020-02-14 22:23:07 -07:00
parent 314d1e12c3
commit f4dc8884f0
4 changed files with 632 additions and 587 deletions

View File

@@ -23,177 +23,17 @@ using namespace swift;
using namespace fine_grained_dependencies;
using namespace mocking_fine_grained_dependency_graphs;
using AddDefinedDecl = SourceFileDepGraphConstructor::AddDefinedDecl;
// For now, in unit tests, mock uses are always nominal
static const NodeKind kindOfUse = NodeKind::nominal;
static Optional<StringRef> noneIfEmpty(StringRef s) {
return s.empty() ? Optional<StringRef>() : s;
}
/// Return true if when the name appears in a unit test, it represents a
/// context, not a baseName. Return false if a single name is a baseName,
/// without context Return None if there shoud be two names
static Optional<bool> singleNameIsContext(const NodeKind kind) {
switch (kind) {
case NodeKind::nominal:
case NodeKind::potentialMember:
return true;
case NodeKind::topLevel:
case NodeKind::dynamicLookup:
case NodeKind::externalDepend:
case NodeKind::sourceFileProvide:
return false;
case NodeKind::member:
return None;
case NodeKind::kindCount:
llvm_unreachable("impossible case");
}
}
static constexpr char nameContextSeparator = ',';
static std::string parseContext(const StringRef s, const NodeKind kind) {
return !singleNameIsContext(kind)
? s.split(nameContextSeparator).first.str()
: singleNameIsContext(kind).getValue() ? s.str() : "";
}
static std::string parseName(const StringRef s, const NodeKind kind) {
const std::string name =
!singleNameIsContext(kind)
? s.split(nameContextSeparator).second.str()
: singleNameIsContext(kind).getValue() ? "" : s.str();
assert(kind != NodeKind::member ||
!name.empty() && "Should be a potentialMember");
return name;
}
// clang-format off
static void parseProvides(StringRef s, const NodeKind kind, const bool includePrivateDeps,
AddDefinedDecl addDefinedDeclFn) {
static const char *privatePrefix = "#";
static constexpr char fingerprintSeparator = '@';
const bool isPrivate = s.consume_front(privatePrefix);
if (isPrivate && !includePrivateDeps)
return;
std::string context = parseContext(s.split(fingerprintSeparator).first, kind);
std::string name = parseName(s.split(fingerprintSeparator).first, kind);
Optional<StringRef> fingerprint = noneIfEmpty(s.split(fingerprintSeparator).second);
addDefinedDeclFn(DependencyKey(kind, DeclAspect::interface, context, name), fingerprint);
}
static const char* defUseSeparator = "->";
void parseDefUse(const StringRef argString, const NodeKind kind, const bool includePrivateDeps,
StringRef swiftDeps,
function_ref<void(const DependencyKey&, const DependencyKey&)> fn) {
static const char* noncascadingPrefix = "#";
static const char* privateHolderPrefix = "~";
StringRef s = argString;
const bool isCascadingUse = !s.consume_front(noncascadingPrefix);
// Someday, we might differentiate.
const DeclAspect aspectOfDefUsed = DeclAspect::interface;
const DeclAspect aspectOfUse = isCascadingUse ? DeclAspect::interface : DeclAspect::implementation;
const bool isHolderPrivate = s.consume_front(privateHolderPrefix);
if (!includePrivateDeps && isHolderPrivate)
return;
const auto defUseStrings = s.split(defUseSeparator);
const auto context = parseContext(defUseStrings.first, kind);
const auto name = parseName(defUseStrings.first, kind);
const DependencyKey defKey = DependencyKey(kind, aspectOfDefUsed, context, name);
auto useKey = [&]() -> DependencyKey {
if (defUseStrings.second.empty()) {
return DependencyKey(NodeKind::sourceFileProvide,
aspectOfUse,
DependencyKey::computeContextForProvidedEntity<
NodeKind::sourceFileProvide>(swiftDeps),
DependencyKey::computeNameForProvidedEntity<
NodeKind::sourceFileProvide>(
swiftDeps));
}
else {
DependencyKey specificUse;
parseProvides(defUseStrings.second, kindOfUse, includePrivateDeps,
[&](const DependencyKey &parsedUse, Optional<StringRef> fingerprint) {
assert(!fingerprint && "Users have no prints");
specificUse = parsedUse.withAspect(aspectOfUse);
});
return specificUse;
}
};
fn(defKey, useKey());
}
static void forEachEntry(const DependencyDescriptions &dependencyDescriptions,
function_ref<void(NodeKind kind, StringRef entry)> fn) {
for (const auto &kindAndEntries: dependencyDescriptions) {
for (StringRef s: kindAndEntries.second)
fn(kindAndEntries.first, s);
}
}
static bool isAProvides(StringRef s) {
return s.find(defUseSeparator) == StringRef::npos;
}
static SourceFileDepGraph mockSourceFileDepGraph(
std::string swiftDepsFilename,
const bool includePrivateDeps,
const bool hadCompilationError,
std::string interfaceHash,
const DependencyDescriptions &dependencyDescriptions) {
auto forEachMockDefinedDecl = [&](AddDefinedDecl addDefinedDeclFn) {
forEachEntry(dependencyDescriptions, [&](NodeKind kind, StringRef s) {
if (isAProvides(s))
parseProvides(s, kind, includePrivateDeps, addDefinedDeclFn);
});
};
auto forEachMockUsedDecl = [&] (function_ref<void(const DependencyKey&, const DependencyKey&)> fn) {
forEachEntry(dependencyDescriptions, [&](NodeKind kind, StringRef s) {
if (!isAProvides(s))
parseDefUse(s, kind, includePrivateDeps, swiftDepsFilename, fn);
});
};
return SourceFileDepGraphConstructor(includePrivateDeps, hadCompilationError)
.construct(
swiftDepsFilename,
interfaceHash,
forEachMockDefinedDecl,
forEachMockUsedDecl);
}
void mocking_fine_grained_dependency_graphs::simulateLoad(
ModuleDepGraph &g, const driver::Job *cmd,
const DependencyDescriptions &dependencyDescriptions,
StringRef interfaceHashIfNonEmpty, const bool includePrivateDeps,
const bool hadCompilationError) {
const auto changes = getChangesForSimulatedLoad(
g, cmd, dependencyDescriptions, interfaceHashIfNonEmpty, includePrivateDeps,
hadCompilationError);
g, cmd, dependencyDescriptions, interfaceHashIfNonEmpty,
includePrivateDeps, hadCompilationError);
assert(changes && "simulated load should always succeed");
}
ModuleDepGraph::Changes
mocking_fine_grained_dependency_graphs::getChangesForSimulatedLoad(
ModuleDepGraph &g, const driver::Job *cmd,
@@ -205,15 +45,17 @@ mocking_fine_grained_dependency_graphs::getChangesForSimulatedLoad(
assert(!swiftDeps.empty());
StringRef interfaceHash =
interfaceHashIfNonEmpty.empty() ? swiftDeps : interfaceHashIfNonEmpty;
auto sfdg =
mockSourceFileDepGraph(swiftDeps, includePrivateDeps, hadCompilationError,
interfaceHash, dependencyDescriptions);
SourceManager sm;
DiagnosticEngine diags(sm);
// help for debugging: emit imported file, too
if (g.emitFineGrainedDependencyDotFileAfterEveryImport) {
sfdg.emitDotFile(swiftDeps, diags);
}
auto sfdg =
MockSourceFileDepGraphConstructor(
includePrivateDeps, hadCompilationError, swiftDeps, interfaceHash,
g.emitFineGrainedDependencyDotFileAfterEveryImport,
dependencyDescriptions, diags)
.construct();
return g.loadFromSourceFileDepGraph(cmd, sfdg, diags);
}
@@ -224,8 +66,8 @@ mocking_fine_grained_dependency_graphs::simulateReload(
StringRef interfaceHashIfNonEmpty, const bool includePrivateDeps,
const bool hadCompilationError) {
const auto changedNodes = getChangesForSimulatedLoad(
g, cmd, dependencyDescriptions, interfaceHashIfNonEmpty, includePrivateDeps,
hadCompilationError);
g, cmd, dependencyDescriptions, interfaceHashIfNonEmpty,
includePrivateDeps, hadCompilationError);
if (!changedNodes)
return g.getAllJobs();
return g.findJobsToRecompileWhenNodesChange(changedNodes.getValue());